@tinycloud/node-sdk 3.2.6-beta.6 → 3.3.0-beta.7

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 (43) hide show
  1. package/dist/{WasmKeyProvider-DEdSyQ0I.d.cts → TinyCloudNode-BchWB_zv.d.cts} +162 -283
  2. package/dist/{WasmKeyProvider-DEdSyQ0I.d.ts → TinyCloudNode-BchWB_zv.d.ts} +162 -283
  3. package/dist/WasmKeyProvider-5Ee7fcAw.d.cts +217 -0
  4. package/dist/WasmKeyProvider-5Ee7fcAw.d.ts +217 -0
  5. package/dist/authority-4HXYteKF.d.ts +118 -0
  6. package/dist/authority-lrA-698X.d.cts +118 -0
  7. package/dist/core.cjs +368 -147
  8. package/dist/core.cjs.map +1 -1
  9. package/dist/core.d.cts +37 -4
  10. package/dist/core.d.ts +37 -4
  11. package/dist/core.js +374 -155
  12. package/dist/core.js.map +1 -1
  13. package/dist/gated-network-BEF2XSTC.d.cts +16 -0
  14. package/dist/gated-network-BEF2XSTC.d.ts +16 -0
  15. package/dist/index.cjs +2702 -524
  16. package/dist/index.cjs.map +1 -1
  17. package/dist/index.d.cts +35 -89
  18. package/dist/index.d.ts +35 -89
  19. package/dist/index.js +2702 -530
  20. package/dist/index.js.map +1 -1
  21. package/dist/replication/authority.cjs +153 -15
  22. package/dist/replication/authority.cjs.map +1 -1
  23. package/dist/replication/authority.d.cts +4 -1
  24. package/dist/replication/authority.d.ts +4 -1
  25. package/dist/replication/authority.js +147 -14
  26. package/dist/replication/authority.js.map +1 -1
  27. package/dist/replication/gated-network.cjs +90 -0
  28. package/dist/replication/gated-network.cjs.map +1 -0
  29. package/dist/replication/gated-network.d.cts +2 -0
  30. package/dist/replication/gated-network.d.ts +2 -0
  31. package/dist/replication/gated-network.js +65 -0
  32. package/dist/replication/gated-network.js.map +1 -0
  33. package/dist/replication/runtime.cjs +84 -6
  34. package/dist/replication/runtime.cjs.map +1 -1
  35. package/dist/replication/runtime.d.cts +2 -1
  36. package/dist/replication/runtime.d.ts +2 -1
  37. package/dist/replication/runtime.js +84 -6
  38. package/dist/replication/runtime.js.map +1 -1
  39. package/dist/{runtime-B5P5SRpC.d.ts → runtime-D1o9Eybt.d.cts} +14 -3
  40. package/dist/{runtime-B5P5SRpC.d.cts → runtime-v62FzQHz.d.ts} +14 -3
  41. package/package.json +14 -4
  42. package/dist/authority-DDGtccBK.d.cts +0 -96
  43. package/dist/authority-DDGtccBK.d.ts +0 -96
@@ -1,23 +1,30 @@
1
1
  // src/replication/authority.ts
2
+ import { SiweMessage } from "siwe";
2
3
  import {
3
4
  actionContains,
4
5
  KV as KV2,
5
6
  canonicalizeRecapCaveats,
6
7
  isCapabilitySubset as isCapabilitySubset2,
8
+ principalDid,
7
9
  parseSpaceUri
8
10
  } from "@tinycloud/sdk-core";
9
11
  import { parseUcanGrant as replicaParseUcanGrant } from "@tinycloud/replica";
10
12
 
11
13
  // src/replication/config.ts
14
+ import { MAX_GRANT_TTL_MS } from "@tinycloud/sdk-services/kv/replication/grantPolicyConstants";
12
15
  import { assertFolderPrefix as assertPureFolderPrefix, kvPrefixCovers } from "@tinycloud/sdk-services/kv/replication/prefix";
13
16
  function assertValidReplicationConfig(replication) {
14
- if (replication === void 0 || replication.enabled !== true) return;
17
+ if (replication === void 0 || !replication.enabled) return;
15
18
  if (replication.storage === void 0 || replication.storage === null) {
16
19
  throw new TypeError("replication.enabled requires replication.storage");
17
20
  }
18
21
  if (!Array.isArray(replication.prefixes) || replication.prefixes.length === 0) {
19
22
  throw new TypeError("replication.prefixes must be a non-empty array");
20
23
  }
24
+ const grantTtlMs = replication.grantTtlMs;
25
+ if (grantTtlMs !== void 0 && (!Number.isFinite(grantTtlMs) || grantTtlMs <= 0 || grantTtlMs > MAX_GRANT_TTL_MS)) {
26
+ throw new TypeError(`replication.grantTtlMs must be a positive number of milliseconds no greater than ${MAX_GRANT_TTL_MS}`);
27
+ }
21
28
  for (const prefix of replication.prefixes) {
22
29
  try {
23
30
  assertPureFolderPrefix(prefix);
@@ -94,9 +101,83 @@ function augmentSignInEntriesWithReplication(input) {
94
101
 
95
102
  // src/replication/authority.ts
96
103
  var parseUcanGrant = replicaParseUcanGrant;
104
+ function reportReplicaDenial(result, reason, onEvent, context) {
105
+ if (result.status !== "denied" && result.status !== "deleted" && result.status !== "marker") return;
106
+ const event = {
107
+ type: "replication.lifecycle",
108
+ at: (/* @__PURE__ */ new Date()).toISOString(),
109
+ reason,
110
+ action: result.status === "denied" ? "denied" : result.status === "deleted" ? "database_deleted" : "marker_set",
111
+ ...result.status === "denied" ? { partitions: result.intents } : {},
112
+ ...result.status === "marker" ? { code: result.code } : {}
113
+ };
114
+ try {
115
+ onEvent?.(event);
116
+ } catch {
117
+ }
118
+ const { type, ...data } = event;
119
+ try {
120
+ context?.emit(type, data);
121
+ } catch {
122
+ }
123
+ }
97
124
  var KV_GET2 = KV2.GET;
98
125
  var KV_SYNC2 = KV2.SYNC;
99
126
  var KV_SERVICE2 = "tinycloud.kv";
127
+ function verifiedOwnerConsentAnchor(session, wasmBindings, exactVerifiedRecap) {
128
+ if (typeof session.siwe !== "string" || typeof session.signature !== "string" || typeof session.address !== "string" || typeof session.chainId !== "number") return null;
129
+ try {
130
+ const verified = wasmBindings.validatePersistedSession?.({
131
+ delegationHeader: session.delegationHeader,
132
+ delegationCid: session.delegationCid,
133
+ spaceId: session.spaceId,
134
+ jwk: session.jwk,
135
+ address: session.address,
136
+ chainId: session.chainId,
137
+ siwe: session.siwe,
138
+ signature: session.signature
139
+ });
140
+ if (!verified || !Number.isSafeInteger(Date.parse(verified.expiresAt ?? ""))) return null;
141
+ const signedIssuedAt = new SiweMessage(session.siwe).issuedAt;
142
+ if (typeof signedIssuedAt !== "string") return null;
143
+ const issuedAt = Date.parse(signedIssuedAt);
144
+ if (!Number.isSafeInteger(issuedAt) || issuedAt < 0) return null;
145
+ const granted = exactVerifiedRecap(verified).filter((entry) => entry.space === session.spaceId && entry.service === "kv").map((entry) => ({ ...entry, service: "tinycloud.kv" }));
146
+ const coversGetAndSync = granted.some((entry) => isCapabilitySubset2([{
147
+ service: "tinycloud.kv",
148
+ space: session.spaceId,
149
+ path: entry.path,
150
+ actions: [KV2.GET, KV2.SYNC]
151
+ }], granted).subset);
152
+ return coversGetAndSync ? { at: issuedAt, source: "siwe" } : null;
153
+ } catch {
154
+ return null;
155
+ }
156
+ }
157
+ function establishReplicaSessionStamp(storage, principal, anchor) {
158
+ if (storage.kind === "indexeddb" && storage.lifecycle?.kind === "indexeddb") {
159
+ return storage.lifecycle.establishSessionStamp(principal, { consentAnchor: anchor });
160
+ }
161
+ if (storage.kind === "sqlite" && storage.lifecycle?.kind === "file") {
162
+ return storage.lifecycle.establishSessionStamp(principal, { consentAnchor: anchor });
163
+ }
164
+ throw Object.assign(new Error("Replica sign-in requires its platform lifecycle gate."), {
165
+ code: "REPLICA_GATED",
166
+ gate: "gate_unavailable"
167
+ });
168
+ }
169
+ function restoreReplicaSessionStamp(storage, principal, persisted) {
170
+ if (storage.kind === "indexeddb" && storage.lifecycle?.kind === "indexeddb") {
171
+ return storage.lifecycle.restoreSessionStamp(principal, persisted);
172
+ }
173
+ if (storage.kind === "sqlite" && storage.lifecycle?.kind === "file") {
174
+ return storage.lifecycle.restoreSessionStamp(principal, persisted);
175
+ }
176
+ throw Object.assign(new Error("Replica restore requires its platform lifecycle gate."), {
177
+ code: "REPLICA_GATED",
178
+ gate: "gate_unavailable"
179
+ });
180
+ }
100
181
  function replicationEntries(spaceId, prefix) {
101
182
  return [{
102
183
  service: KV_SERVICE2,
@@ -144,6 +225,20 @@ function ucanAttCovers(att, space, prefix, ability, options) {
144
225
  function ucanAttUnconstrainedFor(att, space, prefix) {
145
226
  return ucanAttCovers(att, space, prefix, KV_GET2) && ucanAttCovers(att, space, prefix, KV_SYNC2);
146
227
  }
228
+ async function mintNodeReplicationGrant(deviceDid, entries, options, renewalSession, node) {
229
+ if (options?.renewalOnly && !renewalSession) throw new Error("replication renewal lost its owner session");
230
+ const delegateOptions = options?.renewalOnly ? {
231
+ expiry: options.expiryMs,
232
+ onPrepared: async (prepared) => {
233
+ assertRenewalParent(prepared.delegationHeader.Authorization, renewalSession);
234
+ }
235
+ } : options?.expiryMs === void 0 ? void 0 : { expiry: options.expiryMs };
236
+ const result = await node.delegateTo(principalDid(deviceDid), entries, delegateOptions);
237
+ return {
238
+ ucan: result.delegation.delegationHeader.Authorization,
239
+ expiresAt: result.delegation.expiry.getTime()
240
+ };
241
+ }
147
242
  var AUTHORITY_EXPIRY_MARGIN_MS = 6e4;
148
243
  function replicationScopeFromSignedSession(input) {
149
244
  let grant;
@@ -162,9 +257,28 @@ function replicationScopeFromSignedSession(input) {
162
257
  }
163
258
  return void 0;
164
259
  }
260
+ function assertRenewalParent(authorization, session) {
261
+ const grant = parseUcanGrant(authorization);
262
+ if (grant.issuer !== session.verificationMethod.split("#", 1)[0] || grant.prf.length !== 1 || grant.prf[0] !== session.delegationCid) {
263
+ throw Object.assign(new Error("replication renewal requires the bound owner session parent"), { refused: "NOT_COVERED" });
264
+ }
265
+ }
165
266
  function createReplicationAuthority(host) {
166
- const planOrRefusal = (entries) => {
167
- const plan = host.planDelegation(entries);
267
+ const boundSession = host.replicationSession();
268
+ let verifiedAnchor = null;
269
+ try {
270
+ const candidate = boundSession && host.verifiedConsentAnchor?.(boundSession);
271
+ if (candidate && Number.isFinite(candidate.at) && candidate.source !== "first_install") {
272
+ verifiedAnchor = { at: candidate.at, source: candidate.source };
273
+ }
274
+ } catch {
275
+ }
276
+ const activeSession = () => {
277
+ const session = host.replicationSession();
278
+ return session !== void 0 && session === boundSession ? session : void 0;
279
+ };
280
+ const planOrRefusal = (entries, expiryMs) => {
281
+ const plan = host.planDelegation(entries, expiryMs === void 0 ? void 0 : { expiry: expiryMs });
168
282
  if ("refused" in plan) return plan;
169
283
  return { path: plan.path, parentCid: plan.parentCid, expiresAt: plan.expiresAt };
170
284
  };
@@ -176,12 +290,20 @@ function createReplicationAuthority(host) {
176
290
  };
177
291
  const authority = {
178
292
  get sessionOnly() {
179
- const session = host.replicationSession();
180
- return session !== void 0 && session.siwe === void 0;
293
+ const session = activeSession();
294
+ return session === void 0 || session.siwe === void 0;
295
+ },
296
+ consentAnchor() {
297
+ return activeSession() ? verifiedAnchor : null;
298
+ },
299
+ get canRenew() {
300
+ const session = activeSession();
301
+ return verifiedAnchor?.source === "siwe" && session !== void 0 && session.siwe !== void 0;
181
302
  },
182
303
  sessionGrant(prefix) {
183
- const session = host.replicationSession();
304
+ const session = activeSession();
184
305
  if (session === void 0) return { refused: "SESSION_EXPIRING" };
306
+ if (verifiedAnchor === null && session.siwe !== void 0) return { refused: "NOT_COVERED" };
185
307
  const siweExpiry = session.siwe ? host.siweExpiration(session.siwe)?.getTime() : void 0;
186
308
  if (siweExpiry !== void 0 && siweExpiry <= Date.now() + AUTHORITY_EXPIRY_MARGIN_MS) {
187
309
  return { refused: "SESSION_EXPIRING" };
@@ -209,8 +331,9 @@ function createReplicationAuthority(host) {
209
331
  };
210
332
  },
211
333
  plan(prefix) {
212
- const session = host.replicationSession();
334
+ const session = activeSession();
213
335
  if (session === void 0) return { refused: "SESSION_EXPIRING" };
336
+ if (verifiedAnchor === null) return { refused: "NOT_COVERED" };
214
337
  const sessionGrant = this.sessionGrant(prefix);
215
338
  if (!("refused" in sessionGrant)) {
216
339
  const signed = signedSessionGrant(session);
@@ -224,23 +347,27 @@ function createReplicationAuthority(host) {
224
347
  if (authority.sessionOnly) return sessionGrant;
225
348
  return planOrRefusal(replicationEntries(session.spaceId, prefix));
226
349
  },
227
- async mint(deviceDid, prefix, signal) {
228
- if (authority.sessionOnly) throw new Error("compact delegate sessions cannot mint device grants");
229
- const session = host.replicationSession();
230
- if (session === void 0) throw new Error("replication mint without a session");
350
+ async mint(deviceDid, prefix, signal, options) {
351
+ const session = activeSession();
352
+ if (session === void 0) throw new Error("replication mint without the bound session");
353
+ if (session.siwe === void 0) throw new Error("compact delegate sessions cannot mint device grants");
354
+ if (verifiedAnchor?.source !== "siwe") throw new Error("replication mint requires verified owner consent");
231
355
  const entries = replicationEntries(session.spaceId, prefix);
232
- const plan = planOrRefusal(entries);
356
+ const plan = planOrRefusal(entries, options?.expiryMs);
233
357
  if ("refused" in plan) {
234
358
  throw Object.assign(
235
359
  new Error(`replication authority refused the mint: ${plan.refused}`),
236
360
  { refused: plan.refused }
237
361
  );
238
362
  }
363
+ if (options?.renewalOnly && plan.path !== "session") {
364
+ throw Object.assign(new Error("replication renewal requires a session parent"), { refused: "NOT_COVERED" });
365
+ }
239
366
  signal.throwIfAborted();
240
367
  const minted = await new Promise((resolve, reject) => {
241
368
  const onAbort = () => reject(signal.reason ?? new Error("replication mint aborted"));
242
369
  signal.addEventListener("abort", onAbort, { once: true });
243
- host.mintDelegation(deviceDid, entries).then(
370
+ host.mintDelegation(deviceDid, entries, options).then(
244
371
  (result) => {
245
372
  signal.removeEventListener("abort", onAbort);
246
373
  resolve(result);
@@ -258,12 +385,18 @@ function createReplicationAuthority(host) {
258
385
  }
259
386
  export {
260
387
  AUTHORITY_EXPIRY_MARGIN_MS,
388
+ assertRenewalParent,
261
389
  assertValidReplicationConfig,
262
390
  augmentSignInEntriesWithReplication,
263
391
  createReplicationAuthority,
392
+ establishReplicaSessionStamp,
264
393
  hasUnrestrictedGetCoverage,
394
+ mintNodeReplicationGrant,
265
395
  replicationScopeFromSignedSession,
396
+ reportReplicaDenial,
397
+ restoreReplicaSessionStamp,
266
398
  ucanAttCovers,
267
- ucanAttUnconstrainedFor
399
+ ucanAttUnconstrainedFor,
400
+ verifiedOwnerConsentAnchor
268
401
  };
269
402
  //# sourceMappingURL=authority.js.map
@@ -1 +1 @@
1
- {"version":3,"sources":["../../src/replication/authority.ts","../../src/replication/config.ts","../../src/replication/authority-sign-in.ts"],"sourcesContent":["/**\n * Replication authority (TC-858, plan v3 §4).\n *\n * `ReplicationAuthority` answers, per configured prefix, whether this node's\n * session can back a local replica: the session UCAN itself (delegate\n * posture), a child UCAN minted through `delegateTo`, or nothing (the\n * controller then reports `grant_missing` and reads from the network).\n *\n * The unrestricted-authority rule is enforced here, before any network work:\n * a prefix covered only by a caveated `get`/`sync` refuses with\n * `CAVEATED_AUTHORITY` — on the session path, the runtime-grant path, and on\n * any reuse of an installed grant (the adapter marks every grant's\n * `unconstrained` flag; the controller enforces it on reuse).\n */\n\nimport {\n actionContains,\n KV,\n canonicalizeRecapCaveats,\n isCapabilitySubset,\n parseSpaceUri,\n type PermissionEntry,\n type TinyCloudSession,\n} from \"@tinycloud/sdk-core\";\nimport {\n type AuthorityRefusal,\n type ReplicaDevice,\n type ReplicationAuthority,\n} from \"@tinycloud/sdk-services\";\nimport type { ReplicaRuntime } from \"./replica-contract\";\n// @ts-ignore -- node-sdk builds before replica declarations; keep the literal import for bundlers.\nimport { parseUcanGrant as replicaParseUcanGrant } from \"@tinycloud/replica\";\nconst parseUcanGrant = replicaParseUcanGrant as ReplicaRuntime[\"parseUcanGrant\"];\nexport { assertValidReplicationConfig } from \"./config\";\nexport { augmentSignInEntriesWithReplication, hasUnrestrictedGetCoverage } from \"./authority-sign-in\";\n\nconst KV_GET = KV.GET;\nconst KV_SYNC = KV.SYNC;\nconst KV_SERVICE = \"tinycloud.kv\";\n\n/** The delegation the replication grant delegates: get + sync on one folder prefix. */\nfunction replicationEntries(spaceId: string, prefix: string): PermissionEntry[] {\n return [{\n service: KV_SERVICE,\n space: spaceId,\n path: prefix === \"/\" ? \"\" : prefix,\n actions: [KV_GET, KV_SYNC],\n }];\n}\n\n\n\n\n/**\n * The signed UCAN attenuation (`att`: resource → ability → caveat branches).\n * Only array branch sets are known; anything else is treated as constrained —\n * fail closed, never assume unconstrained.\n */\nfunction caveatBranchesUnconstrained(value: unknown): boolean {\n if (value === undefined || value === null) return true;\n if (typeof value === \"object\" && !Array.isArray(value) && Object.keys(value).length === 0) {\n return true;\n }\n if (!Array.isArray(value)) return false;\n try {\n return (\n canonicalizeRecapCaveats(value as Record<string, unknown>[]) ===\n canonicalizeRecapCaveats(undefined)\n );\n } catch {\n return false;\n }\n}\n\n/** The KV path a signed UCAN resource names in `space`, like replica's `kvPathIn`. */\nfunction kvPathInResource(resource: string, space: string): string | undefined {\n for (const root of [`${space}/kv`, `tinycloud://${space}/kv`]) {\n if (resource === root || resource === `${root}/`) return \"/\";\n }\n for (const base of [`${space}/kv/`, `tinycloud://${space}/kv/`]) {\n if (resource.startsWith(base)) return resource.slice(base.length);\n }\n return undefined;\n\n}\n/**\n * Whether the signed `att` grants `ability` over the folder prefix, with\n * unrestricted authority unless explicitly asked to ignore caveats.\n */\nexport function ucanAttCovers(\n att: Record<string, Record<string, unknown>>,\n space: string,\n prefix: string,\n ability: string,\n options?: { ignoreCaveats?: boolean },\n): boolean {\n for (const [resource, abilities] of Object.entries(att)) {\n const path = kvPathInResource(resource, space);\n if (path === undefined) continue;\n for (const [granted, caveats] of Object.entries(abilities)) {\n if (!actionContains(granted, ability)) continue;\n if (!isCapabilitySubset(\n [{ service: KV_SERVICE, space, path: prefix, actions: [ability] }],\n [{ service: KV_SERVICE, space, path, actions: [granted] }],\n ).subset) continue;\n if (options?.ignoreCaveats === true || caveatBranchesUnconstrained(caveats)) return true;\n }\n }\n return false;\n}\n\n/** `unconstrained` for `ReplicaGrantInfo` (§2.1): get AND sync on the prefix carry no caveats. */\nexport function ucanAttUnconstrainedFor(\n att: Record<string, Record<string, unknown>>,\n space: string,\n prefix: string,\n): boolean {\n return (\n ucanAttCovers(att, space, prefix, KV_GET) &&\n ucanAttCovers(att, space, prefix, KV_SYNC)\n );\n}\n\nexport interface DelegationPlanResult {\n path: \"session\" | \"runtime\";\n parentCid: string;\n expiresAt: number;\n}\n\n/**\n * The `TinyCloudNode` internals the authority needs. `planDelegation` is the\n * pure extraction of `delegateTo`'s parent selection (§4.3), so `plan` and\n * `mint` can never disagree about which parent or expiry a delegation gets.\n */\nexport type ReplicationAuthoritySession = Pick<\n TinyCloudSession,\n \"delegationHeader\" | \"delegationCid\" | \"spaceId\" | \"verificationMethod\" | \"jwk\"\n> & Partial<Pick<TinyCloudSession, \"siwe\">>;\n\nexport interface ReplicationAuthorityHost {\n replicationSession(): ReplicationAuthoritySession | undefined;\n /** The SIWE \"Expiration Time\" of the session — the delegateTo delegation cap. */\n siweExpiration(siwe: string): Date | undefined;\n planDelegation(\n entries: PermissionEntry[],\n options?: { expiry?: string | number },\n ): ({ grant?: unknown } & DelegationPlanResult) | AuthorityRefusal;\n mintDelegation(\n deviceDid: string,\n entries: PermissionEntry[],\n ): Promise<{ ucan: string; expiresAt: number }>;\n}\n\n/** Milliseconds of validity a session or parent must have left for authority reuse (delegateTo's margin). */\nexport const AUTHORITY_EXPIRY_MARGIN_MS = 60_000;\n\n\n/** Verify a compact session delegation before using any persisted space metadata. */\nexport function replicationScopeFromSignedSession(input: {\n delegationHeader: { Authorization: string };\n delegationCid: string;\n verificationMethod: string;\n persistedSpace: string;\n}): { space: string; principal: string } | undefined {\n let grant: ReturnType<typeof parseUcanGrant>;\n try {\n grant = parseUcanGrant(input.delegationHeader.Authorization);\n } catch {\n return undefined;\n }\n const bareDid = (value: string): string => value.split(\"#\", 1)[0]!;\n if (\n grant.cid !== input.delegationCid ||\n bareDid(grant.audience) !== bareDid(input.verificationMethod)\n ) return undefined;\n for (const resource of Object.keys(grant.att)) {\n const space = resource.match(/^(?:tinycloud:\\/\\/)?(.+?)\\/kv(?:\\/|$)/)?.[1];\n if (space !== input.persistedSpace) continue;\n const owner = parseSpaceUri(space);\n if (owner?.owner && owner.address && owner.chainId) return { space, principal: owner.owner };\n }\n return undefined;\n}\nexport function createReplicationAuthority(host: ReplicationAuthorityHost): ReplicationAuthority {\n const planOrRefusal = (entries: PermissionEntry[]): DelegationPlanResult | AuthorityRefusal => {\n const plan = host.planDelegation(entries);\n if (\"refused\" in plan) return plan;\n return { path: plan.path, parentCid: plan.parentCid, expiresAt: plan.expiresAt };\n };\n const sessionAudience = (value: string): string => value.split(\"#\", 1)[0]!;\n const signedSessionGrant = (session: ReplicationAuthoritySession) => {\n const grant = parseUcanGrant(session.delegationHeader.Authorization);\n if (\n grant.cid !== session.delegationCid ||\n sessionAudience(grant.audience) !== sessionAudience(session.verificationMethod)\n ) return undefined;\n return grant;\n };\n const authority: ReplicationAuthority = {\n get sessionOnly() {\n const session = host.replicationSession();\n return session !== undefined && session.siwe === undefined;\n },\n sessionGrant(prefix: string): { ucan: string; device: ReplicaDevice } | AuthorityRefusal {\n const session = host.replicationSession();\n if (session === undefined) return { refused: \"SESSION_EXPIRING\" };\n const siweExpiry = session.siwe ? host.siweExpiration(session.siwe)?.getTime() : undefined;\n if (siweExpiry !== undefined && siweExpiry <= Date.now() + AUTHORITY_EXPIRY_MARGIN_MS) {\n return { refused: \"SESSION_EXPIRING\" };\n }\n let grant: ReturnType<typeof parseUcanGrant>;\n try {\n const verified = signedSessionGrant(session);\n if (!verified) return { refused: \"NOT_COVERED\" };\n grant = verified;\n } catch {\n return { refused: \"NOT_COVERED\" };\n }\n const tokenExpiry = grant.expiresAt === null ? undefined : grant.expiresAt * 1000;\n if (tokenExpiry === undefined || tokenExpiry <= Date.now() + AUTHORITY_EXPIRY_MARGIN_MS) {\n return { refused: \"SESSION_EXPIRING\" };\n }\n const covered = ucanAttCovers(grant.att, session.spaceId, prefix, KV_GET, { ignoreCaveats: true }) &&\n ucanAttCovers(grant.att, session.spaceId, prefix, KV_SYNC, { ignoreCaveats: true });\n if (!covered) return { refused: \"NOT_COVERED\" };\n if (!ucanAttUnconstrainedFor(grant.att, session.spaceId, prefix)) {\n return { refused: \"CAVEATED_AUTHORITY\" };\n }\n return {\n ucan: grant.jwt,\n device: { did: session.verificationMethod, jwk: session.jwk },\n };\n },\n plan(prefix: string): DelegationPlanResult | AuthorityRefusal {\n const session = host.replicationSession();\n if (session === undefined) return { refused: \"SESSION_EXPIRING\" };\n const sessionGrant = this.sessionGrant(prefix);\n if (!(\"refused\" in sessionGrant)) {\n const signed = signedSessionGrant(session);\n if (!signed || signed.expiresAt === null) return { refused: \"NOT_COVERED\" };\n return {\n path: \"session\",\n parentCid: session.delegationCid,\n expiresAt: signed.expiresAt * 1000,\n };\n }\n if (authority.sessionOnly) return sessionGrant;\n return planOrRefusal(replicationEntries(session.spaceId, prefix));\n },\n async mint(\n deviceDid: string,\n prefix: string,\n signal: AbortSignal,\n ): Promise<{ ucan: string; parentCid: string; expiresAt: number }> {\n if (authority.sessionOnly) throw new Error(\"compact delegate sessions cannot mint device grants\");\n const session = host.replicationSession();\n if (session === undefined) throw new Error(\"replication mint without a session\");\n const entries = replicationEntries(session.spaceId, prefix);\n const plan = planOrRefusal(entries);\n if (\"refused\" in plan) {\n throw Object.assign(\n new Error(`replication authority refused the mint: ${plan.refused}`),\n { refused: plan.refused },\n );\n }\n signal.throwIfAborted();\n const minted = await new Promise<{ ucan: string; expiresAt: number }>((resolve, reject) => {\n const onAbort = (): void => reject(signal.reason ?? new Error(\"replication mint aborted\"));\n signal.addEventListener(\"abort\", onAbort, { once: true });\n host.mintDelegation(deviceDid, entries).then(\n (result) => {\n signal.removeEventListener(\"abort\", onAbort);\n resolve(result);\n },\n (error: unknown) => {\n signal.removeEventListener(\"abort\", onAbort);\n reject(error instanceof Error ? error : new Error(String(error)));\n },\n );\n });\n return { ucan: minted.ucan, parentCid: plan.parentCid, expiresAt: minted.expiresAt };\n },\n };\n return authority;\n}\n","import { assertFolderPrefix as assertPureFolderPrefix, kvPrefixCovers } from \"@tinycloud/sdk-services/kv/replication/prefix\";\nimport type { ReplicationOptions } from \"@tinycloud/sdk-core\";\n\n/** Constructor-time validation; the space-dependent secrets check runs at sign-in and open. */\nexport function assertValidReplicationConfig(\n replication: (ReplicationOptions & { storage?: unknown }) | undefined,\n): void {\n if (replication === undefined || replication.enabled !== true) return;\n if (replication.storage === undefined || replication.storage === null) {\n throw new TypeError(\"replication.enabled requires replication.storage\");\n }\n if (!Array.isArray(replication.prefixes) || replication.prefixes.length === 0) {\n throw new TypeError(\"replication.prefixes must be a non-empty array\");\n }\n for (const prefix of replication.prefixes) {\n try {\n assertPureFolderPrefix(prefix);\n } catch (error) {\n throw new TypeError(error instanceof Error ? error.message : String(error));\n }\n }\n for (const [index, prefix] of replication.prefixes.entries()) {\n for (const other of replication.prefixes.slice(index + 1)) {\n if (kvPrefixCovers(prefix, other) || kvPrefixCovers(other, prefix)) {\n throw new TypeError(\n `replication.prefixes must not overlap: ${JSON.stringify(prefix)} and ${JSON.stringify(other)}`,\n );\n }\n }\n if ((prefix === \"/\" || prefix.split(\"/\", 1)[0] === \"vault\") && replication.allowSecrets !== true) {\n throw new TypeError(\n `replication prefix ${JSON.stringify(prefix)} overlaps the vault namespace; pass allowSecrets to opt in`,\n );\n }\n }\n}\n","import {\n KV,\n isCapabilitySubset,\n type PermissionEntry,\n type ReplicationOptions,\n} from \"@tinycloud/sdk-core\";\nimport { requiresSecretsOptIn } from \"@tinycloud/sdk-services\";\nimport { assertFolderPrefix } from \"@tinycloud/sdk-services/kv/replication/prefix\";\n\nconst KV_GET = KV.GET;\nconst KV_SYNC = KV.SYNC;\nconst KV_SERVICE = \"tinycloud.kv\";\n\nexport function hasUnrestrictedGetCoverage(\n entries: readonly PermissionEntry[],\n spaceId: string,\n prefix: string,\n): boolean {\n return isCapabilitySubset(\n [{ service: KV_SERVICE, space: spaceId, path: prefix, actions: [KV_GET] }],\n [...entries],\n ).subset;\n}\n\nexport function augmentSignInEntriesWithReplication(input: {\n entries: readonly PermissionEntry[];\n primarySpaceId: string;\n replication?: Pick<ReplicationOptions, \"prefixes\" | \"allowSecrets\">;\n}): PermissionEntry[] {\n const out: PermissionEntry[] = [];\n const replication = input.replication;\n if (replication === undefined) return out;\n const eligiblePaths: string[] = [];\n for (const prefix of replication.prefixes) {\n assertFolderPrefix(prefix);\n const path = prefix === \"/\" ? \"\" : prefix;\n if (\n requiresSecretsOptIn(input.primarySpaceId, prefix) &&\n replication.allowSecrets !== true\n ) {\n continue;\n }\n if (!hasUnrestrictedGetCoverage(input.entries, input.primarySpaceId, path)) {\n continue;\n }\n eligiblePaths.push(path);\n }\n if (\n eligiblePaths.length === replication.prefixes.length &&\n eligiblePaths.length > 0 &&\n hasUnrestrictedGetCoverage(input.entries, input.primarySpaceId, \"\")\n ) {\n return [{\n service: KV_SERVICE,\n space: input.primarySpaceId,\n path: \"\",\n actions: [KV_GET, KV_SYNC],\n }];\n }\n for (const path of eligiblePaths) {\n out.push({\n service: KV_SERVICE,\n space: input.primarySpaceId,\n path,\n actions: [KV_GET, KV_SYNC],\n });\n }\n return out;\n}\n"],"mappings":"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","names":["KV","isCapabilitySubset","KV_GET","KV","KV_SYNC","KV_SERVICE","isCapabilitySubset"]}
1
+ {"version":3,"sources":["../../src/replication/authority.ts","../../src/replication/config.ts","../../src/replication/authority-sign-in.ts"],"sourcesContent":["/**\n * Replication authority (TC-858, plan v3 §4).\n *\n * `ReplicationAuthority` answers, per configured prefix, whether this node's\n * session can back a local replica: the session UCAN itself (delegate\n * posture), a child UCAN minted through `delegateTo`, or nothing (the\n * controller then reports `grant_missing` and reads from the network).\n *\n * The unrestricted-authority rule is enforced here, before any network work:\n * a prefix covered only by a caveated `get`/`sync` refuses with\n * `CAVEATED_AUTHORITY` — on the session path, the runtime-grant path, and on\n * any reuse of an installed grant (the adapter marks every grant's\n * `unconstrained` flag; the controller enforces it on reuse).\n */\nimport { SiweMessage } from \"siwe\";\n\nimport {\n actionContains,\n KV,\n canonicalizeRecapCaveats,\n isCapabilitySubset,\n principalDid,\n parseSpaceUri,\n type PermissionEntry,\n type IWasmBindings,\n type WasmRecapEntry,\n type TinyCloudSession,\n type KVReplicaStorage,\n type ServiceContext,\n type ReplicationOptions,\n} from \"@tinycloud/sdk-core\";\nimport {\n type AuthorityRefusal,\n type ReplicaConsentAnchor,\n type ReplicaDevice,\n type ReplicationAuthority,\n type ReplicationEvent,\n} from \"@tinycloud/sdk-services\";\nimport type { ReplicaDenyInput, ReplicaSessionStamp } from \"@tinycloud/sdk-services/kv/replication\";\nimport type { DelegateToOptions, DelegateToResult, TinyCloudNode } from \"../TinyCloudNode\";\nimport type { ReplicaRuntime } from \"./replica-contract\";\n// @ts-ignore -- node-sdk builds before replica declarations; keep the literal import for bundlers.\nimport { parseUcanGrant as replicaParseUcanGrant } from \"@tinycloud/replica\";\nconst parseUcanGrant = replicaParseUcanGrant as ReplicaRuntime[\"parseUcanGrant\"];\nexport { assertValidReplicationConfig } from \"./config\";\nexport { augmentSignInEntriesWithReplication, hasUnrestrictedGetCoverage } from \"./authority-sign-in\";\n\n/** Report a completed deny from the already-loaded authority; delivery was revoked synchronously. */\nexport function reportReplicaDenial(\n result: { status: string; code?: string; intents?: number },\n reason: ReplicaDenyInput[\"reason\"],\n onEvent: ReplicationOptions[\"onEvent\"],\n context?: ServiceContext,\n): void {\n if (result.status !== \"denied\" && result.status !== \"deleted\" && result.status !== \"marker\") return;\n const event: Extract<ReplicationEvent, { type: \"replication.lifecycle\" }> = {\n type: \"replication.lifecycle\",\n at: new Date().toISOString(),\n reason,\n action: result.status === \"denied\" ? \"denied\" : result.status === \"deleted\" ? \"database_deleted\" : \"marker_set\",\n ...(result.status === \"denied\" ? { partitions: result.intents } : {}),\n ...(result.status === \"marker\" ? { code: result.code } : {}),\n };\n try { onEvent?.(event); } catch { /* Observability cannot undo committed denial. */ }\n const { type, ...data } = event;\n try { context?.emit(type, data); } catch { /* Observability cannot undo committed denial. */ }\n}\n\nconst KV_GET = KV.GET;\nconst KV_SYNC = KV.SYNC;\nconst KV_SERVICE = \"tinycloud.kv\";\n\n/** The verified owner proof is signed, finite, exact-space, and uncaveated on one get+sync scope. */\nexport function verifiedOwnerConsentAnchor(\n session: TinyCloudSession,\n wasmBindings: Pick<IWasmBindings, \"validatePersistedSession\">,\n exactVerifiedRecap: (verified: { verifiedRecap?: unknown }) => WasmRecapEntry[],\n): ReplicaConsentAnchor | null {\n if (typeof session.siwe !== \"string\" || typeof session.signature !== \"string\" ||\n typeof session.address !== \"string\" || typeof session.chainId !== \"number\") return null;\n try {\n const verified = wasmBindings.validatePersistedSession?.({\n delegationHeader: session.delegationHeader,\n delegationCid: session.delegationCid,\n spaceId: session.spaceId,\n jwk: session.jwk,\n address: session.address,\n chainId: session.chainId,\n siwe: session.siwe,\n signature: session.signature,\n });\n if (!verified || !Number.isSafeInteger(Date.parse(verified.expiresAt ?? \"\"))) return null;\n const signedIssuedAt = new SiweMessage(session.siwe).issuedAt;\n if (typeof signedIssuedAt !== \"string\") return null;\n const issuedAt = Date.parse(signedIssuedAt);\n if (!Number.isSafeInteger(issuedAt) || issuedAt < 0) return null;\n const granted = exactVerifiedRecap(verified)\n .filter((entry) => entry.space === session.spaceId && entry.service === \"kv\")\n .map((entry) => ({ ...entry, service: \"tinycloud.kv\" }));\n const coversGetAndSync = granted.some((entry) => isCapabilitySubset([{\n service: \"tinycloud.kv\",\n space: session.spaceId,\n path: entry.path,\n actions: [KV.GET, KV.SYNC],\n }], granted).subset);\n return coversGetAndSync ? { at: issuedAt, source: \"siwe\" } : null;\n } catch {\n return null;\n }\n}\n\n/** Fresh sign-in only: the lifecycle creates keys; restore never calls this. */\nexport function establishReplicaSessionStamp(\n storage: KVReplicaStorage,\n principal: string,\n anchor: ReplicaConsentAnchor,\n): Promise<ReplicaSessionStamp> {\n if (storage.kind === \"indexeddb\" && storage.lifecycle?.kind === \"indexeddb\") {\n return storage.lifecycle.establishSessionStamp(principal, { consentAnchor: anchor });\n }\n if (storage.kind === \"sqlite\" && storage.lifecycle?.kind === \"file\") {\n return storage.lifecycle.establishSessionStamp(principal, { consentAnchor: anchor });\n }\n throw Object.assign(new Error(\"Replica sign-in requires its platform lifecycle gate.\"), {\n code: \"REPLICA_GATED\" as const, gate: \"gate_unavailable\" as const,\n });\n}\n\n/** Existing persisted stamp only: never manufactures an authority on restore. */\nexport function restoreReplicaSessionStamp(\n storage: KVReplicaStorage,\n principal: string,\n persisted: ReplicaSessionStamp | undefined,\n): Promise<ReplicaSessionStamp> {\n if (storage.kind === \"indexeddb\" && storage.lifecycle?.kind === \"indexeddb\") {\n return storage.lifecycle.restoreSessionStamp(principal, persisted);\n }\n if (storage.kind === \"sqlite\" && storage.lifecycle?.kind === \"file\") {\n return storage.lifecycle.restoreSessionStamp(principal, persisted);\n }\n throw Object.assign(new Error(\"Replica restore requires its platform lifecycle gate.\"), {\n code: \"REPLICA_GATED\" as const, gate: \"gate_unavailable\" as const,\n });\n}\n\n/** The delegation the replication grant delegates: get + sync on one folder prefix. */\nfunction replicationEntries(spaceId: string, prefix: string): PermissionEntry[] {\n return [{\n service: KV_SERVICE,\n space: spaceId,\n path: prefix === \"/\" ? \"\" : prefix,\n actions: [KV_GET, KV_SYNC],\n }];\n}\n\n\n\n\n/**\n * The signed UCAN attenuation (`att`: resource → ability → caveat branches).\n * Only array branch sets are known; anything else is treated as constrained —\n * fail closed, never assume unconstrained.\n */\nfunction caveatBranchesUnconstrained(value: unknown): boolean {\n if (value === undefined || value === null) return true;\n if (typeof value === \"object\" && !Array.isArray(value) && Object.keys(value).length === 0) {\n return true;\n }\n if (!Array.isArray(value)) return false;\n try {\n return (\n canonicalizeRecapCaveats(value as Record<string, unknown>[]) ===\n canonicalizeRecapCaveats(undefined)\n );\n } catch {\n return false;\n }\n}\n\n/** The KV path a signed UCAN resource names in `space`, like replica's `kvPathIn`. */\nfunction kvPathInResource(resource: string, space: string): string | undefined {\n for (const root of [`${space}/kv`, `tinycloud://${space}/kv`]) {\n if (resource === root || resource === `${root}/`) return \"/\";\n }\n for (const base of [`${space}/kv/`, `tinycloud://${space}/kv/`]) {\n if (resource.startsWith(base)) return resource.slice(base.length);\n }\n return undefined;\n\n}\n/**\n * Whether the signed `att` grants `ability` over the folder prefix, with\n * unrestricted authority unless explicitly asked to ignore caveats.\n */\nexport function ucanAttCovers(\n att: Record<string, Record<string, unknown>>,\n space: string,\n prefix: string,\n ability: string,\n options?: { ignoreCaveats?: boolean },\n): boolean {\n for (const [resource, abilities] of Object.entries(att)) {\n const path = kvPathInResource(resource, space);\n if (path === undefined) continue;\n for (const [granted, caveats] of Object.entries(abilities)) {\n if (!actionContains(granted, ability)) continue;\n if (!isCapabilitySubset(\n [{ service: KV_SERVICE, space, path: prefix, actions: [ability] }],\n [{ service: KV_SERVICE, space, path, actions: [granted] }],\n ).subset) continue;\n if (options?.ignoreCaveats === true || caveatBranchesUnconstrained(caveats)) return true;\n }\n }\n return false;\n}\n\n/** `unconstrained` for `ReplicaGrantInfo` (§2.1): get AND sync on the prefix carry no caveats. */\nexport function ucanAttUnconstrainedFor(\n att: Record<string, Record<string, unknown>>,\n space: string,\n prefix: string,\n): boolean {\n return (\n ucanAttCovers(att, space, prefix, KV_GET) &&\n ucanAttCovers(att, space, prefix, KV_SYNC)\n );\n}\n\nexport interface DelegationPlanResult {\n path: \"session\" | \"runtime\";\n parentCid: string;\n expiresAt: number;\n}\n\n/**\n * The `TinyCloudNode` internals the authority needs. `planDelegation` is the\n * pure extraction of `delegateTo`'s parent selection (§4.3), so `plan` and\n * `mint` can never disagree about which parent or expiry a delegation gets.\n */\nexport type ReplicationAuthoritySession = Pick<\n TinyCloudSession,\n \"delegationHeader\" | \"delegationCid\" | \"spaceId\" | \"verificationMethod\" | \"jwk\"\n> & Partial<Pick<TinyCloudSession, \"siwe\" | \"signature\" | \"address\" | \"chainId\">>;\n\nexport interface ReplicationAuthorityHost {\n replicationSession(): ReplicationAuthoritySession | undefined;\n /** Validated owner proof only; never infer consent from a compact child UCAN. */\n verifiedConsentAnchor?(session: ReplicationAuthoritySession): ReplicaConsentAnchor | null;\n /** The SIWE \"Expiration Time\" of the session — the delegateTo delegation cap. */\n siweExpiration(siwe: string): Date | undefined;\n planDelegation(\n entries: PermissionEntry[],\n options?: { expiry?: string | number },\n ): ({ grant?: unknown } & DelegationPlanResult) | AuthorityRefusal;\n mintDelegation(\n deviceDid: string,\n entries: PermissionEntry[],\n options?: { expiryMs?: number; renewalOnly?: boolean },\n ): Promise<{ ucan: string; expiresAt: number }>;\n}\n\n/** Delegate a replica grant only through the selected owner parent for silent renewal. */\nexport async function mintNodeReplicationGrant(\n deviceDid: string,\n entries: PermissionEntry[],\n options: { expiryMs?: number; renewalOnly?: boolean } | undefined,\n renewalSession: ReplicationAuthoritySession | undefined,\n node: Pick<TinyCloudNode, \"delegateTo\">,\n): Promise<{ ucan: string; expiresAt: number }> {\n if (options?.renewalOnly && !renewalSession) throw new Error(\"replication renewal lost its owner session\");\n const delegateOptions: DelegateToOptions | undefined = options?.renewalOnly ? {\n expiry: options.expiryMs,\n onPrepared: async (prepared) => {\n assertRenewalParent(prepared.delegationHeader.Authorization, renewalSession!);\n },\n } : options?.expiryMs === undefined ? undefined : { expiry: options.expiryMs };\n const result: DelegateToResult = await node.delegateTo(principalDid(deviceDid), entries, delegateOptions);\n return {\n ucan: result.delegation.delegationHeader.Authorization,\n expiresAt: result.delegation.expiry.getTime(),\n };\n}\n\n/** Milliseconds of validity a session or parent must have left for authority reuse (delegateTo's margin). */\nexport const AUTHORITY_EXPIRY_MARGIN_MS = 60_000;\n\n\n/** Verify a compact session delegation before using any persisted space metadata. */\nexport function replicationScopeFromSignedSession(input: {\n delegationHeader: { Authorization: string };\n delegationCid: string;\n verificationMethod: string;\n persistedSpace: string;\n}): { space: string; principal: string } | undefined {\n let grant: ReturnType<typeof parseUcanGrant>;\n try {\n grant = parseUcanGrant(input.delegationHeader.Authorization);\n } catch {\n return undefined;\n }\n const bareDid = (value: string): string => value.split(\"#\", 1)[0]!;\n if (\n grant.cid !== input.delegationCid ||\n bareDid(grant.audience) !== bareDid(input.verificationMethod)\n ) return undefined;\n for (const resource of Object.keys(grant.att)) {\n const space = resource.match(/^(?:tinycloud:\\/\\/)?(.+?)\\/kv(?:\\/|$)/)?.[1];\n if (space !== input.persistedSpace) continue;\n const owner = parseSpaceUri(space);\n if (owner?.owner && owner.address && owner.chainId) return { space, principal: owner.owner };\n }\n return undefined;\n}\n/** Runs before host activation; a replan cannot silently switch a renewal to a runtime parent. */\nexport function assertRenewalParent(authorization: string, session: ReplicationAuthoritySession): void {\n const grant = parseUcanGrant(authorization);\n if (\n grant.issuer !== session.verificationMethod.split(\"#\", 1)[0] ||\n grant.prf.length !== 1 ||\n grant.prf[0] !== session.delegationCid\n ) {\n throw Object.assign(new Error(\"replication renewal requires the bound owner session parent\"), { refused: \"NOT_COVERED\" as const });\n }\n}\n\nexport function createReplicationAuthority(host: ReplicationAuthorityHost): ReplicationAuthority {\n const boundSession = host.replicationSession();\n let verifiedAnchor: ReplicaConsentAnchor | null = null;\n try {\n const candidate = boundSession && host.verifiedConsentAnchor?.(boundSession);\n if (candidate && Number.isFinite(candidate.at) && candidate.source !== \"first_install\") {\n verifiedAnchor = { at: candidate.at, source: candidate.source };\n }\n } catch {\n // Network sessions remain usable when the optional replica proof cannot be verified.\n }\n const activeSession = (): ReplicationAuthoritySession | undefined => {\n const session = host.replicationSession();\n return session !== undefined && session === boundSession ? session : undefined;\n };\n const planOrRefusal = (entries: PermissionEntry[], expiryMs?: number): DelegationPlanResult | AuthorityRefusal => {\n const plan = host.planDelegation(entries, expiryMs === undefined ? undefined : { expiry: expiryMs });\n if (\"refused\" in plan) return plan;\n return { path: plan.path, parentCid: plan.parentCid, expiresAt: plan.expiresAt };\n };\n const sessionAudience = (value: string): string => value.split(\"#\", 1)[0]!;\n const signedSessionGrant = (session: ReplicationAuthoritySession) => {\n const grant = parseUcanGrant(session.delegationHeader.Authorization);\n if (\n grant.cid !== session.delegationCid ||\n sessionAudience(grant.audience) !== sessionAudience(session.verificationMethod)\n ) return undefined;\n return grant;\n };\n const authority: ReplicationAuthority = {\n get sessionOnly() {\n const session = activeSession();\n return session === undefined || session.siwe === undefined;\n },\n consentAnchor(): ReplicaConsentAnchor | null {\n return activeSession() ? verifiedAnchor : null;\n },\n get canRenew() {\n const session = activeSession();\n return verifiedAnchor?.source === \"siwe\" && session !== undefined && session.siwe !== undefined;\n },\n sessionGrant(prefix: string): { ucan: string; device: ReplicaDevice } | AuthorityRefusal {\n const session = activeSession();\n if (session === undefined) return { refused: \"SESSION_EXPIRING\" };\n // A compact session proves current signed coverage, not consent to install or mint.\n if (verifiedAnchor === null && session.siwe !== undefined) return { refused: \"NOT_COVERED\" };\n const siweExpiry = session.siwe ? host.siweExpiration(session.siwe)?.getTime() : undefined;\n if (siweExpiry !== undefined && siweExpiry <= Date.now() + AUTHORITY_EXPIRY_MARGIN_MS) {\n return { refused: \"SESSION_EXPIRING\" };\n }\n let grant: ReturnType<typeof parseUcanGrant>;\n try {\n const verified = signedSessionGrant(session);\n if (!verified) return { refused: \"NOT_COVERED\" };\n grant = verified;\n } catch {\n return { refused: \"NOT_COVERED\" };\n }\n const tokenExpiry = grant.expiresAt === null ? undefined : grant.expiresAt * 1000;\n if (tokenExpiry === undefined || tokenExpiry <= Date.now() + AUTHORITY_EXPIRY_MARGIN_MS) {\n return { refused: \"SESSION_EXPIRING\" };\n }\n const covered = ucanAttCovers(grant.att, session.spaceId, prefix, KV_GET, { ignoreCaveats: true }) &&\n ucanAttCovers(grant.att, session.spaceId, prefix, KV_SYNC, { ignoreCaveats: true });\n if (!covered) return { refused: \"NOT_COVERED\" };\n if (!ucanAttUnconstrainedFor(grant.att, session.spaceId, prefix)) {\n return { refused: \"CAVEATED_AUTHORITY\" };\n }\n return {\n ucan: grant.jwt,\n device: { did: session.verificationMethod, jwk: session.jwk },\n };\n },\n plan(prefix: string): DelegationPlanResult | AuthorityRefusal {\n const session = activeSession();\n if (session === undefined) return { refused: \"SESSION_EXPIRING\" };\n if (verifiedAnchor === null) return { refused: \"NOT_COVERED\" };\n const sessionGrant = this.sessionGrant(prefix);\n if (!(\"refused\" in sessionGrant)) {\n const signed = signedSessionGrant(session);\n if (!signed || signed.expiresAt === null) return { refused: \"NOT_COVERED\" };\n return {\n path: \"session\",\n parentCid: session.delegationCid,\n expiresAt: signed.expiresAt * 1000,\n };\n }\n if (authority.sessionOnly) return sessionGrant;\n return planOrRefusal(replicationEntries(session.spaceId, prefix));\n },\n async mint(\n deviceDid: string,\n prefix: string,\n signal: AbortSignal,\n options?: { expiryMs?: number; renewalOnly?: boolean },\n ): Promise<{ ucan: string; parentCid: string; expiresAt: number }> {\n const session = activeSession();\n if (session === undefined) throw new Error(\"replication mint without the bound session\");\n if (session.siwe === undefined) throw new Error(\"compact delegate sessions cannot mint device grants\");\n if (verifiedAnchor?.source !== \"siwe\") throw new Error(\"replication mint requires verified owner consent\");\n const entries = replicationEntries(session.spaceId, prefix);\n const plan = planOrRefusal(entries, options?.expiryMs);\n if (\"refused\" in plan) {\n throw Object.assign(\n new Error(`replication authority refused the mint: ${plan.refused}`),\n { refused: plan.refused },\n );\n }\n if (options?.renewalOnly && plan.path !== \"session\") {\n throw Object.assign(new Error(\"replication renewal requires a session parent\"), { refused: \"NOT_COVERED\" as const });\n }\n signal.throwIfAborted();\n const minted = await new Promise<{ ucan: string; expiresAt: number }>((resolve, reject) => {\n const onAbort = (): void => reject(signal.reason ?? new Error(\"replication mint aborted\"));\n signal.addEventListener(\"abort\", onAbort, { once: true });\n host.mintDelegation(deviceDid, entries, options).then(\n (result) => {\n signal.removeEventListener(\"abort\", onAbort);\n resolve(result);\n },\n (error: unknown) => {\n signal.removeEventListener(\"abort\", onAbort);\n reject(error instanceof Error ? error : new Error(String(error)));\n },\n );\n });\n return { ucan: minted.ucan, parentCid: plan.parentCid, expiresAt: minted.expiresAt };\n },\n };\n return authority;\n}\n","import { MAX_GRANT_TTL_MS } from \"@tinycloud/sdk-services/kv/replication/grantPolicyConstants\";\nimport { assertFolderPrefix as assertPureFolderPrefix, kvPrefixCovers } from \"@tinycloud/sdk-services/kv/replication/prefix\";\nimport type { ReplicationOptions } from \"@tinycloud/sdk-core\";\n\n/** Constructor-time validation; the space-dependent secrets check runs at sign-in and open. */\nexport function assertValidReplicationConfig(\n replication: (ReplicationOptions & { storage?: unknown }) | undefined,\n): void {\n if (replication === undefined || !replication.enabled) return;\n if (replication.storage === undefined || replication.storage === null) {\n throw new TypeError(\"replication.enabled requires replication.storage\");\n }\n if (!Array.isArray(replication.prefixes) || replication.prefixes.length === 0) {\n throw new TypeError(\"replication.prefixes must be a non-empty array\");\n }\n const grantTtlMs = replication.grantTtlMs;\n if (grantTtlMs !== undefined && (!Number.isFinite(grantTtlMs) || grantTtlMs <= 0 || grantTtlMs > MAX_GRANT_TTL_MS)) {\n throw new TypeError(`replication.grantTtlMs must be a positive number of milliseconds no greater than ${MAX_GRANT_TTL_MS}`);\n }\n for (const prefix of replication.prefixes) {\n try {\n assertPureFolderPrefix(prefix);\n } catch (error) {\n throw new TypeError(error instanceof Error ? error.message : String(error));\n }\n }\n for (const [index, prefix] of replication.prefixes.entries()) {\n for (const other of replication.prefixes.slice(index + 1)) {\n if (kvPrefixCovers(prefix, other) || kvPrefixCovers(other, prefix)) {\n throw new TypeError(\n `replication.prefixes must not overlap: ${JSON.stringify(prefix)} and ${JSON.stringify(other)}`,\n );\n }\n }\n if ((prefix === \"/\" || prefix.split(\"/\", 1)[0] === \"vault\") && replication.allowSecrets !== true) {\n throw new TypeError(\n `replication prefix ${JSON.stringify(prefix)} overlaps the vault namespace; pass allowSecrets to opt in`,\n );\n }\n }\n}\n","import {\n KV,\n isCapabilitySubset,\n type PermissionEntry,\n type ReplicationOptions,\n} from \"@tinycloud/sdk-core\";\nimport { requiresSecretsOptIn } from \"@tinycloud/sdk-services\";\nimport { assertFolderPrefix } from \"@tinycloud/sdk-services/kv/replication/prefix\";\n\nconst KV_GET = KV.GET;\nconst KV_SYNC = KV.SYNC;\nconst KV_SERVICE = \"tinycloud.kv\";\n\nexport function hasUnrestrictedGetCoverage(\n entries: readonly PermissionEntry[],\n spaceId: string,\n prefix: string,\n): boolean {\n return isCapabilitySubset(\n [{ service: KV_SERVICE, space: spaceId, path: prefix, actions: [KV_GET] }],\n [...entries],\n ).subset;\n}\n\nexport function augmentSignInEntriesWithReplication(input: {\n entries: readonly PermissionEntry[];\n primarySpaceId: string;\n replication?: Pick<ReplicationOptions, \"prefixes\" | \"allowSecrets\">;\n}): PermissionEntry[] {\n const out: PermissionEntry[] = [];\n const replication = input.replication;\n if (replication === undefined) return out;\n const eligiblePaths: string[] = [];\n for (const prefix of replication.prefixes) {\n assertFolderPrefix(prefix);\n const path = prefix === \"/\" ? \"\" : prefix;\n if (\n requiresSecretsOptIn(input.primarySpaceId, prefix) &&\n replication.allowSecrets !== true\n ) {\n continue;\n }\n if (!hasUnrestrictedGetCoverage(input.entries, input.primarySpaceId, path)) {\n continue;\n }\n eligiblePaths.push(path);\n }\n if (\n eligiblePaths.length === replication.prefixes.length &&\n eligiblePaths.length > 0 &&\n hasUnrestrictedGetCoverage(input.entries, input.primarySpaceId, \"\")\n ) {\n return [{\n service: KV_SERVICE,\n space: input.primarySpaceId,\n path: \"\",\n actions: [KV_GET, KV_SYNC],\n }];\n }\n for (const path of eligiblePaths) {\n out.push({\n service: KV_SERVICE,\n space: input.primarySpaceId,\n path,\n actions: [KV_GET, KV_SYNC],\n });\n }\n return out;\n}\n"],"mappings":";AAcA,SAAS,mBAAmB;AAE5B;AAAA,EACE;AAAA,EACA,MAAAA;AAAA,EACA;AAAA,EACA,sBAAAC;AAAA,EACA;AAAA,EACA;AAAA,OAQK;AAYP,SAAS,kBAAkB,6BAA6B;;;AC1CxD,SAAS,wBAAwB;AACjC,SAAS,sBAAsB,wBAAwB,sBAAsB;AAItE,SAAS,6BACd,aACM;AACN,MAAI,gBAAgB,UAAa,CAAC,YAAY,QAAS;AACvD,MAAI,YAAY,YAAY,UAAa,YAAY,YAAY,MAAM;AACrE,UAAM,IAAI,UAAU,kDAAkD;AAAA,EACxE;AACA,MAAI,CAAC,MAAM,QAAQ,YAAY,QAAQ,KAAK,YAAY,SAAS,WAAW,GAAG;AAC7E,UAAM,IAAI,UAAU,gDAAgD;AAAA,EACtE;AACA,QAAM,aAAa,YAAY;AAC/B,MAAI,eAAe,WAAc,CAAC,OAAO,SAAS,UAAU,KAAK,cAAc,KAAK,aAAa,mBAAmB;AAClH,UAAM,IAAI,UAAU,oFAAoF,gBAAgB,EAAE;AAAA,EAC5H;AACA,aAAW,UAAU,YAAY,UAAU;AACzC,QAAI;AACF,6BAAuB,MAAM;AAAA,IAC/B,SAAS,OAAO;AACd,YAAM,IAAI,UAAU,iBAAiB,QAAQ,MAAM,UAAU,OAAO,KAAK,CAAC;AAAA,IAC5E;AAAA,EACF;AACA,aAAW,CAAC,OAAO,MAAM,KAAK,YAAY,SAAS,QAAQ,GAAG;AAC5D,eAAW,SAAS,YAAY,SAAS,MAAM,QAAQ,CAAC,GAAG;AACzD,UAAI,eAAe,QAAQ,KAAK,KAAK,eAAe,OAAO,MAAM,GAAG;AAClE,cAAM,IAAI;AAAA,UACR,0CAA0C,KAAK,UAAU,MAAM,CAAC,QAAQ,KAAK,UAAU,KAAK,CAAC;AAAA,QAC/F;AAAA,MACF;AAAA,IACF;AACA,SAAK,WAAW,OAAO,OAAO,MAAM,KAAK,CAAC,EAAE,CAAC,MAAM,YAAY,YAAY,iBAAiB,MAAM;AAChG,YAAM,IAAI;AAAA,QACR,sBAAsB,KAAK,UAAU,MAAM,CAAC;AAAA,MAC9C;AAAA,IACF;AAAA,EACF;AACF;;;ACxCA;AAAA,EACE;AAAA,EACA;AAAA,OAGK;AACP,SAAS,4BAA4B;AACrC,SAAS,0BAA0B;AAEnC,IAAM,SAAS,GAAG;AAClB,IAAM,UAAU,GAAG;AACnB,IAAM,aAAa;AAEZ,SAAS,2BACd,SACA,SACA,QACS;AACT,SAAO;AAAA,IACL,CAAC,EAAE,SAAS,YAAY,OAAO,SAAS,MAAM,QAAQ,SAAS,CAAC,MAAM,EAAE,CAAC;AAAA,IACzE,CAAC,GAAG,OAAO;AAAA,EACb,EAAE;AACJ;AAEO,SAAS,oCAAoC,OAI9B;AACpB,QAAM,MAAyB,CAAC;AAChC,QAAM,cAAc,MAAM;AAC1B,MAAI,gBAAgB,OAAW,QAAO;AACtC,QAAM,gBAA0B,CAAC;AACjC,aAAW,UAAU,YAAY,UAAU;AACzC,uBAAmB,MAAM;AACzB,UAAM,OAAO,WAAW,MAAM,KAAK;AACnC,QACE,qBAAqB,MAAM,gBAAgB,MAAM,KACjD,YAAY,iBAAiB,MAC7B;AACA;AAAA,IACF;AACA,QAAI,CAAC,2BAA2B,MAAM,SAAS,MAAM,gBAAgB,IAAI,GAAG;AAC1E;AAAA,IACF;AACA,kBAAc,KAAK,IAAI;AAAA,EACzB;AACA,MACE,cAAc,WAAW,YAAY,SAAS,UAC9C,cAAc,SAAS,KACvB,2BAA2B,MAAM,SAAS,MAAM,gBAAgB,EAAE,GAClE;AACA,WAAO,CAAC;AAAA,MACN,SAAS;AAAA,MACT,OAAO,MAAM;AAAA,MACb,MAAM;AAAA,MACN,SAAS,CAAC,QAAQ,OAAO;AAAA,IAC3B,CAAC;AAAA,EACH;AACA,aAAW,QAAQ,eAAe;AAChC,QAAI,KAAK;AAAA,MACP,SAAS;AAAA,MACT,OAAO,MAAM;AAAA,MACb;AAAA,MACA,SAAS,CAAC,QAAQ,OAAO;AAAA,IAC3B,CAAC;AAAA,EACH;AACA,SAAO;AACT;;;AFzBA,IAAM,iBAAiB;AAKhB,SAAS,oBACd,QACA,QACA,SACA,SACM;AACN,MAAI,OAAO,WAAW,YAAY,OAAO,WAAW,aAAa,OAAO,WAAW,SAAU;AAC7F,QAAM,QAAsE;AAAA,IAC1E,MAAM;AAAA,IACN,KAAI,oBAAI,KAAK,GAAE,YAAY;AAAA,IAC3B;AAAA,IACA,QAAQ,OAAO,WAAW,WAAW,WAAW,OAAO,WAAW,YAAY,qBAAqB;AAAA,IACnG,GAAI,OAAO,WAAW,WAAW,EAAE,YAAY,OAAO,QAAQ,IAAI,CAAC;AAAA,IACnE,GAAI,OAAO,WAAW,WAAW,EAAE,MAAM,OAAO,KAAK,IAAI,CAAC;AAAA,EAC5D;AACA,MAAI;AAAE,cAAU,KAAK;AAAA,EAAG,QAAQ;AAAA,EAAoD;AACpF,QAAM,EAAE,MAAM,GAAG,KAAK,IAAI;AAC1B,MAAI;AAAE,aAAS,KAAK,MAAM,IAAI;AAAA,EAAG,QAAQ;AAAA,EAAoD;AAC/F;AAEA,IAAMC,UAASC,IAAG;AAClB,IAAMC,WAAUD,IAAG;AACnB,IAAME,cAAa;AAGZ,SAAS,2BACd,SACA,cACA,oBAC6B;AAC7B,MAAI,OAAO,QAAQ,SAAS,YAAY,OAAO,QAAQ,cAAc,YACjE,OAAO,QAAQ,YAAY,YAAY,OAAO,QAAQ,YAAY,SAAU,QAAO;AACvF,MAAI;AACF,UAAM,WAAW,aAAa,2BAA2B;AAAA,MACvD,kBAAkB,QAAQ;AAAA,MAC1B,eAAe,QAAQ;AAAA,MACvB,SAAS,QAAQ;AAAA,MACjB,KAAK,QAAQ;AAAA,MACb,SAAS,QAAQ;AAAA,MACjB,SAAS,QAAQ;AAAA,MACjB,MAAM,QAAQ;AAAA,MACd,WAAW,QAAQ;AAAA,IACrB,CAAC;AACD,QAAI,CAAC,YAAY,CAAC,OAAO,cAAc,KAAK,MAAM,SAAS,aAAa,EAAE,CAAC,EAAG,QAAO;AACrF,UAAM,iBAAiB,IAAI,YAAY,QAAQ,IAAI,EAAE;AACrD,QAAI,OAAO,mBAAmB,SAAU,QAAO;AAC/C,UAAM,WAAW,KAAK,MAAM,cAAc;AAC1C,QAAI,CAAC,OAAO,cAAc,QAAQ,KAAK,WAAW,EAAG,QAAO;AAC5D,UAAM,UAAU,mBAAmB,QAAQ,EACxC,OAAO,CAAC,UAAU,MAAM,UAAU,QAAQ,WAAW,MAAM,YAAY,IAAI,EAC3E,IAAI,CAAC,WAAW,EAAE,GAAG,OAAO,SAAS,eAAe,EAAE;AACzD,UAAM,mBAAmB,QAAQ,KAAK,CAAC,UAAUC,oBAAmB,CAAC;AAAA,MACnE,SAAS;AAAA,MACT,OAAO,QAAQ;AAAA,MACf,MAAM,MAAM;AAAA,MACZ,SAAS,CAACH,IAAG,KAAKA,IAAG,IAAI;AAAA,IAC3B,CAAC,GAAG,OAAO,EAAE,MAAM;AACnB,WAAO,mBAAmB,EAAE,IAAI,UAAU,QAAQ,OAAO,IAAI;AAAA,EAC/D,QAAQ;AACN,WAAO;AAAA,EACT;AACF;AAGO,SAAS,6BACd,SACA,WACA,QAC8B;AAC9B,MAAI,QAAQ,SAAS,eAAe,QAAQ,WAAW,SAAS,aAAa;AAC3E,WAAO,QAAQ,UAAU,sBAAsB,WAAW,EAAE,eAAe,OAAO,CAAC;AAAA,EACrF;AACA,MAAI,QAAQ,SAAS,YAAY,QAAQ,WAAW,SAAS,QAAQ;AACnE,WAAO,QAAQ,UAAU,sBAAsB,WAAW,EAAE,eAAe,OAAO,CAAC;AAAA,EACrF;AACA,QAAM,OAAO,OAAO,IAAI,MAAM,uDAAuD,GAAG;AAAA,IACtF,MAAM;AAAA,IAA0B,MAAM;AAAA,EACxC,CAAC;AACH;AAGO,SAAS,2BACd,SACA,WACA,WAC8B;AAC9B,MAAI,QAAQ,SAAS,eAAe,QAAQ,WAAW,SAAS,aAAa;AAC3E,WAAO,QAAQ,UAAU,oBAAoB,WAAW,SAAS;AAAA,EACnE;AACA,MAAI,QAAQ,SAAS,YAAY,QAAQ,WAAW,SAAS,QAAQ;AACnE,WAAO,QAAQ,UAAU,oBAAoB,WAAW,SAAS;AAAA,EACnE;AACA,QAAM,OAAO,OAAO,IAAI,MAAM,uDAAuD,GAAG;AAAA,IACtF,MAAM;AAAA,IAA0B,MAAM;AAAA,EACxC,CAAC;AACH;AAGA,SAAS,mBAAmB,SAAiB,QAAmC;AAC9E,SAAO,CAAC;AAAA,IACN,SAASE;AAAA,IACT,OAAO;AAAA,IACP,MAAM,WAAW,MAAM,KAAK;AAAA,IAC5B,SAAS,CAACH,SAAQE,QAAO;AAAA,EAC3B,CAAC;AACH;AAUA,SAAS,4BAA4B,OAAyB;AAC5D,MAAI,UAAU,UAAa,UAAU,KAAM,QAAO;AAClD,MAAI,OAAO,UAAU,YAAY,CAAC,MAAM,QAAQ,KAAK,KAAK,OAAO,KAAK,KAAK,EAAE,WAAW,GAAG;AACzF,WAAO;AAAA,EACT;AACA,MAAI,CAAC,MAAM,QAAQ,KAAK,EAAG,QAAO;AAClC,MAAI;AACF,WACE,yBAAyB,KAAkC,MAC3D,yBAAyB,MAAS;AAAA,EAEtC,QAAQ;AACN,WAAO;AAAA,EACT;AACF;AAGA,SAAS,iBAAiB,UAAkB,OAAmC;AAC7E,aAAW,QAAQ,CAAC,GAAG,KAAK,OAAO,eAAe,KAAK,KAAK,GAAG;AAC7D,QAAI,aAAa,QAAQ,aAAa,GAAG,IAAI,IAAK,QAAO;AAAA,EAC3D;AACA,aAAW,QAAQ,CAAC,GAAG,KAAK,QAAQ,eAAe,KAAK,MAAM,GAAG;AAC/D,QAAI,SAAS,WAAW,IAAI,EAAG,QAAO,SAAS,MAAM,KAAK,MAAM;AAAA,EAClE;AACA,SAAO;AAET;AAKO,SAAS,cACd,KACA,OACA,QACA,SACA,SACS;AACT,aAAW,CAAC,UAAU,SAAS,KAAK,OAAO,QAAQ,GAAG,GAAG;AACvD,UAAM,OAAO,iBAAiB,UAAU,KAAK;AAC7C,QAAI,SAAS,OAAW;AACxB,eAAW,CAAC,SAAS,OAAO,KAAK,OAAO,QAAQ,SAAS,GAAG;AAC1D,UAAI,CAAC,eAAe,SAAS,OAAO,EAAG;AACvC,UAAI,CAACE;AAAA,QACH,CAAC,EAAE,SAASD,aAAY,OAAO,MAAM,QAAQ,SAAS,CAAC,OAAO,EAAE,CAAC;AAAA,QACjE,CAAC,EAAE,SAASA,aAAY,OAAO,MAAM,SAAS,CAAC,OAAO,EAAE,CAAC;AAAA,MAC3D,EAAE,OAAQ;AACV,UAAI,SAAS,kBAAkB,QAAQ,4BAA4B,OAAO,EAAG,QAAO;AAAA,IACtF;AAAA,EACF;AACA,SAAO;AACT;AAGO,SAAS,wBACd,KACA,OACA,QACS;AACT,SACE,cAAc,KAAK,OAAO,QAAQH,OAAM,KACxC,cAAc,KAAK,OAAO,QAAQE,QAAO;AAE7C;AAoCA,eAAsB,yBACpB,WACA,SACA,SACA,gBACA,MAC8C;AAC9C,MAAI,SAAS,eAAe,CAAC,eAAgB,OAAM,IAAI,MAAM,4CAA4C;AACzG,QAAM,kBAAiD,SAAS,cAAc;AAAA,IAC5E,QAAQ,QAAQ;AAAA,IAChB,YAAY,OAAO,aAAa;AAC9B,0BAAoB,SAAS,iBAAiB,eAAe,cAAe;AAAA,IAC9E;AAAA,EACF,IAAI,SAAS,aAAa,SAAY,SAAY,EAAE,QAAQ,QAAQ,SAAS;AAC7E,QAAM,SAA2B,MAAM,KAAK,WAAW,aAAa,SAAS,GAAG,SAAS,eAAe;AACxG,SAAO;AAAA,IACL,MAAM,OAAO,WAAW,iBAAiB;AAAA,IACzC,WAAW,OAAO,WAAW,OAAO,QAAQ;AAAA,EAC9C;AACF;AAGO,IAAM,6BAA6B;AAInC,SAAS,kCAAkC,OAKG;AACnD,MAAI;AACJ,MAAI;AACF,YAAQ,eAAe,MAAM,iBAAiB,aAAa;AAAA,EAC7D,QAAQ;AACN,WAAO;AAAA,EACT;AACA,QAAM,UAAU,CAAC,UAA0B,MAAM,MAAM,KAAK,CAAC,EAAE,CAAC;AAChE,MACE,MAAM,QAAQ,MAAM,iBACpB,QAAQ,MAAM,QAAQ,MAAM,QAAQ,MAAM,kBAAkB,EAC5D,QAAO;AACT,aAAW,YAAY,OAAO,KAAK,MAAM,GAAG,GAAG;AAC7C,UAAM,QAAQ,SAAS,MAAM,uCAAuC,IAAI,CAAC;AACzE,QAAI,UAAU,MAAM,eAAgB;AACpC,UAAM,QAAQ,cAAc,KAAK;AACjC,QAAI,OAAO,SAAS,MAAM,WAAW,MAAM,QAAS,QAAO,EAAE,OAAO,WAAW,MAAM,MAAM;AAAA,EAC7F;AACA,SAAO;AACT;AAEO,SAAS,oBAAoB,eAAuB,SAA4C;AACrG,QAAM,QAAQ,eAAe,aAAa;AAC1C,MACE,MAAM,WAAW,QAAQ,mBAAmB,MAAM,KAAK,CAAC,EAAE,CAAC,KAC3D,MAAM,IAAI,WAAW,KACrB,MAAM,IAAI,CAAC,MAAM,QAAQ,eACzB;AACA,UAAM,OAAO,OAAO,IAAI,MAAM,6DAA6D,GAAG,EAAE,SAAS,cAAuB,CAAC;AAAA,EACnI;AACF;AAEO,SAAS,2BAA2B,MAAsD;AAC/F,QAAM,eAAe,KAAK,mBAAmB;AAC7C,MAAI,iBAA8C;AAClD,MAAI;AACF,UAAM,YAAY,gBAAgB,KAAK,wBAAwB,YAAY;AAC3E,QAAI,aAAa,OAAO,SAAS,UAAU,EAAE,KAAK,UAAU,WAAW,iBAAiB;AACtF,uBAAiB,EAAE,IAAI,UAAU,IAAI,QAAQ,UAAU,OAAO;AAAA,IAChE;AAAA,EACF,QAAQ;AAAA,EAER;AACA,QAAM,gBAAgB,MAA+C;AACnE,UAAM,UAAU,KAAK,mBAAmB;AACxC,WAAO,YAAY,UAAa,YAAY,eAAe,UAAU;AAAA,EACvE;AACA,QAAM,gBAAgB,CAAC,SAA4B,aAA+D;AAChH,UAAM,OAAO,KAAK,eAAe,SAAS,aAAa,SAAY,SAAY,EAAE,QAAQ,SAAS,CAAC;AACnG,QAAI,aAAa,KAAM,QAAO;AAC9B,WAAO,EAAE,MAAM,KAAK,MAAM,WAAW,KAAK,WAAW,WAAW,KAAK,UAAU;AAAA,EACjF;AACA,QAAM,kBAAkB,CAAC,UAA0B,MAAM,MAAM,KAAK,CAAC,EAAE,CAAC;AACxE,QAAM,qBAAqB,CAAC,YAAyC;AACnE,UAAM,QAAQ,eAAe,QAAQ,iBAAiB,aAAa;AACnE,QACE,MAAM,QAAQ,QAAQ,iBACtB,gBAAgB,MAAM,QAAQ,MAAM,gBAAgB,QAAQ,kBAAkB,EAC9E,QAAO;AACT,WAAO;AAAA,EACT;AACA,QAAM,YAAkC;AAAA,IACtC,IAAI,cAAc;AAChB,YAAM,UAAU,cAAc;AAC9B,aAAO,YAAY,UAAa,QAAQ,SAAS;AAAA,IACnD;AAAA,IACA,gBAA6C;AAC3C,aAAO,cAAc,IAAI,iBAAiB;AAAA,IAC5C;AAAA,IACA,IAAI,WAAW;AACb,YAAM,UAAU,cAAc;AAC9B,aAAO,gBAAgB,WAAW,UAAU,YAAY,UAAa,QAAQ,SAAS;AAAA,IACxF;AAAA,IACA,aAAa,QAA4E;AACvF,YAAM,UAAU,cAAc;AAC9B,UAAI,YAAY,OAAW,QAAO,EAAE,SAAS,mBAAmB;AAEhE,UAAI,mBAAmB,QAAQ,QAAQ,SAAS,OAAW,QAAO,EAAE,SAAS,cAAc;AAC3F,YAAM,aAAa,QAAQ,OAAO,KAAK,eAAe,QAAQ,IAAI,GAAG,QAAQ,IAAI;AACjF,UAAI,eAAe,UAAa,cAAc,KAAK,IAAI,IAAI,4BAA4B;AACrF,eAAO,EAAE,SAAS,mBAAmB;AAAA,MACvC;AACA,UAAI;AACJ,UAAI;AACF,cAAM,WAAW,mBAAmB,OAAO;AAC3C,YAAI,CAAC,SAAU,QAAO,EAAE,SAAS,cAAc;AAC/C,gBAAQ;AAAA,MACV,QAAQ;AACN,eAAO,EAAE,SAAS,cAAc;AAAA,MAClC;AACA,YAAM,cAAc,MAAM,cAAc,OAAO,SAAY,MAAM,YAAY;AAC7E,UAAI,gBAAgB,UAAa,eAAe,KAAK,IAAI,IAAI,4BAA4B;AACvF,eAAO,EAAE,SAAS,mBAAmB;AAAA,MACvC;AACA,YAAM,UAAU,cAAc,MAAM,KAAK,QAAQ,SAAS,QAAQF,SAAQ,EAAE,eAAe,KAAK,CAAC,KAC/F,cAAc,MAAM,KAAK,QAAQ,SAAS,QAAQE,UAAS,EAAE,eAAe,KAAK,CAAC;AACpF,UAAI,CAAC,QAAS,QAAO,EAAE,SAAS,cAAc;AAC9C,UAAI,CAAC,wBAAwB,MAAM,KAAK,QAAQ,SAAS,MAAM,GAAG;AAChE,eAAO,EAAE,SAAS,qBAAqB;AAAA,MACzC;AACA,aAAO;AAAA,QACL,MAAM,MAAM;AAAA,QACZ,QAAQ,EAAE,KAAK,QAAQ,oBAAoB,KAAK,QAAQ,IAAI;AAAA,MAC9D;AAAA,IACF;AAAA,IACA,KAAK,QAAyD;AAC5D,YAAM,UAAU,cAAc;AAC9B,UAAI,YAAY,OAAW,QAAO,EAAE,SAAS,mBAAmB;AAChE,UAAI,mBAAmB,KAAM,QAAO,EAAE,SAAS,cAAc;AAC7D,YAAM,eAAe,KAAK,aAAa,MAAM;AAC7C,UAAI,EAAE,aAAa,eAAe;AAChC,cAAM,SAAS,mBAAmB,OAAO;AACzC,YAAI,CAAC,UAAU,OAAO,cAAc,KAAM,QAAO,EAAE,SAAS,cAAc;AAC1E,eAAO;AAAA,UACL,MAAM;AAAA,UACN,WAAW,QAAQ;AAAA,UACnB,WAAW,OAAO,YAAY;AAAA,QAChC;AAAA,MACF;AACA,UAAI,UAAU,YAAa,QAAO;AAClC,aAAO,cAAc,mBAAmB,QAAQ,SAAS,MAAM,CAAC;AAAA,IAClE;AAAA,IACA,MAAM,KACJ,WACA,QACA,QACA,SACiE;AACjE,YAAM,UAAU,cAAc;AAC9B,UAAI,YAAY,OAAW,OAAM,IAAI,MAAM,4CAA4C;AACvF,UAAI,QAAQ,SAAS,OAAW,OAAM,IAAI,MAAM,qDAAqD;AACrG,UAAI,gBAAgB,WAAW,OAAQ,OAAM,IAAI,MAAM,kDAAkD;AACzG,YAAM,UAAU,mBAAmB,QAAQ,SAAS,MAAM;AAC1D,YAAM,OAAO,cAAc,SAAS,SAAS,QAAQ;AACrD,UAAI,aAAa,MAAM;AACrB,cAAM,OAAO;AAAA,UACX,IAAI,MAAM,2CAA2C,KAAK,OAAO,EAAE;AAAA,UACnE,EAAE,SAAS,KAAK,QAAQ;AAAA,QAC1B;AAAA,MACF;AACA,UAAI,SAAS,eAAe,KAAK,SAAS,WAAW;AACnD,cAAM,OAAO,OAAO,IAAI,MAAM,+CAA+C,GAAG,EAAE,SAAS,cAAuB,CAAC;AAAA,MACrH;AACA,aAAO,eAAe;AACtB,YAAM,SAAS,MAAM,IAAI,QAA6C,CAAC,SAAS,WAAW;AACzF,cAAM,UAAU,MAAY,OAAO,OAAO,UAAU,IAAI,MAAM,0BAA0B,CAAC;AACzF,eAAO,iBAAiB,SAAS,SAAS,EAAE,MAAM,KAAK,CAAC;AACxD,aAAK,eAAe,WAAW,SAAS,OAAO,EAAE;AAAA,UAC/C,CAAC,WAAW;AACV,mBAAO,oBAAoB,SAAS,OAAO;AAC3C,oBAAQ,MAAM;AAAA,UAChB;AAAA,UACA,CAAC,UAAmB;AAClB,mBAAO,oBAAoB,SAAS,OAAO;AAC3C,mBAAO,iBAAiB,QAAQ,QAAQ,IAAI,MAAM,OAAO,KAAK,CAAC,CAAC;AAAA,UAClE;AAAA,QACF;AAAA,MACF,CAAC;AACD,aAAO,EAAE,MAAM,OAAO,MAAM,WAAW,KAAK,WAAW,WAAW,OAAO,UAAU;AAAA,IACrF;AAAA,EACF;AACA,SAAO;AACT;","names":["KV","isCapabilitySubset","KV_GET","KV","KV_SYNC","KV_SERVICE","isCapabilitySubset"]}
@@ -0,0 +1,90 @@
1
+ "use strict";
2
+ var __defProp = Object.defineProperty;
3
+ var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
4
+ var __getOwnPropNames = Object.getOwnPropertyNames;
5
+ var __hasOwnProp = Object.prototype.hasOwnProperty;
6
+ var __export = (target, all) => {
7
+ for (var name in all)
8
+ __defProp(target, name, { get: all[name], enumerable: true });
9
+ };
10
+ var __copyProps = (to, from, except, desc) => {
11
+ if (from && typeof from === "object" || typeof from === "function") {
12
+ for (let key of __getOwnPropNames(from))
13
+ if (!__hasOwnProp.call(to, key) && key !== except)
14
+ __defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
15
+ }
16
+ return to;
17
+ };
18
+ var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
19
+
20
+ // src/replication/gated-network.ts
21
+ var gated_network_exports = {};
22
+ __export(gated_network_exports, {
23
+ createGatedNetworkReadThrough: () => createGatedNetworkReadThrough
24
+ });
25
+ module.exports = __toCommonJS(gated_network_exports);
26
+ var import_prefix = require("@tinycloud/sdk-services/kv/replication/prefix");
27
+ function createGatedNetworkReadThrough(input) {
28
+ const report = (op, space, path, replica, reason, outcome, latencyMs) => input.emit({
29
+ type: "replication.read",
30
+ at: new Date(input.now()).toISOString(),
31
+ op,
32
+ space,
33
+ key: path,
34
+ replica,
35
+ source: reason === "cursor_restart" ? "none" : "network",
36
+ reason,
37
+ outcome,
38
+ latencyMs,
39
+ stalenessMs: null,
40
+ coverage: null,
41
+ authority: null,
42
+ ...reason === "replica_gated" ? { code: "REPLICA_GATED" } : {}
43
+ });
44
+ const readNetwork = async (r, op, path, prefix, reason) => {
45
+ const started = input.now();
46
+ let outcome = "error";
47
+ try {
48
+ const result = await r.network();
49
+ outcome = result.ok ? "found" : op === "get" && reason === "not_covered" && "error" in result && result.error.code === "KV_NOT_FOUND" ? "not_found" : "error";
50
+ return result;
51
+ } finally {
52
+ report(op, r.space, path, prefix, reason, outcome, input.now() - started);
53
+ }
54
+ };
55
+ const covered = (path) => input.prefixes.find((prefix) => (0, import_prefix.kvPrefixCovers)(prefix, path));
56
+ return {
57
+ get: (r) => {
58
+ if (r.space !== input.space) return r.network();
59
+ if (r.options?.source === "network") return readNetwork(r, "get", r.path, null, "NETWORK_REQUESTED");
60
+ const prefix = covered(r.path);
61
+ return readNetwork(r, "get", r.path, prefix ?? null, prefix === void 0 ? "not_covered" : "replica_gated");
62
+ },
63
+ list: (r) => {
64
+ if (r.space !== input.space) return r.network();
65
+ if (r.options?.source === "network") return readNetwork(r, "list", r.listPath, null, "NETWORK_REQUESTED");
66
+ if (r.options?.cursor?.startsWith("tcr1.")) {
67
+ report("list", r.space, r.listPath, null, "cursor_restart", "error", 0);
68
+ return Promise.resolve({ ok: false, error: {
69
+ code: "INVALID_INPUT",
70
+ message: "Local list cursor cannot be served; restart without the cursor",
71
+ service: "kv",
72
+ meta: { replication: "cursor_restart" }
73
+ } });
74
+ }
75
+ if (r.options?.cursor) return readNetwork(r, "list", r.listPath, null, "network_cursor");
76
+ if (r.options?.raw) return readNetwork(r, "list", r.listPath, null, "unsupported_option");
77
+ const prefix = covered(r.listPath);
78
+ return readNetwork(r, "list", r.listPath, prefix ?? null, prefix === void 0 ? "not_covered" : "replica_gated");
79
+ },
80
+ write: (r) => r.network(),
81
+ observeNetworkRequested: (r) => {
82
+ if (r.space === input.space) report(r.op, r.space, r.path, null, r.reason, r.outcome, r.latencyMs);
83
+ }
84
+ };
85
+ }
86
+ // Annotate the CommonJS export names for ESM import in node:
87
+ 0 && (module.exports = {
88
+ createGatedNetworkReadThrough
89
+ });
90
+ //# sourceMappingURL=gated-network.cjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../../src/replication/gated-network.ts"],"sourcesContent":["import { kvPrefixCovers } from \"@tinycloud/sdk-services/kv/replication/prefix\";\nimport type { KVReadThrough, ReplicationEvent } from \"@tinycloud/sdk-services\";\n\n/** Loaded only after a refused restore. No replica storage, authority, or worker access. */\nexport function createGatedNetworkReadThrough(input: {\n space: string;\n prefixes: readonly string[];\n now: () => number;\n emit: (event: ReplicationEvent) => void;\n}): KVReadThrough {\n const report = (\n op: \"get\" | \"list\", space: string, path: string, replica: string | null,\n reason: \"replica_gated\" | \"not_covered\" | \"unsupported_option\" | \"network_cursor\" | \"NETWORK_REQUESTED\" | \"cursor_restart\",\n outcome: \"found\" | \"not_found\" | \"error\", latencyMs: number,\n ) => input.emit({\n type: \"replication.read\", at: new Date(input.now()).toISOString(), op, space, key: path,\n replica, source: reason === \"cursor_restart\" ? \"none\" : \"network\", reason, outcome, latencyMs,\n stalenessMs: null, coverage: null, authority: null,\n ...(reason === \"replica_gated\" ? { code: \"REPLICA_GATED\" } : {}),\n });\n const readNetwork = async <T extends { ok: boolean }>(\n r: { space: string; network: () => Promise<T> }, op: \"get\" | \"list\", path: string,\n prefix: string | null, reason: \"replica_gated\" | \"not_covered\" | \"unsupported_option\" | \"network_cursor\" | \"NETWORK_REQUESTED\",\n ): Promise<T> => {\n const started = input.now();\n let outcome: \"found\" | \"not_found\" | \"error\" = \"error\";\n try {\n const result = await r.network();\n outcome = result.ok ? \"found\" : op === \"get\" && reason === \"not_covered\" && \"error\" in result &&\n (result.error as { code?: string }).code === \"KV_NOT_FOUND\" ? \"not_found\" : \"error\";\n return result;\n } finally {\n report(op, r.space, path, prefix, reason, outcome, input.now() - started);\n }\n };\n const covered = (path: string) => input.prefixes.find((prefix) => kvPrefixCovers(prefix, path));\n return {\n get: (r) => {\n if (r.space !== input.space) return r.network();\n if (r.options?.source === \"network\") return readNetwork(r, \"get\", r.path, null, \"NETWORK_REQUESTED\");\n const prefix = covered(r.path);\n return readNetwork(r, \"get\", r.path, prefix ?? null, prefix === undefined ? \"not_covered\" : \"replica_gated\");\n },\n list: (r) => {\n if (r.space !== input.space) return r.network();\n if (r.options?.source === \"network\") return readNetwork(r, \"list\", r.listPath, null, \"NETWORK_REQUESTED\");\n if (r.options?.cursor?.startsWith(\"tcr1.\")) {\n report(\"list\", r.space, r.listPath, null, \"cursor_restart\", \"error\", 0);\n return Promise.resolve({ ok: false, error: {\n code: \"INVALID_INPUT\", message: \"Local list cursor cannot be served; restart without the cursor\",\n service: \"kv\", meta: { replication: \"cursor_restart\" },\n } });\n }\n if (r.options?.cursor) return readNetwork(r, \"list\", r.listPath, null, \"network_cursor\");\n if (r.options?.raw) return readNetwork(r, \"list\", r.listPath, null, \"unsupported_option\");\n const prefix = covered(r.listPath);\n return readNetwork(r, \"list\", r.listPath, prefix ?? null, prefix === undefined ? \"not_covered\" : \"replica_gated\");\n },\n write: (r) => r.network(),\n observeNetworkRequested: (r) => {\n if (r.space === input.space) report(r.op, r.space, r.path, null, r.reason, r.outcome, r.latencyMs);\n },\n };\n}\n"],"mappings":";;;;;;;;;;;;;;;;;;;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,oBAA+B;AAIxB,SAAS,8BAA8B,OAK5B;AAChB,QAAM,SAAS,CACb,IAAoB,OAAe,MAAc,SACjD,QACA,SAA0C,cACvC,MAAM,KAAK;AAAA,IACd,MAAM;AAAA,IAAoB,IAAI,IAAI,KAAK,MAAM,IAAI,CAAC,EAAE,YAAY;AAAA,IAAG;AAAA,IAAI;AAAA,IAAO,KAAK;AAAA,IACnF;AAAA,IAAS,QAAQ,WAAW,mBAAmB,SAAS;AAAA,IAAW;AAAA,IAAQ;AAAA,IAAS;AAAA,IACpF,aAAa;AAAA,IAAM,UAAU;AAAA,IAAM,WAAW;AAAA,IAC9C,GAAI,WAAW,kBAAkB,EAAE,MAAM,gBAAgB,IAAI,CAAC;AAAA,EAChE,CAAC;AACD,QAAM,cAAc,OAClB,GAAiD,IAAoB,MACrE,QAAuB,WACR;AACf,UAAM,UAAU,MAAM,IAAI;AAC1B,QAAI,UAA2C;AAC/C,QAAI;AACF,YAAM,SAAS,MAAM,EAAE,QAAQ;AAC/B,gBAAU,OAAO,KAAK,UAAU,OAAO,SAAS,WAAW,iBAAiB,WAAW,UACpF,OAAO,MAA4B,SAAS,iBAAiB,cAAc;AAC9E,aAAO;AAAA,IACT,UAAE;AACA,aAAO,IAAI,EAAE,OAAO,MAAM,QAAQ,QAAQ,SAAS,MAAM,IAAI,IAAI,OAAO;AAAA,IAC1E;AAAA,EACF;AACA,QAAM,UAAU,CAAC,SAAiB,MAAM,SAAS,KAAK,CAAC,eAAW,8BAAe,QAAQ,IAAI,CAAC;AAC9F,SAAO;AAAA,IACL,KAAK,CAAC,MAAM;AACV,UAAI,EAAE,UAAU,MAAM,MAAO,QAAO,EAAE,QAAQ;AAC9C,UAAI,EAAE,SAAS,WAAW,UAAW,QAAO,YAAY,GAAG,OAAO,EAAE,MAAM,MAAM,mBAAmB;AACnG,YAAM,SAAS,QAAQ,EAAE,IAAI;AAC7B,aAAO,YAAY,GAAG,OAAO,EAAE,MAAM,UAAU,MAAM,WAAW,SAAY,gBAAgB,eAAe;AAAA,IAC7G;AAAA,IACA,MAAM,CAAC,MAAM;AACX,UAAI,EAAE,UAAU,MAAM,MAAO,QAAO,EAAE,QAAQ;AAC9C,UAAI,EAAE,SAAS,WAAW,UAAW,QAAO,YAAY,GAAG,QAAQ,EAAE,UAAU,MAAM,mBAAmB;AACxG,UAAI,EAAE,SAAS,QAAQ,WAAW,OAAO,GAAG;AAC1C,eAAO,QAAQ,EAAE,OAAO,EAAE,UAAU,MAAM,kBAAkB,SAAS,CAAC;AACtE,eAAO,QAAQ,QAAQ,EAAE,IAAI,OAAO,OAAO;AAAA,UACzC,MAAM;AAAA,UAAiB,SAAS;AAAA,UAChC,SAAS;AAAA,UAAM,MAAM,EAAE,aAAa,iBAAiB;AAAA,QACvD,EAAE,CAAC;AAAA,MACL;AACA,UAAI,EAAE,SAAS,OAAQ,QAAO,YAAY,GAAG,QAAQ,EAAE,UAAU,MAAM,gBAAgB;AACvF,UAAI,EAAE,SAAS,IAAK,QAAO,YAAY,GAAG,QAAQ,EAAE,UAAU,MAAM,oBAAoB;AACxF,YAAM,SAAS,QAAQ,EAAE,QAAQ;AACjC,aAAO,YAAY,GAAG,QAAQ,EAAE,UAAU,UAAU,MAAM,WAAW,SAAY,gBAAgB,eAAe;AAAA,IAClH;AAAA,IACA,OAAO,CAAC,MAAM,EAAE,QAAQ;AAAA,IACxB,yBAAyB,CAAC,MAAM;AAC9B,UAAI,EAAE,UAAU,MAAM,MAAO,QAAO,EAAE,IAAI,EAAE,OAAO,EAAE,MAAM,MAAM,EAAE,QAAQ,EAAE,SAAS,EAAE,SAAS;AAAA,IACnG;AAAA,EACF;AACF;","names":[]}
@@ -0,0 +1,2 @@
1
+ import '@tinycloud/sdk-services';
2
+ export { c as createGatedNetworkReadThrough } from '../gated-network-BEF2XSTC.cjs';
@@ -0,0 +1,2 @@
1
+ import '@tinycloud/sdk-services';
2
+ export { c as createGatedNetworkReadThrough } from '../gated-network-BEF2XSTC.js';
@@ -0,0 +1,65 @@
1
+ // src/replication/gated-network.ts
2
+ import { kvPrefixCovers } from "@tinycloud/sdk-services/kv/replication/prefix";
3
+ function createGatedNetworkReadThrough(input) {
4
+ const report = (op, space, path, replica, reason, outcome, latencyMs) => input.emit({
5
+ type: "replication.read",
6
+ at: new Date(input.now()).toISOString(),
7
+ op,
8
+ space,
9
+ key: path,
10
+ replica,
11
+ source: reason === "cursor_restart" ? "none" : "network",
12
+ reason,
13
+ outcome,
14
+ latencyMs,
15
+ stalenessMs: null,
16
+ coverage: null,
17
+ authority: null,
18
+ ...reason === "replica_gated" ? { code: "REPLICA_GATED" } : {}
19
+ });
20
+ const readNetwork = async (r, op, path, prefix, reason) => {
21
+ const started = input.now();
22
+ let outcome = "error";
23
+ try {
24
+ const result = await r.network();
25
+ outcome = result.ok ? "found" : op === "get" && reason === "not_covered" && "error" in result && result.error.code === "KV_NOT_FOUND" ? "not_found" : "error";
26
+ return result;
27
+ } finally {
28
+ report(op, r.space, path, prefix, reason, outcome, input.now() - started);
29
+ }
30
+ };
31
+ const covered = (path) => input.prefixes.find((prefix) => kvPrefixCovers(prefix, path));
32
+ return {
33
+ get: (r) => {
34
+ if (r.space !== input.space) return r.network();
35
+ if (r.options?.source === "network") return readNetwork(r, "get", r.path, null, "NETWORK_REQUESTED");
36
+ const prefix = covered(r.path);
37
+ return readNetwork(r, "get", r.path, prefix ?? null, prefix === void 0 ? "not_covered" : "replica_gated");
38
+ },
39
+ list: (r) => {
40
+ if (r.space !== input.space) return r.network();
41
+ if (r.options?.source === "network") return readNetwork(r, "list", r.listPath, null, "NETWORK_REQUESTED");
42
+ if (r.options?.cursor?.startsWith("tcr1.")) {
43
+ report("list", r.space, r.listPath, null, "cursor_restart", "error", 0);
44
+ return Promise.resolve({ ok: false, error: {
45
+ code: "INVALID_INPUT",
46
+ message: "Local list cursor cannot be served; restart without the cursor",
47
+ service: "kv",
48
+ meta: { replication: "cursor_restart" }
49
+ } });
50
+ }
51
+ if (r.options?.cursor) return readNetwork(r, "list", r.listPath, null, "network_cursor");
52
+ if (r.options?.raw) return readNetwork(r, "list", r.listPath, null, "unsupported_option");
53
+ const prefix = covered(r.listPath);
54
+ return readNetwork(r, "list", r.listPath, prefix ?? null, prefix === void 0 ? "not_covered" : "replica_gated");
55
+ },
56
+ write: (r) => r.network(),
57
+ observeNetworkRequested: (r) => {
58
+ if (r.space === input.space) report(r.op, r.space, r.path, null, r.reason, r.outcome, r.latencyMs);
59
+ }
60
+ };
61
+ }
62
+ export {
63
+ createGatedNetworkReadThrough
64
+ };
65
+ //# sourceMappingURL=gated-network.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../../src/replication/gated-network.ts"],"sourcesContent":["import { kvPrefixCovers } from \"@tinycloud/sdk-services/kv/replication/prefix\";\nimport type { KVReadThrough, ReplicationEvent } from \"@tinycloud/sdk-services\";\n\n/** Loaded only after a refused restore. No replica storage, authority, or worker access. */\nexport function createGatedNetworkReadThrough(input: {\n space: string;\n prefixes: readonly string[];\n now: () => number;\n emit: (event: ReplicationEvent) => void;\n}): KVReadThrough {\n const report = (\n op: \"get\" | \"list\", space: string, path: string, replica: string | null,\n reason: \"replica_gated\" | \"not_covered\" | \"unsupported_option\" | \"network_cursor\" | \"NETWORK_REQUESTED\" | \"cursor_restart\",\n outcome: \"found\" | \"not_found\" | \"error\", latencyMs: number,\n ) => input.emit({\n type: \"replication.read\", at: new Date(input.now()).toISOString(), op, space, key: path,\n replica, source: reason === \"cursor_restart\" ? \"none\" : \"network\", reason, outcome, latencyMs,\n stalenessMs: null, coverage: null, authority: null,\n ...(reason === \"replica_gated\" ? { code: \"REPLICA_GATED\" } : {}),\n });\n const readNetwork = async <T extends { ok: boolean }>(\n r: { space: string; network: () => Promise<T> }, op: \"get\" | \"list\", path: string,\n prefix: string | null, reason: \"replica_gated\" | \"not_covered\" | \"unsupported_option\" | \"network_cursor\" | \"NETWORK_REQUESTED\",\n ): Promise<T> => {\n const started = input.now();\n let outcome: \"found\" | \"not_found\" | \"error\" = \"error\";\n try {\n const result = await r.network();\n outcome = result.ok ? \"found\" : op === \"get\" && reason === \"not_covered\" && \"error\" in result &&\n (result.error as { code?: string }).code === \"KV_NOT_FOUND\" ? \"not_found\" : \"error\";\n return result;\n } finally {\n report(op, r.space, path, prefix, reason, outcome, input.now() - started);\n }\n };\n const covered = (path: string) => input.prefixes.find((prefix) => kvPrefixCovers(prefix, path));\n return {\n get: (r) => {\n if (r.space !== input.space) return r.network();\n if (r.options?.source === \"network\") return readNetwork(r, \"get\", r.path, null, \"NETWORK_REQUESTED\");\n const prefix = covered(r.path);\n return readNetwork(r, \"get\", r.path, prefix ?? null, prefix === undefined ? \"not_covered\" : \"replica_gated\");\n },\n list: (r) => {\n if (r.space !== input.space) return r.network();\n if (r.options?.source === \"network\") return readNetwork(r, \"list\", r.listPath, null, \"NETWORK_REQUESTED\");\n if (r.options?.cursor?.startsWith(\"tcr1.\")) {\n report(\"list\", r.space, r.listPath, null, \"cursor_restart\", \"error\", 0);\n return Promise.resolve({ ok: false, error: {\n code: \"INVALID_INPUT\", message: \"Local list cursor cannot be served; restart without the cursor\",\n service: \"kv\", meta: { replication: \"cursor_restart\" },\n } });\n }\n if (r.options?.cursor) return readNetwork(r, \"list\", r.listPath, null, \"network_cursor\");\n if (r.options?.raw) return readNetwork(r, \"list\", r.listPath, null, \"unsupported_option\");\n const prefix = covered(r.listPath);\n return readNetwork(r, \"list\", r.listPath, prefix ?? null, prefix === undefined ? \"not_covered\" : \"replica_gated\");\n },\n write: (r) => r.network(),\n observeNetworkRequested: (r) => {\n if (r.space === input.space) report(r.op, r.space, r.path, null, r.reason, r.outcome, r.latencyMs);\n },\n };\n}\n"],"mappings":";AAAA,SAAS,sBAAsB;AAIxB,SAAS,8BAA8B,OAK5B;AAChB,QAAM,SAAS,CACb,IAAoB,OAAe,MAAc,SACjD,QACA,SAA0C,cACvC,MAAM,KAAK;AAAA,IACd,MAAM;AAAA,IAAoB,IAAI,IAAI,KAAK,MAAM,IAAI,CAAC,EAAE,YAAY;AAAA,IAAG;AAAA,IAAI;AAAA,IAAO,KAAK;AAAA,IACnF;AAAA,IAAS,QAAQ,WAAW,mBAAmB,SAAS;AAAA,IAAW;AAAA,IAAQ;AAAA,IAAS;AAAA,IACpF,aAAa;AAAA,IAAM,UAAU;AAAA,IAAM,WAAW;AAAA,IAC9C,GAAI,WAAW,kBAAkB,EAAE,MAAM,gBAAgB,IAAI,CAAC;AAAA,EAChE,CAAC;AACD,QAAM,cAAc,OAClB,GAAiD,IAAoB,MACrE,QAAuB,WACR;AACf,UAAM,UAAU,MAAM,IAAI;AAC1B,QAAI,UAA2C;AAC/C,QAAI;AACF,YAAM,SAAS,MAAM,EAAE,QAAQ;AAC/B,gBAAU,OAAO,KAAK,UAAU,OAAO,SAAS,WAAW,iBAAiB,WAAW,UACpF,OAAO,MAA4B,SAAS,iBAAiB,cAAc;AAC9E,aAAO;AAAA,IACT,UAAE;AACA,aAAO,IAAI,EAAE,OAAO,MAAM,QAAQ,QAAQ,SAAS,MAAM,IAAI,IAAI,OAAO;AAAA,IAC1E;AAAA,EACF;AACA,QAAM,UAAU,CAAC,SAAiB,MAAM,SAAS,KAAK,CAAC,WAAW,eAAe,QAAQ,IAAI,CAAC;AAC9F,SAAO;AAAA,IACL,KAAK,CAAC,MAAM;AACV,UAAI,EAAE,UAAU,MAAM,MAAO,QAAO,EAAE,QAAQ;AAC9C,UAAI,EAAE,SAAS,WAAW,UAAW,QAAO,YAAY,GAAG,OAAO,EAAE,MAAM,MAAM,mBAAmB;AACnG,YAAM,SAAS,QAAQ,EAAE,IAAI;AAC7B,aAAO,YAAY,GAAG,OAAO,EAAE,MAAM,UAAU,MAAM,WAAW,SAAY,gBAAgB,eAAe;AAAA,IAC7G;AAAA,IACA,MAAM,CAAC,MAAM;AACX,UAAI,EAAE,UAAU,MAAM,MAAO,QAAO,EAAE,QAAQ;AAC9C,UAAI,EAAE,SAAS,WAAW,UAAW,QAAO,YAAY,GAAG,QAAQ,EAAE,UAAU,MAAM,mBAAmB;AACxG,UAAI,EAAE,SAAS,QAAQ,WAAW,OAAO,GAAG;AAC1C,eAAO,QAAQ,EAAE,OAAO,EAAE,UAAU,MAAM,kBAAkB,SAAS,CAAC;AACtE,eAAO,QAAQ,QAAQ,EAAE,IAAI,OAAO,OAAO;AAAA,UACzC,MAAM;AAAA,UAAiB,SAAS;AAAA,UAChC,SAAS;AAAA,UAAM,MAAM,EAAE,aAAa,iBAAiB;AAAA,QACvD,EAAE,CAAC;AAAA,MACL;AACA,UAAI,EAAE,SAAS,OAAQ,QAAO,YAAY,GAAG,QAAQ,EAAE,UAAU,MAAM,gBAAgB;AACvF,UAAI,EAAE,SAAS,IAAK,QAAO,YAAY,GAAG,QAAQ,EAAE,UAAU,MAAM,oBAAoB;AACxF,YAAM,SAAS,QAAQ,EAAE,QAAQ;AACjC,aAAO,YAAY,GAAG,QAAQ,EAAE,UAAU,UAAU,MAAM,WAAW,SAAY,gBAAgB,eAAe;AAAA,IAClH;AAAA,IACA,OAAO,CAAC,MAAM,EAAE,QAAQ;AAAA,IACxB,yBAAyB,CAAC,MAAM;AAC9B,UAAI,EAAE,UAAU,MAAM,MAAO,QAAO,EAAE,IAAI,EAAE,OAAO,EAAE,MAAM,MAAM,EAAE,QAAQ,EAAE,SAAS,EAAE,SAAS;AAAA,IACnG;AAAA,EACF;AACF;","names":[]}