diff --git a/README.md b/README.md
index 862e482..314e8c0 100644
--- a/README.md
+++ b/README.md
@@ -6,6 +6,10 @@ The SDK has a small bundle size and support tree shaking.
The SDK is currently under early development and the API can change at any time.
+## Breaking changes
+
+- Version 0.1.0 introduces [upload strategy](#upload) to support browser and Node JS.
+
## How to use
### Sync api
@@ -268,7 +272,7 @@ const cids = await data.cids();
Returns a summary of the storage space allocation of the node
-- returns Promise<[CodexNodeSpace](./src/data/types.ts#L58)[]>
+- returns Promise<[CodexNodeSpace](./src/data/types.ts#L56)[]>
Example:
@@ -280,24 +284,55 @@ const space = await data.space();
Upload a file in a streaming manner
-- file (File, required)
-- onProgress (onProgress: (loaded: number, total: number) => void, optional)
-- metadata ({ filename?: string, mimetype?: string }, optional)
+#### Browser
+
+- stategy [BrowserUploadStategy](./src/data/browser-upload.ts#L5)
- returns [UploadResponse](./src/data/types.ts#L80)
Example:
```js
-// Get file from previous event
-const [file] = e.target.files
-const metadata = {
- filename: file.name,
- mimetype: file.type,
+const file = new File(["foo"], "foo.txt", { type: "text/plain" });
+
+const onProgress = (loaded, total) => {
+ console.info("Loaded", loaded, "total", total);
+};
+
+const metadata = { filename: "foo.xt", mimetype: "text/plain" };
+
+const stategy = new BrowserUploadStategy(file, onProgress, metadata);
+
+const uploadResponse = data.upload(stategy);
+
+const res = await uploadResponse.result;
+
+if (res.error) {
+ console.error(res.data);
+ return;
}
-const upload = data.upload(file, (loaded: number, total: number) => {
- // Use loaded and total so update a progress bar for example
-}, metadata);
-await upload.result();
+
+console.info("CID is", res.data);
+```
+
+#### Node
+
+- stategy [NodeUploadStategy](./src/data/node-download.ts#L8)
+- returns [UploadResponse](./src/data/types.ts#L80)
+
+Example:
+
+```js
+const stategy = new NodeUploadStategy("Hello World !");
+const uploadResponse = data.upload(stategy);
+
+const res = await uploadResponse.result;
+
+if (res.error) {
+ console.error(res.data);
+ return;
+}
+
+console.info("CID is", res.data);
```
#### manifest
diff --git a/examples/download/esbuild.js b/examples/download/esbuild.js
index 28c297b..93c9831 100644
--- a/examples/download/esbuild.js
+++ b/examples/download/esbuild.js
@@ -1,19 +1,19 @@
-const { build } = require('esbuild')
-const define = {}
+const { build } = require("esbuild");
+const define = {};
for (const k in process.env) {
- define[`process.env.${k}`] = JSON.stringify(process.env[k])
+ define[`process.env.${k}`] = JSON.stringify(process.env[k]);
}
-if(!process.env["CODEX_NODE_URL"]) {
- define[`process.env.CODEX_NODE_URL`] = "\"http://localhost:8080\""
+if (!process.env["CODEX_NODE_URL"]) {
+ define[`process.env.CODEX_NODE_URL`] = '"http://localhost:8080"';
}
const options = {
- entryPoints: ['./index.js'],
- outfile: './index.bundle.js',
+ entryPoints: ["./index.js"],
+ outfile: "./index.bundle.js",
bundle: true,
define,
-}
+};
-build(options).catch(() => process.exit(1))
\ No newline at end of file
+build(options).catch(() => process.exit(1));
diff --git a/examples/download/index.js b/examples/download/index.js
index e445093..0432bc8 100644
--- a/examples/download/index.js
+++ b/examples/download/index.js
@@ -1,14 +1,15 @@
import { Codex } from "@codex-storage/sdk-js";
async function main() {
- const codex = new Codex(process.env.CODEX_NODE_URL);
+ const codex = new Codex(process.env.CODEX_NODE_URL);
- const data = codex.data
+ const data = codex.data;
- const cid = process.env.CODEX_CID
- const result = await data.networkDownloadStream(cid);
+ const cid = process.env.CODEX_CID;
- console.info(await result.data.text())
+ const result = await data.networkDownloadStream(cid);
+
+ console.info(await result.data.text());
}
-main()
\ No newline at end of file
+main();
diff --git a/examples/download/package-lock.json b/examples/download/package-lock.json
index af9dc06..a7d1c79 100644
--- a/examples/download/package-lock.json
+++ b/examples/download/package-lock.json
@@ -1,31 +1,25 @@
{
- "name": "download",
+ "name": "@codex-storage/sdk-js-download-example",
"version": "1.0.0",
"lockfileVersion": 3,
"requires": true,
"packages": {
"": {
- "name": "download",
+ "name": "@codex-storage/sdk-js-download-example",
"version": "1.0.0",
"license": "ISC",
"dependencies": {
- "@codex-storage/sdk-js": "^0.0.23"
+ "@codex-storage/sdk-js": ".."
},
"devDependencies": {
- "esbuild": "^0.25.1"
+ "esbuild": "^0.25.1",
+ "prettier": "^3.5.3"
}
},
+ "..": {},
"node_modules/@codex-storage/sdk-js": {
- "version": "0.0.23",
- "resolved": "https://registry.npmjs.org/@codex-storage/sdk-js/-/sdk-js-0.0.23.tgz",
- "integrity": "sha512-+ktJs396GERPudRh5zjTvOMjwo3mRHVYN901Qvs0q3YlRK983aewSqJ+Z7NttSQ27oxTcvxQVrilcvzZRHQTkg==",
- "license": "MIT",
- "dependencies": {
- "valibot": "^0.32.0"
- },
- "engines": {
- "node": ">=20"
- }
+ "resolved": "..",
+ "link": true
},
"node_modules/@esbuild/aix-ppc64": {
"version": "0.25.1",
@@ -493,11 +487,21 @@
"@esbuild/win32-x64": "0.25.1"
}
},
- "node_modules/valibot": {
- "version": "0.32.0",
- "resolved": "https://registry.npmjs.org/valibot/-/valibot-0.32.0.tgz",
- "integrity": "sha512-FXBnJl4bNOmeg7lQv+jfvo/wADsRBN8e9C3r+O77Re3dEnDma8opp7p4hcIbF7XJJ30h/5SVohdjer17/sHOsQ==",
- "license": "MIT"
+ "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"
+ }
}
}
}
diff --git a/examples/download/package.json b/examples/download/package.json
index 4211911..6dcbd6b 100644
--- a/examples/download/package.json
+++ b/examples/download/package.json
@@ -9,9 +9,10 @@
"license": "ISC",
"description": "",
"dependencies": {
- "@codex-storage/sdk-js": "^0.0.23"
+ "@codex-storage/sdk-js": ".."
},
"devDependencies": {
- "esbuild": "^0.25.1"
+ "esbuild": "^0.25.1",
+ "prettier": "^3.5.3"
}
}
diff --git a/examples/upload-browser/.gitignore b/examples/upload-browser/.gitignore
new file mode 100644
index 0000000..91097d8
--- /dev/null
+++ b/examples/upload-browser/.gitignore
@@ -0,0 +1 @@
+index.bundle.js
\ No newline at end of file
diff --git a/examples/upload-browser/README.md b/examples/upload-browser/README.md
new file mode 100644
index 0000000..1c13969
--- /dev/null
+++ b/examples/upload-browser/README.md
@@ -0,0 +1,23 @@
+# Download example
+
+Small example to show how to download a file in the browser with Codex.
+
+## Install dependencies
+
+```bash
+npm install
+```
+
+## Build the javascript asset
+
+```bash
+CODEX_CID=REPLACE_BY_YOUR_CIDE npm run build
+```
+
+The response will be displayed as text, so it is better to test with .txt files.
+
+Note: You can define `CODEX_NODE_URL`, default value is "http://localhost:8080".
+
+## Check the results
+
+Open the index.html and open the web console.
diff --git a/examples/upload-browser/esbuild.js b/examples/upload-browser/esbuild.js
new file mode 100644
index 0000000..37b09c6
--- /dev/null
+++ b/examples/upload-browser/esbuild.js
@@ -0,0 +1,22 @@
+const { build } = require("esbuild");
+const define = {};
+
+for (const k in process.env) {
+ define[`process.env.${k}`] = JSON.stringify(process.env[k]);
+}
+
+if (!process.env["CODEX_NODE_URL"]) {
+ define[`process.env.CODEX_NODE_URL`] = '"http://localhost:8080"';
+}
+
+const options = {
+ entryPoints: ["./index.js"],
+ outfile: "./index.bundle.js",
+ bundle: true,
+ define,
+ logOverride: {
+ "ignored-bare-import": "silent",
+ },
+};
+
+build(options).catch(() => process.exit(1));
diff --git a/examples/upload-browser/index.html b/examples/upload-browser/index.html
new file mode 100644
index 0000000..0a494ed
--- /dev/null
+++ b/examples/upload-browser/index.html
@@ -0,0 +1,4 @@
+
+
+
\ No newline at end of file
diff --git a/examples/upload-browser/index.js b/examples/upload-browser/index.js
new file mode 100644
index 0000000..13563e0
--- /dev/null
+++ b/examples/upload-browser/index.js
@@ -0,0 +1,36 @@
+import { Codex } from "@codex-storage/sdk-js";
+import { BrowserUploadStategy } from "@codex-storage/sdk-js/browser";
+
+async function main() {
+ const codex = new Codex(process.env.CODEX_NODE_URL);
+
+ const data = codex.data;
+
+ const file = new File(["foo"], "foo.txt", {
+ type: "text/plain",
+ });
+
+ const onProgress = (loaded, total) => {
+ console.info("Loaded", loaded, "total", total);
+ };
+
+ const metadata = {
+ filename: "foo.xt",
+ mimetype: "text/plain",
+ };
+
+ const stategy = new BrowserUploadStategy(file, onProgress, metadata);
+
+ const uploadResponse = data.upload(stategy);
+
+ const res = await uploadResponse.result;
+
+ if (res.error) {
+ console.error(res.data);
+ return;
+ }
+
+ console.info("CID is", res.data);
+}
+
+main();
diff --git a/examples/upload-browser/package-lock.json b/examples/upload-browser/package-lock.json
new file mode 100644
index 0000000..88dca18
--- /dev/null
+++ b/examples/upload-browser/package-lock.json
@@ -0,0 +1,531 @@
+{
+ "name": "@codex-storage/sdk-js-update-browser-example",
+ "version": "1.0.0",
+ "lockfileVersion": 3,
+ "requires": true,
+ "packages": {
+ "": {
+ "name": "@codex-storage/sdk-js-update-browser-example",
+ "version": "1.0.0",
+ "license": "ISC",
+ "dependencies": {
+ "@codex-storage/sdk-js": "../.."
+ },
+ "devDependencies": {
+ "esbuild": "^0.25.1",
+ "prettier": "^3.5.3"
+ }
+ },
+ "..": {
+ "extraneous": true
+ },
+ "../..": {
+ "name": "@codex-storage/sdk-js",
+ "version": "0.0.23",
+ "license": "MIT",
+ "dependencies": {
+ "undici": "^7.5.0",
+ "valibot": "^0.32.0"
+ },
+ "devDependencies": {
+ "@tsconfig/strictest": "^2.0.5",
+ "prettier": "^3.5.3",
+ "tsup": "^8.3.6",
+ "typescript": "^5.8.2",
+ "vitest": "^3.0.9"
+ },
+ "engines": {
+ "node": ">=20.18.1"
+ }
+ },
+ "../dist": {
+ "extraneous": true
+ },
+ "node_modules/@codex-storage/sdk-js": {
+ "resolved": "../..",
+ "link": true
+ },
+ "node_modules/@esbuild/aix-ppc64": {
+ "version": "0.25.1",
+ "resolved": "https://registry.npmjs.org/@esbuild/aix-ppc64/-/aix-ppc64-0.25.1.tgz",
+ "integrity": "sha512-kfYGy8IdzTGy+z0vFGvExZtxkFlA4zAxgKEahG9KE1ScBjpQnFsNOX8KTU5ojNru5ed5CVoJYXFtoxaq5nFbjQ==",
+ "cpu": [
+ "ppc64"
+ ],
+ "dev": true,
+ "license": "MIT",
+ "optional": true,
+ "os": [
+ "aix"
+ ],
+ "engines": {
+ "node": ">=18"
+ }
+ },
+ "node_modules/@esbuild/android-arm": {
+ "version": "0.25.1",
+ "resolved": "https://registry.npmjs.org/@esbuild/android-arm/-/android-arm-0.25.1.tgz",
+ "integrity": "sha512-dp+MshLYux6j/JjdqVLnMglQlFu+MuVeNrmT5nk6q07wNhCdSnB7QZj+7G8VMUGh1q+vj2Bq8kRsuyA00I/k+Q==",
+ "cpu": [
+ "arm"
+ ],
+ "dev": true,
+ "license": "MIT",
+ "optional": true,
+ "os": [
+ "android"
+ ],
+ "engines": {
+ "node": ">=18"
+ }
+ },
+ "node_modules/@esbuild/android-arm64": {
+ "version": "0.25.1",
+ "resolved": "https://registry.npmjs.org/@esbuild/android-arm64/-/android-arm64-0.25.1.tgz",
+ "integrity": "sha512-50tM0zCJW5kGqgG7fQ7IHvQOcAn9TKiVRuQ/lN0xR+T2lzEFvAi1ZcS8DiksFcEpf1t/GYOeOfCAgDHFpkiSmA==",
+ "cpu": [
+ "arm64"
+ ],
+ "dev": true,
+ "license": "MIT",
+ "optional": true,
+ "os": [
+ "android"
+ ],
+ "engines": {
+ "node": ">=18"
+ }
+ },
+ "node_modules/@esbuild/android-x64": {
+ "version": "0.25.1",
+ "resolved": "https://registry.npmjs.org/@esbuild/android-x64/-/android-x64-0.25.1.tgz",
+ "integrity": "sha512-GCj6WfUtNldqUzYkN/ITtlhwQqGWu9S45vUXs7EIYf+7rCiiqH9bCloatO9VhxsL0Pji+PF4Lz2XXCES+Q8hDw==",
+ "cpu": [
+ "x64"
+ ],
+ "dev": true,
+ "license": "MIT",
+ "optional": true,
+ "os": [
+ "android"
+ ],
+ "engines": {
+ "node": ">=18"
+ }
+ },
+ "node_modules/@esbuild/darwin-arm64": {
+ "version": "0.25.1",
+ "resolved": "https://registry.npmjs.org/@esbuild/darwin-arm64/-/darwin-arm64-0.25.1.tgz",
+ "integrity": "sha512-5hEZKPf+nQjYoSr/elb62U19/l1mZDdqidGfmFutVUjjUZrOazAtwK+Kr+3y0C/oeJfLlxo9fXb1w7L+P7E4FQ==",
+ "cpu": [
+ "arm64"
+ ],
+ "dev": true,
+ "license": "MIT",
+ "optional": true,
+ "os": [
+ "darwin"
+ ],
+ "engines": {
+ "node": ">=18"
+ }
+ },
+ "node_modules/@esbuild/darwin-x64": {
+ "version": "0.25.1",
+ "resolved": "https://registry.npmjs.org/@esbuild/darwin-x64/-/darwin-x64-0.25.1.tgz",
+ "integrity": "sha512-hxVnwL2Dqs3fM1IWq8Iezh0cX7ZGdVhbTfnOy5uURtao5OIVCEyj9xIzemDi7sRvKsuSdtCAhMKarxqtlyVyfA==",
+ "cpu": [
+ "x64"
+ ],
+ "dev": true,
+ "license": "MIT",
+ "optional": true,
+ "os": [
+ "darwin"
+ ],
+ "engines": {
+ "node": ">=18"
+ }
+ },
+ "node_modules/@esbuild/freebsd-arm64": {
+ "version": "0.25.1",
+ "resolved": "https://registry.npmjs.org/@esbuild/freebsd-arm64/-/freebsd-arm64-0.25.1.tgz",
+ "integrity": "sha512-1MrCZs0fZa2g8E+FUo2ipw6jw5qqQiH+tERoS5fAfKnRx6NXH31tXBKI3VpmLijLH6yriMZsxJtaXUyFt/8Y4A==",
+ "cpu": [
+ "arm64"
+ ],
+ "dev": true,
+ "license": "MIT",
+ "optional": true,
+ "os": [
+ "freebsd"
+ ],
+ "engines": {
+ "node": ">=18"
+ }
+ },
+ "node_modules/@esbuild/freebsd-x64": {
+ "version": "0.25.1",
+ "resolved": "https://registry.npmjs.org/@esbuild/freebsd-x64/-/freebsd-x64-0.25.1.tgz",
+ "integrity": "sha512-0IZWLiTyz7nm0xuIs0q1Y3QWJC52R8aSXxe40VUxm6BB1RNmkODtW6LHvWRrGiICulcX7ZvyH6h5fqdLu4gkww==",
+ "cpu": [
+ "x64"
+ ],
+ "dev": true,
+ "license": "MIT",
+ "optional": true,
+ "os": [
+ "freebsd"
+ ],
+ "engines": {
+ "node": ">=18"
+ }
+ },
+ "node_modules/@esbuild/linux-arm": {
+ "version": "0.25.1",
+ "resolved": "https://registry.npmjs.org/@esbuild/linux-arm/-/linux-arm-0.25.1.tgz",
+ "integrity": "sha512-NdKOhS4u7JhDKw9G3cY6sWqFcnLITn6SqivVArbzIaf3cemShqfLGHYMx8Xlm/lBit3/5d7kXvriTUGa5YViuQ==",
+ "cpu": [
+ "arm"
+ ],
+ "dev": true,
+ "license": "MIT",
+ "optional": true,
+ "os": [
+ "linux"
+ ],
+ "engines": {
+ "node": ">=18"
+ }
+ },
+ "node_modules/@esbuild/linux-arm64": {
+ "version": "0.25.1",
+ "resolved": "https://registry.npmjs.org/@esbuild/linux-arm64/-/linux-arm64-0.25.1.tgz",
+ "integrity": "sha512-jaN3dHi0/DDPelk0nLcXRm1q7DNJpjXy7yWaWvbfkPvI+7XNSc/lDOnCLN7gzsyzgu6qSAmgSvP9oXAhP973uQ==",
+ "cpu": [
+ "arm64"
+ ],
+ "dev": true,
+ "license": "MIT",
+ "optional": true,
+ "os": [
+ "linux"
+ ],
+ "engines": {
+ "node": ">=18"
+ }
+ },
+ "node_modules/@esbuild/linux-ia32": {
+ "version": "0.25.1",
+ "resolved": "https://registry.npmjs.org/@esbuild/linux-ia32/-/linux-ia32-0.25.1.tgz",
+ "integrity": "sha512-OJykPaF4v8JidKNGz8c/q1lBO44sQNUQtq1KktJXdBLn1hPod5rE/Hko5ugKKZd+D2+o1a9MFGUEIUwO2YfgkQ==",
+ "cpu": [
+ "ia32"
+ ],
+ "dev": true,
+ "license": "MIT",
+ "optional": true,
+ "os": [
+ "linux"
+ ],
+ "engines": {
+ "node": ">=18"
+ }
+ },
+ "node_modules/@esbuild/linux-loong64": {
+ "version": "0.25.1",
+ "resolved": "https://registry.npmjs.org/@esbuild/linux-loong64/-/linux-loong64-0.25.1.tgz",
+ "integrity": "sha512-nGfornQj4dzcq5Vp835oM/o21UMlXzn79KobKlcs3Wz9smwiifknLy4xDCLUU0BWp7b/houtdrgUz7nOGnfIYg==",
+ "cpu": [
+ "loong64"
+ ],
+ "dev": true,
+ "license": "MIT",
+ "optional": true,
+ "os": [
+ "linux"
+ ],
+ "engines": {
+ "node": ">=18"
+ }
+ },
+ "node_modules/@esbuild/linux-mips64el": {
+ "version": "0.25.1",
+ "resolved": "https://registry.npmjs.org/@esbuild/linux-mips64el/-/linux-mips64el-0.25.1.tgz",
+ "integrity": "sha512-1osBbPEFYwIE5IVB/0g2X6i1qInZa1aIoj1TdL4AaAb55xIIgbg8Doq6a5BzYWgr+tEcDzYH67XVnTmUzL+nXg==",
+ "cpu": [
+ "mips64el"
+ ],
+ "dev": true,
+ "license": "MIT",
+ "optional": true,
+ "os": [
+ "linux"
+ ],
+ "engines": {
+ "node": ">=18"
+ }
+ },
+ "node_modules/@esbuild/linux-ppc64": {
+ "version": "0.25.1",
+ "resolved": "https://registry.npmjs.org/@esbuild/linux-ppc64/-/linux-ppc64-0.25.1.tgz",
+ "integrity": "sha512-/6VBJOwUf3TdTvJZ82qF3tbLuWsscd7/1w+D9LH0W/SqUgM5/JJD0lrJ1fVIfZsqB6RFmLCe0Xz3fmZc3WtyVg==",
+ "cpu": [
+ "ppc64"
+ ],
+ "dev": true,
+ "license": "MIT",
+ "optional": true,
+ "os": [
+ "linux"
+ ],
+ "engines": {
+ "node": ">=18"
+ }
+ },
+ "node_modules/@esbuild/linux-riscv64": {
+ "version": "0.25.1",
+ "resolved": "https://registry.npmjs.org/@esbuild/linux-riscv64/-/linux-riscv64-0.25.1.tgz",
+ "integrity": "sha512-nSut/Mx5gnilhcq2yIMLMe3Wl4FK5wx/o0QuuCLMtmJn+WeWYoEGDN1ipcN72g1WHsnIbxGXd4i/MF0gTcuAjQ==",
+ "cpu": [
+ "riscv64"
+ ],
+ "dev": true,
+ "license": "MIT",
+ "optional": true,
+ "os": [
+ "linux"
+ ],
+ "engines": {
+ "node": ">=18"
+ }
+ },
+ "node_modules/@esbuild/linux-s390x": {
+ "version": "0.25.1",
+ "resolved": "https://registry.npmjs.org/@esbuild/linux-s390x/-/linux-s390x-0.25.1.tgz",
+ "integrity": "sha512-cEECeLlJNfT8kZHqLarDBQso9a27o2Zd2AQ8USAEoGtejOrCYHNtKP8XQhMDJMtthdF4GBmjR2au3x1udADQQQ==",
+ "cpu": [
+ "s390x"
+ ],
+ "dev": true,
+ "license": "MIT",
+ "optional": true,
+ "os": [
+ "linux"
+ ],
+ "engines": {
+ "node": ">=18"
+ }
+ },
+ "node_modules/@esbuild/linux-x64": {
+ "version": "0.25.1",
+ "resolved": "https://registry.npmjs.org/@esbuild/linux-x64/-/linux-x64-0.25.1.tgz",
+ "integrity": "sha512-xbfUhu/gnvSEg+EGovRc+kjBAkrvtk38RlerAzQxvMzlB4fXpCFCeUAYzJvrnhFtdeyVCDANSjJvOvGYoeKzFA==",
+ "cpu": [
+ "x64"
+ ],
+ "dev": true,
+ "license": "MIT",
+ "optional": true,
+ "os": [
+ "linux"
+ ],
+ "engines": {
+ "node": ">=18"
+ }
+ },
+ "node_modules/@esbuild/netbsd-arm64": {
+ "version": "0.25.1",
+ "resolved": "https://registry.npmjs.org/@esbuild/netbsd-arm64/-/netbsd-arm64-0.25.1.tgz",
+ "integrity": "sha512-O96poM2XGhLtpTh+s4+nP7YCCAfb4tJNRVZHfIE7dgmax+yMP2WgMd2OecBuaATHKTHsLWHQeuaxMRnCsH8+5g==",
+ "cpu": [
+ "arm64"
+ ],
+ "dev": true,
+ "license": "MIT",
+ "optional": true,
+ "os": [
+ "netbsd"
+ ],
+ "engines": {
+ "node": ">=18"
+ }
+ },
+ "node_modules/@esbuild/netbsd-x64": {
+ "version": "0.25.1",
+ "resolved": "https://registry.npmjs.org/@esbuild/netbsd-x64/-/netbsd-x64-0.25.1.tgz",
+ "integrity": "sha512-X53z6uXip6KFXBQ+Krbx25XHV/NCbzryM6ehOAeAil7X7oa4XIq+394PWGnwaSQ2WRA0KI6PUO6hTO5zeF5ijA==",
+ "cpu": [
+ "x64"
+ ],
+ "dev": true,
+ "license": "MIT",
+ "optional": true,
+ "os": [
+ "netbsd"
+ ],
+ "engines": {
+ "node": ">=18"
+ }
+ },
+ "node_modules/@esbuild/openbsd-arm64": {
+ "version": "0.25.1",
+ "resolved": "https://registry.npmjs.org/@esbuild/openbsd-arm64/-/openbsd-arm64-0.25.1.tgz",
+ "integrity": "sha512-Na9T3szbXezdzM/Kfs3GcRQNjHzM6GzFBeU1/6IV/npKP5ORtp9zbQjvkDJ47s6BCgaAZnnnu/cY1x342+MvZg==",
+ "cpu": [
+ "arm64"
+ ],
+ "dev": true,
+ "license": "MIT",
+ "optional": true,
+ "os": [
+ "openbsd"
+ ],
+ "engines": {
+ "node": ">=18"
+ }
+ },
+ "node_modules/@esbuild/openbsd-x64": {
+ "version": "0.25.1",
+ "resolved": "https://registry.npmjs.org/@esbuild/openbsd-x64/-/openbsd-x64-0.25.1.tgz",
+ "integrity": "sha512-T3H78X2h1tszfRSf+txbt5aOp/e7TAz3ptVKu9Oyir3IAOFPGV6O9c2naym5TOriy1l0nNf6a4X5UXRZSGX/dw==",
+ "cpu": [
+ "x64"
+ ],
+ "dev": true,
+ "license": "MIT",
+ "optional": true,
+ "os": [
+ "openbsd"
+ ],
+ "engines": {
+ "node": ">=18"
+ }
+ },
+ "node_modules/@esbuild/sunos-x64": {
+ "version": "0.25.1",
+ "resolved": "https://registry.npmjs.org/@esbuild/sunos-x64/-/sunos-x64-0.25.1.tgz",
+ "integrity": "sha512-2H3RUvcmULO7dIE5EWJH8eubZAI4xw54H1ilJnRNZdeo8dTADEZ21w6J22XBkXqGJbe0+wnNJtw3UXRoLJnFEg==",
+ "cpu": [
+ "x64"
+ ],
+ "dev": true,
+ "license": "MIT",
+ "optional": true,
+ "os": [
+ "sunos"
+ ],
+ "engines": {
+ "node": ">=18"
+ }
+ },
+ "node_modules/@esbuild/win32-arm64": {
+ "version": "0.25.1",
+ "resolved": "https://registry.npmjs.org/@esbuild/win32-arm64/-/win32-arm64-0.25.1.tgz",
+ "integrity": "sha512-GE7XvrdOzrb+yVKB9KsRMq+7a2U/K5Cf/8grVFRAGJmfADr/e/ODQ134RK2/eeHqYV5eQRFxb1hY7Nr15fv1NQ==",
+ "cpu": [
+ "arm64"
+ ],
+ "dev": true,
+ "license": "MIT",
+ "optional": true,
+ "os": [
+ "win32"
+ ],
+ "engines": {
+ "node": ">=18"
+ }
+ },
+ "node_modules/@esbuild/win32-ia32": {
+ "version": "0.25.1",
+ "resolved": "https://registry.npmjs.org/@esbuild/win32-ia32/-/win32-ia32-0.25.1.tgz",
+ "integrity": "sha512-uOxSJCIcavSiT6UnBhBzE8wy3n0hOkJsBOzy7HDAuTDE++1DJMRRVCPGisULScHL+a/ZwdXPpXD3IyFKjA7K8A==",
+ "cpu": [
+ "ia32"
+ ],
+ "dev": true,
+ "license": "MIT",
+ "optional": true,
+ "os": [
+ "win32"
+ ],
+ "engines": {
+ "node": ">=18"
+ }
+ },
+ "node_modules/@esbuild/win32-x64": {
+ "version": "0.25.1",
+ "resolved": "https://registry.npmjs.org/@esbuild/win32-x64/-/win32-x64-0.25.1.tgz",
+ "integrity": "sha512-Y1EQdcfwMSeQN/ujR5VayLOJ1BHaK+ssyk0AEzPjC+t1lITgsnccPqFjb6V+LsTp/9Iov4ysfjxLaGJ9RPtkVg==",
+ "cpu": [
+ "x64"
+ ],
+ "dev": true,
+ "license": "MIT",
+ "optional": true,
+ "os": [
+ "win32"
+ ],
+ "engines": {
+ "node": ">=18"
+ }
+ },
+ "node_modules/esbuild": {
+ "version": "0.25.1",
+ "resolved": "https://registry.npmjs.org/esbuild/-/esbuild-0.25.1.tgz",
+ "integrity": "sha512-BGO5LtrGC7vxnqucAe/rmvKdJllfGaYWdyABvyMoXQlfYMb2bbRuReWR5tEGE//4LcNJj9XrkovTqNYRFZHAMQ==",
+ "dev": true,
+ "hasInstallScript": true,
+ "license": "MIT",
+ "bin": {
+ "esbuild": "bin/esbuild"
+ },
+ "engines": {
+ "node": ">=18"
+ },
+ "optionalDependencies": {
+ "@esbuild/aix-ppc64": "0.25.1",
+ "@esbuild/android-arm": "0.25.1",
+ "@esbuild/android-arm64": "0.25.1",
+ "@esbuild/android-x64": "0.25.1",
+ "@esbuild/darwin-arm64": "0.25.1",
+ "@esbuild/darwin-x64": "0.25.1",
+ "@esbuild/freebsd-arm64": "0.25.1",
+ "@esbuild/freebsd-x64": "0.25.1",
+ "@esbuild/linux-arm": "0.25.1",
+ "@esbuild/linux-arm64": "0.25.1",
+ "@esbuild/linux-ia32": "0.25.1",
+ "@esbuild/linux-loong64": "0.25.1",
+ "@esbuild/linux-mips64el": "0.25.1",
+ "@esbuild/linux-ppc64": "0.25.1",
+ "@esbuild/linux-riscv64": "0.25.1",
+ "@esbuild/linux-s390x": "0.25.1",
+ "@esbuild/linux-x64": "0.25.1",
+ "@esbuild/netbsd-arm64": "0.25.1",
+ "@esbuild/netbsd-x64": "0.25.1",
+ "@esbuild/openbsd-arm64": "0.25.1",
+ "@esbuild/openbsd-x64": "0.25.1",
+ "@esbuild/sunos-x64": "0.25.1",
+ "@esbuild/win32-arm64": "0.25.1",
+ "@esbuild/win32-ia32": "0.25.1",
+ "@esbuild/win32-x64": "0.25.1"
+ }
+ },
+ "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"
+ }
+ }
+ }
+}
diff --git a/examples/upload-browser/package.json b/examples/upload-browser/package.json
new file mode 100644
index 0000000..60b3e29
--- /dev/null
+++ b/examples/upload-browser/package.json
@@ -0,0 +1,18 @@
+{
+ "name": "@codex-storage/sdk-js-update-browser-example",
+ "version": "1.0.0",
+ "main": "index.js",
+ "scripts": {
+ "build": "node esbuild.js"
+ },
+ "author": "",
+ "license": "ISC",
+ "description": "",
+ "dependencies": {
+ "@codex-storage/sdk-js": "../.."
+ },
+ "devDependencies": {
+ "esbuild": "^0.25.1",
+ "prettier": "^3.5.3"
+ }
+}
diff --git a/examples/upload-node/README.md b/examples/upload-node/README.md
new file mode 100644
index 0000000..d1ebb90
--- /dev/null
+++ b/examples/upload-node/README.md
@@ -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".
diff --git a/examples/upload-node/index.js b/examples/upload-node/index.js
new file mode 100644
index 0000000..a674da5
--- /dev/null
+++ b/examples/upload-node/index.js
@@ -0,0 +1,23 @@
+const { Codex } = require("@codex-storage/sdk-js");
+const { NodeUploadStategy } = 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 stategy = new NodeUploadStategy("Hello World !");
+ const uploadResponse = data.upload(stategy);
+
+ const res = await uploadResponse.result;
+
+ if (res.error) {
+ console.error(res.data);
+ return;
+ }
+
+ console.info("CID is", res.data);
+}
+
+main();
diff --git a/examples/upload-node/package-lock.json b/examples/upload-node/package-lock.json
new file mode 100644
index 0000000..65237cc
--- /dev/null
+++ b/examples/upload-node/package-lock.json
@@ -0,0 +1,64 @@
+{
+ "name": "@codex-storage/sdk-js-update-node-example",
+ "version": "1.0.0",
+ "lockfileVersion": 3,
+ "requires": true,
+ "packages": {
+ "": {
+ "name": "@codex-storage/sdk-js-update-node-example",
+ "version": "1.0.0",
+ "license": "ISC",
+ "dependencies": {
+ "@codex-storage/sdk-js": "../.."
+ },
+ "devDependencies": {
+ "prettier": "^3.5.3"
+ }
+ },
+ "..": {
+ "extraneous": true
+ },
+ "../..": {
+ "name": "@codex-storage/sdk-js",
+ "version": "0.0.23",
+ "license": "MIT",
+ "dependencies": {
+ "undici": "^7.5.0",
+ "valibot": "^0.32.0"
+ },
+ "devDependencies": {
+ "@tsconfig/strictest": "^2.0.5",
+ "prettier": "^3.5.3",
+ "tsup": "^8.3.6",
+ "typescript": "^5.8.2",
+ "vitest": "^3.0.9"
+ },
+ "engines": {
+ "node": ">=20.18.1"
+ }
+ },
+ "../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"
+ }
+ }
+ }
+}
diff --git a/examples/upload-node/package.json b/examples/upload-node/package.json
new file mode 100644
index 0000000..0629a13
--- /dev/null
+++ b/examples/upload-node/package.json
@@ -0,0 +1,17 @@
+{
+ "name": "@codex-storage/sdk-js-update-node-example",
+ "version": "1.0.0",
+ "main": "index.js",
+ "scripts": {
+ "build": "node esbuild.js"
+ },
+ "author": "",
+ "license": "ISC",
+ "description": "",
+ "dependencies": {
+ "@codex-storage/sdk-js": "../.."
+ },
+ "devDependencies": {
+ "prettier": "^3.5.3"
+ }
+}
diff --git a/package-lock.json b/package-lock.json
index dafefa5..80a8b10 100644
--- a/package-lock.json
+++ b/package-lock.json
@@ -1,25 +1,26 @@
{
"name": "@codex-storage/sdk-js",
- "version": "0.0.23",
+ "version": "0.1.0",
"lockfileVersion": 3,
"requires": true,
"packages": {
"": {
"name": "@codex-storage/sdk-js",
- "version": "0.0.23",
+ "version": "0.1.0",
"license": "MIT",
"dependencies": {
+ "undici": "^7.5.0",
"valibot": "^0.32.0"
},
"devDependencies": {
"@tsconfig/strictest": "^2.0.5",
- "prettier": "^3.4.2",
+ "prettier": "^3.5.3",
"tsup": "^8.3.6",
- "typescript": "^5.7.3",
- "vitest": "^3.0.5"
+ "typescript": "^5.8.2",
+ "vitest": "^3.0.9"
},
"engines": {
- "node": ">=20"
+ "node": ">=20.18.1"
}
},
"node_modules/@esbuild/aix-ppc64": {
@@ -801,15 +802,15 @@
"dev": true
},
"node_modules/@vitest/expect": {
- "version": "3.0.5",
- "resolved": "https://registry.npmjs.org/@vitest/expect/-/expect-3.0.5.tgz",
- "integrity": "sha512-nNIOqupgZ4v5jWuQx2DSlHLEs7Q4Oh/7AYwNyE+k0UQzG7tSmjPXShUikn1mpNGzYEN2jJbTvLejwShMitovBA==",
+ "version": "3.0.9",
+ "resolved": "https://registry.npmjs.org/@vitest/expect/-/expect-3.0.9.tgz",
+ "integrity": "sha512-5eCqRItYgIML7NNVgJj6TVCmdzE7ZVgJhruW0ziSQV4V7PvLkDL1bBkBdcTs/VuIz0IxPb5da1IDSqc1TR9eig==",
"dev": true,
"license": "MIT",
"dependencies": {
- "@vitest/spy": "3.0.5",
- "@vitest/utils": "3.0.5",
- "chai": "^5.1.2",
+ "@vitest/spy": "3.0.9",
+ "@vitest/utils": "3.0.9",
+ "chai": "^5.2.0",
"tinyrainbow": "^2.0.0"
},
"funding": {
@@ -817,13 +818,13 @@
}
},
"node_modules/@vitest/mocker": {
- "version": "3.0.5",
- "resolved": "https://registry.npmjs.org/@vitest/mocker/-/mocker-3.0.5.tgz",
- "integrity": "sha512-CLPNBFBIE7x6aEGbIjaQAX03ZZlBMaWwAjBdMkIf/cAn6xzLTiM3zYqO/WAbieEjsAZir6tO71mzeHZoodThvw==",
+ "version": "3.0.9",
+ "resolved": "https://registry.npmjs.org/@vitest/mocker/-/mocker-3.0.9.tgz",
+ "integrity": "sha512-ryERPIBOnvevAkTq+L1lD+DTFBRcjueL9lOUfXsLfwP92h4e+Heb+PjiqS3/OURWPtywfafK0kj++yDFjWUmrA==",
"dev": true,
"license": "MIT",
"dependencies": {
- "@vitest/spy": "3.0.5",
+ "@vitest/spy": "3.0.9",
"estree-walker": "^3.0.3",
"magic-string": "^0.30.17"
},
@@ -844,9 +845,9 @@
}
},
"node_modules/@vitest/pretty-format": {
- "version": "3.0.5",
- "resolved": "https://registry.npmjs.org/@vitest/pretty-format/-/pretty-format-3.0.5.tgz",
- "integrity": "sha512-CjUtdmpOcm4RVtB+up8r2vVDLR16Mgm/bYdkGFe3Yj/scRfCpbSi2W/BDSDcFK7ohw8UXvjMbOp9H4fByd/cOA==",
+ "version": "3.0.9",
+ "resolved": "https://registry.npmjs.org/@vitest/pretty-format/-/pretty-format-3.0.9.tgz",
+ "integrity": "sha512-OW9F8t2J3AwFEwENg3yMyKWweF7oRJlMyHOMIhO5F3n0+cgQAJZBjNgrF8dLwFTEXl5jUqBLXd9QyyKv8zEcmA==",
"dev": true,
"license": "MIT",
"dependencies": {
@@ -857,38 +858,38 @@
}
},
"node_modules/@vitest/runner": {
- "version": "3.0.5",
- "resolved": "https://registry.npmjs.org/@vitest/runner/-/runner-3.0.5.tgz",
- "integrity": "sha512-BAiZFityFexZQi2yN4OX3OkJC6scwRo8EhRB0Z5HIGGgd2q+Nq29LgHU/+ovCtd0fOfXj5ZI6pwdlUmC5bpi8A==",
+ "version": "3.0.9",
+ "resolved": "https://registry.npmjs.org/@vitest/runner/-/runner-3.0.9.tgz",
+ "integrity": "sha512-NX9oUXgF9HPfJSwl8tUZCMP1oGx2+Sf+ru6d05QjzQz4OwWg0psEzwY6VexP2tTHWdOkhKHUIZH+fS6nA7jfOw==",
"dev": true,
"license": "MIT",
"dependencies": {
- "@vitest/utils": "3.0.5",
- "pathe": "^2.0.2"
+ "@vitest/utils": "3.0.9",
+ "pathe": "^2.0.3"
},
"funding": {
"url": "https://opencollective.com/vitest"
}
},
"node_modules/@vitest/snapshot": {
- "version": "3.0.5",
- "resolved": "https://registry.npmjs.org/@vitest/snapshot/-/snapshot-3.0.5.tgz",
- "integrity": "sha512-GJPZYcd7v8QNUJ7vRvLDmRwl+a1fGg4T/54lZXe+UOGy47F9yUfE18hRCtXL5aHN/AONu29NGzIXSVFh9K0feA==",
+ "version": "3.0.9",
+ "resolved": "https://registry.npmjs.org/@vitest/snapshot/-/snapshot-3.0.9.tgz",
+ "integrity": "sha512-AiLUiuZ0FuA+/8i19mTYd+re5jqjEc2jZbgJ2up0VY0Ddyyxg/uUtBDpIFAy4uzKaQxOW8gMgBdAJJ2ydhu39A==",
"dev": true,
"license": "MIT",
"dependencies": {
- "@vitest/pretty-format": "3.0.5",
+ "@vitest/pretty-format": "3.0.9",
"magic-string": "^0.30.17",
- "pathe": "^2.0.2"
+ "pathe": "^2.0.3"
},
"funding": {
"url": "https://opencollective.com/vitest"
}
},
"node_modules/@vitest/spy": {
- "version": "3.0.5",
- "resolved": "https://registry.npmjs.org/@vitest/spy/-/spy-3.0.5.tgz",
- "integrity": "sha512-5fOzHj0WbUNqPK6blI/8VzZdkBlQLnT25knX0r4dbZI9qoZDf3qAdjoMmDcLG5A83W6oUUFJgUd0EYBc2P5xqg==",
+ "version": "3.0.9",
+ "resolved": "https://registry.npmjs.org/@vitest/spy/-/spy-3.0.9.tgz",
+ "integrity": "sha512-/CcK2UDl0aQ2wtkp3YVWldrpLRNCfVcIOFGlVGKO4R5eajsH393Z1yiXLVQ7vWsj26JOEjeZI0x5sm5P4OGUNQ==",
"dev": true,
"license": "MIT",
"dependencies": {
@@ -899,14 +900,14 @@
}
},
"node_modules/@vitest/utils": {
- "version": "3.0.5",
- "resolved": "https://registry.npmjs.org/@vitest/utils/-/utils-3.0.5.tgz",
- "integrity": "sha512-N9AX0NUoUtVwKwy21JtwzaqR5L5R5A99GAbrHfCCXK1lp593i/3AZAXhSP43wRQuxYsflrdzEfXZFo1reR1Nkg==",
+ "version": "3.0.9",
+ "resolved": "https://registry.npmjs.org/@vitest/utils/-/utils-3.0.9.tgz",
+ "integrity": "sha512-ilHM5fHhZ89MCp5aAaM9uhfl1c2JdxVxl3McqsdVyVNN6JffnEen8UMCdRTzOhGXNQGo5GNL9QugHrz727Wnng==",
"dev": true,
"license": "MIT",
"dependencies": {
- "@vitest/pretty-format": "3.0.5",
- "loupe": "^3.1.2",
+ "@vitest/pretty-format": "3.0.9",
+ "loupe": "^3.1.3",
"tinyrainbow": "^2.0.0"
},
"funding": {
@@ -994,9 +995,9 @@
}
},
"node_modules/chai": {
- "version": "5.1.2",
- "resolved": "https://registry.npmjs.org/chai/-/chai-5.1.2.tgz",
- "integrity": "sha512-aGtmf24DW6MLHHG5gCx4zaI3uBq3KRtxeVs0DjFH6Z0rDNbsvTxFASFvdj79pxjxZ8/5u3PIiN3IwEIQkiiuPw==",
+ "version": "5.2.0",
+ "resolved": "https://registry.npmjs.org/chai/-/chai-5.2.0.tgz",
+ "integrity": "sha512-mCuXncKXk5iCLhfhwTc0izo0gtEmpz5CtG2y8GiOINBlMVS6v8TMRc5TaLWKS6692m9+dVVfzgeVxR5UxWHTYw==",
"dev": true,
"license": "MIT",
"dependencies": {
@@ -1456,9 +1457,9 @@
}
},
"node_modules/pathe": {
- "version": "2.0.2",
- "resolved": "https://registry.npmjs.org/pathe/-/pathe-2.0.2.tgz",
- "integrity": "sha512-15Ztpk+nov8DR524R4BF7uEuzESgzUEAV4Ah7CUMNGXdE5ELuvxElxGXndBl32vMSsWa1jpNf22Z+Er3sKwq+w==",
+ "version": "2.0.3",
+ "resolved": "https://registry.npmjs.org/pathe/-/pathe-2.0.3.tgz",
+ "integrity": "sha512-WUjGcAqP1gQacoQe+OBJsFA7Ld4DyXuUIjZ5cc75cLHvJ7dtNsTugphxIADwspS+AraAUePCKrSVtPLFj/F88w==",
"dev": true,
"license": "MIT"
},
@@ -1572,9 +1573,9 @@
}
},
"node_modules/prettier": {
- "version": "3.4.2",
- "resolved": "https://registry.npmjs.org/prettier/-/prettier-3.4.2.tgz",
- "integrity": "sha512-e9MewbtFo+Fevyuxn/4rrcDAaq0IYxPGLvObpQjiZBMAzB9IGmzlnG9RZy3FFas+eBMu2vA0CszMeduow5dIuQ==",
+ "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": {
@@ -2005,9 +2006,9 @@
}
},
"node_modules/typescript": {
- "version": "5.7.3",
- "resolved": "https://registry.npmjs.org/typescript/-/typescript-5.7.3.tgz",
- "integrity": "sha512-84MVSjMEHP+FQRPy3pX9sTVV/INIex71s9TL2Gm5FG/WG1SqXeKyZ0k7/blY/4FdOzI12CBy1vGc4og/eus0fw==",
+ "version": "5.8.2",
+ "resolved": "https://registry.npmjs.org/typescript/-/typescript-5.8.2.tgz",
+ "integrity": "sha512-aJn6wq13/afZp/jT9QZmwEjDqqvSGp1VT5GVg+f/t6/oVyrgXM6BY1h9BRh/O5p3PlUPAe+WuiEZOmb/49RqoQ==",
"dev": true,
"license": "Apache-2.0",
"bin": {
@@ -2018,15 +2019,25 @@
"node": ">=14.17"
}
},
+ "node_modules/undici": {
+ "version": "7.5.0",
+ "resolved": "https://registry.npmjs.org/undici/-/undici-7.5.0.tgz",
+ "integrity": "sha512-NFQG741e8mJ0fLQk90xKxFdaSM7z4+IQpAgsFI36bCDY9Z2+aXXZjVy2uUksMouWfMI9+w5ejOq5zYYTBCQJDQ==",
+ "license": "MIT",
+ "engines": {
+ "node": ">=20.18.1"
+ }
+ },
"node_modules/valibot": {
"version": "0.32.0",
"resolved": "https://registry.npmjs.org/valibot/-/valibot-0.32.0.tgz",
- "integrity": "sha512-FXBnJl4bNOmeg7lQv+jfvo/wADsRBN8e9C3r+O77Re3dEnDma8opp7p4hcIbF7XJJ30h/5SVohdjer17/sHOsQ=="
+ "integrity": "sha512-FXBnJl4bNOmeg7lQv+jfvo/wADsRBN8e9C3r+O77Re3dEnDma8opp7p4hcIbF7XJJ30h/5SVohdjer17/sHOsQ==",
+ "license": "MIT"
},
"node_modules/vite": {
- "version": "6.2.0",
- "resolved": "https://registry.npmjs.org/vite/-/vite-6.2.0.tgz",
- "integrity": "sha512-7dPxoo+WsT/64rDcwoOjk76XHj+TqNTIvHKcuMQ1k4/SeHDaQt5GFAeLYzrimZrMpn/O6DtdI03WUjdxuPM0oQ==",
+ "version": "6.2.3",
+ "resolved": "https://registry.npmjs.org/vite/-/vite-6.2.3.tgz",
+ "integrity": "sha512-IzwM54g4y9JA/xAeBPNaDXiBF8Jsgl3VBQ2YQ/wOY6fyW3xMdSoltIV3Bo59DErdqdE6RxUfv8W69DvUorE4Eg==",
"dev": true,
"license": "MIT",
"dependencies": {
@@ -2096,16 +2107,16 @@
}
},
"node_modules/vite-node": {
- "version": "3.0.5",
- "resolved": "https://registry.npmjs.org/vite-node/-/vite-node-3.0.5.tgz",
- "integrity": "sha512-02JEJl7SbtwSDJdYS537nU6l+ktdvcREfLksk/NDAqtdKWGqHl+joXzEubHROmS3E6pip+Xgu2tFezMu75jH7A==",
+ "version": "3.0.9",
+ "resolved": "https://registry.npmjs.org/vite-node/-/vite-node-3.0.9.tgz",
+ "integrity": "sha512-w3Gdx7jDcuT9cNn9jExXgOyKmf5UOTb6WMHz8LGAm54eS1Elf5OuBhCxl6zJxGhEeIkgsE1WbHuoL0mj/UXqXg==",
"dev": true,
"license": "MIT",
"dependencies": {
"cac": "^6.7.14",
"debug": "^4.4.0",
"es-module-lexer": "^1.6.0",
- "pathe": "^2.0.2",
+ "pathe": "^2.0.3",
"vite": "^5.0.0 || ^6.0.0"
},
"bin": {
@@ -2119,31 +2130,31 @@
}
},
"node_modules/vitest": {
- "version": "3.0.5",
- "resolved": "https://registry.npmjs.org/vitest/-/vitest-3.0.5.tgz",
- "integrity": "sha512-4dof+HvqONw9bvsYxtkfUp2uHsTN9bV2CZIi1pWgoFpL1Lld8LA1ka9q/ONSsoScAKG7NVGf2stJTI7XRkXb2Q==",
+ "version": "3.0.9",
+ "resolved": "https://registry.npmjs.org/vitest/-/vitest-3.0.9.tgz",
+ "integrity": "sha512-BbcFDqNyBlfSpATmTtXOAOj71RNKDDvjBM/uPfnxxVGrG+FSH2RQIwgeEngTaTkuU/h0ScFvf+tRcKfYXzBybQ==",
"dev": true,
"license": "MIT",
"dependencies": {
- "@vitest/expect": "3.0.5",
- "@vitest/mocker": "3.0.5",
- "@vitest/pretty-format": "^3.0.5",
- "@vitest/runner": "3.0.5",
- "@vitest/snapshot": "3.0.5",
- "@vitest/spy": "3.0.5",
- "@vitest/utils": "3.0.5",
- "chai": "^5.1.2",
+ "@vitest/expect": "3.0.9",
+ "@vitest/mocker": "3.0.9",
+ "@vitest/pretty-format": "^3.0.9",
+ "@vitest/runner": "3.0.9",
+ "@vitest/snapshot": "3.0.9",
+ "@vitest/spy": "3.0.9",
+ "@vitest/utils": "3.0.9",
+ "chai": "^5.2.0",
"debug": "^4.4.0",
"expect-type": "^1.1.0",
"magic-string": "^0.30.17",
- "pathe": "^2.0.2",
+ "pathe": "^2.0.3",
"std-env": "^3.8.0",
"tinybench": "^2.9.0",
"tinyexec": "^0.3.2",
"tinypool": "^1.0.2",
"tinyrainbow": "^2.0.0",
"vite": "^5.0.0 || ^6.0.0",
- "vite-node": "3.0.5",
+ "vite-node": "3.0.9",
"why-is-node-running": "^2.3.0"
},
"bin": {
@@ -2159,8 +2170,8 @@
"@edge-runtime/vm": "*",
"@types/debug": "^4.1.12",
"@types/node": "^18.0.0 || ^20.0.0 || >=22.0.0",
- "@vitest/browser": "3.0.5",
- "@vitest/ui": "3.0.5",
+ "@vitest/browser": "3.0.9",
+ "@vitest/ui": "3.0.9",
"happy-dom": "*",
"jsdom": "*"
},
diff --git a/package.json b/package.json
index 12592d9..4355d39 100644
--- a/package.json
+++ b/package.json
@@ -1,6 +1,6 @@
{
"name": "@codex-storage/sdk-js",
- "version": "0.0.23",
+ "version": "0.1.0",
"description": "Codex SDK to interact with the Codex decentralized storage network.",
"repository": {
"type": "git",
@@ -9,7 +9,7 @@
"scripts": {
"prepack": "npm run build",
"prebuild": "npm run compile && rm -Rf dist/*",
- "build": "tsup src/index.ts src/async.ts --format esm,cjs --dts --sourcemap --treeshake",
+ "build": "tsup src/index.ts src/async.ts src/browser.ts src/node.ts --format esm,cjs --dts --sourcemap --treeshake",
"compile": "tsc --noEmit",
"test": "vitest run",
"test:watch": "vitest",
@@ -35,6 +35,26 @@
"default": "./dist/index.js"
}
},
+ "./browser": {
+ "import": {
+ "types": "./dist/browser.d.ts",
+ "default": "./dist/browser.mjs"
+ },
+ "require": {
+ "types": "./dist/browser.d.cts",
+ "default": "./dist/browser.js"
+ }
+ },
+ "./node": {
+ "import": {
+ "types": "./dist/node.d.ts",
+ "default": "./dist/node.mjs"
+ },
+ "require": {
+ "types": "./dist/node.d.cts",
+ "default": "./dist/node.js"
+ }
+ },
"./async": {
"import": {
"types": "./dist/async.d.ts",
@@ -46,7 +66,6 @@
}
}
},
- "sideEffects": false,
"files": [
"dist"
],
@@ -54,16 +73,17 @@
"readme": "README.md",
"license": "MIT",
"engines": {
- "node": ">=20"
+ "node": ">=20.18.1"
},
"devDependencies": {
"@tsconfig/strictest": "^2.0.5",
- "prettier": "^3.4.2",
+ "prettier": "^3.5.3",
"tsup": "^8.3.6",
- "typescript": "^5.7.3",
- "vitest": "^3.0.5"
+ "typescript": "^5.8.2",
+ "vitest": "^3.0.9"
},
"dependencies": {
+ "undici": "^7.5.0",
"valibot": "^0.32.0"
}
-}
\ No newline at end of file
+}
diff --git a/src/browser.ts b/src/browser.ts
new file mode 100644
index 0000000..69455b7
--- /dev/null
+++ b/src/browser.ts
@@ -0,0 +1 @@
+export * from "./data/browser-upload";
diff --git a/src/data/browser-upload.ts b/src/data/browser-upload.ts
new file mode 100644
index 0000000..8ddf0c5
--- /dev/null
+++ b/src/data/browser-upload.ts
@@ -0,0 +1,74 @@
+import { CodexError } from "../errors/errors";
+import type { SafeValue } from "../values/values";
+import type { UploadStategy } from "./types";
+
+export class BrowserUploadStategy implements UploadStategy {
+ private readonly file: Document | XMLHttpRequestBodyInit;
+ private readonly onProgress:
+ | ((loaded: number, total: number) => void)
+ | undefined;
+ private readonly metadata:
+ | { filename?: string; mimetype?: string }
+ | undefined;
+ private xhr: XMLHttpRequest | undefined;
+
+ constructor(
+ file: Document | XMLHttpRequestBodyInit,
+ onProgress?: (loaded: number, total: number) => void,
+ metadata?: { filename?: string; mimetype?: string }
+ ) {
+ this.file = file;
+ this.onProgress = onProgress;
+ this.metadata = metadata;
+ }
+
+ download(url: string): Promise> {
+ const xhr = new XMLHttpRequest();
+ this.xhr = xhr;
+
+ return new Promise>((resolve) => {
+ xhr.upload.onprogress = (evt) => {
+ if (evt.lengthComputable) {
+ this.onProgress?.(evt.loaded, evt.total);
+ }
+ };
+
+ xhr.open("POST", url, true);
+
+ if (this.metadata?.filename) {
+ xhr.setRequestHeader(
+ "Content-Disposition",
+ 'attachment; filename="' + this.metadata.filename + '"'
+ );
+ }
+
+ if (this.metadata?.mimetype) {
+ xhr.setRequestHeader("Content-Type", this.metadata.mimetype);
+ }
+
+ xhr.send(this.file);
+
+ xhr.onload = function () {
+ if (xhr.status != 200) {
+ resolve({
+ error: true,
+ data: new CodexError(xhr.responseText, { code: xhr.status }),
+ });
+ } else {
+ resolve({ error: false, data: xhr.response });
+ }
+ };
+
+ xhr.onerror = function () {
+ resolve({
+ error: true,
+ data: new CodexError("Something went wrong during the file upload."),
+ });
+ };
+ });
+ }
+
+ abort(): void {
+ this.xhr?.abort();
+ }
+}
diff --git a/src/data/data.ts b/src/data/data.ts
index ed67120..bc5688a 100644
--- a/src/data/data.ts
+++ b/src/data/data.ts
@@ -1,11 +1,11 @@
import { Api } from "../api/config";
-import { CodexError } from "../errors/errors";
import { Fetch } from "../fetch-safe/fetch-safe";
import type { SafeValue } from "../values/values";
import type {
CodexDataResponse,
CodexManifest,
CodexNodeSpace,
+ UploadStategy,
NetworkDownloadResponse,
UploadResponse,
} from "./types";
@@ -24,20 +24,15 @@ export class CodexData {
cids(): Promise> {
const url = this.url + Api.config.prefix + "/data";
- return Fetch.safeJson(url, {
- method: "GET",
- }).then((data) => {
- if (data.error) {
- return data;
- }
+ return Fetch.safeJson(url, { method: "GET" }).then(
+ (data) => {
+ if (data.error) {
+ return data;
+ }
- return {
- error: false,
- data: {
- content: data.data.content,
- },
- };
- });
+ return { error: false, data: { content: data.data.content } };
+ }
+ );
}
/**
@@ -46,9 +41,7 @@ export class CodexData {
space() {
const url = this.url + Api.config.prefix + "/space";
- return Fetch.safeJson(url, {
- method: "GET",
- });
+ return Fetch.safeJson(url, { method: "GET" });
}
/**
@@ -57,59 +50,13 @@ export class CodexData {
* XMLHttpRequest is used instead of fetch for this case, to obtain progress information.
* A callback onProgress can be passed to receive upload progress data information.
*/
- upload(
- file: Document | XMLHttpRequestBodyInit,
- onProgress?: (loaded: number, total: number) => void,
- metadata: { filename?: string, mimetype?: string } = {},
- ): UploadResponse {
+ upload(stategy: UploadStategy): UploadResponse {
const url = this.url + Api.config.prefix + "/data";
- const xhr = new XMLHttpRequest();
-
- const promise = new Promise>((resolve) => {
- xhr.upload.onprogress = (evt) => {
- if (evt.lengthComputable) {
- onProgress?.(evt.loaded, evt.total);
- }
- };
-
- xhr.open("POST", url, true);
-
- if (metadata.filename) {
- xhr.setRequestHeader("Content-Disposition", "attachment; filename=\"" + metadata.filename + "\"")
- }
-
- if (metadata.mimetype) {
- xhr.setRequestHeader("Content-Type", metadata.mimetype)
- }
-
- xhr.send(file);
-
- xhr.onload = function () {
- if (xhr.status != 200) {
- resolve({
- error: true,
- data: new CodexError(xhr.responseText, {
- code: xhr.status,
- }),
- });
- } else {
- resolve({ error: false, data: xhr.response });
- }
- };
-
- xhr.onerror = function () {
- resolve({
- error: true,
- data: new CodexError("Something went wrong during the file upload."),
- });
- };
- });
-
return {
- result: promise,
+ result: stategy.download(url),
abort: () => {
- xhr.abort();
+ stategy.abort();
},
};
}
@@ -121,44 +68,38 @@ export class CodexData {
async localDownload(cid: string): Promise> {
const url = this.url + Api.config.prefix + "/data/" + cid;
- return Fetch.safe(url, {
- method: "GET",
- });
+ return Fetch.safe(url, { method: "GET" });
}
/**
* 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.
*/
- async networkDownload(cid: string): Promise> {
+ async networkDownload(
+ cid: string
+ ): Promise> {
const url = this.url + Api.config.prefix + `/data/${cid}/network`;
- return Fetch.safeJson(url, {
- method: "POST"
- });
+ return Fetch.safeJson(url, { method: "POST" });
}
/**
- * Download a file from the network in a streaming manner.
+ * Download a file from the network in a streaming manner.
* If the file is not available locally, it will be retrieved from other nodes in the network if able.
*/
async networkDownloadStream(cid: string): Promise> {
const url = this.url + Api.config.prefix + `/data/${cid}/network/stream`;
- return Fetch.safe(url, {
- method: "GET"
- });
+ return Fetch.safe(url, { method: "GET" });
}
/**
- * 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.
*/
async fetchManifest(cid: string) {
const url = this.url + Api.config.prefix + `/data/${cid}/network/manifest`;
- return Fetch.safeJson(url, {
- method: "GET",
- });
+ return Fetch.safeJson(url, { method: "GET" });
}
}
diff --git a/src/data/node-upload.ts b/src/data/node-upload.ts
new file mode 100644
index 0000000..507b5e8
--- /dev/null
+++ b/src/data/node-upload.ts
@@ -0,0 +1,69 @@
+import type { Readable } from "node:stream";
+import { CodexError } from "../errors/errors";
+import type { SafeValue } from "../values/values";
+import Undici from "undici";
+import { type FormData } from "undici";
+import type { UploadStategy } from "./types";
+
+export class NodeUploadStategy implements UploadStategy {
+ private readonly body:
+ | string
+ | Buffer
+ | Uint8Array
+ | null
+ | Readable
+ | FormData;
+ private readonly metadata:
+ | { filename?: string; mimetype?: string }
+ | undefined;
+ private abortController: AbortController | undefined;
+
+ constructor(
+ body: string | Buffer | Uint8Array | null | Readable | FormData,
+ metadata?: { filename?: string; mimetype?: string }
+ ) {
+ this.body = body;
+ this.metadata = metadata;
+ }
+
+ async download(url: string): Promise> {
+ const headers: Record = {};
+
+ if (this.metadata?.filename) {
+ headers["Content-Disposition"] =
+ 'attachment; filename="' + this.metadata?.filename + '"';
+ }
+
+ if (this.metadata?.mimetype) {
+ headers["Content-Type"] = this.metadata?.mimetype;
+ }
+
+ const controller = new AbortController();
+ this.abortController = controller;
+
+ const res = await Undici.request(url, {
+ method: "POST",
+ headers,
+ body: this.body,
+ signal: controller.signal,
+ });
+
+ if (res.statusCode < 200 || res.statusCode >= 300) {
+ const msg = `The status code is invalid got ${res.statusCode} - ${await res.body.text()} `;
+ return {
+ error: true,
+ data: new CodexError(msg, { code: res.statusCode }),
+ };
+ }
+
+ return { error: false, data: await res.body.text() };
+ }
+
+ abort(): void {
+ try {
+ this.abortController?.abort();
+ } catch (_) {
+ // Nothing to do
+ }
+ }
+}
diff --git a/src/data/types.ts b/src/data/types.ts
index a086e67..25d4e67 100644
--- a/src/data/types.ts
+++ b/src/data/types.ts
@@ -51,9 +51,7 @@ export type CodexDataContent = {
manifest: CodexManifest;
};
-export type CodexDataResponse = {
- content: CodexDataContent[];
-};
+export type CodexDataResponse = { content: CodexDataContent[] };
export type CodexNodeSpace = {
/**
@@ -82,8 +80,9 @@ export type UploadResponse = {
abort: () => void;
};
+export type NetworkDownloadResponse = { cid: string; manifest: CodexManifest };
-export type NetworkDownloadResponse = {
- cid: string
- manifest: CodexManifest
-}
\ No newline at end of file
+export interface UploadStategy {
+ download(url: string): Promise>;
+ abort(): void;
+}
diff --git a/src/node.ts b/src/node.ts
new file mode 100644
index 0000000..2bc2425
--- /dev/null
+++ b/src/node.ts
@@ -0,0 +1 @@
+export * from "./data/node-upload";