@tinycloud/node-sdk 3.0.0-beta.13 → 3.0.0-beta.14

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.
@@ -1040,6 +1040,10 @@ declare class UnsupportedSessionRestoreError extends Error {
1040
1040
  readonly code: "RESTORE_SESSION_KEY_REPLACEMENT_UNSUPPORTED";
1041
1041
  constructor(reason?: string);
1042
1042
  }
1043
+ declare class InvalidRestoredSessionError extends Error {
1044
+ readonly code: "AUTH_EXPIRED";
1045
+ constructor(message?: string);
1046
+ }
1043
1047
  /**
1044
1048
  * Configuration for TinyCloudNode.
1045
1049
  * All fields are optional - TinyCloudNode can work with zero configuration.
@@ -2460,4 +2464,4 @@ declare class WasmKeyProvider implements KeyProvider {
2460
2464
  */
2461
2465
  declare function createWasmKeyProvider(sessionManager: SessionManagerWithListing): WasmKeyProvider;
2462
2466
 
2463
- export { ACCEPTED_MARKER_VERSIONS as A, BOOTSTRAP_COMPLETION_MARKER_KEY as B, type CompactRuntimeDelegationInput as C, type DelegateToOptions as D, type EnsureEncryptionNetworkOptions as E, FileSessionStorage as F, serializeDelegation as G, MemorySessionStorage as M, type NodeEventEmitterStrategy as N, type OwnerDelegationReceipt as O, type PortableDelegation as P, type RestorableSession as R, type SecretPermissionHint as S, TinyCloudNode as T, type UnifiedOwnerRootInput as U, type ValidatedRuntimeDelegation as V, WasmKeyProvider as W, type AuthDelegationArtifact as a, type AuthRequestArtifact as b, BOOTSTRAP_COMPLETION_MARKER_VERSION as c, type BootstrapCompletionMarker as d, type BootstrapWarning as e, type CreateOwnerDelegationParams as f, type DelegateToResult as g, DelegatedAccess as h, type DelegationAuthority as i, NodeUserAuthorization as j, type NodeUserAuthorizationConfig as k, type RuntimeDelegationActivator as l, type RuntimePermissionGrantOptions as m, type SecretReadInput as n, type SecretReadResult as o, type SignStrategy as p, type TinyCloudNodeConfig as q, type UnifiedOwnerRootReceipt as r, UnsupportedSessionRestoreError as s, type WasmKeyProviderConfig as t, activateCompactRuntimeDelegation as u, activateValidatedRuntimeDelegation as v, createWasmKeyProvider as w, defaultSignStrategy as x, deserializeDelegation as y, grantAuthRequest as z };
2467
+ export { ACCEPTED_MARKER_VERSIONS as A, BOOTSTRAP_COMPLETION_MARKER_KEY as B, type CompactRuntimeDelegationInput as C, type DelegateToOptions as D, type EnsureEncryptionNetworkOptions as E, FileSessionStorage as F, serializeDelegation as G, InvalidRestoredSessionError as I, MemorySessionStorage as M, type NodeEventEmitterStrategy as N, type OwnerDelegationReceipt as O, type PortableDelegation as P, type RestorableSession as R, type SecretPermissionHint as S, TinyCloudNode as T, type UnifiedOwnerRootInput as U, type ValidatedRuntimeDelegation as V, WasmKeyProvider as W, type AuthDelegationArtifact as a, type AuthRequestArtifact as b, BOOTSTRAP_COMPLETION_MARKER_VERSION as c, type BootstrapCompletionMarker as d, type BootstrapWarning as e, type CreateOwnerDelegationParams as f, type DelegateToResult as g, DelegatedAccess as h, type DelegationAuthority as i, NodeUserAuthorization as j, type NodeUserAuthorizationConfig as k, type RuntimeDelegationActivator as l, type RuntimePermissionGrantOptions as m, type SecretReadInput as n, type SecretReadResult as o, type SignStrategy as p, type TinyCloudNodeConfig as q, type UnifiedOwnerRootReceipt as r, UnsupportedSessionRestoreError as s, type WasmKeyProviderConfig as t, activateCompactRuntimeDelegation as u, activateValidatedRuntimeDelegation as v, createWasmKeyProvider as w, defaultSignStrategy as x, deserializeDelegation as y, grantAuthRequest as z };
@@ -1040,6 +1040,10 @@ declare class UnsupportedSessionRestoreError extends Error {
1040
1040
  readonly code: "RESTORE_SESSION_KEY_REPLACEMENT_UNSUPPORTED";
1041
1041
  constructor(reason?: string);
1042
1042
  }
1043
+ declare class InvalidRestoredSessionError extends Error {
1044
+ readonly code: "AUTH_EXPIRED";
1045
+ constructor(message?: string);
1046
+ }
1043
1047
  /**
1044
1048
  * Configuration for TinyCloudNode.
1045
1049
  * All fields are optional - TinyCloudNode can work with zero configuration.
@@ -2460,4 +2464,4 @@ declare class WasmKeyProvider implements KeyProvider {
2460
2464
  */
2461
2465
  declare function createWasmKeyProvider(sessionManager: SessionManagerWithListing): WasmKeyProvider;
2462
2466
 
2463
- export { ACCEPTED_MARKER_VERSIONS as A, BOOTSTRAP_COMPLETION_MARKER_KEY as B, type CompactRuntimeDelegationInput as C, type DelegateToOptions as D, type EnsureEncryptionNetworkOptions as E, FileSessionStorage as F, serializeDelegation as G, MemorySessionStorage as M, type NodeEventEmitterStrategy as N, type OwnerDelegationReceipt as O, type PortableDelegation as P, type RestorableSession as R, type SecretPermissionHint as S, TinyCloudNode as T, type UnifiedOwnerRootInput as U, type ValidatedRuntimeDelegation as V, WasmKeyProvider as W, type AuthDelegationArtifact as a, type AuthRequestArtifact as b, BOOTSTRAP_COMPLETION_MARKER_VERSION as c, type BootstrapCompletionMarker as d, type BootstrapWarning as e, type CreateOwnerDelegationParams as f, type DelegateToResult as g, DelegatedAccess as h, type DelegationAuthority as i, NodeUserAuthorization as j, type NodeUserAuthorizationConfig as k, type RuntimeDelegationActivator as l, type RuntimePermissionGrantOptions as m, type SecretReadInput as n, type SecretReadResult as o, type SignStrategy as p, type TinyCloudNodeConfig as q, type UnifiedOwnerRootReceipt as r, UnsupportedSessionRestoreError as s, type WasmKeyProviderConfig as t, activateCompactRuntimeDelegation as u, activateValidatedRuntimeDelegation as v, createWasmKeyProvider as w, defaultSignStrategy as x, deserializeDelegation as y, grantAuthRequest as z };
2467
+ export { ACCEPTED_MARKER_VERSIONS as A, BOOTSTRAP_COMPLETION_MARKER_KEY as B, type CompactRuntimeDelegationInput as C, type DelegateToOptions as D, type EnsureEncryptionNetworkOptions as E, FileSessionStorage as F, serializeDelegation as G, InvalidRestoredSessionError as I, MemorySessionStorage as M, type NodeEventEmitterStrategy as N, type OwnerDelegationReceipt as O, type PortableDelegation as P, type RestorableSession as R, type SecretPermissionHint as S, TinyCloudNode as T, type UnifiedOwnerRootInput as U, type ValidatedRuntimeDelegation as V, WasmKeyProvider as W, type AuthDelegationArtifact as a, type AuthRequestArtifact as b, BOOTSTRAP_COMPLETION_MARKER_VERSION as c, type BootstrapCompletionMarker as d, type BootstrapWarning as e, type CreateOwnerDelegationParams as f, type DelegateToResult as g, DelegatedAccess as h, type DelegationAuthority as i, NodeUserAuthorization as j, type NodeUserAuthorizationConfig as k, type RuntimeDelegationActivator as l, type RuntimePermissionGrantOptions as m, type SecretReadInput as n, type SecretReadResult as o, type SignStrategy as p, type TinyCloudNodeConfig as q, type UnifiedOwnerRootReceipt as r, UnsupportedSessionRestoreError as s, type WasmKeyProviderConfig as t, activateCompactRuntimeDelegation as u, activateValidatedRuntimeDelegation as v, createWasmKeyProvider as w, defaultSignStrategy as x, deserializeDelegation as y, grantAuthRequest as z };
package/dist/core.cjs CHANGED
@@ -50,6 +50,7 @@ __export(core_exports, {
50
50
  DuckDbService: () => import_sdk_core15.DuckDbService,
51
51
  FileSessionStorage: () => FileSessionStorage,
52
52
  IdentityParseError: () => import_sdk_core11.IdentityParseError,
53
+ InvalidRestoredSessionError: () => InvalidRestoredSessionError,
53
54
  KVService: () => import_sdk_core13.KVService,
54
55
  ManifestValidationError: () => import_sdk_core12.ManifestValidationError,
55
56
  MemorySessionStorage: () => MemorySessionStorage,
@@ -2357,18 +2358,23 @@ var UnsupportedSessionRestoreError = class extends Error {
2357
2358
  this.name = "UnsupportedSessionRestoreError";
2358
2359
  }
2359
2360
  };
2361
+ var InvalidRestoredSessionError = class extends Error {
2362
+ constructor(message = "Persisted session authority is invalid or expired.") {
2363
+ super(message);
2364
+ this.code = "AUTH_EXPIRED";
2365
+ this.name = "InvalidRestoredSessionError";
2366
+ }
2367
+ };
2360
2368
  function canonicalRestoredVerificationMethod(canonicalVerificationMethod, persistedVerificationMethod) {
2361
2369
  if (typeof persistedVerificationMethod !== "string") return void 0;
2362
2370
  const principal = canonicalVerificationMethod.split("#", 1)[0];
2363
2371
  return persistedVerificationMethod === principal || persistedVerificationMethod === canonicalVerificationMethod ? canonicalVerificationMethod : void 0;
2364
2372
  }
2365
2373
  function persistedExpiry(value) {
2366
- if (typeof value !== "string") {
2367
- throw new Error("Persisted session without a SIWE expiration must include expiresAt.");
2368
- }
2374
+ if (typeof value !== "string") throw new InvalidRestoredSessionError("Persisted session must include expiresAt.");
2369
2375
  const expiry = new Date(value);
2370
2376
  if (!Number.isFinite(expiry.getTime()) || expiry.getTime() <= Date.now()) {
2371
- throw new Error("Persisted session expiry is invalid or expired.");
2377
+ throw new InvalidRestoredSessionError();
2372
2378
  }
2373
2379
  return expiry;
2374
2380
  }
@@ -3560,7 +3566,7 @@ var _TinyCloudNode = class _TinyCloudNode {
3560
3566
  return;
3561
3567
  } catch (error) {
3562
3568
  const message = error instanceof Error ? error.message : String(error);
3563
- if (/Unauthorized Action|\b401\b/.test(message)) {
3569
+ if (/Unauthorized Action|\b(?:401|403)\b/.test(message)) {
3564
3570
  console.warn(
3565
3571
  "TinyCloud account registry sync stopped: authorization verdict is not retryable",
3566
3572
  error
@@ -3810,9 +3816,14 @@ var _TinyCloudNode = class _TinyCloudNode {
3810
3816
  */
3811
3817
  async restoreSession(sessionData) {
3812
3818
  await this.wasmBindings.ensureInitialized?.();
3813
- const restoredJwk = clonePersistedSessionJwk(sessionData.jwk);
3819
+ let restoredJwk;
3820
+ try {
3821
+ restoredJwk = clonePersistedSessionJwk(sessionData.jwk);
3822
+ } catch {
3823
+ throw new InvalidRestoredSessionError("Persisted session has an invalid private Ed25519 session key.");
3824
+ }
3814
3825
  if (sessionData.chainId !== void 0 && (!Number.isSafeInteger(sessionData.chainId) || sessionData.chainId <= 0)) {
3815
- throw new Error("Persisted session chain ID must be a positive safe integer.");
3826
+ throw new InvalidRestoredSessionError("Persisted session chain ID must be a positive safe integer.");
3816
3827
  }
3817
3828
  const stagedManager = this.wasmBindings.createSessionManager();
3818
3829
  const stagedReplace = stagedManager.replaceSessionKey;
@@ -3824,32 +3835,31 @@ var _TinyCloudNode = class _TinyCloudNode {
3824
3835
  let stagedKeyId;
3825
3836
  let stagedJwk;
3826
3837
  let canonicalVerificationMethod;
3838
+ const keyIds = liveKeys.call(this.sessionManager);
3839
+ if (!Array.isArray(keyIds) || !keyIds.every((keyId) => typeof keyId === "string")) {
3840
+ throw new UnsupportedSessionRestoreError("it cannot reliably enumerate every live session signer");
3841
+ }
3842
+ for (const keyId of keyIds) {
3843
+ if (keyId === this.sessionKeyId) continue;
3844
+ const jwk = this.sessionManager.jwk(keyId);
3845
+ if (!jwk) throw new Error("missing live session key");
3846
+ stagedReplace.call(stagedManager, clonePersistedSessionJwk(JSON.parse(jwk)), keyId);
3847
+ }
3827
3848
  try {
3828
- const keyIds = liveKeys.call(this.sessionManager);
3829
- if (!Array.isArray(keyIds) || !keyIds.every((keyId) => typeof keyId === "string")) {
3830
- throw new UnsupportedSessionRestoreError("it cannot reliably enumerate every live session signer");
3831
- }
3832
- for (const keyId of keyIds) {
3833
- if (keyId === this.sessionKeyId) continue;
3834
- const jwk = this.sessionManager.jwk(keyId);
3835
- if (!jwk) throw new Error("missing live session key");
3836
- stagedReplace.call(stagedManager, clonePersistedSessionJwk(JSON.parse(jwk)), keyId);
3837
- }
3838
3849
  stagedKeyId = stagedReplace.call(stagedManager, restoredJwk, this.sessionKeyId);
3839
- const stagedJwkJson = stagedManager.jwk(stagedKeyId);
3840
- if (!stagedJwkJson) throw new Error("missing restored session key");
3841
- stagedJwk = clonePersistedSessionJwk(JSON.parse(stagedJwkJson));
3842
- canonicalVerificationMethod = stagedManager.getDID(stagedKeyId);
3843
- } catch (error) {
3844
- if (error instanceof UnsupportedSessionRestoreError) throw error;
3845
- throw new Error("Persisted session has an invalid private Ed25519 session key.");
3850
+ } catch {
3851
+ throw new InvalidRestoredSessionError("Persisted session has an invalid private Ed25519 session key.");
3846
3852
  }
3853
+ const stagedJwkJson = stagedManager.jwk(stagedKeyId);
3854
+ if (!stagedJwkJson) throw new Error("missing restored session key");
3855
+ stagedJwk = clonePersistedSessionJwk(JSON.parse(stagedJwkJson));
3856
+ canonicalVerificationMethod = stagedManager.getDID(stagedKeyId);
3847
3857
  const restoredVerificationMethod = canonicalRestoredVerificationMethod(
3848
3858
  canonicalVerificationMethod,
3849
3859
  sessionData.verificationMethod
3850
3860
  );
3851
3861
  if (!restoredVerificationMethod) {
3852
- throw new Error(
3862
+ throw new InvalidRestoredSessionError(
3853
3863
  "Persisted session verification method does not match its private Ed25519 session key."
3854
3864
  );
3855
3865
  }
@@ -3861,25 +3871,36 @@ var _TinyCloudNode = class _TinyCloudNode {
3861
3871
  ];
3862
3872
  const hasPersistedProof = proofValues.every((value) => value !== void 0);
3863
3873
  if (!hasPersistedProof && (proofValues.some((value) => value !== void 0) || sessionData.expiresAt !== void 0)) {
3864
- throw new Error("Persisted session authority metadata is incomplete.");
3874
+ throw new InvalidRestoredSessionError("Persisted session authority metadata is incomplete.");
3875
+ }
3876
+ let restoredAddress;
3877
+ try {
3878
+ restoredAddress = hasPersistedProof ? (0, import_sdk_core8.canonicalizeAddress)(sessionData.address) : void 0;
3879
+ } catch {
3880
+ throw new InvalidRestoredSessionError("Persisted session has an invalid wallet address.");
3865
3881
  }
3866
- const restoredAddress = hasPersistedProof ? (0, import_sdk_core8.canonicalizeAddress)(sessionData.address) : void 0;
3867
3882
  let stagedSessionExpiry = /* @__PURE__ */ new Date(0);
3868
3883
  let stagedRecap = [];
3869
3884
  if (hasPersistedProof) {
3870
3885
  if (typeof this.wasmBindings.validatePersistedSession !== "function") {
3871
3886
  throw new UnsupportedSessionRestoreError("it cannot verify persisted SIWE authority");
3872
3887
  }
3873
- const verified = this.wasmBindings.validatePersistedSession({
3874
- delegationHeader: sessionData.delegationHeader,
3875
- delegationCid: sessionData.delegationCid,
3876
- spaceId: sessionData.spaceId,
3877
- jwk: stagedJwk,
3878
- address: restoredAddress,
3879
- chainId: sessionData.chainId,
3880
- siwe: sessionData.siwe,
3881
- signature: sessionData.signature
3882
- });
3888
+ const verified = (() => {
3889
+ try {
3890
+ return this.wasmBindings.validatePersistedSession({
3891
+ delegationHeader: sessionData.delegationHeader,
3892
+ delegationCid: sessionData.delegationCid,
3893
+ spaceId: sessionData.spaceId,
3894
+ jwk: stagedJwk,
3895
+ address: restoredAddress,
3896
+ chainId: sessionData.chainId,
3897
+ siwe: sessionData.siwe,
3898
+ signature: sessionData.signature
3899
+ });
3900
+ } catch (error) {
3901
+ throw new InvalidRestoredSessionError(error instanceof Error ? error.message : String(error));
3902
+ }
3903
+ })();
3883
3904
  const exactRecap = verified.verifiedRecap;
3884
3905
  if (!Array.isArray(exactRecap) || !exactRecap.every(
3885
3906
  (entry) => entry !== null && typeof entry === "object" && typeof entry.service === "string" && typeof entry.space === "string" && typeof entry.path === "string" && Array.isArray(entry.actions) && entry.actions.every((action) => typeof action === "string") && Array.isArray(entry.caveats) && entry.caveats.every(
@@ -3900,7 +3921,7 @@ var _TinyCloudNode = class _TinyCloudNode {
3900
3921
  const signedExpiry = verified.expiresAt === void 0 ? void 0 : persistedExpiry(verified.expiresAt);
3901
3922
  const persistedPolicyExpiry = sessionData.expiresAt === void 0 ? void 0 : persistedExpiry(sessionData.expiresAt);
3902
3923
  if (signedExpiry && persistedPolicyExpiry && !sameInstant(signedExpiry, persistedPolicyExpiry)) {
3903
- throw new Error("Persisted session expiry does not match its signed SIWE authority.");
3924
+ throw new InvalidRestoredSessionError("Persisted session expiry does not match its signed SIWE authority.");
3904
3925
  }
3905
3926
  stagedSessionExpiry = signedExpiry ?? persistedPolicyExpiry ?? persistedExpiry(void 0);
3906
3927
  }
@@ -4093,7 +4114,7 @@ var _TinyCloudNode = class _TinyCloudNode {
4093
4114
  const delegations = input.recap.map((entry) => ({
4094
4115
  cid: session.delegationCid,
4095
4116
  delegateDID: session.verificationMethod,
4096
- spaceId: entry.space,
4117
+ spaceId: this.spaceIdsEqual(entry.space, session.spaceId) ? session.spaceId : entry.space,
4097
4118
  path: entry.path,
4098
4119
  actions: [...entry.actions],
4099
4120
  caveats: cloneRecapCaveats(entry.caveats),
@@ -6863,21 +6884,15 @@ var _TinyCloudNode = class _TinyCloudNode {
6863
6884
  }
6864
6885
  return granted.spaceId !== void 0 && requested.spaceId !== void 0 && this.spaceIdsEqual(granted.spaceId, requested.spaceId) && this.pathContains(granted.path, requested.path);
6865
6886
  }
6866
- // Space IDs are `tinycloud:pkh:eip155:<chain>:<0xADDR>:<name>`. The embedded
6867
- // EIP-155 address is case-insensitive, but the CLI canonicalizes it to
6868
- // lowercase when building a space URI while stored runtime delegations keep
6869
- // the EIP-55 checksummed form — so a byte-for-byte compare spuriously rejects
6870
- // an otherwise-valid grant. Lowercase ONLY the `eip155:<chain>:0x<addr>`
6871
- // segment and leave everything else (crucially the case-sensitive space NAME)
6872
- // byte-exact. Mirrors the CLI's `normalizeSpaceForCompare` (OPENKEY_SCOPE_MISMATCH fix).
6887
+ // Space IDs are `tinycloud:pkh:eip155:<chain>:<0xADDR>:<name>`. Compare
6888
+ // only the embedded EIP-155 address without case sensitivity; chain, name,
6889
+ // and all non-PKH space identifiers remain byte-exact.
6873
6890
  spaceIdsEqual(a, b) {
6874
6891
  return this.normalizeSpaceAddress(a) === this.normalizeSpaceAddress(b);
6875
6892
  }
6876
6893
  normalizeSpaceAddress(space) {
6877
- return space.replace(
6878
- /(eip155:\d+:)(0x[0-9a-fA-F]{40})/,
6879
- (_match, prefix, addr) => prefix + addr.toLowerCase()
6880
- );
6894
+ const match = /^(tinycloud:pkh:eip155:\d+:)(0x[0-9a-fA-F]{40})(:.+)$/.exec(space);
6895
+ return match === null ? space : `${match[1]}${match[2].toLowerCase()}${match[3]}`;
6881
6896
  }
6882
6897
  actionContains(grantedAction, requestedAction) {
6883
6898
  if (grantedAction === requestedAction) {
@@ -7757,6 +7772,7 @@ var import_sdk_core21 = require("@tinycloud/sdk-core");
7757
7772
  DuckDbService,
7758
7773
  FileSessionStorage,
7759
7774
  IdentityParseError,
7775
+ InvalidRestoredSessionError,
7760
7776
  KVService,
7761
7777
  ManifestValidationError,
7762
7778
  MemorySessionStorage,