@tinycloud/node-sdk 3.8.0-beta.9 → 3.8.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-jPL2UqH5.d.ts → TinyCloudNode-DaD5vJhL.d.cts} +38 -5
  3. package/dist/{TinyCloudNode-C0LgPzzJ.d.cts → TinyCloudNode-k3TbBwwj.d.ts} +38 -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-C_fWaxAu.d.ts} +1 -1
  7. package/dist/{authority-Dkhr6n-f.d.cts → authority-DJdbZM6k.d.cts} +1 -1
  8. package/dist/core.cjs +238 -29
  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 +239 -30
  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 +188 -29
  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 +193 -31
  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
package/dist/core.cjs CHANGED
@@ -58,6 +58,7 @@ __export(core_exports, {
58
58
  PermissionNotInManifestError: () => import_sdk_core14.PermissionNotInManifestError,
59
59
  PrefixedKVService: () => import_sdk_core15.PrefixedKVService,
60
60
  ProtocolMismatchError: () => import_sdk_core22.ProtocolMismatchError,
61
+ RuntimeDelegationRejectedError: () => RuntimeDelegationRejectedError,
61
62
  SECRET_NAME_RE: () => import_sdk_core18.SECRET_NAME_RE,
62
63
  SQLAction: () => import_sdk_core16.SQLAction,
63
64
  SQLService: () => import_sdk_core16.SQLService,
@@ -80,6 +81,7 @@ __export(core_exports, {
80
81
  VersionCheckError: () => import_sdk_core22.VersionCheckError,
81
82
  WasmKeyProvider: () => WasmKeyProvider,
82
83
  activateCompactRuntimeDelegation: () => activateCompactRuntimeDelegation,
84
+ activateValidatedRuntimeDelegation: () => activateValidatedRuntimeDelegation,
83
85
  addressStorageKey: () => import_sdk_core13.addressStorageKey,
84
86
  buildSpaceUri: () => import_sdk_core21.buildSpaceUri,
85
87
  canonicalizeAddress: () => import_sdk_core13.canonicalizeAddress,
@@ -109,6 +111,7 @@ __export(core_exports, {
109
111
  getNodeReplicationLoaders: () => getNodeReplicationLoaders,
110
112
  getTinyCloudDebugLogs: () => import_sdk_core13.getTinyCloudDebugLogs,
111
113
  installTinyCloudDebugGlobals: () => import_sdk_core13.installTinyCloudDebugGlobals,
114
+ isAppKeyHostBound: () => isAppKeyHostBound,
112
115
  isCapabilitySubset: () => import_sdk_core14.isCapabilitySubset,
113
116
  isEvmAddress: () => import_sdk_core13.isEvmAddress,
114
117
  loadManifest: () => import_sdk_core14.loadManifest,
@@ -130,7 +133,8 @@ __export(core_exports, {
130
133
  resourceCapabilitiesToSpaceAbilitiesMap: () => import_sdk_core14.resourceCapabilitiesToSpaceAbilitiesMap,
131
134
  serializeDelegation: () => serializeDelegation,
132
135
  tinyCloudDebugLogger: () => import_sdk_core13.tinyCloudDebugLogger,
133
- validateManifest: () => import_sdk_core14.validateManifest
136
+ validateManifest: () => import_sdk_core14.validateManifest,
137
+ wireOpenKeyAuthorize: () => wireOpenKeyAuthorize
134
138
  });
135
139
  module.exports = __toCommonJS(core_exports);
136
140
  var import_sdk_core12 = require("@tinycloud/sdk-core");
@@ -371,6 +375,18 @@ function appKeyHostBinding(domain, appId) {
371
375
  const reversed = labels.reverse().join(".");
372
376
  return appId === reversed || appId.startsWith(`${reversed}.`);
373
377
  }
378
+ function isAppKeyHostBound(keysAppId, origin) {
379
+ if (typeof origin === "string" && !origin.includes("://")) {
380
+ return appKeyHostBinding(origin, keysAppId);
381
+ }
382
+ let url;
383
+ try {
384
+ url = typeof origin === "string" ? new URL(origin) : origin;
385
+ } catch {
386
+ return false;
387
+ }
388
+ return appKeyHostBinding(url.host, keysAppId);
389
+ }
374
390
 
375
391
  // src/replication/authority-sign-in.ts
376
392
  var import_sdk_core2 = require("@tinycloud/sdk-core");
@@ -502,6 +518,7 @@ function cloneAbilitiesMap(actions) {
502
518
  var NodeUserAuthorization = class {
503
519
  constructor(config) {
504
520
  this.activeSessionKeyId = "default";
521
+ this.preparedSessionCounter = 0;
505
522
  /** Incremented by resetSession; a sign-in started earlier publishes nothing. */
506
523
  this.sessionGeneration = 0;
507
524
  /**
@@ -1084,7 +1101,8 @@ var NodeUserAuthorization = class {
1084
1101
  return true;
1085
1102
  }
1086
1103
  const parsed = entry.path.includes("/") ? (0, import_resource.parseEncryptionResource)(entry.path) : { ...(0, import_sdk_services2.parseNetworkId)(entry.path), kind: "network" };
1087
- if (parsed.kind !== "network") {
1104
+ const sharePrefix = parsed.kind === "prefix" && parsed.network === "default" && parsed.prefix === "share" && entry.actions.length === 1 && entry.actions[0] === DECRYPT_ACTION && didPrincipalMatches(parsed.ownerDid, currentDid);
1105
+ if (parsed.kind !== "network" && !sharePrefix) {
1088
1106
  throw new import_sdk_core5.ManifestValidationError("named keys go in manifest.keys");
1089
1107
  }
1090
1108
  for (const action of entry.actions) {
@@ -1127,8 +1145,7 @@ var NodeUserAuthorization = class {
1127
1145
  /**
1128
1146
  * Build SIWE overrides from the top-level nonce and siweConfig.
1129
1147
  * - Top-level `nonce` is seeded first so `siweConfig.nonce` wins if both are set.
1130
- * - statement is prepended to the default statement
1131
- * - resources are appended to the default resources
1148
+ * - resources are inserted after WASM preparation, before the final ReCap
1132
1149
  * - uri triggers a warning (overwriting delegation target)
1133
1150
  * - all other fields override directly
1134
1151
  * - per-call nonce overrides siweConfig.nonce when provided
@@ -1146,9 +1163,6 @@ var NodeUserAuthorization = class {
1146
1163
  if (statement) {
1147
1164
  overrides.statement = this.statement ? `${statement} ${this.statement}` : statement;
1148
1165
  }
1149
- if (resources && resources.length > 0) {
1150
- overrides.resources = resources;
1151
- }
1152
1166
  if (uri) {
1153
1167
  console.warn(
1154
1168
  "[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."
@@ -1160,6 +1174,29 @@ var NodeUserAuthorization = class {
1160
1174
  }
1161
1175
  return overrides;
1162
1176
  }
1177
+ prepareSessionWithResources(params) {
1178
+ const resources = this.siweConfig?.resources;
1179
+ if (resources?.some((resource) => typeof resource !== "string" || !/^urn:tinycloud:recipients:[A-Za-z0-9_-]+$/.test(resource))) {
1180
+ throw new Error("SIWE metadata resources must be base64url recipients URIs");
1181
+ }
1182
+ const prepared = this.wasm.prepareSession(params);
1183
+ if (!resources?.length) return prepared;
1184
+ const recapLines = /^- urn:recap:[^\r\n]+$/gim;
1185
+ const recaps = prepared.siwe.match(recapLines);
1186
+ const recap = recaps?.[0];
1187
+ if (recaps?.length !== 1 || !prepared.siwe.endsWith(recap)) {
1188
+ throw new Error("Prepared SIWE must end with exactly one ReCap");
1189
+ }
1190
+ const insertedLines = resources.map((resource) => `- ${resource}`);
1191
+ const siwe = prepared.siwe.slice(0, -recap.length) + insertedLines.join("\n") + "\n" + recap;
1192
+ const expectedFields = (0, import_sdk_core5.extractImmutableSiweFields)(prepared.siwe);
1193
+ expectedFields.nonRecapResources = [expectedFields.nonRecapResources, ...insertedLines].filter(Boolean).join("\n");
1194
+ const actualRecaps = siwe.match(recapLines);
1195
+ if (actualRecaps?.length !== 1 || actualRecaps[0] !== recap || (0, import_sdk_core5.diffImmutableSiweFields)(expectedFields, (0, import_sdk_core5.extractImmutableSiweFields)(siwe)).length) {
1196
+ throw new Error("SIWE metadata insertion changed the prepared message");
1197
+ }
1198
+ return { ...prepared, siwe };
1199
+ }
1163
1200
  /**
1164
1201
  * Add an extension to the authorization flow.
1165
1202
  */
@@ -1407,7 +1444,7 @@ var NodeUserAuthorization = class {
1407
1444
  spaceAbilities[spaceId] = (0, import_sdk_core5.resourceCapabilitiesToAbilitiesMap)(resources);
1408
1445
  }
1409
1446
  const abilities = spaceAbilities[options.spaceId] ?? (0, import_sdk_core5.resourceCapabilitiesToAbilitiesMap)([]);
1410
- const prepared = this.wasm.prepareSession({
1447
+ const prepared = this.prepareSessionWithResources({
1411
1448
  abilities,
1412
1449
  spaceAbilities,
1413
1450
  ...options.rawAbilities !== void 0 ? { rawAbilities: options.rawAbilities } : {},
@@ -1488,8 +1525,8 @@ var NodeUserAuthorization = class {
1488
1525
  this.assertSignInCurrent(generation);
1489
1526
  await this.refreshNamedKeyFeatureForSignIn(address, chainId);
1490
1527
  this.assertSignInCurrent(generation);
1491
- const keyId = `session-${Date.now()}`;
1492
- this.sessionManager.renameSessionKeyId(this.activeSessionKeyId, keyId);
1528
+ const keyId = `session-${Date.now()}-${Math.random().toString(36).slice(2)}`;
1529
+ this.sessionManager.createSessionKey(keyId);
1493
1530
  this.activeSessionKeyId = keyId;
1494
1531
  const jwkString = this.sessionManager.jwk(keyId);
1495
1532
  if (!jwkString) {
@@ -1500,7 +1537,7 @@ var NodeUserAuthorization = class {
1500
1537
  const spaceId = capabilityPlan.spaceId;
1501
1538
  const now = /* @__PURE__ */ new Date();
1502
1539
  const expirationTime = new Date(now.getTime() + this.sessionExpirationMs);
1503
- const prepared = this.wasm.prepareSession({
1540
+ const prepared = this.prepareSessionWithResources({
1504
1541
  abilities: capabilityPlan.abilities,
1505
1542
  ...capabilityPlan.spaceAbilities !== void 0 ? { spaceAbilities: capabilityPlan.spaceAbilities } : {},
1506
1543
  ...capabilityPlan.rawAbilities !== void 0 ? { rawAbilities: capabilityPlan.rawAbilities } : {},
@@ -1635,9 +1672,8 @@ var NodeUserAuthorization = class {
1635
1672
  const address = (0, import_sdk_core5.canonicalizeAddress)(await this.signer.getAddress());
1636
1673
  const chainId = await this.signer.getChainId();
1637
1674
  await this.refreshNamedKeyFeatureForSignIn(address, chainId);
1638
- const keyId = `session-${Date.now()}`;
1639
- this.sessionManager.renameSessionKeyId(this.activeSessionKeyId, keyId);
1640
- this.activeSessionKeyId = keyId;
1675
+ const keyId = `openkey-session-${Date.now()}-${++this.preparedSessionCounter}`;
1676
+ this.sessionManager.createSessionKey(keyId);
1641
1677
  const jwkString = this.sessionManager.jwk(keyId);
1642
1678
  if (!jwkString) {
1643
1679
  throw new Error("Failed to create session key");
@@ -1647,7 +1683,7 @@ var NodeUserAuthorization = class {
1647
1683
  const spaceId = capabilityPlan.spaceId;
1648
1684
  const now = /* @__PURE__ */ new Date();
1649
1685
  const expirationTime = new Date(now.getTime() + this.sessionExpirationMs);
1650
- const prepared = this.wasm.prepareSession({
1686
+ const prepared = this.prepareSessionWithResources({
1651
1687
  abilities: capabilityPlan.abilities,
1652
1688
  ...capabilityPlan.spaceAbilities !== void 0 ? { spaceAbilities: capabilityPlan.spaceAbilities } : {},
1653
1689
  ...capabilityPlan.rawAbilities !== void 0 ? { rawAbilities: capabilityPlan.rawAbilities } : {},
@@ -1718,6 +1754,7 @@ var NodeUserAuthorization = class {
1718
1754
  await this.sessionStorage.save(address, persistedData);
1719
1755
  this._session = clientSession;
1720
1756
  this._tinyCloudSession = tinyCloudSession;
1757
+ this.activeSessionKeyId = keyId;
1721
1758
  this._address = address;
1722
1759
  this._chainId = chainId;
1723
1760
  await this.refreshNodeInfo();
@@ -1764,6 +1801,11 @@ var NodeUserAuthorization = class {
1764
1801
  * @param options Optional overrides for the OpenKey request.
1765
1802
  */
1766
1803
  async signInWithOpenKey(authorizeFn, options) {
1804
+ const pending = await this.prepareOpenKeySignIn(options);
1805
+ return this.completeOpenKeySignIn(pending, authorizeFn(pending.request), options);
1806
+ }
1807
+ /** Finish address, host and SIWE preparation before an approval click. */
1808
+ async prepareOpenKeySignIn(options) {
1767
1809
  refuseCaveated(this.getCapabilityRequest()?.manifests);
1768
1810
  if (options?.host !== void 0) {
1769
1811
  const overrideHost = options.host.trim();
@@ -1775,7 +1817,7 @@ var NodeUserAuthorization = class {
1775
1817
  const signingAddress = (0, import_sdk_core5.canonicalizeAddress)(await this.signer.getAddress());
1776
1818
  const signingChainId = await this.signer.getChainId();
1777
1819
  await this.resolveTinyCloudHostsForSignIn(signingAddress, signingChainId);
1778
- const { prepared, keyId, jwk } = await this.prepareSessionForSigning();
1820
+ const { prepared, keyId, jwk, address, chainId } = await this.prepareSessionForSigning();
1779
1821
  const presentation = this.buildPresentationEnvelope(options?.reason);
1780
1822
  const hostHint = this.primaryTinyCloudHost;
1781
1823
  const originalRequest = {
@@ -1787,12 +1829,32 @@ var NodeUserAuthorization = class {
1787
1829
  keyId: options?.openkeyKeyId,
1788
1830
  presentation
1789
1831
  };
1832
+ return {
1833
+ request: originalRequest,
1834
+ prepared,
1835
+ keyId,
1836
+ jwk,
1837
+ address,
1838
+ chainId,
1839
+ generation: this.sessionGeneration,
1840
+ createdAt: Date.now()
1841
+ };
1842
+ }
1843
+ /** Complete a prepared approval. The caller starts authorization before awaiting this method. */
1844
+ async completeOpenKeySignIn(pending, authorization, options) {
1845
+ if (Date.now() - pending.createdAt > 5 * 6e4) {
1846
+ throw new Error("Prepared OpenKey sign-in expired; prepare again");
1847
+ }
1848
+ if (pending.generation !== this.sessionGeneration) {
1849
+ throw new Error("Prepared OpenKey sign-in expired after sign-out");
1850
+ }
1851
+ const { request: originalRequest, prepared, keyId, jwk } = pending;
1790
1852
  let result;
1791
1853
  let signed;
1792
1854
  let signature;
1793
1855
  for (let attempt = 0; ; ) {
1794
1856
  try {
1795
- result ?? (result = await authorizeFn(originalRequest));
1857
+ result ?? (result = await authorization);
1796
1858
  signed = await this.verifyOpenKeyResult(result, prepared);
1797
1859
  signature = result.signature;
1798
1860
  break;
@@ -2213,6 +2275,50 @@ var NodeUserAuthorization = class {
2213
2275
  }
2214
2276
  };
2215
2277
 
2278
+ // src/authorization/openKeyBridge.ts
2279
+ function wireOpenKeyAuthorize(openkey, opts) {
2280
+ return async (input) => {
2281
+ const result = await openkey.authorizeTinyCloud({
2282
+ protocolVersion: 1,
2283
+ siwe: input.siwe,
2284
+ keyId: input.keyId,
2285
+ jwk: input.jwk,
2286
+ host: input.host,
2287
+ // Forward the presentation envelope verbatim — the OpenKey SDK
2288
+ // validates and size-bounds it before use.
2289
+ presentation: input.presentation
2290
+ }, opts);
2291
+ if (result.protocolVersion !== 1) {
2292
+ throw new Error(
2293
+ `wireOpenKeyAuthorize: OpenKey returned unsupported protocolVersion ${result.protocolVersion}`
2294
+ );
2295
+ }
2296
+ if (typeof result.signedMessage !== "string" || !result.signedMessage) {
2297
+ throw new Error(
2298
+ "wireOpenKeyAuthorize: OpenKey returned no signedMessage \u2014 cannot complete a TinyCloud session"
2299
+ );
2300
+ }
2301
+ if (!Array.isArray(result.selectedActionKeys)) {
2302
+ throw new Error(
2303
+ "wireOpenKeyAuthorize: OpenKey returned no selectedActionKeys"
2304
+ );
2305
+ }
2306
+ if (!Array.isArray(result.permissions)) {
2307
+ throw new Error(
2308
+ "wireOpenKeyAuthorize: OpenKey returned no permissions"
2309
+ );
2310
+ }
2311
+ return {
2312
+ protocolVersion: 1,
2313
+ address: result.address,
2314
+ signature: result.signature,
2315
+ signedMessage: result.signedMessage,
2316
+ selectedActionKeys: result.selectedActionKeys,
2317
+ permissions: result.permissions
2318
+ };
2319
+ };
2320
+ }
2321
+
2216
2322
  // src/recordingServiceContext.ts
2217
2323
  var import_sdk_services3 = require("@tinycloud/sdk-services");
2218
2324
  var import_requestLog = require("@tinycloud/sdk-services/telemetry/requestLog");
@@ -2854,6 +2960,7 @@ function deserializeDelegation(data) {
2854
2960
 
2855
2961
  // src/TinyCloudNode.ts
2856
2962
  var import_siwe2 = require("siwe");
2963
+ var import_share_envelope = require("@tinycloud/share-envelope");
2857
2964
  var import_sdk_core11 = require("@tinycloud/sdk-core");
2858
2965
  var import_sdk_services4 = require("@tinycloud/sdk-services");
2859
2966
  var import_requestLog2 = require("@tinycloud/sdk-services/telemetry/requestLog");
@@ -3832,6 +3939,7 @@ var _TinyCloudNode = class _TinyCloudNode {
3832
3939
  constructor(config = {}) {
3833
3940
  this.signer = null;
3834
3941
  this.auth = null;
3942
+ this.consumedOpenKeyPendings = /* @__PURE__ */ new WeakSet();
3835
3943
  this.tc = null;
3836
3944
  this._chainId = 1;
3837
3945
  this.replicaPurgeFailedHandlers = /* @__PURE__ */ new Set();
@@ -4772,6 +4880,37 @@ var _TinyCloudNode = class _TinyCloudNode {
4772
4880
  }
4773
4881
  await this.signInWith(() => this.auth.signInWithOpenKey(authorizeFn, options));
4774
4882
  }
4883
+ /** Prepare the OpenKey request before the approval click. */
4884
+ async prepareOpenKeySignIn() {
4885
+ if (!this.signer || !this.tc || !this.auth) {
4886
+ throw new Error("Cannot prepare OpenKey sign-in in session-only mode. Provide a signer in config.");
4887
+ }
4888
+ await this.signOutInFlight;
4889
+ await this.accountRegistryTail;
4890
+ await this.wasmBindings.ensureInitialized?.();
4891
+ return this.auth.prepareOpenKeySignIn();
4892
+ }
4893
+ /** Start OpenKey authorization synchronously, then complete normal session setup. */
4894
+ signInWithPreparedOpenKey(pending, authorizeFn) {
4895
+ if (!this.signer || !this.tc || !this.auth || this.signOutInFlight) {
4896
+ throw new Error("Prepared OpenKey sign-in is unavailable");
4897
+ }
4898
+ if (this.consumedOpenKeyPendings.has(pending)) {
4899
+ throw new Error("Prepared OpenKey sign-in was already used");
4900
+ }
4901
+ if (Date.now() - pending.createdAt > 5 * 6e4) {
4902
+ throw new Error("Prepared OpenKey sign-in expired; prepare again");
4903
+ }
4904
+ this.consumedOpenKeyPendings.add(pending);
4905
+ const authorization = authorizeFn(pending.request);
4906
+ void authorization.catch(() => void 0);
4907
+ return this.signInWith(() => {
4908
+ if (this._address !== pending.address || this._chainId !== pending.chainId) {
4909
+ throw new Error("OpenKey account changed after sign-in preparation");
4910
+ }
4911
+ return this.auth.completeOpenKeySignIn(pending, authorization);
4912
+ });
4913
+ }
4775
4914
  async signInWith(performSignIn) {
4776
4915
  refuseCaveated(this.auth?.capabilityRequest?.manifests);
4777
4916
  const epoch = this.sessionEpoch;
@@ -6413,6 +6552,7 @@ var _TinyCloudNode = class _TinyCloudNode {
6413
6552
  invoke: graph.invoke,
6414
6553
  invokeAny: graph.invokeAny,
6415
6554
  signOwnerRevocation: this.signer ? (cid) => this.signOwnerRevocation(cid) : void 0,
6555
+ sessionInvocationSigner: this.sessionInvocationSignerFor(input.serviceSession),
6416
6556
  fetch: graph.fetch
6417
6557
  });
6418
6558
  const keyProvider = new WasmKeyProvider({ sessionManager: input.manager });
@@ -6628,6 +6768,31 @@ var _TinyCloudNode = class _TinyCloudNode {
6628
6768
  if (session === void 0) throw new Error("Not signed in. Call signIn() first.");
6629
6769
  return signBytesWithJwk(bytes, session.jwk);
6630
6770
  }
6771
+ /**
6772
+ * Signs proofless invocations with `session`'s own did:key, for the node's
6773
+ * issued-delegation list and revocation by the delegator. The audience is
6774
+ * this Node's DID; each invocation lives 60 seconds.
6775
+ */
6776
+ sessionInvocationSignerFor(session) {
6777
+ return {
6778
+ did: () => session.verificationMethod.split("#", 1)[0],
6779
+ sign: async (attenuation) => {
6780
+ const now = Math.floor(Date.now() / 1e3);
6781
+ const invocation = await (0, import_sdk_core11.signCompactUcanAuthorization)({
6782
+ issuerDid: session.verificationMethod.split("#", 1)[0],
6783
+ audienceDid: await this.fetchNodeId(),
6784
+ attenuation,
6785
+ facts: [{}],
6786
+ proofs: [],
6787
+ notBefore: now,
6788
+ expiresAt: now + 60,
6789
+ nonce: `urn:uuid:${crypto.randomUUID()}`,
6790
+ sign: (bytes) => signBytesWithJwk(bytes, session.jwk)
6791
+ });
6792
+ return invocation.authorization;
6793
+ }
6794
+ };
6795
+ }
6631
6796
  /** Author a proofless Policy/v3 owner root with the authenticated holder key. */
6632
6797
  async createUnifiedOwnerRoot(input) {
6633
6798
  const ownerDid = this.credentialHolderDid;
@@ -7162,7 +7327,7 @@ var _TinyCloudNode = class _TinyCloudNode {
7162
7327
  graph.assertActive();
7163
7328
  const signed = await this.signRawNetworkAuthorization({
7164
7329
  targetNode: input.targetNode,
7165
- networkId: input.networkId,
7330
+ networkId: input.body.keyPath === void 0 ? input.networkId : `${input.networkId}/${input.body.keyPath}`,
7166
7331
  action: DECRYPT_ACTION2,
7167
7332
  facts: input.facts
7168
7333
  }, { graph, session });
@@ -7335,6 +7500,7 @@ var _TinyCloudNode = class _TinyCloudNode {
7335
7500
  invoke: graph.invoke,
7336
7501
  invokeAny: graph.invokeAny,
7337
7502
  signOwnerRevocation: this.signer ? (cid) => this.signOwnerRevocation(cid) : void 0,
7503
+ sessionInvocationSigner: this.sessionInvocationSignerFor(serviceSession),
7338
7504
  fetch: graph.fetch
7339
7505
  });
7340
7506
  this._spaceService = new import_sdk_core11.SpaceService({
@@ -8118,7 +8284,7 @@ var _TinyCloudNode = class _TinyCloudNode {
8118
8284
  if (!session || !Array.isArray(permissions) || permissions.length === 0) {
8119
8285
  return false;
8120
8286
  }
8121
- const expanded = this.expandPermissionEntries(permissions);
8287
+ const expanded = (0, import_sdk_core11.expandRuntimePermissionEntries)(permissions, (0, import_sdk_core11.pkhDid)(session.address, session.chainId));
8122
8288
  if (this.sessionCoversPermissionEntries(session, expanded)) {
8123
8289
  return true;
8124
8290
  }
@@ -8138,7 +8304,7 @@ var _TinyCloudNode = class _TinyCloudNode {
8138
8304
  if (!session || !Array.isArray(permissions) || permissions.length === 0) {
8139
8305
  return [];
8140
8306
  }
8141
- const expanded = this.expandPermissionEntries(permissions);
8307
+ const expanded = (0, import_sdk_core11.expandRuntimePermissionEntries)(permissions, (0, import_sdk_core11.pkhDid)(session.address, session.chainId));
8142
8308
  return this.findRuntimeGrantsForPermissionEntries(expanded, session).map(
8143
8309
  (grant) => grant.delegation
8144
8310
  );
@@ -8313,7 +8479,28 @@ var _TinyCloudNode = class _TinyCloudNode {
8313
8479
  throw new import_sdk_core11.SessionExpiredError(sessionExpiry);
8314
8480
  }
8315
8481
  }
8316
- const expanded = this.expandPermissionEntries(permissions);
8482
+ const expanded = (0, import_sdk_core11.expandRuntimePermissionEntries)(permissions, (0, import_sdk_core11.pkhDid)(session.address, session.chainId));
8483
+ const bindsShareKey = expanded.some((entry) => entry.service === import_sdk_core11.ENCRYPTION_PERMISSION_SERVICE && entry.actions.includes("tinycloud.encryption/key.create"));
8484
+ const captured = bindsShareKey ? { ...session, jwk: { ...options?.expectedSessionKey ?? session.jwk } } : session;
8485
+ const assertCapturedKey = bindsShareKey ? () => {
8486
+ const live = session.jwk;
8487
+ const key = captured.jwk;
8488
+ 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 !== key.kty || live?.crv !== key.crv || live?.x !== key.x || live?.y !== key.y || live?.d !== key.d) {
8489
+ throw new Error("Runtime permission request cancelled because the session key changed.");
8490
+ }
8491
+ } : void 0;
8492
+ const sessionKeyDid = bindsShareKey ? this.sessionDid : void 0;
8493
+ if (bindsShareKey) {
8494
+ const key = captured.jwk;
8495
+ if (key.kty !== "OKP" || key.crv !== "Ed25519" || typeof key.x !== "string") {
8496
+ throw new Error("Runtime permission session key does not match its signed identity.");
8497
+ }
8498
+ const keyDid = (0, import_share_envelope.didKeyFromEd25519PublicKey)(base64UrlDecode(key.x));
8499
+ if (!didPrincipalMatches2(keyDid, sessionKeyDid) || !didPrincipalMatches2(keyDid, captured.verificationMethod) || !didPrincipalMatches2(keyDid, new import_siwe2.SiweMessage(session.siwe).uri)) {
8500
+ throw new Error("Runtime permission session key does not match its signed identity.");
8501
+ }
8502
+ assertCapturedKey();
8503
+ }
8317
8504
  if (this.sessionCoversPermissionEntries(session, expanded)) {
8318
8505
  return [];
8319
8506
  }
@@ -8363,13 +8550,13 @@ var _TinyCloudNode = class _TinyCloudNode {
8363
8550
  return this.wasmBindings.prepareSession({
8364
8551
  abilities,
8365
8552
  ...rawForDelegation.length > 0 ? { rawAbilities: this.permissionsToRawAbilities(rawForDelegation) } : {},
8366
- address: this.wasmBindings.ensureEip55(session.address),
8367
- chainId: session.chainId,
8553
+ address: this.wasmBindings.ensureEip55(captured.address),
8554
+ chainId: captured.chainId,
8368
8555
  domain: this.siweDomain,
8369
8556
  issuedAt: now.toISOString(),
8370
8557
  expirationTime: expiresAt.toISOString(),
8371
8558
  spaceId,
8372
- jwk: session.jwk
8559
+ jwk: captured.jwk
8373
8560
  });
8374
8561
  } catch (error) {
8375
8562
  if (rawForDelegation.some((entry) => this.isRawRevocationPermissionEntry(entry)) && /invalid ReCap resource URI/i.test(error instanceof Error ? error.message : String(error))) {
@@ -8381,8 +8568,13 @@ var _TinyCloudNode = class _TinyCloudNode {
8381
8568
  throw error;
8382
8569
  }
8383
8570
  })();
8571
+ if (bindsShareKey && !didPrincipalMatches2(new import_siwe2.SiweMessage(prepared.siwe).uri, sessionKeyDid)) {
8572
+ throw new Error("Prepared runtime permission targets a different session key.");
8573
+ }
8574
+ assertCapturedKey?.();
8384
8575
  const signature = await this.signer.signMessage(prepared.siwe);
8385
8576
  graph.assertActive();
8577
+ assertCapturedKey?.();
8386
8578
  const delegatedSession = this.wasmBindings.completeSessionSetup({
8387
8579
  ...prepared,
8388
8580
  signature
@@ -8411,18 +8603,19 @@ var _TinyCloudNode = class _TinyCloudNode {
8411
8603
  delegatedSession,
8412
8604
  delegatedEntries,
8413
8605
  spaceId,
8414
- session,
8606
+ captured,
8415
8607
  expiresAt,
8416
8608
  { siwe: prepared.siwe, signature }
8417
8609
  );
8418
8610
  graph.assertActive();
8611
+ assertCapturedKey?.();
8419
8612
  this.runtimePermissionGrants.push({
8420
8613
  session: {
8421
8614
  delegationHeader: delegatedSession.delegationHeader,
8422
8615
  delegationCid: delegatedSession.delegationCid,
8423
8616
  spaceId,
8424
- verificationMethod: session.verificationMethod,
8425
- jwk: session.jwk
8617
+ verificationMethod: captured.verificationMethod,
8618
+ jwk: captured.jwk
8426
8619
  },
8427
8620
  delegation,
8428
8621
  operations: this.permissionOperations(delegatedEntries, spaceId),
@@ -8751,7 +8944,19 @@ var _TinyCloudNode = class _TinyCloudNode {
8751
8944
  "delegateTo requires a non-empty permissions array"
8752
8945
  );
8753
8946
  }
8754
- const expandedEntries = this.expandPermissionEntries(permissions);
8947
+ const expandedEntries = (0, import_sdk_core11.expandDelegationPermissionEntries)(permissions);
8948
+ const namedKeyEntries = expandedEntries.filter((entry) => entry.service === import_sdk_core11.ENCRYPTION_PERMISSION_SERVICE && entry.path.includes("/"));
8949
+ if (namedKeyEntries.length > 0) {
8950
+ if (expandedEntries.some((entry) => entry.service === import_sdk_core11.ENCRYPTION_PERMISSION_SERVICE && !entry.path.includes("/"))) {
8951
+ throw new import_sdk_core11.ManifestValidationError("named-key delegation cannot include bare-network permissions");
8952
+ }
8953
+ if (options?.forceWalletSign) {
8954
+ throw new import_sdk_core11.ManifestValidationError("named-key delegation requires a signed session grant");
8955
+ }
8956
+ const granted = this.projectSignedRecapCapabilities(session.siwe);
8957
+ const { subset, missing } = this.signedCapabilitySubset(namedKeyEntries, granted);
8958
+ if (!subset) throw new import_sdk_core11.PermissionNotInManifestError(missing, granted);
8959
+ }
8755
8960
  const now = /* @__PURE__ */ new Date();
8756
8961
  const expiryMs = resolveExpiryMs(options?.expiry);
8757
8962
  const expirationTime = new Date(now.getTime() + expiryMs);
@@ -10167,6 +10372,7 @@ var import_sdk_core23 = require("@tinycloud/sdk-core");
10167
10372
  PermissionNotInManifestError,
10168
10373
  PrefixedKVService,
10169
10374
  ProtocolMismatchError,
10375
+ RuntimeDelegationRejectedError,
10170
10376
  SECRET_NAME_RE,
10171
10377
  SQLAction,
10172
10378
  SQLService,
@@ -10189,6 +10395,7 @@ var import_sdk_core23 = require("@tinycloud/sdk-core");
10189
10395
  VersionCheckError,
10190
10396
  WasmKeyProvider,
10191
10397
  activateCompactRuntimeDelegation,
10398
+ activateValidatedRuntimeDelegation,
10192
10399
  addressStorageKey,
10193
10400
  buildSpaceUri,
10194
10401
  canonicalizeAddress,
@@ -10218,6 +10425,7 @@ var import_sdk_core23 = require("@tinycloud/sdk-core");
10218
10425
  getNodeReplicationLoaders,
10219
10426
  getTinyCloudDebugLogs,
10220
10427
  installTinyCloudDebugGlobals,
10428
+ isAppKeyHostBound,
10221
10429
  isCapabilitySubset,
10222
10430
  isEvmAddress,
10223
10431
  loadManifest,
@@ -10239,6 +10447,7 @@ var import_sdk_core23 = require("@tinycloud/sdk-core");
10239
10447
  resourceCapabilitiesToSpaceAbilitiesMap,
10240
10448
  serializeDelegation,
10241
10449
  tinyCloudDebugLogger,
10242
- validateManifest
10450
+ validateManifest,
10451
+ wireOpenKeyAuthorize
10243
10452
  });
10244
10453
  //# sourceMappingURL=core.cjs.map