@tinycloud/node-sdk 3.8.0-beta.2 → 3.8.0-beta.20

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 (44) hide show
  1. package/README.md +6 -0
  2. package/dist/{TinyCloudNode-B6VOBrCb.d.ts → TinyCloudNode-BRyeZas2.d.ts} +47 -6
  3. package/dist/{TinyCloudNode-CVO41O12.d.cts → TinyCloudNode-NrmztjDd.d.cts} +47 -6
  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-DGi1hIMK.d.ts → authority-D6JMJwor.d.ts} +1 -1
  7. package/dist/{authority-DgVV80bI.d.cts → authority-Z-reu6zL.d.cts} +1 -1
  8. package/dist/core.cjs +336 -29
  9. package/dist/core.cjs.map +1 -1
  10. package/dist/core.d.cts +5 -4
  11. package/dist/core.d.ts +5 -4
  12. package/dist/core.js +330 -24
  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 +304 -40
  23. package/dist/index.cjs.map +1 -1
  24. package/dist/index.d.cts +4 -3
  25. package/dist/index.d.ts +4 -3
  26. package/dist/index.js +293 -27
  27. package/dist/index.js.map +1 -1
  28. package/dist/replication/authority.cjs +3 -0
  29. package/dist/replication/authority.cjs.map +1 -1
  30. package/dist/replication/authority.d.cts +4 -3
  31. package/dist/replication/authority.d.ts +4 -3
  32. package/dist/replication/authority.js +3 -0
  33. package/dist/replication/authority.js.map +1 -1
  34. package/dist/replication/runtime.cjs +1 -0
  35. package/dist/replication/runtime.cjs.map +1 -1
  36. package/dist/replication/runtime.js +1 -0
  37. package/dist/replication/runtime.js.map +1 -1
  38. package/dist/share-receive.cjs +775 -0
  39. package/dist/share-receive.cjs.map +1 -0
  40. package/dist/share-receive.d.cts +32 -0
  41. package/dist/share-receive.d.ts +32 -0
  42. package/dist/share-receive.js +777 -0
  43. package/dist/share-receive.js.map +1 -0
  44. package/package.json +11 -4
package/dist/index.cjs CHANGED
@@ -17089,6 +17089,9 @@ function assertValidReplicationConfig(replication) {
17089
17089
  if (replication?.syncScope !== void 0 && replication.syncScope !== "prefixes") {
17090
17090
  throw new TypeError('replication.syncScope must be "prefixes"');
17091
17091
  }
17092
+ if (replication?.contentFetch !== void 0 && replication.contentFetch !== "eager" && replication.contentFetch !== "lazy") {
17093
+ throw new TypeError('replication.contentFetch must be "eager" or "lazy"');
17094
+ }
17092
17095
  if (replication === void 0 || !replication.enabled) return;
17093
17096
  if (replication.storage === void 0 || replication.storage === null) {
17094
17097
  throw new TypeError("replication.enabled requires replication.storage");
@@ -17143,6 +17146,7 @@ function resolvedOptions(options) {
17143
17146
  maxStalenessMs: options.maxStalenessMs ?? 12e4,
17144
17147
  staleSyncTimeoutMs: options.staleSyncTimeoutMs ?? 5e3,
17145
17148
  allowSecrets: options.allowSecrets === true,
17149
+ contentFetch: options.contentFetch ?? "eager",
17146
17150
  verify: options.verify === true
17147
17151
  };
17148
17152
  }
@@ -17964,6 +17968,7 @@ __export(src_exports, {
17964
17968
  hexDecode: () => import_sdk_core22.hexDecode,
17965
17969
  hexEncode: () => import_sdk_core22.hexEncode,
17966
17970
  installTinyCloudDebugGlobals: () => import_sdk_core16.installTinyCloudDebugGlobals,
17971
+ isAppKeyHostBound: () => isAppKeyHostBound,
17967
17972
  isCapabilitySubset: () => import_sdk_core17.isCapabilitySubset,
17968
17973
  isEvmAddress: () => import_sdk_core16.isEvmAddress,
17969
17974
  isNetworkId: () => import_sdk_core22.isNetworkId,
@@ -18824,13 +18829,54 @@ function getNodeReplicationLoaders() {
18824
18829
 
18825
18830
  // src/TinyCloudNode.ts
18826
18831
  var import_sdk_core10 = require("@tinycloud/sdk-core");
18827
- var import_sdk_services3 = require("@tinycloud/sdk-services");
18832
+ var import_sdk_services4 = require("@tinycloud/sdk-services");
18828
18833
  var import_requestLog2 = require("@tinycloud/sdk-services/telemetry/requestLog");
18834
+ var import_resource2 = require("@tinycloud/sdk-services/encryption/resource");
18829
18835
 
18830
18836
  // src/authorization/NodeUserAuthorization.ts
18831
18837
  var import_node_crypto = require("crypto");
18832
18838
  var import_siwe = require("siwe");
18833
18839
  var import_sdk_core5 = require("@tinycloud/sdk-core");
18840
+ var import_resource = require("@tinycloud/sdk-services/encryption/resource");
18841
+ var import_sdk_services3 = require("@tinycloud/sdk-services");
18842
+
18843
+ // src/authorization/appKeyHostBinding.ts
18844
+ var DOMAIN_LABEL = /^[a-z0-9](?:[a-z0-9-]{0,61}[a-z0-9])?$/;
18845
+ var IPV4 = /^\d+\.\d+\.\d+\.\d+$/;
18846
+ var APP_ID = /^[a-z0-9][a-z0-9._-]{0,63}$/;
18847
+ function appKeyHostBinding(domain, appId) {
18848
+ if (!APP_ID.test(appId)) return false;
18849
+ if (domain.endsWith(":")) return false;
18850
+ let url;
18851
+ try {
18852
+ url = new URL(`https://${domain}`);
18853
+ } catch {
18854
+ return false;
18855
+ }
18856
+ if (url.protocol !== "https:" || url.port !== "" || url.username !== "" || url.password !== "") return false;
18857
+ if (url.pathname !== "/" || url.search !== "" || url.hash !== "") return false;
18858
+ const host = url.hostname;
18859
+ if (host.startsWith("[") || host.endsWith(".") || IPV4.test(host)) return false;
18860
+ const labels = host.split(".");
18861
+ if (labels.length < 2 || labels[labels.length - 1] === "localhost") return false;
18862
+ if (!labels.every((label) => DOMAIN_LABEL.test(label))) return false;
18863
+ const reversed = labels.reverse().join(".");
18864
+ return appId === reversed || appId.startsWith(`${reversed}.`);
18865
+ }
18866
+ function isAppKeyHostBound(keysAppId, origin) {
18867
+ if (typeof origin === "string" && !origin.includes("://")) {
18868
+ return appKeyHostBinding(origin, keysAppId);
18869
+ }
18870
+ let url;
18871
+ try {
18872
+ url = typeof origin === "string" ? new URL(origin) : origin;
18873
+ } catch {
18874
+ return false;
18875
+ }
18876
+ return appKeyHostBinding(url.host, keysAppId);
18877
+ }
18878
+
18879
+ // src/authorization/NodeUserAuthorization.ts
18834
18880
  init_authority_sign_in();
18835
18881
 
18836
18882
  // src/authorization/caveatRefusal.ts
@@ -18986,6 +19032,7 @@ function cloneAbilitiesMap(actions) {
18986
19032
  var NodeUserAuthorization = class {
18987
19033
  constructor(config) {
18988
19034
  this.activeSessionKeyId = "default";
19035
+ this.preparedSessionCounter = 0;
18989
19036
  /** Incremented by resetSession; a sign-in started earlier publishes nothing. */
18990
19037
  this.sessionGeneration = 0;
18991
19038
  /**
@@ -19342,6 +19389,23 @@ var NodeUserAuthorization = class {
19342
19389
  );
19343
19390
  return this._capabilityRequest;
19344
19391
  }
19392
+ async refreshNamedKeyFeatureForSignIn(address, chainId) {
19393
+ const request = this.getCapabilityRequest();
19394
+ const siweDomain = this.siweConfig?.domain ?? this.domain;
19395
+ const hasNamedKeys = request?.manifests.some((manifest) => manifest.keys?.length && appKeyHostBinding(siweDomain, manifest.keys_app_id ?? manifest.app_id));
19396
+ if (hasNamedKeys) {
19397
+ await this.resolveTinyCloudHostsForSignIn(address, chainId);
19398
+ await this.refreshNodeInfo();
19399
+ }
19400
+ }
19401
+ /** Manifest key paths that this sign-in cannot grant. */
19402
+ get unavailableKeyPaths() {
19403
+ const request = this.getCapabilityRequest();
19404
+ const siweDomain = this.siweConfig?.domain ?? this.domain;
19405
+ return (request?.manifests ?? []).flatMap(
19406
+ (manifest) => this._nodeFeatures.includes("encryption-named-keys-v1") && appKeyHostBinding(siweDomain, manifest.keys_app_id ?? manifest.app_id) ? [] : (manifest.keys ?? []).map((entry) => "path" in entry ? entry.path : entry.prefix)
19407
+ );
19408
+ }
19345
19409
  resolveSpaceName(space, address, chainId) {
19346
19410
  if (space.startsWith("tinycloud:")) {
19347
19411
  return space;
@@ -19533,15 +19597,32 @@ var NodeUserAuthorization = class {
19533
19597
  }
19534
19598
  const rawAbilities = {};
19535
19599
  const currentDid = (0, import_sdk_core5.pkhDid)(address, chainId);
19600
+ if (this._nodeFeatures.includes("encryption-named-keys-v1")) {
19601
+ const siweDomain = this.siweConfig?.domain ?? this.domain;
19602
+ for (const manifest of request.manifests) {
19603
+ if (!appKeyHostBinding(siweDomain, manifest.keys_app_id ?? manifest.app_id)) continue;
19604
+ for (const declaration of manifest.keys ?? []) {
19605
+ const path = "path" in declaration ? declaration.path : declaration.prefix;
19606
+ const resource = `urn:tinycloud:encryption:${currentDid}:default/${path}`;
19607
+ for (const ability of declaration.abilities) {
19608
+ addRawAbility(rawAbilities, resource, `tinycloud.encryption/${ability}`);
19609
+ }
19610
+ }
19611
+ }
19612
+ }
19536
19613
  const spaceResources = request.resources.filter((entry) => {
19537
19614
  if (entry.service !== import_sdk_core5.ENCRYPTION_PERMISSION_SERVICE) {
19538
19615
  return true;
19539
19616
  }
19617
+ const parsed = entry.path.includes("/") ? (0, import_resource.parseEncryptionResource)(entry.path) : { ...(0, import_sdk_services3.parseNetworkId)(entry.path), kind: "network" };
19618
+ const sharePrefix = parsed.kind === "prefix" && parsed.network === "default" && parsed.prefix === "share" && entry.actions.length === 1 && entry.actions[0] === DECRYPT_ACTION && didPrincipalMatches(parsed.ownerDid, currentDid);
19619
+ if (parsed.kind !== "network" && !sharePrefix) {
19620
+ throw new import_sdk_core5.ManifestValidationError("named keys go in manifest.keys");
19621
+ }
19540
19622
  for (const action of entry.actions) {
19541
19623
  addRawAbility(rawAbilities, entry.path, action);
19542
19624
  }
19543
- if (entry.actions.includes(DECRYPT_ACTION)) {
19544
- const parsed = (0, import_sdk_core5.parseNetworkId)(entry.path);
19625
+ if (entry.actions.includes(DECRYPT_ACTION) && parsed.kind === "network") {
19545
19626
  if (didPrincipalMatches(parsed.ownerDid, currentDid)) {
19546
19627
  addRawAbility(rawAbilities, entry.path, NETWORK_CREATE_ACTION);
19547
19628
  }
@@ -19578,8 +19659,7 @@ var NodeUserAuthorization = class {
19578
19659
  /**
19579
19660
  * Build SIWE overrides from the top-level nonce and siweConfig.
19580
19661
  * - Top-level `nonce` is seeded first so `siweConfig.nonce` wins if both are set.
19581
- * - statement is prepended to the default statement
19582
- * - resources are appended to the default resources
19662
+ * - resources are inserted after WASM preparation, before the final ReCap
19583
19663
  * - uri triggers a warning (overwriting delegation target)
19584
19664
  * - all other fields override directly
19585
19665
  * - per-call nonce overrides siweConfig.nonce when provided
@@ -19597,9 +19677,6 @@ var NodeUserAuthorization = class {
19597
19677
  if (statement) {
19598
19678
  overrides.statement = this.statement ? `${statement} ${this.statement}` : statement;
19599
19679
  }
19600
- if (resources && resources.length > 0) {
19601
- overrides.resources = resources;
19602
- }
19603
19680
  if (uri) {
19604
19681
  console.warn(
19605
19682
  "[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."
@@ -19611,6 +19688,29 @@ var NodeUserAuthorization = class {
19611
19688
  }
19612
19689
  return overrides;
19613
19690
  }
19691
+ prepareSessionWithResources(params) {
19692
+ const resources = this.siweConfig?.resources;
19693
+ if (resources?.some((resource) => typeof resource !== "string" || !/^urn:tinycloud:recipients:[A-Za-z0-9_-]+$/.test(resource))) {
19694
+ throw new Error("SIWE metadata resources must be base64url recipients URIs");
19695
+ }
19696
+ const prepared = this.wasm.prepareSession(params);
19697
+ if (!resources?.length) return prepared;
19698
+ const recapLines = /^- urn:recap:[^\r\n]+$/gim;
19699
+ const recaps = prepared.siwe.match(recapLines);
19700
+ const recap = recaps?.[0];
19701
+ if (recaps?.length !== 1 || !prepared.siwe.endsWith(recap)) {
19702
+ throw new Error("Prepared SIWE must end with exactly one ReCap");
19703
+ }
19704
+ const insertedLines = resources.map((resource) => `- ${resource}`);
19705
+ const siwe = prepared.siwe.slice(0, -recap.length) + insertedLines.join("\n") + "\n" + recap;
19706
+ const expectedFields = (0, import_sdk_core5.extractImmutableSiweFields)(prepared.siwe);
19707
+ expectedFields.nonRecapResources = [expectedFields.nonRecapResources, ...insertedLines].filter(Boolean).join("\n");
19708
+ const actualRecaps = siwe.match(recapLines);
19709
+ if (actualRecaps?.length !== 1 || actualRecaps[0] !== recap || (0, import_sdk_core5.diffImmutableSiweFields)(expectedFields, (0, import_sdk_core5.extractImmutableSiweFields)(siwe)).length) {
19710
+ throw new Error("SIWE metadata insertion changed the prepared message");
19711
+ }
19712
+ return { ...prepared, siwe };
19713
+ }
19614
19714
  /**
19615
19715
  * Add an extension to the authorization flow.
19616
19716
  */
@@ -19858,7 +19958,7 @@ var NodeUserAuthorization = class {
19858
19958
  spaceAbilities[spaceId] = (0, import_sdk_core5.resourceCapabilitiesToAbilitiesMap)(resources);
19859
19959
  }
19860
19960
  const abilities = spaceAbilities[options.spaceId] ?? (0, import_sdk_core5.resourceCapabilitiesToAbilitiesMap)([]);
19861
- const prepared = this.wasm.prepareSession({
19961
+ const prepared = this.prepareSessionWithResources({
19862
19962
  abilities,
19863
19963
  spaceAbilities,
19864
19964
  ...options.rawAbilities !== void 0 ? { rawAbilities: options.rawAbilities } : {},
@@ -19937,6 +20037,8 @@ var NodeUserAuthorization = class {
19937
20037
  this._chainId = chainId;
19938
20038
  await this.resolveTinyCloudHostsForSignIn(address, chainId);
19939
20039
  this.assertSignInCurrent(generation);
20040
+ await this.refreshNamedKeyFeatureForSignIn(address, chainId);
20041
+ this.assertSignInCurrent(generation);
19940
20042
  const keyId = `session-${Date.now()}`;
19941
20043
  this.sessionManager.renameSessionKeyId(this.activeSessionKeyId, keyId);
19942
20044
  this.activeSessionKeyId = keyId;
@@ -19949,7 +20051,7 @@ var NodeUserAuthorization = class {
19949
20051
  const spaceId = capabilityPlan.spaceId;
19950
20052
  const now = /* @__PURE__ */ new Date();
19951
20053
  const expirationTime = new Date(now.getTime() + this.sessionExpirationMs);
19952
- const prepared = this.wasm.prepareSession({
20054
+ const prepared = this.prepareSessionWithResources({
19953
20055
  abilities: capabilityPlan.abilities,
19954
20056
  ...capabilityPlan.spaceAbilities !== void 0 ? { spaceAbilities: capabilityPlan.spaceAbilities } : {},
19955
20057
  ...capabilityPlan.rawAbilities !== void 0 ? { rawAbilities: capabilityPlan.rawAbilities } : {},
@@ -20083,9 +20185,9 @@ var NodeUserAuthorization = class {
20083
20185
  refuseCaveated(this.getCapabilityRequest()?.manifests);
20084
20186
  const address = (0, import_sdk_core5.canonicalizeAddress)(await this.signer.getAddress());
20085
20187
  const chainId = await this.signer.getChainId();
20086
- const keyId = `session-${Date.now()}`;
20087
- this.sessionManager.renameSessionKeyId(this.activeSessionKeyId, keyId);
20088
- this.activeSessionKeyId = keyId;
20188
+ await this.refreshNamedKeyFeatureForSignIn(address, chainId);
20189
+ const keyId = `openkey-session-${Date.now()}-${++this.preparedSessionCounter}`;
20190
+ this.sessionManager.createSessionKey(keyId);
20089
20191
  const jwkString = this.sessionManager.jwk(keyId);
20090
20192
  if (!jwkString) {
20091
20193
  throw new Error("Failed to create session key");
@@ -20095,7 +20197,7 @@ var NodeUserAuthorization = class {
20095
20197
  const spaceId = capabilityPlan.spaceId;
20096
20198
  const now = /* @__PURE__ */ new Date();
20097
20199
  const expirationTime = new Date(now.getTime() + this.sessionExpirationMs);
20098
- const prepared = this.wasm.prepareSession({
20200
+ const prepared = this.prepareSessionWithResources({
20099
20201
  abilities: capabilityPlan.abilities,
20100
20202
  ...capabilityPlan.spaceAbilities !== void 0 ? { spaceAbilities: capabilityPlan.spaceAbilities } : {},
20101
20203
  ...capabilityPlan.rawAbilities !== void 0 ? { rawAbilities: capabilityPlan.rawAbilities } : {},
@@ -20166,6 +20268,7 @@ var NodeUserAuthorization = class {
20166
20268
  await this.sessionStorage.save(address, persistedData);
20167
20269
  this._session = clientSession;
20168
20270
  this._tinyCloudSession = tinyCloudSession;
20271
+ this.activeSessionKeyId = keyId;
20169
20272
  this._address = address;
20170
20273
  this._chainId = chainId;
20171
20274
  await this.refreshNodeInfo();
@@ -20212,6 +20315,11 @@ var NodeUserAuthorization = class {
20212
20315
  * @param options Optional overrides for the OpenKey request.
20213
20316
  */
20214
20317
  async signInWithOpenKey(authorizeFn, options) {
20318
+ const pending = await this.prepareOpenKeySignIn(options);
20319
+ return this.completeOpenKeySignIn(pending, authorizeFn(pending.request), options);
20320
+ }
20321
+ /** Finish address, host and SIWE preparation before an approval click. */
20322
+ async prepareOpenKeySignIn(options) {
20215
20323
  refuseCaveated(this.getCapabilityRequest()?.manifests);
20216
20324
  if (options?.host !== void 0) {
20217
20325
  const overrideHost = options.host.trim();
@@ -20223,7 +20331,7 @@ var NodeUserAuthorization = class {
20223
20331
  const signingAddress = (0, import_sdk_core5.canonicalizeAddress)(await this.signer.getAddress());
20224
20332
  const signingChainId = await this.signer.getChainId();
20225
20333
  await this.resolveTinyCloudHostsForSignIn(signingAddress, signingChainId);
20226
- const { prepared, keyId, jwk } = await this.prepareSessionForSigning();
20334
+ const { prepared, keyId, jwk, address, chainId } = await this.prepareSessionForSigning();
20227
20335
  const presentation = this.buildPresentationEnvelope(options?.reason);
20228
20336
  const hostHint = this.primaryTinyCloudHost;
20229
20337
  const originalRequest = {
@@ -20235,12 +20343,32 @@ var NodeUserAuthorization = class {
20235
20343
  keyId: options?.openkeyKeyId,
20236
20344
  presentation
20237
20345
  };
20346
+ return {
20347
+ request: originalRequest,
20348
+ prepared,
20349
+ keyId,
20350
+ jwk,
20351
+ address,
20352
+ chainId,
20353
+ generation: this.sessionGeneration,
20354
+ createdAt: Date.now()
20355
+ };
20356
+ }
20357
+ /** Complete a prepared approval. The caller starts authorization before awaiting this method. */
20358
+ async completeOpenKeySignIn(pending, authorization, options) {
20359
+ if (Date.now() - pending.createdAt > 5 * 6e4) {
20360
+ throw new Error("Prepared OpenKey sign-in expired; prepare again");
20361
+ }
20362
+ if (pending.generation !== this.sessionGeneration) {
20363
+ throw new Error("Prepared OpenKey sign-in expired after sign-out");
20364
+ }
20365
+ const { request: originalRequest, prepared, keyId, jwk } = pending;
20238
20366
  let result;
20239
20367
  let signed2;
20240
20368
  let signature2;
20241
20369
  for (let attempt = 0; ; ) {
20242
20370
  try {
20243
- result ?? (result = await authorizeFn(originalRequest));
20371
+ result ?? (result = await authorization);
20244
20372
  signed2 = await this.verifyOpenKeyResult(result, prepared);
20245
20373
  signature2 = result.signature;
20246
20374
  break;
@@ -21136,6 +21264,7 @@ var ROOT_DELEGATION_ACTIONS = [
21136
21264
  import_sdk_core10.DUCKDB.ALL
21137
21265
  ];
21138
21266
  var DEFAULT_SESSION_EXPIRATION_MS = import_sdk_core10.EXPIRY.SESSION_MS;
21267
+ var OWNER_REVOCATION_WINDOW_MS = 10 * 6e4;
21139
21268
  function unifiedRootAttenuation(capabilities) {
21140
21269
  const attenuation = {};
21141
21270
  for (const capability of capabilities) {
@@ -21633,6 +21762,7 @@ var _TinyCloudNode = class _TinyCloudNode {
21633
21762
  constructor(config = {}) {
21634
21763
  this.signer = null;
21635
21764
  this.auth = null;
21765
+ this.consumedOpenKeyPendings = /* @__PURE__ */ new WeakSet();
21636
21766
  this.tc = null;
21637
21767
  this._chainId = 1;
21638
21768
  this.replicaPurgeFailedHandlers = /* @__PURE__ */ new Set();
@@ -21667,6 +21797,7 @@ var _TinyCloudNode = class _TinyCloudNode {
21667
21797
  return void 0;
21668
21798
  }
21669
21799
  };
21800
+ this._keysUnavailable = [];
21670
21801
  this._baseVaults = /* @__PURE__ */ new Map();
21671
21802
  this._baseSecrets = /* @__PURE__ */ new Map();
21672
21803
  this._secrets = /* @__PURE__ */ new Map();
@@ -22494,6 +22625,8 @@ var _TinyCloudNode = class _TinyCloudNode {
22494
22625
  this._hooks = void 0;
22495
22626
  this._vault = void 0;
22496
22627
  this._encryption = void 0;
22628
+ this._namedKeyClient = void 0;
22629
+ this._keysUnavailable = [];
22497
22630
  this._baseVaults.clear();
22498
22631
  this._baseSecrets.clear();
22499
22632
  this._secrets.clear();
@@ -22570,6 +22703,37 @@ var _TinyCloudNode = class _TinyCloudNode {
22570
22703
  }
22571
22704
  await this.signInWith(() => this.auth.signInWithOpenKey(authorizeFn, options));
22572
22705
  }
22706
+ /** Prepare the OpenKey request before the approval click. */
22707
+ async prepareOpenKeySignIn() {
22708
+ if (!this.signer || !this.tc || !this.auth) {
22709
+ throw new Error("Cannot prepare OpenKey sign-in in session-only mode. Provide a signer in config.");
22710
+ }
22711
+ await this.signOutInFlight;
22712
+ await this.accountRegistryTail;
22713
+ await this.wasmBindings.ensureInitialized?.();
22714
+ return this.auth.prepareOpenKeySignIn();
22715
+ }
22716
+ /** Start OpenKey authorization synchronously, then complete normal session setup. */
22717
+ signInWithPreparedOpenKey(pending, authorizeFn) {
22718
+ if (!this.signer || !this.tc || !this.auth || this.signOutInFlight) {
22719
+ throw new Error("Prepared OpenKey sign-in is unavailable");
22720
+ }
22721
+ if (this.consumedOpenKeyPendings.has(pending)) {
22722
+ throw new Error("Prepared OpenKey sign-in was already used");
22723
+ }
22724
+ if (Date.now() - pending.createdAt > 5 * 6e4) {
22725
+ throw new Error("Prepared OpenKey sign-in expired; prepare again");
22726
+ }
22727
+ this.consumedOpenKeyPendings.add(pending);
22728
+ const authorization = authorizeFn(pending.request);
22729
+ void authorization.catch(() => void 0);
22730
+ return this.signInWith(() => {
22731
+ if (this._address !== pending.address || this._chainId !== pending.chainId) {
22732
+ throw new Error("OpenKey account changed after sign-in preparation");
22733
+ }
22734
+ return this.auth.completeOpenKeySignIn(pending, authorization);
22735
+ });
22736
+ }
22573
22737
  async signInWith(performSignIn) {
22574
22738
  refuseCaveated(this.auth?.capabilityRequest?.manifests);
22575
22739
  const epoch = this.sessionEpoch;
@@ -22616,6 +22780,8 @@ var _TinyCloudNode = class _TinyCloudNode {
22616
22780
  this._hooks = void 0;
22617
22781
  this._vault = void 0;
22618
22782
  this._encryption = void 0;
22783
+ this._namedKeyClient = void 0;
22784
+ this._keysUnavailable = [];
22619
22785
  this._baseVaults.clear();
22620
22786
  this._baseSecrets.clear();
22621
22787
  this._secrets.clear();
@@ -22668,6 +22834,26 @@ var _TinyCloudNode = class _TinyCloudNode {
22668
22834
  this.assertSessionEpoch(epoch, "Sign-in");
22669
22835
  await this.ensureRequestedEncryptionNetworks();
22670
22836
  this.assertSessionEpoch(epoch, "Sign-in");
22837
+ this._keysUnavailable = this.auth?.unavailableKeyPaths ?? [];
22838
+ if (this._keysUnavailable.length > 0) {
22839
+ this.notificationHandler.warning(`Named keys unavailable: ${this._keysUnavailable.join(", ")}`);
22840
+ }
22841
+ if (this.nodeFeatures.includes("encryption-named-keys-v1")) {
22842
+ for (const manifest of this.auth?.capabilityRequest?.manifests ?? []) {
22843
+ for (const declaration of manifest.keys ?? []) {
22844
+ if ("path" in declaration && declaration.abilities.includes("key.create") && !this._keysUnavailable.includes(declaration.path)) {
22845
+ try {
22846
+ await this.keys.ensureKey(declaration.path);
22847
+ } catch (error) {
22848
+ this._keysUnavailable.push(declaration.path);
22849
+ const code = error && typeof error === "object" && "code" in error && typeof error.code === "string" && /^[A-Z_]+$/.test(error.code) ? error.code : "UNKNOWN";
22850
+ this.notificationHandler.warning(`Named key unavailable: ${declaration.path} (${code})`);
22851
+ }
22852
+ this.assertSessionEpoch(epoch, "Sign-in");
22853
+ }
22854
+ }
22855
+ }
22856
+ }
22671
22857
  if (!bootstrapped && this.config.manifest === void 0 && this.config.capabilityRequest === void 0) {
22672
22858
  await this.ensureOwnedSpaceHostedById(this.ownedSpaceId(import_sdk_core10.SECRETS_SPACE));
22673
22859
  }
@@ -23244,7 +23430,7 @@ var _TinyCloudNode = class _TinyCloudNode {
23244
23430
  if (!this.currentSessionCoversAccountRegistry()) {
23245
23431
  if (!_TinyCloudNode.accountRegistrySkipLogged) {
23246
23432
  _TinyCloudNode.accountRegistrySkipLogged = true;
23247
- import_sdk_services3.tinyCloudDebugLogger.log("registry.skip");
23433
+ import_sdk_services4.tinyCloudDebugLogger.log("registry.skip");
23248
23434
  }
23249
23435
  return;
23250
23436
  }
@@ -23455,7 +23641,8 @@ var _TinyCloudNode = class _TinyCloudNode {
23455
23641
  const networkIds = /* @__PURE__ */ new Set();
23456
23642
  for (const resource of request.resources) {
23457
23643
  if (resource.service === import_sdk_core10.ENCRYPTION_PERMISSION_SERVICE && resource.path.startsWith("urn:tinycloud:encryption:") && resource.actions.includes(DECRYPT_ACTION2)) {
23458
- networkIds.add(resource.path);
23644
+ const parsed = resource.path.includes("/") ? (0, import_resource2.parseEncryptionResource)(resource.path) : { ...(0, import_sdk_core10.parseNetworkId)(resource.path), kind: "network" };
23645
+ if (parsed.kind === "network") networkIds.add(resource.path);
23459
23646
  }
23460
23647
  }
23461
23648
  return [...networkIds];
@@ -24005,6 +24192,8 @@ var _TinyCloudNode = class _TinyCloudNode {
24005
24192
  this._hooks = stagedGraph.hooks;
24006
24193
  this._vault = stagedGraph.vault;
24007
24194
  this._encryption = stagedGraph.encryption;
24195
+ this._namedKeyClient = void 0;
24196
+ this._keysUnavailable = [];
24008
24197
  this._capabilityRegistry = stagedGraph.capabilityRegistry;
24009
24198
  this._keyProvider = stagedGraph.keyProvider;
24010
24199
  this._sharingService = stagedGraph.sharingService;
@@ -24186,6 +24375,7 @@ var _TinyCloudNode = class _TinyCloudNode {
24186
24375
  invoke: graph.invoke,
24187
24376
  invokeAny: graph.invokeAny,
24188
24377
  signOwnerRevocation: this.signer ? (cid) => this.signOwnerRevocation(cid) : void 0,
24378
+ sessionInvocationSigner: this.sessionInvocationSignerFor(input.serviceSession),
24189
24379
  fetch: graph.fetch
24190
24380
  });
24191
24381
  const keyProvider = new WasmKeyProvider({ sessionManager: input.manager });
@@ -24401,6 +24591,31 @@ var _TinyCloudNode = class _TinyCloudNode {
24401
24591
  if (session === void 0) throw new Error("Not signed in. Call signIn() first.");
24402
24592
  return signBytesWithJwk(bytes, session.jwk);
24403
24593
  }
24594
+ /**
24595
+ * Signs proofless invocations with `session`'s own did:key, for the node's
24596
+ * issued-delegation list and revocation by the delegator. The audience is
24597
+ * this Node's DID; each invocation lives 60 seconds.
24598
+ */
24599
+ sessionInvocationSignerFor(session) {
24600
+ return {
24601
+ did: () => session.verificationMethod.split("#", 1)[0],
24602
+ sign: async (attenuation) => {
24603
+ const now = Math.floor(Date.now() / 1e3);
24604
+ const invocation = await (0, import_sdk_core10.signCompactUcanAuthorization)({
24605
+ issuerDid: session.verificationMethod.split("#", 1)[0],
24606
+ audienceDid: await this.fetchNodeId(),
24607
+ attenuation,
24608
+ facts: [{}],
24609
+ proofs: [],
24610
+ notBefore: now,
24611
+ expiresAt: now + 60,
24612
+ nonce: `urn:uuid:${crypto.randomUUID()}`,
24613
+ sign: (bytes) => signBytesWithJwk(bytes, session.jwk)
24614
+ });
24615
+ return invocation.authorization;
24616
+ }
24617
+ };
24618
+ }
24404
24619
  /** Author a proofless Policy/v3 owner root with the authenticated holder key. */
24405
24620
  async createUnifiedOwnerRoot(input) {
24406
24621
  const ownerDid = this.credentialHolderDid;
@@ -24914,7 +25129,7 @@ var _TinyCloudNode = class _TinyCloudNode {
24914
25129
  );
24915
25130
  graph.assertActive();
24916
25131
  if (!response.ok) {
24917
- const permissionHint = response.status === 401 || response.status === 403 ? (0, import_sdk_services3.parsePermissionHint)({
25132
+ const permissionHint = response.status === 401 || response.status === 403 ? (0, import_sdk_services4.parsePermissionHint)({
24918
25133
  service: "tinycloud.encryption",
24919
25134
  path: networkId,
24920
25135
  actions: ["tinycloud.encryption/decrypt"]
@@ -24935,7 +25150,7 @@ var _TinyCloudNode = class _TinyCloudNode {
24935
25150
  graph.assertActive();
24936
25151
  const signed2 = await this.signRawNetworkAuthorization({
24937
25152
  targetNode: input.targetNode,
24938
- networkId: input.networkId,
25153
+ networkId: input.body.keyPath === void 0 ? input.networkId : `${input.networkId}/${input.body.keyPath}`,
24939
25154
  action: DECRYPT_ACTION2,
24940
25155
  facts: input.facts
24941
25156
  }, { graph, session });
@@ -25108,6 +25323,7 @@ var _TinyCloudNode = class _TinyCloudNode {
25108
25323
  invoke: graph.invoke,
25109
25324
  invokeAny: graph.invokeAny,
25110
25325
  signOwnerRevocation: this.signer ? (cid) => this.signOwnerRevocation(cid) : void 0,
25326
+ sessionInvocationSigner: this.sessionInvocationSignerFor(serviceSession),
25111
25327
  fetch: graph.fetch
25112
25328
  });
25113
25329
  this._spaceService = new import_sdk_core10.SpaceService({
@@ -25358,7 +25574,7 @@ var _TinyCloudNode = class _TinyCloudNode {
25358
25574
  * Sign a wallet (CACAO) revocation of the delegation `cid` for the node's
25359
25575
  * `POST /revoke`, and return its Authorization header value. The node
25360
25576
  * accepts it when the owner delegated `cid` or owns a space its abilities
25361
- * target, whichever key issued it. Valid for 60 seconds. Requires the
25577
+ * target, whichever key issued it. Valid for 10 minutes. Requires the
25362
25578
  * owner wallet signer.
25363
25579
  */
25364
25580
  async signOwnerRevocation(cid) {
@@ -25374,7 +25590,7 @@ var _TinyCloudNode = class _TinyCloudNode {
25374
25590
  chainId: session.chainId,
25375
25591
  nonce: (0, import_siwe2.generateNonce)(),
25376
25592
  issuedAt: issuedAt.toISOString(),
25377
- expirationTime: new Date(issuedAt.getTime() + 6e4).toISOString()
25593
+ expirationTime: new Date(issuedAt.getTime() + OWNER_REVOCATION_WINDOW_MS).toISOString()
25378
25594
  }).prepareMessage();
25379
25595
  const signature2 = await this.signer.signMessage(siwe);
25380
25596
  return this.wasmBindings.siweToDelegationHeaders({ siwe, signature: signature2 }).Authorization;
@@ -25601,6 +25817,40 @@ var _TinyCloudNode = class _TinyCloudNode {
25601
25817
  get encryption() {
25602
25818
  return this.getEncryptionService();
25603
25819
  }
25820
+ /** Named keys bound to the current session. */
25821
+ get keys() {
25822
+ return new Proxy({}, {
25823
+ get: (_target, property) => {
25824
+ if (property === "refreshNodeInfo") {
25825
+ return () => {
25826
+ void this._namedKeyClient?.then((client) => client.refreshNodeInfo());
25827
+ };
25828
+ }
25829
+ if (typeof property !== "string" || ![
25830
+ "getPublicKey",
25831
+ "describeKey",
25832
+ "createKey",
25833
+ "blockKey",
25834
+ "unblockKey",
25835
+ "ensureKey",
25836
+ "encrypt",
25837
+ "decrypt",
25838
+ "decryptMany"
25839
+ ].includes(property)) return void 0;
25840
+ return (...args) => {
25841
+ this._namedKeyClient ?? (this._namedKeyClient = import("./encryption-keys.cjs").then(({ createNamedKeyClient }) => createNamedKeyClient(this)));
25842
+ return this._namedKeyClient.then((client) => {
25843
+ const method = client[property];
25844
+ return method.apply(client, args);
25845
+ });
25846
+ };
25847
+ }
25848
+ });
25849
+ }
25850
+ /** Manifest key paths unavailable during the latest `signIn()` attempt. */
25851
+ get keysUnavailable() {
25852
+ return this._keysUnavailable;
25853
+ }
25604
25854
  async getEncryptionNetwork(nameOrNetworkId = this.getDefaultEncryptionNetworkId()) {
25605
25855
  const networkId = nameOrNetworkId.startsWith("urn:tinycloud:encryption:") ? nameOrNetworkId : this.getDefaultEncryptionNetworkId(nameOrNetworkId);
25606
25856
  return this.fetchEncryptionNetworkAt(
@@ -25728,7 +25978,7 @@ var _TinyCloudNode = class _TinyCloudNode {
25728
25978
  );
25729
25979
  if (result.status !== "ok") {
25730
25980
  if (result.status === "permission_required") {
25731
- const hint = (0, import_sdk_services3.parsePermissionHint)(result.hint);
25981
+ const hint = (0, import_sdk_services4.parsePermissionHint)(result.hint);
25732
25982
  if (hint === void 0) return { status: "read_failed" };
25733
25983
  return {
25734
25984
  status: "permission_required",
@@ -26490,7 +26740,19 @@ var _TinyCloudNode = class _TinyCloudNode {
26490
26740
  "delegateTo requires a non-empty permissions array"
26491
26741
  );
26492
26742
  }
26493
- const expandedEntries = this.expandPermissionEntries(permissions);
26743
+ const expandedEntries = (0, import_sdk_core10.expandDelegationPermissionEntries)(permissions);
26744
+ const namedKeyEntries = expandedEntries.filter((entry) => entry.service === import_sdk_core10.ENCRYPTION_PERMISSION_SERVICE && entry.path.includes("/"));
26745
+ if (namedKeyEntries.length > 0) {
26746
+ if (expandedEntries.some((entry) => entry.service === import_sdk_core10.ENCRYPTION_PERMISSION_SERVICE && !entry.path.includes("/"))) {
26747
+ throw new import_sdk_core10.ManifestValidationError("named-key delegation cannot include bare-network permissions");
26748
+ }
26749
+ if (options?.forceWalletSign) {
26750
+ throw new import_sdk_core10.ManifestValidationError("named-key delegation requires a signed session grant");
26751
+ }
26752
+ const granted = this.projectSignedRecapCapabilities(session.siwe);
26753
+ const { subset, missing } = this.signedCapabilitySubset(namedKeyEntries, granted);
26754
+ if (!subset) throw new import_sdk_core10.PermissionNotInManifestError(missing, granted);
26755
+ }
26494
26756
  const now = /* @__PURE__ */ new Date();
26495
26757
  const expiryMs = resolveExpiryMs(options?.expiry);
26496
26758
  const expirationTime = new Date(now.getTime() + expiryMs);
@@ -28009,7 +28271,7 @@ var FileSessionStorage = class {
28009
28271
  };
28010
28272
 
28011
28273
  // src/authorization/openKeyBridge.ts
28012
- function wireOpenKeyAuthorize(openkey) {
28274
+ function wireOpenKeyAuthorize(openkey, opts) {
28013
28275
  return async (input) => {
28014
28276
  const result = await openkey.authorizeTinyCloud({
28015
28277
  protocolVersion: 1,
@@ -28020,7 +28282,7 @@ function wireOpenKeyAuthorize(openkey) {
28020
28282
  // Forward the presentation envelope verbatim — the OpenKey SDK
28021
28283
  // validates and size-bounds it before use.
28022
28284
  presentation: input.presentation
28023
- });
28285
+ }, opts);
28024
28286
  if (result.protocolVersion !== 1) {
28025
28287
  throw new Error(
28026
28288
  `wireOpenKeyAuthorize: OpenKey returned unsupported protocolVersion ${result.protocolVersion}`
@@ -28073,7 +28335,7 @@ var import_node_fs = require("fs");
28073
28335
  var import_promises = require("fs/promises");
28074
28336
  var import_node_path = require("path");
28075
28337
  var import_sdk_core14 = require("@tinycloud/sdk-core");
28076
- var import_sdk_services4 = require("@tinycloud/sdk-services");
28338
+ var import_sdk_services5 = require("@tinycloud/sdk-services");
28077
28339
  var import_contractConstants = require("@tinycloud/sdk-services/kv/replication/contractConstants");
28078
28340
  init_authority();
28079
28341
  var REPLICA_LOGOUT_PENDING_FILE = "replica-logout-pending.json";
@@ -28635,7 +28897,7 @@ function sha256Base32(material) {
28635
28897
  return out.slice(0, 26);
28636
28898
  }
28637
28899
  function partitionDirOf(root, identity) {
28638
- return (0, import_node_path.join)(root, sha256Base32((0, import_sdk_services4.replicationIdentityKey)(identity)));
28900
+ return (0, import_node_path.join)(root, sha256Base32((0, import_sdk_services5.replicationIdentityKey)(identity)));
28639
28901
  }
28640
28902
  function replicaHashOf(prefix, deviceDid) {
28641
28903
  return sha256Base32(`${prefix}
@@ -28709,8 +28971,8 @@ function deviceRecordOf(value) {
28709
28971
  }
28710
28972
  function sameIdentity(a, b) {
28711
28973
  try {
28712
- const left = (0, import_sdk_services4.canonicalReplicationIdentity)(a);
28713
- const right = (0, import_sdk_services4.canonicalReplicationIdentity)(b);
28974
+ const left = (0, import_sdk_services5.canonicalReplicationIdentity)(a);
28975
+ const right = (0, import_sdk_services5.canonicalReplicationIdentity)(b);
28714
28976
  return left.host === right.host && left.space === right.space && left.principal === right.principal;
28715
28977
  } catch {
28716
28978
  return false;
@@ -28726,7 +28988,7 @@ async function ensurePartitionIdentity(dir, identity, dirSync) {
28726
28988
  const file = (0, import_node_path.join)(dir, "identity.json");
28727
28989
  const existing = await readJsonFile(file);
28728
28990
  if (existing === void 0) {
28729
- await writeJsonAtomic(file, { v: 1, ...(0, import_sdk_services4.canonicalReplicationIdentity)(identity) }, dirSync);
28991
+ await writeJsonAtomic(file, { v: 1, ...(0, import_sdk_services5.canonicalReplicationIdentity)(identity) }, dirSync);
28730
28992
  return;
28731
28993
  }
28732
28994
  const record = identityRecordOf(existing);
@@ -28825,7 +29087,7 @@ withGate_fn = async function(section) {
28825
29087
  if (snapshot === void 0) throw gated("gate_unavailable");
28826
29088
  const [principalHash, identityKeyHash] = await Promise.all([
28827
29089
  gate.principalHashOf(snapshot.salt, this.identity.principal),
28828
- gate.identityHashOf(snapshot.salt, (0, import_sdk_services4.replicationIdentityKey)(this.identity))
29090
+ gate.identityHashOf(snapshot.salt, (0, import_sdk_services5.replicationIdentityKey)(this.identity))
28829
29091
  ]);
28830
29092
  const access = {
28831
29093
  stamp: __privateGet(this, _stamp),
@@ -29096,7 +29358,8 @@ var SqliteReplicaHandle = class {
29096
29358
  options.signal.addEventListener("abort", onAbort, { once: true });
29097
29359
  const engine = new (__privateGet(this, _replica)).Replica({
29098
29360
  store: __privateGet(this, _store),
29099
- transportFor
29361
+ transportFor,
29362
+ ...this.spec.contentFetch === void 0 ? {} : { contentFetch: this.spec.contentFetch }
29100
29363
  });
29101
29364
  const running = engine.sync({ signal: abort.signal });
29102
29365
  const registration = { promise: running, abort: () => abort.abort() };
@@ -29325,7 +29588,7 @@ function createSqliteReplicaStorage(options) {
29325
29588
  if (snapshot === void 0) throw gated("gate_unavailable");
29326
29589
  const [principalHash, identityKeyHash] = await Promise.all([
29327
29590
  gate.principalHashOf(snapshot.salt, principal),
29328
- identity === void 0 ? Promise.resolve(void 0) : gate.identityHashOf(snapshot.salt, (0, import_sdk_services4.replicationIdentityKey)(identity))
29591
+ identity === void 0 ? Promise.resolve(void 0) : gate.identityHashOf(snapshot.salt, (0, import_sdk_services5.replicationIdentityKey)(identity))
29329
29592
  ]);
29330
29593
  return profileSection(async () => {
29331
29594
  assertLogoutClear(options.logoutPendingFile);
@@ -29348,7 +29611,7 @@ function createSqliteReplicaStorage(options) {
29348
29611
  if (snapshot === void 0) throw gated("gate_unavailable");
29349
29612
  const [principalHash, identityKeyHash] = await Promise.all([
29350
29613
  gate.principalHashOf(snapshot.salt, spec.identity.principal),
29351
- gate.identityHashOf(snapshot.salt, (0, import_sdk_services4.replicationIdentityKey)(spec.identity))
29614
+ gate.identityHashOf(snapshot.salt, (0, import_sdk_services5.replicationIdentityKey)(spec.identity))
29352
29615
  ]);
29353
29616
  const access = {
29354
29617
  stamp: spec.stamp,
@@ -29432,7 +29695,7 @@ function createSqliteReplicaStorage(options) {
29432
29695
  const identity = identityRecordOf(await readJsonFile((0, import_node_path.join)(idDir, "identity.json")));
29433
29696
  if (identity === void 0) throw new ReplicaStorageError("STORAGE_ERROR", `Missing identity at ${idDir}.`);
29434
29697
  if (await gate.principalHashOf(salt, identity.principal) !== principalHash) continue;
29435
- const identityKeyHash = await gate.identityHashOf(salt, (0, import_sdk_services4.replicationIdentityKey)(identity));
29698
+ const identityKeyHash = await gate.identityHashOf(salt, (0, import_sdk_services5.replicationIdentityKey)(identity));
29436
29699
  const recordedAt = Date.now();
29437
29700
  if (await pathExists((0, import_node_path.join)(idDir, "pending.json")) || await pathExists((0, import_node_path.join)(idDir, "device.jwk"))) {
29438
29701
  intents.push({ id: `pending:${identityKeyHash}`, kind: "pending", identityKeyHash, principalHash, recordedAt });
@@ -30110,7 +30373,7 @@ function createSqliteReplicaStorage(options) {
30110
30373
  for (const dir of await identityDirs()) {
30111
30374
  const identity = identityRecordOf(await readJsonFile((0, import_node_path.join)(dir, "identity.json")));
30112
30375
  if (identity === void 0) throw new ReplicaStorageError("STORAGE_ERROR", `Missing identity at ${dir}.`);
30113
- const hash3 = await gate.identityHashOf(state.salt, (0, import_sdk_services4.replicationIdentityKey)(identity));
30376
+ const hash3 = await gate.identityHashOf(state.salt, (0, import_sdk_services5.replicationIdentityKey)(identity));
30114
30377
  if (intent.kind === "pending" ? hash3 === intent.identityKeyHash : intent.partitionId.startsWith(`${hash3}:`)) {
30115
30378
  idDir = dir;
30116
30379
  break;
@@ -30256,7 +30519,7 @@ function createSqliteReplicaStorage(options) {
30256
30519
  const gate = await fileGate();
30257
30520
  const snapshot = await gate.readGateSnapshot(profileDir);
30258
30521
  if (snapshot === void 0) throw gated("gate_unavailable");
30259
- const identityKeyHash = await gate.identityHashOf(snapshot.salt, (0, import_sdk_services4.replicationIdentityKey)(spec.identity));
30522
+ const identityKeyHash = await gate.identityHashOf(snapshot.salt, (0, import_sdk_services5.replicationIdentityKey)(spec.identity));
30260
30523
  const resolvePolicy = async (at, recordFirst) => {
30261
30524
  const policy = spec.grantPolicy;
30262
30525
  if (!Number.isSafeInteger(policy.grantTtlMs) || policy.grantTtlMs <= 0 || policy.grantTtlMs > import_contractConstants.MAX_GRANT_TTL_MS) {
@@ -30278,7 +30541,7 @@ function createSqliteReplicaStorage(options) {
30278
30541
  let partitionId;
30279
30542
  const storeGuard = (section) => guarded(spec.identity.principal, spec.stamp, spec.identity, partitionId, section);
30280
30543
  return guarded(spec.identity.principal, spec.stamp, spec.identity, void 0, async () => {
30281
- if ((0, import_sdk_services4.requiresSecretsOptIn)(spec.space, spec.prefix) && spec.allowSecrets !== true) {
30544
+ if ((0, import_sdk_services5.requiresSecretsOptIn)(spec.space, spec.prefix) && spec.allowSecrets !== true) {
30282
30545
  throw new replica.ReplicaError(
30283
30546
  replica.ReplicaErrorCode.SECRETS_OPT_IN_REQUIRED,
30284
30547
  `Replicating ${spec.space}/kv/${spec.prefix} copies secret material to disk; pass allowSecrets to opt in.`
@@ -30524,7 +30787,7 @@ function createSqliteReplicaStorage(options) {
30524
30787
  const gate = await fileGate();
30525
30788
  const currentGate = await gate.readGateSnapshot(profileDir);
30526
30789
  if (currentGate !== void 0 && currentGate.principalHash !== null && currentGate.principalHash === await gate.principalHashOf(currentGate.salt, target.identity.principal)) {
30527
- const identityKeyHash = await gate.identityHashOf(currentGate.salt, (0, import_sdk_services4.replicationIdentityKey)(target.identity));
30790
+ const identityKeyHash = await gate.identityHashOf(currentGate.salt, (0, import_sdk_services5.replicationIdentityKey)(target.identity));
30528
30791
  await retainGrantInstalls(gate, currentGate, identityKeyHash, store);
30529
30792
  }
30530
30793
  if (state.revoked === null) {
@@ -30713,6 +30976,7 @@ function sqliteReplicaStorage(options) {
30713
30976
  hexDecode,
30714
30977
  hexEncode,
30715
30978
  installTinyCloudDebugGlobals,
30979
+ isAppKeyHostBound,
30716
30980
  isCapabilitySubset,
30717
30981
  isEvmAddress,
30718
30982
  isNetworkId,