@opendatalabs/vana-sdk 3.11.0 → 3.12.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +37 -1
- package/dist/index.browser.js +44 -7
- package/dist/index.browser.js.map +2 -2
- package/dist/index.node.cjs +44 -7
- package/dist/index.node.cjs.map +2 -2
- package/dist/index.node.js +44 -7
- package/dist/index.node.js.map +2 -2
- package/dist/storage/index.cjs.map +1 -1
- package/dist/storage/index.d.ts +1 -1
- package/dist/storage/index.js.map +1 -1
- package/dist/storage/providers/vana-storage.cjs +44 -7
- package/dist/storage/providers/vana-storage.cjs.map +1 -1
- package/dist/storage/providers/vana-storage.d.ts +33 -0
- package/dist/storage/providers/vana-storage.js +44 -7
- package/dist/storage/providers/vana-storage.js.map +1 -1
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -108,6 +108,42 @@ const result = await storage.upload(myBlob, "report.json");
|
|
|
108
108
|
console.log(result.url);
|
|
109
109
|
```
|
|
110
110
|
|
|
111
|
+
### Scope Vana storage to a protocol network
|
|
112
|
+
|
|
113
|
+
`VanaStorage` has two independent axes. `endpoint` is the **product host**
|
|
114
|
+
(e.g. `https://storage.vana.org` for production, `https://storage-dev.vana.org`
|
|
115
|
+
for internal staging). `network` is the **protocol network** (`mainnet` or
|
|
116
|
+
`moksha`) that scopes the blob path. They are not synonyms — `storage-dev` is a
|
|
117
|
+
staging host, not a stand-in for Moksha.
|
|
118
|
+
|
|
119
|
+
```typescript
|
|
120
|
+
import { createVanaStorageProvider } from "@opendatalabs/vana-sdk/node";
|
|
121
|
+
|
|
122
|
+
const storage = createVanaStorageProvider({
|
|
123
|
+
endpoint: "https://storage.vana.org", // product host
|
|
124
|
+
network: "moksha", // protocol namespace within that host
|
|
125
|
+
signer: {
|
|
126
|
+
address: account.address,
|
|
127
|
+
signMessage: (msg) => account.signMessage({ message: msg }),
|
|
128
|
+
},
|
|
129
|
+
});
|
|
130
|
+
|
|
131
|
+
// Uploads to /v1/networks/moksha/blobs/{owner}/{scope}/{collectedAt}
|
|
132
|
+
const result = await storage.upload(
|
|
133
|
+
myBlob,
|
|
134
|
+
"instagram.profile/2026-05-08T20:00:00.000Z",
|
|
135
|
+
);
|
|
136
|
+
```
|
|
137
|
+
|
|
138
|
+
When `network` is omitted, `VanaStorage` uses the legacy `/v1/blobs/...` routes,
|
|
139
|
+
preserving backward compatibility. The Web3Signed audience is always the
|
|
140
|
+
endpoint origin, never the network.
|
|
141
|
+
|
|
142
|
+
A network-configured provider still accepts legacy same-endpoint
|
|
143
|
+
`/v1/blobs/...` URLs so it can read or delete objects written before the opt-in,
|
|
144
|
+
but it rejects URLs scoped to a _different_ explicit network — a Moksha provider
|
|
145
|
+
won't act on a `mainnet`-scoped URL, and vice versa.
|
|
146
|
+
|
|
111
147
|
## Build a Vana app
|
|
112
148
|
|
|
113
149
|
Request user-approved data, read it from the user's Personal Server, and pay
|
|
@@ -262,7 +298,7 @@ in October 2025; the report is in [`audits/`](https://github.com/vana-com/vana-s
|
|
|
262
298
|
|
|
263
299
|
- [Documentation](https://docs.vana.org/docs/sdk)
|
|
264
300
|
- [API reference](https://vana-com.github.io/vana-sdk)
|
|
265
|
-
- [Discord](https://discord.gg/
|
|
301
|
+
- [Discord](https://discord.gg/vanaofficial)
|
|
266
302
|
|
|
267
303
|
## License
|
|
268
304
|
|
package/dist/index.browser.js
CHANGED
|
@@ -29028,12 +29028,14 @@ async function buildWeb3SignedHeader(params) {
|
|
|
29028
29028
|
|
|
29029
29029
|
// src/storage/providers/vana-storage.ts
|
|
29030
29030
|
var DEFAULT_ENDPOINT = "https://storage.vana.org";
|
|
29031
|
-
var
|
|
29031
|
+
var LEGACY_BLOB_PATH_PREFIX = "/v1/blobs";
|
|
29032
29032
|
var DEFAULT_TOKEN_TTL_SECONDS = 300;
|
|
29033
29033
|
var MAX_UPLOAD_ATTEMPTS = 4;
|
|
29034
29034
|
var MAX_RATE_LIMIT_DELAY_MS = 3e4;
|
|
29035
29035
|
var VanaStorage = class {
|
|
29036
29036
|
endpoint;
|
|
29037
|
+
network;
|
|
29038
|
+
blobPathPrefix;
|
|
29037
29039
|
signer;
|
|
29038
29040
|
ownerAddress;
|
|
29039
29041
|
fetchImpl;
|
|
@@ -29046,6 +29048,15 @@ var VanaStorage = class {
|
|
|
29046
29048
|
);
|
|
29047
29049
|
}
|
|
29048
29050
|
this.endpoint = (config.endpoint ?? DEFAULT_ENDPOINT).replace(/\/+$/, "");
|
|
29051
|
+
if (config.network !== void 0 && !isProtocolNetwork(config.network)) {
|
|
29052
|
+
throw new StorageError(
|
|
29053
|
+
`Unsupported vana-storage network '${String(config.network)}'`,
|
|
29054
|
+
"INVALID_NETWORK",
|
|
29055
|
+
"vana-storage"
|
|
29056
|
+
);
|
|
29057
|
+
}
|
|
29058
|
+
this.network = config.network;
|
|
29059
|
+
this.blobPathPrefix = this.network ? `/v1/networks/${this.network}/blobs` : LEGACY_BLOB_PATH_PREFIX;
|
|
29049
29060
|
this.signer = config.signer;
|
|
29050
29061
|
this.ownerAddress = (config.ownerAddress ?? config.signer.address).toLowerCase();
|
|
29051
29062
|
this.fetchImpl = config.fetchImpl ?? globalThis.fetch.bind(globalThis);
|
|
@@ -29066,7 +29077,7 @@ var VanaStorage = class {
|
|
|
29066
29077
|
);
|
|
29067
29078
|
}
|
|
29068
29079
|
const subpath = encodeRelativePath(filename);
|
|
29069
|
-
const path = `${
|
|
29080
|
+
const path = `${this.blobPathPrefix}/${this.ownerAddress}/${subpath}`;
|
|
29070
29081
|
const body = new Uint8Array(await file.arrayBuffer());
|
|
29071
29082
|
const contentType = file.type !== "" ? file.type : "application/octet-stream";
|
|
29072
29083
|
const header = await this.signRequest("PUT", path, body);
|
|
@@ -29234,12 +29245,18 @@ var VanaStorage = class {
|
|
|
29234
29245
|
"vana-storage"
|
|
29235
29246
|
);
|
|
29236
29247
|
}
|
|
29237
|
-
const
|
|
29238
|
-
|
|
29239
|
-
const valid = segments.length === 5 && segments[0] === "v1" && segments[1] === "blobs" && segments[2]?.toLowerCase() === this.ownerAddress && segments[3] !== void 0 && !isTraversal(segments[3]) && segments[4] !== void 0 && !isTraversal(segments[4]);
|
|
29240
|
-
if (!valid) {
|
|
29248
|
+
const route = parseBlobPath(parsed.pathname);
|
|
29249
|
+
if (!route || route.owner.toLowerCase() !== this.ownerAddress) {
|
|
29241
29250
|
throw new StorageError(
|
|
29242
|
-
`URL path '${parsed.pathname}' must be
|
|
29251
|
+
`URL path '${parsed.pathname}' must be ${this.blobPathPrefix}/${this.ownerAddress}/{scope}/{collectedAt}`,
|
|
29252
|
+
"INVALID_URL",
|
|
29253
|
+
"vana-storage"
|
|
29254
|
+
);
|
|
29255
|
+
}
|
|
29256
|
+
const crossNetwork = this.network ? route.network !== void 0 && route.network !== this.network : route.network !== void 0;
|
|
29257
|
+
if (crossNetwork) {
|
|
29258
|
+
throw new StorageError(
|
|
29259
|
+
`URL network '${route.network ?? "legacy"}' does not match provider network '${this.network ?? "legacy"}'`,
|
|
29243
29260
|
"INVALID_URL",
|
|
29244
29261
|
"vana-storage"
|
|
29245
29262
|
);
|
|
@@ -29247,6 +29264,26 @@ var VanaStorage = class {
|
|
|
29247
29264
|
return parsed.pathname;
|
|
29248
29265
|
}
|
|
29249
29266
|
};
|
|
29267
|
+
var PROTOCOL_NETWORKS = ["mainnet", "moksha"];
|
|
29268
|
+
function isProtocolNetwork(value) {
|
|
29269
|
+
return typeof value === "string" && PROTOCOL_NETWORKS.includes(value);
|
|
29270
|
+
}
|
|
29271
|
+
function parseBlobPath(pathname) {
|
|
29272
|
+
const segments = pathname.split("/").filter((s) => s.length > 0);
|
|
29273
|
+
const isTraversal = (s) => s === "." || s === "..";
|
|
29274
|
+
if (segments.length === 5 && segments[0] === "v1" && segments[1] === "blobs") {
|
|
29275
|
+
const [, , owner, scope, collectedAt] = segments;
|
|
29276
|
+
if (isTraversal(scope) || isTraversal(collectedAt)) return null;
|
|
29277
|
+
return { owner, scope, collectedAt };
|
|
29278
|
+
}
|
|
29279
|
+
if (segments.length === 7 && segments[0] === "v1" && segments[1] === "networks" && segments[3] === "blobs") {
|
|
29280
|
+
const [, , network, , owner, scope, collectedAt] = segments;
|
|
29281
|
+
if (!isProtocolNetwork(network)) return null;
|
|
29282
|
+
if (isTraversal(scope) || isTraversal(collectedAt)) return null;
|
|
29283
|
+
return { network, owner, scope, collectedAt };
|
|
29284
|
+
}
|
|
29285
|
+
return null;
|
|
29286
|
+
}
|
|
29250
29287
|
function encodeRelativePath(filename) {
|
|
29251
29288
|
const parts = filename.split("/");
|
|
29252
29289
|
if (parts.length !== 2 || parts.some((p) => p.length === 0 || p === "." || p === "..")) {
|