@opendatalabs/vana-sdk 3.15.0 → 3.17.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.
Files changed (50) hide show
  1. package/README.md +107 -0
  2. package/dist/errors.cjs +94 -2
  3. package/dist/errors.cjs.map +1 -1
  4. package/dist/errors.d.ts +123 -0
  5. package/dist/errors.js +82 -1
  6. package/dist/errors.js.map +1 -1
  7. package/dist/index.browser.d.ts +4 -0
  8. package/dist/index.browser.js +1155 -14
  9. package/dist/index.browser.js.map +4 -4
  10. package/dist/index.node.cjs +1205 -15
  11. package/dist/index.node.cjs.map +4 -4
  12. package/dist/index.node.d.ts +4 -0
  13. package/dist/index.node.js +1155 -14
  14. package/dist/index.node.js.map +4 -4
  15. package/dist/protocol/gateway.cjs +16 -2
  16. package/dist/protocol/gateway.cjs.map +1 -1
  17. package/dist/protocol/gateway.d.ts +2 -0
  18. package/dist/protocol/gateway.js +16 -2
  19. package/dist/protocol/gateway.js.map +1 -1
  20. package/dist/protocol/lineage.cjs +287 -0
  21. package/dist/protocol/lineage.cjs.map +1 -0
  22. package/dist/protocol/lineage.d.ts +228 -0
  23. package/dist/protocol/lineage.js +258 -0
  24. package/dist/protocol/lineage.js.map +1 -0
  25. package/dist/protocol/lineage.test.d.ts +1 -0
  26. package/dist/protocol/personal-server-error-body.cjs +57 -0
  27. package/dist/protocol/personal-server-error-body.cjs.map +1 -0
  28. package/dist/protocol/personal-server-error-body.d.ts +18 -0
  29. package/dist/protocol/personal-server-error-body.js +32 -0
  30. package/dist/protocol/personal-server-error-body.js.map +1 -0
  31. package/dist/protocol/personal-server-write.cjs +623 -0
  32. package/dist/protocol/personal-server-write.cjs.map +1 -0
  33. package/dist/protocol/personal-server-write.d.ts +284 -0
  34. package/dist/protocol/personal-server-write.js +601 -0
  35. package/dist/protocol/personal-server-write.js.map +1 -0
  36. package/dist/protocol/personal-server-write.test.d.ts +1 -0
  37. package/dist/protocol/scope-actions.cjs +185 -0
  38. package/dist/protocol/scope-actions.cjs.map +1 -0
  39. package/dist/protocol/scope-actions.d.ts +145 -0
  40. package/dist/protocol/scope-actions.js +154 -0
  41. package/dist/protocol/scope-actions.js.map +1 -0
  42. package/dist/protocol/scope-actions.test.d.ts +1 -0
  43. package/dist/protocol/write-signer.cjs +67 -0
  44. package/dist/protocol/write-signer.cjs.map +1 -0
  45. package/dist/protocol/write-signer.d.ts +59 -0
  46. package/dist/protocol/write-signer.js +43 -0
  47. package/dist/protocol/write-signer.js.map +1 -0
  48. package/dist/protocol/write-signer.test.d.ts +1 -0
  49. package/dist/tests/mock-personal-server.d.ts +127 -0
  50. package/package.json +1 -1
@@ -1279,6 +1279,76 @@ var TransactionPendingError = class extends VanaError {
1279
1279
  };
1280
1280
  }
1281
1281
  };
1282
+ var PersonalServerWriteError = class extends VanaError {
1283
+ constructor(message, code, status, errorCode = null, details) {
1284
+ super(message, code);
1285
+ this.status = status;
1286
+ this.errorCode = errorCode;
1287
+ this.details = details;
1288
+ }
1289
+ status;
1290
+ errorCode;
1291
+ details;
1292
+ };
1293
+ var WriteRequestError = class extends PersonalServerWriteError {
1294
+ constructor(message, details) {
1295
+ super(message, "WRITE_INVALID_REQUEST", void 0, null, details);
1296
+ }
1297
+ };
1298
+ var WriteTransportError = class extends PersonalServerWriteError {
1299
+ constructor(message, attempts, cause) {
1300
+ super(message, "WRITE_TRANSPORT_ERROR", void 0, null, { attempts });
1301
+ this.attempts = attempts;
1302
+ this.cause = cause;
1303
+ }
1304
+ attempts;
1305
+ };
1306
+ var WriteSessionError = class extends PersonalServerWriteError {
1307
+ constructor(message, status, errorCode = null, details) {
1308
+ super(message, "WRITE_SESSION_REJECTED", status, errorCode, details);
1309
+ }
1310
+ };
1311
+ var WriteSessionExpiredError = class extends PersonalServerWriteError {
1312
+ constructor(message, details) {
1313
+ super(message, "WRITE_SESSION_EXPIRED", void 0, null, details);
1314
+ }
1315
+ };
1316
+ var WriteUnauthorizedError = class extends PersonalServerWriteError {
1317
+ constructor(message, errorCode = null, details) {
1318
+ super(message, "WRITE_UNAUTHORIZED", 401, errorCode, details);
1319
+ }
1320
+ };
1321
+ var WriteForbiddenError = class extends PersonalServerWriteError {
1322
+ constructor(message, errorCode = null, details) {
1323
+ super(message, "WRITE_FORBIDDEN", 403, errorCode, details);
1324
+ }
1325
+ };
1326
+ var WriteConflictError = class extends PersonalServerWriteError {
1327
+ constructor(message, errorCode = null, details) {
1328
+ super(message, "WRITE_CONFLICT", 409, errorCode, details);
1329
+ }
1330
+ };
1331
+ var WriteLineageError = class extends PersonalServerWriteError {
1332
+ constructor(message, status = 422, errorCode = null, details) {
1333
+ super(message, "WRITE_LINEAGE_REJECTED", status, errorCode, details);
1334
+ }
1335
+ };
1336
+ var WriteRejectedError = class extends PersonalServerWriteError {
1337
+ constructor(message, status, errorCode = null, details) {
1338
+ super(message, "WRITE_REJECTED", status, errorCode, details);
1339
+ }
1340
+ };
1341
+ var LineageReadError = class extends VanaError {
1342
+ constructor(message, status, errorCode = null, details) {
1343
+ super(message, "LINEAGE_READ_ERROR");
1344
+ this.status = status;
1345
+ this.errorCode = errorCode;
1346
+ this.details = details;
1347
+ }
1348
+ status;
1349
+ errorCode;
1350
+ details;
1351
+ };
1282
1352
 
1283
1353
  // src/contracts/contractController.ts
1284
1354
  import {
@@ -32172,13 +32242,13 @@ function createViemPersonalServerRegistrationSigner(source, options = {}) {
32172
32242
  if (isPersonalServerRegistrationSigner(source)) {
32173
32243
  return source;
32174
32244
  }
32175
- const accountAddress = getAccountAddress(options.account) ?? getAccountAddress(source.account);
32176
- if (accountAddress) {
32245
+ const accountAddress2 = getAccountAddress(options.account) ?? getAccountAddress(source.account);
32246
+ if (accountAddress2) {
32177
32247
  return {
32178
- address: accountAddress,
32248
+ address: accountAddress2,
32179
32249
  signTypedData: (typedData) => source.signTypedData({
32180
32250
  ...typedData,
32181
- account: options.account ?? source.account ?? accountAddress
32251
+ account: options.account ?? source.account ?? accountAddress2
32182
32252
  })
32183
32253
  };
32184
32254
  }
@@ -32263,12 +32333,12 @@ function createViemPersonalServerLiteOwnerBindingSigner(source, options = {}) {
32263
32333
  if (isPersonalServerLiteOwnerBindingSigner(source)) {
32264
32334
  return source;
32265
32335
  }
32266
- const accountAddress = getAccountAddress2(options.account) ?? getAccountAddress2(source.account);
32267
- if (accountAddress) {
32336
+ const accountAddress2 = getAccountAddress2(options.account) ?? getAccountAddress2(source.account);
32337
+ if (accountAddress2) {
32268
32338
  return {
32269
- address: accountAddress,
32339
+ address: accountAddress2,
32270
32340
  signMessage: ({ message }) => source.signMessage({
32271
- account: options.account ?? source.account ?? accountAddress,
32341
+ account: options.account ?? source.account ?? accountAddress2,
32272
32342
  message
32273
32343
  })
32274
32344
  };
@@ -32947,7 +33017,1022 @@ function scopeCoveredByGrant(requestedScope, grantedScopes) {
32947
33017
  );
32948
33018
  }
32949
33019
 
33020
+ // src/protocol/scope-actions.ts
33021
+ var SCOPE_ACTIONS = ["read", "write"];
33022
+ var InvalidScopeEntryError = class extends Error {
33023
+ /** The offending entry, verbatim (unknown because it may not be a string). */
33024
+ entry;
33025
+ constructor(entry, reason) {
33026
+ super(`Invalid scope entry ${describeValue(entry)}: ${reason}`);
33027
+ this.name = "InvalidScopeEntryError";
33028
+ this.entry = entry;
33029
+ }
33030
+ };
33031
+ var OPERATION_SEPARATOR = ":";
33032
+ function describeValue(value) {
33033
+ if (typeof value === "string") return JSON.stringify(value);
33034
+ if (value === null) return "null";
33035
+ return `[${typeof value}]`;
33036
+ }
33037
+ var OPERATION_BY_PREFIX = {
33038
+ write: "write"
33039
+ };
33040
+ function assertScopePart(entry, scope) {
33041
+ if (scope.length === 0) {
33042
+ throw new InvalidScopeEntryError(entry, "scope part is empty");
33043
+ }
33044
+ if (scope.includes(OPERATION_SEPARATOR)) {
33045
+ throw new InvalidScopeEntryError(
33046
+ entry,
33047
+ `scope part must not contain "${OPERATION_SEPARATOR}"`
33048
+ );
33049
+ }
33050
+ }
33051
+ function parseScopeEntry(entry) {
33052
+ const raw = entry;
33053
+ if (typeof raw !== "string") {
33054
+ throw new InvalidScopeEntryError(raw, "entry must be a string");
33055
+ }
33056
+ const separatorIndex = entry.indexOf(OPERATION_SEPARATOR);
33057
+ if (separatorIndex === -1) {
33058
+ assertScopePart(entry, entry);
33059
+ return { scope: entry, action: "read" };
33060
+ }
33061
+ const prefix = entry.slice(0, separatorIndex);
33062
+ const scope = entry.slice(separatorIndex + 1);
33063
+ const action = Object.hasOwn(OPERATION_BY_PREFIX, prefix) ? OPERATION_BY_PREFIX[prefix] : void 0;
33064
+ if (action === void 0) {
33065
+ throw new InvalidScopeEntryError(
33066
+ entry,
33067
+ `unknown operation "${prefix}" (known: ${Object.keys(OPERATION_BY_PREFIX).join(", ")}; read has no prefix)`
33068
+ );
33069
+ }
33070
+ assertScopePart(entry, scope);
33071
+ return { scope, action };
33072
+ }
33073
+ function formatScopeEntry(parsed) {
33074
+ const { scope, action } = parsed;
33075
+ assertScopePart(scope, scope);
33076
+ if (action === "read") return scope;
33077
+ const prefix = Object.entries(OPERATION_BY_PREFIX).find(
33078
+ ([, candidate]) => candidate === action
33079
+ )?.[0];
33080
+ if (prefix === void 0) {
33081
+ throw new InvalidScopeEntryError(
33082
+ scope,
33083
+ `unknown action ${describeValue(action)} (known: ${SCOPE_ACTIONS.join(", ")})`
33084
+ );
33085
+ }
33086
+ return `${prefix}${OPERATION_SEPARATOR}${scope}`;
33087
+ }
33088
+ function compareScopes(a, b) {
33089
+ if (a < b) return -1;
33090
+ if (a > b) return 1;
33091
+ return 0;
33092
+ }
33093
+ function sortActions(actions) {
33094
+ const present = new Set(actions);
33095
+ return SCOPE_ACTIONS.filter((action) => present.has(action));
33096
+ }
33097
+ function grantPermissions(scopes) {
33098
+ const byScope = /* @__PURE__ */ new Map();
33099
+ for (const entry of scopes) {
33100
+ const { scope, action } = parseScopeEntry(entry);
33101
+ let actions = byScope.get(scope);
33102
+ if (actions === void 0) {
33103
+ actions = /* @__PURE__ */ new Set();
33104
+ byScope.set(scope, actions);
33105
+ }
33106
+ actions.add(action);
33107
+ }
33108
+ return [...byScope.keys()].sort(compareScopes).map((scope) => ({
33109
+ scope,
33110
+ actions: sortActions(byScope.get(scope) ?? [])
33111
+ }));
33112
+ }
33113
+ function permissionsToScopes(permissions) {
33114
+ const byScope = /* @__PURE__ */ new Map();
33115
+ for (const { scope, actions } of permissions) {
33116
+ let merged = byScope.get(scope);
33117
+ if (merged === void 0) {
33118
+ merged = /* @__PURE__ */ new Set();
33119
+ byScope.set(scope, merged);
33120
+ }
33121
+ for (const action of actions) {
33122
+ if (!SCOPE_ACTIONS.includes(action)) {
33123
+ throw new InvalidScopeEntryError(
33124
+ scope,
33125
+ `unknown action ${describeValue(action)} (known: ${SCOPE_ACTIONS.join(", ")})`
33126
+ );
33127
+ }
33128
+ merged.add(action);
33129
+ }
33130
+ }
33131
+ const entries = [];
33132
+ for (const scope of [...byScope.keys()].sort(compareScopes)) {
33133
+ for (const action of sortActions(byScope.get(scope) ?? [])) {
33134
+ entries.push(formatScopeEntry({ scope, action }));
33135
+ }
33136
+ }
33137
+ return entries;
33138
+ }
33139
+ function hasAction(scopes, scope, action) {
33140
+ if (scope.includes(OPERATION_SEPARATOR)) return false;
33141
+ for (const entry of scopes) {
33142
+ let parsed;
33143
+ try {
33144
+ parsed = parseScopeEntry(entry);
33145
+ } catch (error) {
33146
+ if (error instanceof InvalidScopeEntryError) continue;
33147
+ throw error;
33148
+ }
33149
+ if (parsed.action === action && scopeMatchesPattern(scope, parsed.scope)) {
33150
+ return true;
33151
+ }
33152
+ }
33153
+ return false;
33154
+ }
33155
+ function tryGrantPermissions(scopes) {
33156
+ try {
33157
+ return grantPermissions(scopes);
33158
+ } catch (error) {
33159
+ if (error instanceof InvalidScopeEntryError) return void 0;
33160
+ throw error;
33161
+ }
33162
+ }
33163
+
33164
+ // src/protocol/personal-server-write.ts
33165
+ import { sha256 as sha2565 } from "@noble/hashes/sha2";
33166
+ import { bytesToHex as bytesToHex2, isAddress as isAddress5 } from "viem";
33167
+ import { z as z4 } from "zod";
33168
+
33169
+ // src/protocol/lineage.ts
33170
+ import {
33171
+ encodeAbiParameters,
33172
+ isAddress as isAddress4,
33173
+ keccak256
33174
+ } from "viem";
33175
+ import { z as z3 } from "zod";
33176
+
33177
+ // src/protocol/personal-server-error-body.ts
33178
+ function isRecord2(value) {
33179
+ return value !== null && typeof value === "object" && !Array.isArray(value);
33180
+ }
33181
+ async function readPersonalServerErrorBody(response) {
33182
+ let body;
33183
+ try {
33184
+ body = await response.json();
33185
+ } catch {
33186
+ return { errorCode: null, message: null };
33187
+ }
33188
+ if (!isRecord2(body)) return { errorCode: null, message: null };
33189
+ const nested = isRecord2(body.error) ? body.error : null;
33190
+ const gatewayShape = typeof body.error === "string" && typeof body.code === "string";
33191
+ const code = nested?.errorCode ?? nested?.code ?? body.errorCode ?? (gatewayShape ? body.code : void 0) ?? (typeof body.error === "string" ? body.error : void 0) ?? body.code;
33192
+ const message = nested?.message ?? body.message ?? (gatewayShape ? body.error : void 0);
33193
+ const gatewayDetails = {};
33194
+ for (const key of ["unknown", "scope", "sourceScope"]) {
33195
+ if (gatewayShape && body[key] !== void 0)
33196
+ gatewayDetails[key] = body[key];
33197
+ }
33198
+ const details = nested?.details ?? body.details ?? (Object.keys(gatewayDetails).length > 0 ? gatewayDetails : void 0);
33199
+ return {
33200
+ errorCode: typeof code === "string" ? code : null,
33201
+ message: typeof message === "string" ? message : null,
33202
+ ...isRecord2(details) ? { details } : {}
33203
+ };
33204
+ }
33205
+
33206
+ // src/protocol/write-signer.ts
33207
+ function isRecord3(value) {
33208
+ return value !== null && typeof value === "object";
33209
+ }
33210
+ function isViemWriteAccount(source) {
33211
+ return isRecord3(source) && source.type === "local" && typeof source.address === "string" && typeof source.signMessage === "function";
33212
+ }
33213
+ function isViemWriteWalletClient(source) {
33214
+ return isRecord3(source) && typeof source.signMessage === "function" && source.type !== "local" && (source.type === "walletClient" || "transport" in source);
33215
+ }
33216
+ function accountAddress(account) {
33217
+ return typeof account === "string" ? account : account.address;
33218
+ }
33219
+ function resolveWriteSigner(source, options = {}) {
33220
+ if (isViemWriteWalletClient(source)) {
33221
+ const account = options.account ?? source.account;
33222
+ if (account === void 0) {
33223
+ throw new WriteRequestError(
33224
+ "Viem wallet client requires an account option or account property"
33225
+ );
33226
+ }
33227
+ return {
33228
+ address: accountAddress(account),
33229
+ signMessage: (message) => source.signMessage({ account, message })
33230
+ };
33231
+ }
33232
+ if (isViemWriteAccount(source)) {
33233
+ return {
33234
+ address: source.address,
33235
+ signMessage: (message) => source.signMessage({ message })
33236
+ };
33237
+ }
33238
+ if (!isRecord3(source) || typeof source.signMessage !== "function") {
33239
+ throw new WriteRequestError(
33240
+ "signer must be a viem LocalAccount, a viem WalletClient, or a { signMessage } object"
33241
+ );
33242
+ }
33243
+ return source;
33244
+ }
33245
+
33246
+ // src/protocol/lineage.ts
33247
+ var DATA_POINT_ID_PATTERN = /^0x[0-9a-fA-F]{64}$/;
33248
+ function isDataPointId(value) {
33249
+ return typeof value === "string" && DATA_POINT_ID_PATTERN.test(value);
33250
+ }
33251
+ function deriveDataPointId(ownerAddress, scope) {
33252
+ if (!isAddress4(ownerAddress, { strict: false })) {
33253
+ throw new Error(
33254
+ `ownerAddress is not an EVM address: ${String(ownerAddress)}`
33255
+ );
33256
+ }
33257
+ return keccak256(
33258
+ encodeAbiParameters(
33259
+ [
33260
+ { name: "ownerAddress", type: "address" },
33261
+ { name: "scope", type: "string" }
33262
+ ],
33263
+ [ownerAddress, scope]
33264
+ )
33265
+ );
33266
+ }
33267
+ var DataPointIdSchema = z3.string().regex(DATA_POINT_ID_PATTERN).transform((value) => value.toLowerCase());
33268
+ var VERSION_PATTERN = /^[1-9]\d*$/;
33269
+ var NODE_VERSION_PATTERN = /^(0|[1-9]\d*)$/;
33270
+ var VersionSchema = z3.union([z3.string(), z3.number()]).transform(String).refine((value) => NODE_VERSION_PATTERN.test(value), {
33271
+ message: "version must be a decimal integer"
33272
+ });
33273
+ var ViewVersionSchema = VersionSchema.refine(
33274
+ (value) => VERSION_PATTERN.test(value),
33275
+ { message: "version must be a positive decimal integer" }
33276
+ );
33277
+ function scopeNamespace(scope) {
33278
+ const dot = scope.indexOf(".");
33279
+ return dot === -1 ? scope : scope.slice(0, dot);
33280
+ }
33281
+ function derivedScopeViolatesNaming(derivedScope, sourceScope) {
33282
+ return scopeNamespace(derivedScope) === scopeNamespace(sourceScope);
33283
+ }
33284
+ function assertDerivedScopeNaming(derivedScope, sourceScopes) {
33285
+ for (const sourceScope of sourceScopes) {
33286
+ if (derivedScopeViolatesNaming(derivedScope, sourceScope)) {
33287
+ throw new WriteRequestError(
33288
+ `Derived scope ${derivedScope} must not share its first segment with source scope ${sourceScope}; put derivatives in the app's own namespace`,
33289
+ { scope: derivedScope, sourceScope }
33290
+ );
33291
+ }
33292
+ }
33293
+ }
33294
+ var LineageNodeSchema = z3.object({
33295
+ dataPointId: DataPointIdSchema,
33296
+ scope: z3.string(),
33297
+ /**
33298
+ * The node's current version, decimal string; `"0"` for a source that no
33299
+ * longer resolves to a registered data point.
33300
+ */
33301
+ version: VersionSchema,
33302
+ /** The node's tombstone time, or `null` when live. */
33303
+ deletedAt: z3.string().nullable()
33304
+ });
33305
+ var RedactedLineageNodeSchema = z3.object({
33306
+ dataPointId: DataPointIdSchema,
33307
+ redacted: z3.literal(true)
33308
+ });
33309
+ var LineageEntrySchema = z3.union([
33310
+ RedactedLineageNodeSchema,
33311
+ LineageNodeSchema
33312
+ ]);
33313
+ var LineageGraphSchema = z3.object({
33314
+ dataPointId: DataPointIdSchema,
33315
+ /** The data point owner; every node in the view belongs to it. */
33316
+ ownerAddress: z3.string().optional(),
33317
+ scope: z3.string(),
33318
+ /**
33319
+ * The derived record's version whose lineage is shown: the requested one,
33320
+ * else the current one, else (current is a tombstone) the last version
33321
+ * that carried lineage.
33322
+ */
33323
+ version: ViewVersionSchema,
33324
+ deletedAt: z3.string().nullable(),
33325
+ sources: z3.array(LineageEntrySchema),
33326
+ derivatives: z3.array(LineageEntrySchema),
33327
+ /** `true` when `derivatives` was cut at the server's cap (1000). */
33328
+ derivativesTruncated: z3.boolean().optional()
33329
+ });
33330
+ function isRedactedLineageNode(entry) {
33331
+ return "redacted" in entry && entry.redacted === true;
33332
+ }
33333
+ function personalServerLineagePath(scope, version) {
33334
+ return `/v1/data/${encodeURIComponent(scope)}/lineage${version === void 0 ? "" : `/${String(version)}`}`;
33335
+ }
33336
+ function gatewayLineagePath(dataPointId, version) {
33337
+ return `/v1/data/${dataPointId.toLowerCase()}/lineage${version === void 0 ? "" : `/${String(version)}`}`;
33338
+ }
33339
+ function normalizeBaseUrl(url) {
33340
+ return url.replace(/\/+$/, "");
33341
+ }
33342
+ function resolveFetch(fetchFn) {
33343
+ const resolved = fetchFn ?? globalThis.fetch;
33344
+ if (resolved === void 0) {
33345
+ throw new LineageReadError("No fetch implementation available");
33346
+ }
33347
+ return resolved;
33348
+ }
33349
+ function normalizeVersion(version) {
33350
+ if (version === void 0) return void 0;
33351
+ const text = String(version);
33352
+ if (!VERSION_PATTERN.test(text)) {
33353
+ throw new LineageReadError(
33354
+ "version must be a positive decimal integer",
33355
+ void 0,
33356
+ "INVALID_VERSION",
33357
+ { version }
33358
+ );
33359
+ }
33360
+ return text;
33361
+ }
33362
+ async function lineageReadFailure(source, response) {
33363
+ const { errorCode, message, details } = await readPersonalServerErrorBody(response);
33364
+ return new LineageReadError(
33365
+ message ?? `${source} lineage read failed: ${response.status} ${response.statusText}`,
33366
+ response.status,
33367
+ errorCode,
33368
+ details
33369
+ );
33370
+ }
33371
+ async function parseLineageGraph(source, response) {
33372
+ let body;
33373
+ try {
33374
+ body = await response.json();
33375
+ } catch (err) {
33376
+ throw new LineageReadError(
33377
+ `${source} lineage response is not JSON`,
33378
+ response.status,
33379
+ null,
33380
+ { cause: err instanceof Error ? err.message : String(err) }
33381
+ );
33382
+ }
33383
+ const envelope = isRecord2(body) && isRecord2(body.data) ? body : void 0;
33384
+ const parsed = LineageGraphSchema.safeParse(envelope?.data ?? body);
33385
+ if (!parsed.success) {
33386
+ throw new LineageReadError(
33387
+ `${source} lineage response is not a lineage view`,
33388
+ response.status,
33389
+ null,
33390
+ { issues: parsed.error.issues }
33391
+ );
33392
+ }
33393
+ const proof = isRecord2(envelope?.proof) ? envelope.proof : void 0;
33394
+ return proof === void 0 ? parsed.data : { ...parsed.data, proof };
33395
+ }
33396
+ async function sendLineageRead(source, fetchFn, url, headers) {
33397
+ let response;
33398
+ try {
33399
+ response = await fetchFn(url, { method: "GET", headers });
33400
+ } catch (err) {
33401
+ throw new LineageReadError(
33402
+ `${source} lineage read failed: ${err instanceof Error ? err.message : String(err)}`,
33403
+ void 0,
33404
+ null,
33405
+ { cause: err instanceof Error ? err.message : String(err) }
33406
+ );
33407
+ }
33408
+ if (!response.ok) {
33409
+ throw await lineageReadFailure(source, response);
33410
+ }
33411
+ return parseLineageGraph(source, response);
33412
+ }
33413
+ async function getPersonalServerLineage(params) {
33414
+ const fetchFn = resolveFetch(params.fetch);
33415
+ const baseUrl = normalizeBaseUrl(params.personalServerUrl);
33416
+ const audience = params.audience ?? baseUrl;
33417
+ const signer = resolveWriteSigner(params.signer, { account: params.account });
33418
+ const path = personalServerLineagePath(
33419
+ params.scope,
33420
+ normalizeVersion(params.version)
33421
+ );
33422
+ const headers = new Headers(params.headers);
33423
+ headers.set(
33424
+ "Authorization",
33425
+ await buildWeb3SignedHeader({
33426
+ signMessage: signer.signMessage,
33427
+ aud: audience,
33428
+ method: "GET",
33429
+ uri: path,
33430
+ grantId: params.grantId
33431
+ })
33432
+ );
33433
+ return sendLineageRead(
33434
+ "Personal Server",
33435
+ fetchFn,
33436
+ `${baseUrl}${path}`,
33437
+ headers
33438
+ );
33439
+ }
33440
+ async function getGatewayLineage(params) {
33441
+ if (!isDataPointId(params.dataPointId)) {
33442
+ throw new LineageReadError(
33443
+ "dataPointId must be a 32-byte hex string (see deriveDataPointId)",
33444
+ void 0,
33445
+ "INVALID_DATA_POINT_ID",
33446
+ { dataPointId: params.dataPointId }
33447
+ );
33448
+ }
33449
+ const fetchFn = resolveFetch(params.fetch);
33450
+ const baseUrl = normalizeBaseUrl(params.gatewayUrl);
33451
+ const signer = resolveWriteSigner(params.signer, { account: params.account });
33452
+ const uri = gatewayLineagePath(
33453
+ params.dataPointId,
33454
+ normalizeVersion(params.version)
33455
+ );
33456
+ const headers = new Headers(params.headers);
33457
+ headers.set(
33458
+ "Authorization",
33459
+ await buildWeb3SignedHeader({
33460
+ signMessage: signer.signMessage,
33461
+ aud: baseUrl,
33462
+ method: "GET",
33463
+ uri,
33464
+ grantId: params.grantId?.toLowerCase()
33465
+ })
33466
+ );
33467
+ return sendLineageRead("Gateway", fetchFn, `${baseUrl}${uri}`, headers);
33468
+ }
33469
+ function getLineage(params) {
33470
+ return "personalServerUrl" in params ? getPersonalServerLineage(params) : getGatewayLineage(params);
33471
+ }
33472
+
33473
+ // src/protocol/personal-server-write.ts
33474
+ var WRITE_SESSION_PATH = "/v1/write/session";
33475
+ var WRITE_SIGNATURE_HEADER = "X-Vana-Write-Signature";
33476
+ var WRITE_METADATA_HEADER = "X-Vana-Metadata";
33477
+ var LINEAGE_FIELD = "lineage";
33478
+ var MAX_LINEAGE_SOURCES = 256;
33479
+ var WRITE_FILENAME_HEADER = "X-Filename";
33480
+ var WRITE_CONTENT_DISPOSITION_HEADER = "Content-Disposition";
33481
+ var WRITER_ATTRIBUTION_KEY = "$writtenBy";
33482
+ var LINEAGE_KEY = "$lineage";
33483
+ var RESERVED_WRITE_KEYS = [
33484
+ WRITER_ATTRIBUTION_KEY,
33485
+ LINEAGE_KEY
33486
+ ];
33487
+ var WriteDataResultSchema = IngestResponseSchema.extend({
33488
+ // Present when the write carried lineage: the validated, lowercased ids.
33489
+ lineage: z4.object({ sources: z4.array(z4.string()) }).optional()
33490
+ });
33491
+ var WriteSessionResponseSchema = z4.object({
33492
+ access_token: z4.string().min(1),
33493
+ token_type: z4.string(),
33494
+ expires_in: z4.number().nonnegative(),
33495
+ scope: z4.string()
33496
+ });
33497
+ function normalizeBaseUrl2(url) {
33498
+ return url.replace(/\/+$/, "");
33499
+ }
33500
+ function resolveFetch2(fetchFn) {
33501
+ const resolved = fetchFn ?? globalThis.fetch;
33502
+ if (resolved === void 0) {
33503
+ throw new WriteRequestError("No fetch implementation available");
33504
+ }
33505
+ return resolved;
33506
+ }
33507
+ function dataPath(scope) {
33508
+ return `/v1/data/${encodeURIComponent(scope)}`;
33509
+ }
33510
+ function errorMessage(err) {
33511
+ return err instanceof Error ? err.message : String(err);
33512
+ }
33513
+ function finiteOr(value, fallback) {
33514
+ return typeof value === "number" && Number.isFinite(value) ? value : fallback;
33515
+ }
33516
+ function sleep2(ms) {
33517
+ return new Promise((resolve) => setTimeout(resolve, ms));
33518
+ }
33519
+ var issuedProofIats = /* @__PURE__ */ new Map();
33520
+ var issuedProofBuckets = /* @__PURE__ */ new Map();
33521
+ var issuedProofIatsPrunedAtSec = 0;
33522
+ var WEB3_SIGNED_PROOF_LIFETIME_SECONDS = 300;
33523
+ var WEB3_SIGNED_CLOCK_SKEW_SECONDS = 60;
33524
+ var PROOF_IAT_RETENTION_SECONDS = WEB3_SIGNED_PROOF_LIFETIME_SECONDS + WEB3_SIGNED_CLOCK_SKEW_SECONDS;
33525
+ var PROOF_IAT_MAX_AHEAD_SECONDS = 30;
33526
+ function pruneIssuedProofIats(nowSec) {
33527
+ if (issuedProofIatsPrunedAtSec === nowSec) return;
33528
+ issuedProofIatsPrunedAtSec = nowSec;
33529
+ const cutoff = nowSec - PROOF_IAT_RETENTION_SECONDS;
33530
+ for (const [sec, keys] of issuedProofBuckets) {
33531
+ if (sec >= cutoff) continue;
33532
+ for (const key of keys) issuedProofIats.delete(key);
33533
+ issuedProofBuckets.delete(sec);
33534
+ }
33535
+ }
33536
+ function setIssuedProofIat(key, iat, previous) {
33537
+ if (previous !== void 0) {
33538
+ const bucket2 = issuedProofBuckets.get(previous);
33539
+ bucket2?.delete(key);
33540
+ if (bucket2?.size === 0) issuedProofBuckets.delete(previous);
33541
+ }
33542
+ issuedProofIats.set(key, iat);
33543
+ let bucket = issuedProofBuckets.get(iat);
33544
+ if (bucket === void 0) {
33545
+ bucket = /* @__PURE__ */ new Set();
33546
+ issuedProofBuckets.set(iat, bucket);
33547
+ }
33548
+ bucket.add(key);
33549
+ }
33550
+ function nextProofIat(proofKey) {
33551
+ const nowSec = Math.floor(Date.now() / 1e3);
33552
+ pruneIssuedProofIats(nowSec);
33553
+ const last = issuedProofIats.get(proofKey);
33554
+ const iat = last === void 0 ? nowSec : Math.max(nowSec, last + 1);
33555
+ setIssuedProofIat(proofKey, iat, last);
33556
+ const waitSec = iat - nowSec - PROOF_IAT_MAX_AHEAD_SECONDS;
33557
+ if (waitSec <= 0) return Promise.resolve(iat);
33558
+ return sleep2(waitSec * 1e3).then(() => iat);
33559
+ }
33560
+ function proofKeyFor(parts) {
33561
+ return bytesToHex2(
33562
+ sha2565(
33563
+ new TextEncoder().encode(
33564
+ JSON.stringify([
33565
+ parts.aud,
33566
+ parts.method,
33567
+ parts.uri,
33568
+ parts.grantId,
33569
+ parts.signedBytes ? bytesToHex2(sha2565(parts.signedBytes)) : ""
33570
+ ])
33571
+ )
33572
+ )
33573
+ );
33574
+ }
33575
+ async function sendWithFreshProof(label, fetchFn, options, proofKey, build) {
33576
+ const attempts = Math.max(1, Math.floor(finiteOr(options?.attempts, 3)));
33577
+ let delayMs = Math.max(0, finiteOr(options?.initialDelayMs, 1e3));
33578
+ let lastError;
33579
+ for (let attempt = 0; attempt < attempts; attempt++) {
33580
+ const { url, init } = await build(await nextProofIat(proofKey));
33581
+ try {
33582
+ return await fetchFn(url, init);
33583
+ } catch (err) {
33584
+ lastError = err;
33585
+ }
33586
+ if (attempt < attempts - 1) {
33587
+ await sleep2(delayMs);
33588
+ delayMs *= 2;
33589
+ }
33590
+ }
33591
+ throw new WriteTransportError(
33592
+ `${label} failed after ${attempts} attempt(s): ${errorMessage(lastError)}`,
33593
+ attempts,
33594
+ lastError
33595
+ );
33596
+ }
33597
+ async function openWriteSession(params) {
33598
+ const fetchFn = resolveFetch2(params.fetch);
33599
+ const personalServerUrl = normalizeBaseUrl2(params.personalServerUrl);
33600
+ const audience = params.audience ?? personalServerUrl;
33601
+ const signer = resolveWriteSigner(params.signer, { account: params.account });
33602
+ const response = await sendWithFreshProof(
33603
+ "Write session handshake",
33604
+ fetchFn,
33605
+ params.retry,
33606
+ proofKeyFor({
33607
+ aud: audience,
33608
+ method: "POST",
33609
+ uri: WRITE_SESSION_PATH,
33610
+ grantId: params.grantId
33611
+ }),
33612
+ async (iat) => {
33613
+ const headers = new Headers(params.headers);
33614
+ headers.set(
33615
+ "Authorization",
33616
+ await buildWeb3SignedHeader({
33617
+ signMessage: signer.signMessage,
33618
+ aud: audience,
33619
+ method: "POST",
33620
+ uri: WRITE_SESSION_PATH,
33621
+ grantId: params.grantId,
33622
+ iat
33623
+ })
33624
+ );
33625
+ return {
33626
+ url: `${personalServerUrl}${WRITE_SESSION_PATH}`,
33627
+ init: { method: "POST", headers }
33628
+ };
33629
+ }
33630
+ );
33631
+ const mintedAt = Date.now();
33632
+ if (!response.ok) {
33633
+ const { errorCode, message, details } = await readPersonalServerErrorBody(response);
33634
+ throw new WriteSessionError(
33635
+ message ?? `Write session handshake failed: ${response.status} ${response.statusText}`,
33636
+ response.status,
33637
+ errorCode,
33638
+ details
33639
+ );
33640
+ }
33641
+ let body;
33642
+ try {
33643
+ body = await response.json();
33644
+ } catch (err) {
33645
+ throw new WriteSessionError(
33646
+ "Write session response is not JSON",
33647
+ response.status,
33648
+ null,
33649
+ { cause: errorMessage(err) }
33650
+ );
33651
+ }
33652
+ const parsed = WriteSessionResponseSchema.safeParse(body);
33653
+ if (!parsed.success) {
33654
+ throw new WriteSessionError(
33655
+ "Write session response is not a session",
33656
+ response.status,
33657
+ null,
33658
+ { issues: parsed.error.issues }
33659
+ );
33660
+ }
33661
+ if (parsed.data.token_type.toLowerCase() !== "bearer") {
33662
+ throw new WriteSessionError(
33663
+ `Write session token type is not Bearer: ${parsed.data.token_type}`,
33664
+ response.status
33665
+ );
33666
+ }
33667
+ return {
33668
+ personalServerUrl,
33669
+ audience,
33670
+ grantId: params.grantId,
33671
+ accessToken: parsed.data.access_token,
33672
+ expiresAt: mintedAt + parsed.data.expires_in * 1e3,
33673
+ writeScopes: parsed.data.scope.split(" ").filter((s) => s.length > 0),
33674
+ signer
33675
+ };
33676
+ }
33677
+ function isWriteSession(value) {
33678
+ if (!isRecord2(value)) return false;
33679
+ const signer = value.signer;
33680
+ return typeof value.personalServerUrl === "string" && typeof value.audience === "string" && typeof value.grantId === "string" && typeof value.accessToken === "string" && value.accessToken.length > 0 && typeof value.expiresAt === "number" && Number.isFinite(value.expiresAt) && Array.isArray(value.writeScopes) && value.writeScopes.every((scope) => typeof scope === "string") && isRecord2(signer) && typeof signer.signMessage === "function";
33681
+ }
33682
+ function sessionCoversScope(session, scope) {
33683
+ if (!isRecord2(session) || !Array.isArray(session.writeScopes) || !session.writeScopes.every((pattern) => typeof pattern === "string")) {
33684
+ throw new WriteRequestError("session must come from openWriteSession");
33685
+ }
33686
+ return session.writeScopes.some(
33687
+ (pattern) => scopeMatchesPattern(scope, pattern)
33688
+ );
33689
+ }
33690
+ function normalizeBinaryMimeType(contentType) {
33691
+ if (!contentType) return "application/octet-stream";
33692
+ return contentType.split(";")[0].trim() || "application/octet-stream";
33693
+ }
33694
+ function parseWriteMetadataHeader(value) {
33695
+ if (value === null) return void 0;
33696
+ const trimmed = value.trim();
33697
+ if (trimmed === "") return void 0;
33698
+ try {
33699
+ return JSON.parse(trimmed);
33700
+ } catch {
33701
+ return value;
33702
+ }
33703
+ }
33704
+ function encodeWriteMetadataHeader(metadata) {
33705
+ let json;
33706
+ try {
33707
+ json = JSON.stringify(metadata);
33708
+ } catch (err) {
33709
+ throw new WriteRequestError(
33710
+ `metadata is not JSON-serialisable: ${errorMessage(err)}`
33711
+ );
33712
+ }
33713
+ if (typeof json !== "string") {
33714
+ throw new WriteRequestError("metadata must serialise to JSON");
33715
+ }
33716
+ return json.replace(
33717
+ /[\u007f-\uffff]/g,
33718
+ (c) => `\\u${c.charCodeAt(0).toString(16).padStart(4, "0")}`
33719
+ );
33720
+ }
33721
+ function binaryWriteSignedBytes(input) {
33722
+ const metadata = parseWriteMetadataHeader(input.metadataHeader ?? null);
33723
+ const record = {
33724
+ $binary: true,
33725
+ mimeType: normalizeBinaryMimeType(input.contentType),
33726
+ ...input.filename ? { filename: input.filename } : {},
33727
+ sizeBytes: input.bytes.length,
33728
+ contentHash: bytesToHex2(sha2565(input.bytes)),
33729
+ encoding: "base64",
33730
+ content: toBase64(input.bytes),
33731
+ ...metadata !== void 0 ? { metadata } : {}
33732
+ };
33733
+ return new TextEncoder().encode(JSON.stringify(record));
33734
+ }
33735
+ var PRINTABLE_ASCII = /^[\x20-\x7e]*$/;
33736
+ function setFilenameHeader(headers, filename) {
33737
+ if (PRINTABLE_ASCII.test(filename)) {
33738
+ headers.set(WRITE_FILENAME_HEADER, filename);
33739
+ return;
33740
+ }
33741
+ headers.set(
33742
+ WRITE_CONTENT_DISPOSITION_HEADER,
33743
+ `attachment; filename*=UTF-8''${encodeURIComponent(filename)}`
33744
+ );
33745
+ }
33746
+ function assertNoReservedKeys(value, where) {
33747
+ for (const key of RESERVED_WRITE_KEYS) {
33748
+ if (Object.prototype.hasOwnProperty.call(value, key)) {
33749
+ throw new WriteRequestError(
33750
+ `${where} must not contain the reserved ${key} key; the Personal Server stamps it`,
33751
+ { key }
33752
+ );
33753
+ }
33754
+ }
33755
+ }
33756
+ function isLineagePair(value) {
33757
+ return isRecord2(value) && typeof value.ownerAddress === "string" && typeof value.scope === "string";
33758
+ }
33759
+ function normalizeLineage(lineage, derivedScope) {
33760
+ if (!Array.isArray(lineage)) {
33761
+ throw new WriteRequestError("lineage must be an array of data point ids");
33762
+ }
33763
+ if (lineage.length > MAX_LINEAGE_SOURCES) {
33764
+ throw new WriteRequestError(
33765
+ `lineage lists ${lineage.length} sources; the maximum is ${MAX_LINEAGE_SOURCES}`,
33766
+ { max: MAX_LINEAGE_SOURCES, count: lineage.length }
33767
+ );
33768
+ }
33769
+ const seen = /* @__PURE__ */ new Set();
33770
+ const sources = [];
33771
+ const sourceScopes = [];
33772
+ const ownIds = /* @__PURE__ */ new Set();
33773
+ for (const entry of lineage) {
33774
+ let id;
33775
+ if (isLineagePair(entry)) {
33776
+ if (!isAddress5(entry.ownerAddress, { strict: false })) {
33777
+ throw new WriteRequestError(
33778
+ "lineage source ownerAddress must be an EVM address",
33779
+ { ownerAddress: entry.ownerAddress }
33780
+ );
33781
+ }
33782
+ if (entry.scope.length === 0) {
33783
+ throw new WriteRequestError("lineage source scope is required");
33784
+ }
33785
+ id = deriveDataPointId(entry.ownerAddress, entry.scope);
33786
+ sourceScopes.push(entry.scope);
33787
+ ownIds.add(deriveDataPointId(entry.ownerAddress, derivedScope));
33788
+ } else if (isDataPointId(entry)) {
33789
+ id = entry;
33790
+ } else {
33791
+ throw new WriteRequestError(
33792
+ "lineage entries must be 32-byte hex data point ids or { ownerAddress, scope } pairs",
33793
+ { entry }
33794
+ );
33795
+ }
33796
+ const normalized = id.toLowerCase();
33797
+ if (seen.has(normalized)) {
33798
+ throw new WriteRequestError("lineage must not repeat a data point id", {
33799
+ dataPointId: normalized
33800
+ });
33801
+ }
33802
+ seen.add(normalized);
33803
+ sources.push(normalized);
33804
+ }
33805
+ for (const own of ownIds) {
33806
+ if (seen.has(own)) {
33807
+ throw new WriteRequestError(
33808
+ "lineage must not cite the record's own data point",
33809
+ { dataPointId: own, scope: derivedScope }
33810
+ );
33811
+ }
33812
+ }
33813
+ assertDerivedScopeNaming(derivedScope, sourceScopes);
33814
+ return sources;
33815
+ }
33816
+ function assertNoLineageField(value, where) {
33817
+ if (Object.prototype.hasOwnProperty.call(value, LINEAGE_FIELD)) {
33818
+ throw new WriteRequestError(
33819
+ `${where}.${LINEAGE_FIELD} is reserved; pass sources through the lineage option`
33820
+ );
33821
+ }
33822
+ }
33823
+ function buildMetadataHeader(metadata, sources) {
33824
+ if (metadata !== void 0) {
33825
+ if (!isRecord2(metadata)) {
33826
+ throw new WriteRequestError("metadata must be a plain object");
33827
+ }
33828
+ assertNoReservedKeys(metadata, "metadata");
33829
+ assertNoLineageField(metadata, "metadata");
33830
+ }
33831
+ if (metadata === void 0 && sources === void 0) return void 0;
33832
+ return encodeWriteMetadataHeader({
33833
+ ...metadata ?? {},
33834
+ ...sources !== void 0 ? { [LINEAGE_FIELD]: sources } : {}
33835
+ });
33836
+ }
33837
+ function prepareWrite(params) {
33838
+ if (params.binary !== void 0 && params.data !== void 0) {
33839
+ throw new WriteRequestError("Pass either data or binary, not both");
33840
+ }
33841
+ const rawLineage = params.lineage;
33842
+ const sources = rawLineage === void 0 || rawLineage === null ? void 0 : normalizeLineage(rawLineage, params.scope);
33843
+ if (params.binary !== void 0) {
33844
+ const { bytes, contentType, filename } = params.binary;
33845
+ if (!(bytes instanceof Uint8Array)) {
33846
+ throw new WriteRequestError("binary.bytes must be a Uint8Array");
33847
+ }
33848
+ if (typeof contentType !== "string" || contentType.trim() === "") {
33849
+ throw new WriteRequestError("binary.contentType is required");
33850
+ }
33851
+ if (filename !== void 0) {
33852
+ if (typeof filename !== "string") {
33853
+ throw new WriteRequestError("binary.filename must be a string");
33854
+ }
33855
+ if (filename !== filename.trim()) {
33856
+ throw new WriteRequestError(
33857
+ "binary.filename must not have leading or trailing whitespace"
33858
+ );
33859
+ }
33860
+ }
33861
+ const metadataHeader = buildMetadataHeader(params.metadata, sources);
33862
+ return {
33863
+ body: bytes,
33864
+ signedBytes: binaryWriteSignedBytes({
33865
+ bytes,
33866
+ contentType,
33867
+ filename,
33868
+ metadataHeader
33869
+ }),
33870
+ contentType,
33871
+ filename,
33872
+ metadataHeader
33873
+ };
33874
+ }
33875
+ if (params.data === void 0) {
33876
+ throw new WriteRequestError("Pass data (a JSON object) or binary");
33877
+ }
33878
+ if (!isRecord2(params.data)) {
33879
+ throw new WriteRequestError("data must be a plain JSON object");
33880
+ }
33881
+ if (params.metadata !== void 0) {
33882
+ throw new WriteRequestError(
33883
+ "metadata applies to binary writes; put fields to store inside data"
33884
+ );
33885
+ }
33886
+ assertNoReservedKeys(params.data, "data");
33887
+ assertNoLineageField(params.data, "data");
33888
+ const record = sources === void 0 ? params.data : { ...params.data, [LINEAGE_FIELD]: sources };
33889
+ let text;
33890
+ try {
33891
+ text = JSON.stringify(record);
33892
+ } catch (err) {
33893
+ throw new WriteRequestError(
33894
+ `data is not JSON-serialisable: ${errorMessage(err)}`
33895
+ );
33896
+ }
33897
+ if (typeof text !== "string" || !text.startsWith("{")) {
33898
+ throw new WriteRequestError("data must serialise to a JSON object");
33899
+ }
33900
+ const body = new TextEncoder().encode(text);
33901
+ return {
33902
+ body,
33903
+ signedBytes: body,
33904
+ contentType: "application/json"
33905
+ };
33906
+ }
33907
+ async function writeErrorFromResponse(response) {
33908
+ const { errorCode, message, details } = await readPersonalServerErrorBody(response);
33909
+ const text = message ?? `Personal Server write failed: ${response.status} ${response.statusText}`;
33910
+ if (response.status === 422 || errorCode?.startsWith("LINEAGE_")) {
33911
+ return new WriteLineageError(text, response.status, errorCode, details);
33912
+ }
33913
+ switch (response.status) {
33914
+ case 401:
33915
+ return new WriteUnauthorizedError(text, errorCode, details);
33916
+ case 403:
33917
+ return new WriteForbiddenError(text, errorCode, details);
33918
+ case 409:
33919
+ return new WriteConflictError(text, errorCode, details);
33920
+ default:
33921
+ return new WriteRejectedError(text, response.status, errorCode, details);
33922
+ }
33923
+ }
33924
+ async function writeData(params) {
33925
+ const { session } = params;
33926
+ if (!isWriteSession(session)) {
33927
+ throw new WriteRequestError("session must come from openWriteSession");
33928
+ }
33929
+ const fetchFn = resolveFetch2(params.fetch);
33930
+ if (typeof params.scope !== "string" || params.scope.length === 0) {
33931
+ throw new WriteRequestError("scope is required");
33932
+ }
33933
+ const prepared = prepareWrite(params);
33934
+ if (Date.now() >= session.expiresAt) {
33935
+ throw new WriteSessionExpiredError(
33936
+ "Write session has expired; open a new session",
33937
+ { grantId: session.grantId, expiresAt: session.expiresAt }
33938
+ );
33939
+ }
33940
+ const path = dataPath(params.scope);
33941
+ const response = await sendWithFreshProof(
33942
+ `Write to ${params.scope}`,
33943
+ fetchFn,
33944
+ params.retry,
33945
+ proofKeyFor({
33946
+ aud: session.audience,
33947
+ method: "POST",
33948
+ uri: path,
33949
+ grantId: session.grantId,
33950
+ signedBytes: prepared.signedBytes
33951
+ }),
33952
+ async (iat) => {
33953
+ const headers = new Headers(params.headers);
33954
+ headers.set("Content-Type", prepared.contentType);
33955
+ headers.set("Authorization", `Bearer ${session.accessToken}`);
33956
+ if (prepared.filename) {
33957
+ setFilenameHeader(headers, prepared.filename);
33958
+ }
33959
+ if (prepared.metadataHeader !== void 0) {
33960
+ headers.set(WRITE_METADATA_HEADER, prepared.metadataHeader);
33961
+ }
33962
+ headers.set(
33963
+ WRITE_SIGNATURE_HEADER,
33964
+ await buildWeb3SignedHeader({
33965
+ signMessage: session.signer.signMessage,
33966
+ aud: session.audience,
33967
+ method: "POST",
33968
+ uri: path,
33969
+ body: prepared.signedBytes,
33970
+ grantId: session.grantId,
33971
+ iat
33972
+ })
33973
+ );
33974
+ return {
33975
+ url: `${session.personalServerUrl}${path}`,
33976
+ init: {
33977
+ method: "POST",
33978
+ headers,
33979
+ body: prepared.body
33980
+ }
33981
+ };
33982
+ }
33983
+ );
33984
+ if (!response.ok) {
33985
+ throw await writeErrorFromResponse(response);
33986
+ }
33987
+ let body;
33988
+ try {
33989
+ body = await response.json();
33990
+ } catch (err) {
33991
+ throw new WriteRejectedError(
33992
+ "Personal Server write response is not JSON",
33993
+ response.status,
33994
+ null,
33995
+ { cause: errorMessage(err) }
33996
+ );
33997
+ }
33998
+ const parsed = WriteDataResultSchema.safeParse(body);
33999
+ if (!parsed.success) {
34000
+ throw new WriteRejectedError(
34001
+ "Personal Server write response is not an ingest result",
34002
+ response.status,
34003
+ null,
34004
+ { issues: parsed.error.issues }
34005
+ );
34006
+ }
34007
+ return parsed.data;
34008
+ }
34009
+ async function writePersonalServerData(params) {
34010
+ const session = await openWriteSession({
34011
+ personalServerUrl: params.personalServerUrl,
34012
+ signer: params.signer,
34013
+ grantId: params.grantId,
34014
+ account: params.account,
34015
+ audience: params.audience,
34016
+ fetch: params.fetch,
34017
+ headers: params.headers,
34018
+ retry: params.retry
34019
+ });
34020
+ const writeParams = { ...params, session };
34021
+ const result = await writeData(writeParams);
34022
+ return { ...result, session };
34023
+ }
34024
+
32950
34025
  // src/protocol/gateway.ts
34026
+ function withGrantPermissions(grant) {
34027
+ const stripped = { ...grant };
34028
+ delete stripped.permissions;
34029
+ const scopes = stripped.scopes;
34030
+ if (!Array.isArray(scopes)) {
34031
+ return stripped;
34032
+ }
34033
+ const permissions = tryGrantPermissions(scopes);
34034
+ return permissions === void 0 ? stripped : { ...stripped, permissions };
34035
+ }
32951
34036
  function createGatewayClient(baseUrl) {
32952
34037
  const base = baseUrl.replace(/\/+$/, "");
32953
34038
  async function unwrapEnvelope(res) {
@@ -32977,7 +34062,9 @@ function createGatewayClient(baseUrl) {
32977
34062
  if (!res.ok) {
32978
34063
  throw new Error(`Gateway error: ${res.status} ${res.statusText}`);
32979
34064
  }
32980
- return unwrapEnvelope(res);
34065
+ return withGrantPermissions(
34066
+ await unwrapEnvelope(res)
34067
+ );
32981
34068
  },
32982
34069
  async listGrantsByUser(userAddress) {
32983
34070
  const res = await fetch(`${base}/v1/grants?user=${userAddress}`);
@@ -32985,7 +34072,8 @@ function createGatewayClient(baseUrl) {
32985
34072
  if (!res.ok) {
32986
34073
  throw new Error(`Gateway error: ${res.status} ${res.statusText}`);
32987
34074
  }
32988
- return unwrapEnvelope(res);
34075
+ const grants = await unwrapEnvelope(res);
34076
+ return grants.map(withGrantPermissions);
32989
34077
  },
32990
34078
  async getSchemaForScope(scope) {
32991
34079
  const res = await fetch(`${base}/v1/schemas?scope=${scope}`);
@@ -33386,7 +34474,7 @@ var KNOWN_CODES = /* @__PURE__ */ new Set([
33386
34474
  "server_not_configured",
33387
34475
  "content_too_large"
33388
34476
  ]);
33389
- function isRecord2(value) {
34477
+ function isRecord4(value) {
33390
34478
  return value !== null && typeof value === "object" && !Array.isArray(value);
33391
34479
  }
33392
34480
  function normalizeCode(value) {
@@ -33397,10 +34485,10 @@ function normalizeCode(value) {
33397
34485
  return KNOWN_CODES.has(code) ? code : null;
33398
34486
  }
33399
34487
  function extractPSErrorBody(body) {
33400
- if (!isRecord2(body)) {
34488
+ if (!isRecord4(body)) {
33401
34489
  return null;
33402
34490
  }
33403
- const nested = isRecord2(body.error) ? body.error : null;
34491
+ const nested = isRecord4(body.error) ? body.error : null;
33404
34492
  const code = normalizeCode(
33405
34493
  nested?.errorCode ?? nested?.code ?? body.errorCode ?? body.code
33406
34494
  );
@@ -33451,9 +34539,17 @@ export {
33451
34539
  InMemoryTokenStore,
33452
34540
  IngestResponseSchema,
33453
34541
  InvalidConfigurationError,
34542
+ InvalidScopeEntryError,
33454
34543
  InvalidSignatureError,
33455
34544
  IpfsStorage,
34545
+ LINEAGE_FIELD,
34546
+ LINEAGE_KEY,
34547
+ LineageEntrySchema,
34548
+ LineageGraphSchema,
34549
+ LineageNodeSchema,
34550
+ LineageReadError,
33456
34551
  MASTER_KEY_MESSAGE,
34552
+ MAX_LINEAGE_SOURCES,
33457
34553
  MissingAuthError,
33458
34554
  NATIVE_ASSET_ADDRESS,
33459
34555
  NATIVE_VANA_ASSET,
@@ -33470,12 +34566,16 @@ export {
33470
34566
  PSError,
33471
34567
  PermissionError,
33472
34568
  PersonalServerError,
34569
+ PersonalServerWriteError,
33473
34570
  PinataStorage,
33474
34571
  R2Storage,
33475
34572
  RECORD_DATA_ACCESS_TYPES,
33476
34573
  REGISTRATION_KIND_FOR_OP,
34574
+ RESERVED_WRITE_KEYS,
33477
34575
  ReadOnlyError,
34576
+ RedactedLineageNodeSchema,
33478
34577
  RelayerError,
34578
+ SCOPE_ACTIONS,
33479
34579
  SERVER_REGISTRATION_TYPES,
33480
34580
  ScopeSchema,
33481
34581
  SerializationError,
@@ -33487,7 +34587,24 @@ export {
33487
34587
  UserRejectedRequestError,
33488
34588
  VanaError,
33489
34589
  VanaStorage,
34590
+ WRITER_ATTRIBUTION_KEY,
34591
+ WRITE_CONTENT_DISPOSITION_HEADER,
34592
+ WRITE_FILENAME_HEADER,
34593
+ WRITE_METADATA_HEADER,
34594
+ WRITE_SESSION_PATH,
34595
+ WRITE_SIGNATURE_HEADER,
34596
+ WriteConflictError,
34597
+ WriteForbiddenError,
34598
+ WriteLineageError,
34599
+ WriteRejectedError,
34600
+ WriteRequestError,
34601
+ WriteSessionError,
34602
+ WriteSessionExpiredError,
34603
+ WriteTransportError,
34604
+ WriteUnauthorizedError,
34605
+ assertDerivedScopeNaming,
33490
34606
  assertValidPkceVerifier,
34607
+ binaryWriteSignedBytes,
33491
34608
  buildDepositNativeRequest,
33492
34609
  buildDepositTokenRequest,
33493
34610
  buildMarkDataPointUnavailableRequest,
@@ -33515,16 +34632,21 @@ export {
33515
34632
  dataRegistryContractAddress,
33516
34633
  dataRegistryDomain,
33517
34634
  decryptWithPassword,
34635
+ deriveDataPointId,
33518
34636
  deriveMasterKey,
33519
34637
  deriveScopeKey,
34638
+ derivedScopeViolatesNaming,
33520
34639
  deserializeECIES,
33521
34640
  detectPlatform,
33522
34641
  encodeDepositNativeData,
33523
34642
  encodeDepositTokenData,
33524
34643
  encodeSetDataPointStatusData,
34644
+ encodeWriteMetadataHeader,
33525
34645
  encryptWithPassword,
33526
34646
  escrowContractAddress,
33527
34647
  escrowPaymentDomain,
34648
+ formatScopeEntry,
34649
+ gatewayLineagePath,
33528
34650
  generatePkceVerifier,
33529
34651
  genericPaymentDomain,
33530
34652
  getAbi,
@@ -33534,37 +34656,56 @@ export {
33534
34656
  getContractController,
33535
34657
  getContractInfo,
33536
34658
  getFee,
34659
+ getGatewayLineage,
34660
+ getLineage,
33537
34661
  getOpFee,
34662
+ getPersonalServerLineage,
33538
34663
  getPlatformCapabilities,
33539
34664
  getServiceEndpoints,
34665
+ grantPermissions,
33540
34666
  grantRegistrationDomain,
33541
34667
  grantRevocationDomain,
34668
+ hasAction,
34669
+ isDataPointId,
33542
34670
  isDataPortabilityGatewayConfig,
33543
34671
  isECIESEncrypted,
33544
34672
  isPlatformSupported,
34673
+ isRedactedLineageNode,
33545
34674
  mainnetServices,
33546
34675
  moksha,
33547
34676
  mokshaServices,
33548
34677
  mokshaTestnet2 as mokshaTestnet,
34678
+ normalizeBinaryMimeType,
34679
+ openWriteSession,
33549
34680
  parsePSError,
33550
34681
  parseScope,
34682
+ parseScopeEntry,
33551
34683
  parseWeb3SignedHeader,
34684
+ parseWriteMetadataHeader,
34685
+ permissionsToScopes,
33552
34686
  personalServerDataReadPath,
34687
+ personalServerLineagePath,
33553
34688
  personalServerRegistrationDomain,
33554
34689
  readPersonalServerData,
33555
34690
  recoverServerOwner,
33556
34691
  registerPersonalServerSignature,
34692
+ resolveWriteSigner,
33557
34693
  scopeCoveredByGrant,
33558
34694
  scopeMatchesPattern,
34695
+ scopeNamespace,
33559
34696
  scopeToPathSegments,
33560
34697
  serializeECIES,
33561
34698
  serverRegistrationDomain,
34699
+ sessionCoversScope,
33562
34700
  signPersonalServerLiteOwnerBinding,
33563
34701
  signPersonalServerLiteOwnerBindingWithAccountClient,
33564
34702
  signPersonalServerRegistrationWithAccount,
34703
+ tryGrantPermissions,
33565
34704
  vanaMainnet2 as vanaMainnet,
33566
34705
  verifyGrantRegistration,
33567
34706
  verifyPkceChallenge,
33568
- verifyWeb3Signed
34707
+ verifyWeb3Signed,
34708
+ writeData,
34709
+ writePersonalServerData
33569
34710
  };
33570
34711
  //# sourceMappingURL=index.browser.js.map