@tinycloud/node-sdk 3.8.0-beta.9 → 3.8.1-beta.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 (36) hide show
  1. package/README.md +6 -0
  2. package/dist/{TinyCloudNode-C0LgPzzJ.d.cts → TinyCloudNode-BhWBbCay.d.cts} +50 -5
  3. package/dist/{TinyCloudNode-jPL2UqH5.d.ts → TinyCloudNode-BjJJIifr.d.ts} +50 -5
  4. package/dist/{WasmKeyProvider-5Ee7fcAw.d.cts → WasmKeyProvider-BKCPRC-c.d.cts} +21 -1
  5. package/dist/{WasmKeyProvider-5Ee7fcAw.d.ts → WasmKeyProvider-BKCPRC-c.d.ts} +21 -1
  6. package/dist/{authority-DvHTgPC4.d.ts → authority-BzqKNzOr.d.ts} +1 -1
  7. package/dist/{authority-Dkhr6n-f.d.cts → authority-WCJA3phs.d.cts} +1 -1
  8. package/dist/core.cjs +265 -31
  9. package/dist/core.cjs.map +1 -1
  10. package/dist/core.d.cts +4 -4
  11. package/dist/core.d.ts +4 -4
  12. package/dist/core.js +266 -32
  13. package/dist/core.js.map +1 -1
  14. package/dist/credentials-core.d.cts +1 -1
  15. package/dist/credentials-core.d.ts +1 -1
  16. package/dist/credentials.d.cts +1 -1
  17. package/dist/credentials.d.ts +1 -1
  18. package/dist/{delegation-0LKZkmP2.d.cts → delegation-Ckc3UETl.d.cts} +1 -1
  19. package/dist/{delegation-0LKZkmP2.d.ts → delegation-Ckc3UETl.d.ts} +1 -1
  20. package/dist/encryption-keys.d.cts +2 -2
  21. package/dist/encryption-keys.d.ts +2 -2
  22. package/dist/index.cjs +215 -31
  23. package/dist/index.cjs.map +1 -1
  24. package/dist/index.d.cts +3 -3
  25. package/dist/index.d.ts +3 -3
  26. package/dist/index.js +220 -33
  27. package/dist/index.js.map +1 -1
  28. package/dist/replication/authority.d.cts +3 -3
  29. package/dist/replication/authority.d.ts +3 -3
  30. package/dist/share-receive.cjs +775 -0
  31. package/dist/share-receive.cjs.map +1 -0
  32. package/dist/share-receive.d.cts +32 -0
  33. package/dist/share-receive.d.ts +32 -0
  34. package/dist/share-receive.js +777 -0
  35. package/dist/share-receive.js.map +1 -0
  36. package/package.json +11 -4
@@ -1,5 +1,5 @@
1
1
  import { CredentialFlowDescriptor, CredentialRequirement, CredentialHolderBinding, IssuedCredentialEnvelope, CredentialIssuerMetadata, ClientSession, IKVService, StoredCredentialRecord, VerifiedCredential, CredentialProgressEvent, CredentialStorageReceipt, UnifiedPolicyV2, UnifiedPolicyCapability, PolicyCredentialAdmissionV3 } from '@tinycloud/sdk-core';
2
- import { V as ValidatedRuntimeDelegation } from './delegation-0LKZkmP2.cjs';
2
+ import { V as ValidatedRuntimeDelegation } from './delegation-Ckc3UETl.cjs';
3
3
 
4
4
  interface CredentialClient {
5
5
  readonly sessionDid: string;
@@ -1,5 +1,5 @@
1
1
  import { CredentialFlowDescriptor, CredentialRequirement, CredentialHolderBinding, IssuedCredentialEnvelope, CredentialIssuerMetadata, ClientSession, IKVService, StoredCredentialRecord, VerifiedCredential, CredentialProgressEvent, CredentialStorageReceipt, UnifiedPolicyV2, UnifiedPolicyCapability, PolicyCredentialAdmissionV3 } from '@tinycloud/sdk-core';
2
- import { V as ValidatedRuntimeDelegation } from './delegation-0LKZkmP2.js';
2
+ import { V as ValidatedRuntimeDelegation } from './delegation-Ckc3UETl.js';
3
3
 
4
4
  interface CredentialClient {
5
5
  readonly sessionDid: string;
@@ -1,4 +1,4 @@
1
1
  export { CredentialAcquisitionTheme, CredentialAcquisitionTransport, CredentialBrowserInteractionAdapter, CredentialClient, CredentialInlineInteractionAdapter, CredentialInputRequest, CredentialInteractionAdapter, CredentialInteractionKind, CredentialInteractionSurface, CredentialProofSubject, CredentialRedirectResumeState, CredentialRedirectStore, CredentialRequestState, CredentialSigningAdapter, CredentialsAcquireOptions, CredentialsEnsureOptions, CredentialsEnsureResult, CredentialsOperationOptions, CredentialsPolicyAdmissionOptions, CredentialsPolicyAdmissionResult, HolderSignatureKey, InlineCredentialProofHandler, InlineCredentialProofRequest, OpenCredentialsHttpTransport, PrimitiveStepHandler, PrimitiveStepResult, ReceiverCredentialCustody, interpretCredentialFlow, mailboxSubject } from './credentials-core.cjs';
2
2
  export { D as DEFAULT_EMAIL_PROOF_PROFILE, E as EMAIL_PROOF_CREDENTIAL_TYPE, a as EMAIL_PROOF_PENDING_MAX_MS, b as EmailProofAcquireInput, c as EmailProofAcquisition, d as EmailProofError, e as EmailProofErrorCode, f as EmailProofOptions, g as EmailProofPending, h as EmailProofPendingStore, i as EmailProofProfileId, j as EmailProofRequestInput, k as EmailProofResult, l as EmailProofStep, H as HolderAlgorithm, m as HolderSigner, S as StoredEmailProofInput, n as StoredEmailProofRecord, o as acquireEmailProof, p as completeEmailProof, q as createEd25519HolderSigner, r as createMemoryEmailProofPendingStore, s as emailProofRequirement, t as requestEmailProofCode, v as verifyStoredEmailProof } from './email-proof-GXXQhIff.cjs';
3
3
  import '@tinycloud/sdk-core';
4
- import './delegation-0LKZkmP2.cjs';
4
+ import './delegation-Ckc3UETl.cjs';
@@ -1,4 +1,4 @@
1
1
  export { CredentialAcquisitionTheme, CredentialAcquisitionTransport, CredentialBrowserInteractionAdapter, CredentialClient, CredentialInlineInteractionAdapter, CredentialInputRequest, CredentialInteractionAdapter, CredentialInteractionKind, CredentialInteractionSurface, CredentialProofSubject, CredentialRedirectResumeState, CredentialRedirectStore, CredentialRequestState, CredentialSigningAdapter, CredentialsAcquireOptions, CredentialsEnsureOptions, CredentialsEnsureResult, CredentialsOperationOptions, CredentialsPolicyAdmissionOptions, CredentialsPolicyAdmissionResult, HolderSignatureKey, InlineCredentialProofHandler, InlineCredentialProofRequest, OpenCredentialsHttpTransport, PrimitiveStepHandler, PrimitiveStepResult, ReceiverCredentialCustody, interpretCredentialFlow, mailboxSubject } from './credentials-core.js';
2
2
  export { D as DEFAULT_EMAIL_PROOF_PROFILE, E as EMAIL_PROOF_CREDENTIAL_TYPE, a as EMAIL_PROOF_PENDING_MAX_MS, b as EmailProofAcquireInput, c as EmailProofAcquisition, d as EmailProofError, e as EmailProofErrorCode, f as EmailProofOptions, g as EmailProofPending, h as EmailProofPendingStore, i as EmailProofProfileId, j as EmailProofRequestInput, k as EmailProofResult, l as EmailProofStep, H as HolderAlgorithm, m as HolderSigner, S as StoredEmailProofInput, n as StoredEmailProofRecord, o as acquireEmailProof, p as completeEmailProof, q as createEd25519HolderSigner, r as createMemoryEmailProofPendingStore, s as emailProofRequirement, t as requestEmailProofCode, v as verifyStoredEmailProof } from './email-proof-GXXQhIff.js';
3
3
  import '@tinycloud/sdk-core';
4
- import './delegation-0LKZkmP2.js';
4
+ import './delegation-Ckc3UETl.js';
@@ -248,4 +248,4 @@ declare function serializeDelegation(delegation: PortableDelegation): string;
248
248
  */
249
249
  declare function deserializeDelegation(data: string): PortableDelegation;
250
250
 
251
- export { type AuthDelegationArtifact as A, type CompactRuntimeDelegationInput as C, type DelegationAuthority as D, type PortableDelegation as P, RUNTIME_DELEGATION_REJECTIONS as R, type SessionGrantProof as S, type ValidatedRuntimeDelegation as V, activateCompactRuntimeDelegation as a, type AuthRequestArtifact as b, type RuntimeDelegationActivator as c, deserializeDelegation as d, RuntimeDelegationRejectedError as e, type RuntimeDelegationRejection as f, type VerifiedSessionGrant as g, activateValidatedRuntimeDelegation as h, grantAuthRequest as i, signedCompactUcanExpiry as j, siweRuntimeDelegation as k, serializeDelegation as s };
251
+ export { type AuthDelegationArtifact as A, type CompactRuntimeDelegationInput as C, type DelegationAuthority as D, type PortableDelegation as P, RuntimeDelegationRejectedError as R, type SessionGrantProof as S, type ValidatedRuntimeDelegation as V, type RuntimeDelegationRejection as a, activateCompactRuntimeDelegation as b, activateValidatedRuntimeDelegation as c, deserializeDelegation as d, type AuthRequestArtifact as e, RUNTIME_DELEGATION_REJECTIONS as f, type RuntimeDelegationActivator as g, type VerifiedSessionGrant as h, grantAuthRequest as i, signedCompactUcanExpiry as j, siweRuntimeDelegation as k, serializeDelegation as s };
@@ -248,4 +248,4 @@ declare function serializeDelegation(delegation: PortableDelegation): string;
248
248
  */
249
249
  declare function deserializeDelegation(data: string): PortableDelegation;
250
250
 
251
- export { type AuthDelegationArtifact as A, type CompactRuntimeDelegationInput as C, type DelegationAuthority as D, type PortableDelegation as P, RUNTIME_DELEGATION_REJECTIONS as R, type SessionGrantProof as S, type ValidatedRuntimeDelegation as V, activateCompactRuntimeDelegation as a, type AuthRequestArtifact as b, type RuntimeDelegationActivator as c, deserializeDelegation as d, RuntimeDelegationRejectedError as e, type RuntimeDelegationRejection as f, type VerifiedSessionGrant as g, activateValidatedRuntimeDelegation as h, grantAuthRequest as i, signedCompactUcanExpiry as j, siweRuntimeDelegation as k, serializeDelegation as s };
251
+ export { type AuthDelegationArtifact as A, type CompactRuntimeDelegationInput as C, type DelegationAuthority as D, type PortableDelegation as P, RuntimeDelegationRejectedError as R, type SessionGrantProof as S, type ValidatedRuntimeDelegation as V, type RuntimeDelegationRejection as a, activateCompactRuntimeDelegation as b, activateValidatedRuntimeDelegation as c, deserializeDelegation as d, type AuthRequestArtifact as e, RUNTIME_DELEGATION_REJECTIONS as f, type RuntimeDelegationActivator as g, type VerifiedSessionGrant as h, grantAuthRequest as i, signedCompactUcanExpiry as j, siweRuntimeDelegation as k, serializeDelegation as s };
@@ -1,11 +1,11 @@
1
1
  import { NamedKeyClient } from '@tinycloud/sdk-services/encryption/named-keys';
2
2
  export { DecryptManyResult, KeyCallOptions, KeyDescriptor, KeyEncryptOptions, NamedKeyClient, NamedKeyEnvelope, NamedKeyError, NamedKeyErrorCode, PublicKeyDescriptor, buildKeyAdminFacts, buildKeyDescribeFacts } from '@tinycloud/sdk-services/encryption/named-keys';
3
- import { T as TinyCloudNode } from './TinyCloudNode-C0LgPzzJ.cjs';
3
+ import { T as TinyCloudNode } from './TinyCloudNode-BhWBbCay.cjs';
4
4
  import '@tinycloud/sdk-core';
5
5
  import '@tinycloud/sdk-services/kv/replication';
6
6
  import '@tinycloud/sdk-services';
7
7
  import 'events';
8
- import './delegation-0LKZkmP2.cjs';
8
+ import './delegation-Ckc3UETl.cjs';
9
9
 
10
10
  /**
11
11
  * Named encryption keys for a signed-in {@link TinyCloudNode}.
@@ -1,11 +1,11 @@
1
1
  import { NamedKeyClient } from '@tinycloud/sdk-services/encryption/named-keys';
2
2
  export { DecryptManyResult, KeyCallOptions, KeyDescriptor, KeyEncryptOptions, NamedKeyClient, NamedKeyEnvelope, NamedKeyError, NamedKeyErrorCode, PublicKeyDescriptor, buildKeyAdminFacts, buildKeyDescribeFacts } from '@tinycloud/sdk-services/encryption/named-keys';
3
- import { T as TinyCloudNode } from './TinyCloudNode-jPL2UqH5.js';
3
+ import { T as TinyCloudNode } from './TinyCloudNode-BjJJIifr.js';
4
4
  import '@tinycloud/sdk-core';
5
5
  import '@tinycloud/sdk-services/kv/replication';
6
6
  import '@tinycloud/sdk-services';
7
7
  import 'events';
8
- import './delegation-0LKZkmP2.js';
8
+ import './delegation-Ckc3UETl.js';
9
9
 
10
10
  /**
11
11
  * Named encryption keys for a signed-in {@link TinyCloudNode}.
package/dist/index.cjs CHANGED
@@ -17968,6 +17968,7 @@ __export(src_exports, {
17968
17968
  hexDecode: () => import_sdk_core22.hexDecode,
17969
17969
  hexEncode: () => import_sdk_core22.hexEncode,
17970
17970
  installTinyCloudDebugGlobals: () => import_sdk_core16.installTinyCloudDebugGlobals,
17971
+ isAppKeyHostBound: () => isAppKeyHostBound,
17971
17972
  isCapabilitySubset: () => import_sdk_core17.isCapabilitySubset,
17972
17973
  isEvmAddress: () => import_sdk_core16.isEvmAddress,
17973
17974
  isNetworkId: () => import_sdk_core22.isNetworkId,
@@ -18813,6 +18814,7 @@ function deserializeDelegation(data) {
18813
18814
 
18814
18815
  // src/TinyCloudNode.ts
18815
18816
  var import_siwe2 = require("siwe");
18817
+ var import_share_envelope = require("@tinycloud/share-envelope");
18816
18818
 
18817
18819
  // src/replication/module-registry.ts
18818
18820
  var nodeLoaders;
@@ -18862,6 +18864,18 @@ function appKeyHostBinding(domain, appId) {
18862
18864
  const reversed = labels.reverse().join(".");
18863
18865
  return appId === reversed || appId.startsWith(`${reversed}.`);
18864
18866
  }
18867
+ function isAppKeyHostBound(keysAppId, origin) {
18868
+ if (typeof origin === "string" && !origin.includes("://")) {
18869
+ return appKeyHostBinding(origin, keysAppId);
18870
+ }
18871
+ let url;
18872
+ try {
18873
+ url = typeof origin === "string" ? new URL(origin) : origin;
18874
+ } catch {
18875
+ return false;
18876
+ }
18877
+ return appKeyHostBinding(url.host, keysAppId);
18878
+ }
18865
18879
 
18866
18880
  // src/authorization/NodeUserAuthorization.ts
18867
18881
  init_authority_sign_in();
@@ -19019,6 +19033,7 @@ function cloneAbilitiesMap(actions) {
19019
19033
  var NodeUserAuthorization = class {
19020
19034
  constructor(config) {
19021
19035
  this.activeSessionKeyId = "default";
19036
+ this.preparedSessionCounter = 0;
19022
19037
  /** Incremented by resetSession; a sign-in started earlier publishes nothing. */
19023
19038
  this.sessionGeneration = 0;
19024
19039
  /**
@@ -19601,7 +19616,8 @@ var NodeUserAuthorization = class {
19601
19616
  return true;
19602
19617
  }
19603
19618
  const parsed = entry.path.includes("/") ? (0, import_resource.parseEncryptionResource)(entry.path) : { ...(0, import_sdk_services3.parseNetworkId)(entry.path), kind: "network" };
19604
- if (parsed.kind !== "network") {
19619
+ const sharePrefix = parsed.kind === "prefix" && parsed.network === "default" && parsed.prefix === "share" && entry.actions.length === 1 && entry.actions[0] === DECRYPT_ACTION && didPrincipalMatches(parsed.ownerDid, currentDid);
19620
+ if (parsed.kind !== "network" && !sharePrefix) {
19605
19621
  throw new import_sdk_core5.ManifestValidationError("named keys go in manifest.keys");
19606
19622
  }
19607
19623
  for (const action of entry.actions) {
@@ -19644,8 +19660,7 @@ var NodeUserAuthorization = class {
19644
19660
  /**
19645
19661
  * Build SIWE overrides from the top-level nonce and siweConfig.
19646
19662
  * - Top-level `nonce` is seeded first so `siweConfig.nonce` wins if both are set.
19647
- * - statement is prepended to the default statement
19648
- * - resources are appended to the default resources
19663
+ * - resources are inserted after WASM preparation, before the final ReCap
19649
19664
  * - uri triggers a warning (overwriting delegation target)
19650
19665
  * - all other fields override directly
19651
19666
  * - per-call nonce overrides siweConfig.nonce when provided
@@ -19663,9 +19678,6 @@ var NodeUserAuthorization = class {
19663
19678
  if (statement) {
19664
19679
  overrides.statement = this.statement ? `${statement} ${this.statement}` : statement;
19665
19680
  }
19666
- if (resources && resources.length > 0) {
19667
- overrides.resources = resources;
19668
- }
19669
19681
  if (uri) {
19670
19682
  console.warn(
19671
19683
  "[tinycloud] siweConfig.uri is overwriting the delegation target URI. This may break delegation chain validation if the URI does not match the session key DID."
@@ -19677,6 +19689,29 @@ var NodeUserAuthorization = class {
19677
19689
  }
19678
19690
  return overrides;
19679
19691
  }
19692
+ prepareSessionWithResources(params) {
19693
+ const resources = this.siweConfig?.resources;
19694
+ if (resources?.some((resource) => typeof resource !== "string" || !/^urn:tinycloud:recipients:[A-Za-z0-9_-]+$/.test(resource))) {
19695
+ throw new Error("SIWE metadata resources must be base64url recipients URIs");
19696
+ }
19697
+ const prepared = this.wasm.prepareSession(params);
19698
+ if (!resources?.length) return prepared;
19699
+ const recapLines = /^- urn:recap:[^\r\n]+$/gim;
19700
+ const recaps = prepared.siwe.match(recapLines);
19701
+ const recap = recaps?.[0];
19702
+ if (recaps?.length !== 1 || !prepared.siwe.endsWith(recap)) {
19703
+ throw new Error("Prepared SIWE must end with exactly one ReCap");
19704
+ }
19705
+ const insertedLines = resources.map((resource) => `- ${resource}`);
19706
+ const siwe = prepared.siwe.slice(0, -recap.length) + insertedLines.join("\n") + "\n" + recap;
19707
+ const expectedFields = (0, import_sdk_core5.extractImmutableSiweFields)(prepared.siwe);
19708
+ expectedFields.nonRecapResources = [expectedFields.nonRecapResources, ...insertedLines].filter(Boolean).join("\n");
19709
+ const actualRecaps = siwe.match(recapLines);
19710
+ if (actualRecaps?.length !== 1 || actualRecaps[0] !== recap || (0, import_sdk_core5.diffImmutableSiweFields)(expectedFields, (0, import_sdk_core5.extractImmutableSiweFields)(siwe)).length) {
19711
+ throw new Error("SIWE metadata insertion changed the prepared message");
19712
+ }
19713
+ return { ...prepared, siwe };
19714
+ }
19680
19715
  /**
19681
19716
  * Add an extension to the authorization flow.
19682
19717
  */
@@ -19924,7 +19959,7 @@ var NodeUserAuthorization = class {
19924
19959
  spaceAbilities[spaceId] = (0, import_sdk_core5.resourceCapabilitiesToAbilitiesMap)(resources);
19925
19960
  }
19926
19961
  const abilities = spaceAbilities[options.spaceId] ?? (0, import_sdk_core5.resourceCapabilitiesToAbilitiesMap)([]);
19927
- const prepared = this.wasm.prepareSession({
19962
+ const prepared = this.prepareSessionWithResources({
19928
19963
  abilities,
19929
19964
  spaceAbilities,
19930
19965
  ...options.rawAbilities !== void 0 ? { rawAbilities: options.rawAbilities } : {},
@@ -20005,8 +20040,8 @@ var NodeUserAuthorization = class {
20005
20040
  this.assertSignInCurrent(generation);
20006
20041
  await this.refreshNamedKeyFeatureForSignIn(address, chainId);
20007
20042
  this.assertSignInCurrent(generation);
20008
- const keyId = `session-${Date.now()}`;
20009
- this.sessionManager.renameSessionKeyId(this.activeSessionKeyId, keyId);
20043
+ const keyId = `session-${Date.now()}-${Math.random().toString(36).slice(2)}`;
20044
+ this.sessionManager.createSessionKey(keyId);
20010
20045
  this.activeSessionKeyId = keyId;
20011
20046
  const jwkString = this.sessionManager.jwk(keyId);
20012
20047
  if (!jwkString) {
@@ -20017,7 +20052,7 @@ var NodeUserAuthorization = class {
20017
20052
  const spaceId = capabilityPlan.spaceId;
20018
20053
  const now = /* @__PURE__ */ new Date();
20019
20054
  const expirationTime = new Date(now.getTime() + this.sessionExpirationMs);
20020
- const prepared = this.wasm.prepareSession({
20055
+ const prepared = this.prepareSessionWithResources({
20021
20056
  abilities: capabilityPlan.abilities,
20022
20057
  ...capabilityPlan.spaceAbilities !== void 0 ? { spaceAbilities: capabilityPlan.spaceAbilities } : {},
20023
20058
  ...capabilityPlan.rawAbilities !== void 0 ? { rawAbilities: capabilityPlan.rawAbilities } : {},
@@ -20152,9 +20187,8 @@ var NodeUserAuthorization = class {
20152
20187
  const address = (0, import_sdk_core5.canonicalizeAddress)(await this.signer.getAddress());
20153
20188
  const chainId = await this.signer.getChainId();
20154
20189
  await this.refreshNamedKeyFeatureForSignIn(address, chainId);
20155
- const keyId = `session-${Date.now()}`;
20156
- this.sessionManager.renameSessionKeyId(this.activeSessionKeyId, keyId);
20157
- this.activeSessionKeyId = keyId;
20190
+ const keyId = `openkey-session-${Date.now()}-${++this.preparedSessionCounter}`;
20191
+ this.sessionManager.createSessionKey(keyId);
20158
20192
  const jwkString = this.sessionManager.jwk(keyId);
20159
20193
  if (!jwkString) {
20160
20194
  throw new Error("Failed to create session key");
@@ -20164,7 +20198,7 @@ var NodeUserAuthorization = class {
20164
20198
  const spaceId = capabilityPlan.spaceId;
20165
20199
  const now = /* @__PURE__ */ new Date();
20166
20200
  const expirationTime = new Date(now.getTime() + this.sessionExpirationMs);
20167
- const prepared = this.wasm.prepareSession({
20201
+ const prepared = this.prepareSessionWithResources({
20168
20202
  abilities: capabilityPlan.abilities,
20169
20203
  ...capabilityPlan.spaceAbilities !== void 0 ? { spaceAbilities: capabilityPlan.spaceAbilities } : {},
20170
20204
  ...capabilityPlan.rawAbilities !== void 0 ? { rawAbilities: capabilityPlan.rawAbilities } : {},
@@ -20235,6 +20269,7 @@ var NodeUserAuthorization = class {
20235
20269
  await this.sessionStorage.save(address, persistedData);
20236
20270
  this._session = clientSession;
20237
20271
  this._tinyCloudSession = tinyCloudSession;
20272
+ this.activeSessionKeyId = keyId;
20238
20273
  this._address = address;
20239
20274
  this._chainId = chainId;
20240
20275
  await this.refreshNodeInfo();
@@ -20281,6 +20316,11 @@ var NodeUserAuthorization = class {
20281
20316
  * @param options Optional overrides for the OpenKey request.
20282
20317
  */
20283
20318
  async signInWithOpenKey(authorizeFn, options) {
20319
+ const pending = await this.prepareOpenKeySignIn(options);
20320
+ return this.completeOpenKeySignIn(pending, authorizeFn(pending.request), options);
20321
+ }
20322
+ /** Finish address, host and SIWE preparation before an approval click. */
20323
+ async prepareOpenKeySignIn(options) {
20284
20324
  refuseCaveated(this.getCapabilityRequest()?.manifests);
20285
20325
  if (options?.host !== void 0) {
20286
20326
  const overrideHost = options.host.trim();
@@ -20292,7 +20332,7 @@ var NodeUserAuthorization = class {
20292
20332
  const signingAddress = (0, import_sdk_core5.canonicalizeAddress)(await this.signer.getAddress());
20293
20333
  const signingChainId = await this.signer.getChainId();
20294
20334
  await this.resolveTinyCloudHostsForSignIn(signingAddress, signingChainId);
20295
- const { prepared, keyId, jwk } = await this.prepareSessionForSigning();
20335
+ const { prepared, keyId, jwk, address, chainId } = await this.prepareSessionForSigning();
20296
20336
  const presentation = this.buildPresentationEnvelope(options?.reason);
20297
20337
  const hostHint = this.primaryTinyCloudHost;
20298
20338
  const originalRequest = {
@@ -20304,12 +20344,32 @@ var NodeUserAuthorization = class {
20304
20344
  keyId: options?.openkeyKeyId,
20305
20345
  presentation
20306
20346
  };
20347
+ return {
20348
+ request: originalRequest,
20349
+ prepared,
20350
+ keyId,
20351
+ jwk,
20352
+ address,
20353
+ chainId,
20354
+ generation: this.sessionGeneration,
20355
+ createdAt: Date.now()
20356
+ };
20357
+ }
20358
+ /** Complete a prepared approval. The caller starts authorization before awaiting this method. */
20359
+ async completeOpenKeySignIn(pending, authorization, options) {
20360
+ if (Date.now() - pending.createdAt > 5 * 6e4) {
20361
+ throw new Error("Prepared OpenKey sign-in expired; prepare again");
20362
+ }
20363
+ if (pending.generation !== this.sessionGeneration) {
20364
+ throw new Error("Prepared OpenKey sign-in expired after sign-out");
20365
+ }
20366
+ const { request: originalRequest, prepared, keyId, jwk } = pending;
20307
20367
  let result;
20308
20368
  let signed2;
20309
20369
  let signature2;
20310
20370
  for (let attempt = 0; ; ) {
20311
20371
  try {
20312
- result ?? (result = await authorizeFn(originalRequest));
20372
+ result ?? (result = await authorization);
20313
20373
  signed2 = await this.verifyOpenKeyResult(result, prepared);
20314
20374
  signature2 = result.signature;
20315
20375
  break;
@@ -21703,6 +21763,7 @@ var _TinyCloudNode = class _TinyCloudNode {
21703
21763
  constructor(config = {}) {
21704
21764
  this.signer = null;
21705
21765
  this.auth = null;
21766
+ this.consumedOpenKeyPendings = /* @__PURE__ */ new WeakSet();
21706
21767
  this.tc = null;
21707
21768
  this._chainId = 1;
21708
21769
  this.replicaPurgeFailedHandlers = /* @__PURE__ */ new Set();
@@ -22643,6 +22704,37 @@ var _TinyCloudNode = class _TinyCloudNode {
22643
22704
  }
22644
22705
  await this.signInWith(() => this.auth.signInWithOpenKey(authorizeFn, options));
22645
22706
  }
22707
+ /** Prepare the OpenKey request before the approval click. */
22708
+ async prepareOpenKeySignIn() {
22709
+ if (!this.signer || !this.tc || !this.auth) {
22710
+ throw new Error("Cannot prepare OpenKey sign-in in session-only mode. Provide a signer in config.");
22711
+ }
22712
+ await this.signOutInFlight;
22713
+ await this.accountRegistryTail;
22714
+ await this.wasmBindings.ensureInitialized?.();
22715
+ return this.auth.prepareOpenKeySignIn();
22716
+ }
22717
+ /** Start OpenKey authorization synchronously, then complete normal session setup. */
22718
+ signInWithPreparedOpenKey(pending, authorizeFn) {
22719
+ if (!this.signer || !this.tc || !this.auth || this.signOutInFlight) {
22720
+ throw new Error("Prepared OpenKey sign-in is unavailable");
22721
+ }
22722
+ if (this.consumedOpenKeyPendings.has(pending)) {
22723
+ throw new Error("Prepared OpenKey sign-in was already used");
22724
+ }
22725
+ if (Date.now() - pending.createdAt > 5 * 6e4) {
22726
+ throw new Error("Prepared OpenKey sign-in expired; prepare again");
22727
+ }
22728
+ this.consumedOpenKeyPendings.add(pending);
22729
+ const authorization = authorizeFn(pending.request);
22730
+ void authorization.catch(() => void 0);
22731
+ return this.signInWith(() => {
22732
+ if (this._address !== pending.address || this._chainId !== pending.chainId) {
22733
+ throw new Error("OpenKey account changed after sign-in preparation");
22734
+ }
22735
+ return this.auth.completeOpenKeySignIn(pending, authorization);
22736
+ });
22737
+ }
22646
22738
  async signInWith(performSignIn) {
22647
22739
  refuseCaveated(this.auth?.capabilityRequest?.manifests);
22648
22740
  const epoch = this.sessionEpoch;
@@ -24284,6 +24376,7 @@ var _TinyCloudNode = class _TinyCloudNode {
24284
24376
  invoke: graph.invoke,
24285
24377
  invokeAny: graph.invokeAny,
24286
24378
  signOwnerRevocation: this.signer ? (cid) => this.signOwnerRevocation(cid) : void 0,
24379
+ sessionInvocationSigner: this.sessionInvocationSignerFor(input.serviceSession),
24287
24380
  fetch: graph.fetch
24288
24381
  });
24289
24382
  const keyProvider = new WasmKeyProvider({ sessionManager: input.manager });
@@ -24499,6 +24592,31 @@ var _TinyCloudNode = class _TinyCloudNode {
24499
24592
  if (session === void 0) throw new Error("Not signed in. Call signIn() first.");
24500
24593
  return signBytesWithJwk(bytes, session.jwk);
24501
24594
  }
24595
+ /**
24596
+ * Signs proofless invocations with `session`'s own did:key, for the node's
24597
+ * issued-delegation list and revocation by the delegator. The audience is
24598
+ * this Node's DID; each invocation lives 60 seconds.
24599
+ */
24600
+ sessionInvocationSignerFor(session) {
24601
+ return {
24602
+ did: () => session.verificationMethod.split("#", 1)[0],
24603
+ sign: async (attenuation) => {
24604
+ const now = Math.floor(Date.now() / 1e3);
24605
+ const invocation = await (0, import_sdk_core10.signCompactUcanAuthorization)({
24606
+ issuerDid: session.verificationMethod.split("#", 1)[0],
24607
+ audienceDid: await this.fetchNodeId(),
24608
+ attenuation,
24609
+ facts: [{}],
24610
+ proofs: [],
24611
+ notBefore: now,
24612
+ expiresAt: now + 60,
24613
+ nonce: `urn:uuid:${crypto.randomUUID()}`,
24614
+ sign: (bytes) => signBytesWithJwk(bytes, session.jwk)
24615
+ });
24616
+ return invocation.authorization;
24617
+ }
24618
+ };
24619
+ }
24502
24620
  /** Author a proofless Policy/v3 owner root with the authenticated holder key. */
24503
24621
  async createUnifiedOwnerRoot(input) {
24504
24622
  const ownerDid = this.credentialHolderDid;
@@ -25033,7 +25151,7 @@ var _TinyCloudNode = class _TinyCloudNode {
25033
25151
  graph.assertActive();
25034
25152
  const signed2 = await this.signRawNetworkAuthorization({
25035
25153
  targetNode: input.targetNode,
25036
- networkId: input.networkId,
25154
+ networkId: input.body.keyPath === void 0 ? input.networkId : `${input.networkId}/${input.body.keyPath}`,
25037
25155
  action: DECRYPT_ACTION2,
25038
25156
  facts: input.facts
25039
25157
  }, { graph, session });
@@ -25206,6 +25324,7 @@ var _TinyCloudNode = class _TinyCloudNode {
25206
25324
  invoke: graph.invoke,
25207
25325
  invokeAny: graph.invokeAny,
25208
25326
  signOwnerRevocation: this.signer ? (cid) => this.signOwnerRevocation(cid) : void 0,
25327
+ sessionInvocationSigner: this.sessionInvocationSignerFor(serviceSession),
25209
25328
  fetch: graph.fetch
25210
25329
  });
25211
25330
  this._spaceService = new import_sdk_core10.SpaceService({
@@ -25989,7 +26108,7 @@ var _TinyCloudNode = class _TinyCloudNode {
25989
26108
  if (!session || !Array.isArray(permissions) || permissions.length === 0) {
25990
26109
  return false;
25991
26110
  }
25992
- const expanded = this.expandPermissionEntries(permissions);
26111
+ const expanded = (0, import_sdk_core10.expandRuntimePermissionEntries)(permissions, (0, import_sdk_core10.pkhDid)(session.address, session.chainId));
25993
26112
  if (this.sessionCoversPermissionEntries(session, expanded)) {
25994
26113
  return true;
25995
26114
  }
@@ -26009,7 +26128,7 @@ var _TinyCloudNode = class _TinyCloudNode {
26009
26128
  if (!session || !Array.isArray(permissions) || permissions.length === 0) {
26010
26129
  return [];
26011
26130
  }
26012
- const expanded = this.expandPermissionEntries(permissions);
26131
+ const expanded = (0, import_sdk_core10.expandRuntimePermissionEntries)(permissions, (0, import_sdk_core10.pkhDid)(session.address, session.chainId));
26013
26132
  return this.findRuntimeGrantsForPermissionEntries(expanded, session).map(
26014
26133
  (grant) => grant.delegation
26015
26134
  );
@@ -26184,7 +26303,28 @@ var _TinyCloudNode = class _TinyCloudNode {
26184
26303
  throw new import_sdk_core10.SessionExpiredError(sessionExpiry);
26185
26304
  }
26186
26305
  }
26187
- const expanded = this.expandPermissionEntries(permissions);
26306
+ const expanded = (0, import_sdk_core10.expandRuntimePermissionEntries)(permissions, (0, import_sdk_core10.pkhDid)(session.address, session.chainId));
26307
+ const bindsShareKey = expanded.some((entry) => entry.service === import_sdk_core10.ENCRYPTION_PERMISSION_SERVICE && entry.actions.includes("tinycloud.encryption/key.create"));
26308
+ const captured = bindsShareKey ? { ...session, jwk: { ...options?.expectedSessionKey ?? session.jwk } } : session;
26309
+ const assertCapturedKey = bindsShareKey ? () => {
26310
+ const live = session.jwk;
26311
+ const key2 = captured.jwk;
26312
+ if (this.currentTinyCloudSession() !== session || session.verificationMethod !== captured.verificationMethod || session.delegationCid !== captured.delegationCid || session.spaceId !== captured.spaceId || session.address !== captured.address || session.chainId !== captured.chainId || live?.kty !== key2.kty || live?.crv !== key2.crv || live?.x !== key2.x || live?.y !== key2.y || live?.d !== key2.d) {
26313
+ throw new Error("Runtime permission request cancelled because the session key changed.");
26314
+ }
26315
+ } : void 0;
26316
+ const sessionKeyDid = bindsShareKey ? this.sessionDid : void 0;
26317
+ if (bindsShareKey) {
26318
+ const key2 = captured.jwk;
26319
+ if (key2.kty !== "OKP" || key2.crv !== "Ed25519" || typeof key2.x !== "string") {
26320
+ throw new Error("Runtime permission session key does not match its signed identity.");
26321
+ }
26322
+ const keyDid = (0, import_share_envelope.didKeyFromEd25519PublicKey)(base64UrlDecode(key2.x));
26323
+ if (!didPrincipalMatches2(keyDid, sessionKeyDid) || !didPrincipalMatches2(keyDid, captured.verificationMethod) || !didPrincipalMatches2(keyDid, new import_siwe2.SiweMessage(session.siwe).uri)) {
26324
+ throw new Error("Runtime permission session key does not match its signed identity.");
26325
+ }
26326
+ assertCapturedKey();
26327
+ }
26188
26328
  if (this.sessionCoversPermissionEntries(session, expanded)) {
26189
26329
  return [];
26190
26330
  }
@@ -26192,7 +26332,7 @@ var _TinyCloudNode = class _TinyCloudNode {
26192
26332
  if (existingGrants.length > 0) {
26193
26333
  return existingGrants.map((grant) => grant.delegation);
26194
26334
  }
26195
- if (!this.signer) {
26335
+ if (!this.signer && options?.signMessage === void 0) {
26196
26336
  throw new Error(
26197
26337
  "grantRuntimePermissions requires wallet mode with a signer or privateKey."
26198
26338
  );
@@ -26234,13 +26374,13 @@ var _TinyCloudNode = class _TinyCloudNode {
26234
26374
  return this.wasmBindings.prepareSession({
26235
26375
  abilities,
26236
26376
  ...rawForDelegation.length > 0 ? { rawAbilities: this.permissionsToRawAbilities(rawForDelegation) } : {},
26237
- address: this.wasmBindings.ensureEip55(session.address),
26238
- chainId: session.chainId,
26377
+ address: this.wasmBindings.ensureEip55(captured.address),
26378
+ chainId: captured.chainId,
26239
26379
  domain: this.siweDomain,
26240
26380
  issuedAt: now.toISOString(),
26241
26381
  expirationTime: expiresAt.toISOString(),
26242
26382
  spaceId,
26243
- jwk: session.jwk
26383
+ jwk: captured.jwk
26244
26384
  });
26245
26385
  } catch (error) {
26246
26386
  if (rawForDelegation.some((entry) => this.isRawRevocationPermissionEntry(entry)) && /invalid ReCap resource URI/i.test(error instanceof Error ? error.message : String(error))) {
@@ -26252,8 +26392,19 @@ var _TinyCloudNode = class _TinyCloudNode {
26252
26392
  throw error;
26253
26393
  }
26254
26394
  })();
26255
- const signature2 = await this.signer.signMessage(prepared.siwe);
26395
+ if (bindsShareKey && !didPrincipalMatches2(new import_siwe2.SiweMessage(prepared.siwe).uri, sessionKeyDid)) {
26396
+ throw new Error("Prepared runtime permission targets a different session key.");
26397
+ }
26398
+ assertCapturedKey?.();
26399
+ if (options?.signMessage !== void 0) {
26400
+ this.assertRuntimeGrantMessage(prepared.siwe, session);
26401
+ }
26402
+ const signature2 = options?.signMessage !== void 0 ? await options.signMessage(prepared.siwe) : await this.signer.signMessage(prepared.siwe);
26403
+ if (options?.signMessage !== void 0 && !await (0, import_sdk_core10.verifyEip191MessageSignature)(prepared.siwe, signature2, session.address)) {
26404
+ throw new Error("The signature does not match the account that owns this session.");
26405
+ }
26256
26406
  graph.assertActive();
26407
+ assertCapturedKey?.();
26257
26408
  const delegatedSession = this.wasmBindings.completeSessionSetup({
26258
26409
  ...prepared,
26259
26410
  signature: signature2
@@ -26282,18 +26433,19 @@ var _TinyCloudNode = class _TinyCloudNode {
26282
26433
  delegatedSession,
26283
26434
  delegatedEntries,
26284
26435
  spaceId,
26285
- session,
26436
+ captured,
26286
26437
  expiresAt,
26287
26438
  { siwe: prepared.siwe, signature: signature2 }
26288
26439
  );
26289
26440
  graph.assertActive();
26441
+ assertCapturedKey?.();
26290
26442
  this.runtimePermissionGrants.push({
26291
26443
  session: {
26292
26444
  delegationHeader: delegatedSession.delegationHeader,
26293
26445
  delegationCid: delegatedSession.delegationCid,
26294
26446
  spaceId,
26295
- verificationMethod: session.verificationMethod,
26296
- jwk: session.jwk
26447
+ verificationMethod: captured.verificationMethod,
26448
+ jwk: captured.jwk
26297
26449
  },
26298
26450
  delegation,
26299
26451
  operations: this.permissionOperations(delegatedEntries, spaceId),
@@ -26622,7 +26774,19 @@ var _TinyCloudNode = class _TinyCloudNode {
26622
26774
  "delegateTo requires a non-empty permissions array"
26623
26775
  );
26624
26776
  }
26625
- const expandedEntries = this.expandPermissionEntries(permissions);
26777
+ const expandedEntries = (0, import_sdk_core10.expandDelegationPermissionEntries)(permissions);
26778
+ const namedKeyEntries = expandedEntries.filter((entry) => entry.service === import_sdk_core10.ENCRYPTION_PERMISSION_SERVICE && entry.path.includes("/"));
26779
+ if (namedKeyEntries.length > 0) {
26780
+ if (expandedEntries.some((entry) => entry.service === import_sdk_core10.ENCRYPTION_PERMISSION_SERVICE && !entry.path.includes("/"))) {
26781
+ throw new import_sdk_core10.ManifestValidationError("named-key delegation cannot include bare-network permissions");
26782
+ }
26783
+ if (options?.forceWalletSign) {
26784
+ throw new import_sdk_core10.ManifestValidationError("named-key delegation requires a signed session grant");
26785
+ }
26786
+ const granted = this.projectSignedRecapCapabilities(session.siwe);
26787
+ const { subset, missing } = this.signedCapabilitySubset(namedKeyEntries, granted);
26788
+ if (!subset) throw new import_sdk_core10.PermissionNotInManifestError(missing, granted);
26789
+ }
26626
26790
  const now = /* @__PURE__ */ new Date();
26627
26791
  const expiryMs = resolveExpiryMs(options?.expiry);
26628
26792
  const expirationTime = new Date(now.getTime() + expiryMs);
@@ -27056,6 +27220,25 @@ var _TinyCloudNode = class _TinyCloudNode {
27056
27220
  expandPermissionEntries(permissions) {
27057
27221
  return (0, import_sdk_core10.expandPermissionEntries)(permissions);
27058
27222
  }
27223
+ /**
27224
+ * Checks the SIWE text a caller-supplied signer is asked to sign: it must be in canonical form (parsing and
27225
+ * re-serializing it gives the same bytes) and name the session's account and chain. The caller then checks the
27226
+ * signature against these exact bytes.
27227
+ */
27228
+ assertRuntimeGrantMessage(siwe, session) {
27229
+ let parsed;
27230
+ try {
27231
+ parsed = new import_siwe2.SiweMessage(siwe);
27232
+ } catch {
27233
+ throw new Error("The prepared sign-in message is not a valid SIWE message.");
27234
+ }
27235
+ if (parsed.prepareMessage() !== siwe) {
27236
+ throw new Error("The prepared sign-in message is not in canonical form.");
27237
+ }
27238
+ if (parsed.chainId !== session.chainId || (0, import_sdk_core10.canonicalizeAddress)(parsed.address) !== (0, import_sdk_core10.canonicalizeAddress)(session.address)) {
27239
+ throw new Error("The prepared sign-in message is for a different account or chain than this session.");
27240
+ }
27241
+ }
27059
27242
  /**
27060
27243
  * The current WASM child-delegation APIs accept action-only maps. Refuse any
27061
27244
  * constrained branch rather than signing a broader action-only child UCAN.
@@ -28141,7 +28324,7 @@ var FileSessionStorage = class {
28141
28324
  };
28142
28325
 
28143
28326
  // src/authorization/openKeyBridge.ts
28144
- function wireOpenKeyAuthorize(openkey) {
28327
+ function wireOpenKeyAuthorize(openkey, opts) {
28145
28328
  return async (input) => {
28146
28329
  const result = await openkey.authorizeTinyCloud({
28147
28330
  protocolVersion: 1,
@@ -28152,7 +28335,7 @@ function wireOpenKeyAuthorize(openkey) {
28152
28335
  // Forward the presentation envelope verbatim — the OpenKey SDK
28153
28336
  // validates and size-bounds it before use.
28154
28337
  presentation: input.presentation
28155
- });
28338
+ }, opts);
28156
28339
  if (result.protocolVersion !== 1) {
28157
28340
  throw new Error(
28158
28341
  `wireOpenKeyAuthorize: OpenKey returned unsupported protocolVersion ${result.protocolVersion}`
@@ -30846,6 +31029,7 @@ function sqliteReplicaStorage(options) {
30846
31029
  hexDecode,
30847
31030
  hexEncode,
30848
31031
  installTinyCloudDebugGlobals,
31032
+ isAppKeyHostBound,
30849
31033
  isCapabilitySubset,
30850
31034
  isEvmAddress,
30851
31035
  isNetworkId,