mirror of
https://github.com/logos-storage/logos-storage-js.git
synced 2026-01-04 06:23:06 +00:00
Add throwable usage
This commit is contained in:
parent
26a3caacc8
commit
63a868e311
14
README.md
14
README.md
@ -114,6 +114,20 @@ if (slots.error) {
|
|||||||
// Access the slots within slots.data.
|
// Access the slots within slots.data.
|
||||||
```
|
```
|
||||||
|
|
||||||
|
If you prefer to use the "classic" JavaScript mode and deal with exceptions, you can import the throwable component instead:
|
||||||
|
|
||||||
|
```js
|
||||||
|
import { Codex } from "@codex-storage/sdk-js/throwable";
|
||||||
|
|
||||||
|
const marketplace = codex.marketplace;
|
||||||
|
|
||||||
|
try {
|
||||||
|
const slots = marketplace.activeSlots();
|
||||||
|
} catch (e) {
|
||||||
|
// Do something
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
### Compatibility
|
### Compatibility
|
||||||
|
|
||||||
| SDK version | Codex version | Codex app |
|
| SDK version | Codex version | Codex app |
|
||||||
|
|||||||
17
examples/upload-node-throwable/README.md
Normal file
17
examples/upload-node-throwable/README.md
Normal file
@ -0,0 +1,17 @@
|
|||||||
|
# Download example
|
||||||
|
|
||||||
|
Small example to show how to download a file in the browser with Codex.
|
||||||
|
|
||||||
|
## Install dependencies
|
||||||
|
|
||||||
|
```bash
|
||||||
|
npm install
|
||||||
|
```
|
||||||
|
|
||||||
|
## Run node
|
||||||
|
|
||||||
|
```bash
|
||||||
|
node index.js
|
||||||
|
```
|
||||||
|
|
||||||
|
Note: You can define `CODEX_NODE_URL`, default value is "http://localhost:8080".
|
||||||
18
examples/upload-node-throwable/index.js
Normal file
18
examples/upload-node-throwable/index.js
Normal file
@ -0,0 +1,18 @@
|
|||||||
|
const { Codex } = require("@codex-storage/sdk-js/throwable");
|
||||||
|
const { NodeUploadStrategy } = require("@codex-storage/sdk-js/node");
|
||||||
|
|
||||||
|
async function main() {
|
||||||
|
const codex = new Codex(
|
||||||
|
process.env.CODEX_NODE_URL || "http://localhost:8080"
|
||||||
|
);
|
||||||
|
const data = codex.data;
|
||||||
|
|
||||||
|
const strategy = new NodeUploadStrategy("Hello World !");
|
||||||
|
const uploadResponse = data.upload(strategy);
|
||||||
|
|
||||||
|
const cid = await uploadResponse.result;
|
||||||
|
|
||||||
|
console.info("CID is", cid);
|
||||||
|
}
|
||||||
|
|
||||||
|
main();
|
||||||
79
examples/upload-node-throwable/package-lock.json
generated
Normal file
79
examples/upload-node-throwable/package-lock.json
generated
Normal file
@ -0,0 +1,79 @@
|
|||||||
|
{
|
||||||
|
"name": "@codex-storage/sdk-js-update-node-throwable-example",
|
||||||
|
"version": "1.0.0",
|
||||||
|
"lockfileVersion": 3,
|
||||||
|
"requires": true,
|
||||||
|
"packages": {
|
||||||
|
"": {
|
||||||
|
"name": "@codex-storage/sdk-js-update-node-throwable-example",
|
||||||
|
"version": "1.0.0",
|
||||||
|
"license": "ISC",
|
||||||
|
"dependencies": {
|
||||||
|
"@codex-storage/sdk-js": "../..",
|
||||||
|
"undici": "^7.7.0"
|
||||||
|
},
|
||||||
|
"devDependencies": {
|
||||||
|
"prettier": "^3.5.3"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"..": {
|
||||||
|
"extraneous": true
|
||||||
|
},
|
||||||
|
"../..": {
|
||||||
|
"name": "@codex-storage/sdk-js",
|
||||||
|
"version": "0.1.2",
|
||||||
|
"license": "MIT",
|
||||||
|
"dependencies": {
|
||||||
|
"valibot": "^1.0.0"
|
||||||
|
},
|
||||||
|
"devDependencies": {
|
||||||
|
"@tsconfig/strictest": "^2.0.5",
|
||||||
|
"@types/node": "^22.13.17",
|
||||||
|
"oas-normalize": "^14.0.0",
|
||||||
|
"openapi-typescript": "^7.6.1",
|
||||||
|
"prettier": "^3.5.3",
|
||||||
|
"tsup": "^8.3.6",
|
||||||
|
"typescript": "^5.8.2",
|
||||||
|
"vitest": "^3.1.1"
|
||||||
|
},
|
||||||
|
"engines": {
|
||||||
|
"node": ">=20.18.1"
|
||||||
|
},
|
||||||
|
"peerDependencies": {
|
||||||
|
"undici": "^7.7.0"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"../dist": {
|
||||||
|
"extraneous": true
|
||||||
|
},
|
||||||
|
"node_modules/@codex-storage/sdk-js": {
|
||||||
|
"resolved": "../..",
|
||||||
|
"link": true
|
||||||
|
},
|
||||||
|
"node_modules/prettier": {
|
||||||
|
"version": "3.5.3",
|
||||||
|
"resolved": "https://registry.npmjs.org/prettier/-/prettier-3.5.3.tgz",
|
||||||
|
"integrity": "sha512-QQtaxnoDJeAkDvDKWCLiwIXkTgRhwYDEQCghU9Z6q03iyek/rxRh/2lC3HB7P8sWT2xC/y5JDctPLBIGzHKbhw==",
|
||||||
|
"dev": true,
|
||||||
|
"license": "MIT",
|
||||||
|
"bin": {
|
||||||
|
"prettier": "bin/prettier.cjs"
|
||||||
|
},
|
||||||
|
"engines": {
|
||||||
|
"node": ">=14"
|
||||||
|
},
|
||||||
|
"funding": {
|
||||||
|
"url": "https://github.com/prettier/prettier?sponsor=1"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"node_modules/undici": {
|
||||||
|
"version": "7.7.0",
|
||||||
|
"resolved": "https://registry.npmjs.org/undici/-/undici-7.7.0.tgz",
|
||||||
|
"integrity": "sha512-tZ6+5NBq4KH35rr46XJ2JPFKxfcBlYNaqLF/wyWIO9RMHqqU/gx/CLB1Y2qMcgB8lWw/bKHa7qzspqCN7mUHvA==",
|
||||||
|
"license": "MIT",
|
||||||
|
"engines": {
|
||||||
|
"node": ">=20.18.1"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
16
examples/upload-node-throwable/package.json
Normal file
16
examples/upload-node-throwable/package.json
Normal file
@ -0,0 +1,16 @@
|
|||||||
|
{
|
||||||
|
"name": "@codex-storage/sdk-js-update-node-throwable-example",
|
||||||
|
"version": "1.0.0",
|
||||||
|
"main": "index.js",
|
||||||
|
"scripts": {},
|
||||||
|
"author": "",
|
||||||
|
"license": "ISC",
|
||||||
|
"description": "",
|
||||||
|
"dependencies": {
|
||||||
|
"@codex-storage/sdk-js": "../..",
|
||||||
|
"undici": "^7.7.0"
|
||||||
|
},
|
||||||
|
"devDependencies": {
|
||||||
|
"prettier": "^3.5.3"
|
||||||
|
}
|
||||||
|
}
|
||||||
12
package.json
12
package.json
@ -9,7 +9,7 @@
|
|||||||
"scripts": {
|
"scripts": {
|
||||||
"prepack": "npm run build",
|
"prepack": "npm run build",
|
||||||
"prebuild": "npm run compile && rm -Rf dist/*",
|
"prebuild": "npm run compile && rm -Rf dist/*",
|
||||||
"build": "tsup src/index.ts src/async.ts src/browser.ts src/node.ts --format esm,cjs --dts --sourcemap --treeshake",
|
"build": "tsup src/index.ts src/async.ts src/browser.ts src/node.ts src/throwable.ts --format esm,cjs --dts --sourcemap --treeshake",
|
||||||
"compile": "tsc --noEmit",
|
"compile": "tsc --noEmit",
|
||||||
"test": "vitest run",
|
"test": "vitest run",
|
||||||
"test:watch": "vitest",
|
"test:watch": "vitest",
|
||||||
@ -35,6 +35,16 @@
|
|||||||
"default": "./dist/index.js"
|
"default": "./dist/index.js"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"./throwable": {
|
||||||
|
"import": {
|
||||||
|
"types": "./dist/throwable.d.ts",
|
||||||
|
"default": "./dist/throwable.mjs"
|
||||||
|
},
|
||||||
|
"require": {
|
||||||
|
"types": "./dist/throwable.d.cts",
|
||||||
|
"default": "./dist/throwable.js"
|
||||||
|
}
|
||||||
|
},
|
||||||
"./browser": {
|
"./browser": {
|
||||||
"import": {
|
"import": {
|
||||||
"types": "./dist/browser.d.ts",
|
"types": "./dist/browser.d.ts",
|
||||||
|
|||||||
33
src/data/data.throwable.ts
Normal file
33
src/data/data.throwable.ts
Normal file
@ -0,0 +1,33 @@
|
|||||||
|
import { CodexData } from "./data";
|
||||||
|
import type { UploadStrategy } from "./types";
|
||||||
|
import { type FetchAuth } from "../fetch-safe/fetch-safe";
|
||||||
|
import { Throwable } from "../throwable/throwable";
|
||||||
|
|
||||||
|
type CodexDataThrowableOptions = {
|
||||||
|
auth?: FetchAuth;
|
||||||
|
};
|
||||||
|
|
||||||
|
export class CodexDataThrowable {
|
||||||
|
readonly data: CodexData;
|
||||||
|
|
||||||
|
constructor(url: string, options?: CodexDataThrowableOptions) {
|
||||||
|
this.data = new CodexData(url, options);
|
||||||
|
}
|
||||||
|
|
||||||
|
cids = () => Throwable.from(this.data.cids());
|
||||||
|
space = () => Throwable.from(this.data.space());
|
||||||
|
upload = (strategy: UploadStrategy) => {
|
||||||
|
const { result, abort } = this.data.upload(strategy);
|
||||||
|
return {
|
||||||
|
result: Throwable.from(result),
|
||||||
|
abort,
|
||||||
|
};
|
||||||
|
};
|
||||||
|
localDownload = (cid: string) => Throwable.from(this.data.localDownload(cid));
|
||||||
|
networkDownload = (cid: string) =>
|
||||||
|
Throwable.from(this.data.networkDownload(cid));
|
||||||
|
networkDownloadStream = (cid: string) =>
|
||||||
|
Throwable.from(this.data.networkDownloadStream(cid));
|
||||||
|
fetchManifest = (cid: string) => Throwable.from(this.data.fetchManifest(cid));
|
||||||
|
delete = (cid: string) => Throwable.from(this.data.delete(cid));
|
||||||
|
}
|
||||||
20
src/debug/debug.throwable.ts
Normal file
20
src/debug/debug.throwable.ts
Normal file
@ -0,0 +1,20 @@
|
|||||||
|
import type { CodexLogLevel } from "./types";
|
||||||
|
import { type FetchAuth } from "../fetch-safe/fetch-safe";
|
||||||
|
import { Throwable } from "../throwable/throwable";
|
||||||
|
import { CodexDebug } from "./debug";
|
||||||
|
|
||||||
|
type CodexDebugThrowableOptions = {
|
||||||
|
auth?: FetchAuth;
|
||||||
|
};
|
||||||
|
|
||||||
|
export class CodexDebugThrowable {
|
||||||
|
readonly debug: CodexDebug;
|
||||||
|
|
||||||
|
constructor(url: string, options?: CodexDebugThrowableOptions) {
|
||||||
|
this.debug = new CodexDebug(url, options);
|
||||||
|
}
|
||||||
|
|
||||||
|
setLogLevel = (level: CodexLogLevel) =>
|
||||||
|
Throwable.from(this.debug.setLogLevel(level));
|
||||||
|
info = () => Throwable.from(this.debug.info());
|
||||||
|
}
|
||||||
37
src/marketplace/marketplace.throwable.ts
Normal file
37
src/marketplace/marketplace.throwable.ts
Normal file
@ -0,0 +1,37 @@
|
|||||||
|
import { type FetchAuth } from "../fetch-safe/fetch-safe";
|
||||||
|
import { Throwable } from "../throwable/throwable";
|
||||||
|
import { CodexMarketplace } from "./marketplace";
|
||||||
|
import type {
|
||||||
|
CodexAvailabilityPatchInput,
|
||||||
|
CodexCreateAvailabilityInput,
|
||||||
|
CodexCreateStorageRequestInput,
|
||||||
|
} from "./types";
|
||||||
|
|
||||||
|
type CodexMarketplaceThrowableOptions = {
|
||||||
|
auth?: FetchAuth;
|
||||||
|
};
|
||||||
|
|
||||||
|
export class CodexMarketplaceThrowable {
|
||||||
|
readonly marketplace: CodexMarketplace;
|
||||||
|
|
||||||
|
constructor(url: string, options?: CodexMarketplaceThrowableOptions) {
|
||||||
|
this.marketplace = new CodexMarketplace(url, options);
|
||||||
|
}
|
||||||
|
|
||||||
|
activeSlots = () => Throwable.from(this.marketplace.activeSlots());
|
||||||
|
activeSlot = (slotId: string) =>
|
||||||
|
Throwable.from(this.marketplace.activeSlot(slotId));
|
||||||
|
availabilities = () => Throwable.from(this.marketplace.availabilities());
|
||||||
|
createAvailability = (input: CodexCreateAvailabilityInput) =>
|
||||||
|
Throwable.from(this.marketplace.createAvailability(input));
|
||||||
|
updateAvailability = (input: CodexAvailabilityPatchInput) =>
|
||||||
|
Throwable.from(this.marketplace.updateAvailability(input));
|
||||||
|
reservations = (availabilityId: string) =>
|
||||||
|
Throwable.from(this.marketplace.reservations(availabilityId));
|
||||||
|
purchaseIds = () => Throwable.from(this.marketplace.purchaseIds());
|
||||||
|
purchases = () => Throwable.from(this.marketplace.purchases());
|
||||||
|
purchaseDetail = (purchaseId: string) =>
|
||||||
|
Throwable.from(this.marketplace.purchaseDetail(purchaseId));
|
||||||
|
createStorageRequest = (input: CodexCreateStorageRequestInput) =>
|
||||||
|
Throwable.from(this.marketplace.createStorageRequest(input));
|
||||||
|
}
|
||||||
23
src/node/node.throwable.ts
Normal file
23
src/node/node.throwable.ts
Normal file
@ -0,0 +1,23 @@
|
|||||||
|
import type { CodexPeerIdContentType, CodexSprContentType } from "./types";
|
||||||
|
import { type FetchAuth } from "../fetch-safe/fetch-safe";
|
||||||
|
import { Throwable } from "../throwable/throwable";
|
||||||
|
import { CodexNode } from "./node";
|
||||||
|
|
||||||
|
type CodexNodeThrowableOptions = {
|
||||||
|
auth?: FetchAuth;
|
||||||
|
};
|
||||||
|
|
||||||
|
export class CodexNodeThrowable {
|
||||||
|
readonly node: CodexNode;
|
||||||
|
|
||||||
|
constructor(url: string, options?: CodexNodeThrowableOptions) {
|
||||||
|
this.node = new CodexNode(url, options);
|
||||||
|
}
|
||||||
|
|
||||||
|
connect = (peerId: string, addrs: string[] = []) =>
|
||||||
|
Throwable.from(this.node.connect(peerId, addrs));
|
||||||
|
spr = (type: CodexSprContentType = "json") =>
|
||||||
|
Throwable.from(this.node.spr(type));
|
||||||
|
peerId = (type: CodexPeerIdContentType = "json") =>
|
||||||
|
Throwable.from(this.node.peerId(type));
|
||||||
|
}
|
||||||
84
src/throwable.ts
Normal file
84
src/throwable.ts
Normal file
@ -0,0 +1,84 @@
|
|||||||
|
import { CodexDataThrowable } from "./data/data.throwable";
|
||||||
|
import { CodexNodeThrowable } from "./node/node.throwable";
|
||||||
|
import { CodexMarketplaceThrowable } from "./marketplace/marketplace.throwable";
|
||||||
|
import { CodexDebugThrowable } from "./debug/debug.throwable";
|
||||||
|
import type { FetchAuth } from "./fetch-safe/fetch-safe";
|
||||||
|
|
||||||
|
export * from "./fetch-safe/fetch-safe";
|
||||||
|
export * from "./marketplace/types";
|
||||||
|
export * from "./debug/types";
|
||||||
|
export * from "./data/types";
|
||||||
|
export * from "./values/values";
|
||||||
|
export * from "./errors/errors";
|
||||||
|
|
||||||
|
export { CodexDebugThrowable } from "./debug/debug.throwable";
|
||||||
|
export { CodexDataThrowable } from "./data/data.throwable";
|
||||||
|
export { CodexNodeThrowable } from "./node/node.throwable";
|
||||||
|
export { CodexMarketplaceThrowable } from "./marketplace/marketplace.throwable";
|
||||||
|
|
||||||
|
type CodexProps = {
|
||||||
|
auth?: FetchAuth;
|
||||||
|
};
|
||||||
|
|
||||||
|
export class Codex {
|
||||||
|
readonly url: string;
|
||||||
|
private _marketplace: CodexMarketplaceThrowable | null;
|
||||||
|
private _data: CodexDataThrowable | null;
|
||||||
|
private _node: CodexNodeThrowable | null;
|
||||||
|
private _debug: CodexDebugThrowable | null;
|
||||||
|
private readonly auth: FetchAuth = {};
|
||||||
|
|
||||||
|
constructor(url: string, options?: CodexProps) {
|
||||||
|
this.url = url;
|
||||||
|
this._marketplace = null;
|
||||||
|
this._data = null;
|
||||||
|
this._node = null;
|
||||||
|
this._debug = null;
|
||||||
|
|
||||||
|
if (options?.auth) {
|
||||||
|
this.auth = options?.auth;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
get marketplace() {
|
||||||
|
if (this._marketplace) {
|
||||||
|
return this._marketplace;
|
||||||
|
}
|
||||||
|
|
||||||
|
this._marketplace = new CodexMarketplaceThrowable(this.url, {
|
||||||
|
auth: this.auth,
|
||||||
|
});
|
||||||
|
|
||||||
|
return this._marketplace;
|
||||||
|
}
|
||||||
|
|
||||||
|
get data() {
|
||||||
|
if (this._data) {
|
||||||
|
return this._data;
|
||||||
|
}
|
||||||
|
|
||||||
|
this._data = new CodexDataThrowable(this.url, { auth: this.auth });
|
||||||
|
|
||||||
|
return this._data;
|
||||||
|
}
|
||||||
|
|
||||||
|
get node() {
|
||||||
|
if (this._node) {
|
||||||
|
return this._node;
|
||||||
|
}
|
||||||
|
|
||||||
|
this._node = new CodexNodeThrowable(this.url, { auth: this.auth });
|
||||||
|
|
||||||
|
return this._node;
|
||||||
|
}
|
||||||
|
|
||||||
|
get debug() {
|
||||||
|
if (this._debug) {
|
||||||
|
return this._debug;
|
||||||
|
}
|
||||||
|
|
||||||
|
this._debug = new CodexDebugThrowable(this.url, { auth: this.auth });
|
||||||
|
|
||||||
|
return this._debug;
|
||||||
|
}
|
||||||
|
}
|
||||||
19
src/throwable/throwable.spec.ts
Normal file
19
src/throwable/throwable.spec.ts
Normal file
@ -0,0 +1,19 @@
|
|||||||
|
import { assert, describe, it } from "vitest";
|
||||||
|
import { CodexDataThrowable } from "../data/data.throwable";
|
||||||
|
import { CodexError } from "../errors/errors";
|
||||||
|
|
||||||
|
describe("data", () => {
|
||||||
|
const data = new CodexDataThrowable(
|
||||||
|
process.env["CLIENT_URL"] || "http://localhost:8080"
|
||||||
|
);
|
||||||
|
|
||||||
|
it("returns an error when providing an invalid cid", async () => {
|
||||||
|
try {
|
||||||
|
await data.delete("hello");
|
||||||
|
assert.fail();
|
||||||
|
} catch (e) {
|
||||||
|
assert.ok(e instanceof CodexError);
|
||||||
|
assert.ok(e.message.includes("Incorrect Cid"));
|
||||||
|
}
|
||||||
|
});
|
||||||
|
});
|
||||||
13
src/throwable/throwable.ts
Normal file
13
src/throwable/throwable.ts
Normal file
@ -0,0 +1,13 @@
|
|||||||
|
import type { SafeValue } from "../values/values";
|
||||||
|
|
||||||
|
export const Throwable = {
|
||||||
|
async from<T>(safePromise: Promise<SafeValue<T>>): Promise<T> {
|
||||||
|
const result = await safePromise;
|
||||||
|
|
||||||
|
if (result.error) {
|
||||||
|
throw result.data;
|
||||||
|
}
|
||||||
|
|
||||||
|
return result.data;
|
||||||
|
},
|
||||||
|
};
|
||||||
Loading…
x
Reference in New Issue
Block a user