@tinycloud/node-sdk 3.8.0-beta.1 → 3.8.0-beta.2
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.
- package/dist/{TinyCloudNode-Ckqu_fqH.d.ts → TinyCloudNode-B6VOBrCb.d.ts} +14 -1
- package/dist/{TinyCloudNode-DDfx8Fx5.d.cts → TinyCloudNode-CVO41O12.d.cts} +14 -1
- package/dist/{authority-DcyJpajL.d.ts → authority-DGi1hIMK.d.ts} +20 -4
- package/dist/{authority-BwM_s3Ya.d.cts → authority-DgVV80bI.d.cts} +20 -4
- package/dist/core.cjs +47 -13
- package/dist/core.cjs.map +1 -1
- package/dist/core.d.cts +3 -3
- package/dist/core.d.ts +3 -3
- package/dist/core.js +47 -13
- package/dist/core.js.map +1 -1
- package/dist/encryption-keys.d.cts +1 -1
- package/dist/encryption-keys.d.ts +1 -1
- package/dist/index.cjs +83 -14
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +2 -2
- package/dist/index.d.ts +2 -2
- package/dist/index.js +83 -14
- package/dist/index.js.map +1 -1
- package/dist/replication/authority.cjs +36 -0
- package/dist/replication/authority.cjs.map +1 -1
- package/dist/replication/authority.d.cts +2 -2
- package/dist/replication/authority.d.ts +2 -2
- package/dist/replication/authority.js +35 -0
- package/dist/replication/authority.js.map +1 -1
- package/dist/replication/runtime.cjs.map +1 -1
- package/dist/replication/runtime.d.cts +1 -1
- package/dist/replication/runtime.d.ts +1 -1
- package/dist/replication/runtime.js.map +1 -1
- package/dist/{runtime-v62FzQHz.d.ts → runtime-CO4VXnPq.d.ts} +2 -1
- package/dist/{runtime-D1o9Eybt.d.cts → runtime-mRhSu-vJ.d.cts} +2 -1
- package/package.json +4 -4
|
@@ -1,4 +1,4 @@
|
|
|
1
1
|
import '../gated-network-BEF2XSTC.cjs';
|
|
2
2
|
import '@tinycloud/sdk-core';
|
|
3
3
|
import '@tinycloud/sdk-services';
|
|
4
|
-
export { G as GatedReplicationRuntimeBinding, R as ReplicationRuntime, a as ReplicationRuntimeBinding, b as ReplicationRuntimeOptions } from '../runtime-
|
|
4
|
+
export { G as GatedReplicationRuntimeBinding, R as ReplicationRuntime, a as ReplicationRuntimeBinding, b as ReplicationRuntimeOptions } from '../runtime-mRhSu-vJ.cjs';
|
|
@@ -1,4 +1,4 @@
|
|
|
1
1
|
import '../gated-network-BEF2XSTC.js';
|
|
2
2
|
import '@tinycloud/sdk-core';
|
|
3
3
|
import '@tinycloud/sdk-services';
|
|
4
|
-
export { G as GatedReplicationRuntimeBinding, R as ReplicationRuntime, a as ReplicationRuntimeBinding, b as ReplicationRuntimeOptions } from '../runtime-
|
|
4
|
+
export { G as GatedReplicationRuntimeBinding, R as ReplicationRuntime, a as ReplicationRuntimeBinding, b as ReplicationRuntimeOptions } from '../runtime-CO4VXnPq.js';
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../../src/replication/runtime.ts"],"sourcesContent":["import { pkhDid } from \"@tinycloud/sdk-core\";\nimport type { FetchFunction, ServiceContext, ServiceSession } from \"@tinycloud/sdk-core\";\nimport type {\n KVReadThrough,\n KVReplicaStorage,\n KVReplicationController,\n PendingWriteStore,\n ReplicationAuthority,\n ReplicationControl,\n ReplicationEvent,\n ReplicaSessionStamp,\n ReplicationIdentity,\n ReplicationOptions,\n ReplicaGateReason,\n ReplicationScheduler,\n} from \"@tinycloud/sdk-services\";\n\ntype ReplicationServices = typeof import(\"@tinycloud/sdk-services/kv/replication\");\n\nexport interface ReplicationRuntimeOptions extends ReplicationOptions {\n storage: KVReplicaStorage;\n mode?: \"background\" | \"foreground\";\n}\n\nexport interface ReplicationRuntimeBinding {\n context: ServiceContext;\n session: ServiceSession;\n address?: string;\n chainId?: number;\n principal?: string;\n stamp?: ReplicaSessionStamp;\n authority: ReplicationAuthority;\n nodeFeatures?: readonly string[];\n primaryKV: Array<{ space: string; kv: { setReadThrough(readThrough: KVReadThrough | null): void } }>;\n}\nexport type GatedReplicationRuntimeBinding = Pick<ReplicationRuntimeBinding, \"context\" | \"session\" | \"primaryKV\"> & {\n gate: ReplicaGateReason;\n};\n\nconst scheduler: ReplicationScheduler = {\n now: () => Date.now(),\n setTimeout(fn, ms) {\n const timer = setTimeout(fn, ms);\n timer.unref?.();\n return () => clearTimeout(timer);\n },\n};\n\nfunction resolvedOptions(options: ReplicationRuntimeOptions) {\n return {\n ...options,\n syncIntervalMs: options.syncIntervalMs ?? 60_000,\n maxStalenessMs: options.maxStalenessMs ?? 120_000,\n staleSyncTimeoutMs: options.staleSyncTimeoutMs ?? 5_000,\n allowSecrets: options.allowSecrets === true,\n verify: options.verify === true,\n };\n}\ntype ReadThroughKV = {\n setReadThrough(readThrough: KVReadThrough | null): void;\n setReadThroughReady?(ready: Promise<unknown>): void;\n};\n\nexport class ReplicationRuntime {\n readonly control: ReplicationControl;\n private readonly pending = new Map<string, { stamp?: ReplicaSessionStamp; store: PendingWriteStore }>();\n private readonly attached = new Map<ReadThroughKV, string>();\n private current?: KVReplicationController;\n private gated?: KVReadThrough;\n private gatedReason?: ReplicaGateReason;\n private lastController?: KVReplicationController;\n private unsubscribeConsentExpired?: () => void;\n private previous: Promise<void> = Promise.resolve();\n private binding: Promise<void> = Promise.resolve();\n private services?: Promise<ReplicationServices>;\n private generation = 0;\n private lastIdentity?: ReplicationIdentity;\n private lastPending?: PendingWriteStore;\n private primarySpace?: string;\n private pendingPurge?: Parameters<KVReplicationController[\"purge\"]>[0];\n private pendingPurgeResult?: ReturnType<KVReplicationController[\"purge\"]>;\n private bindingActive = false;\n private pendingPurgeSet = false;\n private purgedGeneration?: number;\n private closed = false;\n constructor(\n private readonly options: ReplicationRuntimeOptions,\n private readonly clock: ReplicationScheduler = scheduler,\n ) {\n this.control = {\n status: async () => {\n await this.binding;\n if (this.gatedReason) return this.options.prefixes.map((prefix) => ({\n prefix, state: \"gated\" as const, gate: this.gatedReason, errorCode: \"REPLICA_GATED\",\n pending: { inFlight: 0, committed: 0, ambiguous: 0 }, pinned: [], lagMs: null,\n }));\n return this.current ? this.current.status() : [];\n },\n sync: async (input) => {\n await this.binding;\n if (this.gatedReason) throw Object.assign(new Error(\"Replica restore is gated.\"), {\n code: \"REPLICA_GATED\", gate: this.gatedReason,\n });\n if (this.purgedGeneration === this.generation) return;\n if (this.current) await this.current.sync(input);\n },\n purge: (input) => {\n if (this.bindingActive) {\n this.pendingPurge = input;\n this.pendingPurgeSet = true;\n const existing = this.current ?? this.lastController;\n if (existing) {\n this.pendingPurgeResult = existing.purge(input);\n this.purgedGeneration = this.generation;\n }\n return this.binding.then(() => this.pendingPurgeResult ?? { purged: [], failed: [] });\n }\n const controller = this.current ?? this.lastController;\n if (!controller) return Promise.resolve({ purged: [], failed: [] });\n this.purgedGeneration = this.generation;\n return controller.purge(input);\n },\n clearPending: async () => {\n await this.binding;\n if (this.current) return this.current.clearPending();\n const pending = this.lastPending;\n if (!pending) return 0;\n return pending.update((state) => {\n const before = state.records.length;\n state.records = state.records.filter((record) =>\n record.state === \"committed\" ||\n (record.state === \"in_flight\" && this.clock.now() - Date.parse(record.at) <= 10 * 60_000),\n );\n return before - state.records.length;\n });\n },\n close: async () => {\n this.closed = true;\n this.unbind();\n await this.binding.catch(() => undefined);\n await this.previous;\n },\n };\n }\n\n private loadServices(): Promise<ReplicationServices> {\n return (this.services ??= import(\"@tinycloud/sdk-services/kv/replication\"));\n }\n\n private detachAll(): void {\n for (const kv of this.attached.keys()) kv.setReadThrough(null);\n this.attached.clear();\n }\n\n /** Observe a refused restore without opening replica state; loader failure leaves raw network KV usable. */\n bindGatedNetworkOnly(\n input: GatedReplicationRuntimeBinding,\n loadGatedNetwork: () => Promise<typeof import(\"./gated-network\")>,\n ): Promise<void> {\n if (this.closed || !this.options.enabled) return Promise.resolve();\n const retired = this.unbind();\n const generation = this.generation;\n this.purgedGeneration = undefined;\n this.pendingPurge = undefined;\n this.pendingPurgeResult = undefined;\n this.pending.clear();\n this.lastController = undefined;\n this.lastPending = undefined;\n this.lastIdentity = undefined;\n this.gatedReason = input.gate;\n this.primarySpace = input.session.spaceId;\n this.binding = retired.then(async () => {\n let create: typeof import(\"./gated-network\").createGatedNetworkReadThrough;\n try {\n ({ createGatedNetworkReadThrough: create } = await loadGatedNetwork());\n } catch {\n // Refusal already gates local delivery; a missing observer cannot end a network session.\n return;\n }\n if (generation !== this.generation || this.closed || typeof create !== \"function\") return;\n const networkOnly = create({\n space: input.session.spaceId,\n prefixes: this.options.prefixes,\n now: () => this.clock.now(),\n emit: (event) => {\n if (generation !== this.generation || this.closed || this.gated !== networkOnly) return;\n try { this.options.onEvent?.(event); } catch { /* Telemetry cannot change network results. */ }\n const { type, ...data } = event;\n try { input.context.emit(type, data); } catch { /* Telemetry cannot change network results. */ }\n },\n });\n this.gated = networkOnly;\n for (const scoped of input.primaryKV) this.attach(scoped.space, scoped.kv);\n });\n return this.binding;\n }\n\n bind(input: ReplicationRuntimeBinding): Promise<void> {\n if (this.closed || !this.options.enabled) return Promise.resolve();\n this.gated = undefined;\n this.gatedReason = undefined;\n this.bindingActive = true;\n const generation = ++this.generation;\n this.purgedGeneration = undefined;\n this.unsubscribeConsentExpired?.();\n this.unsubscribeConsentExpired = undefined;\n const { context, session } = input;\n const emit = (event: ReplicationEvent): void => {\n try { this.options.onEvent?.(event); } catch { /* Observability must not affect KV behavior. */ }\n const { type, ...data } = event;\n context.emit(type, data);\n };\n const previous = this.current;\n this.current = undefined;\n for (const kv of this.attached.keys()) kv.setReadThrough(null);\n this.primarySpace = session.spaceId;\n const close = previous ? previous.close().catch(() => undefined) : Promise.resolve();\n this.previous = this.previous.then(() => close);\n const previousClose = this.previous;\n this.binding = this.loadServices().then((services) => {\n if (generation !== this.generation || this.closed) return;\n let identity: ReplicationIdentity;\n try {\n identity = services.canonicalReplicationIdentity({\n host: context.hosts[0]!,\n space: session.spaceId,\n principal: input.principal ?? pkhDid(input.address!, input.chainId!),\n });\n } catch {\n for (const prefix of this.options.prefixes) {\n emit({ type: \"replication.state\", at: new Date(this.clock.now()).toISOString(), space: session.spaceId, replica: prefix, state: \"unavailable\", code: \"CONFIG_INVALID\" });\n }\n return;\n }\n const key = services.replicationIdentityKey(identity);\n let cached = this.pending.get(key);\n const stamp = input.stamp;\n if (!cached || cached.stamp?.incarnation !== stamp?.incarnation || cached.stamp?.lifecycleEpoch !== stamp?.lifecycleEpoch) {\n const store = this.options.storage.pendingWrites?.(identity, { stamp });\n if (!store && this.options.storage.lifecycle) {\n throw Object.assign(new Error(\"Gated replication requires a stamped pending store\"), { code: \"REPLICA_GATED\", gate: \"gate_unavailable\" });\n }\n cached = { stamp, store: store ?? services.createMemoryPendingStore(identity) };\n this.pending.set(key, cached);\n }\n const pending = cached.store;\n this.lastPending = pending;\n const controller = services.createKVReplication({\n options: resolvedOptions(this.options),\n mode: this.options.mode ?? \"background\",\n storage: this.options.storage,\n identity,\n session: { id: session.delegationCid, did: session.verificationMethod, space: session.spaceId },\n stamp: input.stamp,\n authority: input.authority,\n pending,\n scheduler: this.clock,\n emit,\n fetch: context.fetch as FetchFunction,\n nodeFeatures: input.nodeFeatures,\n previous: previousClose,\n });\n this.current = controller;\n this.unsubscribeConsentExpired = this.options.storage.lifecycle?.subscribeConsentExpired?.(\n (stamp) => controller.observeConsentExpired(stamp),\n );\n this.lastController = controller;\n this.lastIdentity = identity;\n for (const [kv, space] of this.attached) {\n kv.setReadThrough(space === this.primarySpace ? controller : null);\n }\n for (const scoped of input.primaryKV) this.attach(scoped.space, scoped.kv);\n if (this.pendingPurgeSet) {\n this.pendingPurgeResult = controller.purge(this.pendingPurge);\n this.purgedGeneration = generation;\n this.pendingPurge = undefined;\n this.pendingPurgeSet = false;\n }\n }).finally(() => {\n if (generation === this.generation) this.bindingActive = false;\n });\n for (const kv of this.attached.keys()) kv.setReadThroughReady?.(this.binding);\n return this.binding;\n }\n\n attach(space: string, kv: ReadThroughKV): Promise<void> {\n this.attached.set(kv, space);\n kv.setReadThrough(space === this.primarySpace ? this.current ?? this.gated ?? null : null);\n const generation = this.generation;\n return this.binding.then(() => {\n if (generation === this.generation && !this.closed && this.attached.get(kv) === space) {\n kv.setReadThrough(space === this.primarySpace ? this.current ?? this.gated ?? null : null);\n }\n });\n }\n\n unbind(): Promise<void> {\n this.generation++;\n this.bindingActive = false;\n this.pendingPurgeSet = false;\n this.unsubscribeConsentExpired?.();\n this.unsubscribeConsentExpired = undefined;\n const controller = this.current;\n this.current = undefined;\n this.gated = undefined;\n this.gatedReason = undefined;\n this.primarySpace = undefined;\n this.detachAll();\n const binding = this.binding;\n const close = binding.then(() => controller?.close()).catch(() => undefined);\n this.previous = this.previous.then(() => close);\n return this.previous;\n }\n\n get boundIdentity(): ReplicationIdentity | undefined {\n return this.lastIdentity;\n }\n}\n"],"mappings":";AAAA,SAAS,cAAc;AAuCvB,IAAM,YAAkC;AAAA,EACtC,KAAK,MAAM,KAAK,IAAI;AAAA,EACpB,WAAW,IAAI,IAAI;AACjB,UAAM,QAAQ,WAAW,IAAI,EAAE;AAC/B,UAAM,QAAQ;AACd,WAAO,MAAM,aAAa,KAAK;AAAA,EACjC;AACF;AAEA,SAAS,gBAAgB,SAAoC;AAC3D,SAAO;AAAA,IACL,GAAG;AAAA,IACH,gBAAgB,QAAQ,kBAAkB;AAAA,IAC1C,gBAAgB,QAAQ,kBAAkB;AAAA,IAC1C,oBAAoB,QAAQ,sBAAsB;AAAA,IAClD,cAAc,QAAQ,iBAAiB;AAAA,IACvC,QAAQ,QAAQ,WAAW;AAAA,EAC7B;AACF;AAMO,IAAM,qBAAN,MAAyB;AAAA,EAsB9B,YACmB,SACA,QAA8B,WAC/C;AAFiB;AACA;AAtBnB,SAAiB,UAAU,oBAAI,IAAuE;AACtG,SAAiB,WAAW,oBAAI,IAA2B;AAM3D,SAAQ,WAA0B,QAAQ,QAAQ;AAClD,SAAQ,UAAyB,QAAQ,QAAQ;AAEjD,SAAQ,aAAa;AAMrB,SAAQ,gBAAgB;AACxB,SAAQ,kBAAkB;AAE1B,SAAQ,SAAS;AAKf,SAAK,UAAU;AAAA,MACb,QAAQ,YAAY;AAClB,cAAM,KAAK;AACX,YAAI,KAAK,YAAa,QAAO,KAAK,QAAQ,SAAS,IAAI,CAAC,YAAY;AAAA,UAClE;AAAA,UAAQ,OAAO;AAAA,UAAkB,MAAM,KAAK;AAAA,UAAa,WAAW;AAAA,UACpE,SAAS,EAAE,UAAU,GAAG,WAAW,GAAG,WAAW,EAAE;AAAA,UAAG,QAAQ,CAAC;AAAA,UAAG,OAAO;AAAA,QAC3E,EAAE;AACF,eAAO,KAAK,UAAU,KAAK,QAAQ,OAAO,IAAI,CAAC;AAAA,MACjD;AAAA,MACA,MAAM,OAAO,UAAU;AACrB,cAAM,KAAK;AACX,YAAI,KAAK,YAAa,OAAM,OAAO,OAAO,IAAI,MAAM,2BAA2B,GAAG;AAAA,UAChF,MAAM;AAAA,UAAiB,MAAM,KAAK;AAAA,QACpC,CAAC;AACD,YAAI,KAAK,qBAAqB,KAAK,WAAY;AAC/C,YAAI,KAAK,QAAS,OAAM,KAAK,QAAQ,KAAK,KAAK;AAAA,MACjD;AAAA,MACA,OAAO,CAAC,UAAU;AAChB,YAAI,KAAK,eAAe;AACtB,eAAK,eAAe;AACpB,eAAK,kBAAkB;AACvB,gBAAM,WAAW,KAAK,WAAW,KAAK;AACtC,cAAI,UAAU;AACZ,iBAAK,qBAAqB,SAAS,MAAM,KAAK;AAC9C,iBAAK,mBAAmB,KAAK;AAAA,UAC/B;AACA,iBAAO,KAAK,QAAQ,KAAK,MAAM,KAAK,sBAAsB,EAAE,QAAQ,CAAC,GAAG,QAAQ,CAAC,EAAE,CAAC;AAAA,QACtF;AACA,cAAM,aAAa,KAAK,WAAW,KAAK;AACxC,YAAI,CAAC,WAAY,QAAO,QAAQ,QAAQ,EAAE,QAAQ,CAAC,GAAG,QAAQ,CAAC,EAAE,CAAC;AAClE,aAAK,mBAAmB,KAAK;AAC7B,eAAO,WAAW,MAAM,KAAK;AAAA,MAC/B;AAAA,MACA,cAAc,YAAY;AACxB,cAAM,KAAK;AACX,YAAI,KAAK,QAAS,QAAO,KAAK,QAAQ,aAAa;AACnD,cAAM,UAAU,KAAK;AACrB,YAAI,CAAC,QAAS,QAAO;AACrB,eAAO,QAAQ,OAAO,CAAC,UAAU;AAC/B,gBAAM,SAAS,MAAM,QAAQ;AAC7B,gBAAM,UAAU,MAAM,QAAQ;AAAA,YAAO,CAAC,WACpC,OAAO,UAAU,eAChB,OAAO,UAAU,eAAe,KAAK,MAAM,IAAI,IAAI,KAAK,MAAM,OAAO,EAAE,KAAK,KAAK;AAAA,UACpF;AACA,iBAAO,SAAS,MAAM,QAAQ;AAAA,QAChC,CAAC;AAAA,MACH;AAAA,MACA,OAAO,YAAY;AACjB,aAAK,SAAS;AACd,aAAK,OAAO;AACZ,cAAM,KAAK,QAAQ,MAAM,MAAM,MAAS;AACxC,cAAM,KAAK;AAAA,MACb;AAAA,IACF;AAAA,EACF;AAAA,EAEQ,eAA6C;AACnD,WAAQ,KAAK,aAAL,KAAK,WAAa,OAAO,wCAAwC;AAAA,EAC3E;AAAA,EAEQ,YAAkB;AACxB,eAAW,MAAM,KAAK,SAAS,KAAK,EAAG,IAAG,eAAe,IAAI;AAC7D,SAAK,SAAS,MAAM;AAAA,EACtB;AAAA;AAAA,EAGA,qBACE,OACA,kBACe;AACf,QAAI,KAAK,UAAU,CAAC,KAAK,QAAQ,QAAS,QAAO,QAAQ,QAAQ;AACjE,UAAM,UAAU,KAAK,OAAO;AAC5B,UAAM,aAAa,KAAK;AACxB,SAAK,mBAAmB;AACxB,SAAK,eAAe;AACpB,SAAK,qBAAqB;AAC1B,SAAK,QAAQ,MAAM;AACnB,SAAK,iBAAiB;AACtB,SAAK,cAAc;AACnB,SAAK,eAAe;AACpB,SAAK,cAAc,MAAM;AACzB,SAAK,eAAe,MAAM,QAAQ;AAClC,SAAK,UAAU,QAAQ,KAAK,YAAY;AACtC,UAAI;AACJ,UAAI;AACF,SAAC,EAAE,+BAA+B,OAAO,IAAI,MAAM,iBAAiB;AAAA,MACtE,QAAQ;AAEN;AAAA,MACF;AACA,UAAI,eAAe,KAAK,cAAc,KAAK,UAAU,OAAO,WAAW,WAAY;AACnF,YAAM,cAAc,OAAO;AAAA,QACzB,OAAO,MAAM,QAAQ;AAAA,QACrB,UAAU,KAAK,QAAQ;AAAA,QACvB,KAAK,MAAM,KAAK,MAAM,IAAI;AAAA,QAC1B,MAAM,CAAC,UAAU;AACf,cAAI,eAAe,KAAK,cAAc,KAAK,UAAU,KAAK,UAAU,YAAa;AACjF,cAAI;AAAE,iBAAK,QAAQ,UAAU,KAAK;AAAA,UAAG,QAAQ;AAAA,UAAiD;AAC9F,gBAAM,EAAE,MAAM,GAAG,KAAK,IAAI;AAC1B,cAAI;AAAE,kBAAM,QAAQ,KAAK,MAAM,IAAI;AAAA,UAAG,QAAQ;AAAA,UAAiD;AAAA,QACjG;AAAA,MACF,CAAC;AACD,WAAK,QAAQ;AACb,iBAAW,UAAU,MAAM,UAAW,MAAK,OAAO,OAAO,OAAO,OAAO,EAAE;AAAA,IAC3E,CAAC;AACD,WAAO,KAAK;AAAA,EACd;AAAA,EAEA,KAAK,OAAiD;AACpD,QAAI,KAAK,UAAU,CAAC,KAAK,QAAQ,QAAS,QAAO,QAAQ,QAAQ;AACjE,SAAK,QAAQ;AACb,SAAK,cAAc;AACnB,SAAK,gBAAgB;AACrB,UAAM,aAAa,EAAE,KAAK;AAC1B,SAAK,mBAAmB;AACxB,SAAK,4BAA4B;AACjC,SAAK,4BAA4B;AACjC,UAAM,EAAE,SAAS,QAAQ,IAAI;AAC7B,UAAM,OAAO,CAAC,UAAkC;AAC9C,UAAI;AAAE,aAAK,QAAQ,UAAU,KAAK;AAAA,MAAG,QAAQ;AAAA,MAAmD;AAChG,YAAM,EAAE,MAAM,GAAG,KAAK,IAAI;AAC1B,cAAQ,KAAK,MAAM,IAAI;AAAA,IACzB;AACA,UAAM,WAAW,KAAK;AACtB,SAAK,UAAU;AACf,eAAW,MAAM,KAAK,SAAS,KAAK,EAAG,IAAG,eAAe,IAAI;AAC7D,SAAK,eAAe,QAAQ;AAC5B,UAAM,QAAQ,WAAW,SAAS,MAAM,EAAE,MAAM,MAAM,MAAS,IAAI,QAAQ,QAAQ;AACnF,SAAK,WAAW,KAAK,SAAS,KAAK,MAAM,KAAK;AAC9C,UAAM,gBAAgB,KAAK;AAC3B,SAAK,UAAU,KAAK,aAAa,EAAE,KAAK,CAAC,aAAa;AACpD,UAAI,eAAe,KAAK,cAAc,KAAK,OAAQ;AACnD,UAAI;AACJ,UAAI;AACF,mBAAW,SAAS,6BAA6B;AAAA,UAC/C,MAAM,QAAQ,MAAM,CAAC;AAAA,UACrB,OAAO,QAAQ;AAAA,UACf,WAAW,MAAM,aAAa,OAAO,MAAM,SAAU,MAAM,OAAQ;AAAA,QACrE,CAAC;AAAA,MACH,QAAQ;AACN,mBAAW,UAAU,KAAK,QAAQ,UAAU;AAC1C,eAAK,EAAE,MAAM,qBAAqB,IAAI,IAAI,KAAK,KAAK,MAAM,IAAI,CAAC,EAAE,YAAY,GAAG,OAAO,QAAQ,SAAS,SAAS,QAAQ,OAAO,eAAe,MAAM,iBAAiB,CAAC;AAAA,QACzK;AACA;AAAA,MACF;AACA,YAAM,MAAM,SAAS,uBAAuB,QAAQ;AACpD,UAAI,SAAS,KAAK,QAAQ,IAAI,GAAG;AACjC,YAAM,QAAQ,MAAM;AACpB,UAAI,CAAC,UAAU,OAAO,OAAO,gBAAgB,OAAO,eAAe,OAAO,OAAO,mBAAmB,OAAO,gBAAgB;AACzH,cAAM,QAAQ,KAAK,QAAQ,QAAQ,gBAAgB,UAAU,EAAE,MAAM,CAAC;AACtE,YAAI,CAAC,SAAS,KAAK,QAAQ,QAAQ,WAAW;AAC5C,gBAAM,OAAO,OAAO,IAAI,MAAM,oDAAoD,GAAG,EAAE,MAAM,iBAAiB,MAAM,mBAAmB,CAAC;AAAA,QAC1I;AACA,iBAAS,EAAE,OAAO,OAAO,SAAS,SAAS,yBAAyB,QAAQ,EAAE;AAC9E,aAAK,QAAQ,IAAI,KAAK,MAAM;AAAA,MAC9B;AACA,YAAM,UAAU,OAAO;AACvB,WAAK,cAAc;AACnB,YAAM,aAAa,SAAS,oBAAoB;AAAA,QAC9C,SAAS,gBAAgB,KAAK,OAAO;AAAA,QACrC,MAAM,KAAK,QAAQ,QAAQ;AAAA,QAC3B,SAAS,KAAK,QAAQ;AAAA,QACtB;AAAA,QACA,SAAS,EAAE,IAAI,QAAQ,eAAe,KAAK,QAAQ,oBAAoB,OAAO,QAAQ,QAAQ;AAAA,QAC9F,OAAO,MAAM;AAAA,QACb,WAAW,MAAM;AAAA,QACjB;AAAA,QACA,WAAW,KAAK;AAAA,QAChB;AAAA,QACA,OAAO,QAAQ;AAAA,QACf,cAAc,MAAM;AAAA,QACpB,UAAU;AAAA,MACZ,CAAC;AACD,WAAK,UAAU;AACf,WAAK,4BAA4B,KAAK,QAAQ,QAAQ,WAAW;AAAA,QAC/D,CAACA,WAAU,WAAW,sBAAsBA,MAAK;AAAA,MACnD;AACA,WAAK,iBAAiB;AACtB,WAAK,eAAe;AACpB,iBAAW,CAAC,IAAI,KAAK,KAAK,KAAK,UAAU;AACvC,WAAG,eAAe,UAAU,KAAK,eAAe,aAAa,IAAI;AAAA,MACnE;AACA,iBAAW,UAAU,MAAM,UAAW,MAAK,OAAO,OAAO,OAAO,OAAO,EAAE;AACzE,UAAI,KAAK,iBAAiB;AACxB,aAAK,qBAAqB,WAAW,MAAM,KAAK,YAAY;AAC5D,aAAK,mBAAmB;AACxB,aAAK,eAAe;AACpB,aAAK,kBAAkB;AAAA,MACzB;AAAA,IACF,CAAC,EAAE,QAAQ,MAAM;AACf,UAAI,eAAe,KAAK,WAAY,MAAK,gBAAgB;AAAA,IAC3D,CAAC;AACD,eAAW,MAAM,KAAK,SAAS,KAAK,EAAG,IAAG,sBAAsB,KAAK,OAAO;AAC5E,WAAO,KAAK;AAAA,EACd;AAAA,EAEA,OAAO,OAAe,IAAkC;AACtD,SAAK,SAAS,IAAI,IAAI,KAAK;AAC3B,OAAG,eAAe,UAAU,KAAK,eAAe,KAAK,WAAW,KAAK,SAAS,OAAO,IAAI;AACzF,UAAM,aAAa,KAAK;AACxB,WAAO,KAAK,QAAQ,KAAK,MAAM;AAC7B,UAAI,eAAe,KAAK,cAAc,CAAC,KAAK,UAAU,KAAK,SAAS,IAAI,EAAE,MAAM,OAAO;AACrF,WAAG,eAAe,UAAU,KAAK,eAAe,KAAK,WAAW,KAAK,SAAS,OAAO,IAAI;AAAA,MAC3F;AAAA,IACF,CAAC;AAAA,EACH;AAAA,EAEA,SAAwB;AACtB,SAAK;AACL,SAAK,gBAAgB;AACrB,SAAK,kBAAkB;AACvB,SAAK,4BAA4B;AACjC,SAAK,4BAA4B;AACjC,UAAM,aAAa,KAAK;AACxB,SAAK,UAAU;AACf,SAAK,QAAQ;AACb,SAAK,cAAc;AACnB,SAAK,eAAe;AACpB,SAAK,UAAU;AACf,UAAM,UAAU,KAAK;AACrB,UAAM,QAAQ,QAAQ,KAAK,MAAM,YAAY,MAAM,CAAC,EAAE,MAAM,MAAM,MAAS;AAC3E,SAAK,WAAW,KAAK,SAAS,KAAK,MAAM,KAAK;AAC9C,WAAO,KAAK;AAAA,EACd;AAAA,EAEA,IAAI,gBAAiD;AACnD,WAAO,KAAK;AAAA,EACd;AACF;","names":["stamp"]}
|
|
1
|
+
{"version":3,"sources":["../../src/replication/runtime.ts"],"sourcesContent":["import { pkhDid } from \"@tinycloud/sdk-core\";\nimport type { FetchFunction, ServiceContext, ServiceSession } from \"@tinycloud/sdk-core\";\nimport type {\n KVReadThrough,\n KVReplicaStorage,\n KVReplicationController,\n PendingWriteStore,\n ReplicationAuthority,\n ReplicationControl,\n ReplicationEvent,\n ReplicaSessionStamp,\n ReplicationIdentity,\n ReplicationOptions,\n ReplicaGateReason,\n ReplicationScheduler,\n} from \"@tinycloud/sdk-services\";\n\ntype ReplicationServices = typeof import(\"@tinycloud/sdk-services/kv/replication\");\n\nexport interface ReplicationRuntimeOptions extends ReplicationOptions {\n storage: KVReplicaStorage;\n mode?: \"background\" | \"foreground\";\n}\n\nexport interface ReplicationRuntimeBinding {\n context: ServiceContext;\n session: ServiceSession;\n address?: string;\n chainId?: number;\n principal?: string;\n stamp?: ReplicaSessionStamp;\n authority: ReplicationAuthority;\n nodeFeatures?: readonly string[];\n primaryKV: Array<{ space: string; kv: { setReadThrough(readThrough: KVReadThrough | null): void } }>;\n}\nexport type GatedReplicationRuntimeBinding = Pick<ReplicationRuntimeBinding, \"context\" | \"session\" | \"primaryKV\"> & {\n gate: ReplicaGateReason;\n};\n\nconst scheduler: ReplicationScheduler = {\n now: () => Date.now(),\n setTimeout(fn, ms) {\n const timer = setTimeout(fn, ms);\n timer.unref?.();\n return () => clearTimeout(timer);\n },\n};\n\nfunction resolvedOptions(options: ReplicationRuntimeOptions) {\n return {\n ...options,\n syncIntervalMs: options.syncIntervalMs ?? 60_000,\n maxStalenessMs: options.maxStalenessMs ?? 120_000,\n staleSyncTimeoutMs: options.staleSyncTimeoutMs ?? 5_000,\n allowSecrets: options.allowSecrets === true,\n verify: options.verify === true,\n };\n}\ntype ReadThroughKV = {\n setReadThrough(readThrough: KVReadThrough | null): void;\n setReadThroughReady?(ready: Promise<unknown>): void;\n};\n\nexport class ReplicationRuntime {\n /** The node facade adds `purgeLocalCopy`: it needs the node's deny state, not the runtime's. */\n readonly control: Omit<ReplicationControl, \"purgeLocalCopy\">;\n private readonly pending = new Map<string, { stamp?: ReplicaSessionStamp; store: PendingWriteStore }>();\n private readonly attached = new Map<ReadThroughKV, string>();\n private current?: KVReplicationController;\n private gated?: KVReadThrough;\n private gatedReason?: ReplicaGateReason;\n private lastController?: KVReplicationController;\n private unsubscribeConsentExpired?: () => void;\n private previous: Promise<void> = Promise.resolve();\n private binding: Promise<void> = Promise.resolve();\n private services?: Promise<ReplicationServices>;\n private generation = 0;\n private lastIdentity?: ReplicationIdentity;\n private lastPending?: PendingWriteStore;\n private primarySpace?: string;\n private pendingPurge?: Parameters<KVReplicationController[\"purge\"]>[0];\n private pendingPurgeResult?: ReturnType<KVReplicationController[\"purge\"]>;\n private bindingActive = false;\n private pendingPurgeSet = false;\n private purgedGeneration?: number;\n private closed = false;\n constructor(\n private readonly options: ReplicationRuntimeOptions,\n private readonly clock: ReplicationScheduler = scheduler,\n ) {\n this.control = {\n status: async () => {\n await this.binding;\n if (this.gatedReason) return this.options.prefixes.map((prefix) => ({\n prefix, state: \"gated\" as const, gate: this.gatedReason, errorCode: \"REPLICA_GATED\",\n pending: { inFlight: 0, committed: 0, ambiguous: 0 }, pinned: [], lagMs: null,\n }));\n return this.current ? this.current.status() : [];\n },\n sync: async (input) => {\n await this.binding;\n if (this.gatedReason) throw Object.assign(new Error(\"Replica restore is gated.\"), {\n code: \"REPLICA_GATED\", gate: this.gatedReason,\n });\n if (this.purgedGeneration === this.generation) return;\n if (this.current) await this.current.sync(input);\n },\n purge: (input) => {\n if (this.bindingActive) {\n this.pendingPurge = input;\n this.pendingPurgeSet = true;\n const existing = this.current ?? this.lastController;\n if (existing) {\n this.pendingPurgeResult = existing.purge(input);\n this.purgedGeneration = this.generation;\n }\n return this.binding.then(() => this.pendingPurgeResult ?? { purged: [], failed: [] });\n }\n const controller = this.current ?? this.lastController;\n if (!controller) return Promise.resolve({ purged: [], failed: [] });\n this.purgedGeneration = this.generation;\n return controller.purge(input);\n },\n clearPending: async () => {\n await this.binding;\n if (this.current) return this.current.clearPending();\n const pending = this.lastPending;\n if (!pending) return 0;\n return pending.update((state) => {\n const before = state.records.length;\n state.records = state.records.filter((record) =>\n record.state === \"committed\" ||\n (record.state === \"in_flight\" && this.clock.now() - Date.parse(record.at) <= 10 * 60_000),\n );\n return before - state.records.length;\n });\n },\n close: async () => {\n this.closed = true;\n this.unbind();\n await this.binding.catch(() => undefined);\n await this.previous;\n },\n };\n }\n\n private loadServices(): Promise<ReplicationServices> {\n return (this.services ??= import(\"@tinycloud/sdk-services/kv/replication\"));\n }\n\n private detachAll(): void {\n for (const kv of this.attached.keys()) kv.setReadThrough(null);\n this.attached.clear();\n }\n\n /** Observe a refused restore without opening replica state; loader failure leaves raw network KV usable. */\n bindGatedNetworkOnly(\n input: GatedReplicationRuntimeBinding,\n loadGatedNetwork: () => Promise<typeof import(\"./gated-network\")>,\n ): Promise<void> {\n if (this.closed || !this.options.enabled) return Promise.resolve();\n const retired = this.unbind();\n const generation = this.generation;\n this.purgedGeneration = undefined;\n this.pendingPurge = undefined;\n this.pendingPurgeResult = undefined;\n this.pending.clear();\n this.lastController = undefined;\n this.lastPending = undefined;\n this.lastIdentity = undefined;\n this.gatedReason = input.gate;\n this.primarySpace = input.session.spaceId;\n this.binding = retired.then(async () => {\n let create: typeof import(\"./gated-network\").createGatedNetworkReadThrough;\n try {\n ({ createGatedNetworkReadThrough: create } = await loadGatedNetwork());\n } catch {\n // Refusal already gates local delivery; a missing observer cannot end a network session.\n return;\n }\n if (generation !== this.generation || this.closed || typeof create !== \"function\") return;\n const networkOnly = create({\n space: input.session.spaceId,\n prefixes: this.options.prefixes,\n now: () => this.clock.now(),\n emit: (event) => {\n if (generation !== this.generation || this.closed || this.gated !== networkOnly) return;\n try { this.options.onEvent?.(event); } catch { /* Telemetry cannot change network results. */ }\n const { type, ...data } = event;\n try { input.context.emit(type, data); } catch { /* Telemetry cannot change network results. */ }\n },\n });\n this.gated = networkOnly;\n for (const scoped of input.primaryKV) this.attach(scoped.space, scoped.kv);\n });\n return this.binding;\n }\n\n bind(input: ReplicationRuntimeBinding): Promise<void> {\n if (this.closed || !this.options.enabled) return Promise.resolve();\n this.gated = undefined;\n this.gatedReason = undefined;\n this.bindingActive = true;\n const generation = ++this.generation;\n this.purgedGeneration = undefined;\n this.unsubscribeConsentExpired?.();\n this.unsubscribeConsentExpired = undefined;\n const { context, session } = input;\n const emit = (event: ReplicationEvent): void => {\n try { this.options.onEvent?.(event); } catch { /* Observability must not affect KV behavior. */ }\n const { type, ...data } = event;\n context.emit(type, data);\n };\n const previous = this.current;\n this.current = undefined;\n for (const kv of this.attached.keys()) kv.setReadThrough(null);\n this.primarySpace = session.spaceId;\n const close = previous ? previous.close().catch(() => undefined) : Promise.resolve();\n this.previous = this.previous.then(() => close);\n const previousClose = this.previous;\n this.binding = this.loadServices().then((services) => {\n if (generation !== this.generation || this.closed) return;\n let identity: ReplicationIdentity;\n try {\n identity = services.canonicalReplicationIdentity({\n host: context.hosts[0]!,\n space: session.spaceId,\n principal: input.principal ?? pkhDid(input.address!, input.chainId!),\n });\n } catch {\n for (const prefix of this.options.prefixes) {\n emit({ type: \"replication.state\", at: new Date(this.clock.now()).toISOString(), space: session.spaceId, replica: prefix, state: \"unavailable\", code: \"CONFIG_INVALID\" });\n }\n return;\n }\n const key = services.replicationIdentityKey(identity);\n let cached = this.pending.get(key);\n const stamp = input.stamp;\n if (!cached || cached.stamp?.incarnation !== stamp?.incarnation || cached.stamp?.lifecycleEpoch !== stamp?.lifecycleEpoch) {\n const store = this.options.storage.pendingWrites?.(identity, { stamp });\n if (!store && this.options.storage.lifecycle) {\n throw Object.assign(new Error(\"Gated replication requires a stamped pending store\"), { code: \"REPLICA_GATED\", gate: \"gate_unavailable\" });\n }\n cached = { stamp, store: store ?? services.createMemoryPendingStore(identity) };\n this.pending.set(key, cached);\n }\n const pending = cached.store;\n this.lastPending = pending;\n const controller = services.createKVReplication({\n options: resolvedOptions(this.options),\n mode: this.options.mode ?? \"background\",\n storage: this.options.storage,\n identity,\n session: { id: session.delegationCid, did: session.verificationMethod, space: session.spaceId },\n stamp: input.stamp,\n authority: input.authority,\n pending,\n scheduler: this.clock,\n emit,\n fetch: context.fetch as FetchFunction,\n nodeFeatures: input.nodeFeatures,\n previous: previousClose,\n });\n this.current = controller;\n this.unsubscribeConsentExpired = this.options.storage.lifecycle?.subscribeConsentExpired?.(\n (stamp) => controller.observeConsentExpired(stamp),\n );\n this.lastController = controller;\n this.lastIdentity = identity;\n for (const [kv, space] of this.attached) {\n kv.setReadThrough(space === this.primarySpace ? controller : null);\n }\n for (const scoped of input.primaryKV) this.attach(scoped.space, scoped.kv);\n if (this.pendingPurgeSet) {\n this.pendingPurgeResult = controller.purge(this.pendingPurge);\n this.purgedGeneration = generation;\n this.pendingPurge = undefined;\n this.pendingPurgeSet = false;\n }\n }).finally(() => {\n if (generation === this.generation) this.bindingActive = false;\n });\n for (const kv of this.attached.keys()) kv.setReadThroughReady?.(this.binding);\n return this.binding;\n }\n\n attach(space: string, kv: ReadThroughKV): Promise<void> {\n this.attached.set(kv, space);\n kv.setReadThrough(space === this.primarySpace ? this.current ?? this.gated ?? null : null);\n const generation = this.generation;\n return this.binding.then(() => {\n if (generation === this.generation && !this.closed && this.attached.get(kv) === space) {\n kv.setReadThrough(space === this.primarySpace ? this.current ?? this.gated ?? null : null);\n }\n });\n }\n\n unbind(): Promise<void> {\n this.generation++;\n this.bindingActive = false;\n this.pendingPurgeSet = false;\n this.unsubscribeConsentExpired?.();\n this.unsubscribeConsentExpired = undefined;\n const controller = this.current;\n this.current = undefined;\n this.gated = undefined;\n this.gatedReason = undefined;\n this.primarySpace = undefined;\n this.detachAll();\n const binding = this.binding;\n const close = binding.then(() => controller?.close()).catch(() => undefined);\n this.previous = this.previous.then(() => close);\n return this.previous;\n }\n\n get boundIdentity(): ReplicationIdentity | undefined {\n return this.lastIdentity;\n }\n}\n"],"mappings":"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","names":["stamp"]}
|
|
@@ -32,7 +32,8 @@ type ReadThroughKV = {
|
|
|
32
32
|
declare class ReplicationRuntime {
|
|
33
33
|
private readonly options;
|
|
34
34
|
private readonly clock;
|
|
35
|
-
|
|
35
|
+
/** The node facade adds `purgeLocalCopy`: it needs the node's deny state, not the runtime's. */
|
|
36
|
+
readonly control: Omit<ReplicationControl, "purgeLocalCopy">;
|
|
36
37
|
private readonly pending;
|
|
37
38
|
private readonly attached;
|
|
38
39
|
private current?;
|
|
@@ -32,7 +32,8 @@ type ReadThroughKV = {
|
|
|
32
32
|
declare class ReplicationRuntime {
|
|
33
33
|
private readonly options;
|
|
34
34
|
private readonly clock;
|
|
35
|
-
|
|
35
|
+
/** The node facade adds `purgeLocalCopy`: it needs the node's deny state, not the runtime's. */
|
|
36
|
+
readonly control: Omit<ReplicationControl, "purgeLocalCopy">;
|
|
36
37
|
private readonly pending;
|
|
37
38
|
private readonly attached;
|
|
38
39
|
private current?;
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@tinycloud/node-sdk",
|
|
3
|
-
"version": "3.8.0-beta.
|
|
3
|
+
"version": "3.8.0-beta.2",
|
|
4
4
|
"description": "TinyCloud SDK for Node.js with configurable authorization strategies",
|
|
5
5
|
"author": "TinyCloud, Inc.",
|
|
6
6
|
"license": "EGPL",
|
|
@@ -89,9 +89,9 @@
|
|
|
89
89
|
"test:integration": "echo 'Integration tests live in tests/node-sdk workspace'"
|
|
90
90
|
},
|
|
91
91
|
"dependencies": {
|
|
92
|
-
"@tinycloud/replica": "0.
|
|
93
|
-
"@tinycloud/sdk-services": "3.8.0-beta.
|
|
94
|
-
"@tinycloud/sdk-core": "3.8.0-beta.
|
|
92
|
+
"@tinycloud/replica": "0.4.0-beta.1",
|
|
93
|
+
"@tinycloud/sdk-services": "3.8.0-beta.2",
|
|
94
|
+
"@tinycloud/sdk-core": "3.8.0-beta.2",
|
|
95
95
|
"@tinycloud/node-sdk-wasm": "1.7.8",
|
|
96
96
|
"siwe": "^3.0.0"
|
|
97
97
|
},
|