@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
@@ -1288,6 +1288,76 @@ var TransactionPendingError = class extends VanaError {
1288
1288
  };
1289
1289
  }
1290
1290
  };
1291
+ var PersonalServerWriteError = class extends VanaError {
1292
+ constructor(message, code, status, errorCode = null, details) {
1293
+ super(message, code);
1294
+ this.status = status;
1295
+ this.errorCode = errorCode;
1296
+ this.details = details;
1297
+ }
1298
+ status;
1299
+ errorCode;
1300
+ details;
1301
+ };
1302
+ var WriteRequestError = class extends PersonalServerWriteError {
1303
+ constructor(message, details) {
1304
+ super(message, "WRITE_INVALID_REQUEST", void 0, null, details);
1305
+ }
1306
+ };
1307
+ var WriteTransportError = class extends PersonalServerWriteError {
1308
+ constructor(message, attempts, cause) {
1309
+ super(message, "WRITE_TRANSPORT_ERROR", void 0, null, { attempts });
1310
+ this.attempts = attempts;
1311
+ this.cause = cause;
1312
+ }
1313
+ attempts;
1314
+ };
1315
+ var WriteSessionError = class extends PersonalServerWriteError {
1316
+ constructor(message, status, errorCode = null, details) {
1317
+ super(message, "WRITE_SESSION_REJECTED", status, errorCode, details);
1318
+ }
1319
+ };
1320
+ var WriteSessionExpiredError = class extends PersonalServerWriteError {
1321
+ constructor(message, details) {
1322
+ super(message, "WRITE_SESSION_EXPIRED", void 0, null, details);
1323
+ }
1324
+ };
1325
+ var WriteUnauthorizedError = class extends PersonalServerWriteError {
1326
+ constructor(message, errorCode = null, details) {
1327
+ super(message, "WRITE_UNAUTHORIZED", 401, errorCode, details);
1328
+ }
1329
+ };
1330
+ var WriteForbiddenError = class extends PersonalServerWriteError {
1331
+ constructor(message, errorCode = null, details) {
1332
+ super(message, "WRITE_FORBIDDEN", 403, errorCode, details);
1333
+ }
1334
+ };
1335
+ var WriteConflictError = class extends PersonalServerWriteError {
1336
+ constructor(message, errorCode = null, details) {
1337
+ super(message, "WRITE_CONFLICT", 409, errorCode, details);
1338
+ }
1339
+ };
1340
+ var WriteLineageError = class extends PersonalServerWriteError {
1341
+ constructor(message, status = 422, errorCode = null, details) {
1342
+ super(message, "WRITE_LINEAGE_REJECTED", status, errorCode, details);
1343
+ }
1344
+ };
1345
+ var WriteRejectedError = class extends PersonalServerWriteError {
1346
+ constructor(message, status, errorCode = null, details) {
1347
+ super(message, "WRITE_REJECTED", status, errorCode, details);
1348
+ }
1349
+ };
1350
+ var LineageReadError = class extends VanaError {
1351
+ constructor(message, status, errorCode = null, details) {
1352
+ super(message, "LINEAGE_READ_ERROR");
1353
+ this.status = status;
1354
+ this.errorCode = errorCode;
1355
+ this.details = details;
1356
+ }
1357
+ status;
1358
+ errorCode;
1359
+ details;
1360
+ };
1291
1361
 
1292
1362
  // src/contracts/contractController.ts
1293
1363
  import {
@@ -32799,13 +32869,13 @@ function createViemPersonalServerRegistrationSigner(source, options = {}) {
32799
32869
  if (isPersonalServerRegistrationSigner(source)) {
32800
32870
  return source;
32801
32871
  }
32802
- const accountAddress = getAccountAddress(options.account) ?? getAccountAddress(source.account);
32803
- if (accountAddress) {
32872
+ const accountAddress2 = getAccountAddress(options.account) ?? getAccountAddress(source.account);
32873
+ if (accountAddress2) {
32804
32874
  return {
32805
- address: accountAddress,
32875
+ address: accountAddress2,
32806
32876
  signTypedData: (typedData) => source.signTypedData({
32807
32877
  ...typedData,
32808
- account: options.account ?? source.account ?? accountAddress
32878
+ account: options.account ?? source.account ?? accountAddress2
32809
32879
  })
32810
32880
  };
32811
32881
  }
@@ -32890,12 +32960,12 @@ function createViemPersonalServerLiteOwnerBindingSigner(source, options = {}) {
32890
32960
  if (isPersonalServerLiteOwnerBindingSigner(source)) {
32891
32961
  return source;
32892
32962
  }
32893
- const accountAddress = getAccountAddress2(options.account) ?? getAccountAddress2(source.account);
32894
- if (accountAddress) {
32963
+ const accountAddress2 = getAccountAddress2(options.account) ?? getAccountAddress2(source.account);
32964
+ if (accountAddress2) {
32895
32965
  return {
32896
- address: accountAddress,
32966
+ address: accountAddress2,
32897
32967
  signMessage: ({ message }) => source.signMessage({
32898
- account: options.account ?? source.account ?? accountAddress,
32968
+ account: options.account ?? source.account ?? accountAddress2,
32899
32969
  message
32900
32970
  })
32901
32971
  };
@@ -33574,7 +33644,1022 @@ function scopeCoveredByGrant(requestedScope, grantedScopes) {
33574
33644
  );
33575
33645
  }
33576
33646
 
33647
+ // src/protocol/scope-actions.ts
33648
+ var SCOPE_ACTIONS = ["read", "write"];
33649
+ var InvalidScopeEntryError = class extends Error {
33650
+ /** The offending entry, verbatim (unknown because it may not be a string). */
33651
+ entry;
33652
+ constructor(entry, reason) {
33653
+ super(`Invalid scope entry ${describeValue(entry)}: ${reason}`);
33654
+ this.name = "InvalidScopeEntryError";
33655
+ this.entry = entry;
33656
+ }
33657
+ };
33658
+ var OPERATION_SEPARATOR = ":";
33659
+ function describeValue(value) {
33660
+ if (typeof value === "string") return JSON.stringify(value);
33661
+ if (value === null) return "null";
33662
+ return `[${typeof value}]`;
33663
+ }
33664
+ var OPERATION_BY_PREFIX = {
33665
+ write: "write"
33666
+ };
33667
+ function assertScopePart(entry, scope) {
33668
+ if (scope.length === 0) {
33669
+ throw new InvalidScopeEntryError(entry, "scope part is empty");
33670
+ }
33671
+ if (scope.includes(OPERATION_SEPARATOR)) {
33672
+ throw new InvalidScopeEntryError(
33673
+ entry,
33674
+ `scope part must not contain "${OPERATION_SEPARATOR}"`
33675
+ );
33676
+ }
33677
+ }
33678
+ function parseScopeEntry(entry) {
33679
+ const raw = entry;
33680
+ if (typeof raw !== "string") {
33681
+ throw new InvalidScopeEntryError(raw, "entry must be a string");
33682
+ }
33683
+ const separatorIndex = entry.indexOf(OPERATION_SEPARATOR);
33684
+ if (separatorIndex === -1) {
33685
+ assertScopePart(entry, entry);
33686
+ return { scope: entry, action: "read" };
33687
+ }
33688
+ const prefix = entry.slice(0, separatorIndex);
33689
+ const scope = entry.slice(separatorIndex + 1);
33690
+ const action = Object.hasOwn(OPERATION_BY_PREFIX, prefix) ? OPERATION_BY_PREFIX[prefix] : void 0;
33691
+ if (action === void 0) {
33692
+ throw new InvalidScopeEntryError(
33693
+ entry,
33694
+ `unknown operation "${prefix}" (known: ${Object.keys(OPERATION_BY_PREFIX).join(", ")}; read has no prefix)`
33695
+ );
33696
+ }
33697
+ assertScopePart(entry, scope);
33698
+ return { scope, action };
33699
+ }
33700
+ function formatScopeEntry(parsed) {
33701
+ const { scope, action } = parsed;
33702
+ assertScopePart(scope, scope);
33703
+ if (action === "read") return scope;
33704
+ const prefix = Object.entries(OPERATION_BY_PREFIX).find(
33705
+ ([, candidate]) => candidate === action
33706
+ )?.[0];
33707
+ if (prefix === void 0) {
33708
+ throw new InvalidScopeEntryError(
33709
+ scope,
33710
+ `unknown action ${describeValue(action)} (known: ${SCOPE_ACTIONS.join(", ")})`
33711
+ );
33712
+ }
33713
+ return `${prefix}${OPERATION_SEPARATOR}${scope}`;
33714
+ }
33715
+ function compareScopes(a, b) {
33716
+ if (a < b) return -1;
33717
+ if (a > b) return 1;
33718
+ return 0;
33719
+ }
33720
+ function sortActions(actions) {
33721
+ const present = new Set(actions);
33722
+ return SCOPE_ACTIONS.filter((action) => present.has(action));
33723
+ }
33724
+ function grantPermissions(scopes) {
33725
+ const byScope = /* @__PURE__ */ new Map();
33726
+ for (const entry of scopes) {
33727
+ const { scope, action } = parseScopeEntry(entry);
33728
+ let actions = byScope.get(scope);
33729
+ if (actions === void 0) {
33730
+ actions = /* @__PURE__ */ new Set();
33731
+ byScope.set(scope, actions);
33732
+ }
33733
+ actions.add(action);
33734
+ }
33735
+ return [...byScope.keys()].sort(compareScopes).map((scope) => ({
33736
+ scope,
33737
+ actions: sortActions(byScope.get(scope) ?? [])
33738
+ }));
33739
+ }
33740
+ function permissionsToScopes(permissions) {
33741
+ const byScope = /* @__PURE__ */ new Map();
33742
+ for (const { scope, actions } of permissions) {
33743
+ let merged = byScope.get(scope);
33744
+ if (merged === void 0) {
33745
+ merged = /* @__PURE__ */ new Set();
33746
+ byScope.set(scope, merged);
33747
+ }
33748
+ for (const action of actions) {
33749
+ if (!SCOPE_ACTIONS.includes(action)) {
33750
+ throw new InvalidScopeEntryError(
33751
+ scope,
33752
+ `unknown action ${describeValue(action)} (known: ${SCOPE_ACTIONS.join(", ")})`
33753
+ );
33754
+ }
33755
+ merged.add(action);
33756
+ }
33757
+ }
33758
+ const entries = [];
33759
+ for (const scope of [...byScope.keys()].sort(compareScopes)) {
33760
+ for (const action of sortActions(byScope.get(scope) ?? [])) {
33761
+ entries.push(formatScopeEntry({ scope, action }));
33762
+ }
33763
+ }
33764
+ return entries;
33765
+ }
33766
+ function hasAction(scopes, scope, action) {
33767
+ if (scope.includes(OPERATION_SEPARATOR)) return false;
33768
+ for (const entry of scopes) {
33769
+ let parsed;
33770
+ try {
33771
+ parsed = parseScopeEntry(entry);
33772
+ } catch (error) {
33773
+ if (error instanceof InvalidScopeEntryError) continue;
33774
+ throw error;
33775
+ }
33776
+ if (parsed.action === action && scopeMatchesPattern(scope, parsed.scope)) {
33777
+ return true;
33778
+ }
33779
+ }
33780
+ return false;
33781
+ }
33782
+ function tryGrantPermissions(scopes) {
33783
+ try {
33784
+ return grantPermissions(scopes);
33785
+ } catch (error) {
33786
+ if (error instanceof InvalidScopeEntryError) return void 0;
33787
+ throw error;
33788
+ }
33789
+ }
33790
+
33791
+ // src/protocol/personal-server-write.ts
33792
+ import { sha256 as sha2565 } from "@noble/hashes/sha2";
33793
+ import { bytesToHex as bytesToHex2, isAddress as isAddress5 } from "viem";
33794
+ import { z as z4 } from "zod";
33795
+
33796
+ // src/protocol/lineage.ts
33797
+ import {
33798
+ encodeAbiParameters,
33799
+ isAddress as isAddress4,
33800
+ keccak256
33801
+ } from "viem";
33802
+ import { z as z3 } from "zod";
33803
+
33804
+ // src/protocol/personal-server-error-body.ts
33805
+ function isRecord2(value) {
33806
+ return value !== null && typeof value === "object" && !Array.isArray(value);
33807
+ }
33808
+ async function readPersonalServerErrorBody(response) {
33809
+ let body;
33810
+ try {
33811
+ body = await response.json();
33812
+ } catch {
33813
+ return { errorCode: null, message: null };
33814
+ }
33815
+ if (!isRecord2(body)) return { errorCode: null, message: null };
33816
+ const nested = isRecord2(body.error) ? body.error : null;
33817
+ const gatewayShape = typeof body.error === "string" && typeof body.code === "string";
33818
+ const code = nested?.errorCode ?? nested?.code ?? body.errorCode ?? (gatewayShape ? body.code : void 0) ?? (typeof body.error === "string" ? body.error : void 0) ?? body.code;
33819
+ const message = nested?.message ?? body.message ?? (gatewayShape ? body.error : void 0);
33820
+ const gatewayDetails = {};
33821
+ for (const key of ["unknown", "scope", "sourceScope"]) {
33822
+ if (gatewayShape && body[key] !== void 0)
33823
+ gatewayDetails[key] = body[key];
33824
+ }
33825
+ const details = nested?.details ?? body.details ?? (Object.keys(gatewayDetails).length > 0 ? gatewayDetails : void 0);
33826
+ return {
33827
+ errorCode: typeof code === "string" ? code : null,
33828
+ message: typeof message === "string" ? message : null,
33829
+ ...isRecord2(details) ? { details } : {}
33830
+ };
33831
+ }
33832
+
33833
+ // src/protocol/write-signer.ts
33834
+ function isRecord3(value) {
33835
+ return value !== null && typeof value === "object";
33836
+ }
33837
+ function isViemWriteAccount(source) {
33838
+ return isRecord3(source) && source.type === "local" && typeof source.address === "string" && typeof source.signMessage === "function";
33839
+ }
33840
+ function isViemWriteWalletClient(source) {
33841
+ return isRecord3(source) && typeof source.signMessage === "function" && source.type !== "local" && (source.type === "walletClient" || "transport" in source);
33842
+ }
33843
+ function accountAddress(account) {
33844
+ return typeof account === "string" ? account : account.address;
33845
+ }
33846
+ function resolveWriteSigner(source, options = {}) {
33847
+ if (isViemWriteWalletClient(source)) {
33848
+ const account = options.account ?? source.account;
33849
+ if (account === void 0) {
33850
+ throw new WriteRequestError(
33851
+ "Viem wallet client requires an account option or account property"
33852
+ );
33853
+ }
33854
+ return {
33855
+ address: accountAddress(account),
33856
+ signMessage: (message) => source.signMessage({ account, message })
33857
+ };
33858
+ }
33859
+ if (isViemWriteAccount(source)) {
33860
+ return {
33861
+ address: source.address,
33862
+ signMessage: (message) => source.signMessage({ message })
33863
+ };
33864
+ }
33865
+ if (!isRecord3(source) || typeof source.signMessage !== "function") {
33866
+ throw new WriteRequestError(
33867
+ "signer must be a viem LocalAccount, a viem WalletClient, or a { signMessage } object"
33868
+ );
33869
+ }
33870
+ return source;
33871
+ }
33872
+
33873
+ // src/protocol/lineage.ts
33874
+ var DATA_POINT_ID_PATTERN = /^0x[0-9a-fA-F]{64}$/;
33875
+ function isDataPointId(value) {
33876
+ return typeof value === "string" && DATA_POINT_ID_PATTERN.test(value);
33877
+ }
33878
+ function deriveDataPointId(ownerAddress, scope) {
33879
+ if (!isAddress4(ownerAddress, { strict: false })) {
33880
+ throw new Error(
33881
+ `ownerAddress is not an EVM address: ${String(ownerAddress)}`
33882
+ );
33883
+ }
33884
+ return keccak256(
33885
+ encodeAbiParameters(
33886
+ [
33887
+ { name: "ownerAddress", type: "address" },
33888
+ { name: "scope", type: "string" }
33889
+ ],
33890
+ [ownerAddress, scope]
33891
+ )
33892
+ );
33893
+ }
33894
+ var DataPointIdSchema = z3.string().regex(DATA_POINT_ID_PATTERN).transform((value) => value.toLowerCase());
33895
+ var VERSION_PATTERN = /^[1-9]\d*$/;
33896
+ var NODE_VERSION_PATTERN = /^(0|[1-9]\d*)$/;
33897
+ var VersionSchema = z3.union([z3.string(), z3.number()]).transform(String).refine((value) => NODE_VERSION_PATTERN.test(value), {
33898
+ message: "version must be a decimal integer"
33899
+ });
33900
+ var ViewVersionSchema = VersionSchema.refine(
33901
+ (value) => VERSION_PATTERN.test(value),
33902
+ { message: "version must be a positive decimal integer" }
33903
+ );
33904
+ function scopeNamespace(scope) {
33905
+ const dot = scope.indexOf(".");
33906
+ return dot === -1 ? scope : scope.slice(0, dot);
33907
+ }
33908
+ function derivedScopeViolatesNaming(derivedScope, sourceScope) {
33909
+ return scopeNamespace(derivedScope) === scopeNamespace(sourceScope);
33910
+ }
33911
+ function assertDerivedScopeNaming(derivedScope, sourceScopes) {
33912
+ for (const sourceScope of sourceScopes) {
33913
+ if (derivedScopeViolatesNaming(derivedScope, sourceScope)) {
33914
+ throw new WriteRequestError(
33915
+ `Derived scope ${derivedScope} must not share its first segment with source scope ${sourceScope}; put derivatives in the app's own namespace`,
33916
+ { scope: derivedScope, sourceScope }
33917
+ );
33918
+ }
33919
+ }
33920
+ }
33921
+ var LineageNodeSchema = z3.object({
33922
+ dataPointId: DataPointIdSchema,
33923
+ scope: z3.string(),
33924
+ /**
33925
+ * The node's current version, decimal string; `"0"` for a source that no
33926
+ * longer resolves to a registered data point.
33927
+ */
33928
+ version: VersionSchema,
33929
+ /** The node's tombstone time, or `null` when live. */
33930
+ deletedAt: z3.string().nullable()
33931
+ });
33932
+ var RedactedLineageNodeSchema = z3.object({
33933
+ dataPointId: DataPointIdSchema,
33934
+ redacted: z3.literal(true)
33935
+ });
33936
+ var LineageEntrySchema = z3.union([
33937
+ RedactedLineageNodeSchema,
33938
+ LineageNodeSchema
33939
+ ]);
33940
+ var LineageGraphSchema = z3.object({
33941
+ dataPointId: DataPointIdSchema,
33942
+ /** The data point owner; every node in the view belongs to it. */
33943
+ ownerAddress: z3.string().optional(),
33944
+ scope: z3.string(),
33945
+ /**
33946
+ * The derived record's version whose lineage is shown: the requested one,
33947
+ * else the current one, else (current is a tombstone) the last version
33948
+ * that carried lineage.
33949
+ */
33950
+ version: ViewVersionSchema,
33951
+ deletedAt: z3.string().nullable(),
33952
+ sources: z3.array(LineageEntrySchema),
33953
+ derivatives: z3.array(LineageEntrySchema),
33954
+ /** `true` when `derivatives` was cut at the server's cap (1000). */
33955
+ derivativesTruncated: z3.boolean().optional()
33956
+ });
33957
+ function isRedactedLineageNode(entry) {
33958
+ return "redacted" in entry && entry.redacted === true;
33959
+ }
33960
+ function personalServerLineagePath(scope, version) {
33961
+ return `/v1/data/${encodeURIComponent(scope)}/lineage${version === void 0 ? "" : `/${String(version)}`}`;
33962
+ }
33963
+ function gatewayLineagePath(dataPointId, version) {
33964
+ return `/v1/data/${dataPointId.toLowerCase()}/lineage${version === void 0 ? "" : `/${String(version)}`}`;
33965
+ }
33966
+ function normalizeBaseUrl(url) {
33967
+ return url.replace(/\/+$/, "");
33968
+ }
33969
+ function resolveFetch(fetchFn) {
33970
+ const resolved = fetchFn ?? globalThis.fetch;
33971
+ if (resolved === void 0) {
33972
+ throw new LineageReadError("No fetch implementation available");
33973
+ }
33974
+ return resolved;
33975
+ }
33976
+ function normalizeVersion(version) {
33977
+ if (version === void 0) return void 0;
33978
+ const text = String(version);
33979
+ if (!VERSION_PATTERN.test(text)) {
33980
+ throw new LineageReadError(
33981
+ "version must be a positive decimal integer",
33982
+ void 0,
33983
+ "INVALID_VERSION",
33984
+ { version }
33985
+ );
33986
+ }
33987
+ return text;
33988
+ }
33989
+ async function lineageReadFailure(source, response) {
33990
+ const { errorCode, message, details } = await readPersonalServerErrorBody(response);
33991
+ return new LineageReadError(
33992
+ message ?? `${source} lineage read failed: ${response.status} ${response.statusText}`,
33993
+ response.status,
33994
+ errorCode,
33995
+ details
33996
+ );
33997
+ }
33998
+ async function parseLineageGraph(source, response) {
33999
+ let body;
34000
+ try {
34001
+ body = await response.json();
34002
+ } catch (err) {
34003
+ throw new LineageReadError(
34004
+ `${source} lineage response is not JSON`,
34005
+ response.status,
34006
+ null,
34007
+ { cause: err instanceof Error ? err.message : String(err) }
34008
+ );
34009
+ }
34010
+ const envelope = isRecord2(body) && isRecord2(body.data) ? body : void 0;
34011
+ const parsed = LineageGraphSchema.safeParse(envelope?.data ?? body);
34012
+ if (!parsed.success) {
34013
+ throw new LineageReadError(
34014
+ `${source} lineage response is not a lineage view`,
34015
+ response.status,
34016
+ null,
34017
+ { issues: parsed.error.issues }
34018
+ );
34019
+ }
34020
+ const proof = isRecord2(envelope?.proof) ? envelope.proof : void 0;
34021
+ return proof === void 0 ? parsed.data : { ...parsed.data, proof };
34022
+ }
34023
+ async function sendLineageRead(source, fetchFn, url, headers) {
34024
+ let response;
34025
+ try {
34026
+ response = await fetchFn(url, { method: "GET", headers });
34027
+ } catch (err) {
34028
+ throw new LineageReadError(
34029
+ `${source} lineage read failed: ${err instanceof Error ? err.message : String(err)}`,
34030
+ void 0,
34031
+ null,
34032
+ { cause: err instanceof Error ? err.message : String(err) }
34033
+ );
34034
+ }
34035
+ if (!response.ok) {
34036
+ throw await lineageReadFailure(source, response);
34037
+ }
34038
+ return parseLineageGraph(source, response);
34039
+ }
34040
+ async function getPersonalServerLineage(params) {
34041
+ const fetchFn = resolveFetch(params.fetch);
34042
+ const baseUrl = normalizeBaseUrl(params.personalServerUrl);
34043
+ const audience = params.audience ?? baseUrl;
34044
+ const signer = resolveWriteSigner(params.signer, { account: params.account });
34045
+ const path = personalServerLineagePath(
34046
+ params.scope,
34047
+ normalizeVersion(params.version)
34048
+ );
34049
+ const headers = new Headers(params.headers);
34050
+ headers.set(
34051
+ "Authorization",
34052
+ await buildWeb3SignedHeader({
34053
+ signMessage: signer.signMessage,
34054
+ aud: audience,
34055
+ method: "GET",
34056
+ uri: path,
34057
+ grantId: params.grantId
34058
+ })
34059
+ );
34060
+ return sendLineageRead(
34061
+ "Personal Server",
34062
+ fetchFn,
34063
+ `${baseUrl}${path}`,
34064
+ headers
34065
+ );
34066
+ }
34067
+ async function getGatewayLineage(params) {
34068
+ if (!isDataPointId(params.dataPointId)) {
34069
+ throw new LineageReadError(
34070
+ "dataPointId must be a 32-byte hex string (see deriveDataPointId)",
34071
+ void 0,
34072
+ "INVALID_DATA_POINT_ID",
34073
+ { dataPointId: params.dataPointId }
34074
+ );
34075
+ }
34076
+ const fetchFn = resolveFetch(params.fetch);
34077
+ const baseUrl = normalizeBaseUrl(params.gatewayUrl);
34078
+ const signer = resolveWriteSigner(params.signer, { account: params.account });
34079
+ const uri = gatewayLineagePath(
34080
+ params.dataPointId,
34081
+ normalizeVersion(params.version)
34082
+ );
34083
+ const headers = new Headers(params.headers);
34084
+ headers.set(
34085
+ "Authorization",
34086
+ await buildWeb3SignedHeader({
34087
+ signMessage: signer.signMessage,
34088
+ aud: baseUrl,
34089
+ method: "GET",
34090
+ uri,
34091
+ grantId: params.grantId?.toLowerCase()
34092
+ })
34093
+ );
34094
+ return sendLineageRead("Gateway", fetchFn, `${baseUrl}${uri}`, headers);
34095
+ }
34096
+ function getLineage(params) {
34097
+ return "personalServerUrl" in params ? getPersonalServerLineage(params) : getGatewayLineage(params);
34098
+ }
34099
+
34100
+ // src/protocol/personal-server-write.ts
34101
+ var WRITE_SESSION_PATH = "/v1/write/session";
34102
+ var WRITE_SIGNATURE_HEADER = "X-Vana-Write-Signature";
34103
+ var WRITE_METADATA_HEADER = "X-Vana-Metadata";
34104
+ var LINEAGE_FIELD = "lineage";
34105
+ var MAX_LINEAGE_SOURCES = 256;
34106
+ var WRITE_FILENAME_HEADER = "X-Filename";
34107
+ var WRITE_CONTENT_DISPOSITION_HEADER = "Content-Disposition";
34108
+ var WRITER_ATTRIBUTION_KEY = "$writtenBy";
34109
+ var LINEAGE_KEY = "$lineage";
34110
+ var RESERVED_WRITE_KEYS = [
34111
+ WRITER_ATTRIBUTION_KEY,
34112
+ LINEAGE_KEY
34113
+ ];
34114
+ var WriteDataResultSchema = IngestResponseSchema.extend({
34115
+ // Present when the write carried lineage: the validated, lowercased ids.
34116
+ lineage: z4.object({ sources: z4.array(z4.string()) }).optional()
34117
+ });
34118
+ var WriteSessionResponseSchema = z4.object({
34119
+ access_token: z4.string().min(1),
34120
+ token_type: z4.string(),
34121
+ expires_in: z4.number().nonnegative(),
34122
+ scope: z4.string()
34123
+ });
34124
+ function normalizeBaseUrl2(url) {
34125
+ return url.replace(/\/+$/, "");
34126
+ }
34127
+ function resolveFetch2(fetchFn) {
34128
+ const resolved = fetchFn ?? globalThis.fetch;
34129
+ if (resolved === void 0) {
34130
+ throw new WriteRequestError("No fetch implementation available");
34131
+ }
34132
+ return resolved;
34133
+ }
34134
+ function dataPath(scope) {
34135
+ return `/v1/data/${encodeURIComponent(scope)}`;
34136
+ }
34137
+ function errorMessage(err) {
34138
+ return err instanceof Error ? err.message : String(err);
34139
+ }
34140
+ function finiteOr(value, fallback) {
34141
+ return typeof value === "number" && Number.isFinite(value) ? value : fallback;
34142
+ }
34143
+ function sleep2(ms) {
34144
+ return new Promise((resolve) => setTimeout(resolve, ms));
34145
+ }
34146
+ var issuedProofIats = /* @__PURE__ */ new Map();
34147
+ var issuedProofBuckets = /* @__PURE__ */ new Map();
34148
+ var issuedProofIatsPrunedAtSec = 0;
34149
+ var WEB3_SIGNED_PROOF_LIFETIME_SECONDS = 300;
34150
+ var WEB3_SIGNED_CLOCK_SKEW_SECONDS = 60;
34151
+ var PROOF_IAT_RETENTION_SECONDS = WEB3_SIGNED_PROOF_LIFETIME_SECONDS + WEB3_SIGNED_CLOCK_SKEW_SECONDS;
34152
+ var PROOF_IAT_MAX_AHEAD_SECONDS = 30;
34153
+ function pruneIssuedProofIats(nowSec) {
34154
+ if (issuedProofIatsPrunedAtSec === nowSec) return;
34155
+ issuedProofIatsPrunedAtSec = nowSec;
34156
+ const cutoff = nowSec - PROOF_IAT_RETENTION_SECONDS;
34157
+ for (const [sec, keys] of issuedProofBuckets) {
34158
+ if (sec >= cutoff) continue;
34159
+ for (const key of keys) issuedProofIats.delete(key);
34160
+ issuedProofBuckets.delete(sec);
34161
+ }
34162
+ }
34163
+ function setIssuedProofIat(key, iat, previous) {
34164
+ if (previous !== void 0) {
34165
+ const bucket2 = issuedProofBuckets.get(previous);
34166
+ bucket2?.delete(key);
34167
+ if (bucket2?.size === 0) issuedProofBuckets.delete(previous);
34168
+ }
34169
+ issuedProofIats.set(key, iat);
34170
+ let bucket = issuedProofBuckets.get(iat);
34171
+ if (bucket === void 0) {
34172
+ bucket = /* @__PURE__ */ new Set();
34173
+ issuedProofBuckets.set(iat, bucket);
34174
+ }
34175
+ bucket.add(key);
34176
+ }
34177
+ function nextProofIat(proofKey) {
34178
+ const nowSec = Math.floor(Date.now() / 1e3);
34179
+ pruneIssuedProofIats(nowSec);
34180
+ const last = issuedProofIats.get(proofKey);
34181
+ const iat = last === void 0 ? nowSec : Math.max(nowSec, last + 1);
34182
+ setIssuedProofIat(proofKey, iat, last);
34183
+ const waitSec = iat - nowSec - PROOF_IAT_MAX_AHEAD_SECONDS;
34184
+ if (waitSec <= 0) return Promise.resolve(iat);
34185
+ return sleep2(waitSec * 1e3).then(() => iat);
34186
+ }
34187
+ function proofKeyFor(parts) {
34188
+ return bytesToHex2(
34189
+ sha2565(
34190
+ new TextEncoder().encode(
34191
+ JSON.stringify([
34192
+ parts.aud,
34193
+ parts.method,
34194
+ parts.uri,
34195
+ parts.grantId,
34196
+ parts.signedBytes ? bytesToHex2(sha2565(parts.signedBytes)) : ""
34197
+ ])
34198
+ )
34199
+ )
34200
+ );
34201
+ }
34202
+ async function sendWithFreshProof(label, fetchFn, options, proofKey, build) {
34203
+ const attempts = Math.max(1, Math.floor(finiteOr(options?.attempts, 3)));
34204
+ let delayMs = Math.max(0, finiteOr(options?.initialDelayMs, 1e3));
34205
+ let lastError;
34206
+ for (let attempt = 0; attempt < attempts; attempt++) {
34207
+ const { url, init } = await build(await nextProofIat(proofKey));
34208
+ try {
34209
+ return await fetchFn(url, init);
34210
+ } catch (err) {
34211
+ lastError = err;
34212
+ }
34213
+ if (attempt < attempts - 1) {
34214
+ await sleep2(delayMs);
34215
+ delayMs *= 2;
34216
+ }
34217
+ }
34218
+ throw new WriteTransportError(
34219
+ `${label} failed after ${attempts} attempt(s): ${errorMessage(lastError)}`,
34220
+ attempts,
34221
+ lastError
34222
+ );
34223
+ }
34224
+ async function openWriteSession(params) {
34225
+ const fetchFn = resolveFetch2(params.fetch);
34226
+ const personalServerUrl = normalizeBaseUrl2(params.personalServerUrl);
34227
+ const audience = params.audience ?? personalServerUrl;
34228
+ const signer = resolveWriteSigner(params.signer, { account: params.account });
34229
+ const response = await sendWithFreshProof(
34230
+ "Write session handshake",
34231
+ fetchFn,
34232
+ params.retry,
34233
+ proofKeyFor({
34234
+ aud: audience,
34235
+ method: "POST",
34236
+ uri: WRITE_SESSION_PATH,
34237
+ grantId: params.grantId
34238
+ }),
34239
+ async (iat) => {
34240
+ const headers = new Headers(params.headers);
34241
+ headers.set(
34242
+ "Authorization",
34243
+ await buildWeb3SignedHeader({
34244
+ signMessage: signer.signMessage,
34245
+ aud: audience,
34246
+ method: "POST",
34247
+ uri: WRITE_SESSION_PATH,
34248
+ grantId: params.grantId,
34249
+ iat
34250
+ })
34251
+ );
34252
+ return {
34253
+ url: `${personalServerUrl}${WRITE_SESSION_PATH}`,
34254
+ init: { method: "POST", headers }
34255
+ };
34256
+ }
34257
+ );
34258
+ const mintedAt = Date.now();
34259
+ if (!response.ok) {
34260
+ const { errorCode, message, details } = await readPersonalServerErrorBody(response);
34261
+ throw new WriteSessionError(
34262
+ message ?? `Write session handshake failed: ${response.status} ${response.statusText}`,
34263
+ response.status,
34264
+ errorCode,
34265
+ details
34266
+ );
34267
+ }
34268
+ let body;
34269
+ try {
34270
+ body = await response.json();
34271
+ } catch (err) {
34272
+ throw new WriteSessionError(
34273
+ "Write session response is not JSON",
34274
+ response.status,
34275
+ null,
34276
+ { cause: errorMessage(err) }
34277
+ );
34278
+ }
34279
+ const parsed = WriteSessionResponseSchema.safeParse(body);
34280
+ if (!parsed.success) {
34281
+ throw new WriteSessionError(
34282
+ "Write session response is not a session",
34283
+ response.status,
34284
+ null,
34285
+ { issues: parsed.error.issues }
34286
+ );
34287
+ }
34288
+ if (parsed.data.token_type.toLowerCase() !== "bearer") {
34289
+ throw new WriteSessionError(
34290
+ `Write session token type is not Bearer: ${parsed.data.token_type}`,
34291
+ response.status
34292
+ );
34293
+ }
34294
+ return {
34295
+ personalServerUrl,
34296
+ audience,
34297
+ grantId: params.grantId,
34298
+ accessToken: parsed.data.access_token,
34299
+ expiresAt: mintedAt + parsed.data.expires_in * 1e3,
34300
+ writeScopes: parsed.data.scope.split(" ").filter((s) => s.length > 0),
34301
+ signer
34302
+ };
34303
+ }
34304
+ function isWriteSession(value) {
34305
+ if (!isRecord2(value)) return false;
34306
+ const signer = value.signer;
34307
+ 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";
34308
+ }
34309
+ function sessionCoversScope(session, scope) {
34310
+ if (!isRecord2(session) || !Array.isArray(session.writeScopes) || !session.writeScopes.every((pattern) => typeof pattern === "string")) {
34311
+ throw new WriteRequestError("session must come from openWriteSession");
34312
+ }
34313
+ return session.writeScopes.some(
34314
+ (pattern) => scopeMatchesPattern(scope, pattern)
34315
+ );
34316
+ }
34317
+ function normalizeBinaryMimeType(contentType) {
34318
+ if (!contentType) return "application/octet-stream";
34319
+ return contentType.split(";")[0].trim() || "application/octet-stream";
34320
+ }
34321
+ function parseWriteMetadataHeader(value) {
34322
+ if (value === null) return void 0;
34323
+ const trimmed = value.trim();
34324
+ if (trimmed === "") return void 0;
34325
+ try {
34326
+ return JSON.parse(trimmed);
34327
+ } catch {
34328
+ return value;
34329
+ }
34330
+ }
34331
+ function encodeWriteMetadataHeader(metadata) {
34332
+ let json;
34333
+ try {
34334
+ json = JSON.stringify(metadata);
34335
+ } catch (err) {
34336
+ throw new WriteRequestError(
34337
+ `metadata is not JSON-serialisable: ${errorMessage(err)}`
34338
+ );
34339
+ }
34340
+ if (typeof json !== "string") {
34341
+ throw new WriteRequestError("metadata must serialise to JSON");
34342
+ }
34343
+ return json.replace(
34344
+ /[\u007f-\uffff]/g,
34345
+ (c) => `\\u${c.charCodeAt(0).toString(16).padStart(4, "0")}`
34346
+ );
34347
+ }
34348
+ function binaryWriteSignedBytes(input) {
34349
+ const metadata = parseWriteMetadataHeader(input.metadataHeader ?? null);
34350
+ const record = {
34351
+ $binary: true,
34352
+ mimeType: normalizeBinaryMimeType(input.contentType),
34353
+ ...input.filename ? { filename: input.filename } : {},
34354
+ sizeBytes: input.bytes.length,
34355
+ contentHash: bytesToHex2(sha2565(input.bytes)),
34356
+ encoding: "base64",
34357
+ content: toBase64(input.bytes),
34358
+ ...metadata !== void 0 ? { metadata } : {}
34359
+ };
34360
+ return new TextEncoder().encode(JSON.stringify(record));
34361
+ }
34362
+ var PRINTABLE_ASCII = /^[\x20-\x7e]*$/;
34363
+ function setFilenameHeader(headers, filename) {
34364
+ if (PRINTABLE_ASCII.test(filename)) {
34365
+ headers.set(WRITE_FILENAME_HEADER, filename);
34366
+ return;
34367
+ }
34368
+ headers.set(
34369
+ WRITE_CONTENT_DISPOSITION_HEADER,
34370
+ `attachment; filename*=UTF-8''${encodeURIComponent(filename)}`
34371
+ );
34372
+ }
34373
+ function assertNoReservedKeys(value, where) {
34374
+ for (const key of RESERVED_WRITE_KEYS) {
34375
+ if (Object.prototype.hasOwnProperty.call(value, key)) {
34376
+ throw new WriteRequestError(
34377
+ `${where} must not contain the reserved ${key} key; the Personal Server stamps it`,
34378
+ { key }
34379
+ );
34380
+ }
34381
+ }
34382
+ }
34383
+ function isLineagePair(value) {
34384
+ return isRecord2(value) && typeof value.ownerAddress === "string" && typeof value.scope === "string";
34385
+ }
34386
+ function normalizeLineage(lineage, derivedScope) {
34387
+ if (!Array.isArray(lineage)) {
34388
+ throw new WriteRequestError("lineage must be an array of data point ids");
34389
+ }
34390
+ if (lineage.length > MAX_LINEAGE_SOURCES) {
34391
+ throw new WriteRequestError(
34392
+ `lineage lists ${lineage.length} sources; the maximum is ${MAX_LINEAGE_SOURCES}`,
34393
+ { max: MAX_LINEAGE_SOURCES, count: lineage.length }
34394
+ );
34395
+ }
34396
+ const seen = /* @__PURE__ */ new Set();
34397
+ const sources = [];
34398
+ const sourceScopes = [];
34399
+ const ownIds = /* @__PURE__ */ new Set();
34400
+ for (const entry of lineage) {
34401
+ let id;
34402
+ if (isLineagePair(entry)) {
34403
+ if (!isAddress5(entry.ownerAddress, { strict: false })) {
34404
+ throw new WriteRequestError(
34405
+ "lineage source ownerAddress must be an EVM address",
34406
+ { ownerAddress: entry.ownerAddress }
34407
+ );
34408
+ }
34409
+ if (entry.scope.length === 0) {
34410
+ throw new WriteRequestError("lineage source scope is required");
34411
+ }
34412
+ id = deriveDataPointId(entry.ownerAddress, entry.scope);
34413
+ sourceScopes.push(entry.scope);
34414
+ ownIds.add(deriveDataPointId(entry.ownerAddress, derivedScope));
34415
+ } else if (isDataPointId(entry)) {
34416
+ id = entry;
34417
+ } else {
34418
+ throw new WriteRequestError(
34419
+ "lineage entries must be 32-byte hex data point ids or { ownerAddress, scope } pairs",
34420
+ { entry }
34421
+ );
34422
+ }
34423
+ const normalized = id.toLowerCase();
34424
+ if (seen.has(normalized)) {
34425
+ throw new WriteRequestError("lineage must not repeat a data point id", {
34426
+ dataPointId: normalized
34427
+ });
34428
+ }
34429
+ seen.add(normalized);
34430
+ sources.push(normalized);
34431
+ }
34432
+ for (const own of ownIds) {
34433
+ if (seen.has(own)) {
34434
+ throw new WriteRequestError(
34435
+ "lineage must not cite the record's own data point",
34436
+ { dataPointId: own, scope: derivedScope }
34437
+ );
34438
+ }
34439
+ }
34440
+ assertDerivedScopeNaming(derivedScope, sourceScopes);
34441
+ return sources;
34442
+ }
34443
+ function assertNoLineageField(value, where) {
34444
+ if (Object.prototype.hasOwnProperty.call(value, LINEAGE_FIELD)) {
34445
+ throw new WriteRequestError(
34446
+ `${where}.${LINEAGE_FIELD} is reserved; pass sources through the lineage option`
34447
+ );
34448
+ }
34449
+ }
34450
+ function buildMetadataHeader(metadata, sources) {
34451
+ if (metadata !== void 0) {
34452
+ if (!isRecord2(metadata)) {
34453
+ throw new WriteRequestError("metadata must be a plain object");
34454
+ }
34455
+ assertNoReservedKeys(metadata, "metadata");
34456
+ assertNoLineageField(metadata, "metadata");
34457
+ }
34458
+ if (metadata === void 0 && sources === void 0) return void 0;
34459
+ return encodeWriteMetadataHeader({
34460
+ ...metadata ?? {},
34461
+ ...sources !== void 0 ? { [LINEAGE_FIELD]: sources } : {}
34462
+ });
34463
+ }
34464
+ function prepareWrite(params) {
34465
+ if (params.binary !== void 0 && params.data !== void 0) {
34466
+ throw new WriteRequestError("Pass either data or binary, not both");
34467
+ }
34468
+ const rawLineage = params.lineage;
34469
+ const sources = rawLineage === void 0 || rawLineage === null ? void 0 : normalizeLineage(rawLineage, params.scope);
34470
+ if (params.binary !== void 0) {
34471
+ const { bytes, contentType, filename } = params.binary;
34472
+ if (!(bytes instanceof Uint8Array)) {
34473
+ throw new WriteRequestError("binary.bytes must be a Uint8Array");
34474
+ }
34475
+ if (typeof contentType !== "string" || contentType.trim() === "") {
34476
+ throw new WriteRequestError("binary.contentType is required");
34477
+ }
34478
+ if (filename !== void 0) {
34479
+ if (typeof filename !== "string") {
34480
+ throw new WriteRequestError("binary.filename must be a string");
34481
+ }
34482
+ if (filename !== filename.trim()) {
34483
+ throw new WriteRequestError(
34484
+ "binary.filename must not have leading or trailing whitespace"
34485
+ );
34486
+ }
34487
+ }
34488
+ const metadataHeader = buildMetadataHeader(params.metadata, sources);
34489
+ return {
34490
+ body: bytes,
34491
+ signedBytes: binaryWriteSignedBytes({
34492
+ bytes,
34493
+ contentType,
34494
+ filename,
34495
+ metadataHeader
34496
+ }),
34497
+ contentType,
34498
+ filename,
34499
+ metadataHeader
34500
+ };
34501
+ }
34502
+ if (params.data === void 0) {
34503
+ throw new WriteRequestError("Pass data (a JSON object) or binary");
34504
+ }
34505
+ if (!isRecord2(params.data)) {
34506
+ throw new WriteRequestError("data must be a plain JSON object");
34507
+ }
34508
+ if (params.metadata !== void 0) {
34509
+ throw new WriteRequestError(
34510
+ "metadata applies to binary writes; put fields to store inside data"
34511
+ );
34512
+ }
34513
+ assertNoReservedKeys(params.data, "data");
34514
+ assertNoLineageField(params.data, "data");
34515
+ const record = sources === void 0 ? params.data : { ...params.data, [LINEAGE_FIELD]: sources };
34516
+ let text;
34517
+ try {
34518
+ text = JSON.stringify(record);
34519
+ } catch (err) {
34520
+ throw new WriteRequestError(
34521
+ `data is not JSON-serialisable: ${errorMessage(err)}`
34522
+ );
34523
+ }
34524
+ if (typeof text !== "string" || !text.startsWith("{")) {
34525
+ throw new WriteRequestError("data must serialise to a JSON object");
34526
+ }
34527
+ const body = new TextEncoder().encode(text);
34528
+ return {
34529
+ body,
34530
+ signedBytes: body,
34531
+ contentType: "application/json"
34532
+ };
34533
+ }
34534
+ async function writeErrorFromResponse(response) {
34535
+ const { errorCode, message, details } = await readPersonalServerErrorBody(response);
34536
+ const text = message ?? `Personal Server write failed: ${response.status} ${response.statusText}`;
34537
+ if (response.status === 422 || errorCode?.startsWith("LINEAGE_")) {
34538
+ return new WriteLineageError(text, response.status, errorCode, details);
34539
+ }
34540
+ switch (response.status) {
34541
+ case 401:
34542
+ return new WriteUnauthorizedError(text, errorCode, details);
34543
+ case 403:
34544
+ return new WriteForbiddenError(text, errorCode, details);
34545
+ case 409:
34546
+ return new WriteConflictError(text, errorCode, details);
34547
+ default:
34548
+ return new WriteRejectedError(text, response.status, errorCode, details);
34549
+ }
34550
+ }
34551
+ async function writeData(params) {
34552
+ const { session } = params;
34553
+ if (!isWriteSession(session)) {
34554
+ throw new WriteRequestError("session must come from openWriteSession");
34555
+ }
34556
+ const fetchFn = resolveFetch2(params.fetch);
34557
+ if (typeof params.scope !== "string" || params.scope.length === 0) {
34558
+ throw new WriteRequestError("scope is required");
34559
+ }
34560
+ const prepared = prepareWrite(params);
34561
+ if (Date.now() >= session.expiresAt) {
34562
+ throw new WriteSessionExpiredError(
34563
+ "Write session has expired; open a new session",
34564
+ { grantId: session.grantId, expiresAt: session.expiresAt }
34565
+ );
34566
+ }
34567
+ const path = dataPath(params.scope);
34568
+ const response = await sendWithFreshProof(
34569
+ `Write to ${params.scope}`,
34570
+ fetchFn,
34571
+ params.retry,
34572
+ proofKeyFor({
34573
+ aud: session.audience,
34574
+ method: "POST",
34575
+ uri: path,
34576
+ grantId: session.grantId,
34577
+ signedBytes: prepared.signedBytes
34578
+ }),
34579
+ async (iat) => {
34580
+ const headers = new Headers(params.headers);
34581
+ headers.set("Content-Type", prepared.contentType);
34582
+ headers.set("Authorization", `Bearer ${session.accessToken}`);
34583
+ if (prepared.filename) {
34584
+ setFilenameHeader(headers, prepared.filename);
34585
+ }
34586
+ if (prepared.metadataHeader !== void 0) {
34587
+ headers.set(WRITE_METADATA_HEADER, prepared.metadataHeader);
34588
+ }
34589
+ headers.set(
34590
+ WRITE_SIGNATURE_HEADER,
34591
+ await buildWeb3SignedHeader({
34592
+ signMessage: session.signer.signMessage,
34593
+ aud: session.audience,
34594
+ method: "POST",
34595
+ uri: path,
34596
+ body: prepared.signedBytes,
34597
+ grantId: session.grantId,
34598
+ iat
34599
+ })
34600
+ );
34601
+ return {
34602
+ url: `${session.personalServerUrl}${path}`,
34603
+ init: {
34604
+ method: "POST",
34605
+ headers,
34606
+ body: prepared.body
34607
+ }
34608
+ };
34609
+ }
34610
+ );
34611
+ if (!response.ok) {
34612
+ throw await writeErrorFromResponse(response);
34613
+ }
34614
+ let body;
34615
+ try {
34616
+ body = await response.json();
34617
+ } catch (err) {
34618
+ throw new WriteRejectedError(
34619
+ "Personal Server write response is not JSON",
34620
+ response.status,
34621
+ null,
34622
+ { cause: errorMessage(err) }
34623
+ );
34624
+ }
34625
+ const parsed = WriteDataResultSchema.safeParse(body);
34626
+ if (!parsed.success) {
34627
+ throw new WriteRejectedError(
34628
+ "Personal Server write response is not an ingest result",
34629
+ response.status,
34630
+ null,
34631
+ { issues: parsed.error.issues }
34632
+ );
34633
+ }
34634
+ return parsed.data;
34635
+ }
34636
+ async function writePersonalServerData(params) {
34637
+ const session = await openWriteSession({
34638
+ personalServerUrl: params.personalServerUrl,
34639
+ signer: params.signer,
34640
+ grantId: params.grantId,
34641
+ account: params.account,
34642
+ audience: params.audience,
34643
+ fetch: params.fetch,
34644
+ headers: params.headers,
34645
+ retry: params.retry
34646
+ });
34647
+ const writeParams = { ...params, session };
34648
+ const result = await writeData(writeParams);
34649
+ return { ...result, session };
34650
+ }
34651
+
33577
34652
  // src/protocol/gateway.ts
34653
+ function withGrantPermissions(grant) {
34654
+ const stripped = { ...grant };
34655
+ delete stripped.permissions;
34656
+ const scopes = stripped.scopes;
34657
+ if (!Array.isArray(scopes)) {
34658
+ return stripped;
34659
+ }
34660
+ const permissions = tryGrantPermissions(scopes);
34661
+ return permissions === void 0 ? stripped : { ...stripped, permissions };
34662
+ }
33578
34663
  function createGatewayClient(baseUrl) {
33579
34664
  const base = baseUrl.replace(/\/+$/, "");
33580
34665
  async function unwrapEnvelope(res) {
@@ -33604,7 +34689,9 @@ function createGatewayClient(baseUrl) {
33604
34689
  if (!res.ok) {
33605
34690
  throw new Error(`Gateway error: ${res.status} ${res.statusText}`);
33606
34691
  }
33607
- return unwrapEnvelope(res);
34692
+ return withGrantPermissions(
34693
+ await unwrapEnvelope(res)
34694
+ );
33608
34695
  },
33609
34696
  async listGrantsByUser(userAddress) {
33610
34697
  const res = await fetch(`${base}/v1/grants?user=${userAddress}`);
@@ -33612,7 +34699,8 @@ function createGatewayClient(baseUrl) {
33612
34699
  if (!res.ok) {
33613
34700
  throw new Error(`Gateway error: ${res.status} ${res.statusText}`);
33614
34701
  }
33615
- return unwrapEnvelope(res);
34702
+ const grants = await unwrapEnvelope(res);
34703
+ return grants.map(withGrantPermissions);
33616
34704
  },
33617
34705
  async getSchemaForScope(scope) {
33618
34706
  const res = await fetch(`${base}/v1/schemas?scope=${scope}`);
@@ -34481,7 +35569,7 @@ var KNOWN_CODES = /* @__PURE__ */ new Set([
34481
35569
  "server_not_configured",
34482
35570
  "content_too_large"
34483
35571
  ]);
34484
- function isRecord2(value) {
35572
+ function isRecord4(value) {
34485
35573
  return value !== null && typeof value === "object" && !Array.isArray(value);
34486
35574
  }
34487
35575
  function normalizeCode(value) {
@@ -34492,10 +35580,10 @@ function normalizeCode(value) {
34492
35580
  return KNOWN_CODES.has(code) ? code : null;
34493
35581
  }
34494
35582
  function extractPSErrorBody(body) {
34495
- if (!isRecord2(body)) {
35583
+ if (!isRecord4(body)) {
34496
35584
  return null;
34497
35585
  }
34498
- const nested = isRecord2(body.error) ? body.error : null;
35586
+ const nested = isRecord4(body.error) ? body.error : null;
34499
35587
  const code = normalizeCode(
34500
35588
  nested?.errorCode ?? nested?.code ?? body.errorCode ?? body.code
34501
35589
  );
@@ -34547,9 +35635,17 @@ export {
34547
35635
  InMemoryTokenStore,
34548
35636
  IngestResponseSchema,
34549
35637
  InvalidConfigurationError,
35638
+ InvalidScopeEntryError,
34550
35639
  InvalidSignatureError,
34551
35640
  IpfsStorage,
35641
+ LINEAGE_FIELD,
35642
+ LINEAGE_KEY,
35643
+ LineageEntrySchema,
35644
+ LineageGraphSchema,
35645
+ LineageNodeSchema,
35646
+ LineageReadError,
34552
35647
  MASTER_KEY_MESSAGE,
35648
+ MAX_LINEAGE_SOURCES,
34553
35649
  MissingAuthError,
34554
35650
  NATIVE_ASSET_ADDRESS,
34555
35651
  NATIVE_VANA_ASSET,
@@ -34568,12 +35664,16 @@ export {
34568
35664
  PSError,
34569
35665
  PermissionError,
34570
35666
  PersonalServerError,
35667
+ PersonalServerWriteError,
34571
35668
  PinataStorage,
34572
35669
  R2Storage,
34573
35670
  RECORD_DATA_ACCESS_TYPES,
34574
35671
  REGISTRATION_KIND_FOR_OP,
35672
+ RESERVED_WRITE_KEYS,
34575
35673
  ReadOnlyError,
35674
+ RedactedLineageNodeSchema,
34576
35675
  RelayerError,
35676
+ SCOPE_ACTIONS,
34577
35677
  SERVER_REGISTRATION_TYPES,
34578
35678
  ScopeSchema,
34579
35679
  SerializationError,
@@ -34585,9 +35685,26 @@ export {
34585
35685
  UserRejectedRequestError,
34586
35686
  VanaError,
34587
35687
  VanaStorage,
35688
+ WRITER_ATTRIBUTION_KEY,
35689
+ WRITE_CONTENT_DISPOSITION_HEADER,
35690
+ WRITE_FILENAME_HEADER,
35691
+ WRITE_METADATA_HEADER,
35692
+ WRITE_SESSION_PATH,
35693
+ WRITE_SIGNATURE_HEADER,
35694
+ WriteConflictError,
35695
+ WriteForbiddenError,
35696
+ WriteLineageError,
35697
+ WriteRejectedError,
35698
+ WriteRequestError,
35699
+ WriteSessionError,
35700
+ WriteSessionExpiredError,
35701
+ WriteTransportError,
35702
+ WriteUnauthorizedError,
35703
+ assertDerivedScopeNaming,
34588
35704
  assertValidPkceVerifier,
34589
35705
  authorizeEscrowPayment,
34590
35706
  authorizeGrantPayment,
35707
+ binaryWriteSignedBytes,
34591
35708
  buildDepositNativeRequest,
34592
35709
  buildDepositTokenRequest,
34593
35710
  buildEscrowPaymentHeader,
@@ -34621,16 +35738,21 @@ export {
34621
35738
  dataRegistryContractAddress,
34622
35739
  dataRegistryDomain,
34623
35740
  decryptWithPassword,
35741
+ deriveDataPointId,
34624
35742
  deriveMasterKey,
34625
35743
  deriveScopeKey,
35744
+ derivedScopeViolatesNaming,
34626
35745
  deserializeECIES,
34627
35746
  detectPlatform,
34628
35747
  encodeDepositNativeData,
34629
35748
  encodeDepositTokenData,
34630
35749
  encodeSetDataPointStatusData,
35750
+ encodeWriteMetadataHeader,
34631
35751
  encryptWithPassword,
34632
35752
  escrowContractAddress,
34633
35753
  escrowPaymentDomain,
35754
+ formatScopeEntry,
35755
+ gatewayLineagePath,
34634
35756
  generatePkceVerifier,
34635
35757
  genericPaymentDomain,
34636
35758
  getAbi,
@@ -34640,42 +35762,61 @@ export {
34640
35762
  getContractController,
34641
35763
  getContractInfo,
34642
35764
  getFee,
35765
+ getGatewayLineage,
35766
+ getLineage,
34643
35767
  getOpFee,
35768
+ getPersonalServerLineage,
34644
35769
  getPlatformCapabilities,
34645
35770
  getServiceEndpoints,
35771
+ grantPermissions,
34646
35772
  grantRegistrationDomain,
34647
35773
  grantRevocationDomain,
35774
+ hasAction,
35775
+ isDataPointId,
34648
35776
  isDataPortabilityGatewayConfig,
34649
35777
  isECIESEncrypted,
34650
35778
  isPlatformSupported,
35779
+ isRedactedLineageNode,
34651
35780
  mainnetServices,
34652
35781
  moksha,
34653
35782
  mokshaServices,
34654
35783
  mokshaTestnet2 as mokshaTestnet,
35784
+ normalizeBinaryMimeType,
35785
+ openWriteSession,
34655
35786
  parsePSError,
34656
35787
  parsePersonalServerPaymentRequired,
34657
35788
  parseScope,
35789
+ parseScopeEntry,
34658
35790
  parseWeb3SignedHeader,
35791
+ parseWriteMetadataHeader,
34659
35792
  paymentReceiptFromHeader,
34660
35793
  paymentResponseMetadataFromHeader,
35794
+ permissionsToScopes,
34661
35795
  personalServerDataReadPath,
35796
+ personalServerLineagePath,
34662
35797
  personalServerRegistrationDomain,
34663
35798
  readPersonalServerData,
34664
35799
  recoverServerOwner,
34665
35800
  registerPersonalServerSignature,
35801
+ resolveWriteSigner,
34666
35802
  scopeCoveredByGrant,
34667
35803
  scopeMatchesPattern,
35804
+ scopeNamespace,
34668
35805
  scopeToPathSegments,
34669
35806
  serializeECIES,
34670
35807
  serverRegistrationDomain,
35808
+ sessionCoversScope,
34671
35809
  signPersonalServerLiteOwnerBinding,
34672
35810
  signPersonalServerLiteOwnerBindingWithAccountClient,
34673
35811
  signPersonalServerRegistrationWithAccount,
34674
35812
  toDirectFeeBreakdown,
34675
35813
  toDirectPaymentReceipt,
35814
+ tryGrantPermissions,
34676
35815
  vanaMainnet2 as vanaMainnet,
34677
35816
  verifyGrantRegistration,
34678
35817
  verifyPkceChallenge,
34679
- verifyWeb3Signed
35818
+ verifyWeb3Signed,
35819
+ writeData,
35820
+ writePersonalServerData
34680
35821
  };
34681
35822
  //# sourceMappingURL=index.node.js.map