mirror of
https://github.com/logos-storage/logos-storage-js.git
synced 2026-01-02 13:33:07 +00:00
chore: generate types from open api (#14)
* Generate types from the open api file * Update dependencies * Update dependencies * Update the openapi schema * Fix merge * Fix doc reference
This commit is contained in:
parent
921bb617ef
commit
3bf517d1bb
1
.gitignore
vendored
1
.gitignore
vendored
@ -1,3 +1,4 @@
|
|||||||
node_modules
|
node_modules
|
||||||
dist
|
dist
|
||||||
*.tgz
|
*.tgz
|
||||||
|
index.bundle.js
|
||||||
78
README.md
78
README.md
@ -10,6 +10,14 @@ The SDK is currently under early development and the API can change at any time.
|
|||||||
|
|
||||||
- Version 0.1.0 introduces [upload strategy](#upload) to support browser and Node JS.
|
- Version 0.1.0 introduces [upload strategy](#upload) to support browser and Node JS.
|
||||||
|
|
||||||
|
## Types generation
|
||||||
|
|
||||||
|
The types are generated from the openapi.yaml using the commande:
|
||||||
|
|
||||||
|
```bash
|
||||||
|
npx openapi-typescript ./openapi.yaml -o src/openapi.ts --default-non-nullable false
|
||||||
|
```
|
||||||
|
|
||||||
## How to use
|
## How to use
|
||||||
|
|
||||||
### Sync api
|
### Sync api
|
||||||
@ -126,7 +134,7 @@ const marketplace = codex.marketplace;
|
|||||||
|
|
||||||
Returns active slots.
|
Returns active slots.
|
||||||
|
|
||||||
- returns Promise<[CodexSlot](./src/marketplace/types.ts#L85)[]>
|
- returns Promise<[CodexSlot](./src/marketplace/types.ts#L7)[]>
|
||||||
|
|
||||||
Example:
|
Example:
|
||||||
|
|
||||||
@ -139,7 +147,7 @@ const slots = await marketplace.activeSlots();
|
|||||||
Returns active slot with id {slotId} for the host.
|
Returns active slot with id {slotId} for the host.
|
||||||
|
|
||||||
- slotId (string, required)
|
- slotId (string, required)
|
||||||
- returns Promise<[CodexSlot](./src/marketplace/types.ts#L85)[]>
|
- returns Promise<[CodexSlotAgent](./src/marketplace/types.ts#L12)[]>
|
||||||
|
|
||||||
Example:
|
Example:
|
||||||
|
|
||||||
@ -152,7 +160,7 @@ const slot = await marketplace.activeSlot(slotId);
|
|||||||
|
|
||||||
Returns storage that is for sale.
|
Returns storage that is for sale.
|
||||||
|
|
||||||
- returns Promise<[CodexAvailability](./src/marketplace/types.ts#L99)>
|
- returns Promise<[CodexAvailability](./src/marketplace/types.ts#L20)>
|
||||||
|
|
||||||
Example:
|
Example:
|
||||||
|
|
||||||
@ -164,8 +172,8 @@ const availabilities = await marketplace.availabilities();
|
|||||||
|
|
||||||
Offers storage for sale.
|
Offers storage for sale.
|
||||||
|
|
||||||
- input ([CodexCreateAvailabilityInput](./src/marketplace/types.ts#L175), required)
|
- input ([CodexCreateAvailabilityInput](./src/marketplace/types.ts#L45), required)
|
||||||
- returns Promise<[CodexAvailabilityCreateResponse](./src/marketplace/types.ts#L186)[]>
|
- returns Promise<[CodexAvailability](./src/marketplace/types.ts#L20)[]>
|
||||||
|
|
||||||
Example:
|
Example:
|
||||||
|
|
||||||
@ -182,7 +190,7 @@ const response = await marketplace.createAvailability({
|
|||||||
|
|
||||||
Updates availability.
|
Updates availability.
|
||||||
|
|
||||||
- input ([CodexUpdateAvailabilityInput](./src/marketplace/types.ts#L186), required)
|
- input ([CodexAvailabilityPatchInput](./src/marketplace/types.ts#L66), required)
|
||||||
- returns Promise<"">
|
- returns Promise<"">
|
||||||
|
|
||||||
Example:
|
Example:
|
||||||
@ -202,7 +210,7 @@ const response = await marketplace.updateAvailability({
|
|||||||
Return list of reservations for ongoing Storage Requests that the node hosts.
|
Return list of reservations for ongoing Storage Requests that the node hosts.
|
||||||
|
|
||||||
- availabilityId (string, required)
|
- availabilityId (string, required)
|
||||||
- returns Promise<[CodexReservation](./src/marketplace/types.ts#L198)[]>
|
- returns Promise<[CodexReservation](./src/marketplace/types.ts#L83)[]>
|
||||||
|
|
||||||
Example:
|
Example:
|
||||||
|
|
||||||
@ -214,7 +222,7 @@ const reservations = await marketplace.reservations("Ox...");
|
|||||||
|
|
||||||
Creates a new Request for storage
|
Creates a new Request for storage
|
||||||
|
|
||||||
- input ([CodexCreateStorageRequestInput](./src/marketplace/types.ts#L230), required)
|
- input ([CodexCreateStorageRequestInput](./src/marketplace/types.ts#L120), required)
|
||||||
- returns Promise<string>
|
- returns Promise<string>
|
||||||
|
|
||||||
Example:
|
Example:
|
||||||
@ -248,7 +256,7 @@ const ids = await marketplace.purchaseIds();
|
|||||||
Returns purchase details
|
Returns purchase details
|
||||||
|
|
||||||
- purchaseId (string, required)
|
- purchaseId (string, required)
|
||||||
- returns Promise<[CodexPurchase](./src/marketplace/types.ts#L214)[]>
|
- returns Promise<[CodexPurchase](./src/marketplace/types.ts#L103)[]>
|
||||||
|
|
||||||
Example:
|
Example:
|
||||||
|
|
||||||
@ -274,7 +282,7 @@ const data = codex.data;
|
|||||||
|
|
||||||
Returns the manifest stored locally in node.
|
Returns the manifest stored locally in node.
|
||||||
|
|
||||||
- returns Promise<[CodexDataResponse](./src/data/types.ts#L54)[]>
|
- returns Promise<[CodexDataItem](./src/data/types.ts#L8)[]>
|
||||||
|
|
||||||
Example:
|
Example:
|
||||||
|
|
||||||
@ -286,7 +294,7 @@ const cids = await data.cids();
|
|||||||
|
|
||||||
Returns a summary of the storage space allocation of the node
|
Returns a summary of the storage space allocation of the node
|
||||||
|
|
||||||
- returns Promise<[CodexNodeSpace](./src/data/types.ts#L56)[]>
|
- returns Promise<[CodexNodeSpace](./src/data/types.ts#L15)[]>
|
||||||
|
|
||||||
Example:
|
Example:
|
||||||
|
|
||||||
@ -301,7 +309,7 @@ Upload a file in a streaming manner
|
|||||||
#### Browser
|
#### Browser
|
||||||
|
|
||||||
- stategy [BrowserUploadStategy](./src/data/browser-upload.ts#L5)
|
- stategy [BrowserUploadStategy](./src/data/browser-upload.ts#L5)
|
||||||
- returns [UploadResponse](./src/data/types.ts#L80)
|
- returns [UploadResponse](./src/data/types.ts#L17)
|
||||||
|
|
||||||
Example:
|
Example:
|
||||||
|
|
||||||
@ -330,8 +338,8 @@ console.info("CID is", res.data);
|
|||||||
|
|
||||||
#### Node
|
#### Node
|
||||||
|
|
||||||
- stategy [NodeUploadStategy](./src/data/node-download.ts#L8)
|
- stategy [NodeUploadStategy](./src/data/node-upload.ts#L9)
|
||||||
- returns [UploadResponse](./src/data/types.ts#L80)
|
- returns [UploadResponse](./src/data/types.ts#L17)
|
||||||
|
|
||||||
Example:
|
Example:
|
||||||
|
|
||||||
@ -354,7 +362,7 @@ console.info("CID is", res.data);
|
|||||||
Download only the dataset manifest from the network to the local node if it's not available locally.
|
Download only the dataset manifest from the network to the local node if it's not available locally.
|
||||||
|
|
||||||
- cid (string, required)
|
- cid (string, required)
|
||||||
- returns [CodexManifest](./src/data/types.ts#L3)
|
- returns [CodexManifest](./src/data/types.ts#L30)
|
||||||
|
|
||||||
Example:
|
Example:
|
||||||
|
|
||||||
@ -410,7 +418,7 @@ const data = codex.debug;
|
|||||||
|
|
||||||
Set log level at run time.
|
Set log level at run time.
|
||||||
|
|
||||||
- level ([CodexLogLevel](./src/debug/types.ts#L3), required)
|
- level ([CodexLogLevel](./src/debug/types.ts#L7), required)
|
||||||
- returns Promise<"">
|
- returns Promise<"">
|
||||||
|
|
||||||
Example:
|
Example:
|
||||||
@ -423,7 +431,7 @@ await debug.setLogLevel("DEBUG");
|
|||||||
|
|
||||||
Gets node information
|
Gets node information
|
||||||
|
|
||||||
- returns Promise<[CodexDebugInfo](./src/debug/types.ts#L15)>
|
- returns Promise<[CodexDebugInfo](./src/debug/types.ts#L23)>
|
||||||
|
|
||||||
Example:
|
Example:
|
||||||
|
|
||||||
@ -448,10 +456,44 @@ const node = codex.node;
|
|||||||
|
|
||||||
Get Node's SPR
|
Get Node's SPR
|
||||||
|
|
||||||
- returns Promise<[CodexSpr](./src/node/types.ts#L1)>
|
- returns Promise<[CodexSpr](./src/node/types.ts#L11)>
|
||||||
|
|
||||||
Example:
|
Example:
|
||||||
|
|
||||||
```js
|
```js
|
||||||
const spr = await node.spr();
|
const spr = await node.spr();
|
||||||
```
|
```
|
||||||
|
|
||||||
|
By default, the response will be a json. You can use `text` option to get the string:
|
||||||
|
|
||||||
|
#### peeriD
|
||||||
|
|
||||||
|
Get Node's peer id
|
||||||
|
|
||||||
|
- returns Promise<[CodexPeerId](./src/node/types.ts#L25)>
|
||||||
|
|
||||||
|
Example:
|
||||||
|
|
||||||
|
```js
|
||||||
|
const peerId = await node.peerId();
|
||||||
|
```
|
||||||
|
|
||||||
|
By default, the response will be a json. You can use `text` option to get the string:
|
||||||
|
|
||||||
|
```js
|
||||||
|
const peerId = await node.peerId("text");
|
||||||
|
```
|
||||||
|
|
||||||
|
#### connect
|
||||||
|
|
||||||
|
Connect to a peer
|
||||||
|
|
||||||
|
- returns Promise<string>
|
||||||
|
|
||||||
|
Example:
|
||||||
|
|
||||||
|
```js
|
||||||
|
const peerId = "..."
|
||||||
|
const addrs = [...]
|
||||||
|
const spr = await node.connect(peerId, addrs);
|
||||||
|
```
|
||||||
|
|||||||
15
examples/upload-node/package-lock.json
generated
15
examples/upload-node/package-lock.json
generated
@ -10,7 +10,7 @@
|
|||||||
"license": "ISC",
|
"license": "ISC",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@codex-storage/sdk-js": "../..",
|
"@codex-storage/sdk-js": "../..",
|
||||||
"undici": "^7.6.0"
|
"undici": "^7.7.0"
|
||||||
},
|
},
|
||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
"prettier": "^3.5.3"
|
"prettier": "^3.5.3"
|
||||||
@ -24,11 +24,14 @@
|
|||||||
"version": "0.1.1",
|
"version": "0.1.1",
|
||||||
"license": "MIT",
|
"license": "MIT",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"valibot": "^0.32.0"
|
"undici": "^7.7.0",
|
||||||
|
"valibot": "^1.0.0"
|
||||||
},
|
},
|
||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
"@tsconfig/strictest": "^2.0.5",
|
"@tsconfig/strictest": "^2.0.5",
|
||||||
"@types/node": "^22.13.13",
|
"@types/node": "^22.13.17",
|
||||||
|
"oas-normalize": "^13.1.2",
|
||||||
|
"openapi-typescript": "^7.6.1",
|
||||||
"prettier": "^3.5.3",
|
"prettier": "^3.5.3",
|
||||||
"tsup": "^8.3.6",
|
"tsup": "^8.3.6",
|
||||||
"typescript": "^5.8.2",
|
"typescript": "^5.8.2",
|
||||||
@ -65,9 +68,9 @@
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/undici": {
|
"node_modules/undici": {
|
||||||
"version": "7.6.0",
|
"version": "7.7.0",
|
||||||
"resolved": "https://registry.npmjs.org/undici/-/undici-7.6.0.tgz",
|
"resolved": "https://registry.npmjs.org/undici/-/undici-7.7.0.tgz",
|
||||||
"integrity": "sha512-gaFsbThjrDGvAaD670r81RZro/s6H2PVZF640Qn0p5kZK+/rim7/mmyfp2W7VB5vOMaFM8vuFBJUaMlaZTYHlA==",
|
"integrity": "sha512-tZ6+5NBq4KH35rr46XJ2JPFKxfcBlYNaqLF/wyWIO9RMHqqU/gx/CLB1Y2qMcgB8lWw/bKHa7qzspqCN7mUHvA==",
|
||||||
"license": "MIT",
|
"license": "MIT",
|
||||||
"engines": {
|
"engines": {
|
||||||
"node": ">=20.18.1"
|
"node": ">=20.18.1"
|
||||||
|
|||||||
@ -2,15 +2,13 @@
|
|||||||
"name": "@codex-storage/sdk-js-update-node-example",
|
"name": "@codex-storage/sdk-js-update-node-example",
|
||||||
"version": "1.0.0",
|
"version": "1.0.0",
|
||||||
"main": "index.js",
|
"main": "index.js",
|
||||||
"scripts": {
|
"scripts": {},
|
||||||
"build": "node esbuild.js"
|
|
||||||
},
|
|
||||||
"author": "",
|
"author": "",
|
||||||
"license": "ISC",
|
"license": "ISC",
|
||||||
"description": "",
|
"description": "",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@codex-storage/sdk-js": "../..",
|
"@codex-storage/sdk-js": "../..",
|
||||||
"undici": "^7.6.0"
|
"undici": "^7.7.0"
|
||||||
},
|
},
|
||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
"prettier": "^3.5.3"
|
"prettier": "^3.5.3"
|
||||||
|
|||||||
1012
openapi.yaml
Normal file
1012
openapi.yaml
Normal file
File diff suppressed because it is too large
Load Diff
1142
package-lock.json
generated
1142
package-lock.json
generated
File diff suppressed because it is too large
Load Diff
@ -77,16 +77,18 @@
|
|||||||
},
|
},
|
||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
"@tsconfig/strictest": "^2.0.5",
|
"@tsconfig/strictest": "^2.0.5",
|
||||||
"@types/node": "^22.13.14",
|
"@types/node": "^22.13.17",
|
||||||
|
"oas-normalize": "^13.1.2",
|
||||||
|
"openapi-typescript": "^7.6.1",
|
||||||
"prettier": "^3.5.3",
|
"prettier": "^3.5.3",
|
||||||
"tsup": "^8.3.6",
|
"tsup": "^8.3.6",
|
||||||
"typescript": "^5.8.2",
|
"typescript": "^5.8.2",
|
||||||
"vitest": "^3.1.1"
|
"vitest": "^3.1.1"
|
||||||
},
|
},
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"valibot": "^0.32.0"
|
"valibot": "^1.0.0"
|
||||||
},
|
},
|
||||||
"peerDependencies": {
|
"peerDependencies": {
|
||||||
"undici": "^7.0.0"
|
"undici": "^7.7.0"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -7,11 +7,14 @@ import {
|
|||||||
import type { SafeValue } from "../values/values";
|
import type { SafeValue } from "../values/values";
|
||||||
import type {
|
import type {
|
||||||
CodexDataResponse,
|
CodexDataResponse,
|
||||||
CodexManifest,
|
|
||||||
CodexNodeSpace,
|
|
||||||
UploadStategy,
|
UploadStategy,
|
||||||
NetworkDownloadResponse,
|
|
||||||
UploadResponse,
|
UploadResponse,
|
||||||
|
CodexSpaceResponse,
|
||||||
|
CodexNodeSpace,
|
||||||
|
CodexDataNetworkResponse,
|
||||||
|
CodexNetworkDownload,
|
||||||
|
CodexManifest,
|
||||||
|
CodexDataItems,
|
||||||
} from "./types";
|
} from "./types";
|
||||||
|
|
||||||
type CodexDataOptions = {
|
type CodexDataOptions = {
|
||||||
@ -34,7 +37,7 @@ export class CodexData {
|
|||||||
* Lists manifest CIDs stored locally in node.
|
* Lists manifest CIDs stored locally in node.
|
||||||
* TODO: remove the faker data part when the api is ready
|
* TODO: remove the faker data part when the api is ready
|
||||||
*/
|
*/
|
||||||
cids(): Promise<SafeValue<CodexDataResponse>> {
|
cids(): Promise<SafeValue<CodexDataItems>> {
|
||||||
const url = this.url + Api.config.prefix + "/data";
|
const url = this.url + Api.config.prefix + "/data";
|
||||||
|
|
||||||
return Fetch.safeJson<CodexDataResponse>(url, {
|
return Fetch.safeJson<CodexDataResponse>(url, {
|
||||||
@ -52,10 +55,10 @@ export class CodexData {
|
|||||||
/**
|
/**
|
||||||
* Gets a summary of the storage space allocation of the node.
|
* Gets a summary of the storage space allocation of the node.
|
||||||
*/
|
*/
|
||||||
space() {
|
space(): Promise<SafeValue<CodexNodeSpace>> {
|
||||||
const url = this.url + Api.config.prefix + "/space";
|
const url = this.url + Api.config.prefix + "/space";
|
||||||
|
|
||||||
return Fetch.safeJson<CodexNodeSpace>(url, {
|
return Fetch.safeJson<CodexSpaceResponse>(url, {
|
||||||
method: "GET",
|
method: "GET",
|
||||||
headers: FetchAuthBuilder.build(this.auth),
|
headers: FetchAuthBuilder.build(this.auth),
|
||||||
});
|
});
|
||||||
@ -95,12 +98,10 @@ export class CodexData {
|
|||||||
* Download a file from the network to the local node if it's not available locally.
|
* Download a file from the network to the local node if it's not available locally.
|
||||||
* Note: Download is performed async. Call can return before download is completed.
|
* Note: Download is performed async. Call can return before download is completed.
|
||||||
*/
|
*/
|
||||||
async networkDownload(
|
async networkDownload(cid: string): Promise<SafeValue<CodexNetworkDownload>> {
|
||||||
cid: string
|
|
||||||
): Promise<SafeValue<NetworkDownloadResponse>> {
|
|
||||||
const url = this.url + Api.config.prefix + `/data/${cid}/network`;
|
const url = this.url + Api.config.prefix + `/data/${cid}/network`;
|
||||||
|
|
||||||
return Fetch.safeJson(url, {
|
return Fetch.safeJson<CodexDataNetworkResponse>(url, {
|
||||||
method: "POST",
|
method: "POST",
|
||||||
headers: FetchAuthBuilder.build(this.auth),
|
headers: FetchAuthBuilder.build(this.auth),
|
||||||
});
|
});
|
||||||
@ -123,7 +124,7 @@ export class CodexData {
|
|||||||
* Download only the dataset manifest from the network to the local node
|
* Download only the dataset manifest from the network to the local node
|
||||||
* if it's not available locally.
|
* if it's not available locally.
|
||||||
*/
|
*/
|
||||||
async fetchManifest(cid: string) {
|
async fetchManifest(cid: string): Promise<SafeValue<CodexManifest>> {
|
||||||
const url = this.url + Api.config.prefix + `/data/${cid}/network/manifest`;
|
const url = this.url + Api.config.prefix + `/data/${cid}/network/manifest`;
|
||||||
|
|
||||||
return Fetch.safeJson<CodexManifest>(url, {
|
return Fetch.safeJson<CodexManifest>(url, {
|
||||||
|
|||||||
@ -1,87 +1,33 @@
|
|||||||
|
import type { components, paths } from "../openapi";
|
||||||
import type { FetchAuth } from "../fetch-safe/fetch-safe";
|
import type { FetchAuth } from "../fetch-safe/fetch-safe";
|
||||||
import type { SafeValue } from "../values/values";
|
import type { SafeValue } from "../values/values";
|
||||||
|
|
||||||
export type CodexManifest = {
|
export type CodexDataResponse =
|
||||||
/**
|
paths["/data"]["get"]["responses"][200]["content"]["application/json"];
|
||||||
* "Root hash of the content"
|
|
||||||
*/
|
|
||||||
// rootHash: string;
|
|
||||||
|
|
||||||
/**
|
export type CodexDataItem = components["schemas"]["DataItem"];
|
||||||
* Length of original content in bytes
|
|
||||||
*/
|
|
||||||
// originalBytes: number;
|
|
||||||
|
|
||||||
/**
|
export type CodexDataItems = CodexDataResponse;
|
||||||
* Total size of all blocks
|
|
||||||
*/
|
|
||||||
datasetSize: number;
|
|
||||||
|
|
||||||
/**
|
export type CodexSpaceResponse =
|
||||||
* "Size of blocks"
|
paths["/space"]["get"]["responses"][200]["content"]["application/json"];
|
||||||
*/
|
|
||||||
blockSize: number;
|
|
||||||
|
|
||||||
/**
|
export type CodexNodeSpace = CodexSpaceResponse;
|
||||||
* Indicates if content is protected by erasure-coding
|
|
||||||
*/
|
|
||||||
protected: boolean;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Root of the merkle tree
|
|
||||||
*/
|
|
||||||
treeCid: string;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Name of the name
|
|
||||||
*/
|
|
||||||
filename: string | null;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Mimetype
|
|
||||||
*/
|
|
||||||
mimetype: string | null;
|
|
||||||
};
|
|
||||||
|
|
||||||
export type CodexDataContent = {
|
|
||||||
/**
|
|
||||||
* Content Identifier as specified at https://github.com/multiformats/cid
|
|
||||||
*/
|
|
||||||
cid: string;
|
|
||||||
|
|
||||||
manifest: CodexManifest;
|
|
||||||
};
|
|
||||||
|
|
||||||
export type CodexDataResponse = { content: CodexDataContent[] };
|
|
||||||
|
|
||||||
export type CodexNodeSpace = {
|
|
||||||
/**
|
|
||||||
* Number of blocks stored by the node
|
|
||||||
*/
|
|
||||||
totalBlocks: number;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Maximum storage space used by the node
|
|
||||||
*/
|
|
||||||
quotaMaxBytes: number;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Amount of storage space currently in use
|
|
||||||
*/
|
|
||||||
quotaUsedBytes: number;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Amount of storage space reserved
|
|
||||||
*/
|
|
||||||
quotaReservedBytes: number;
|
|
||||||
};
|
|
||||||
|
|
||||||
export type UploadResponse = {
|
export type UploadResponse = {
|
||||||
result: Promise<SafeValue<string>>;
|
result: Promise<SafeValue<string>>;
|
||||||
abort: () => void;
|
abort: () => void;
|
||||||
};
|
};
|
||||||
|
|
||||||
export type NetworkDownloadResponse = { cid: string; manifest: CodexManifest };
|
export type CodexDataNetworkResponse =
|
||||||
|
paths["/data/{cid}/network"]["post"]["responses"][200]["content"]["application/json"];
|
||||||
|
|
||||||
|
export type CodexNetworkDownload = components["schemas"]["DataItem"];
|
||||||
|
|
||||||
|
export type CodexFetchManifestResponse =
|
||||||
|
paths["/data/{cid}/network/manifest"]["get"]["responses"][200]["content"]["application/json"];
|
||||||
|
|
||||||
|
export type CodexManifest = CodexFetchManifestResponse;
|
||||||
|
|
||||||
export type UploadStategyOptions = {
|
export type UploadStategyOptions = {
|
||||||
auth?: FetchAuth;
|
auth?: FetchAuth;
|
||||||
|
|||||||
@ -6,7 +6,12 @@ import {
|
|||||||
type FetchAuth,
|
type FetchAuth,
|
||||||
} from "../fetch-safe/fetch-safe";
|
} from "../fetch-safe/fetch-safe";
|
||||||
import type { SafeValue } from "../values/values";
|
import type { SafeValue } from "../values/values";
|
||||||
import { CodexLogLevel, type CodexDebugInfo } from "./types";
|
import {
|
||||||
|
CodexLogLevelInput,
|
||||||
|
type CodexDebugInfo,
|
||||||
|
type CodexInfoResponse,
|
||||||
|
type CodexLogLevel,
|
||||||
|
} from "./types";
|
||||||
import * as v from "valibot";
|
import * as v from "valibot";
|
||||||
|
|
||||||
type CodexDebugOptions = {
|
type CodexDebugOptions = {
|
||||||
@ -28,8 +33,8 @@ export class CodexDebug {
|
|||||||
/**
|
/**
|
||||||
* Set log level at run time
|
* Set log level at run time
|
||||||
*/
|
*/
|
||||||
async setLogLevel(level: CodexLogLevel): Promise<SafeValue<"">> {
|
async setLogLevel(level: CodexLogLevel): Promise<SafeValue<string>> {
|
||||||
const result = v.safeParse(CodexLogLevel, level);
|
const result = v.safeParse(CodexLogLevelInput, level);
|
||||||
|
|
||||||
if (!result.success) {
|
if (!result.success) {
|
||||||
return Promise.resolve({
|
return Promise.resolve({
|
||||||
@ -46,26 +51,20 @@ export class CodexDebug {
|
|||||||
"/debug/chronicles/loglevel?level=" +
|
"/debug/chronicles/loglevel?level=" +
|
||||||
level;
|
level;
|
||||||
|
|
||||||
const res = await Fetch.safe(url, {
|
return Fetch.safeText(url, {
|
||||||
method: "POST",
|
method: "POST",
|
||||||
headers: FetchAuthBuilder.build(this.auth),
|
headers: FetchAuthBuilder.build(this.auth),
|
||||||
body: "",
|
body: "",
|
||||||
});
|
});
|
||||||
|
|
||||||
if (res.error) {
|
|
||||||
return res;
|
|
||||||
}
|
|
||||||
|
|
||||||
return { error: false, data: "" };
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Gets node information
|
* Gets node information
|
||||||
*/
|
*/
|
||||||
info() {
|
info(): Promise<SafeValue<CodexDebugInfo>> {
|
||||||
const url = this.url + Api.config.prefix + `/debug/info`;
|
const url = this.url + Api.config.prefix + `/debug/info`;
|
||||||
|
|
||||||
return Fetch.safeJson<CodexDebugInfo>(url, {
|
return Fetch.safeJson<CodexInfoResponse>(url, {
|
||||||
method: "GET",
|
method: "GET",
|
||||||
headers: FetchAuthBuilder.build(this.auth),
|
headers: FetchAuthBuilder.build(this.auth),
|
||||||
});
|
});
|
||||||
|
|||||||
@ -1,6 +1,13 @@
|
|||||||
import * as v from "valibot";
|
import * as v from "valibot";
|
||||||
|
import type { paths } from "../openapi";
|
||||||
|
|
||||||
export const CodexLogLevel = v.picklist([
|
export type CodexLogLevelResponse =
|
||||||
|
paths["/debug/chronicles/loglevel"]["post"]["responses"][200]["content"];
|
||||||
|
|
||||||
|
export type CodexLogLevel =
|
||||||
|
paths["/debug/chronicles/loglevel"]["post"]["parameters"]["query"]["level"];
|
||||||
|
|
||||||
|
export const CodexLogLevelInput = v.picklist([
|
||||||
"TRACE",
|
"TRACE",
|
||||||
"DEBUG",
|
"DEBUG",
|
||||||
"INFO",
|
"INFO",
|
||||||
@ -10,49 +17,7 @@ export const CodexLogLevel = v.picklist([
|
|||||||
"FATAL",
|
"FATAL",
|
||||||
]);
|
]);
|
||||||
|
|
||||||
export type CodexLogLevel = v.InferOutput<typeof CodexLogLevel>;
|
export type CodexInfoResponse =
|
||||||
|
paths["/debug/info"]["get"]["responses"][200]["content"]["application/json"];
|
||||||
|
|
||||||
export type CodexDebugInfo = {
|
export type CodexDebugInfo = CodexInfoResponse;
|
||||||
/**
|
|
||||||
* Peer Identity reference as specified at https://docs.libp2p.io/concepts/fundamentals/peers/
|
|
||||||
*/
|
|
||||||
id: string;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Address of node as specified by the multi-address specification https://multiformats.io/multiaddr/
|
|
||||||
*/
|
|
||||||
addrs: string[];
|
|
||||||
|
|
||||||
announceAddresses: string[]
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Path of the data repository where all nodes data are stored
|
|
||||||
*/
|
|
||||||
repo: string;
|
|
||||||
|
|
||||||
// Signed Peer Record (libp2p)
|
|
||||||
spr: string;
|
|
||||||
|
|
||||||
table: {
|
|
||||||
localNode: {
|
|
||||||
nodeId: string
|
|
||||||
peerId: string
|
|
||||||
record: string
|
|
||||||
address: string
|
|
||||||
seen: boolean
|
|
||||||
}
|
|
||||||
|
|
||||||
nodes: {
|
|
||||||
nodeId: string
|
|
||||||
peerId: string
|
|
||||||
record: string
|
|
||||||
address: string
|
|
||||||
seen: boolean
|
|
||||||
}[]
|
|
||||||
}
|
|
||||||
|
|
||||||
codex: {
|
|
||||||
version: string
|
|
||||||
revision: string
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|||||||
@ -60,4 +60,14 @@ export const Fetch = {
|
|||||||
|
|
||||||
return Promises.safe(() => res.data.json());
|
return Promises.safe(() => res.data.json());
|
||||||
},
|
},
|
||||||
|
|
||||||
|
async safeText(url: string, init: RequestInit): Promise<SafeValue<string>> {
|
||||||
|
const res = await this.safe(url, init);
|
||||||
|
|
||||||
|
if (res.error) {
|
||||||
|
return res;
|
||||||
|
}
|
||||||
|
|
||||||
|
return Promises.safe(() => res.data.text());
|
||||||
|
},
|
||||||
};
|
};
|
||||||
|
|||||||
@ -104,10 +104,12 @@ function minNumberValidationError(field: string, min: number) {
|
|||||||
function createAvailability() {
|
function createAvailability() {
|
||||||
return {
|
return {
|
||||||
id: randomEthereumAddress(),
|
id: randomEthereumAddress(),
|
||||||
totalSize: randomInt(0, 9).toString(),
|
totalSize: randomInt(0, 9),
|
||||||
duration: randomInt(0, 9).toString(),
|
duration: randomInt(0, 9),
|
||||||
minPrice: randomInt(0, 9).toString(),
|
minPrice: randomInt(0, 9),
|
||||||
maxCollateral: randomInt(0, 9).toString(),
|
minPricePerBytePerSecond: randomInt(0, 9),
|
||||||
|
totalCollateral: randomInt(0, 900),
|
||||||
|
totalRemainingCollateral: randomInt(0, 900),
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -210,7 +212,7 @@ describe("marketplace", () => {
|
|||||||
});
|
});
|
||||||
|
|
||||||
it("returns a response when the request succeed", async () => {
|
it("returns a response when the request succeed", async () => {
|
||||||
const data = { ...createAvailability(), freeSize: "1000" };
|
const data = { ...createAvailability(), freeSize: 1000 };
|
||||||
|
|
||||||
const spy = vi.spyOn(Fetch, "safeJson");
|
const spy = vi.spyOn(Fetch, "safeJson");
|
||||||
spy.mockImplementationOnce(() => Promise.resolve({ error: false, data }));
|
spy.mockImplementationOnce(() => Promise.resolve({ error: false, data }));
|
||||||
@ -228,16 +230,16 @@ describe("marketplace", () => {
|
|||||||
});
|
});
|
||||||
|
|
||||||
it("returns a response when the create availability succeed", async () => {
|
it("returns a response when the create availability succeed", async () => {
|
||||||
const data = { ...createAvailability(), freeSize: "1000" };
|
const data = { ...createAvailability(), freeSize: 1000 };
|
||||||
|
|
||||||
const spy = vi.spyOn(Fetch, "safeJson");
|
const spy = vi.spyOn(Fetch, "safeJson");
|
||||||
spy.mockImplementationOnce(() => Promise.resolve({ error: false, data }));
|
spy.mockImplementationOnce(() => Promise.resolve({ error: false, data }));
|
||||||
|
|
||||||
const response = await marketplace.createAvailability({
|
const response = await marketplace.createAvailability({
|
||||||
totalCollateral: 1,
|
totalCollateral: data.totalCollateral,
|
||||||
totalSize: 3000,
|
totalSize: data.totalSize,
|
||||||
minPricePerBytePerSecond: 100,
|
minPricePerBytePerSecond: data.minPricePerBytePerSecond,
|
||||||
duration: 100,
|
duration: data.duration,
|
||||||
});
|
});
|
||||||
|
|
||||||
assert.ok(!response.error);
|
assert.ok(!response.error);
|
||||||
|
|||||||
@ -8,16 +8,27 @@ import {
|
|||||||
} from "../fetch-safe/fetch-safe";
|
} from "../fetch-safe/fetch-safe";
|
||||||
import type { SafeValue } from "../values/values";
|
import type { SafeValue } from "../values/values";
|
||||||
import {
|
import {
|
||||||
|
type CodexAvailabilityResponse,
|
||||||
type CodexAvailability,
|
type CodexAvailability,
|
||||||
|
type CodexSlot,
|
||||||
|
type CodexSlotAgent,
|
||||||
|
type CodexSlotResponse,
|
||||||
|
type CodexSlotAgentResponse,
|
||||||
|
type CodexAvailabilityWithoutTypes,
|
||||||
type CodexAvailabilityCreateResponse,
|
type CodexAvailabilityCreateResponse,
|
||||||
type CodexAvailabilityDto,
|
type CodexAvailabilityCreateBody,
|
||||||
|
CodexAvailabilityPatchInput,
|
||||||
|
type CodexReservationsResponse,
|
||||||
|
type CodexPurchaseIdsResponse,
|
||||||
|
type CodexPurchaseResponse,
|
||||||
|
type CodexPurchase,
|
||||||
|
type CodexStorageRequestCreateBody,
|
||||||
|
type CodexReservation,
|
||||||
|
type CodexPurchaseWithoutTypes,
|
||||||
|
} from "./types";
|
||||||
|
import {
|
||||||
CodexCreateAvailabilityInput,
|
CodexCreateAvailabilityInput,
|
||||||
CodexCreateStorageRequestInput,
|
CodexCreateStorageRequestInput,
|
||||||
type CodexPurchase,
|
|
||||||
type CodexReservation,
|
|
||||||
type CodexSlot,
|
|
||||||
type CodexStorageRequest,
|
|
||||||
CodexUpdateAvailabilityInput,
|
|
||||||
} from "./types";
|
} from "./types";
|
||||||
|
|
||||||
type CodexMarketplaceOptions = {
|
type CodexMarketplaceOptions = {
|
||||||
@ -42,7 +53,7 @@ export class CodexMarketplace {
|
|||||||
async activeSlots(): Promise<SafeValue<CodexSlot[]>> {
|
async activeSlots(): Promise<SafeValue<CodexSlot[]>> {
|
||||||
const url = this.url + Api.config.prefix + "/sales/slots";
|
const url = this.url + Api.config.prefix + "/sales/slots";
|
||||||
|
|
||||||
return Fetch.safeJson<CodexSlot[]>(url, {
|
return Fetch.safeJson<CodexSlotResponse[]>(url, {
|
||||||
method: "GET",
|
method: "GET",
|
||||||
headers: FetchAuthBuilder.build(this.auth),
|
headers: FetchAuthBuilder.build(this.auth),
|
||||||
});
|
});
|
||||||
@ -51,22 +62,40 @@ export class CodexMarketplace {
|
|||||||
/**
|
/**
|
||||||
* Returns active slot with id {slotId} for the host
|
* Returns active slot with id {slotId} for the host
|
||||||
*/
|
*/
|
||||||
async activeSlot(slotId: string): Promise<SafeValue<CodexSlot>> {
|
async activeSlot(slotId: string): Promise<SafeValue<CodexSlotAgent>> {
|
||||||
const url = this.url + Api.config.prefix + "/sales/slots/" + slotId;
|
const url = this.url + Api.config.prefix + "/sales/slots/" + slotId;
|
||||||
|
|
||||||
return Fetch.safeJson<CodexSlot>(url, {
|
return Fetch.safeJson<CodexSlotAgentResponse>(url, {
|
||||||
method: "GET",
|
method: "GET",
|
||||||
headers: FetchAuthBuilder.build(this.auth),
|
headers: FetchAuthBuilder.build(this.auth),
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private transformAvailability({
|
||||||
|
freeSize,
|
||||||
|
...a
|
||||||
|
}: CodexAvailabilityWithoutTypes) {
|
||||||
|
const availability: CodexAvailability = {
|
||||||
|
...a,
|
||||||
|
minPricePerBytePerSecond: parseInt(a.minPricePerBytePerSecond, 10),
|
||||||
|
totalCollateral: parseInt(a.totalCollateral, 10),
|
||||||
|
totalRemainingCollateral: parseInt(a.totalRemainingCollateral, 10),
|
||||||
|
};
|
||||||
|
|
||||||
|
if (freeSize) {
|
||||||
|
availability.freeSize = freeSize;
|
||||||
|
}
|
||||||
|
|
||||||
|
return availability;
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Returns storage that is for sale
|
* Returns storage that is for sale
|
||||||
*/
|
*/
|
||||||
async availabilities(): Promise<SafeValue<CodexAvailability[]>> {
|
async availabilities(): Promise<SafeValue<CodexAvailability[]>> {
|
||||||
const url = this.url + Api.config.prefix + "/sales/availability";
|
const url = this.url + Api.config.prefix + "/sales/availability";
|
||||||
|
|
||||||
const res = await Fetch.safeJson<CodexAvailabilityDto[]>(url, {
|
const res = await Fetch.safeJson<CodexAvailabilityResponse>(url, {
|
||||||
method: "GET",
|
method: "GET",
|
||||||
headers: FetchAuthBuilder.build(this.auth),
|
headers: FetchAuthBuilder.build(this.auth),
|
||||||
});
|
});
|
||||||
@ -77,15 +106,7 @@ export class CodexMarketplace {
|
|||||||
|
|
||||||
return {
|
return {
|
||||||
error: false,
|
error: false,
|
||||||
data: res.data.map((a) => ({
|
data: res.data.map(this.transformAvailability),
|
||||||
id: a.id,
|
|
||||||
totalSize: parseInt(a.totalSize, 10),
|
|
||||||
freeSize: parseInt(a.freeSize, 10),
|
|
||||||
duration: parseInt(a.duration, 10),
|
|
||||||
minPricePerBytePerSecond: parseInt(a.minPricePerBytePerSecond, 10),
|
|
||||||
totalCollateral: parseInt(a.totalCollateral, 10),
|
|
||||||
totalRemainingCollateral: parseInt(a.totalRemainingCollateral, 10),
|
|
||||||
})),
|
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -94,7 +115,7 @@ export class CodexMarketplace {
|
|||||||
*/
|
*/
|
||||||
async createAvailability(
|
async createAvailability(
|
||||||
input: CodexCreateAvailabilityInput
|
input: CodexCreateAvailabilityInput
|
||||||
): Promise<SafeValue<CodexAvailabilityCreateResponse>> {
|
): Promise<SafeValue<CodexAvailability>> {
|
||||||
const result = v.safeParse(CodexCreateAvailabilityInput, input);
|
const result = v.safeParse(CodexCreateAvailabilityInput, input);
|
||||||
|
|
||||||
if (!result.success) {
|
if (!result.success) {
|
||||||
@ -108,17 +129,32 @@ export class CodexMarketplace {
|
|||||||
|
|
||||||
const url = this.url + Api.config.prefix + "/sales/availability";
|
const url = this.url + Api.config.prefix + "/sales/availability";
|
||||||
|
|
||||||
const body = result.output;
|
const body: CodexAvailabilityCreateBody = {
|
||||||
|
totalSize: result.output.totalSize,
|
||||||
|
duration: result.output.duration,
|
||||||
|
minPricePerBytePerSecond:
|
||||||
|
result.output.minPricePerBytePerSecond.toString(),
|
||||||
|
totalCollateral: result.output.totalCollateral.toString(),
|
||||||
|
};
|
||||||
|
|
||||||
|
if (result.output.enabled) {
|
||||||
|
body.enabled = result.output.enabled;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (result.output.until) {
|
||||||
|
body.until = result.output.until;
|
||||||
|
}
|
||||||
|
|
||||||
return Fetch.safeJson<CodexAvailabilityCreateResponse>(url, {
|
return Fetch.safeJson<CodexAvailabilityCreateResponse>(url, {
|
||||||
method: "POST",
|
method: "POST",
|
||||||
headers: FetchAuthBuilder.build(this.auth),
|
headers: FetchAuthBuilder.build(this.auth),
|
||||||
body: JSON.stringify({
|
body: JSON.stringify(body),
|
||||||
totalSize: body.totalSize.toString(),
|
}).then((result) => {
|
||||||
duration: body.duration.toString(),
|
if (result.error) {
|
||||||
minPricePerBytePerSecond: body.minPricePerBytePerSecond.toString(),
|
return result;
|
||||||
totalCollateral: body.totalCollateral.toString(),
|
}
|
||||||
}),
|
|
||||||
|
return { error: false, data: this.transformAvailability(result.data) };
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -127,9 +163,9 @@ export class CodexMarketplace {
|
|||||||
* Existing Requests linked to this Availability will continue as is.
|
* Existing Requests linked to this Availability will continue as is.
|
||||||
*/
|
*/
|
||||||
async updateAvailability(
|
async updateAvailability(
|
||||||
input: CodexUpdateAvailabilityInput
|
input: CodexAvailabilityPatchInput
|
||||||
): Promise<SafeValue<"">> {
|
): Promise<SafeValue<"">> {
|
||||||
const result = v.safeParse(CodexUpdateAvailabilityInput, input);
|
const result = v.safeParse(CodexAvailabilityPatchInput, input);
|
||||||
|
|
||||||
if (!result.success) {
|
if (!result.success) {
|
||||||
return {
|
return {
|
||||||
@ -143,17 +179,26 @@ export class CodexMarketplace {
|
|||||||
const url =
|
const url =
|
||||||
this.url + Api.config.prefix + "/sales/availability/" + result.output.id;
|
this.url + Api.config.prefix + "/sales/availability/" + result.output.id;
|
||||||
|
|
||||||
const body = result.output;
|
const body: CodexAvailabilityCreateBody = {
|
||||||
|
totalSize: result.output.totalSize,
|
||||||
|
duration: result.output.duration,
|
||||||
|
minPricePerBytePerSecond:
|
||||||
|
result.output.minPricePerBytePerSecond.toString(),
|
||||||
|
totalCollateral: result.output.totalCollateral.toString(),
|
||||||
|
};
|
||||||
|
|
||||||
|
if (result.output.enabled) {
|
||||||
|
body.enabled = result.output.enabled;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (result.output.until) {
|
||||||
|
body.until = result.output.until;
|
||||||
|
}
|
||||||
|
|
||||||
const res = await Fetch.safe(url, {
|
const res = await Fetch.safe(url, {
|
||||||
method: "PATCH",
|
method: "PATCH",
|
||||||
headers: FetchAuthBuilder.build(this.auth),
|
headers: FetchAuthBuilder.build(this.auth),
|
||||||
body: JSON.stringify({
|
body: JSON.stringify(body),
|
||||||
totalSize: body.totalSize.toString(),
|
|
||||||
duration: body.duration.toString(),
|
|
||||||
minPricePerBytePerSecond: body.minPricePerBytePerSecond.toString(),
|
|
||||||
totalCollateral: body.totalCollateral.toString(),
|
|
||||||
}),
|
|
||||||
});
|
});
|
||||||
|
|
||||||
if (res.error) {
|
if (res.error) {
|
||||||
@ -174,7 +219,7 @@ export class CodexMarketplace {
|
|||||||
Api.config.prefix +
|
Api.config.prefix +
|
||||||
`/sales/availability/${availabilityId}/reservations`;
|
`/sales/availability/${availabilityId}/reservations`;
|
||||||
|
|
||||||
return Fetch.safeJson<CodexReservation[]>(url, {
|
return Fetch.safeJson<CodexReservationsResponse>(url, {
|
||||||
method: "GET",
|
method: "GET",
|
||||||
headers: FetchAuthBuilder.build(this.auth),
|
headers: FetchAuthBuilder.build(this.auth),
|
||||||
});
|
});
|
||||||
@ -183,22 +228,47 @@ export class CodexMarketplace {
|
|||||||
/**
|
/**
|
||||||
* Returns list of purchase IDs
|
* Returns list of purchase IDs
|
||||||
*/
|
*/
|
||||||
async purchaseIds(): Promise<SafeValue<string[]>> {
|
async purchaseIds(): Promise<SafeValue<CodexPurchaseIdsResponse>> {
|
||||||
const url = this.url + Api.config.prefix + `/storage/purchases`;
|
const url = this.url + Api.config.prefix + `/storage/purchases`;
|
||||||
|
|
||||||
return Fetch.safeJson<string[]>(url, {
|
return Fetch.safeJson<CodexPurchaseIdsResponse>(url, {
|
||||||
method: "GET",
|
method: "GET",
|
||||||
headers: FetchAuthBuilder.build(this.auth),
|
headers: FetchAuthBuilder.build(this.auth),
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
async purchases(): Promise<SafeValue<CodexPurchase[]>> {
|
private transformPurchase(p: CodexPurchaseWithoutTypes): CodexPurchase {
|
||||||
const url = this.url + Api.config.prefix + `/storage/purchases`;
|
const purchase: CodexPurchase = {
|
||||||
|
requestId: p.requestId,
|
||||||
|
state: p.state,
|
||||||
|
};
|
||||||
|
|
||||||
const res = await Fetch.safeJson<string[]>(url, {
|
if (p.error) {
|
||||||
method: "GET",
|
purchase.error = p.error;
|
||||||
headers: FetchAuthBuilder.build(this.auth),
|
}
|
||||||
});
|
|
||||||
|
if (!p.request) {
|
||||||
|
return purchase;
|
||||||
|
}
|
||||||
|
|
||||||
|
return {
|
||||||
|
...purchase,
|
||||||
|
request: {
|
||||||
|
...p.request,
|
||||||
|
ask: {
|
||||||
|
...p.request.ask,
|
||||||
|
proofProbability: parseInt(p.request.ask.proofProbability, 10),
|
||||||
|
pricePerBytePerSecond: parseInt(
|
||||||
|
p.request.ask.pricePerBytePerSecond,
|
||||||
|
10
|
||||||
|
),
|
||||||
|
},
|
||||||
|
},
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
async purchases(): Promise<SafeValue<CodexPurchase[]>> {
|
||||||
|
const res = await this.purchaseIds();
|
||||||
|
|
||||||
if (res.error) {
|
if (res.error) {
|
||||||
return res;
|
return res;
|
||||||
@ -220,7 +290,6 @@ export class CodexMarketplace {
|
|||||||
state: "error",
|
state: "error",
|
||||||
error: p.data.message,
|
error: p.data.message,
|
||||||
requestId: "",
|
requestId: "",
|
||||||
request: {} as CodexStorageRequest,
|
|
||||||
} satisfies CodexPurchase)
|
} satisfies CodexPurchase)
|
||||||
: p.data
|
: p.data
|
||||||
),
|
),
|
||||||
@ -234,9 +303,15 @@ export class CodexMarketplace {
|
|||||||
const url =
|
const url =
|
||||||
this.url + Api.config.prefix + `/storage/purchases/` + purchaseId;
|
this.url + Api.config.prefix + `/storage/purchases/` + purchaseId;
|
||||||
|
|
||||||
return Fetch.safeJson<CodexPurchase>(url, {
|
return Fetch.safeJson<CodexPurchaseResponse>(url, {
|
||||||
method: "GET",
|
|
||||||
headers: FetchAuthBuilder.build(this.auth),
|
headers: FetchAuthBuilder.build(this.auth),
|
||||||
|
method: "GET",
|
||||||
|
}).then((res) => {
|
||||||
|
if (res.error) {
|
||||||
|
return res;
|
||||||
|
}
|
||||||
|
|
||||||
|
return { error: false, data: this.transformPurchase(res.data) };
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -269,24 +344,18 @@ export class CodexMarketplace {
|
|||||||
} = result.output;
|
} = result.output;
|
||||||
const url = this.url + Api.config.prefix + "/storage/request/" + cid;
|
const url = this.url + Api.config.prefix + "/storage/request/" + cid;
|
||||||
|
|
||||||
const res = await Fetch.safe(url, {
|
return Fetch.safeText(url, {
|
||||||
method: "POST",
|
method: "POST",
|
||||||
headers: FetchAuthBuilder.build(this.auth),
|
headers: FetchAuthBuilder.build(this.auth),
|
||||||
body: JSON.stringify({
|
body: JSON.stringify({
|
||||||
duration: duration.toString(),
|
duration,
|
||||||
pricePerBytePerSecond: pricePerBytePerSecond.toString(),
|
pricePerBytePerSecond: pricePerBytePerSecond.toString(),
|
||||||
proofProbability: proofProbability.toString(),
|
proofProbability: proofProbability.toString(),
|
||||||
nodes,
|
nodes,
|
||||||
collateralPerByte: collateralPerByte.toString(),
|
collateralPerByte: collateralPerByte.toString(),
|
||||||
expiry: expiry.toString(),
|
expiry,
|
||||||
tolerance,
|
tolerance,
|
||||||
}),
|
} satisfies CodexStorageRequestCreateBody),
|
||||||
});
|
});
|
||||||
|
|
||||||
if (res.error) {
|
|
||||||
return res;
|
|
||||||
}
|
|
||||||
|
|
||||||
return { error: false, data: await res.data.text() };
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -1,232 +1,122 @@
|
|||||||
|
import type { components, paths } from "../openapi";
|
||||||
import * as v from "valibot";
|
import * as v from "valibot";
|
||||||
|
|
||||||
export type CodexStorageRequest = {
|
export type CodexSlotResponse =
|
||||||
id: string;
|
paths["/sales/slots"]["get"]["responses"][200]["content"]["application/json"];
|
||||||
|
|
||||||
/**
|
export type CodexSlot = CodexSlotResponse;
|
||||||
* Address of Ethereum address
|
|
||||||
*/
|
|
||||||
client: string;
|
|
||||||
|
|
||||||
ask: {
|
export type CodexSlotAgentResponse =
|
||||||
/**
|
paths["/sales/slots/{slotId}"]["get"]["responses"][200]["content"]["application/json"];
|
||||||
* Number of slots that the tequest want to have the content spread over.
|
|
||||||
*/
|
|
||||||
slots: number;
|
|
||||||
|
|
||||||
/**
|
export type CodexSlotAgent = CodexSlotAgentResponse;
|
||||||
* Amount of storage per slot (in bytes) as decimal string.
|
|
||||||
*/
|
|
||||||
slotSize: string;
|
|
||||||
|
|
||||||
/**
|
export type CodexAvailabilityResponse =
|
||||||
* The duration of the storage request in seconds.
|
paths["/sales/availability"]["get"]["responses"][200]["content"]["application/json"];
|
||||||
*/
|
|
||||||
duration: string;
|
|
||||||
|
|
||||||
/**
|
export type CodexAvailabilityWithoutTypes =
|
||||||
* How often storage proofs are required as decimal string (in periods).
|
components["schemas"]["SalesAvailabilityREAD"];
|
||||||
*/
|
|
||||||
proofProbability: string;
|
|
||||||
|
|
||||||
/**
|
export type CodexAvailability = Omit<
|
||||||
* The amount of tokens paid per byte per second per slot to hosts the client is willing to pay
|
CodexAvailabilityWithoutTypes,
|
||||||
*/
|
| "freeSize"
|
||||||
pricePerBytePerSecond: string;
|
| "totalSize"
|
||||||
|
| "minPricePerBytePerSecond"
|
||||||
/**
|
| "duration"
|
||||||
* Max slots that can be lost without data considered to be lost.
|
| "totalCollateral"
|
||||||
*/
|
| "totalRemainingCollateral"
|
||||||
maxSlotLoss: number;
|
> & {
|
||||||
};
|
freeSize?: number;
|
||||||
|
|
||||||
content: {
|
|
||||||
/**
|
|
||||||
* Unique Content ID
|
|
||||||
*/
|
|
||||||
cid: string;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Erasure code parameters
|
|
||||||
*/
|
|
||||||
// erasure: {
|
|
||||||
/**
|
|
||||||
* Total number of chunks generated by the erasure code process.
|
|
||||||
*/
|
|
||||||
// totalChunks: number;
|
|
||||||
// };
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Parameters for Proof of Retrievability
|
|
||||||
*/
|
|
||||||
// por: {
|
|
||||||
// u: string;
|
|
||||||
// publicKey: string;
|
|
||||||
// name: string;
|
|
||||||
// };
|
|
||||||
};
|
|
||||||
|
|
||||||
/* Number as decimal string that represents expiry threshold in seconds from when the Request is submitted.
|
|
||||||
* When the threshold is reached and the Request does not find requested amount of nodes to host the data, the Request is voided.
|
|
||||||
* The number of seconds can not be higher then the Request's duration itself.
|
|
||||||
*/
|
|
||||||
expiry: string;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Random data
|
|
||||||
*/
|
|
||||||
nonce: string;
|
|
||||||
};
|
|
||||||
|
|
||||||
/**
|
|
||||||
* A storage slot is a portion of a storage contract that needs to be fulfilled
|
|
||||||
* by a host. To initiate a contract, all the slots must be filled.
|
|
||||||
*/
|
|
||||||
export type CodexSlot = {
|
|
||||||
id: string;
|
|
||||||
|
|
||||||
request: CodexStorageRequest;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* The slot index as hexadecimal string
|
|
||||||
*/
|
|
||||||
slotIndex: "string";
|
|
||||||
};
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Storage availability for sell.
|
|
||||||
*/
|
|
||||||
export type CodexAvailability = {
|
|
||||||
id: string;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Size of available storage in bytes
|
|
||||||
*/
|
|
||||||
totalSize: number;
|
totalSize: number;
|
||||||
|
|
||||||
/**
|
|
||||||
* Unused size of availability's storage in bytes as decimal string
|
|
||||||
*/
|
|
||||||
freeSize: number;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Maximum time the storage should be sold for (in seconds)
|
|
||||||
*/
|
|
||||||
duration: number;
|
duration: number;
|
||||||
|
|
||||||
/**
|
|
||||||
* Minimal price per byte per second paid (in amount of tokens) for the
|
|
||||||
* hosted request's slot for the request's duration as decimal string
|
|
||||||
*/
|
|
||||||
minPricePerBytePerSecond: number;
|
minPricePerBytePerSecond: number;
|
||||||
|
|
||||||
/**
|
|
||||||
* Total collateral (in amount of tokens) that can be used for matching requests
|
|
||||||
*/
|
|
||||||
totalCollateral: number;
|
totalCollateral: number;
|
||||||
|
|
||||||
totalRemainingCollateral: number;
|
totalRemainingCollateral: number;
|
||||||
};
|
};
|
||||||
|
|
||||||
/**
|
export type CodexAvailabilityCreateResponse =
|
||||||
* Storage availability received from the api.
|
paths["/sales/availability"]["post"]["responses"][201]["content"]["application/json"];
|
||||||
*/
|
|
||||||
export type CodexAvailabilityDto = {
|
|
||||||
id: string;
|
|
||||||
|
|
||||||
/**
|
export type CodexAvailabilityCreateBody = Exclude<
|
||||||
* Size of available storage in bytes
|
paths["/sales/availability"]["post"]["requestBody"],
|
||||||
*/
|
undefined
|
||||||
totalSize: string;
|
>["content"]["application/json"];
|
||||||
|
|
||||||
/**
|
|
||||||
* Unused size of availability's storage in bytes as decimal string
|
|
||||||
*/
|
|
||||||
freeSize: string;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Maximum time the storage should be sold for (in seconds)
|
|
||||||
*/
|
|
||||||
duration: string;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Minimal price per byte per second paid (in amount of tokens) for the
|
|
||||||
* hosted request's slot for the request's duration as decimal string
|
|
||||||
*/
|
|
||||||
minPricePerBytePerSecond: string;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Total collateral (in amount of tokens) that can be used for matching requests
|
|
||||||
*/
|
|
||||||
totalCollateral: string;
|
|
||||||
|
|
||||||
totalRemainingCollateral: string;
|
|
||||||
};
|
|
||||||
|
|
||||||
export type CodexAvailabilityCreateResponse = CodexAvailability & {
|
|
||||||
id: string;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Unused size of availability's storage in bytes as decimal string
|
|
||||||
*/
|
|
||||||
freeSize: string;
|
|
||||||
};
|
|
||||||
|
|
||||||
export const CodexCreateAvailabilityInput = v.strictObject({
|
export const CodexCreateAvailabilityInput = v.strictObject({
|
||||||
totalSize: v.pipe(v.number(), v.minValue(1)),
|
totalSize: v.pipe(v.number(), v.minValue(1)),
|
||||||
duration: v.pipe(v.number(), v.minValue(1)),
|
duration: v.pipe(v.number(), v.minValue(1)),
|
||||||
minPricePerBytePerSecond: v.number(),
|
minPricePerBytePerSecond: v.number(),
|
||||||
totalCollateral: v.number(),
|
totalCollateral: v.number(),
|
||||||
|
enabled: v.optional(v.boolean()),
|
||||||
|
until: v.optional(v.number()),
|
||||||
});
|
});
|
||||||
|
|
||||||
|
export type CodexAvailabilityPatchResponse =
|
||||||
|
paths["/sales/availability/{id}"]["patch"]["responses"][204]["content"];
|
||||||
|
|
||||||
|
export type CodexAvailabilityPatchBody = Exclude<
|
||||||
|
paths["/sales/availability"]["post"]["requestBody"],
|
||||||
|
undefined
|
||||||
|
>["content"]["application/json"];
|
||||||
|
|
||||||
export type CodexCreateAvailabilityInput = v.InferOutput<
|
export type CodexCreateAvailabilityInput = v.InferOutput<
|
||||||
typeof CodexCreateAvailabilityInput
|
typeof CodexCreateAvailabilityInput
|
||||||
>;
|
>;
|
||||||
|
|
||||||
export const CodexUpdateAvailabilityInput = v.strictObject({
|
export const CodexAvailabilityPatchInput = v.strictObject({
|
||||||
id: v.string(),
|
id: v.string(),
|
||||||
totalSize: v.pipe(v.number(), v.minValue(1)),
|
totalSize: v.pipe(v.number(), v.minValue(1)),
|
||||||
duration: v.pipe(v.number(), v.minValue(1)),
|
duration: v.pipe(v.number(), v.minValue(1)),
|
||||||
minPricePerBytePerSecond: v.number(),
|
minPricePerBytePerSecond: v.number(),
|
||||||
totalCollateral: v.number(),
|
totalCollateral: v.number(),
|
||||||
|
enabled: v.optional(v.boolean()),
|
||||||
|
until: v.optional(v.number()),
|
||||||
});
|
});
|
||||||
|
|
||||||
export type CodexUpdateAvailabilityInput = v.InferOutput<
|
export type CodexAvailabilityPatchInput = v.InferOutput<
|
||||||
typeof CodexUpdateAvailabilityInput
|
typeof CodexAvailabilityPatchInput
|
||||||
>;
|
>;
|
||||||
|
|
||||||
export type CodexReservation = {
|
export type CodexReservationsResponse =
|
||||||
id: string;
|
paths["/sales/availability/{id}/reservations"]["get"]["responses"][200]["content"]["application/json"];
|
||||||
availabilityId: string;
|
|
||||||
requestId: string;
|
|
||||||
|
|
||||||
/**
|
export type CodexReservation = components["schemas"]["Reservation"];
|
||||||
* Size in bytes
|
|
||||||
*/
|
|
||||||
size: string;
|
|
||||||
|
|
||||||
/**
|
export type CodexPurchaseIdsResponse =
|
||||||
* Slot Index as hexadecimal string
|
paths["/storage/purchases"]["get"]["responses"][200]["content"]["application/json"];
|
||||||
*/
|
|
||||||
slotIndex: string;
|
export type CodexPurchaseResponse =
|
||||||
|
paths["/storage/purchases/{id}"]["get"]["responses"][200]["content"]["application/json"];
|
||||||
|
|
||||||
|
export type CodexStorageAsk = Omit<
|
||||||
|
components["schemas"]["StorageAsk"],
|
||||||
|
"slotSize" | "duration" | "proofProbability" | "pricePerBytePerSecond"
|
||||||
|
> & {
|
||||||
|
slotSize: number;
|
||||||
|
duration: number;
|
||||||
|
proofProbability: number;
|
||||||
|
pricePerBytePerSecond: number;
|
||||||
};
|
};
|
||||||
|
|
||||||
export type CodexPurchase = {
|
export type CodexPurchaseWithoutTypes = components["schemas"]["Purchase"];
|
||||||
/**
|
|
||||||
* Description of the request's state
|
|
||||||
*/
|
|
||||||
state: string;
|
|
||||||
|
|
||||||
/**
|
export type CodexPurchase = Omit<
|
||||||
* If request failed, then here is presented the error message
|
components["schemas"]["Purchase"],
|
||||||
*/
|
"request"
|
||||||
error: string;
|
> & {
|
||||||
|
request?: Omit<components["schemas"]["StorageRequest"], "ask"> & {
|
||||||
request: CodexStorageRequest;
|
ask: CodexStorageAsk;
|
||||||
|
};
|
||||||
requestId: string;
|
|
||||||
};
|
};
|
||||||
|
|
||||||
|
export type CodexStorageRequestResponse =
|
||||||
|
paths["/storage/request/{cid}"]["post"]["responses"][200]["content"]["text/plain"];
|
||||||
|
|
||||||
|
export type CodexStorageRequestCreateBody = Exclude<
|
||||||
|
paths["/storage/request/{cid}"]["post"]["requestBody"],
|
||||||
|
undefined
|
||||||
|
>["content"]["application/json"];
|
||||||
|
|
||||||
export const CodexCreateStorageRequestInput = v.strictObject({
|
export const CodexCreateStorageRequestInput = v.strictObject({
|
||||||
cid: v.string(),
|
cid: v.string(),
|
||||||
duration: v.pipe(v.number(), v.minValue(1)),
|
duration: v.pipe(v.number(), v.minValue(1)),
|
||||||
|
|||||||
@ -5,7 +5,14 @@ import {
|
|||||||
type FetchAuth,
|
type FetchAuth,
|
||||||
} from "../fetch-safe/fetch-safe";
|
} from "../fetch-safe/fetch-safe";
|
||||||
import type { SafeValue } from "../values/values";
|
import type { SafeValue } from "../values/values";
|
||||||
import type { CodexSpr } from "./types";
|
import type {
|
||||||
|
CodexPeerId,
|
||||||
|
CodexPeerIdContentType,
|
||||||
|
CodexPeerIdJsonResponse,
|
||||||
|
CodexSpr,
|
||||||
|
CodexSprContentType,
|
||||||
|
CodexSprJsonResponse,
|
||||||
|
} from "./types";
|
||||||
|
|
||||||
type CodexNodeOptions = {
|
type CodexNodeOptions = {
|
||||||
auth?: FetchAuth;
|
auth?: FetchAuth;
|
||||||
@ -25,9 +32,8 @@ export class CodexNode {
|
|||||||
|
|
||||||
/**
|
/**
|
||||||
* Connect to a peer
|
* Connect to a peer
|
||||||
* TODO check result
|
|
||||||
*/
|
*/
|
||||||
connect(peerId: string, addrs: string[] = []) {
|
connect(peerId: string, addrs: string[] = []): Promise<SafeValue<string>> {
|
||||||
const params = new URLSearchParams();
|
const params = new URLSearchParams();
|
||||||
|
|
||||||
for (const addr of addrs) {
|
for (const addr of addrs) {
|
||||||
@ -37,7 +43,7 @@ export class CodexNode {
|
|||||||
const url =
|
const url =
|
||||||
this.url + Api.config.prefix + `/connect/${peerId}?` + params.toString();
|
this.url + Api.config.prefix + `/connect/${peerId}?` + params.toString();
|
||||||
|
|
||||||
return Fetch.safe(url, {
|
return Fetch.safeText(url, {
|
||||||
method: "GET",
|
method: "GET",
|
||||||
headers: FetchAuthBuilder.build(this.auth),
|
headers: FetchAuthBuilder.build(this.auth),
|
||||||
});
|
});
|
||||||
@ -46,25 +52,54 @@ export class CodexNode {
|
|||||||
/**
|
/**
|
||||||
* Get Node's SPR
|
* Get Node's SPR
|
||||||
*/
|
*/
|
||||||
async spr(): Promise<SafeValue<CodexSpr>> {
|
async spr(
|
||||||
|
type: CodexSprContentType = "json"
|
||||||
|
): Promise<SafeValue<CodexSpr<CodexSprContentType>>> {
|
||||||
const url = this.url + Api.config.prefix + "/spr";
|
const url = this.url + Api.config.prefix + "/spr";
|
||||||
|
|
||||||
return Fetch.safeJson(url, {
|
if (type === "json") {
|
||||||
|
return Fetch.safeJson<CodexSprJsonResponse>(url, {
|
||||||
|
method: "GET",
|
||||||
|
headers: {
|
||||||
|
...FetchAuthBuilder.build(this.auth),
|
||||||
|
"Content-Type": "application/json",
|
||||||
|
},
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
return Fetch.safeText(url, {
|
||||||
method: "GET",
|
method: "GET",
|
||||||
headers: FetchAuthBuilder.build(this.auth),
|
headers: {
|
||||||
|
...FetchAuthBuilder.build(this.auth),
|
||||||
|
"Content-Type": "text/plain",
|
||||||
|
},
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Get Node's PeerID
|
* Get Node's PeerID
|
||||||
* TODO check result
|
|
||||||
*/
|
*/
|
||||||
peerId() {
|
peerId(
|
||||||
|
type: CodexPeerIdContentType = "json"
|
||||||
|
): Promise<SafeValue<CodexPeerId<CodexPeerIdContentType>>> {
|
||||||
const url = this.url + Api.config.prefix + "/node/peerid";
|
const url = this.url + Api.config.prefix + "/node/peerid";
|
||||||
|
|
||||||
return Fetch.safe(url, {
|
if (type === "json") {
|
||||||
|
return Fetch.safeJson<CodexPeerIdJsonResponse>(url, {
|
||||||
|
method: "GET",
|
||||||
|
headers: {
|
||||||
|
...FetchAuthBuilder.build(this.auth),
|
||||||
|
"Content-Type": "application/json",
|
||||||
|
},
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
return Fetch.safeText(url, {
|
||||||
method: "GET",
|
method: "GET",
|
||||||
headers: FetchAuthBuilder.build(this.auth),
|
headers: {
|
||||||
|
...FetchAuthBuilder.build(this.auth),
|
||||||
|
"Content-Type": "text/plain",
|
||||||
|
},
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -1,3 +1,29 @@
|
|||||||
export type CodexSpr = {
|
import type { paths } from "../openapi";
|
||||||
spr: string;
|
|
||||||
};
|
export type CodexSprTextResponse =
|
||||||
|
paths["/spr"]["get"]["responses"][200]["content"]["text/plain"];
|
||||||
|
|
||||||
|
export type CodexSprJsonResponse =
|
||||||
|
paths["/spr"]["get"]["responses"][200]["content"]["application/json"];
|
||||||
|
|
||||||
|
export type CodexSprContentType = "json" | "text";
|
||||||
|
|
||||||
|
export type CodexSpr<T extends CodexSprContentType> = T extends "json"
|
||||||
|
? CodexSprJsonResponse
|
||||||
|
: T extends "text"
|
||||||
|
? CodexSprTextResponse
|
||||||
|
: never;
|
||||||
|
|
||||||
|
export type CodexPeerIdTextResponse =
|
||||||
|
paths["/peerid"]["get"]["responses"][200]["content"]["text/plain"];
|
||||||
|
|
||||||
|
export type CodexPeerIdJsonResponse =
|
||||||
|
paths["/peerid"]["get"]["responses"][200]["content"]["application/json"];
|
||||||
|
|
||||||
|
export type CodexPeerIdContentType = "json" | "text";
|
||||||
|
|
||||||
|
export type CodexPeerId<T extends CodexPeerIdContentType> = T extends "json"
|
||||||
|
? CodexPeerIdJsonResponse
|
||||||
|
: T extends "text"
|
||||||
|
? CodexPeerIdTextResponse
|
||||||
|
: never;
|
||||||
|
|||||||
1449
src/openapi.ts
Normal file
1449
src/openapi.ts
Normal file
File diff suppressed because it is too large
Load Diff
@ -14,6 +14,7 @@
|
|||||||
"module": "ESNext",
|
"module": "ESNext",
|
||||||
"moduleResolution": "Bundler",
|
"moduleResolution": "Bundler",
|
||||||
"verbatimModuleSyntax": true,
|
"verbatimModuleSyntax": true,
|
||||||
"sourceMap": true
|
"sourceMap": true,
|
||||||
|
"noUncheckedIndexedAccess": true
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
Loading…
x
Reference in New Issue
Block a user