@tinycloud/node-sdk 3.2.0-beta.2 → 3.2.0-beta.3

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/index.cjs CHANGED
@@ -5,6 +5,9 @@ var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
5
5
  var __getOwnPropNames = Object.getOwnPropertyNames;
6
6
  var __getProtoOf = Object.getPrototypeOf;
7
7
  var __hasOwnProp = Object.prototype.hasOwnProperty;
8
+ var __typeError = (msg) => {
9
+ throw TypeError(msg);
10
+ };
8
11
  var __esm = (fn, res) => function __init() {
9
12
  return fn && (res = (0, fn[__getOwnPropNames(fn)[0]])(fn = 0)), res;
10
13
  };
@@ -32,6 +35,11 @@ var __toESM = (mod, isNodeMode, target) => (target = mod != null ? __create(__ge
32
35
  mod
33
36
  ));
34
37
  var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
38
+ var __accessCheck = (obj, member, msg) => member.has(obj) || __typeError("Cannot " + msg);
39
+ var __privateGet = (obj, member, getter) => (__accessCheck(obj, member, "read from private field"), getter ? getter.call(obj) : member.get(obj));
40
+ var __privateAdd = (obj, member, value) => member.has(obj) ? __typeError("Cannot add the same private member more than once") : member instanceof WeakSet ? member.add(obj) : member.set(obj, value);
41
+ var __privateSet = (obj, member, value, setter) => (__accessCheck(obj, member, "write to private field"), setter ? setter.call(obj, value) : member.set(obj, value), value);
42
+ var __privateMethod = (obj, member, method) => (__accessCheck(obj, member, "access private method"), method);
35
43
 
36
44
  // ../../node_modules/bn.js/lib/bn.js
37
45
  var require_bn = __commonJS({
@@ -14350,8 +14358,8 @@ function searchPath(object, path) {
14350
14358
  }
14351
14359
  return currentChild;
14352
14360
  }
14353
- function uuidV4(randomBytes2) {
14354
- const bytes = arrayify(randomBytes2);
14361
+ function uuidV4(randomBytes3) {
14362
+ const bytes = arrayify(randomBytes3);
14355
14363
  bytes[6] = bytes[6] & 15 | 64;
14356
14364
  bytes[8] = bytes[8] & 63 | 128;
14357
14365
  const value = hexlify(bytes);
@@ -17022,170 +17030,632 @@ var require_utils2 = __commonJS({
17022
17030
  }
17023
17031
  });
17024
17032
 
17033
+ // src/replication/config.ts
17034
+ function assertValidReplicationConfig(replication) {
17035
+ if (replication === void 0 || replication.enabled !== true) return;
17036
+ if (replication.storage === void 0 || replication.storage === null) {
17037
+ throw new TypeError("replication.enabled requires replication.storage");
17038
+ }
17039
+ if (!Array.isArray(replication.prefixes) || replication.prefixes.length === 0) {
17040
+ throw new TypeError("replication.prefixes must be a non-empty array");
17041
+ }
17042
+ for (const prefix of replication.prefixes) {
17043
+ if (typeof prefix !== "string" || prefix === "") {
17044
+ throw new TypeError("replication.prefixes must not contain an empty prefix");
17045
+ }
17046
+ }
17047
+ for (const [index, prefix] of replication.prefixes.entries()) {
17048
+ for (const other of replication.prefixes.slice(index + 1)) {
17049
+ if ((0, import_sdk_services.kvPrefixCovers)(prefix, other) || (0, import_sdk_services.kvPrefixCovers)(other, prefix)) {
17050
+ throw new TypeError(
17051
+ `replication.prefixes must not overlap: ${JSON.stringify(prefix)} and ${JSON.stringify(other)}`
17052
+ );
17053
+ }
17054
+ }
17055
+ if (prefix.split("/", 1)[0] === "vault" && replication.allowSecrets !== true) {
17056
+ throw new TypeError(
17057
+ `replication prefix ${JSON.stringify(prefix)} overlaps the vault namespace; pass allowSecrets to opt in`
17058
+ );
17059
+ }
17060
+ }
17061
+ }
17062
+ var import_sdk_services;
17063
+ var init_config = __esm({
17064
+ "src/replication/config.ts"() {
17065
+ "use strict";
17066
+ import_sdk_services = require("@tinycloud/sdk-services");
17067
+ }
17068
+ });
17069
+
17070
+ // src/replication/authority-sign-in.ts
17071
+ function hasUnrestrictedGetCoverage(entries, spaceId, prefix) {
17072
+ const requiredPaths = (0, import_sdk_core2.grantPathsForSelector)(prefix);
17073
+ return (0, import_sdk_core2.isCapabilitySubset)(
17074
+ requiredPaths.map((path) => ({ service: KV_SERVICE, space: spaceId, path, actions: [KV_GET] })),
17075
+ [...entries]
17076
+ ).subset;
17077
+ }
17078
+ function augmentSignInEntriesWithReplication(input) {
17079
+ const out = [];
17080
+ const replication = input.replication;
17081
+ if (replication === void 0) return out;
17082
+ for (const prefix of replication.prefixes) {
17083
+ if ((0, import_sdk_services2.requiresSecretsOptIn)(input.primarySpaceId, prefix) && replication.allowSecrets !== true) {
17084
+ continue;
17085
+ }
17086
+ if (!hasUnrestrictedGetCoverage(input.entries, input.primarySpaceId, prefix)) {
17087
+ continue;
17088
+ }
17089
+ for (const path of (0, import_sdk_core2.grantPathsForSelector)(prefix)) {
17090
+ out.push({
17091
+ service: KV_SERVICE,
17092
+ space: input.primarySpaceId,
17093
+ path,
17094
+ actions: [KV_GET, KV_SYNC]
17095
+ });
17096
+ }
17097
+ }
17098
+ return out;
17099
+ }
17100
+ var import_sdk_core2, import_sdk_services2, KV_GET, KV_SYNC, KV_SERVICE;
17101
+ var init_authority_sign_in = __esm({
17102
+ "src/replication/authority-sign-in.ts"() {
17103
+ "use strict";
17104
+ import_sdk_core2 = require("@tinycloud/sdk-core");
17105
+ import_sdk_services2 = require("@tinycloud/sdk-services");
17106
+ KV_GET = import_sdk_core2.KV.GET;
17107
+ KV_SYNC = import_sdk_core2.KV.SYNC;
17108
+ KV_SERVICE = "tinycloud.kv";
17109
+ }
17110
+ });
17111
+
17112
+ // src/replication/runtime.ts
17113
+ var runtime_exports = {};
17114
+ __export(runtime_exports, {
17115
+ ReplicationRuntime: () => ReplicationRuntime
17116
+ });
17117
+ function resolvedOptions(options) {
17118
+ return {
17119
+ ...options,
17120
+ syncIntervalMs: options.syncIntervalMs ?? 6e4,
17121
+ maxStalenessMs: options.maxStalenessMs ?? 12e4,
17122
+ staleSyncTimeoutMs: options.staleSyncTimeoutMs ?? 5e3,
17123
+ allowSecrets: options.allowSecrets === true,
17124
+ verify: options.verify === true
17125
+ };
17126
+ }
17127
+ var import_sdk_core10, scheduler, ReplicationRuntime;
17128
+ var init_runtime = __esm({
17129
+ "src/replication/runtime.ts"() {
17130
+ "use strict";
17131
+ import_sdk_core10 = require("@tinycloud/sdk-core");
17132
+ scheduler = {
17133
+ now: () => Date.now(),
17134
+ setTimeout(fn, ms) {
17135
+ const timer = setTimeout(fn, ms);
17136
+ timer.unref?.();
17137
+ return () => clearTimeout(timer);
17138
+ }
17139
+ };
17140
+ ReplicationRuntime = class {
17141
+ constructor(options, clock = scheduler) {
17142
+ this.options = options;
17143
+ this.clock = clock;
17144
+ this.pending = /* @__PURE__ */ new Map();
17145
+ this.attached = /* @__PURE__ */ new Map();
17146
+ this.previous = Promise.resolve();
17147
+ this.binding = Promise.resolve();
17148
+ this.generation = 0;
17149
+ this.bindingActive = false;
17150
+ this.pendingPurgeSet = false;
17151
+ this.closed = false;
17152
+ this.control = {
17153
+ status: async () => {
17154
+ await this.binding;
17155
+ return this.current ? this.current.status() : [];
17156
+ },
17157
+ sync: async (input) => {
17158
+ await this.binding;
17159
+ if (this.purgedGeneration === this.generation) return;
17160
+ if (this.current) await this.current.sync(input);
17161
+ },
17162
+ purge: (input) => {
17163
+ if (this.bindingActive) {
17164
+ this.pendingPurge = input;
17165
+ this.pendingPurgeSet = true;
17166
+ const existing = this.current ?? this.lastController;
17167
+ if (existing) {
17168
+ this.pendingPurgeResult = existing.purge(input);
17169
+ this.purgedGeneration = this.generation;
17170
+ }
17171
+ return this.binding.then(() => this.pendingPurgeResult ?? { purged: [], failed: [] });
17172
+ }
17173
+ const controller = this.current ?? this.lastController;
17174
+ if (!controller) return Promise.resolve({ purged: [], failed: [] });
17175
+ this.purgedGeneration = this.generation;
17176
+ return controller.purge(input);
17177
+ },
17178
+ clearPending: async () => {
17179
+ await this.binding;
17180
+ if (this.current) return this.current.clearPending();
17181
+ const pending = this.lastPending;
17182
+ if (!pending) return 0;
17183
+ return pending.update((state) => {
17184
+ const before = state.records.length;
17185
+ state.records = state.records.filter(
17186
+ (record) => record.state === "committed" || record.state === "in_flight" && this.clock.now() - Date.parse(record.at) <= 10 * 6e4
17187
+ );
17188
+ return before - state.records.length;
17189
+ });
17190
+ },
17191
+ close: async () => {
17192
+ this.closed = true;
17193
+ this.unbind();
17194
+ await this.binding.catch(() => void 0);
17195
+ await this.previous;
17196
+ }
17197
+ };
17198
+ }
17199
+ loadServices() {
17200
+ return this.services ?? (this.services = import("@tinycloud/sdk-services/kv/replication"));
17201
+ }
17202
+ detachAll() {
17203
+ for (const kv of this.attached.keys()) kv.setReadThrough(null);
17204
+ this.attached.clear();
17205
+ }
17206
+ bind(input) {
17207
+ if (this.closed || !this.options.enabled) return Promise.resolve();
17208
+ this.bindingActive = true;
17209
+ const generation = ++this.generation;
17210
+ this.purgedGeneration = void 0;
17211
+ const { context, session } = input;
17212
+ const emit = (event) => {
17213
+ try {
17214
+ this.options.onEvent?.(event);
17215
+ } catch {
17216
+ }
17217
+ const { type, ...data } = event;
17218
+ context.emit(type, data);
17219
+ };
17220
+ const previous = this.current;
17221
+ this.current = void 0;
17222
+ for (const kv of this.attached.keys()) kv.setReadThrough(null);
17223
+ this.primarySpace = session.spaceId;
17224
+ const close = previous ? previous.close().catch(() => void 0) : Promise.resolve();
17225
+ this.previous = this.previous.then(() => close);
17226
+ const previousClose = this.previous;
17227
+ this.binding = this.loadServices().then((services) => {
17228
+ if (generation !== this.generation || this.closed) return;
17229
+ let identity;
17230
+ try {
17231
+ identity = services.canonicalReplicationIdentity({
17232
+ host: context.hosts[0],
17233
+ space: session.spaceId,
17234
+ principal: input.principal ?? (0, import_sdk_core10.pkhDid)(input.address, input.chainId)
17235
+ });
17236
+ } catch {
17237
+ for (const prefix of this.options.prefixes) {
17238
+ emit({ type: "replication.state", at: new Date(this.clock.now()).toISOString(), space: session.spaceId, replica: prefix, state: "unavailable", code: "CONFIG_INVALID" });
17239
+ }
17240
+ return;
17241
+ }
17242
+ const key2 = services.replicationIdentityKey(identity);
17243
+ let pending = this.pending.get(key2);
17244
+ if (!pending) {
17245
+ pending = this.options.storage.pendingWrites?.(identity) ?? services.createMemoryPendingStore(identity);
17246
+ this.pending.set(key2, pending);
17247
+ }
17248
+ this.lastPending = pending;
17249
+ const controller = services.createKVReplication({
17250
+ options: resolvedOptions(this.options),
17251
+ mode: this.options.mode ?? "background",
17252
+ storage: this.options.storage,
17253
+ identity,
17254
+ session: { id: session.delegationCid, did: session.verificationMethod, space: session.spaceId },
17255
+ authority: input.authority,
17256
+ pending,
17257
+ scheduler: this.clock,
17258
+ emit,
17259
+ fetch: context.fetch,
17260
+ previous: previousClose
17261
+ });
17262
+ this.current = controller;
17263
+ this.lastController = controller;
17264
+ this.lastIdentity = identity;
17265
+ for (const [kv, space] of this.attached) {
17266
+ kv.setReadThrough(space === this.primarySpace ? controller : null);
17267
+ }
17268
+ for (const scoped of input.primaryKV) this.attach(scoped.space, scoped.kv);
17269
+ if (this.pendingPurgeSet) {
17270
+ this.pendingPurgeResult = controller.purge(this.pendingPurge);
17271
+ this.purgedGeneration = generation;
17272
+ this.pendingPurge = void 0;
17273
+ this.pendingPurgeSet = false;
17274
+ }
17275
+ }).finally(() => {
17276
+ if (generation === this.generation) this.bindingActive = false;
17277
+ });
17278
+ for (const kv of this.attached.keys()) kv.setReadThroughReady?.(this.binding);
17279
+ return this.binding;
17280
+ }
17281
+ attach(space, kv) {
17282
+ this.attached.set(kv, space);
17283
+ kv.setReadThrough(space === this.primarySpace ? this.current ?? null : null);
17284
+ return this.binding.then(() => {
17285
+ kv.setReadThrough(space === this.primarySpace ? this.current ?? null : null);
17286
+ });
17287
+ }
17288
+ unbind() {
17289
+ this.generation++;
17290
+ this.bindingActive = false;
17291
+ this.pendingPurgeSet = false;
17292
+ const controller = this.current;
17293
+ this.current = void 0;
17294
+ this.primarySpace = void 0;
17295
+ this.detachAll();
17296
+ const binding = this.binding;
17297
+ const close = binding.then(() => controller?.close()).catch(() => void 0);
17298
+ this.previous = this.previous.then(() => close);
17299
+ return this.previous;
17300
+ }
17301
+ get boundIdentity() {
17302
+ return this.lastIdentity;
17303
+ }
17304
+ };
17305
+ }
17306
+ });
17307
+
17308
+ // src/replication/authority.ts
17309
+ var authority_exports = {};
17310
+ __export(authority_exports, {
17311
+ AUTHORITY_EXPIRY_MARGIN_MS: () => AUTHORITY_EXPIRY_MARGIN_MS,
17312
+ assertValidReplicationConfig: () => assertValidReplicationConfig,
17313
+ augmentSignInEntriesWithReplication: () => augmentSignInEntriesWithReplication,
17314
+ createReplicationAuthority: () => createReplicationAuthority,
17315
+ hasUnrestrictedGetCoverage: () => hasUnrestrictedGetCoverage,
17316
+ replicationScopeFromSignedSession: () => replicationScopeFromSignedSession,
17317
+ ucanAttCovers: () => ucanAttCovers,
17318
+ ucanAttUnconstrainedFor: () => ucanAttUnconstrainedFor
17319
+ });
17320
+ function replicationEntries(spaceId, prefix) {
17321
+ return (0, import_sdk_core11.grantPathsForSelector)(prefix).map((path) => ({
17322
+ service: KV_SERVICE2,
17323
+ space: spaceId,
17324
+ path,
17325
+ actions: [KV_GET2, KV_SYNC2]
17326
+ }));
17327
+ }
17328
+ function caveatBranchesUnconstrained(value) {
17329
+ if (value === void 0 || value === null) return true;
17330
+ if (typeof value === "object" && !Array.isArray(value) && Object.keys(value).length === 0) {
17331
+ return true;
17332
+ }
17333
+ if (!Array.isArray(value)) return false;
17334
+ try {
17335
+ return (0, import_sdk_core11.canonicalizeRecapCaveats)(value) === (0, import_sdk_core11.canonicalizeRecapCaveats)(void 0);
17336
+ } catch {
17337
+ return false;
17338
+ }
17339
+ }
17340
+ function kvPathInResource(resource, space) {
17341
+ for (const base2 of [`${space}/kv/`, `tinycloud://${space}/kv/`]) {
17342
+ if (resource.startsWith(base2)) return resource.slice(base2.length);
17343
+ }
17344
+ return void 0;
17345
+ }
17346
+ function ucanAttCovers(att, space, prefix, ability, options) {
17347
+ const requiredPaths = prefix.endsWith("/") ? [prefix] : [prefix, `${prefix}/`];
17348
+ return requiredPaths.every((requestedPath) => {
17349
+ for (const [resource, abilities] of Object.entries(att)) {
17350
+ const path = kvPathInResource(resource, space);
17351
+ if (path === void 0) continue;
17352
+ for (const [granted, caveats] of Object.entries(abilities)) {
17353
+ if (!(0, import_sdk_core11.actionContains)(granted, ability)) continue;
17354
+ if (!(0, import_sdk_core11.isCapabilitySubset)(
17355
+ [{ service: KV_SERVICE2, space, path: requestedPath, actions: [ability] }],
17356
+ [{ service: KV_SERVICE2, space, path, actions: [granted] }]
17357
+ ).subset) continue;
17358
+ if (options?.ignoreCaveats === true || caveatBranchesUnconstrained(caveats)) return true;
17359
+ }
17360
+ }
17361
+ return false;
17362
+ });
17363
+ }
17364
+ function ucanAttUnconstrainedFor(att, space, prefix) {
17365
+ return ucanAttCovers(att, space, prefix, KV_GET2) && ucanAttCovers(att, space, prefix, KV_SYNC2);
17366
+ }
17367
+ function replicationScopeFromSignedSession(input) {
17368
+ let grant;
17369
+ try {
17370
+ grant = parseUcanGrant(input.delegationHeader.Authorization);
17371
+ } catch {
17372
+ return void 0;
17373
+ }
17374
+ const bareDid = (value) => value.split("#", 1)[0];
17375
+ if (grant.cid !== input.delegationCid || bareDid(grant.audience) !== bareDid(input.verificationMethod)) return void 0;
17376
+ for (const resource of Object.keys(grant.att)) {
17377
+ const space = resource.match(/^(?:tinycloud:\/\/)?(.+?)\/kv\//)?.[1];
17378
+ if (space !== input.persistedSpace) continue;
17379
+ const owner = (0, import_sdk_core11.parseSpaceUri)(space);
17380
+ if (owner?.owner && owner.address && owner.chainId) return { space, principal: owner.owner };
17381
+ }
17382
+ return void 0;
17383
+ }
17384
+ function createReplicationAuthority(host) {
17385
+ const planOrRefusal = (entries) => {
17386
+ const plan = host.planDelegation(entries);
17387
+ if ("refused" in plan) return plan;
17388
+ return { path: plan.path, parentCid: plan.parentCid, expiresAt: plan.expiresAt };
17389
+ };
17390
+ const sessionAudience = (value) => value.split("#", 1)[0];
17391
+ const signedSessionGrant = (session) => {
17392
+ const grant = parseUcanGrant(session.delegationHeader.Authorization);
17393
+ if (grant.cid !== session.delegationCid || sessionAudience(grant.audience) !== sessionAudience(session.verificationMethod)) return void 0;
17394
+ return grant;
17395
+ };
17396
+ const authority = {
17397
+ get sessionOnly() {
17398
+ const session = host.replicationSession();
17399
+ return session !== void 0 && session.siwe === void 0;
17400
+ },
17401
+ sessionGrant(prefix) {
17402
+ const session = host.replicationSession();
17403
+ if (session === void 0) return { refused: "SESSION_EXPIRING" };
17404
+ const siweExpiry = session.siwe ? host.siweExpiration(session.siwe)?.getTime() : void 0;
17405
+ if (siweExpiry !== void 0 && siweExpiry <= Date.now() + AUTHORITY_EXPIRY_MARGIN_MS) {
17406
+ return { refused: "SESSION_EXPIRING" };
17407
+ }
17408
+ let grant;
17409
+ try {
17410
+ const verified = signedSessionGrant(session);
17411
+ if (!verified) return { refused: "NOT_COVERED" };
17412
+ grant = verified;
17413
+ } catch {
17414
+ return { refused: "NOT_COVERED" };
17415
+ }
17416
+ const tokenExpiry = grant.expiresAt === null ? void 0 : grant.expiresAt * 1e3;
17417
+ if (tokenExpiry === void 0 || tokenExpiry <= Date.now() + AUTHORITY_EXPIRY_MARGIN_MS) {
17418
+ return { refused: "SESSION_EXPIRING" };
17419
+ }
17420
+ const covered = ucanAttCovers(grant.att, session.spaceId, prefix, KV_GET2, { ignoreCaveats: true }) && ucanAttCovers(grant.att, session.spaceId, prefix, KV_SYNC2, { ignoreCaveats: true });
17421
+ if (!covered) return { refused: "NOT_COVERED" };
17422
+ if (!ucanAttUnconstrainedFor(grant.att, session.spaceId, prefix)) {
17423
+ return { refused: "CAVEATED_AUTHORITY" };
17424
+ }
17425
+ return {
17426
+ ucan: grant.jwt,
17427
+ device: { did: session.verificationMethod, jwk: session.jwk }
17428
+ };
17429
+ },
17430
+ plan(prefix) {
17431
+ const session = host.replicationSession();
17432
+ if (session === void 0) return { refused: "SESSION_EXPIRING" };
17433
+ const sessionGrant = this.sessionGrant(prefix);
17434
+ if (!("refused" in sessionGrant)) {
17435
+ const signed2 = signedSessionGrant(session);
17436
+ if (!signed2 || signed2.expiresAt === null) return { refused: "NOT_COVERED" };
17437
+ return {
17438
+ path: "session",
17439
+ parentCid: session.delegationCid,
17440
+ expiresAt: signed2.expiresAt * 1e3
17441
+ };
17442
+ }
17443
+ if (authority.sessionOnly) return sessionGrant;
17444
+ return planOrRefusal(replicationEntries(session.spaceId, prefix));
17445
+ },
17446
+ async mint(deviceDid, prefix, signal) {
17447
+ if (authority.sessionOnly) throw new Error("compact delegate sessions cannot mint device grants");
17448
+ const session = host.replicationSession();
17449
+ if (session === void 0) throw new Error("replication mint without a session");
17450
+ const entries = replicationEntries(session.spaceId, prefix);
17451
+ const plan = planOrRefusal(entries);
17452
+ if ("refused" in plan) {
17453
+ throw Object.assign(
17454
+ new Error(`replication authority refused the mint: ${plan.refused}`),
17455
+ { refused: plan.refused }
17456
+ );
17457
+ }
17458
+ signal.throwIfAborted();
17459
+ const minted = await new Promise((resolve, reject2) => {
17460
+ const onAbort = () => reject2(signal.reason ?? new Error("replication mint aborted"));
17461
+ signal.addEventListener("abort", onAbort, { once: true });
17462
+ host.mintDelegation(deviceDid, entries).then(
17463
+ (result) => {
17464
+ signal.removeEventListener("abort", onAbort);
17465
+ resolve(result);
17466
+ },
17467
+ (error) => {
17468
+ signal.removeEventListener("abort", onAbort);
17469
+ reject2(error instanceof Error ? error : new Error(String(error)));
17470
+ }
17471
+ );
17472
+ });
17473
+ return { ucan: minted.ucan, parentCid: plan.parentCid, expiresAt: minted.expiresAt };
17474
+ }
17475
+ };
17476
+ return authority;
17477
+ }
17478
+ var import_sdk_core11, import_replica, parseUcanGrant, KV_GET2, KV_SYNC2, KV_SERVICE2, AUTHORITY_EXPIRY_MARGIN_MS;
17479
+ var init_authority = __esm({
17480
+ "src/replication/authority.ts"() {
17481
+ "use strict";
17482
+ import_sdk_core11 = require("@tinycloud/sdk-core");
17483
+ import_replica = require("@tinycloud/replica");
17484
+ init_config();
17485
+ init_authority_sign_in();
17486
+ parseUcanGrant = import_replica.parseUcanGrant;
17487
+ KV_GET2 = import_sdk_core11.KV.GET;
17488
+ KV_SYNC2 = import_sdk_core11.KV.SYNC;
17489
+ KV_SERVICE2 = "tinycloud.kv";
17490
+ AUTHORITY_EXPIRY_MARGIN_MS = 6e4;
17491
+ }
17492
+ });
17493
+
17025
17494
  // src/index.ts
17026
- var index_exports = {};
17027
- __export(index_exports, {
17495
+ var src_exports = {};
17496
+ __export(src_exports, {
17028
17497
  ACCEPTED_MARKER_VERSIONS: () => ACCEPTED_MARKER_VERSIONS,
17029
- ACCOUNT_REGISTRY_PATH: () => import_sdk_core12.ACCOUNT_REGISTRY_PATH,
17030
- ACCOUNT_REGISTRY_SPACE: () => import_sdk_core12.ACCOUNT_REGISTRY_SPACE,
17031
- AccountService: () => import_sdk_core4.AccountService,
17032
- AutoApproveSpaceCreationHandler: () => import_sdk_core11.AutoApproveSpaceCreationHandler,
17498
+ ACCOUNT_REGISTRY_PATH: () => import_sdk_core16.ACCOUNT_REGISTRY_PATH,
17499
+ ACCOUNT_REGISTRY_SPACE: () => import_sdk_core16.ACCOUNT_REGISTRY_SPACE,
17500
+ AccountService: () => import_sdk_core5.AccountService,
17501
+ AutoApproveSpaceCreationHandler: () => import_sdk_core15.AutoApproveSpaceCreationHandler,
17033
17502
  BOOTSTRAP_COMPLETION_MARKER_KEY: () => BOOTSTRAP_COMPLETION_MARKER_KEY,
17034
17503
  BOOTSTRAP_COMPLETION_MARKER_VERSION: () => BOOTSTRAP_COMPLETION_MARKER_VERSION,
17035
- CapabilityKeyRegistry: () => import_sdk_core20.CapabilityKeyRegistry,
17036
- CapabilityKeyRegistryErrorCodes: () => import_sdk_core20.CapabilityKeyRegistryErrorCodes,
17037
- CaveatedDelegationUnsupportedError: () => import_sdk_core12.CaveatedDelegationUnsupportedError,
17038
- DECRYPT_ACTION: () => import_sdk_core17.DECRYPT_ACTION,
17039
- DECRYPT_FACT_TYPE: () => import_sdk_core17.DECRYPT_FACT_TYPE,
17040
- DECRYPT_RESULT_TYPE: () => import_sdk_core17.DECRYPT_RESULT_TYPE,
17041
- DEFAULT_ENCRYPTION_ALG: () => import_sdk_core17.DEFAULT_ENCRYPTION_ALG,
17042
- DEFAULT_KEY_VERSION: () => import_sdk_core17.DEFAULT_KEY_VERSION,
17043
- DEFAULT_MANIFEST_SPACE: () => import_sdk_core12.DEFAULT_MANIFEST_SPACE,
17044
- DEFAULT_MANIFEST_VERSION: () => import_sdk_core12.DEFAULT_MANIFEST_VERSION,
17045
- DEFAULT_SIGNED_READ_URL_EXPIRY_MS: () => import_sdk_core13.DEFAULT_SIGNED_READ_URL_EXPIRY_MS,
17046
- DataVaultService: () => import_sdk_core16.DataVaultService,
17047
- DatabaseHandle: () => import_sdk_core14.DatabaseHandle,
17048
- DecryptTransportResponseError: () => import_sdk_core17.DecryptTransportResponseError,
17504
+ CapabilityKeyRegistry: () => import_sdk_core24.CapabilityKeyRegistry,
17505
+ CapabilityKeyRegistryErrorCodes: () => import_sdk_core24.CapabilityKeyRegistryErrorCodes,
17506
+ CaveatedDelegationUnsupportedError: () => import_sdk_core16.CaveatedDelegationUnsupportedError,
17507
+ DECRYPT_ACTION: () => import_sdk_core21.DECRYPT_ACTION,
17508
+ DECRYPT_FACT_TYPE: () => import_sdk_core21.DECRYPT_FACT_TYPE,
17509
+ DECRYPT_RESULT_TYPE: () => import_sdk_core21.DECRYPT_RESULT_TYPE,
17510
+ DEFAULT_ENCRYPTION_ALG: () => import_sdk_core21.DEFAULT_ENCRYPTION_ALG,
17511
+ DEFAULT_KEY_VERSION: () => import_sdk_core21.DEFAULT_KEY_VERSION,
17512
+ DEFAULT_MANIFEST_SPACE: () => import_sdk_core16.DEFAULT_MANIFEST_SPACE,
17513
+ DEFAULT_MANIFEST_VERSION: () => import_sdk_core16.DEFAULT_MANIFEST_VERSION,
17514
+ DEFAULT_SIGNED_READ_URL_EXPIRY_MS: () => import_sdk_core17.DEFAULT_SIGNED_READ_URL_EXPIRY_MS,
17515
+ DataVaultService: () => import_sdk_core20.DataVaultService,
17516
+ DatabaseHandle: () => import_sdk_core18.DatabaseHandle,
17517
+ DecryptTransportResponseError: () => import_sdk_core21.DecryptTransportResponseError,
17049
17518
  DelegatedAccess: () => DelegatedAccess,
17050
- DelegationErrorCodes: () => import_sdk_core19.DelegationErrorCodes,
17051
- DelegationManager: () => import_sdk_core19.DelegationManager,
17052
- DuckDbAction: () => import_sdk_core15.DuckDbAction,
17053
- DuckDbDatabaseHandle: () => import_sdk_core15.DuckDbDatabaseHandle,
17054
- DuckDbService: () => import_sdk_core15.DuckDbService,
17055
- ENCRYPTION_NETWORK_URN_PREFIX: () => import_sdk_core17.ENCRYPTION_NETWORK_URN_PREFIX,
17056
- ENCRYPTION_SERVICE: () => import_sdk_core17.ENCRYPTION_SERVICE,
17057
- ENCRYPTION_SERVICE_SHORT: () => import_sdk_core17.ENCRYPTION_SERVICE_SHORT,
17058
- ENVELOPE_VERSION: () => import_sdk_core17.ENVELOPE_VERSION,
17059
- EncryptionService: () => import_sdk_core17.EncryptionService,
17519
+ DelegationErrorCodes: () => import_sdk_core23.DelegationErrorCodes,
17520
+ DelegationManager: () => import_sdk_core23.DelegationManager,
17521
+ DuckDbAction: () => import_sdk_core19.DuckDbAction,
17522
+ DuckDbDatabaseHandle: () => import_sdk_core19.DuckDbDatabaseHandle,
17523
+ DuckDbService: () => import_sdk_core19.DuckDbService,
17524
+ ENCRYPTION_NETWORK_URN_PREFIX: () => import_sdk_core21.ENCRYPTION_NETWORK_URN_PREFIX,
17525
+ ENCRYPTION_SERVICE: () => import_sdk_core21.ENCRYPTION_SERVICE,
17526
+ ENCRYPTION_SERVICE_SHORT: () => import_sdk_core21.ENCRYPTION_SERVICE_SHORT,
17527
+ ENVELOPE_VERSION: () => import_sdk_core21.ENVELOPE_VERSION,
17528
+ EncryptionService: () => import_sdk_core21.EncryptionService,
17060
17529
  FileSessionStorage: () => FileSessionStorage,
17061
- HooksService: () => import_sdk_core18.HooksService,
17062
- IdentityParseError: () => import_sdk_core11.IdentityParseError,
17530
+ HooksService: () => import_sdk_core22.HooksService,
17531
+ IdentityParseError: () => import_sdk_core15.IdentityParseError,
17063
17532
  InvalidRestoredSessionError: () => InvalidRestoredSessionError,
17064
- KVService: () => import_sdk_core13.KVService,
17065
- MAX_SECRET_SCOPE_LENGTH: () => import_sdk_core16.MAX_SECRET_SCOPE_LENGTH,
17066
- ManifestValidationError: () => import_sdk_core12.ManifestValidationError,
17533
+ KVService: () => import_sdk_core17.KVService,
17534
+ MAX_SECRET_SCOPE_LENGTH: () => import_sdk_core20.MAX_SECRET_SCOPE_LENGTH,
17535
+ ManifestValidationError: () => import_sdk_core16.ManifestValidationError,
17067
17536
  MemorySessionStorage: () => MemorySessionStorage,
17068
- NETWORK_NAME_PATTERN: () => import_sdk_core17.NETWORK_NAME_PATTERN,
17069
- NetworkIdError: () => import_sdk_core17.NetworkIdError,
17537
+ NETWORK_NAME_PATTERN: () => import_sdk_core21.NETWORK_NAME_PATTERN,
17538
+ NetworkIdError: () => import_sdk_core21.NetworkIdError,
17070
17539
  NodeUserAuthorization: () => NodeUserAuthorization,
17071
17540
  NodeWasmBindings: () => NodeWasmBindings,
17072
- PermissionNotInManifestError: () => import_sdk_core12.PermissionNotInManifestError,
17073
- PrefixedKVService: () => import_sdk_core13.PrefixedKVService,
17541
+ PermissionNotInManifestError: () => import_sdk_core16.PermissionNotInManifestError,
17542
+ PrefixedKVService: () => import_sdk_core17.PrefixedKVService,
17074
17543
  PrivateKeySigner: () => PrivateKeySigner,
17075
- ProtocolMismatchError: () => import_sdk_core22.ProtocolMismatchError,
17544
+ ProtocolMismatchError: () => import_sdk_core26.ProtocolMismatchError,
17076
17545
  RUNTIME_DELEGATION_REJECTIONS: () => RUNTIME_DELEGATION_REJECTIONS,
17077
17546
  RuntimeDelegationRejectedError: () => RuntimeDelegationRejectedError,
17078
- SECRET_NAME_RE: () => import_sdk_core16.SECRET_NAME_RE,
17079
- SECRET_SCOPE_RE: () => import_sdk_core16.SECRET_SCOPE_RE,
17080
- SQLAction: () => import_sdk_core14.SQLAction,
17081
- SQLService: () => import_sdk_core14.SQLService,
17082
- STORAGE_FULL_MESSAGE: () => import_sdk_core11.STORAGE_FULL_MESSAGE,
17083
- STORAGE_WRITE_TOO_LARGE_MESSAGE: () => import_sdk_core11.STORAGE_WRITE_TOO_LARGE_MESSAGE,
17084
- SecretsService: () => import_sdk_core16.SecretsService,
17085
- ServiceContext: () => import_sdk_core23.ServiceContext,
17086
- SessionExpiredError: () => import_sdk_core12.SessionExpiredError,
17087
- SharingService: () => import_sdk_core19.SharingService,
17088
- SilentNotificationHandler: () => import_sdk_core11.SilentNotificationHandler,
17089
- Space: () => import_sdk_core21.Space,
17090
- SpaceErrorCodes: () => import_sdk_core21.SpaceErrorCodes,
17091
- SpaceService: () => import_sdk_core21.SpaceService,
17092
- TC832_RESERVED_SCOPES: () => import_sdk_core16.TC832_RESERVED_SCOPES,
17093
- TinyCloud: () => import_sdk_core10.TinyCloud,
17094
- TinyCloudDebugLogger: () => import_sdk_core11.TinyCloudDebugLogger,
17547
+ SECRET_NAME_RE: () => import_sdk_core20.SECRET_NAME_RE,
17548
+ SECRET_SCOPE_RE: () => import_sdk_core20.SECRET_SCOPE_RE,
17549
+ SQLAction: () => import_sdk_core18.SQLAction,
17550
+ SQLService: () => import_sdk_core18.SQLService,
17551
+ STORAGE_FULL_MESSAGE: () => import_sdk_core15.STORAGE_FULL_MESSAGE,
17552
+ STORAGE_WRITE_TOO_LARGE_MESSAGE: () => import_sdk_core15.STORAGE_WRITE_TOO_LARGE_MESSAGE,
17553
+ SecretsService: () => import_sdk_core20.SecretsService,
17554
+ ServiceContext: () => import_sdk_core27.ServiceContext,
17555
+ SessionExpiredError: () => import_sdk_core16.SessionExpiredError,
17556
+ SharingService: () => import_sdk_core23.SharingService,
17557
+ SilentNotificationHandler: () => import_sdk_core15.SilentNotificationHandler,
17558
+ Space: () => import_sdk_core25.Space,
17559
+ SpaceErrorCodes: () => import_sdk_core25.SpaceErrorCodes,
17560
+ SpaceService: () => import_sdk_core25.SpaceService,
17561
+ TC832_RESERVED_SCOPES: () => import_sdk_core20.TC832_RESERVED_SCOPES,
17562
+ TinyCloud: () => import_sdk_core14.TinyCloud,
17563
+ TinyCloudDebugLogger: () => import_sdk_core15.TinyCloudDebugLogger,
17095
17564
  TinyCloudNode: () => TinyCloudNode,
17096
- UnsupportedFeatureError: () => import_sdk_core22.UnsupportedFeatureError,
17565
+ UnsupportedFeatureError: () => import_sdk_core26.UnsupportedFeatureError,
17097
17566
  UnsupportedSessionRestoreError: () => UnsupportedSessionRestoreError,
17098
- VAULT_PERMISSION_SERVICE: () => import_sdk_core12.VAULT_PERMISSION_SERVICE,
17099
- VaultHeaders: () => import_sdk_core16.VaultHeaders,
17100
- VaultPublicSpaceKVActions: () => import_sdk_core16.VaultPublicSpaceKVActions,
17101
- VersionCheckError: () => import_sdk_core22.VersionCheckError,
17567
+ VAULT_PERMISSION_SERVICE: () => import_sdk_core16.VAULT_PERMISSION_SERVICE,
17568
+ VaultHeaders: () => import_sdk_core20.VaultHeaders,
17569
+ VaultPublicSpaceKVActions: () => import_sdk_core20.VaultPublicSpaceKVActions,
17570
+ VersionCheckError: () => import_sdk_core26.VersionCheckError,
17102
17571
  WasmKeyProvider: () => WasmKeyProvider,
17103
17572
  activateCompactRuntimeDelegation: () => activateCompactRuntimeDelegation,
17104
17573
  activateValidatedRuntimeDelegation: () => activateValidatedRuntimeDelegation,
17105
- addressStorageKey: () => import_sdk_core11.addressStorageKey,
17106
- appSecretScope: () => import_sdk_core16.appSecretScope,
17107
- buildCanonicalDecryptRequest: () => import_sdk_core17.buildCanonicalDecryptRequest,
17108
- buildDecryptAttenuation: () => import_sdk_core17.buildDecryptAttenuation,
17109
- buildDecryptFacts: () => import_sdk_core17.buildDecryptFacts,
17110
- buildDecryptInvocation: () => import_sdk_core17.buildDecryptInvocation,
17111
- buildNetworkId: () => import_sdk_core17.buildNetworkId,
17112
- buildSpaceUri: () => import_sdk_core21.buildSpaceUri,
17113
- canonicalHashHex: () => import_sdk_core17.canonicalHashHex,
17114
- canonicalSignedResponse: () => import_sdk_core17.canonicalSignedResponse,
17115
- canonicalizeAddress: () => import_sdk_core11.canonicalizeAddress,
17116
- canonicalizeDid: () => import_sdk_core11.canonicalizeDid,
17117
- canonicalizeDidUrl: () => import_sdk_core11.canonicalizeDidUrl,
17118
- canonicalizeEncryptionJson: () => import_sdk_core17.canonicalizeEncryptionJson,
17119
- canonicalizeNetworkId: () => import_sdk_core11.canonicalizeNetworkId,
17120
- canonicalizeSecretScope: () => import_sdk_core16.canonicalizeSecretScope,
17121
- checkDecryptInvocationInput: () => import_sdk_core17.checkDecryptInvocationInput,
17122
- checkNodeInfo: () => import_sdk_core22.checkNodeInfo,
17123
- clearTinyCloudDebugLogs: () => import_sdk_core11.clearTinyCloudDebugLogs,
17124
- composeManifestRequest: () => import_sdk_core12.composeManifestRequest,
17125
- createCapabilityKeyRegistry: () => import_sdk_core20.createCapabilityKeyRegistry,
17126
- createOpenKeyCallbackSigningStrategy: () => import_sdk_core2.createOpenKeyCallbackSigningStrategy,
17127
- createSharingService: () => import_sdk_core19.createSharingService,
17128
- createSpaceService: () => import_sdk_core21.createSpaceService,
17129
- createVaultCrypto: () => import_sdk_core16.createVaultCrypto,
17574
+ addressStorageKey: () => import_sdk_core15.addressStorageKey,
17575
+ appSecretScope: () => import_sdk_core20.appSecretScope,
17576
+ buildCanonicalDecryptRequest: () => import_sdk_core21.buildCanonicalDecryptRequest,
17577
+ buildDecryptAttenuation: () => import_sdk_core21.buildDecryptAttenuation,
17578
+ buildDecryptFacts: () => import_sdk_core21.buildDecryptFacts,
17579
+ buildDecryptInvocation: () => import_sdk_core21.buildDecryptInvocation,
17580
+ buildNetworkId: () => import_sdk_core21.buildNetworkId,
17581
+ buildSpaceUri: () => import_sdk_core25.buildSpaceUri,
17582
+ canonicalHashHex: () => import_sdk_core21.canonicalHashHex,
17583
+ canonicalSignedResponse: () => import_sdk_core21.canonicalSignedResponse,
17584
+ canonicalizeAddress: () => import_sdk_core15.canonicalizeAddress,
17585
+ canonicalizeDid: () => import_sdk_core15.canonicalizeDid,
17586
+ canonicalizeDidUrl: () => import_sdk_core15.canonicalizeDidUrl,
17587
+ canonicalizeEncryptionJson: () => import_sdk_core21.canonicalizeEncryptionJson,
17588
+ canonicalizeNetworkId: () => import_sdk_core15.canonicalizeNetworkId,
17589
+ canonicalizeSecretScope: () => import_sdk_core20.canonicalizeSecretScope,
17590
+ checkDecryptInvocationInput: () => import_sdk_core21.checkDecryptInvocationInput,
17591
+ checkNodeInfo: () => import_sdk_core26.checkNodeInfo,
17592
+ clearTinyCloudDebugLogs: () => import_sdk_core15.clearTinyCloudDebugLogs,
17593
+ composeManifestRequest: () => import_sdk_core16.composeManifestRequest,
17594
+ createCapabilityKeyRegistry: () => import_sdk_core24.createCapabilityKeyRegistry,
17595
+ createOpenKeyCallbackSigningStrategy: () => import_sdk_core3.createOpenKeyCallbackSigningStrategy,
17596
+ createSharingService: () => import_sdk_core23.createSharingService,
17597
+ createSpaceService: () => import_sdk_core25.createSpaceService,
17598
+ createVaultCrypto: () => import_sdk_core20.createVaultCrypto,
17130
17599
  createWasmKeyProvider: () => createWasmKeyProvider,
17131
- decryptEnvelopeWithKey: () => import_sdk_core17.decryptEnvelopeWithKey,
17600
+ decryptEnvelopeWithKey: () => import_sdk_core21.decryptEnvelopeWithKey,
17132
17601
  defaultSignStrategy: () => defaultSignStrategy,
17133
- defaultSpaceCreationHandler: () => import_sdk_core11.defaultSpaceCreationHandler,
17134
- deriveSignedReceiverKey: () => import_sdk_core17.deriveSignedReceiverKey,
17602
+ defaultSpaceCreationHandler: () => import_sdk_core15.defaultSpaceCreationHandler,
17603
+ deriveSignedReceiverKey: () => import_sdk_core21.deriveSignedReceiverKey,
17135
17604
  deserializeDelegation: () => deserializeDelegation,
17136
- didCacheKey: () => import_sdk_core11.didCacheKey,
17137
- didEquals: () => import_sdk_core11.didEquals,
17138
- disableTinyCloudDebug: () => import_sdk_core11.disableTinyCloudDebug,
17139
- discoverNetwork: () => import_sdk_core17.discoverNetwork,
17140
- enableTinyCloudDebug: () => import_sdk_core11.enableTinyCloudDebug,
17141
- encryptToNetwork: () => import_sdk_core17.encryptToNetwork,
17142
- encryptionBase64Decode: () => import_sdk_core17.encryptionBase64Decode,
17143
- encryptionBase64Encode: () => import_sdk_core17.encryptionBase64Encode,
17144
- encryptionError: () => import_sdk_core17.encryptionError,
17145
- encryptionUtf8Decode: () => import_sdk_core17.encryptionUtf8Decode,
17146
- encryptionUtf8Encode: () => import_sdk_core17.encryptionUtf8Encode,
17147
- ensureNetworkUsableForDecrypt: () => import_sdk_core17.ensureNetworkUsableForDecrypt,
17148
- expandActionShortNames: () => import_sdk_core12.expandActionShortNames,
17149
- expandPermissionEntries: () => import_sdk_core12.expandPermissionEntries,
17150
- expandPermissionEntry: () => import_sdk_core12.expandPermissionEntry,
17605
+ didCacheKey: () => import_sdk_core15.didCacheKey,
17606
+ didEquals: () => import_sdk_core15.didEquals,
17607
+ disableTinyCloudDebug: () => import_sdk_core15.disableTinyCloudDebug,
17608
+ discoverNetwork: () => import_sdk_core21.discoverNetwork,
17609
+ enableTinyCloudDebug: () => import_sdk_core15.enableTinyCloudDebug,
17610
+ encryptToNetwork: () => import_sdk_core21.encryptToNetwork,
17611
+ encryptionBase64Decode: () => import_sdk_core21.encryptionBase64Decode,
17612
+ encryptionBase64Encode: () => import_sdk_core21.encryptionBase64Encode,
17613
+ encryptionError: () => import_sdk_core21.encryptionError,
17614
+ encryptionUtf8Decode: () => import_sdk_core21.encryptionUtf8Decode,
17615
+ encryptionUtf8Encode: () => import_sdk_core21.encryptionUtf8Encode,
17616
+ ensureNetworkUsableForDecrypt: () => import_sdk_core21.ensureNetworkUsableForDecrypt,
17617
+ expandActionShortNames: () => import_sdk_core16.expandActionShortNames,
17618
+ expandPermissionEntries: () => import_sdk_core16.expandPermissionEntries,
17619
+ expandPermissionEntry: () => import_sdk_core16.expandPermissionEntry,
17151
17620
  extractSiweExpiration: () => extractSiweExpiration,
17152
- generateRandomReceiverKey: () => import_sdk_core17.generateRandomReceiverKey,
17153
- getTinyCloudDebugLogs: () => import_sdk_core11.getTinyCloudDebugLogs,
17621
+ generateRandomReceiverKey: () => import_sdk_core21.generateRandomReceiverKey,
17622
+ getTinyCloudDebugLogs: () => import_sdk_core15.getTinyCloudDebugLogs,
17154
17623
  grantAuthRequest: () => grantAuthRequest,
17155
- hexDecode: () => import_sdk_core17.hexDecode,
17156
- hexEncode: () => import_sdk_core17.hexEncode,
17157
- installTinyCloudDebugGlobals: () => import_sdk_core11.installTinyCloudDebugGlobals,
17158
- isCapabilitySubset: () => import_sdk_core12.isCapabilitySubset,
17159
- isEvmAddress: () => import_sdk_core11.isEvmAddress,
17160
- isNetworkId: () => import_sdk_core17.isNetworkId,
17161
- isStorageFullError: () => import_sdk_core11.isStorageFullError,
17162
- loadManifest: () => import_sdk_core12.loadManifest,
17163
- makePkhSpaceId: () => import_sdk_core11.makePkhSpaceId,
17164
- makePublicSpaceId: () => import_sdk_core21.makePublicSpaceId,
17165
- networkDiscoveryKey: () => import_sdk_core17.networkDiscoveryKey,
17166
- openWrappedKey: () => import_sdk_core17.openWrappedKey,
17167
- parseCanonicalNetworkId: () => import_sdk_core11.parseCanonicalNetworkId,
17168
- parseExpiry: () => import_sdk_core12.parseExpiry,
17169
- parseNetworkId: () => import_sdk_core17.parseNetworkId,
17170
- parsePkhDid: () => import_sdk_core11.parsePkhDid,
17171
- parseSecretCatalogKey: () => import_sdk_core16.parseSecretCatalogKey,
17172
- parseSpaceUri: () => import_sdk_core21.parseSpaceUri,
17173
- pkhDid: () => import_sdk_core11.pkhDid,
17174
- principalDid: () => import_sdk_core11.principalDid,
17175
- principalDidEquals: () => import_sdk_core11.principalDidEquals,
17176
- resolveManifest: () => import_sdk_core12.resolveManifest,
17177
- resolveSecretListPrefix: () => import_sdk_core16.resolveSecretListPrefix,
17178
- resolveSecretPath: () => import_sdk_core16.resolveSecretPath,
17179
- resourceCapabilitiesToSpaceAbilitiesMap: () => import_sdk_core12.resourceCapabilitiesToSpaceAbilitiesMap,
17624
+ hexDecode: () => import_sdk_core21.hexDecode,
17625
+ hexEncode: () => import_sdk_core21.hexEncode,
17626
+ installTinyCloudDebugGlobals: () => import_sdk_core15.installTinyCloudDebugGlobals,
17627
+ isCapabilitySubset: () => import_sdk_core16.isCapabilitySubset,
17628
+ isEvmAddress: () => import_sdk_core15.isEvmAddress,
17629
+ isNetworkId: () => import_sdk_core21.isNetworkId,
17630
+ isStorageFullError: () => import_sdk_core15.isStorageFullError,
17631
+ loadManifest: () => import_sdk_core16.loadManifest,
17632
+ makePkhSpaceId: () => import_sdk_core15.makePkhSpaceId,
17633
+ makePublicSpaceId: () => import_sdk_core25.makePublicSpaceId,
17634
+ networkDiscoveryKey: () => import_sdk_core21.networkDiscoveryKey,
17635
+ openWrappedKey: () => import_sdk_core21.openWrappedKey,
17636
+ parseCanonicalNetworkId: () => import_sdk_core15.parseCanonicalNetworkId,
17637
+ parseExpiry: () => import_sdk_core16.parseExpiry,
17638
+ parseNetworkId: () => import_sdk_core21.parseNetworkId,
17639
+ parsePkhDid: () => import_sdk_core15.parsePkhDid,
17640
+ parseSecretCatalogKey: () => import_sdk_core20.parseSecretCatalogKey,
17641
+ parseSpaceUri: () => import_sdk_core25.parseSpaceUri,
17642
+ pkhDid: () => import_sdk_core15.pkhDid,
17643
+ principalDid: () => import_sdk_core15.principalDid,
17644
+ principalDidEquals: () => import_sdk_core15.principalDidEquals,
17645
+ resolveManifest: () => import_sdk_core16.resolveManifest,
17646
+ resolveSecretListPrefix: () => import_sdk_core20.resolveSecretListPrefix,
17647
+ resolveSecretPath: () => import_sdk_core20.resolveSecretPath,
17648
+ resourceCapabilitiesToSpaceAbilitiesMap: () => import_sdk_core16.resourceCapabilitiesToSpaceAbilitiesMap,
17180
17649
  serializeDelegation: () => serializeDelegation,
17181
17650
  signedCompactUcanExpiry: () => signedCompactUcanExpiry,
17182
- tinyCloudDebugLogger: () => import_sdk_core11.tinyCloudDebugLogger,
17183
- validateEnvelope: () => import_sdk_core17.validateEnvelope,
17184
- validateManifest: () => import_sdk_core12.validateManifest,
17185
- verifyDecryptResponse: () => import_sdk_core17.verifyDecryptResponse,
17651
+ sqliteReplicaStorage: () => sqliteReplicaStorage,
17652
+ tinyCloudDebugLogger: () => import_sdk_core15.tinyCloudDebugLogger,
17653
+ validateEnvelope: () => import_sdk_core21.validateEnvelope,
17654
+ validateManifest: () => import_sdk_core16.validateManifest,
17655
+ verifyDecryptResponse: () => import_sdk_core21.verifyDecryptResponse,
17186
17656
  wireOpenKeyAuthorize: () => wireOpenKeyAuthorize
17187
17657
  });
17188
- module.exports = __toCommonJS(index_exports);
17658
+ module.exports = __toCommonJS(src_exports);
17189
17659
 
17190
17660
  // src/NodeWasmBindings.ts
17191
17661
  var import_node_sdk_wasm = require("@tinycloud/node-sdk-wasm");
@@ -17817,16 +18287,32 @@ function deserializeDelegation(data) {
17817
18287
  }
17818
18288
 
17819
18289
  // src/TinyCloudNode.ts
17820
- var import_sdk_core8 = require("@tinycloud/sdk-core");
17821
- var import_sdk_services = require("@tinycloud/sdk-services");
18290
+ init_config();
18291
+
18292
+ // src/replication/module-registry.ts
18293
+ var nodeLoaders;
18294
+ function registerReplicationLoaders(loaders) {
18295
+ nodeLoaders = loaders;
18296
+ }
18297
+ function getNodeReplicationLoaders() {
18298
+ if (nodeLoaders === void 0) {
18299
+ throw new Error("Replication requires registering replication controller loaders.");
18300
+ }
18301
+ return nodeLoaders;
18302
+ }
18303
+
18304
+ // src/TinyCloudNode.ts
18305
+ var import_sdk_core9 = require("@tinycloud/sdk-core");
18306
+ var import_sdk_services3 = require("@tinycloud/sdk-services");
17822
18307
 
17823
18308
  // src/authorization/NodeUserAuthorization.ts
17824
18309
  var import_node_crypto = require("crypto");
17825
18310
  var import_siwe = require("siwe");
17826
- var import_sdk_core3 = require("@tinycloud/sdk-core");
18311
+ var import_sdk_core4 = require("@tinycloud/sdk-core");
18312
+ init_authority_sign_in();
17827
18313
 
17828
18314
  // src/authorization/strategies.ts
17829
- var import_sdk_core2 = require("@tinycloud/sdk-core");
18315
+ var import_sdk_core3 = require("@tinycloud/sdk-core");
17830
18316
  var defaultSignStrategy = { type: "auto-sign" };
17831
18317
 
17832
18318
  // src/storage/MemorySessionStorage.ts
@@ -17901,8 +18387,8 @@ var MemorySessionStorage = class {
17901
18387
  };
17902
18388
 
17903
18389
  // src/authorization/NodeUserAuthorization.ts
17904
- var DECRYPT_ACTION = import_sdk_core3.ENCRYPTION.DECRYPT;
17905
- var NETWORK_CREATE_ACTION = import_sdk_core3.ENCRYPTION.NETWORK_CREATE;
18390
+ var DECRYPT_ACTION = import_sdk_core4.ENCRYPTION.DECRYPT;
18391
+ var NETWORK_CREATE_ACTION = import_sdk_core4.ENCRYPTION.NETWORK_CREATE;
17906
18392
  function describeHostFailure(result) {
17907
18393
  const text = result.error?.trim();
17908
18394
  return text ? `${result.status} - ${text}` : `${result.status}`;
@@ -17930,7 +18416,7 @@ function canonicalOpenKeyManifestSha256Hex(value) {
17930
18416
  }
17931
18417
  function didPrincipalMatches(actual, expected) {
17932
18418
  try {
17933
- return (0, import_sdk_core3.principalDidEquals)(actual, expected);
18419
+ return (0, import_sdk_core4.principalDidEquals)(actual, expected);
17934
18420
  } catch {
17935
18421
  return actual === expected;
17936
18422
  }
@@ -17971,30 +18457,30 @@ var NodeUserAuthorization = class {
17971
18457
  this.spacePrefix = config.spacePrefix ?? "default";
17972
18458
  this.defaultActions = config.defaultActions ?? {
17973
18459
  kv: {
17974
- "": [import_sdk_core3.KV.PUT, import_sdk_core3.KV.GET, import_sdk_core3.KV.DEL, import_sdk_core3.KV.LIST, import_sdk_core3.KV.METADATA]
18460
+ "": [import_sdk_core4.KV.PUT, import_sdk_core4.KV.GET, import_sdk_core4.KV.DEL, import_sdk_core4.KV.LIST, import_sdk_core4.KV.METADATA]
17975
18461
  },
17976
18462
  sql: {
17977
- "": [import_sdk_core3.SQL.READ, import_sdk_core3.SQL.WRITE, import_sdk_core3.SQL.SCHEMA, import_sdk_core3.SQL.ADMIN, import_sdk_core3.SQL.EXPORT]
18463
+ "": [import_sdk_core4.SQL.READ, import_sdk_core4.SQL.WRITE, import_sdk_core4.SQL.SCHEMA, import_sdk_core4.SQL.ADMIN, import_sdk_core4.SQL.EXPORT]
17978
18464
  },
17979
18465
  duckdb: {
17980
18466
  "": [
17981
- import_sdk_core3.DUCKDB.READ,
17982
- import_sdk_core3.DUCKDB.WRITE,
17983
- import_sdk_core3.DUCKDB.ADMIN,
17984
- import_sdk_core3.DUCKDB.DESCRIBE,
17985
- import_sdk_core3.DUCKDB.EXPORT,
17986
- import_sdk_core3.DUCKDB.IMPORT,
17987
- import_sdk_core3.DUCKDB.EXECUTE
18467
+ import_sdk_core4.DUCKDB.READ,
18468
+ import_sdk_core4.DUCKDB.WRITE,
18469
+ import_sdk_core4.DUCKDB.ADMIN,
18470
+ import_sdk_core4.DUCKDB.DESCRIBE,
18471
+ import_sdk_core4.DUCKDB.EXPORT,
18472
+ import_sdk_core4.DUCKDB.IMPORT,
18473
+ import_sdk_core4.DUCKDB.EXECUTE
17988
18474
  ]
17989
18475
  },
17990
18476
  capabilities: {
17991
- "": [import_sdk_core3.CAPABILITIES.READ]
18477
+ "": [import_sdk_core4.CAPABILITIES.READ]
17992
18478
  },
17993
18479
  hooks: {
17994
- "": [import_sdk_core3.HOOKS.SUBSCRIBE, import_sdk_core3.HOOKS.REGISTER, import_sdk_core3.HOOKS.LIST, import_sdk_core3.HOOKS.UNREGISTER]
18480
+ "": [import_sdk_core4.HOOKS.SUBSCRIBE, import_sdk_core4.HOOKS.REGISTER, import_sdk_core4.HOOKS.LIST, import_sdk_core4.HOOKS.UNREGISTER]
17995
18481
  }
17996
18482
  };
17997
- this.sessionExpirationMs = config.sessionExpirationMs ?? import_sdk_core3.EXPIRY.SESSION_MS;
18483
+ this.sessionExpirationMs = config.sessionExpirationMs ?? import_sdk_core4.EXPIRY.SESSION_MS;
17998
18484
  this.autoCreateSpace = config.autoCreateSpace ?? false;
17999
18485
  this.spaceCreationHandler = config.spaceCreationHandler;
18000
18486
  this.tinycloudHosts = config.tinycloudHosts;
@@ -18009,6 +18495,7 @@ var NodeUserAuthorization = class {
18009
18495
  this.nonce = config.nonce;
18010
18496
  this.siweConfig = config.siweConfig;
18011
18497
  this.includeAccountRegistryPermissions = config.includeAccountRegistryPermissions ?? true;
18498
+ this.replication = config.replication?.enabled === true ? config.replication : void 0;
18012
18499
  this._manifest = config.manifest;
18013
18500
  this._capabilityRequest = config.capabilityRequest;
18014
18501
  this.sessionManager = config.sessionManager ?? this.wasm.createSessionManager();
@@ -18073,7 +18560,7 @@ var NodeUserAuthorization = class {
18073
18560
  * {@link ensureTinyCloudHosts}.
18074
18561
  */
18075
18562
  setRestoredTinyCloudSession(session, hosts) {
18076
- const address = (0, import_sdk_core3.canonicalizeAddress)(session.address);
18563
+ const address = (0, import_sdk_core4.canonicalizeAddress)(session.address);
18077
18564
  this._tinyCloudSession = { ...session, address };
18078
18565
  this._address = address;
18079
18566
  this._chainId = session.chainId;
@@ -18134,8 +18621,8 @@ var NodeUserAuthorization = class {
18134
18621
  if (this.tinycloudHosts && this.tinycloudHosts.length > 0) {
18135
18622
  return;
18136
18623
  }
18137
- const subject = (0, import_sdk_core3.pkhDid)(address, chainId);
18138
- const resolved = await (0, import_sdk_core3.resolveTinyCloudHosts)(subject, {
18624
+ const subject = (0, import_sdk_core4.pkhDid)(address, chainId);
18625
+ const resolved = await (0, import_sdk_core4.resolveTinyCloudHosts)(subject, {
18139
18626
  registryUrl: this.tinycloudRegistryUrl,
18140
18627
  fallbackHosts: this.tinycloudFallbackHosts,
18141
18628
  autoDiscoverLocalNode: this.autoDiscoverLocalNode,
@@ -18203,7 +18690,7 @@ var NodeUserAuthorization = class {
18203
18690
  if (this._manifest === void 0) {
18204
18691
  return void 0;
18205
18692
  }
18206
- this._capabilityRequest = (0, import_sdk_core3.composeManifestRequest)(
18693
+ this._capabilityRequest = (0, import_sdk_core4.composeManifestRequest)(
18207
18694
  Array.isArray(this._manifest) ? this._manifest : [this._manifest],
18208
18695
  {
18209
18696
  includeAccountRegistryPermissions: this.includeAccountRegistryPermissions
@@ -18215,50 +18702,173 @@ var NodeUserAuthorization = class {
18215
18702
  if (space.startsWith("tinycloud:")) {
18216
18703
  return space;
18217
18704
  }
18218
- return (0, import_sdk_core3.makePkhSpaceId)(address, chainId, space);
18705
+ return (0, import_sdk_core4.makePkhSpaceId)(address, chainId, space);
18706
+ }
18707
+ /**
18708
+ * The plain-session primary abilities: `defaultActions` (the shared table)
18709
+ * unless the primary space IS the account space, where account-registry
18710
+ * permissions merge into a private clone so the shared table is never
18711
+ * mutated. Shared between `resolveSignInCapabilities` and
18712
+ * `signInPermissionInputs` so sign-in and `replicationSignInEntries`
18713
+ * can't disagree (§4.6).
18714
+ */
18715
+ primaryActionsForSignIn() {
18716
+ const primaryActions = this.includeAccountRegistryPermissions && this.spacePrefix === import_sdk_core4.ACCOUNT_REGISTRY_SPACE ? cloneAbilitiesMap(this.defaultActions) : this.defaultActions;
18717
+ if (this.includeAccountRegistryPermissions && this.spacePrefix === import_sdk_core4.ACCOUNT_REGISTRY_SPACE) {
18718
+ const accountAbilities = (0, import_sdk_core4.resourceCapabilitiesToAbilitiesMap)(
18719
+ import_sdk_core4.ACCOUNT_MANIFEST_PERMISSIONS
18720
+ );
18721
+ for (const [service, paths] of Object.entries(accountAbilities)) {
18722
+ const existingPaths = primaryActions[service] ?? (primaryActions[service] = {});
18723
+ for (const [path, actions] of Object.entries(paths)) {
18724
+ const existingActions = existingPaths[path] ?? (existingPaths[path] = []);
18725
+ for (const action of actions) {
18726
+ if (!existingActions.includes(action)) existingActions.push(action);
18727
+ }
18728
+ }
18729
+ }
18730
+ }
18731
+ return primaryActions;
18732
+ }
18733
+ /**
18734
+ * The abilities a `spacePrefix: "secrets"` plain session actually requests
18735
+ * for its primary space: the vault-secrets subtree only — the
18736
+ * `defaultActions` root `get` is REPLACED, not merged (sign-in installs
18737
+ * this map under the primary space id). Shared between
18738
+ * `resolveSignInCapabilities` and `signInPermissionInputs` so the
18739
+ * replication augmentation measures coverage against the effective
18740
+ * pre-replication request, never the uninstalled `primaryActions` (§4.1).
18741
+ */
18742
+ secretsPrimaryAbilities() {
18743
+ return {
18744
+ kv: {
18745
+ "vault/secrets/": [
18746
+ import_sdk_core4.KV.GET,
18747
+ import_sdk_core4.KV.PUT,
18748
+ import_sdk_core4.KV.DEL,
18749
+ import_sdk_core4.KV.LIST,
18750
+ import_sdk_core4.KV.METADATA
18751
+ ]
18752
+ }
18753
+ };
18754
+ }
18755
+ /**
18756
+ * The effective sign-in request as `PermissionEntry`s plus the resolved
18757
+ * primary space id — the inputs to the replication augmentation (§4.1).
18758
+ * `resolveSignInCapabilities` merges the augmented entries into its
18759
+ * abilities; `replicationSignInEntries()` returns them verbatim, so the
18760
+ * entries the SIWE recap carries and the restore check sees are the same.
18761
+ */
18762
+ signInPermissionInputs(address, chainId) {
18763
+ const request = this.getCapabilityRequest();
18764
+ if (request === void 0) {
18765
+ const primarySpaceId2 = (0, import_sdk_core4.makePkhSpaceId)(address, chainId, this.spacePrefix);
18766
+ const effectivePrimary = this.spacePrefix === "secrets" ? this.secretsPrimaryAbilities() : this.primaryActionsForSignIn();
18767
+ const kvPaths = effectivePrimary["kv"] ?? {};
18768
+ return {
18769
+ primarySpaceId: primarySpaceId2,
18770
+ entries: Object.entries(kvPaths).map(([path, actions]) => ({
18771
+ service: "tinycloud.kv",
18772
+ space: primarySpaceId2,
18773
+ path,
18774
+ actions: [...actions]
18775
+ }))
18776
+ };
18777
+ }
18778
+ const spaceResources = request.resources.filter(
18779
+ (entry) => entry.service !== import_sdk_core4.ENCRYPTION_PERMISSION_SERVICE
18780
+ );
18781
+ const primarySpaceName = spaceResources.find((entry) => entry.space !== "account")?.space ?? import_sdk_core4.DEFAULT_MANIFEST_SPACE;
18782
+ const primarySpaceId = this.resolveSpaceName(
18783
+ primarySpaceName,
18784
+ address,
18785
+ chainId
18786
+ );
18787
+ return {
18788
+ primarySpaceId,
18789
+ entries: spaceResources.map((entry) => ({
18790
+ service: entry.service,
18791
+ space: this.resolveSpaceName(entry.space, address, chainId),
18792
+ path: entry.path,
18793
+ actions: [...entry.actions]
18794
+ }))
18795
+ };
18796
+ }
18797
+ /**
18798
+ * Merge replication augmentation entries into a space's abilities map
18799
+ * without mutating shared tables (`defaultActions` may back the base map):
18800
+ * the primary entry in `spaceAbilities` is replaced with a copy whose `kv`
18801
+ * paths gain `get`/`sync`. Returns the merged map for `abilities`.
18802
+ */
18803
+ mergeReplicationEntries(spaceAbilities, primarySpaceId, abilities, entries) {
18804
+ var _a;
18805
+ if (entries.length === 0) {
18806
+ return abilities;
18807
+ }
18808
+ const base2 = spaceAbilities[primarySpaceId] ?? abilities;
18809
+ const kv = {};
18810
+ for (const [path, actions] of Object.entries(base2["kv"] ?? {})) {
18811
+ kv[path] = [...actions];
18812
+ }
18813
+ for (const entry of entries) {
18814
+ const list = kv[_a = entry.path] ?? (kv[_a] = []);
18815
+ for (const action of entry.actions) {
18816
+ if (!list.includes(action)) list.push(action);
18817
+ }
18818
+ }
18819
+ const merged = { ...base2, kv };
18820
+ spaceAbilities[primarySpaceId] = merged;
18821
+ return merged;
18822
+ }
18823
+ /**
18824
+ * The replication entries this authorization's sign-in request carries
18825
+ * for the signed-in or restored address (TC-858 §4.1/§4.6): the output of
18826
+ * the same augmentation `resolveSignInCapabilities` runs — one
18827
+ * `{tinycloud.kv, primarySpace, prefix, [get, sync]}` per configured
18828
+ * prefix that already has an unrestricted covering `get` and passes the
18829
+ * secrets opt-in gate. Empty when replication is off or no address is
18830
+ * known. Pure.
18831
+ */
18832
+ replicationSignInEntries() {
18833
+ if (this.replication === void 0) return [];
18834
+ const address = this._address ?? this._tinyCloudSession?.address;
18835
+ const chainId = this._chainId ?? this._tinyCloudSession?.chainId;
18836
+ if (address === void 0 || chainId === void 0) return [];
18837
+ const { entries, primarySpaceId } = this.signInPermissionInputs(address, chainId);
18838
+ return augmentSignInEntriesWithReplication({
18839
+ entries,
18840
+ primarySpaceId,
18841
+ replication: this.replication
18842
+ });
18219
18843
  }
18220
18844
  defaultEncryptionNetworkId(address, chainId) {
18221
- return `urn:tinycloud:encryption:${(0, import_sdk_core3.pkhDid)(address, chainId)}:default`;
18845
+ return `urn:tinycloud:encryption:${(0, import_sdk_core4.pkhDid)(address, chainId)}:default`;
18222
18846
  }
18223
18847
  resolveSignInCapabilities(address, chainId) {
18224
18848
  const request = this.getCapabilityRequest();
18225
18849
  if (request === void 0) {
18226
18850
  const defaultNetworkId = this.defaultEncryptionNetworkId(address, chainId);
18227
- const primarySpaceId2 = (0, import_sdk_core3.makePkhSpaceId)(address, chainId, this.spacePrefix);
18228
- const secretsSpaceId = (0, import_sdk_core3.makePkhSpaceId)(address, chainId, "secrets");
18229
- const primaryActions = this.includeAccountRegistryPermissions && this.spacePrefix === import_sdk_core3.ACCOUNT_REGISTRY_SPACE ? cloneAbilitiesMap(this.defaultActions) : this.defaultActions;
18851
+ const primarySpaceId2 = (0, import_sdk_core4.makePkhSpaceId)(address, chainId, this.spacePrefix);
18852
+ const secretsSpaceId = (0, import_sdk_core4.makePkhSpaceId)(address, chainId, "secrets");
18853
+ const primaryActions = this.primaryActionsForSignIn();
18230
18854
  const spaceAbilities2 = {
18231
18855
  [primarySpaceId2]: primaryActions,
18232
- [secretsSpaceId]: {
18233
- kv: {
18234
- "vault/secrets/": [
18235
- import_sdk_core3.KV.GET,
18236
- import_sdk_core3.KV.PUT,
18237
- import_sdk_core3.KV.DEL,
18238
- import_sdk_core3.KV.LIST,
18239
- import_sdk_core3.KV.METADATA
18240
- ]
18241
- }
18242
- }
18856
+ [secretsSpaceId]: this.secretsPrimaryAbilities()
18243
18857
  };
18244
- if (this.includeAccountRegistryPermissions && this.spacePrefix !== import_sdk_core3.ACCOUNT_REGISTRY_SPACE) {
18245
- spaceAbilities2[(0, import_sdk_core3.makePkhSpaceId)(address, chainId, import_sdk_core3.ACCOUNT_REGISTRY_SPACE)] = (0, import_sdk_core3.resourceCapabilitiesToAbilitiesMap)(import_sdk_core3.ACCOUNT_MANIFEST_PERMISSIONS);
18246
- } else if (this.includeAccountRegistryPermissions) {
18247
- const accountAbilities = (0, import_sdk_core3.resourceCapabilitiesToAbilitiesMap)(
18248
- import_sdk_core3.ACCOUNT_MANIFEST_PERMISSIONS
18249
- );
18250
- for (const [service, paths] of Object.entries(accountAbilities)) {
18251
- const existingPaths = primaryActions[service] ?? (primaryActions[service] = {});
18252
- for (const [path, actions] of Object.entries(paths)) {
18253
- const existingActions = existingPaths[path] ?? (existingPaths[path] = []);
18254
- for (const action of actions) {
18255
- if (!existingActions.includes(action)) existingActions.push(action);
18256
- }
18257
- }
18258
- }
18259
- }
18858
+ if (this.includeAccountRegistryPermissions && this.spacePrefix !== import_sdk_core4.ACCOUNT_REGISTRY_SPACE) {
18859
+ spaceAbilities2[(0, import_sdk_core4.makePkhSpaceId)(address, chainId, import_sdk_core4.ACCOUNT_REGISTRY_SPACE)] = (0, import_sdk_core4.resourceCapabilitiesToAbilitiesMap)(import_sdk_core4.ACCOUNT_MANIFEST_PERMISSIONS);
18860
+ }
18861
+ const mergedPrimary = this.mergeReplicationEntries(
18862
+ spaceAbilities2,
18863
+ primarySpaceId2,
18864
+ primaryActions,
18865
+ augmentSignInEntriesWithReplication({
18866
+ ...this.signInPermissionInputs(address, chainId),
18867
+ replication: this.replication
18868
+ })
18869
+ );
18260
18870
  return {
18261
- abilities: primaryActions,
18871
+ abilities: mergedPrimary,
18262
18872
  spaceId: primarySpaceId2,
18263
18873
  spaceAbilities: spaceAbilities2,
18264
18874
  rawAbilities: {
@@ -18267,35 +18877,44 @@ var NodeUserAuthorization = class {
18267
18877
  };
18268
18878
  }
18269
18879
  const rawAbilities = {};
18270
- const currentDid = (0, import_sdk_core3.pkhDid)(address, chainId);
18880
+ const currentDid = (0, import_sdk_core4.pkhDid)(address, chainId);
18271
18881
  const spaceResources = request.resources.filter((entry) => {
18272
- if (entry.service !== import_sdk_core3.ENCRYPTION_PERMISSION_SERVICE) {
18882
+ if (entry.service !== import_sdk_core4.ENCRYPTION_PERMISSION_SERVICE) {
18273
18883
  return true;
18274
18884
  }
18275
18885
  for (const action of entry.actions) {
18276
18886
  addRawAbility(rawAbilities, entry.path, action);
18277
18887
  }
18278
18888
  if (entry.actions.includes(DECRYPT_ACTION)) {
18279
- const parsed = (0, import_sdk_core3.parseNetworkId)(entry.path);
18889
+ const parsed = (0, import_sdk_core4.parseNetworkId)(entry.path);
18280
18890
  if (didPrincipalMatches(parsed.ownerDid, currentDid)) {
18281
18891
  addRawAbility(rawAbilities, entry.path, NETWORK_CREATE_ACTION);
18282
18892
  }
18283
18893
  }
18284
18894
  return false;
18285
18895
  });
18286
- const primarySpaceName = spaceResources.find((entry) => entry.space !== "account")?.space ?? import_sdk_core3.DEFAULT_MANIFEST_SPACE;
18896
+ const primarySpaceName = spaceResources.find((entry) => entry.space !== "account")?.space ?? import_sdk_core4.DEFAULT_MANIFEST_SPACE;
18287
18897
  const primarySpaceId = this.resolveSpaceName(
18288
18898
  primarySpaceName,
18289
18899
  address,
18290
18900
  chainId
18291
18901
  );
18292
- const bySpace = (0, import_sdk_core3.resourceCapabilitiesToSpaceAbilitiesMap)(spaceResources);
18902
+ const bySpace = (0, import_sdk_core4.resourceCapabilitiesToSpaceAbilitiesMap)(spaceResources);
18293
18903
  const spaceAbilities = {};
18294
18904
  for (const [space, abilities] of Object.entries(bySpace)) {
18295
18905
  spaceAbilities[this.resolveSpaceName(space, address, chainId)] = abilities;
18296
18906
  }
18907
+ const mergedPrimaryAbilities = this.mergeReplicationEntries(
18908
+ spaceAbilities,
18909
+ primarySpaceId,
18910
+ spaceAbilities[primarySpaceId] ?? (0, import_sdk_core4.resourceCapabilitiesToAbilitiesMap)([]),
18911
+ augmentSignInEntriesWithReplication({
18912
+ ...this.signInPermissionInputs(address, chainId),
18913
+ replication: this.replication
18914
+ })
18915
+ );
18297
18916
  return {
18298
- abilities: spaceAbilities[primarySpaceId] ?? (0, import_sdk_core3.resourceCapabilitiesToAbilitiesMap)([]),
18917
+ abilities: mergedPrimaryAbilities,
18299
18918
  spaceId: primarySpaceId,
18300
18919
  spaceAbilities,
18301
18920
  rawAbilities: Object.keys(rawAbilities).length > 0 ? rawAbilities : void 0
@@ -18353,14 +18972,14 @@ var NodeUserAuthorization = class {
18353
18972
  * Create the space on the TinyCloud server (host delegation).
18354
18973
  * This registers the user as the owner of the space.
18355
18974
  */
18356
- async hostSpace(targetSpaceId, purpose) {
18975
+ async hostSpace(targetSpaceId, purpose, signal) {
18357
18976
  if (!this._tinyCloudSession || !this._address || !this._chainId) {
18358
18977
  throw new Error("Must be signed in to host space");
18359
18978
  }
18360
18979
  await this.ensureTinyCloudHosts();
18361
18980
  const host = this.primaryTinyCloudHost;
18362
18981
  const spaceId = targetSpaceId ?? this._tinyCloudSession.spaceId;
18363
- const peerId = await (0, import_sdk_core3.fetchPeerId)(host, spaceId);
18982
+ const peerId = await (0, import_sdk_core4.fetchPeerId)(host, spaceId, signal);
18364
18983
  const siwe = this.wasm.generateHostSIWEMessage({
18365
18984
  address: this._address,
18366
18985
  chainId: this._chainId,
@@ -18369,9 +18988,28 @@ var NodeUserAuthorization = class {
18369
18988
  spaceId,
18370
18989
  peerId
18371
18990
  });
18372
- const signature2 = await this.signMessage(siwe, purpose);
18991
+ if (signal?.aborted) throw signal.reason;
18992
+ const signing = this.signMessage(siwe, purpose);
18993
+ let signature2;
18994
+ if (!signal) {
18995
+ signature2 = await signing;
18996
+ } else {
18997
+ let rejectOnAbort;
18998
+ const aborted = new Promise((_resolve, reject2) => {
18999
+ rejectOnAbort = reject2;
19000
+ });
19001
+ const onAbort = () => rejectOnAbort(signal.reason);
19002
+ signal.addEventListener("abort", onAbort, { once: true });
19003
+ if (signal.aborted) onAbort();
19004
+ try {
19005
+ signature2 = await Promise.race([signing, aborted]);
19006
+ } finally {
19007
+ signal.removeEventListener("abort", onAbort);
19008
+ }
19009
+ }
19010
+ if (signal?.aborted) throw signal.reason;
18373
19011
  const headers = this.wasm.siweToDelegationHeaders({ siwe, signature: signature2 });
18374
- return (0, import_sdk_core3.submitHostDelegation)(host, headers);
19012
+ return (0, import_sdk_core4.submitHostDelegation)(host, headers, signal);
18375
19013
  }
18376
19014
  /**
18377
19015
  * Create a specific space on the server via host delegation.
@@ -18392,8 +19030,8 @@ var NodeUserAuthorization = class {
18392
19030
  * keeps its HTTP status (e.g. a typed 401/403) instead of collapsing to
18393
19031
  * `false`.
18394
19032
  */
18395
- async hostOwnedSpaceResult(spaceId, purpose) {
18396
- return this.hostSpace(spaceId, purpose);
19033
+ async hostOwnedSpaceResult(spaceId, purpose, signal) {
19034
+ return this.hostSpace(spaceId, purpose, signal);
18397
19035
  }
18398
19036
  /**
18399
19037
  * Ensure the user's space exists on the TinyCloud server.
@@ -18410,12 +19048,12 @@ var NodeUserAuthorization = class {
18410
19048
  await this.ensureTinyCloudHosts();
18411
19049
  const host = this.primaryTinyCloudHost;
18412
19050
  const primarySpaceId = this._tinyCloudSession.spaceId;
18413
- const result = await (0, import_sdk_core3.activateSessionWithHost)(
19051
+ const result = await (0, import_sdk_core4.activateSessionWithHost)(
18414
19052
  host,
18415
19053
  this._tinyCloudSession.delegationHeader
18416
19054
  );
18417
19055
  this.recordActivationSkippedSpaces(result, primarySpaceId);
18418
- const handler = this.spaceCreationHandler ?? (this.autoCreateSpace ? new import_sdk_core3.AutoApproveSpaceCreationHandler() : void 0);
19056
+ const handler = this.spaceCreationHandler ?? (this.autoCreateSpace ? new import_sdk_core4.AutoApproveSpaceCreationHandler() : void 0);
18419
19057
  const creationContext = {
18420
19058
  spaceId: primarySpaceId,
18421
19059
  address: this._address,
@@ -18451,7 +19089,7 @@ var NodeUserAuthorization = class {
18451
19089
  throw error;
18452
19090
  }
18453
19091
  await new Promise((resolve) => setTimeout(resolve, 100));
18454
- const retryResult = await (0, import_sdk_core3.activateSessionWithHost)(
19092
+ const retryResult = await (0, import_sdk_core4.activateSessionWithHost)(
18455
19093
  host,
18456
19094
  this._tinyCloudSession.delegationHeader
18457
19095
  );
@@ -18491,7 +19129,7 @@ var NodeUserAuthorization = class {
18491
19129
  throw error;
18492
19130
  }
18493
19131
  await new Promise((resolve) => setTimeout(resolve, 100));
18494
- const retryResult = await (0, import_sdk_core3.activateSessionWithHost)(
19132
+ const retryResult = await (0, import_sdk_core4.activateSessionWithHost)(
18495
19133
  host,
18496
19134
  this._tinyCloudSession.delegationHeader
18497
19135
  );
@@ -18533,7 +19171,7 @@ var NodeUserAuthorization = class {
18533
19171
  const jwk = JSON.parse(jwkString);
18534
19172
  const now = /* @__PURE__ */ new Date();
18535
19173
  const expirationTime = new Date(now.getTime() + this.sessionExpirationMs);
18536
- const abilities = (0, import_sdk_core3.resourceCapabilitiesToAbilitiesMap)(
19174
+ const abilities = (0, import_sdk_core4.resourceCapabilitiesToAbilitiesMap)(
18537
19175
  options.capabilityRequest.resources
18538
19176
  );
18539
19177
  const prepared = this.wasm.prepareSession({
@@ -18584,7 +19222,7 @@ var NodeUserAuthorization = class {
18584
19222
  * @param options - Optional per-call SIWE overrides for this sign-in only
18585
19223
  */
18586
19224
  async signIn(options) {
18587
- this._address = (0, import_sdk_core3.canonicalizeAddress)(await this.signer.getAddress());
19225
+ this._address = (0, import_sdk_core4.canonicalizeAddress)(await this.signer.getAddress());
18588
19226
  this._chainId = await this.signer.getChainId();
18589
19227
  const address = this._address;
18590
19228
  const chainId = this._chainId;
@@ -18633,7 +19271,7 @@ var NodeUserAuthorization = class {
18633
19271
  siwe: prepared.siwe,
18634
19272
  signature: signature2
18635
19273
  };
18636
- const spacesMetadata = this.enablePublicSpace ? { public: (0, import_sdk_core3.makePkhSpaceId)(address, chainId, "public") } : void 0;
19274
+ const spacesMetadata = this.enablePublicSpace ? { public: (0, import_sdk_core4.makePkhSpaceId)(address, chainId, "public") } : void 0;
18637
19275
  const tinyCloudSession = {
18638
19276
  address,
18639
19277
  chainId,
@@ -18671,7 +19309,7 @@ var NodeUserAuthorization = class {
18671
19309
  this._address = address;
18672
19310
  this._chainId = chainId;
18673
19311
  const infoHost = this.primaryTinyCloudHost;
18674
- const nodeInfo = await (0, import_sdk_core3.checkNodeInfo)(
19312
+ const nodeInfo = await (0, import_sdk_core4.checkNodeInfo)(
18675
19313
  infoHost,
18676
19314
  this.wasm.protocolVersion()
18677
19315
  );
@@ -18711,7 +19349,7 @@ var NodeUserAuthorization = class {
18711
19349
  */
18712
19350
  async signMessage(message, purpose) {
18713
19351
  if (!this._address) {
18714
- this._address = (0, import_sdk_core3.canonicalizeAddress)(await this.signer.getAddress());
19352
+ this._address = (0, import_sdk_core4.canonicalizeAddress)(await this.signer.getAddress());
18715
19353
  }
18716
19354
  if (!this._chainId) {
18717
19355
  this._chainId = await this.signer.getChainId();
@@ -18739,7 +19377,7 @@ var NodeUserAuthorization = class {
18739
19377
  * ```
18740
19378
  */
18741
19379
  async prepareSessionForSigning() {
18742
- const address = (0, import_sdk_core3.canonicalizeAddress)(await this.signer.getAddress());
19380
+ const address = (0, import_sdk_core4.canonicalizeAddress)(await this.signer.getAddress());
18743
19381
  const chainId = await this.signer.getChainId();
18744
19382
  const keyId = `session-${Date.now()}`;
18745
19383
  this.sessionManager.renameSessionKeyId(this.activeSessionKeyId, keyId);
@@ -18790,7 +19428,7 @@ var NodeUserAuthorization = class {
18790
19428
  ...prepared,
18791
19429
  signature: signature2
18792
19430
  });
18793
- const address = (0, import_sdk_core3.canonicalizeAddress)(await this.signer.getAddress());
19431
+ const address = (0, import_sdk_core4.canonicalizeAddress)(await this.signer.getAddress());
18794
19432
  const chainId = await this.signer.getChainId();
18795
19433
  await this.resolveTinyCloudHostsForSignIn(address, chainId);
18796
19434
  const clientSession = {
@@ -18801,7 +19439,7 @@ var NodeUserAuthorization = class {
18801
19439
  siwe: prepared.siwe,
18802
19440
  signature: signature2
18803
19441
  };
18804
- const spacesMetadata = this.enablePublicSpace ? { public: (0, import_sdk_core3.makePkhSpaceId)(address, chainId, "public") } : void 0;
19442
+ const spacesMetadata = this.enablePublicSpace ? { public: (0, import_sdk_core4.makePkhSpaceId)(address, chainId, "public") } : void 0;
18805
19443
  const tinyCloudSession = {
18806
19444
  address,
18807
19445
  chainId,
@@ -18843,7 +19481,7 @@ var NodeUserAuthorization = class {
18843
19481
  this._address = address;
18844
19482
  this._chainId = chainId;
18845
19483
  const infoHost = this.primaryTinyCloudHost;
18846
- const nodeInfo = await (0, import_sdk_core3.checkNodeInfo)(
19484
+ const nodeInfo = await (0, import_sdk_core4.checkNodeInfo)(
18847
19485
  infoHost,
18848
19486
  this.wasm.protocolVersion()
18849
19487
  );
@@ -18899,7 +19537,7 @@ var NodeUserAuthorization = class {
18899
19537
  }
18900
19538
  this.tinycloudHosts = [overrideHost];
18901
19539
  }
18902
- const signingAddress = (0, import_sdk_core3.canonicalizeAddress)(await this.signer.getAddress());
19540
+ const signingAddress = (0, import_sdk_core4.canonicalizeAddress)(await this.signer.getAddress());
18903
19541
  const signingChainId = await this.signer.getChainId();
18904
19542
  await this.resolveTinyCloudHostsForSignIn(signingAddress, signingChainId);
18905
19543
  const { prepared, keyId, jwk } = await this.prepareSessionForSigning();
@@ -19004,8 +19642,8 @@ var NodeUserAuthorization = class {
19004
19642
  "signInWithOpenKeyResult requires prepared.siwe (the SDK-generated SIWE the sign-in was proposed with)"
19005
19643
  );
19006
19644
  }
19007
- const expectedAddress = (0, import_sdk_core3.canonicalizeAddress)(await this.signer.getAddress());
19008
- if ((0, import_sdk_core3.canonicalizeAddress)(result.address) !== expectedAddress) {
19645
+ const expectedAddress = (0, import_sdk_core4.canonicalizeAddress)(await this.signer.getAddress());
19646
+ if ((0, import_sdk_core4.canonicalizeAddress)(result.address) !== expectedAddress) {
19009
19647
  throw new Error(
19010
19648
  `OpenKey returned signature from ${result.address} but expected ${expectedAddress}`
19011
19649
  );
@@ -19030,15 +19668,15 @@ var NodeUserAuthorization = class {
19030
19668
  `OpenKey signature verification failed${type ? `: ${type}` : ""}${details}`
19031
19669
  );
19032
19670
  }
19033
- if ((0, import_sdk_core3.canonicalizeAddress)(parsedSignedSiwe.address) !== expectedAddress) {
19671
+ if ((0, import_sdk_core4.canonicalizeAddress)(parsedSignedSiwe.address) !== expectedAddress) {
19034
19672
  throw new Error(
19035
19673
  `OpenKey signedMessage.address (${parsedSignedSiwe.address}) does not match local signer address (${expectedAddress})`
19036
19674
  );
19037
19675
  }
19038
19676
  const originalHasRecap = /(?:^|\n)-\s+urn:recap:/i.test(prepared.siwe);
19039
- const originalFields = (0, import_sdk_core3.extractImmutableSiweFields)(prepared.siwe);
19040
- const signedFields = (0, import_sdk_core3.extractImmutableSiweFields)(result.signedMessage);
19041
- const changedFields = (0, import_sdk_core3.diffImmutableSiweFields)(originalFields, signedFields, {
19677
+ const originalFields = (0, import_sdk_core4.extractImmutableSiweFields)(prepared.siwe);
19678
+ const signedFields = (0, import_sdk_core4.extractImmutableSiweFields)(result.signedMessage);
19679
+ const changedFields = (0, import_sdk_core4.diffImmutableSiweFields)(originalFields, signedFields, {
19042
19680
  originalHasRecap
19043
19681
  });
19044
19682
  if (changedFields.length > 0) {
@@ -19049,20 +19687,20 @@ var NodeUserAuthorization = class {
19049
19687
  let originalCaps;
19050
19688
  let signedCaps;
19051
19689
  try {
19052
- originalCaps = (0, import_sdk_core3.extractRecapAttenuations)(prepared.siwe);
19690
+ originalCaps = (0, import_sdk_core4.extractRecapAttenuations)(prepared.siwe);
19053
19691
  } catch (err) {
19054
19692
  throw new Error(
19055
19693
  `Failed to decode prepared SIWE recap: ${err.message}`
19056
19694
  );
19057
19695
  }
19058
19696
  try {
19059
- signedCaps = (0, import_sdk_core3.extractRecapAttenuations)(result.signedMessage);
19697
+ signedCaps = (0, import_sdk_core4.extractRecapAttenuations)(result.signedMessage);
19060
19698
  } catch (err) {
19061
19699
  throw new Error(
19062
19700
  `Failed to decode OpenKey signedMessage recap: ${err.message}`
19063
19701
  );
19064
19702
  }
19065
- const unauthorized = (0, import_sdk_core3.unauthorizedRecapCapabilities)(signedCaps, originalCaps);
19703
+ const unauthorized = (0, import_sdk_core4.unauthorizedRecapCapabilities)(signedCaps, originalCaps);
19066
19704
  if (unauthorized.length > 0) {
19067
19705
  const previewLimit = 5;
19068
19706
  const preview = unauthorized.slice(0, previewLimit).map((u) => `${u.resource}::${u.action}`).join(", ");
@@ -19079,7 +19717,7 @@ var NodeUserAuthorization = class {
19079
19717
  const grantedPairs = /* @__PURE__ */ new Set();
19080
19718
  const grantedFourPartIndex = /* @__PURE__ */ new Map();
19081
19719
  for (const [resource, actions] of Object.entries(signedCaps)) {
19082
- const { space, path } = (0, import_sdk_core3.parseCanonicalRecapResource)(resource);
19720
+ const { space, path } = (0, import_sdk_core4.parseCanonicalRecapResource)(resource);
19083
19721
  for (const action of Object.keys(actions)) {
19084
19722
  grantedPairs.add(`${resource}\0${action}`);
19085
19723
  const slashIdx = action.indexOf("/");
@@ -19320,16 +19958,16 @@ var NodeUserAuthorization = class {
19320
19958
  };
19321
19959
 
19322
19960
  // src/account/AccountService.ts
19323
- var import_sdk_core4 = require("@tinycloud/sdk-core");
19961
+ var import_sdk_core5 = require("@tinycloud/sdk-core");
19324
19962
 
19325
19963
  // src/DelegatedAccess.ts
19326
- var import_sdk_core5 = require("@tinycloud/sdk-core");
19964
+ var import_sdk_core6 = require("@tinycloud/sdk-core");
19327
19965
  var DelegatedAccess = class {
19328
19966
  constructor(session, delegation, host, invoke2, invokeAny2, telemetry) {
19329
19967
  this.session = session;
19330
19968
  this._delegation = delegation;
19331
19969
  this.host = host;
19332
- this._serviceContext = new import_sdk_core5.ServiceContext({
19970
+ this._serviceContext = new import_sdk_core6.ServiceContext({
19333
19971
  invoke: invoke2,
19334
19972
  invokeAny: invokeAny2,
19335
19973
  fetch: globalThis.fetch.bind(globalThis),
@@ -19337,16 +19975,16 @@ var DelegatedAccess = class {
19337
19975
  telemetry
19338
19976
  });
19339
19977
  const prefix = this._delegation.path.replace(/\/$/, "");
19340
- this._kv = new import_sdk_core5.KVService({ prefix });
19978
+ this._kv = new import_sdk_core6.KVService({ prefix });
19341
19979
  this._kv.initialize(this._serviceContext);
19342
19980
  this._serviceContext.registerService("kv", this._kv);
19343
- this._sql = new import_sdk_core5.SQLService({});
19981
+ this._sql = new import_sdk_core6.SQLService({});
19344
19982
  this._sql.initialize(this._serviceContext);
19345
19983
  this._serviceContext.registerService("sql", this._sql);
19346
- this._duckdb = new import_sdk_core5.DuckDbService({});
19984
+ this._duckdb = new import_sdk_core6.DuckDbService({});
19347
19985
  this._duckdb.initialize(this._serviceContext);
19348
19986
  this._serviceContext.registerService("duckdb", this._duckdb);
19349
- this._hooks = new import_sdk_core5.HooksService({});
19987
+ this._hooks = new import_sdk_core6.HooksService({});
19350
19988
  this._hooks.initialize(this._serviceContext);
19351
19989
  this._serviceContext.registerService("hooks", this._hooks);
19352
19990
  const serviceSession = {
@@ -19496,7 +20134,7 @@ function createWasmKeyProvider(sessionManager) {
19496
20134
  }
19497
20135
 
19498
20136
  // src/delegateToHelpers.ts
19499
- var import_sdk_core6 = require("@tinycloud/sdk-core");
20137
+ var import_sdk_core7 = require("@tinycloud/sdk-core");
19500
20138
  function legacyParamsToPermissionEntries(actions, path, spaceIdOverride) {
19501
20139
  const byService = /* @__PURE__ */ new Map();
19502
20140
  for (const a of actions) {
@@ -19527,7 +20165,7 @@ function legacyParamsToPermissionEntries(actions, path, spaceIdOverride) {
19527
20165
  }
19528
20166
  return entries;
19529
20167
  }
19530
- var DEFAULT_DELEGATION_EXPIRY_MS = import_sdk_core6.EXPIRY.SESSION_MS;
20168
+ var DEFAULT_DELEGATION_EXPIRY_MS = import_sdk_core7.EXPIRY.SESSION_MS;
19531
20169
  function resolveExpiryMs(expiry) {
19532
20170
  if (expiry === void 0) {
19533
20171
  return DEFAULT_DELEGATION_EXPIRY_MS;
@@ -19540,10 +20178,10 @@ function resolveExpiryMs(expiry) {
19540
20178
  }
19541
20179
  return expiry;
19542
20180
  }
19543
- return (0, import_sdk_core6.parseExpiry)(expiry);
20181
+ return (0, import_sdk_core7.parseExpiry)(expiry);
19544
20182
  }
19545
20183
  function extractSiweExpiration(siwe) {
19546
- const parsed = new import_sdk_core6.SiweMessage(siwe);
20184
+ const parsed = new import_sdk_core7.SiweMessage(siwe);
19547
20185
  if (parsed.expirationTime === void 0 || parsed.expirationTime === null) {
19548
20186
  return void 0;
19549
20187
  }
@@ -19557,7 +20195,7 @@ function extractSiweExpiration(siwe) {
19557
20195
  }
19558
20196
 
19559
20197
  // src/NodeSecretsService.ts
19560
- var import_sdk_core7 = require("@tinycloud/sdk-core");
20198
+ var import_sdk_core8 = require("@tinycloud/sdk-core");
19561
20199
  var SECRETS_SPACE = "secrets";
19562
20200
  function ok() {
19563
20201
  return { ok: true, data: void 0 };
@@ -19590,7 +20228,7 @@ function secretActionName(action) {
19590
20228
  }
19591
20229
  function secretPermissionEntries(name, options, action, space, encryptionNetworkId) {
19592
20230
  const entries = [];
19593
- const path = action === "list" ? (0, import_sdk_core7.resolveSecretListPrefix)(options) : (0, import_sdk_core7.resolveSecretPath)(name, options).permissionPaths.vault;
20231
+ const path = action === "list" ? (0, import_sdk_core8.resolveSecretListPrefix)(options) : (0, import_sdk_core8.resolveSecretPath)(name, options).permissionPaths.vault;
19594
20232
  entries.push({
19595
20233
  service: "tinycloud.kv",
19596
20234
  space,
@@ -19687,7 +20325,7 @@ var NodeSecretsService = class {
19687
20325
  );
19688
20326
  } catch (error) {
19689
20327
  return secretsError(
19690
- import_sdk_core7.ErrorCodes.INVALID_INPUT,
20328
+ import_sdk_core8.ErrorCodes.INVALID_INPUT,
19691
20329
  error instanceof Error ? error.message : String(error),
19692
20330
  error instanceof Error ? error : void 0
19693
20331
  );
@@ -19697,7 +20335,7 @@ var NodeSecretsService = class {
19697
20335
  }
19698
20336
  if (!this.config.canEscalate()) {
19699
20337
  return secretsError(
19700
- import_sdk_core7.ErrorCodes.PERMISSION_DENIED,
20338
+ import_sdk_core8.ErrorCodes.PERMISSION_DENIED,
19701
20339
  `Cannot autosign ${displayActionUrn(action)} for ${target}; TinyCloudNode needs wallet mode with a signer or privateKey.`
19702
20340
  );
19703
20341
  }
@@ -19706,7 +20344,7 @@ var NodeSecretsService = class {
19706
20344
  return this.restoreUnlockAfterEscalation();
19707
20345
  } catch (error) {
19708
20346
  return secretsError(
19709
- import_sdk_core7.ErrorCodes.PERMISSION_DENIED,
20347
+ import_sdk_core8.ErrorCodes.PERMISSION_DENIED,
19710
20348
  error instanceof Error ? error.message : `Autosign escalation for ${displayActionUrn(action)} on ${target} failed.`,
19711
20349
  error instanceof Error ? error : void 0
19712
20350
  );
@@ -19727,10 +20365,10 @@ var NodeSecretsService = class {
19727
20365
  return false;
19728
20366
  }
19729
20367
  const manifests = Array.isArray(manifest) ? manifest : [manifest];
19730
- const requestedEntries = (0, import_sdk_core7.expandPermissionEntries)(permissionEntries);
20368
+ const requestedEntries = (0, import_sdk_core8.expandPermissionEntries)(permissionEntries);
19731
20369
  return requestedEntries.every(
19732
20370
  (entry) => manifests.some((candidate) => {
19733
- const resolved = (0, import_sdk_core7.resolveManifest)(candidate);
20371
+ const resolved = (0, import_sdk_core8.resolveManifest)(candidate);
19734
20372
  return resolved.resources.some(
19735
20373
  (resource) => resource.service === entry.service && spaceMatches(
19736
20374
  resource.space,
@@ -19746,8 +20384,8 @@ var NodeSecretsService = class {
19746
20384
  // src/TinyCloudNode.ts
19747
20385
  var DEFAULT_HOST = "https://node.tinycloud.xyz";
19748
20386
  var DEFAULT_ENCRYPTION_NETWORK_NAME = "default";
19749
- var NETWORK_CREATE_ACTION2 = import_sdk_core8.ENCRYPTION.NETWORK_CREATE;
19750
- var DECRYPT_ACTION2 = import_sdk_core8.ENCRYPTION.DECRYPT;
20387
+ var NETWORK_CREATE_ACTION2 = import_sdk_core9.ENCRYPTION.NETWORK_CREATE;
20388
+ var DECRYPT_ACTION2 = import_sdk_core9.ENCRYPTION.DECRYPT;
19751
20389
  var BOOTSTRAP_COMPLETION_MARKER_KEY = "system/bootstrap/complete";
19752
20390
  var BOOTSTRAP_COMPLETION_MARKER_VERSION = 1;
19753
20391
  var ACCEPTED_MARKER_VERSIONS = [BOOTSTRAP_COMPLETION_MARKER_VERSION];
@@ -19756,24 +20394,24 @@ function isSecretPayload(value) {
19756
20394
  return typeof value === "object" && value !== null && "value" in value && typeof value.value === "string" && "createdAt" in value && typeof value.createdAt === "string" && "updatedAt" in value && typeof value.updatedAt === "string";
19757
20395
  }
19758
20396
  var ROOT_DELEGATION_ACTIONS = [
19759
- import_sdk_core8.KV.PUT,
19760
- import_sdk_core8.KV.GET,
19761
- import_sdk_core8.KV.DEL,
19762
- import_sdk_core8.KV.LIST,
19763
- import_sdk_core8.KV.METADATA,
19764
- import_sdk_core8.SQL.READ,
19765
- import_sdk_core8.SQL.WRITE,
19766
- import_sdk_core8.SQL.ADMIN,
19767
- import_sdk_core8.SQL.ALL,
19768
- import_sdk_core8.DUCKDB.READ,
19769
- import_sdk_core8.DUCKDB.WRITE,
19770
- import_sdk_core8.DUCKDB.ADMIN,
19771
- import_sdk_core8.DUCKDB.DESCRIBE,
19772
- import_sdk_core8.DUCKDB.EXPORT,
19773
- import_sdk_core8.DUCKDB.IMPORT,
19774
- import_sdk_core8.DUCKDB.ALL
20397
+ import_sdk_core9.KV.PUT,
20398
+ import_sdk_core9.KV.GET,
20399
+ import_sdk_core9.KV.DEL,
20400
+ import_sdk_core9.KV.LIST,
20401
+ import_sdk_core9.KV.METADATA,
20402
+ import_sdk_core9.SQL.READ,
20403
+ import_sdk_core9.SQL.WRITE,
20404
+ import_sdk_core9.SQL.ADMIN,
20405
+ import_sdk_core9.SQL.ALL,
20406
+ import_sdk_core9.DUCKDB.READ,
20407
+ import_sdk_core9.DUCKDB.WRITE,
20408
+ import_sdk_core9.DUCKDB.ADMIN,
20409
+ import_sdk_core9.DUCKDB.DESCRIBE,
20410
+ import_sdk_core9.DUCKDB.EXPORT,
20411
+ import_sdk_core9.DUCKDB.IMPORT,
20412
+ import_sdk_core9.DUCKDB.ALL
19775
20413
  ];
19776
- var DEFAULT_SESSION_EXPIRATION_MS = import_sdk_core8.EXPIRY.SESSION_MS;
20414
+ var DEFAULT_SESSION_EXPIRATION_MS = import_sdk_core9.EXPIRY.SESSION_MS;
19777
20415
  function unifiedRootAttenuation(capabilities) {
19778
20416
  const attenuation = {};
19779
20417
  for (const capability of capabilities) {
@@ -19819,7 +20457,7 @@ function isInteractiveSigner(config) {
19819
20457
  }
19820
20458
  function didPrincipalMatches2(actual, expected) {
19821
20459
  try {
19822
- return (0, import_sdk_core8.principalDidEquals)(actual, expected);
20460
+ return (0, import_sdk_core9.principalDidEquals)(actual, expected);
19823
20461
  } catch {
19824
20462
  return actual === expected;
19825
20463
  }
@@ -20030,7 +20668,7 @@ function ownerDelegationPermissions(params) {
20030
20668
  }
20031
20669
  const slash = action.indexOf("/");
20032
20670
  const service = slash === -1 ? "" : action.slice(0, slash);
20033
- if (import_sdk_core8.SERVICE_LONG_TO_SHORT[service] === void 0) {
20671
+ if (import_sdk_core9.SERVICE_LONG_TO_SHORT[service] === void 0) {
20034
20672
  throw new Error("Owner delegation capabilities are unsupported");
20035
20673
  }
20036
20674
  const actions = byService.get(service) ?? [];
@@ -20046,7 +20684,7 @@ function ownerDelegationPermissions(params) {
20046
20684
  }
20047
20685
  const resources = /* @__PURE__ */ new Set();
20048
20686
  for (const permission of permissions) {
20049
- if (typeof permission.service !== "string" || import_sdk_core8.SERVICE_LONG_TO_SHORT[permission.service] === void 0 || typeof permission.path !== "string" || permission.path.length === 0 || permission.path.trim() !== permission.path || /[\u0000-\u001f\u007f\\*]/.test(permission.path) || !Array.isArray(permission.actions) || permission.actions.length === 0 || permission.actions.length > 32) {
20687
+ if (typeof permission.service !== "string" || import_sdk_core9.SERVICE_LONG_TO_SHORT[permission.service] === void 0 || typeof permission.path !== "string" || permission.path.length === 0 || permission.path.trim() !== permission.path || /[\u0000-\u001f\u007f\\*]/.test(permission.path) || !Array.isArray(permission.actions) || permission.actions.length === 0 || permission.actions.length > 32) {
20050
20688
  throw new Error("Owner delegation requires bounded capabilities");
20051
20689
  }
20052
20690
  const resourceKey = `${permission.service}\0${permission.path}`;
@@ -20061,9 +20699,9 @@ function ownerDelegationPermissions(params) {
20061
20699
  }
20062
20700
  actions.add(action);
20063
20701
  }
20064
- if (permission.service === import_sdk_core8.ENCRYPTION_PERMISSION_SERVICE) {
20702
+ if (permission.service === import_sdk_core9.ENCRYPTION_PERMISSION_SERVICE) {
20065
20703
  try {
20066
- (0, import_sdk_core8.parseNetworkId)(permission.path);
20704
+ (0, import_sdk_core9.parseNetworkId)(permission.path);
20067
20705
  } catch {
20068
20706
  throw new Error("Owner delegation encryption permission requires a canonical network URN");
20069
20707
  }
@@ -20075,11 +20713,11 @@ function ownerPermissionsToAbilities(permissions) {
20075
20713
  const abilities = {};
20076
20714
  const rawAbilities = {};
20077
20715
  for (const permission of permissions) {
20078
- if (permission.service === import_sdk_core8.ENCRYPTION_PERMISSION_SERVICE) {
20716
+ if (permission.service === import_sdk_core9.ENCRYPTION_PERMISSION_SERVICE) {
20079
20717
  rawAbilities[permission.path] = [...permission.actions];
20080
20718
  continue;
20081
20719
  }
20082
- const shortService = import_sdk_core8.SERVICE_LONG_TO_SHORT[permission.service];
20720
+ const shortService = import_sdk_core9.SERVICE_LONG_TO_SHORT[permission.service];
20083
20721
  abilities[shortService] ?? (abilities[shortService] = {});
20084
20722
  abilities[shortService][permission.path] = [...permission.actions];
20085
20723
  }
@@ -20211,6 +20849,8 @@ var _TinyCloudNode = class _TinyCloudNode {
20211
20849
  this.confirmedHostedSpaceIds = /* @__PURE__ */ new Set();
20212
20850
  /** Serializes account-registry writes for the active node instance. */
20213
20851
  this.accountRegistryTail = Promise.resolve();
20852
+ /** Bounds best-effort registry work on the sign-in critical path. */
20853
+ this.accountRegistryDeadlineMs = 4e3;
20214
20854
  /**
20215
20855
  * True when the last signIn() detected an interactive signer and skipped
20216
20856
  * client-side bootstrap. Apps can read this to know whether bootstrap was
@@ -20282,18 +20922,53 @@ var _TinyCloudNode = class _TinyCloudNode {
20282
20922
  if (!granted?.caveats?.length) {
20283
20923
  return entry;
20284
20924
  }
20285
- if (entry.caveats !== void 0 && !(0, import_sdk_core8.recapCaveatsEqual)(entry.caveats, granted.caveats)) {
20925
+ if (entry.caveats !== void 0 && !(0, import_sdk_core9.recapCaveatsEqual)(entry.caveats, granted.caveats)) {
20286
20926
  throw new Error("Invocation caveats do not match signed ReCap authority.");
20287
20927
  }
20288
20928
  return { ...entry, caveats: cloneRecapCaveats(granted.caveats) };
20289
20929
  });
20290
20930
  return this.wasmBindings.invokeAny(invocationSession, caveatPreservingEntries, facts);
20291
20931
  };
20932
+ assertValidReplicationConfig(config.replication);
20292
20933
  this.explicitHost = config.host;
20293
20934
  this.config = {
20294
20935
  ...config,
20295
20936
  host: config.host ?? DEFAULT_HOST
20296
20937
  };
20938
+ if (this.config.replication?.enabled) {
20939
+ const runtime = getNodeReplicationLoaders().runtime().then(({ ReplicationRuntime: ReplicationRuntime2 }) => {
20940
+ const instance = new ReplicationRuntime2(this.config.replication);
20941
+ this.replicationRuntimeInstance = instance;
20942
+ return instance;
20943
+ });
20944
+ this.replicationRuntime = runtime;
20945
+ this.replicationControl = {
20946
+ status: async () => {
20947
+ const status = await runtime.then((ready) => ready.control.status());
20948
+ const scopeError = this.replicationScopeError;
20949
+ if (!scopeError) return status;
20950
+ return this.config.replication.prefixes.map((prefix) => ({
20951
+ prefix,
20952
+ state: "unavailable",
20953
+ lastError: {
20954
+ at: (/* @__PURE__ */ new Date()).toISOString(),
20955
+ code: "SESSION_SCOPE_MISMATCH",
20956
+ message: scopeError
20957
+ },
20958
+ pending: { inFlight: 0, committed: 0, ambiguous: 0 },
20959
+ pinned: [],
20960
+ lagMs: null
20961
+ }));
20962
+ },
20963
+ sync: async (input) => (await runtime).control.sync(input),
20964
+ purge: (input) => {
20965
+ const instance = this.replicationRuntimeInstance;
20966
+ return instance ? instance.control.purge(input) : runtime.then((ready) => ready.control.purge(input));
20967
+ },
20968
+ clearPending: async () => (await runtime).control.clearPending(),
20969
+ close: async () => (await runtime).control.close()
20970
+ };
20971
+ }
20297
20972
  if (config.wasmBindings) {
20298
20973
  this.wasmBindings = config.wasmBindings;
20299
20974
  } else if (_TinyCloudNode.nodeDefaults) {
@@ -20317,13 +20992,13 @@ var _TinyCloudNode = class _TinyCloudNode {
20317
20992
  }
20318
20993
  this.sessionKeyJwk = JSON.parse(jwkStr);
20319
20994
  this._serviceGraph = this.createServiceGraphLifetime();
20320
- this._capabilityRegistry = new import_sdk_core8.CapabilityKeyRegistry();
20995
+ this._capabilityRegistry = new import_sdk_core9.CapabilityKeyRegistry();
20321
20996
  this._keyProvider = new WasmKeyProvider({
20322
20997
  sessionManager: this.sessionManager
20323
20998
  });
20324
- this.notificationHandler = config.notificationHandler ?? new import_sdk_core8.SilentNotificationHandler();
20999
+ this.notificationHandler = config.notificationHandler ?? new import_sdk_core9.SilentNotificationHandler();
20325
21000
  const receiveOnlyGraph = this._serviceGraph;
20326
- this._sharingService = new import_sdk_core8.SharingService({
21001
+ this._sharingService = new import_sdk_core9.SharingService({
20327
21002
  hosts: [this.config.host],
20328
21003
  // session: undefined - not needed for receive()
20329
21004
  invoke: receiveOnlyGraph.invoke,
@@ -20339,8 +21014,8 @@ var _TinyCloudNode = class _TinyCloudNode {
20339
21014
  // delegationManager: undefined - not needed for receive()
20340
21015
  createKVService: (config2) => {
20341
21016
  const prefix = config2.pathPrefix?.replace(/\/$/, "");
20342
- const kvService = new import_sdk_core8.KVService({ prefix });
20343
- const kvContext = receiveOnlyGraph.track(new import_sdk_core8.ServiceContext({
21017
+ const kvService = new import_sdk_core9.KVService({ prefix });
21018
+ const kvContext = receiveOnlyGraph.track(new import_sdk_core9.ServiceContext({
20344
21019
  invoke: config2.invoke,
20345
21020
  fetch: config2.fetch ?? globalThis.fetch.bind(globalThis),
20346
21021
  hosts: config2.hosts,
@@ -20413,10 +21088,17 @@ var _TinyCloudNode = class _TinyCloudNode {
20413
21088
  nonce: config.nonce,
20414
21089
  siweConfig: config.siweConfig,
20415
21090
  manifest: useBootstrapSignInRequest ? void 0 : config.manifest,
20416
- capabilityRequest: useBootstrapSignInRequest ? config.includeAccountRegistryPermissions === false ? import_sdk_core8.BOOTSTRAP_DEFAULT_ONLY_SESSION_REQUEST : import_sdk_core8.BOOTSTRAP_SESSION_REQUESTS.default : config.capabilityRequest,
20417
- includeAccountRegistryPermissions: useBootstrapSignInRequest ? false : config.includeAccountRegistryPermissions
21091
+ capabilityRequest: useBootstrapSignInRequest ? config.includeAccountRegistryPermissions === false ? import_sdk_core9.BOOTSTRAP_DEFAULT_ONLY_SESSION_REQUEST : import_sdk_core9.BOOTSTRAP_SESSION_REQUESTS.default : config.capabilityRequest,
21092
+ includeAccountRegistryPermissions: useBootstrapSignInRequest ? false : config.includeAccountRegistryPermissions,
21093
+ // Sign-in needs only the entry inputs (prefixes + secrets opt-in);
21094
+ // storage and scheduling never leave TinyCloudNode.
21095
+ replication: config.replication?.enabled === true ? {
21096
+ enabled: true,
21097
+ prefixes: config.replication.prefixes,
21098
+ allowSecrets: config.replication.allowSecrets === true
21099
+ } : void 0
20418
21100
  });
20419
- this.tc = new import_sdk_core8.TinyCloud(this.auth, {
21101
+ this.tc = new import_sdk_core9.TinyCloud(this.auth, {
20420
21102
  invokeAny: this.invokeAnyWithRuntimePermissions,
20421
21103
  telemetry: config.telemetry
20422
21104
  });
@@ -20496,7 +21178,7 @@ var _TinyCloudNode = class _TinyCloudNode {
20496
21178
  /** Publish the active owner Node as a session-signed registry record. */
20497
21179
  async publishActiveNodeLocation(registryUrl, fetchFn = globalThis.fetch.bind(globalThis)) {
20498
21180
  const node = await this.activeNodeIdentity();
20499
- return (0, import_sdk_core8.publishLocationRecord)({
21181
+ return (0, import_sdk_core9.publishLocationRecord)({
20500
21182
  registryUrl,
20501
21183
  subject: this.credentialHolderDid,
20502
21184
  nodeOrigin: node.origin,
@@ -20513,7 +21195,7 @@ var _TinyCloudNode = class _TinyCloudNode {
20513
21195
  */
20514
21196
  get did() {
20515
21197
  if (this._address) {
20516
- return (0, import_sdk_core8.pkhDid)(this._address, this._chainId);
21198
+ return (0, import_sdk_core9.pkhDid)(this._address, this._chainId);
20517
21199
  }
20518
21200
  return this.sessionManager.getDID(this.sessionKeyId);
20519
21201
  }
@@ -20550,7 +21232,7 @@ var _TinyCloudNode = class _TinyCloudNode {
20550
21232
  /** Normalize signed capabilities without collapsing nested encryption into raw authority. */
20551
21233
  projectSignedRecapCapabilities(siwe) {
20552
21234
  const projected = this.parseRecapWithCaveats(siwe).map((entry) => {
20553
- const normalized = (0, import_sdk_core8.parseRecapCapabilities)(() => [entry], siwe)[0];
21235
+ const normalized = (0, import_sdk_core9.parseRecapCapabilities)(() => [entry], siwe)[0];
20554
21236
  if (normalized.service !== "tinycloud.encryption") return normalized;
20555
21237
  if (!this.isEncryptionNetworkOperation("encryption", entry.path, entry.space)) {
20556
21238
  return { ...normalized, space: entry.space };
@@ -20595,14 +21277,14 @@ var _TinyCloudNode = class _TinyCloudNode {
20595
21277
  if (!this._address) {
20596
21278
  return void 0;
20597
21279
  }
20598
- return this.wasmBindings.makeSpaceId(this._address, this._chainId, import_sdk_core8.ACCOUNT_REGISTRY_SPACE);
21280
+ return this.wasmBindings.makeSpaceId(this._address, this._chainId, import_sdk_core9.ACCOUNT_REGISTRY_SPACE);
20599
21281
  }
20600
21282
  /**
20601
21283
  * Account-level application and delegation helpers.
20602
21284
  */
20603
21285
  get account() {
20604
21286
  if (!this._account) {
20605
- this._account = new import_sdk_core4.AccountService({
21287
+ this._account = new import_sdk_core5.AccountService({
20606
21288
  getDid: () => this.did,
20607
21289
  getHost: () => this.hosts[0] ?? this.config.host,
20608
21290
  getPrimarySpaceId: () => this.spaceId,
@@ -20648,7 +21330,7 @@ var _TinyCloudNode = class _TinyCloudNode {
20648
21330
  }
20649
21331
  await this.accountRegistryTail;
20650
21332
  await this.wasmBindings.ensureInitialized?.();
20651
- this._address = (0, import_sdk_core8.canonicalizeAddress)(await this.signer.getAddress());
21333
+ this._address = (0, import_sdk_core9.canonicalizeAddress)(await this.signer.getAddress());
20652
21334
  this._chainId = await this.signer.getChainId();
20653
21335
  this._kv = void 0;
20654
21336
  this._sql = void 0;
@@ -20665,6 +21347,9 @@ var _TinyCloudNode = class _TinyCloudNode {
20665
21347
  this.confirmedHostedSpaceIds.clear();
20666
21348
  await this.tc.signIn(options);
20667
21349
  this.syncResolvedHostFromAuth();
21350
+ this.replicationDelegateSession = void 0;
21351
+ this.replicationScopeError = void 0;
21352
+ if (this.replicationRuntime) await (await this.replicationRuntime).unbind();
20668
21353
  const oldGraph = this._serviceGraph;
20669
21354
  this._serviceGraph = this.createServiceGraphLifetime();
20670
21355
  oldGraph.retire();
@@ -20674,7 +21359,7 @@ var _TinyCloudNode = class _TinyCloudNode {
20674
21359
  this.sessionKeyId = signedInSession.sessionKey;
20675
21360
  this.sessionKeyJwk = signedInSession.jwk;
20676
21361
  }
20677
- this.initializeServices();
21362
+ await this.initializeServices();
20678
21363
  const primarySession = this.currentTinyCloudSession();
20679
21364
  if (primarySession) {
20680
21365
  this.registerPrimarySessionGrant(primarySession);
@@ -20682,10 +21367,11 @@ var _TinyCloudNode = class _TinyCloudNode {
20682
21367
  const bootstrapped = await this.bootstrapAccountIfNeeded();
20683
21368
  await this.ensureRequestedEncryptionNetworks();
20684
21369
  if (!bootstrapped && this.config.manifest === void 0 && this.config.capabilityRequest === void 0) {
20685
- await this.ensureOwnedSpaceHostedById(this.ownedSpaceId(import_sdk_core8.SECRETS_SPACE));
21370
+ await this.ensureOwnedSpaceHostedById(this.ownedSpaceId(import_sdk_core9.SECRETS_SPACE));
20686
21371
  }
20687
21372
  if (!bootstrapped) {
20688
21373
  this.scheduleAccountRegistrySync();
21374
+ await this.accountRegistryTail;
20689
21375
  }
20690
21376
  this.notificationHandler.success("Successfully signed in");
20691
21377
  }
@@ -20713,7 +21399,7 @@ var _TinyCloudNode = class _TinyCloudNode {
20713
21399
  this._bootstrapStatus = { skipped: true, reason: "interactive-signer" };
20714
21400
  return false;
20715
21401
  }
20716
- const steps = (0, import_sdk_core8.bootstrapSteps)(this._address, this._chainId);
21402
+ const steps = (0, import_sdk_core9.bootstrapSteps)(this._address, this._chainId);
20717
21403
  try {
20718
21404
  const decision = await this.resolveBootstrapDecision(steps);
20719
21405
  if (decision.action === "skip") {
@@ -20751,7 +21437,7 @@ var _TinyCloudNode = class _TinyCloudNode {
20751
21437
  if (!auth) {
20752
21438
  throw new Error("Account bootstrap requires an active wallet session");
20753
21439
  }
20754
- const accountSpaceId = this.ownedSpaceId(import_sdk_core8.ACCOUNT_REGISTRY_SPACE);
21440
+ const accountSpaceId = this.ownedSpaceId(import_sdk_core9.ACCOUNT_REGISTRY_SPACE);
20755
21441
  const skipped = auth.lastActivationSkippedSpaceIds;
20756
21442
  if (skipped.includes(accountSpaceId)) return { action: "run", mode: "fresh" };
20757
21443
  if (skipped.some((spaceId) => enshrinedSpaceIds.has(spaceId))) {
@@ -20774,7 +21460,7 @@ var _TinyCloudNode = class _TinyCloudNode {
20774
21460
  }
20775
21461
  return { action: "run", mode: "repair" };
20776
21462
  }
20777
- if (marker.error.code === import_sdk_core8.ErrorCodes.KV_NOT_FOUND && this.markerReadIsUnhostedSpace(marker.error.meta)) {
21463
+ if (marker.error.code === import_sdk_core9.ErrorCodes.KV_NOT_FOUND && this.markerReadIsUnhostedSpace(marker.error.meta)) {
20778
21464
  return { action: "run", mode: "fresh" };
20779
21465
  }
20780
21466
  } catch (err) {
@@ -20788,7 +21474,7 @@ var _TinyCloudNode = class _TinyCloudNode {
20788
21474
  return { action: "run", mode: "repair" };
20789
21475
  }
20790
21476
  async readBootstrapCompletionMarker() {
20791
- return this.kvForSpace(this.ownedSpaceId(import_sdk_core8.ACCOUNT_REGISTRY_SPACE)).get(
21477
+ return this.kvForSpace(this.ownedSpaceId(import_sdk_core9.ACCOUNT_REGISTRY_SPACE)).get(
20792
21478
  BOOTSTRAP_COMPLETION_MARKER_KEY
20793
21479
  );
20794
21480
  }
@@ -20797,7 +21483,7 @@ var _TinyCloudNode = class _TinyCloudNode {
20797
21483
  throw new Error("Bootstrap completion marker requires an active wallet session");
20798
21484
  }
20799
21485
  const canonicalStepIds = new Set(
20800
- (0, import_sdk_core8.bootstrapSteps)(this._address, this._chainId).map((step) => step.id)
21486
+ (0, import_sdk_core9.bootstrapSteps)(this._address, this._chainId).map((step) => step.id)
20801
21487
  );
20802
21488
  const providedStepIds = new Set(steps.map((step) => step.id));
20803
21489
  if (canonicalStepIds.size !== providedStepIds.size || [...canonicalStepIds].some((stepId) => !providedStepIds.has(stepId))) {
@@ -20808,7 +21494,7 @@ var _TinyCloudNode = class _TinyCloudNode {
20808
21494
  stepIds: [...canonicalStepIds],
20809
21495
  completedAt: (/* @__PURE__ */ new Date()).toISOString()
20810
21496
  };
20811
- const written = await this.kvForSpace(this.ownedSpaceId(import_sdk_core8.ACCOUNT_REGISTRY_SPACE)).put(
21497
+ const written = await this.kvForSpace(this.ownedSpaceId(import_sdk_core9.ACCOUNT_REGISTRY_SPACE)).put(
20812
21498
  BOOTSTRAP_COMPLETION_MARKER_KEY,
20813
21499
  marker
20814
21500
  );
@@ -20847,7 +21533,7 @@ var _TinyCloudNode = class _TinyCloudNode {
20847
21533
  const warnings = [];
20848
21534
  const primarySession = auth.tinyCloudSession;
20849
21535
  const defaultSpaceId = this.ownedSpaceId("default");
20850
- const canReusePrimaryBootstrapSession = primarySession?.spaceId === defaultSpaceId && auth.capabilityRequest === import_sdk_core8.BOOTSTRAP_SESSION_REQUESTS.default;
21536
+ const canReusePrimaryBootstrapSession = primarySession?.spaceId === defaultSpaceId && auth.capabilityRequest === import_sdk_core9.BOOTSTRAP_SESSION_REQUESTS.default;
20851
21537
  for (const step of steps) {
20852
21538
  if (step.kind !== "session") continue;
20853
21539
  if (step.space === "default" && canReusePrimaryBootstrapSession && primarySession) {
@@ -20862,7 +21548,7 @@ var _TinyCloudNode = class _TinyCloudNode {
20862
21548
  try {
20863
21549
  session = await auth.createBootstrapSession({
20864
21550
  spaceId: step.spaceId,
20865
- capabilityRequest: step.request ?? import_sdk_core8.BOOTSTRAP_SESSION_REQUESTS[step.space],
21551
+ capabilityRequest: step.request ?? import_sdk_core9.BOOTSTRAP_SESSION_REQUESTS[step.space],
20866
21552
  rawAbilities
20867
21553
  });
20868
21554
  } catch (err) {
@@ -20892,7 +21578,7 @@ var _TinyCloudNode = class _TinyCloudNode {
20892
21578
  if (!session) {
20893
21579
  throw new Error(`Missing bootstrap session for ${step.space}`);
20894
21580
  }
20895
- const activated = await (0, import_sdk_core8.activateSessionWithHost)(host, session.delegationHeader);
21581
+ const activated = await (0, import_sdk_core9.activateSessionWithHost)(host, session.delegationHeader);
20896
21582
  if (!activated.success || activated.skipped?.includes(step.spaceId)) {
20897
21583
  throw Object.assign(
20898
21584
  new Error(
@@ -20903,7 +21589,7 @@ var _TinyCloudNode = class _TinyCloudNode {
20903
21589
  }
20904
21590
  this.registerBootstrapRuntimeGrant(
20905
21591
  session,
20906
- import_sdk_core8.BOOTSTRAP_SESSION_REQUESTS[step.space],
21592
+ import_sdk_core9.BOOTSTRAP_SESSION_REQUESTS[step.space],
20907
21593
  rawAbilitiesBySpace.get(step.space)
20908
21594
  );
20909
21595
  }
@@ -20952,7 +21638,7 @@ var _TinyCloudNode = class _TinyCloudNode {
20952
21638
  }
20953
21639
  if (step.kind === "seed-applications") {
20954
21640
  const registered = await this.account.applications.register(
20955
- step.manifests.length > 0 ? [...step.manifests] : import_sdk_core8.TINYCLOUD_SECRETS_BOOTSTRAP_MANIFEST,
21641
+ step.manifests.length > 0 ? [...step.manifests] : import_sdk_core9.TINYCLOUD_SECRETS_BOOTSTRAP_MANIFEST,
20956
21642
  // The write is an INSERT OR REPLACE and is safe to repeat during a
20957
21643
  // repair, so skip the manifest-hash pre-read.
20958
21644
  { assumeUnregistered: true }
@@ -20971,7 +21657,7 @@ var _TinyCloudNode = class _TinyCloudNode {
20971
21657
  migrations: [
20972
21658
  {
20973
21659
  id: "001_initial",
20974
- sql: [...import_sdk_core8.SECRET_RECORDS_SCHEMA]
21660
+ sql: [...import_sdk_core9.SECRET_RECORDS_SCHEMA]
20975
21661
  }
20976
21662
  ]
20977
21663
  });
@@ -21138,7 +21824,7 @@ var _TinyCloudNode = class _TinyCloudNode {
21138
21824
  provenance: "primary"
21139
21825
  });
21140
21826
  }
21141
- async writeManifestRegistryRecords() {
21827
+ async writeManifestRegistryRecords(account, signal) {
21142
21828
  const request = this.capabilityRequest;
21143
21829
  if (!request || request.registryRecords.length === 0) {
21144
21830
  return;
@@ -21146,9 +21832,10 @@ var _TinyCloudNode = class _TinyCloudNode {
21146
21832
  if (!this.auth || !this.signer) {
21147
21833
  throw new Error("Manifest registry write requires wallet mode");
21148
21834
  }
21149
- const accountSpaceId = this.ownedSpaceId(import_sdk_core8.ACCOUNT_REGISTRY_SPACE);
21150
- await this.ensureOwnedSpaceHostedById(accountSpaceId);
21151
- const result = await this.account.applications.register(request.manifests);
21835
+ const accountSpaceId = this.ownedSpaceId(import_sdk_core9.ACCOUNT_REGISTRY_SPACE);
21836
+ await this.ensureOwnedSpaceHostedById(accountSpaceId, signal);
21837
+ if (signal.aborted) throw signal.reason;
21838
+ const result = await account.applications.register(request.manifests);
21152
21839
  if (!result.ok) {
21153
21840
  throw Object.assign(
21154
21841
  new Error(`Failed to write manifest registry records: ${result.error.message}`),
@@ -21156,34 +21843,113 @@ var _TinyCloudNode = class _TinyCloudNode {
21156
21843
  );
21157
21844
  }
21158
21845
  }
21846
+ createAccountRegistryServices(context, signal) {
21847
+ const session = context.session;
21848
+ if (!session) throw new Error("Account registry requires an active service session");
21849
+ const contexts = [context];
21850
+ const accountSpaceId = this.ownedSpaceId(import_sdk_core9.ACCOUNT_REGISTRY_SPACE);
21851
+ const createScopedContext = (spaceId) => {
21852
+ const scoped = this._serviceGraph.track(new import_sdk_core9.ServiceContext({
21853
+ invoke: context.invoke,
21854
+ invokeAny: context.invokeAny,
21855
+ fetch: context.fetch,
21856
+ hosts: context.hosts,
21857
+ telemetry: this.config.telemetry
21858
+ }));
21859
+ scoped.setOperationAbortSignal(signal);
21860
+ scoped.setSession({ ...session, spaceId });
21861
+ contexts.push(scoped);
21862
+ return scoped;
21863
+ };
21864
+ const sql = new import_sdk_core9.SQLService({});
21865
+ const sqlContext = createScopedContext(accountSpaceId);
21866
+ sql.initialize(sqlContext);
21867
+ const spaces = new import_sdk_core9.SpaceService({
21868
+ hosts: context.hosts,
21869
+ session,
21870
+ invoke: context.invoke,
21871
+ fetch: (url, init2) => context.fetch(url, {
21872
+ ...init2,
21873
+ signal: init2?.signal ? AbortSignal.any([init2.signal, signal]) : signal
21874
+ }),
21875
+ userDid: this.did,
21876
+ createKVService: (spaceId) => {
21877
+ const kv = new import_sdk_core9.KVService({});
21878
+ kv.initialize(createScopedContext(spaceId));
21879
+ return kv;
21880
+ }
21881
+ });
21882
+ return {
21883
+ contexts,
21884
+ account: new import_sdk_core5.AccountService({
21885
+ getDid: () => this.did,
21886
+ getHost: () => context.hosts[0] ?? this.config.host,
21887
+ getPrimarySpaceId: () => session.spaceId,
21888
+ getAccountSpaceId: () => accountSpaceId,
21889
+ getSpaces: () => spaces,
21890
+ getAccountDb: () => sql.db("account"),
21891
+ ensureAccountSpaceHosted: () => this.ensureOwnedSpaceHostedById(accountSpaceId, signal)
21892
+ })
21893
+ };
21894
+ }
21159
21895
  scheduleAccountRegistrySync() {
21160
21896
  const session = this.currentTinyCloudSession();
21161
21897
  if (!session || this.pendingAccountRegistrySync?.session === session) {
21162
21898
  return;
21163
21899
  }
21900
+ const controller = new AbortController();
21901
+ const deadline = setTimeout(
21902
+ () => controller.abort(new DOMException("Account registry deadline exceeded", "TimeoutError")),
21903
+ this.accountRegistryDeadlineMs
21904
+ );
21164
21905
  const promise = this.enqueueAccountRegistryOperation(session, async () => {
21165
- await this.withAccountRegistryRetry(async () => {
21166
- if (this.currentTinyCloudSession() !== session) {
21167
- return;
21168
- }
21169
- await this.account.index.ensure();
21170
- if (this.currentTinyCloudSession() !== session) {
21171
- return;
21172
- }
21173
- await this.writeManifestRegistryRecords();
21174
- if (this.currentTinyCloudSession() !== session) {
21175
- return;
21176
- }
21177
- if (this.currentSessionCanListSpaces()) {
21178
- const spaces = await this.account.spaces.syncAccessible();
21179
- if (!spaces.ok) {
21180
- throw Object.assign(
21181
- new Error(`Failed to sync account spaces: ${spaces.error.message}`),
21182
- { cause: spaces.error }
21183
- );
21906
+ const sharedContext = this._serviceContext;
21907
+ if (!sharedContext) return;
21908
+ const context = this._serviceGraph.track(new import_sdk_core9.ServiceContext({
21909
+ invoke: sharedContext.invoke,
21910
+ invokeAny: sharedContext.invokeAny,
21911
+ fetch: sharedContext.fetch,
21912
+ hosts: sharedContext.hosts,
21913
+ telemetry: this.config.telemetry
21914
+ }));
21915
+ context.setOperationAbortSignal(controller.signal);
21916
+ const current = this.currentTinyCloudSession();
21917
+ if (!current) return;
21918
+ context.setSession({
21919
+ delegationHeader: current.delegationHeader,
21920
+ delegationCid: current.delegationCid,
21921
+ spaceId: current.spaceId,
21922
+ verificationMethod: current.verificationMethod,
21923
+ jwk: current.jwk
21924
+ });
21925
+ const registry = this.createAccountRegistryServices(context, controller.signal);
21926
+ try {
21927
+ await this.withAccountRegistryRetry(async () => {
21928
+ if (controller.signal.aborted) throw controller.signal.reason;
21929
+ if (this.currentTinyCloudSession() !== session) return;
21930
+ await registry.account.index.ensure();
21931
+ if (controller.signal.aborted) throw controller.signal.reason;
21932
+ if (this.currentTinyCloudSession() !== session) return;
21933
+ await this.writeManifestRegistryRecords(registry.account, controller.signal);
21934
+ if (controller.signal.aborted) throw controller.signal.reason;
21935
+ if (this.currentTinyCloudSession() !== session) return;
21936
+ if (this.currentSessionCanListSpaces()) {
21937
+ const result = await registry.account.spaces.syncAccessible();
21938
+ if (controller.signal.aborted) throw controller.signal.reason;
21939
+ if (!result.ok) {
21940
+ throw Object.assign(
21941
+ new Error(`Failed to sync account spaces: ${result.error.message}`),
21942
+ { cause: result.error }
21943
+ );
21944
+ }
21184
21945
  }
21946
+ }, controller.signal);
21947
+ } finally {
21948
+ for (const operationContext of registry.contexts) {
21949
+ operationContext.retire();
21185
21950
  }
21186
- });
21951
+ clearTimeout(deadline);
21952
+ }
21187
21953
  });
21188
21954
  this.pendingAccountRegistrySync = { session, promise };
21189
21955
  const clearPendingSync = () => {
@@ -21192,6 +21958,10 @@ var _TinyCloudNode = class _TinyCloudNode {
21192
21958
  }
21193
21959
  };
21194
21960
  void promise.then(clearPendingSync, clearPendingSync);
21961
+ void promise.then(
21962
+ () => clearTimeout(deadline),
21963
+ () => clearTimeout(deadline)
21964
+ );
21195
21965
  }
21196
21966
  enqueueAccountRegistryOperation(session, task) {
21197
21967
  const operation = this.accountRegistryTail.then(async () => {
@@ -21227,15 +21997,23 @@ var _TinyCloudNode = class _TinyCloudNode {
21227
21997
  (operation) => operation.service === "space" && this.actionContains(operation.action, "tinycloud.space/list")
21228
21998
  );
21229
21999
  }
21230
- async withAccountRegistryRetry(task) {
22000
+ async withAccountRegistryRetry(task, signal) {
21231
22001
  const delays = [250, 1e3, 3e3];
21232
22002
  let lastError;
21233
22003
  for (let attempt = 0; attempt < delays.length; attempt += 1) {
22004
+ if (signal.aborted) {
22005
+ console.warn("TinyCloud account registry sync stopped: deadline exceeded", signal.reason);
22006
+ return;
22007
+ }
21234
22008
  try {
21235
22009
  await task();
21236
22010
  return;
21237
22011
  } catch (error) {
21238
- const verdict = (0, import_sdk_core8.authorizationVerdictOf)(error);
22012
+ if (signal.aborted) {
22013
+ console.warn("TinyCloud account registry sync stopped: deadline exceeded", error);
22014
+ return;
22015
+ }
22016
+ const verdict = (0, import_sdk_core9.authorizationVerdictOf)(error);
21239
22017
  const message = error instanceof Error ? error.message : String(error);
21240
22018
  const isAuthorizationVerdict = verdict === void 0 ? /Unauthorized Action|\b(?:401|403)\b/.test(message) : verdict !== "other";
21241
22019
  if (isAuthorizationVerdict) {
@@ -21245,13 +22023,29 @@ var _TinyCloudNode = class _TinyCloudNode {
21245
22023
  );
21246
22024
  return;
21247
22025
  }
21248
- if ((0, import_sdk_core8.isStorageFullError)(error) || (0, import_sdk_core8.isStorageFullError)(error?.cause) || message.includes(import_sdk_core8.STORAGE_FULL_MESSAGE) || message.includes(import_sdk_core8.STORAGE_WRITE_TOO_LARGE_MESSAGE)) {
21249
- console.warn("TinyCloud account registry sync stopped: storage is full", error);
22026
+ if ((0, import_sdk_core9.isStorageFullError)(error) || (0, import_sdk_core9.isStorageFullError)(error?.cause) || message.includes(import_sdk_core9.STORAGE_FULL_MESSAGE) || message.includes(import_sdk_core9.STORAGE_WRITE_TOO_LARGE_MESSAGE)) {
22027
+ console.warn(
22028
+ "TinyCloud account registry sync stopped: storage is full",
22029
+ error
22030
+ );
21250
22031
  return;
21251
22032
  }
21252
22033
  lastError = error;
21253
22034
  if (attempt < delays.length - 1) {
21254
- await new Promise((resolve) => setTimeout(resolve, delays[attempt]));
22035
+ await new Promise((resolve, reject2) => {
22036
+ const timer = setTimeout(() => {
22037
+ signal.removeEventListener("abort", onAbort);
22038
+ resolve();
22039
+ }, delays[attempt]);
22040
+ const onAbort = () => {
22041
+ clearTimeout(timer);
22042
+ signal.removeEventListener("abort", onAbort);
22043
+ reject2(signal.reason);
22044
+ };
22045
+ signal.addEventListener("abort", onAbort, { once: true });
22046
+ }).catch((error2) => {
22047
+ if (!signal.aborted) throw error2;
22048
+ });
21255
22049
  }
21256
22050
  }
21257
22051
  }
@@ -21267,7 +22061,7 @@ var _TinyCloudNode = class _TinyCloudNode {
21267
22061
  }
21268
22062
  const networkIds = /* @__PURE__ */ new Set();
21269
22063
  for (const resource of request.resources) {
21270
- if (resource.service === import_sdk_core8.ENCRYPTION_PERMISSION_SERVICE && resource.path.startsWith("urn:tinycloud:encryption:") && resource.actions.includes(DECRYPT_ACTION2)) {
22064
+ if (resource.service === import_sdk_core9.ENCRYPTION_PERMISSION_SERVICE && resource.path.startsWith("urn:tinycloud:encryption:") && resource.actions.includes(DECRYPT_ACTION2)) {
21271
22065
  networkIds.add(resource.path);
21272
22066
  }
21273
22067
  }
@@ -21278,7 +22072,7 @@ var _TinyCloudNode = class _TinyCloudNode {
21278
22072
  return;
21279
22073
  }
21280
22074
  for (const networkId of this.requestedEncryptionNetworkIds()) {
21281
- const parsed = (0, import_sdk_core8.parseNetworkId)(networkId);
22075
+ const parsed = (0, import_sdk_core9.parseNetworkId)(networkId);
21282
22076
  if (!didPrincipalMatches2(parsed.ownerDid, this.did)) {
21283
22077
  continue;
21284
22078
  }
@@ -21301,7 +22095,7 @@ var _TinyCloudNode = class _TinyCloudNode {
21301
22095
  * self-revealing: the next write to the space fails immediately and loudly
21302
22096
  * with `404 Space not found`.
21303
22097
  */
21304
- async ensureOwnedSpaceHostedById(spaceId) {
22098
+ async ensureOwnedSpaceHostedById(spaceId, signal) {
21305
22099
  if (!this.auth) {
21306
22100
  throw new Error("Owned space hosting requires wallet mode");
21307
22101
  }
@@ -21316,7 +22110,7 @@ var _TinyCloudNode = class _TinyCloudNode {
21316
22110
  if (!host) {
21317
22111
  throw new Error("Owned space hosting requires a TinyCloud host");
21318
22112
  }
21319
- const activation = await (0, import_sdk_core8.activateSessionWithHost)(host, session.delegationHeader);
22113
+ const activation = await (0, import_sdk_core9.activateSessionWithHost)(host, session.delegationHeader, signal);
21320
22114
  if (activation.success && !activation.skipped?.includes(spaceId)) {
21321
22115
  this.confirmedHostedSpaceIds.add(spaceId);
21322
22116
  return;
@@ -21327,15 +22121,16 @@ var _TinyCloudNode = class _TinyCloudNode {
21327
22121
  { cause: activation }
21328
22122
  );
21329
22123
  }
21330
- const created = await this.auth.hostOwnedSpaceResult(spaceId);
22124
+ const authorization = this.auth;
22125
+ const created = signal ? await authorization.hostOwnedSpaceResult(spaceId, void 0, signal) : await authorization.hostOwnedSpaceResult(spaceId);
21331
22126
  if (!created.success) {
21332
22127
  throw Object.assign(
21333
22128
  new Error(`Failed to create owned space ${spaceId}: ${describeHostFailure2(created)}`),
21334
22129
  { cause: created }
21335
22130
  );
21336
22131
  }
21337
- await new Promise((resolve) => setTimeout(resolve, 100));
21338
- const retry = await (0, import_sdk_core8.activateSessionWithHost)(host, session.delegationHeader);
22132
+ if (signal?.aborted) throw signal.reason;
22133
+ const retry = await (0, import_sdk_core9.activateSessionWithHost)(host, session.delegationHeader, signal);
21339
22134
  if (!retry.success || retry.skipped?.includes(spaceId)) {
21340
22135
  throw Object.assign(
21341
22136
  new Error(
@@ -21383,7 +22178,7 @@ var _TinyCloudNode = class _TinyCloudNode {
21383
22178
  { cause: hosted }
21384
22179
  );
21385
22180
  }
21386
- const activation = await (0, import_sdk_core8.activateSessionWithHost)(
22181
+ const activation = await (0, import_sdk_core9.activateSessionWithHost)(
21387
22182
  host,
21388
22183
  session.delegationHeader
21389
22184
  );
@@ -21571,7 +22366,7 @@ var _TinyCloudNode = class _TinyCloudNode {
21571
22366
  }
21572
22367
  let restoredAddress;
21573
22368
  try {
21574
- restoredAddress = hasPersistedProof ? (0, import_sdk_core8.canonicalizeAddress)(sessionData.address) : void 0;
22369
+ restoredAddress = hasPersistedProof ? (0, import_sdk_core9.canonicalizeAddress)(sessionData.address) : void 0;
21575
22370
  } catch {
21576
22371
  throw new InvalidRestoredSessionError("Persisted session has an invalid wallet address.");
21577
22372
  }
@@ -21613,8 +22408,36 @@ var _TinyCloudNode = class _TinyCloudNode {
21613
22408
  const stagedHost = resolvedHost ?? this.config.host;
21614
22409
  const stagedAddress = restoredAddress;
21615
22410
  const stagedChainId = sessionData.chainId ?? 1;
21616
- const stagedNodeDid = stagedAddress ? (0, import_sdk_core8.pkhDid)(stagedAddress, stagedChainId) : canonicalVerificationMethod;
21617
- const serviceSession = {
22411
+ let replicationPrincipal;
22412
+ let compactReplicationSession;
22413
+ let replicationScopeError;
22414
+ if (this.config.replication?.enabled) {
22415
+ if (stagedAddress !== void 0) {
22416
+ replicationPrincipal = (0, import_sdk_core9.pkhDid)(stagedAddress, stagedChainId);
22417
+ } else {
22418
+ const { replicationScopeFromSignedSession: replicationScopeFromSignedSession2 } = await getNodeReplicationLoaders().authority();
22419
+ const signedScope = replicationScopeFromSignedSession2({
22420
+ delegationHeader: sessionData.delegationHeader,
22421
+ delegationCid: sessionData.delegationCid,
22422
+ verificationMethod: restoredVerificationMethod,
22423
+ persistedSpace: sessionData.spaceId
22424
+ });
22425
+ if (!signedScope) {
22426
+ replicationScopeError = "Persisted space does not match the locally verified delegation scope.";
22427
+ } else {
22428
+ replicationPrincipal = signedScope.principal;
22429
+ compactReplicationSession = {
22430
+ delegationHeader: sessionData.delegationHeader,
22431
+ delegationCid: sessionData.delegationCid,
22432
+ spaceId: signedScope.space,
22433
+ verificationMethod: restoredVerificationMethod,
22434
+ jwk: stagedJwk
22435
+ };
22436
+ }
22437
+ }
22438
+ }
22439
+ const stagedNodeDid = stagedAddress ? (0, import_sdk_core9.pkhDid)(stagedAddress, stagedChainId) : canonicalVerificationMethod;
22440
+ const serviceSession = {
21618
22441
  delegationHeader: sessionData.delegationHeader,
21619
22442
  delegationCid: sessionData.delegationCid,
21620
22443
  spaceId: sessionData.spaceId,
@@ -21641,7 +22464,7 @@ var _TinyCloudNode = class _TinyCloudNode {
21641
22464
  stagedSessionExpiry,
21642
22465
  stagedRecap
21643
22466
  );
21644
- const stagedAccountSpaceId = stagedAddress ? this.wasmBindings.makeSpaceId(stagedAddress, stagedChainId, import_sdk_core8.ACCOUNT_REGISTRY_SPACE) : void 0;
22467
+ const stagedAccountSpaceId = stagedAddress ? this.wasmBindings.makeSpaceId(stagedAddress, stagedChainId, import_sdk_core9.ACCOUNT_REGISTRY_SPACE) : void 0;
21645
22468
  const stagedGraph = this.stageRestoredServiceGraph({
21646
22469
  host: stagedHost,
21647
22470
  manager: stagedManager,
@@ -21691,7 +22514,18 @@ var _TinyCloudNode = class _TinyCloudNode {
21691
22514
  } else {
21692
22515
  this._restoredTcSession = stagedTcSession;
21693
22516
  }
22517
+ this.replicationDelegateSession = compactReplicationSession;
22518
+ this.replicationScopeError = replicationScopeError;
22519
+ if (this.replicationRuntime) await (await this.replicationRuntime).unbind();
21694
22520
  oldGraph.retire();
22521
+ if (replicationScopeError) {
22522
+ stagedGraph.serviceContext.emit("replication.state", {
22523
+ state: "unavailable",
22524
+ code: "SESSION_SCOPE_MISMATCH",
22525
+ detail: replicationScopeError
22526
+ });
22527
+ }
22528
+ await this.bindReplicationRuntime(stagedGraph.serviceContext, serviceSession, stagedGraph.kv, replicationPrincipal);
21695
22529
  oldCore?.retireServices?.();
21696
22530
  }
21697
22531
  stagePrimarySessionState(session, verificationMethod, host, sessionExpiry, recap) {
@@ -21742,7 +22576,7 @@ var _TinyCloudNode = class _TinyCloudNode {
21742
22576
  }
21743
22577
  stageRestoredServiceGraph(input) {
21744
22578
  const graph = this.createServiceGraphLifetime();
21745
- const core = this.auth ? new import_sdk_core8.TinyCloud(this.auth, {
22579
+ const core = this.auth ? new import_sdk_core9.TinyCloud(this.auth, {
21746
22580
  invokeAny: graph.invokeAny,
21747
22581
  telemetry: this.config.telemetry
21748
22582
  }) : null;
@@ -21751,23 +22585,23 @@ var _TinyCloudNode = class _TinyCloudNode {
21751
22585
  const coreContext = graph.track(core.serviceContext);
21752
22586
  coreContext.setSession(input.serviceSession);
21753
22587
  }
21754
- const serviceContext = graph.track(new import_sdk_core8.ServiceContext({
22588
+ const serviceContext = graph.track(new import_sdk_core9.ServiceContext({
21755
22589
  invoke: graph.invoke,
21756
22590
  invokeAny: graph.invokeAny,
21757
22591
  fetch: graph.fetch,
21758
22592
  hosts: [input.host],
21759
22593
  telemetry: this.config.telemetry
21760
22594
  }));
21761
- const kv = new import_sdk_core8.KVService({});
22595
+ const kv = new import_sdk_core9.KVService({});
21762
22596
  kv.initialize(serviceContext);
21763
22597
  serviceContext.registerService("kv", kv);
21764
- const sql = new import_sdk_core8.SQLService({});
22598
+ const sql = new import_sdk_core9.SQLService({});
21765
22599
  sql.initialize(serviceContext);
21766
22600
  serviceContext.registerService("sql", sql);
21767
- const duckdb = new import_sdk_core8.DuckDbService({});
22601
+ const duckdb = new import_sdk_core9.DuckDbService({});
21768
22602
  duckdb.initialize(serviceContext);
21769
22603
  serviceContext.registerService("duckdb", duckdb);
21770
- const hooks = new import_sdk_core8.HooksService({});
22604
+ const hooks = new import_sdk_core9.HooksService({});
21771
22605
  hooks.initialize(serviceContext);
21772
22606
  serviceContext.registerService("hooks", hooks);
21773
22607
  serviceContext.setSession(input.serviceSession);
@@ -21790,7 +22624,7 @@ var _TinyCloudNode = class _TinyCloudNode {
21790
22624
  });
21791
22625
  vault.initialize(serviceContext);
21792
22626
  serviceContext.registerService("vault", vault);
21793
- const capabilityRegistry = new import_sdk_core8.CapabilityKeyRegistry();
22627
+ const capabilityRegistry = new import_sdk_core9.CapabilityKeyRegistry();
21794
22628
  if (input.tinyCloudSession) {
21795
22629
  const session = input.tinyCloudSession;
21796
22630
  const delegations = input.recap.map((entry) => ({
@@ -21814,7 +22648,7 @@ var _TinyCloudNode = class _TinyCloudNode {
21814
22648
  }, delegations);
21815
22649
  }
21816
22650
  }
21817
- const delegationManager = new import_sdk_core8.DelegationManager({
22651
+ const delegationManager = new import_sdk_core9.DelegationManager({
21818
22652
  hosts: [input.host],
21819
22653
  accountSpaceId: input.accountSpaceId,
21820
22654
  session: input.serviceSession,
@@ -21823,7 +22657,7 @@ var _TinyCloudNode = class _TinyCloudNode {
21823
22657
  fetch: graph.fetch
21824
22658
  });
21825
22659
  const keyProvider = new WasmKeyProvider({ sessionManager: input.manager });
21826
- const sharingService = new import_sdk_core8.SharingService({
22660
+ const sharingService = new import_sdk_core9.SharingService({
21827
22661
  hosts: [input.host],
21828
22662
  invoke: graph.invoke,
21829
22663
  fetch: graph.fetch,
@@ -21836,8 +22670,8 @@ var _TinyCloudNode = class _TinyCloudNode {
21836
22670
  return this.wasmBindings.computeCid(data, codec);
21837
22671
  },
21838
22672
  createKVService: (config) => {
21839
- const service = new import_sdk_core8.KVService({ prefix: config.pathPrefix?.replace(/\/$/, "") });
21840
- const context = graph.track(new import_sdk_core8.ServiceContext({
22673
+ const service = new import_sdk_core9.KVService({ prefix: config.pathPrefix?.replace(/\/$/, "") });
22674
+ const context = graph.track(new import_sdk_core9.ServiceContext({
21841
22675
  invoke: config.invoke,
21842
22676
  fetch: config.fetch ?? globalThis.fetch.bind(globalThis),
21843
22677
  hosts: config.hosts,
@@ -21845,6 +22679,7 @@ var _TinyCloudNode = class _TinyCloudNode {
21845
22679
  }));
21846
22680
  context.setSession(config.session);
21847
22681
  service.initialize(context);
22682
+ this.attachReplicationKV(config.session.spaceId, service);
21848
22683
  return service;
21849
22684
  }
21850
22685
  });
@@ -21866,7 +22701,7 @@ var _TinyCloudNode = class _TinyCloudNode {
21866
22701
  return delegation;
21867
22702
  } : void 0
21868
22703
  });
21869
- const spaceService = new import_sdk_core8.SpaceService({
22704
+ const spaceService = new import_sdk_core9.SpaceService({
21870
22705
  hosts: [input.host],
21871
22706
  session: input.serviceSession,
21872
22707
  invoke: graph.invoke,
@@ -21875,8 +22710,8 @@ var _TinyCloudNode = class _TinyCloudNode {
21875
22710
  userDid: input.nodeDid,
21876
22711
  createKVService: (spaceId) => {
21877
22712
  graph.assertActive();
21878
- const scopedKv = new import_sdk_core8.KVService({});
21879
- const context = graph.track(new import_sdk_core8.ServiceContext({
22713
+ const scopedKv = new import_sdk_core9.KVService({});
22714
+ const context = graph.track(new import_sdk_core9.ServiceContext({
21880
22715
  invoke: graph.invoke,
21881
22716
  invokeAny: graph.invokeAny,
21882
22717
  fetch: graph.fetch,
@@ -21885,12 +22720,13 @@ var _TinyCloudNode = class _TinyCloudNode {
21885
22720
  }));
21886
22721
  context.setSession({ ...input.serviceSession, spaceId });
21887
22722
  scopedKv.initialize(context);
22723
+ this.attachReplicationKV(spaceId, scopedKv);
21888
22724
  return scopedKv;
21889
22725
  },
21890
22726
  createVaultService: (spaceId) => {
21891
22727
  graph.assertActive();
21892
- const scopedKv = new import_sdk_core8.KVService({});
21893
- const context = graph.track(new import_sdk_core8.ServiceContext({
22728
+ const scopedKv = new import_sdk_core9.KVService({});
22729
+ const context = graph.track(new import_sdk_core9.ServiceContext({
21894
22730
  invoke: graph.invoke,
21895
22731
  invokeAny: graph.invokeAny,
21896
22732
  fetch: graph.fetch,
@@ -21899,6 +22735,7 @@ var _TinyCloudNode = class _TinyCloudNode {
21899
22735
  }));
21900
22736
  context.setSession({ ...input.serviceSession, spaceId });
21901
22737
  scopedKv.initialize(context);
22738
+ this.attachReplicationKV(spaceId, scopedKv);
21902
22739
  const scopedVault = this.createVaultService(spaceId, scopedKv, encryption, {
21903
22740
  host: input.host,
21904
22741
  did: input.nodeDid,
@@ -21976,7 +22813,7 @@ var _TinyCloudNode = class _TinyCloudNode {
21976
22813
  if (address === void 0 || chainId === void 0) {
21977
22814
  return void 0;
21978
22815
  }
21979
- const resolved = await (0, import_sdk_core8.resolveTinyCloudHosts)((0, import_sdk_core8.pkhDid)(address, chainId), {
22816
+ const resolved = await (0, import_sdk_core9.resolveTinyCloudHosts)((0, import_sdk_core9.pkhDid)(address, chainId), {
21980
22817
  registryUrl: this.config.tinycloudRegistryUrl,
21981
22818
  fallbackHosts: this.config.tinycloudFallbackHosts,
21982
22819
  autoDiscoverLocalNode: this.config.autoDiscoverLocalNode,
@@ -22028,7 +22865,7 @@ var _TinyCloudNode = class _TinyCloudNode {
22028
22865
  nodeAudience: input.nodeAudience,
22029
22866
  ...input.role === "policy-enforcement" ? { enforcerDid: input.audienceDid } : {}
22030
22867
  };
22031
- const root = await (0, import_sdk_core8.signCompactUcanRootAuthorization)({
22868
+ const root = await (0, import_sdk_core9.signCompactUcanRootAuthorization)({
22032
22869
  issuerDid: ownerDid,
22033
22870
  audienceDid: input.audienceDid,
22034
22871
  attenuation: unifiedRootAttenuation(input.capabilities),
@@ -22070,7 +22907,7 @@ var _TinyCloudNode = class _TinyCloudNode {
22070
22907
  if (decision.needsApproval) return void 0;
22071
22908
  throw new Error(decision.reason ?? "OpenKey automatic credential signing was rejected");
22072
22909
  }
22073
- if (typeof decision.signature !== "string" || !await (0, import_sdk_core8.verifyEip191MessageSignature)(
22910
+ if (typeof decision.signature !== "string" || !await (0, import_sdk_core9.verifyEip191MessageSignature)(
22074
22911
  request.message,
22075
22912
  decision.signature,
22076
22913
  request.address
@@ -22095,7 +22932,7 @@ var _TinyCloudNode = class _TinyCloudNode {
22095
22932
  if (approval) {
22096
22933
  const decision = await approval(request);
22097
22934
  if (!decision.approved) throw new Error(decision.reason ?? "Credential signing was rejected");
22098
- if (decision.signature !== void 0 && !await (0, import_sdk_core8.verifyEip191MessageSignature)(
22935
+ if (decision.signature !== void 0 && !await (0, import_sdk_core9.verifyEip191MessageSignature)(
22099
22936
  request.message,
22100
22937
  decision.signature,
22101
22938
  request.address
@@ -22178,10 +23015,15 @@ var _TinyCloudNode = class _TinyCloudNode {
22178
23015
  nonce: this.config.nonce,
22179
23016
  siweConfig: this.config.siweConfig,
22180
23017
  manifest: useBootstrapSignInRequest ? void 0 : this.config.manifest,
22181
- capabilityRequest: useBootstrapSignInRequest ? this.config.includeAccountRegistryPermissions === false ? import_sdk_core8.BOOTSTRAP_DEFAULT_ONLY_SESSION_REQUEST : import_sdk_core8.BOOTSTRAP_SESSION_REQUESTS.default : this.config.capabilityRequest,
22182
- includeAccountRegistryPermissions: useBootstrapSignInRequest ? false : this.config.includeAccountRegistryPermissions
23018
+ capabilityRequest: useBootstrapSignInRequest ? this.config.includeAccountRegistryPermissions === false ? import_sdk_core9.BOOTSTRAP_DEFAULT_ONLY_SESSION_REQUEST : import_sdk_core9.BOOTSTRAP_SESSION_REQUESTS.default : this.config.capabilityRequest,
23019
+ includeAccountRegistryPermissions: useBootstrapSignInRequest ? false : this.config.includeAccountRegistryPermissions,
23020
+ replication: this.config.replication?.enabled === true ? {
23021
+ enabled: true,
23022
+ prefixes: this.config.replication.prefixes,
23023
+ allowSecrets: this.config.replication.allowSecrets === true
23024
+ } : void 0
22183
23025
  });
22184
- this.tc = new import_sdk_core8.TinyCloud(this.auth, {
23026
+ this.tc = new import_sdk_core9.TinyCloud(this.auth, {
22185
23027
  invokeAny: this.invokeAnyWithRuntimePermissions,
22186
23028
  telemetry: this.config.telemetry
22187
23029
  });
@@ -22231,10 +23073,15 @@ var _TinyCloudNode = class _TinyCloudNode {
22231
23073
  nonce: this.config.nonce,
22232
23074
  siweConfig: this.config.siweConfig,
22233
23075
  manifest: useBootstrapSignInRequest ? void 0 : this.config.manifest,
22234
- capabilityRequest: useBootstrapSignInRequest ? this.config.includeAccountRegistryPermissions === false ? import_sdk_core8.BOOTSTRAP_DEFAULT_ONLY_SESSION_REQUEST : import_sdk_core8.BOOTSTRAP_SESSION_REQUESTS.default : this.config.capabilityRequest,
22235
- includeAccountRegistryPermissions: useBootstrapSignInRequest ? false : this.config.includeAccountRegistryPermissions
23076
+ capabilityRequest: useBootstrapSignInRequest ? this.config.includeAccountRegistryPermissions === false ? import_sdk_core9.BOOTSTRAP_DEFAULT_ONLY_SESSION_REQUEST : import_sdk_core9.BOOTSTRAP_SESSION_REQUESTS.default : this.config.capabilityRequest,
23077
+ includeAccountRegistryPermissions: useBootstrapSignInRequest ? false : this.config.includeAccountRegistryPermissions,
23078
+ replication: this.config.replication?.enabled === true ? {
23079
+ enabled: true,
23080
+ prefixes: this.config.replication.prefixes,
23081
+ allowSecrets: this.config.replication.allowSecrets === true
23082
+ } : void 0
22236
23083
  });
22237
- this.tc = new import_sdk_core8.TinyCloud(this.auth, {
23084
+ this.tc = new import_sdk_core9.TinyCloud(this.auth, {
22238
23085
  invokeAny: this.invokeAnyWithRuntimePermissions,
22239
23086
  telemetry: this.config.telemetry
22240
23087
  });
@@ -22244,7 +23091,7 @@ var _TinyCloudNode = class _TinyCloudNode {
22244
23091
  * Initialize the service context and KV service after sign-in.
22245
23092
  * @internal
22246
23093
  */
22247
- initializeServices() {
23094
+ async initializeServices() {
22248
23095
  const session = this.currentTinyCloudSession();
22249
23096
  if (!session) {
22250
23097
  return;
@@ -22255,28 +23102,28 @@ var _TinyCloudNode = class _TinyCloudNode {
22255
23102
  this._serviceGraph.fetch
22256
23103
  );
22257
23104
  this._serviceGraph.track(this.tc.serviceContext);
22258
- this._serviceContext = this._serviceGraph.track(new import_sdk_core8.ServiceContext({
23105
+ this._serviceContext = this._serviceGraph.track(new import_sdk_core9.ServiceContext({
22259
23106
  invoke: this._serviceGraph.invoke,
22260
23107
  invokeAny: this._serviceGraph.invokeAny,
22261
23108
  fetch: this._serviceGraph.fetch,
22262
23109
  hosts: [this.config.host],
22263
23110
  telemetry: this.config.telemetry
22264
23111
  }));
22265
- this._kv = new import_sdk_core8.KVService({});
23112
+ this._kv = new import_sdk_core9.KVService({});
22266
23113
  this._kv.initialize(this._serviceContext);
22267
23114
  this._serviceContext.registerService("kv", this._kv);
22268
23115
  const features = this.nodeFeatures;
22269
23116
  if (features.length === 0 || features.includes("sql")) {
22270
- this._sql = new import_sdk_core8.SQLService({});
23117
+ this._sql = new import_sdk_core9.SQLService({});
22271
23118
  this._sql.initialize(this._serviceContext);
22272
23119
  this._serviceContext.registerService("sql", this._sql);
22273
23120
  }
22274
23121
  if (features.length === 0 || features.includes("duckdb")) {
22275
- this._duckdb = new import_sdk_core8.DuckDbService({});
23122
+ this._duckdb = new import_sdk_core9.DuckDbService({});
22276
23123
  this._duckdb.initialize(this._serviceContext);
22277
23124
  this._serviceContext.registerService("duckdb", this._duckdb);
22278
23125
  }
22279
- this._hooks = new import_sdk_core8.HooksService({});
23126
+ this._hooks = new import_sdk_core9.HooksService({});
22280
23127
  this._hooks.initialize(this._serviceContext);
22281
23128
  this._serviceContext.registerService("hooks", this._hooks);
22282
23129
  const serviceSession = {
@@ -22287,16 +23134,22 @@ var _TinyCloudNode = class _TinyCloudNode {
22287
23134
  jwk: session.jwk
22288
23135
  };
22289
23136
  this._serviceContext.setSession(serviceSession);
23137
+ await this.bindReplicationRuntime(this._serviceContext, serviceSession, this._kv);
22290
23138
  this.tc.serviceContext.setSession(serviceSession);
22291
23139
  this._vault = this.createVaultService(session.spaceId, this._kv);
22292
23140
  this._vault.initialize(this._serviceContext);
22293
23141
  this._serviceContext.registerService("vault", this._vault);
22294
23142
  this.initializeV2Services(serviceSession);
22295
23143
  }
23144
+ attachReplicationKV(spaceId, kvService) {
23145
+ if (!this.replicationRuntime) return;
23146
+ const attached = this.replicationRuntime.then((runtime) => runtime.attach(spaceId, kvService));
23147
+ kvService.setReadThroughReady(attached);
23148
+ }
22296
23149
  createSpaceScopedKVService(spaceId) {
22297
- const kvService = new import_sdk_core8.KVService({});
23150
+ const kvService = new import_sdk_core9.KVService({});
22298
23151
  if (this._serviceContext) {
22299
- const spaceScopedContext = this._serviceGraph.track(new import_sdk_core8.ServiceContext({
23152
+ const spaceScopedContext = this._serviceGraph.track(new import_sdk_core9.ServiceContext({
22300
23153
  invoke: this._serviceContext.invoke,
22301
23154
  invokeAny: this._serviceContext.invokeAny,
22302
23155
  fetch: this._serviceContext.fetch,
@@ -22308,6 +23161,7 @@ var _TinyCloudNode = class _TinyCloudNode {
22308
23161
  spaceScopedContext.setSession({ ...session, spaceId });
22309
23162
  }
22310
23163
  kvService.initialize(spaceScopedContext);
23164
+ this.attachReplicationKV(spaceId, kvService);
22311
23165
  }
22312
23166
  return kvService;
22313
23167
  }
@@ -22388,7 +23242,7 @@ var _TinyCloudNode = class _TinyCloudNode {
22388
23242
  const shared = wasm.vault_x25519_dh(receiverPrivateKey, peerPublic);
22389
23243
  return columnDecrypt(shared, ciphertext);
22390
23244
  },
22391
- verifyNodeSignature: (nodeId, message, signature2) => (0, import_sdk_core8.verifyDidKeyEd25519Signature)(nodeId, message, signature2)
23245
+ verifyNodeSignature: (nodeId, message, signature2) => (0, import_sdk_core9.verifyDidKeyEd25519Signature)(nodeId, message, signature2)
22392
23246
  };
22393
23247
  }
22394
23248
  /**
@@ -22404,7 +23258,7 @@ var _TinyCloudNode = class _TinyCloudNode {
22404
23258
  if (cached) return cached;
22405
23259
  const response = await fetch(`${this.config.host}/info`);
22406
23260
  if (!response.ok) {
22407
- throw await (0, import_sdk_core8.httpResponseError)(response, "Failed to fetch node info");
23261
+ throw await (0, import_sdk_core9.httpResponseError)(response, "Failed to fetch node info");
22408
23262
  }
22409
23263
  const info = await response.json();
22410
23264
  if (typeof info.nodeId !== "string" || info.nodeId.length === 0) {
@@ -22454,7 +23308,7 @@ var _TinyCloudNode = class _TinyCloudNode {
22454
23308
  );
22455
23309
  if (response.status === 404) return null;
22456
23310
  if (!response.ok) {
22457
- throw await (0, import_sdk_core8.httpResponseError)(response, `Failed to fetch encryption network ${networkId}`);
23311
+ throw await (0, import_sdk_core9.httpResponseError)(response, `Failed to fetch encryption network ${networkId}`);
22458
23312
  }
22459
23313
  const body = await response.json();
22460
23314
  return "descriptor" in body && body.descriptor ? body.descriptor : body;
@@ -22485,17 +23339,17 @@ var _TinyCloudNode = class _TinyCloudNode {
22485
23339
  );
22486
23340
  graph.assertActive();
22487
23341
  if (!response.ok) {
22488
- const permissionHint = response.status === 401 || response.status === 403 ? (0, import_sdk_services.parsePermissionHint)({
23342
+ const permissionHint = response.status === 401 || response.status === 403 ? (0, import_sdk_services3.parsePermissionHint)({
22489
23343
  service: "tinycloud.encryption",
22490
23344
  path: networkId,
22491
23345
  actions: ["tinycloud.encryption/decrypt"]
22492
23346
  }) : void 0;
22493
- throw new import_sdk_core8.DecryptTransportResponseError(response.status, permissionHint);
23347
+ throw new import_sdk_core9.DecryptTransportResponseError(response.status, permissionHint);
22494
23348
  }
22495
23349
  return await response.json();
22496
23350
  }
22497
23351
  };
22498
- return new import_sdk_core8.EncryptionService({
23352
+ return new import_sdk_core9.EncryptionService({
22499
23353
  crypto: crypto3,
22500
23354
  signer: {
22501
23355
  signDecryptInvocation: async (input) => {
@@ -22509,7 +23363,7 @@ var _TinyCloudNode = class _TinyCloudNode {
22509
23363
  graph.assertActive();
22510
23364
  return {
22511
23365
  ...signed2,
22512
- canonicalBody: (0, import_sdk_core8.canonicalizeEncryptionJson)(
23366
+ canonicalBody: (0, import_sdk_core9.canonicalizeEncryptionJson)(
22513
23367
  input.body
22514
23368
  )
22515
23369
  };
@@ -22541,7 +23395,7 @@ var _TinyCloudNode = class _TinyCloudNode {
22541
23395
  if (!address || !didPrincipalMatches2(principal, did)) {
22542
23396
  return null;
22543
23397
  }
22544
- const publicSpaceId = (0, import_sdk_core8.makePublicSpaceId)(address, chainId);
23398
+ const publicSpaceId = (0, import_sdk_core9.makePublicSpaceId)(address, chainId);
22545
23399
  const encodedKey = discoveryKey.split("/").map(encodeURIComponent).join("/");
22546
23400
  const response = await graph.fetch(
22547
23401
  `${host}/public/${encodeURIComponent(publicSpaceId)}/kv/${encodedKey}`,
@@ -22573,7 +23427,7 @@ var _TinyCloudNode = class _TinyCloudNode {
22573
23427
  createVaultService(spaceId, kv, encryptionService = this.getEncryptionService(), nodeContext) {
22574
23428
  const wasm = this.wasmBindings;
22575
23429
  const serviceGraph = nodeContext?.serviceGraph ?? this._serviceGraph;
22576
- const vaultCrypto = (0, import_sdk_core8.createVaultCrypto)({
23430
+ const vaultCrypto = (0, import_sdk_core9.createVaultCrypto)({
22577
23431
  vault_encrypt: wasm.vault_encrypt,
22578
23432
  vault_decrypt: wasm.vault_decrypt,
22579
23433
  vault_derive_key: wasm.vault_derive_key,
@@ -22588,7 +23442,7 @@ var _TinyCloudNode = class _TinyCloudNode {
22588
23442
  const chainId = nodeContext?.chainId ?? this._chainId;
22589
23443
  const host = nodeContext?.host ?? this.config.host;
22590
23444
  const ownerDid = this.ownerDidFromSpaceId(spaceId) ?? did;
22591
- return new import_sdk_core8.DataVaultService({
23445
+ return new import_sdk_core9.DataVaultService({
22592
23446
  spaceId,
22593
23447
  crypto: vaultCrypto,
22594
23448
  encryption: {
@@ -22613,8 +23467,8 @@ var _TinyCloudNode = class _TinyCloudNode {
22613
23467
  serviceGraph.assertActive();
22614
23468
  return self2._publicKV ?? self2.tc.publicKV;
22615
23469
  },
22616
- readPublicSpace: (host2, targetSpaceId, key2) => import_sdk_core8.TinyCloud.readPublicSpace(host2, targetSpaceId, key2),
22617
- makePublicSpaceId: import_sdk_core8.TinyCloud.makePublicSpaceId,
23470
+ readPublicSpace: (host2, targetSpaceId, key2) => import_sdk_core9.TinyCloud.readPublicSpace(host2, targetSpaceId, key2),
23471
+ makePublicSpaceId: import_sdk_core9.TinyCloud.makePublicSpaceId,
22618
23472
  did,
22619
23473
  address: address ?? "",
22620
23474
  chainId,
@@ -22628,7 +23482,7 @@ var _TinyCloudNode = class _TinyCloudNode {
22628
23482
  */
22629
23483
  initializeV2Services(serviceSession) {
22630
23484
  const graph = this._serviceGraph;
22631
- this._capabilityRegistry = new import_sdk_core8.CapabilityKeyRegistry();
23485
+ this._capabilityRegistry = new import_sdk_core9.CapabilityKeyRegistry();
22632
23486
  const tcSession = this.auth?.tinyCloudSession;
22633
23487
  if (tcSession && this._address) {
22634
23488
  const sessionKey = {
@@ -22668,7 +23522,7 @@ var _TinyCloudNode = class _TinyCloudNode {
22668
23522
  }
22669
23523
  this._capabilityRegistry.registerKey(sessionKey, delegations);
22670
23524
  }
22671
- this._delegationManager = new import_sdk_core8.DelegationManager({
23525
+ this._delegationManager = new import_sdk_core9.DelegationManager({
22672
23526
  hosts: [this.config.host],
22673
23527
  accountSpaceId: this.accountSpaceId,
22674
23528
  session: serviceSession,
@@ -22676,7 +23530,7 @@ var _TinyCloudNode = class _TinyCloudNode {
22676
23530
  invokeAny: graph.invokeAny,
22677
23531
  fetch: graph.fetch
22678
23532
  });
22679
- this._spaceService = new import_sdk_core8.SpaceService({
23533
+ this._spaceService = new import_sdk_core9.SpaceService({
22680
23534
  hosts: [this.config.host],
22681
23535
  session: serviceSession,
22682
23536
  invoke: graph.invoke,
@@ -22741,7 +23595,7 @@ var _TinyCloudNode = class _TinyCloudNode {
22741
23595
  await this.account.spaces.register(space);
22742
23596
  }
22743
23597
  });
22744
- this._sharingService = new import_sdk_core8.SharingService({
23598
+ this._sharingService = new import_sdk_core9.SharingService({
22745
23599
  hosts: [this.config.host],
22746
23600
  session: serviceSession,
22747
23601
  invoke: graph.invoke,
@@ -22761,8 +23615,8 @@ var _TinyCloudNode = class _TinyCloudNode {
22761
23615
  },
22762
23616
  createKVService: (config) => {
22763
23617
  graph.assertActive();
22764
- const service = new import_sdk_core8.KVService({ prefix: config.pathPrefix?.replace(/\/$/, "") });
22765
- const context = graph.track(new import_sdk_core8.ServiceContext({
23618
+ const service = new import_sdk_core9.KVService({ prefix: config.pathPrefix?.replace(/\/$/, "") });
23619
+ const context = graph.track(new import_sdk_core9.ServiceContext({
22766
23620
  invoke: config.invoke,
22767
23621
  fetch: config.fetch ?? graph.fetch,
22768
23622
  hosts: config.hosts,
@@ -22770,6 +23624,7 @@ var _TinyCloudNode = class _TinyCloudNode {
22770
23624
  }));
22771
23625
  context.setSession(config.session);
22772
23626
  service.initialize(context);
23627
+ this.attachReplicationKV(config.session.spaceId, service);
22773
23628
  return service;
22774
23629
  },
22775
23630
  onRootDelegationNeeded: this.signer ? async (params) => {
@@ -22855,15 +23710,15 @@ var _TinyCloudNode = class _TinyCloudNode {
22855
23710
  }
22856
23711
  const permissions = ownerDelegationPermissions(params);
22857
23712
  const now = /* @__PURE__ */ new Date();
22858
- if (!(params.expiresAt instanceof Date) || params.expiresAt.getTime() <= now.getTime() || params.expiresAt.getTime() - now.getTime() > import_sdk_core8.EXPIRY.MAX_MS) {
23713
+ if (!(params.expiresAt instanceof Date) || params.expiresAt.getTime() <= now.getTime() || params.expiresAt.getTime() - now.getTime() > import_sdk_core9.EXPIRY.MAX_MS) {
22859
23714
  throw new Error("Owner delegation expiry must be explicit, future, and within EXPIRY.MAX_MS");
22860
23715
  }
22861
23716
  if (!this.signer) throw new Error("Owner wallet signer is required");
22862
23717
  const session = this.currentTinyCloudSession();
22863
23718
  if (!session) throw new Error("Owner session is required");
22864
- const ownerDid = (0, import_sdk_core8.pkhDid)(session.address, session.chainId);
23719
+ const ownerDid = (0, import_sdk_core9.pkhDid)(session.address, session.chainId);
22865
23720
  for (const permission of permissions) {
22866
- if (permission.service === import_sdk_core8.ENCRYPTION_PERMISSION_SERVICE && !(0, import_sdk_core8.principalDidEquals)((0, import_sdk_core8.parseNetworkId)(permission.path).ownerDid, ownerDid)) {
23721
+ if (permission.service === import_sdk_core9.ENCRYPTION_PERMISSION_SERVICE && !(0, import_sdk_core9.principalDidEquals)((0, import_sdk_core9.parseNetworkId)(permission.path).ownerDid, ownerDid)) {
22867
23722
  throw new Error("Owner delegation cannot grant a foreign encryption network");
22868
23723
  }
22869
23724
  }
@@ -22884,7 +23739,7 @@ var _TinyCloudNode = class _TinyCloudNode {
22884
23739
  const signature2 = await this.signer.signMessage(prepared.siwe);
22885
23740
  assertOwnerGraphActive();
22886
23741
  const delegationSession = this.wasmBindings.completeSessionSetup({ ...prepared, signature: signature2 });
22887
- const activation = await (0, import_sdk_core8.activateSessionWithHost)(host, delegationSession.delegationHeader);
23742
+ const activation = await (0, import_sdk_core9.activateSessionWithHost)(host, delegationSession.delegationHeader);
22888
23743
  assertOwnerGraphActive();
22889
23744
  if (!activation.success) {
22890
23745
  throw Object.assign(
@@ -22920,7 +23775,7 @@ var _TinyCloudNode = class _TinyCloudNode {
22920
23775
  /** Register a signed policy and sibling roots with this Node's Policy/v3 runtime. */
22921
23776
  async registerPolicy(params) {
22922
23777
  this._serviceGraph.assertActive();
22923
- return (0, import_sdk_core8.registerPolicyV3)({
23778
+ return (0, import_sdk_core9.registerPolicyV3)({
22924
23779
  ...params,
22925
23780
  nodeOrigin: this.config.host,
22926
23781
  fetch: globalThis.fetch.bind(globalThis)
@@ -22947,23 +23802,23 @@ var _TinyCloudNode = class _TinyCloudNode {
22947
23802
  jti: base64UrlEncode(jtiDigest.slice(0, 16)),
22948
23803
  expiresAt: new Date(input.expiresAt).toISOString().replace(/\.\d{3}Z$/, "Z")
22949
23804
  };
22950
- const requestBodyDigest = base64UrlEncode(new Uint8Array(await crypto.subtle.digest("SHA-256", new TextEncoder().encode((0, import_sdk_core8.canonicalizeEncryptionJson)(body)))));
23805
+ const requestBodyDigest = base64UrlEncode(new Uint8Array(await crypto.subtle.digest("SHA-256", new TextEncoder().encode((0, import_sdk_core9.canonicalizeEncryptionJson)(body)))));
22951
23806
  const request = { ...body, requestBodyDigest };
22952
23807
  const authorization = authorizationHeader(this.invokeAnyWithRuntimePermissions(serviceSession, [{ spaceId: session.spaceId, service: "kv", path: input.resourcePath, action: "tinycloud.kv/get" }]));
22953
23808
  const response = await fetch(`${this.config.host}/policy/v3/deliveries/authorize`, {
22954
23809
  method: "POST",
22955
23810
  headers: { accept: "application/json", "content-type": "application/json", authorization },
22956
- body: (0, import_sdk_core8.canonicalizeEncryptionJson)(request)
23811
+ body: (0, import_sdk_core9.canonicalizeEncryptionJson)(request)
22957
23812
  });
22958
- if (!response.ok) throw await (0, import_sdk_core8.httpResponseError)(response, "V3 share delivery authorization failed");
22959
- const verified = (0, import_sdk_core8.validateShareDeliveryAuthorizationV3Bytes)(new Uint8Array(await response.arrayBuffer()), {
23813
+ if (!response.ok) throw await (0, import_sdk_core9.httpResponseError)(response, "V3 share delivery authorization failed");
23814
+ const verified = (0, import_sdk_core9.validateShareDeliveryAuthorizationV3Bytes)(new Uint8Array(await response.arrayBuffer()), {
22960
23815
  request,
22961
23816
  senderKeyDid: this.credentialHolderDid,
22962
23817
  deliveryAudience: input.deliveryAudience
22963
23818
  });
22964
23819
  const requestDigest = new Uint8Array(await crypto.subtle.digest(
22965
23820
  "SHA-256",
22966
- new TextEncoder().encode(`${import_sdk_core8.CREDENTIAL_INVITATION_REQUEST_DOMAIN}${(0, import_sdk_core8.canonicalizeEncryptionJson)(verified.request)}`)
23821
+ new TextEncoder().encode(`${import_sdk_core9.CREDENTIAL_INVITATION_REQUEST_DOMAIN}${(0, import_sdk_core9.canonicalizeEncryptionJson)(verified.request)}`)
22967
23822
  ));
22968
23823
  return {
22969
23824
  ...verified,
@@ -23031,7 +23886,7 @@ var _TinyCloudNode = class _TinyCloudNode {
23031
23886
  if (!this._sql) {
23032
23887
  const features = this.nodeFeatures;
23033
23888
  if (features.length > 0 && !features.includes("sql")) {
23034
- throw new import_sdk_core8.UnsupportedFeatureError("sql", this.config.host, features);
23889
+ throw new import_sdk_core9.UnsupportedFeatureError("sql", this.config.host, features);
23035
23890
  }
23036
23891
  throw new Error("Not signed in. Call signIn() first.");
23037
23892
  }
@@ -23055,8 +23910,8 @@ var _TinyCloudNode = class _TinyCloudNode {
23055
23910
  if (!this._serviceContext || !this._serviceContext.session) {
23056
23911
  throw new Error("Not signed in. Call signIn() first.");
23057
23912
  }
23058
- const sql = new import_sdk_core8.SQLService({});
23059
- const spaceScopedContext = this._serviceGraph.track(new import_sdk_core8.ServiceContext({
23913
+ const sql = new import_sdk_core9.SQLService({});
23914
+ const spaceScopedContext = this._serviceGraph.track(new import_sdk_core9.ServiceContext({
23060
23915
  invoke: this._serviceContext.invoke,
23061
23916
  invokeAny: this._serviceContext.invokeAny,
23062
23917
  fetch: this._serviceContext.fetch,
@@ -23085,8 +23940,8 @@ var _TinyCloudNode = class _TinyCloudNode {
23085
23940
  if (!this._serviceContext || !this._serviceContext.session) {
23086
23941
  throw new Error("Not signed in. Call signIn() first.");
23087
23942
  }
23088
- const kv = new import_sdk_core8.KVService({});
23089
- const spaceScopedContext = this._serviceGraph.track(new import_sdk_core8.ServiceContext({
23943
+ const kv = new import_sdk_core9.KVService({});
23944
+ const spaceScopedContext = this._serviceGraph.track(new import_sdk_core9.ServiceContext({
23090
23945
  invoke: this._serviceContext.invoke,
23091
23946
  invokeAny: this._serviceContext.invokeAny,
23092
23947
  fetch: this._serviceContext.fetch,
@@ -23094,6 +23949,7 @@ var _TinyCloudNode = class _TinyCloudNode {
23094
23949
  }));
23095
23950
  spaceScopedContext.setSession({ ...this._serviceContext.session, spaceId });
23096
23951
  kv.initialize(spaceScopedContext);
23952
+ this.attachReplicationKV(spaceId, kv);
23097
23953
  return kv;
23098
23954
  }
23099
23955
  /**
@@ -23103,7 +23959,7 @@ var _TinyCloudNode = class _TinyCloudNode {
23103
23959
  if (!this._duckdb) {
23104
23960
  const features = this.nodeFeatures;
23105
23961
  if (features.length > 0 && !features.includes("duckdb")) {
23106
- throw new import_sdk_core8.UnsupportedFeatureError("duckdb", this.config.host, features);
23962
+ throw new import_sdk_core9.UnsupportedFeatureError("duckdb", this.config.host, features);
23107
23963
  }
23108
23964
  throw new Error("Not signed in. Call signIn() first.");
23109
23965
  }
@@ -23147,7 +24003,7 @@ var _TinyCloudNode = class _TinyCloudNode {
23147
24003
  type: NETWORK_ADMIN_TYPE,
23148
24004
  targetNode,
23149
24005
  networkId,
23150
- bodyHash: (0, import_sdk_core8.canonicalHashHex)(
24006
+ bodyHash: (0, import_sdk_core9.canonicalHashHex)(
23151
24007
  crypto3.sha256,
23152
24008
  body
23153
24009
  ),
@@ -23165,7 +24021,7 @@ var _TinyCloudNode = class _TinyCloudNode {
23165
24021
  Authorization: signed2.authorization,
23166
24022
  "Content-Type": "application/json"
23167
24023
  },
23168
- body: (0, import_sdk_core8.canonicalizeEncryptionJson)(
24024
+ body: (0, import_sdk_core9.canonicalizeEncryptionJson)(
23169
24025
  body
23170
24026
  )
23171
24027
  });
@@ -23177,7 +24033,7 @@ var _TinyCloudNode = class _TinyCloudNode {
23177
24033
  );
23178
24034
  }
23179
24035
  if (!response.ok) {
23180
- throw await (0, import_sdk_core8.httpResponseError)(response, `Failed to create encryption network ${networkId}`);
24036
+ throw await (0, import_sdk_core9.httpResponseError)(response, `Failed to create encryption network ${networkId}`);
23181
24037
  }
23182
24038
  const created = await response.json();
23183
24039
  return created.descriptor;
@@ -23196,7 +24052,7 @@ var _TinyCloudNode = class _TinyCloudNode {
23196
24052
  return existing;
23197
24053
  }
23198
24054
  }
23199
- const parsed = (0, import_sdk_core8.parseNetworkId)(networkId);
24055
+ const parsed = (0, import_sdk_core9.parseNetworkId)(networkId);
23200
24056
  if (!didPrincipalMatches2(parsed.ownerDid, this.did)) {
23201
24057
  throw new Error(
23202
24058
  `Cannot create encryption network ${networkId}: owner ${parsed.ownerDid} does not match signed-in DID ${this.did}`
@@ -23244,14 +24100,14 @@ var _TinyCloudNode = class _TinyCloudNode {
23244
24100
  * normal KV and encryption invocation paths.
23245
24101
  */
23246
24102
  async readSecret(input) {
23247
- const resolved = (0, import_sdk_core8.resolveSecretPath)(input.name, { scope: input.scope });
24103
+ const resolved = (0, import_sdk_core9.resolveSecretPath)(input.name, { scope: input.scope });
23248
24104
  const targetSpace = input.space.startsWith("tinycloud:") ? input.space : this.ownedSpaceId(input.space);
23249
24105
  const result = await this.getBaseVault(targetSpace).readNetworkEncrypted(
23250
24106
  resolved.vaultKey
23251
24107
  );
23252
24108
  if (result.status !== "ok") {
23253
24109
  if (result.status === "permission_required") {
23254
- const hint = (0, import_sdk_services.parsePermissionHint)(result.hint);
24110
+ const hint = (0, import_sdk_services3.parsePermissionHint)(result.hint);
23255
24111
  if (hint === void 0) return { status: "read_failed" };
23256
24112
  return {
23257
24113
  status: "permission_required",
@@ -23277,7 +24133,7 @@ var _TinyCloudNode = class _TinyCloudNode {
23277
24133
  const resolvedSpace = spaceId.startsWith("tinycloud:") ? spaceId : this.ownedSpaceId(spaceId);
23278
24134
  let secrets = this._baseSecrets.get(resolvedSpace);
23279
24135
  if (!secrets) {
23280
- secrets = new import_sdk_core8.SecretsService(() => this.getBaseVault(resolvedSpace));
24136
+ secrets = new import_sdk_core9.SecretsService(() => this.getBaseVault(resolvedSpace));
23281
24137
  this._baseSecrets.set(resolvedSpace, secrets);
23282
24138
  }
23283
24139
  return secrets;
@@ -23420,7 +24276,7 @@ var _TinyCloudNode = class _TinyCloudNode {
23420
24276
  for (const grant of this.runtimePermissionGrants) {
23421
24277
  if (grant.provenance === "primary") continue;
23422
24278
  for (const operation of grant.operations) {
23423
- const service = import_sdk_core8.SERVICE_SHORT_TO_LONG[operation.service];
24279
+ const service = import_sdk_core9.SERVICE_SHORT_TO_LONG[operation.service];
23424
24280
  if (service === void 0 || typeof operation.path !== "string" || typeof operation.action !== "string") {
23425
24281
  continue;
23426
24282
  }
@@ -23438,7 +24294,7 @@ var _TinyCloudNode = class _TinyCloudNode {
23438
24294
  service,
23439
24295
  ...space === void 0 ? {} : { space },
23440
24296
  path: operation.path,
23441
- caveats: (0, import_sdk_core8.canonicalizeRecapCaveats)(caveats)
24297
+ caveats: (0, import_sdk_core9.canonicalizeRecapCaveats)(caveats)
23442
24298
  });
23443
24299
  const existing = grouped.get(identity);
23444
24300
  if (existing === void 0) {
@@ -23483,7 +24339,7 @@ var _TinyCloudNode = class _TinyCloudNode {
23483
24339
  delegationCid: grant.delegationCid,
23484
24340
  spaceId: grant.spaceId,
23485
24341
  jwk: this.sessionKeyJwk,
23486
- address: (0, import_sdk_core8.canonicalizeAddress)(grant.address),
24342
+ address: (0, import_sdk_core9.canonicalizeAddress)(grant.address),
23487
24343
  chainId: grant.chainId,
23488
24344
  siwe: grant.siwe,
23489
24345
  signature: grant.signature
@@ -23504,10 +24360,10 @@ var _TinyCloudNode = class _TinyCloudNode {
23504
24360
  async useRuntimeDelegation(delegation) {
23505
24361
  const session = this.currentTinyCloudSession();
23506
24362
  if (!session) {
23507
- throw new import_sdk_core8.SessionExpiredError(/* @__PURE__ */ new Date(0));
24363
+ throw new import_sdk_core9.SessionExpiredError(/* @__PURE__ */ new Date(0));
23508
24364
  }
23509
24365
  if (delegation.expiry.getTime() <= Date.now()) {
23510
- throw new import_sdk_core8.SessionExpiredError(delegation.expiry);
24366
+ throw new import_sdk_core9.SessionExpiredError(delegation.expiry);
23511
24367
  }
23512
24368
  const expectedDids = [session.verificationMethod, this.sessionDid];
23513
24369
  if (!expectedDids.some((did) => didPrincipalMatches2(delegation.delegateDID, did))) {
@@ -23518,7 +24374,7 @@ var _TinyCloudNode = class _TinyCloudNode {
23518
24374
  const targetHost = delegation.host ?? this.config.host;
23519
24375
  let activateResult;
23520
24376
  try {
23521
- activateResult = await (0, import_sdk_core8.activateSessionWithHost)(
24377
+ activateResult = await (0, import_sdk_core9.activateSessionWithHost)(
23522
24378
  targetHost,
23523
24379
  delegation.delegationHeader
23524
24380
  );
@@ -23560,13 +24416,13 @@ var _TinyCloudNode = class _TinyCloudNode {
23560
24416
  }
23561
24417
  const session = this.currentTinyCloudSession();
23562
24418
  if (!session) {
23563
- throw new import_sdk_core8.SessionExpiredError(/* @__PURE__ */ new Date(0));
24419
+ throw new import_sdk_core9.SessionExpiredError(/* @__PURE__ */ new Date(0));
23564
24420
  }
23565
24421
  const sessionExpiry = extractSiweExpiration(session.siwe);
23566
24422
  if (sessionExpiry !== void 0) {
23567
24423
  const marginMs = _TinyCloudNode.SESSION_EXPIRY_SAFETY_MARGIN_MS;
23568
24424
  if (sessionExpiry.getTime() <= Date.now() + marginMs) {
23569
- throw new import_sdk_core8.SessionExpiredError(sessionExpiry);
24425
+ throw new import_sdk_core9.SessionExpiredError(sessionExpiry);
23570
24426
  }
23571
24427
  }
23572
24428
  const expanded = this.expandPermissionEntries(permissions);
@@ -23642,7 +24498,7 @@ var _TinyCloudNode = class _TinyCloudNode {
23642
24498
  ...prepared,
23643
24499
  signature: signature2
23644
24500
  });
23645
- const activateResult = await (0, import_sdk_core8.activateSessionWithHost)(
24501
+ const activateResult = await (0, import_sdk_core9.activateSessionWithHost)(
23646
24502
  this.config.host,
23647
24503
  delegatedSession.delegationHeader
23648
24504
  );
@@ -23815,10 +24671,10 @@ var _TinyCloudNode = class _TinyCloudNode {
23815
24671
  throw new Error("Public space not enabled. Set enablePublicSpace: true in config.");
23816
24672
  }
23817
24673
  await this.auth.hostPublicSpace(publicSpaceId);
23818
- const kvActions = [import_sdk_core8.KV.PUT, import_sdk_core8.KV.GET, import_sdk_core8.KV.DEL, import_sdk_core8.KV.LIST, import_sdk_core8.KV.METADATA];
24674
+ const kvActions = [import_sdk_core9.KV.PUT, import_sdk_core9.KV.GET, import_sdk_core9.KV.DEL, import_sdk_core9.KV.LIST, import_sdk_core9.KV.METADATA];
23819
24675
  const abilities = { kv: { "": kvActions } };
23820
24676
  const now = /* @__PURE__ */ new Date();
23821
- const expiryMs = import_sdk_core8.EXPIRY.EPHEMERAL_MS;
24677
+ const expiryMs = import_sdk_core9.EXPIRY.EPHEMERAL_MS;
23822
24678
  const expirationTime = new Date(now.getTime() + expiryMs);
23823
24679
  const prepared = this.wasmBindings.prepareSession({
23824
24680
  abilities,
@@ -23836,7 +24692,7 @@ var _TinyCloudNode = class _TinyCloudNode {
23836
24692
  ...prepared,
23837
24693
  signature: signature2
23838
24694
  });
23839
- const activateResult = await (0, import_sdk_core8.activateSessionWithHost)(
24695
+ const activateResult = await (0, import_sdk_core9.activateSessionWithHost)(
23840
24696
  this.config.host,
23841
24697
  delegationSession.delegationHeader
23842
24698
  );
@@ -23866,8 +24722,8 @@ var _TinyCloudNode = class _TinyCloudNode {
23866
24722
  }]);
23867
24723
  }
23868
24724
  if (this._serviceContext) {
23869
- const publicKV = new import_sdk_core8.KVService({ prefix: "" });
23870
- const publicContext = this._serviceGraph.track(new import_sdk_core8.ServiceContext({
24725
+ const publicKV = new import_sdk_core9.KVService({ prefix: "" });
24726
+ const publicContext = this._serviceGraph.track(new import_sdk_core9.ServiceContext({
23871
24727
  invoke: this._serviceGraph.invoke,
23872
24728
  fetch: this._serviceGraph.fetch,
23873
24729
  hosts: this._serviceContext.hosts,
@@ -24019,14 +24875,14 @@ var _TinyCloudNode = class _TinyCloudNode {
24019
24875
  }
24020
24876
  const session = this.currentTinyCloudSession();
24021
24877
  if (!session) {
24022
- throw new import_sdk_core8.SessionExpiredError(/* @__PURE__ */ new Date(0));
24878
+ throw new import_sdk_core9.SessionExpiredError(/* @__PURE__ */ new Date(0));
24023
24879
  }
24024
24880
  const sessionExpiry = extractSiweExpiration(session.siwe);
24025
24881
  if (sessionExpiry !== void 0) {
24026
24882
  const now2 = Date.now();
24027
24883
  const marginMs = _TinyCloudNode.SESSION_EXPIRY_SAFETY_MARGIN_MS;
24028
24884
  if (sessionExpiry.getTime() <= now2 + marginMs) {
24029
- throw new import_sdk_core8.SessionExpiredError(sessionExpiry);
24885
+ throw new import_sdk_core9.SessionExpiredError(sessionExpiry);
24030
24886
  }
24031
24887
  }
24032
24888
  if (!Array.isArray(permissions) || permissions.length === 0) {
@@ -24056,31 +24912,31 @@ var _TinyCloudNode = class _TinyCloudNode {
24056
24912
  );
24057
24913
  return { delegation: delegation2, prompted: true };
24058
24914
  }
24059
- const granted = this.projectSignedRecapCapabilities(session.siwe);
24060
- const { subset, missing } = this.signedCapabilitySubset(expandedEntries, granted);
24061
- if (!subset) {
24062
- const runtimeOperations = this.permissionEntriesToOperations(expandedEntries, session);
24063
- const runtimeGrant = this.findGrantForOperations(
24064
- runtimeOperations,
24065
- { excludePrimary: true }
24066
- );
24067
- if (runtimeGrant) {
24068
- const marginMs = _TinyCloudNode.SESSION_EXPIRY_SAFETY_MARGIN_MS;
24069
- if (runtimeGrant.expiresAt.getTime() <= Date.now() + marginMs) {
24070
- throw new import_sdk_core8.SessionExpiredError(runtimeGrant.expiresAt);
24071
- }
24072
- const runtimeExpiration = runtimeGrant.expiresAt < effectiveExpiration ? runtimeGrant.expiresAt : effectiveExpiration;
24073
- const delegation2 = await this.createDelegationViaRuntimeGrant(
24074
- did,
24075
- expandedEntries,
24076
- runtimeExpiration,
24077
- runtimeGrant,
24078
- runtimeOperations,
24079
- onPrepared
24080
- );
24081
- return { delegation: delegation2, prompted: false };
24915
+ const plan = this.planDerivation(
24916
+ expandedEntries,
24917
+ session,
24918
+ effectiveExpiration,
24919
+ Date.now()
24920
+ );
24921
+ if ("refused" in plan) {
24922
+ if (plan.refused === "SESSION_EXPIRING") {
24923
+ throw new import_sdk_core9.SessionExpiredError(plan.expiredAt ?? sessionExpiry ?? /* @__PURE__ */ new Date(0));
24924
+ }
24925
+ if (plan.refused === "CAVEATED_AUTHORITY") {
24926
+ throw new import_sdk_core9.CaveatedDelegationUnsupportedError(plan.caveated ?? []);
24082
24927
  }
24083
- throw new import_sdk_core8.PermissionNotInManifestError(missing, granted);
24928
+ throw new import_sdk_core9.PermissionNotInManifestError(plan.missing ?? [], plan.granted ?? []);
24929
+ }
24930
+ if (plan.path === "runtime") {
24931
+ const delegation2 = await this.createDelegationViaRuntimeGrant(
24932
+ did,
24933
+ expandedEntries,
24934
+ plan.effectiveExpiration,
24935
+ plan.grant,
24936
+ plan.operations,
24937
+ onPrepared
24938
+ );
24939
+ return { delegation: delegation2, prompted: false };
24084
24940
  }
24085
24941
  const delegation = await this.createDelegationViaWasmPath(
24086
24942
  did,
@@ -24091,6 +24947,149 @@ var _TinyCloudNode = class _TinyCloudNode {
24091
24947
  );
24092
24948
  return { delegation, prompted: false };
24093
24949
  }
24950
+ /**
24951
+ * What `delegateTo` would select for `entries`, without signing or any
24952
+ * network call (TC-858 plan v3 §4.3): the session path when the signed
24953
+ * recap covers every entry, the runtime-grant path otherwise, or a
24954
+ * refusal. A refusal of `CAVEATED_AUTHORITY` means coverage exists only
24955
+ * through caveated branches, which the action-only WASM child-delegation
24956
+ * boundary cannot preserve — replication never derives authority through
24957
+ * them. `expiredAt`/`missing`/`granted`/`caveated` carry the payload
24958
+ * `delegateTo` turns back into its typed errors.
24959
+ * @internal
24960
+ */
24961
+ planDerivation(expandedEntries, session, effectiveExpiration, nowMs) {
24962
+ const caveatedRequest = expandedEntries.filter(
24963
+ (entry) => !(0, import_sdk_core9.recapCaveatsEqual)(entry.caveats, void 0)
24964
+ );
24965
+ if (caveatedRequest.length > 0) {
24966
+ return { refused: "CAVEATED_AUTHORITY", caveated: caveatedRequest };
24967
+ }
24968
+ const granted = this.projectSignedRecapCapabilities(session.siwe);
24969
+ const { subset, missing } = this.signedCapabilitySubset(expandedEntries, granted);
24970
+ if (subset) {
24971
+ return {
24972
+ path: "session",
24973
+ parentCid: session.delegationCid,
24974
+ expiresAt: effectiveExpiration.getTime(),
24975
+ effectiveExpiration
24976
+ };
24977
+ }
24978
+ const runtimeOperations = this.permissionEntriesToOperations(expandedEntries, session);
24979
+ const runtimeGrant = this.findGrantForOperations(
24980
+ runtimeOperations,
24981
+ { excludePrimary: true }
24982
+ );
24983
+ if (runtimeGrant) {
24984
+ const marginMs = _TinyCloudNode.SESSION_EXPIRY_SAFETY_MARGIN_MS;
24985
+ if (runtimeGrant.expiresAt.getTime() <= nowMs + marginMs) {
24986
+ return { refused: "SESSION_EXPIRING", expiredAt: runtimeGrant.expiresAt };
24987
+ }
24988
+ const caveated = this.caveatedRuntimeGrantEntries(
24989
+ expandedEntries,
24990
+ runtimeOperations,
24991
+ runtimeGrant
24992
+ );
24993
+ if (caveated.length > 0) {
24994
+ return { refused: "CAVEATED_AUTHORITY", caveated };
24995
+ }
24996
+ const runtimeExpiration = runtimeGrant.expiresAt < effectiveExpiration ? runtimeGrant.expiresAt : effectiveExpiration;
24997
+ return {
24998
+ path: "runtime",
24999
+ parentCid: runtimeGrant.session.delegationCid,
25000
+ expiresAt: runtimeExpiration.getTime(),
25001
+ effectiveExpiration: runtimeExpiration,
25002
+ grant: runtimeGrant,
25003
+ operations: runtimeOperations
25004
+ };
25005
+ }
25006
+ const relaxedGranted = granted.map((entry) => ({ ...entry, caveats: void 0 }));
25007
+ const relaxedRequested = expandedEntries.map((entry) => ({ ...entry, caveats: void 0 }));
25008
+ const relaxed = this.signedCapabilitySubset(relaxedRequested, relaxedGranted);
25009
+ if (relaxed.subset) {
25010
+ return {
25011
+ refused: "CAVEATED_AUTHORITY",
25012
+ caveated: missing.map((entry) => ({ ...entry, caveats: [{ via: "session-recap" }] }))
25013
+ };
25014
+ }
25015
+ return { refused: "NOT_COVERED", missing, granted };
25016
+ }
25017
+ /**
25018
+ * The plan `delegateTo(device, entries)` would follow, as a pure lookup:
25019
+ * no WASM sign and no `POST /delegate`. Backs
25020
+ * `ReplicationAuthority.plan` (and `mint` inside it) so a predicted
25021
+ * parent and expiry can never disagree with what a mint would use (§4.3,
25022
+ * §4.4). Session expiry inside the 60 s margin refuses with
25023
+ * `SESSION_EXPIRING`; the same check delegateTo performs.
25024
+ * @internal
25025
+ */
25026
+ planDelegation(entries, options) {
25027
+ if (!Array.isArray(entries) || entries.length === 0) {
25028
+ throw new Error("planDelegation requires a non-empty permissions array");
25029
+ }
25030
+ const session = this.currentTinyCloudSession();
25031
+ if (!session) {
25032
+ return { refused: "SESSION_EXPIRING", expiredAt: /* @__PURE__ */ new Date(0) };
25033
+ }
25034
+ const nowMs = Date.now();
25035
+ const sessionExpiry = extractSiweExpiration(session.siwe);
25036
+ if (sessionExpiry !== void 0 && sessionExpiry.getTime() <= nowMs + _TinyCloudNode.SESSION_EXPIRY_SAFETY_MARGIN_MS) {
25037
+ return { refused: "SESSION_EXPIRING", expiredAt: sessionExpiry };
25038
+ }
25039
+ const expandedEntries = this.expandPermissionEntries(entries);
25040
+ const expiryMs = resolveExpiryMs(options?.expiry);
25041
+ const expirationTime = new Date(nowMs + expiryMs);
25042
+ const effectiveExpiration = sessionExpiry !== void 0 && sessionExpiry < expirationTime ? sessionExpiry : expirationTime;
25043
+ return this.planDerivation(expandedEntries, session, effectiveExpiration, nowMs);
25044
+ }
25045
+ /**
25046
+ * The replication entries this node's sign-in request carries for the
25047
+ * current replication config and the signed-in or restored address: the
25048
+ * output of the same augmentation step `resolveSignInCapabilities` runs,
25049
+ * with the unrestricted-get and secrets gates applied (§4.1, §4.6).
25050
+ * Empty when replication is off or no address is known. Pure.
25051
+ */
25052
+ replicationSignInEntries() {
25053
+ if (this.config.replication?.enabled !== true) return [];
25054
+ const auth = this.auth;
25055
+ if (auth === void 0 || typeof auth.replicationSignInEntries !== "function") {
25056
+ return [];
25057
+ }
25058
+ return auth.replicationSignInEntries();
25059
+ }
25060
+ async replicationAuthority() {
25061
+ const { createReplicationAuthority: createReplicationAuthority2 } = await getNodeReplicationLoaders().authority();
25062
+ return createReplicationAuthority2({
25063
+ replicationSession: () => this.currentTinyCloudSession() ?? this.replicationDelegateSession,
25064
+ siweExpiration: (siwe) => extractSiweExpiration(siwe),
25065
+ planDelegation: (entries, options) => this.planDelegation(entries, options),
25066
+ mintDelegation: async (deviceDid, entries) => {
25067
+ const result = await this.delegateTo((0, import_sdk_core9.principalDid)(deviceDid), entries);
25068
+ return {
25069
+ ucan: result.delegation.delegationHeader.Authorization,
25070
+ expiresAt: result.delegation.expiry.getTime()
25071
+ };
25072
+ }
25073
+ });
25074
+ }
25075
+ async bindReplicationRuntime(context, session, kv, principal) {
25076
+ if (!this.replicationRuntime) return;
25077
+ const identityPrincipal = principal ?? (this._address === void 0 ? void 0 : (0, import_sdk_core9.pkhDid)(this._address, this._chainId));
25078
+ if (identityPrincipal === void 0) return;
25079
+ const runtime = await this.replicationRuntime;
25080
+ const authority = await this.replicationAuthority();
25081
+ await runtime.bind({
25082
+ context,
25083
+ session,
25084
+ principal: identityPrincipal,
25085
+ authority,
25086
+ primaryKV: [{ space: session.spaceId, kv }]
25087
+ });
25088
+ }
25089
+ /** Stable control facade for this node's optional replication runtime. */
25090
+ get replication() {
25091
+ return this.replicationControl;
25092
+ }
24094
25093
  /**
24095
25094
  * Materialize one manifest-declared delegation using the current session key.
24096
25095
  * Delivery is intentionally out of band; callers decide how to transmit the
@@ -24164,7 +25163,7 @@ var _TinyCloudNode = class _TinyCloudNode {
24164
25163
  const spaceId = resolvedSpaces.size === 1 ? [...resolvedSpaces][0] : session.spaceId;
24165
25164
  const abilities = {};
24166
25165
  for (const entry of entries) {
24167
- const shortService = import_sdk_core8.SERVICE_LONG_TO_SHORT[entry.service];
25166
+ const shortService = import_sdk_core9.SERVICE_LONG_TO_SHORT[entry.service];
24168
25167
  if (shortService === void 0) {
24169
25168
  throw new Error(
24170
25169
  `delegateTo: unknown service '${entry.service}' \u2014 no short-form mapping`
@@ -24221,7 +25220,7 @@ var _TinyCloudNode = class _TinyCloudNode {
24221
25220
  if (onPrepared) {
24222
25221
  await onPrepared(delegation);
24223
25222
  }
24224
- const activateResult = await (0, import_sdk_core8.activateSessionWithHost)(
25223
+ const activateResult = await (0, import_sdk_core9.activateSessionWithHost)(
24225
25224
  this.config.host,
24226
25225
  delegationHeader
24227
25226
  );
@@ -24263,7 +25262,7 @@ var _TinyCloudNode = class _TinyCloudNode {
24263
25262
  if (onPrepared) {
24264
25263
  await onPrepared(delegation);
24265
25264
  }
24266
- const activateResult = await (0, import_sdk_core8.activateSessionWithHost)(
25265
+ const activateResult = await (0, import_sdk_core9.activateSessionWithHost)(
24267
25266
  targetHost,
24268
25267
  delegationHeader
24269
25268
  );
@@ -24292,7 +25291,7 @@ var _TinyCloudNode = class _TinyCloudNode {
24292
25291
  return this.wasmBindings.makeSpaceId(session.address, session.chainId, space);
24293
25292
  }
24294
25293
  expandPermissionEntries(permissions) {
24295
- return (0, import_sdk_core8.expandPermissionEntries)(permissions);
25294
+ return (0, import_sdk_core9.expandPermissionEntries)(permissions);
24296
25295
  }
24297
25296
  /**
24298
25297
  * The current WASM child-delegation APIs accept action-only maps. Refuse any
@@ -24300,10 +25299,10 @@ var _TinyCloudNode = class _TinyCloudNode {
24300
25299
  */
24301
25300
  assertDelegationCaveatsPreservable(entries) {
24302
25301
  const caveated = entries.filter(
24303
- (entry) => !(0, import_sdk_core8.recapCaveatsEqual)(entry.caveats, void 0)
25302
+ (entry) => !(0, import_sdk_core9.recapCaveatsEqual)(entry.caveats, void 0)
24304
25303
  );
24305
25304
  if (caveated.length > 0) {
24306
- throw new import_sdk_core8.CaveatedDelegationUnsupportedError(caveated);
25305
+ throw new import_sdk_core9.CaveatedDelegationUnsupportedError(caveated);
24307
25306
  }
24308
25307
  }
24309
25308
  /**
@@ -24313,6 +25312,18 @@ var _TinyCloudNode = class _TinyCloudNode {
24313
25312
  * it only accepts action maps, so reject the selected constrained branch.
24314
25313
  */
24315
25314
  assertRuntimeGrantCaveatsPreservable(entries, requestedOperations, grant) {
25315
+ const caveated = this.caveatedRuntimeGrantEntries(entries, requestedOperations, grant);
25316
+ if (caveated.length > 0) {
25317
+ throw new import_sdk_core9.CaveatedDelegationUnsupportedError(caveated);
25318
+ }
25319
+ }
25320
+ /**
25321
+ * The entries of `grant` that cover a requested operation while carrying
25322
+ * caveats — the branches {@link assertRuntimeGrantCaveatsPreservable}
25323
+ * rejects and {@link planDerivation} classifies as `CAVEATED_AUTHORITY`.
25324
+ * Shared so the pure plan and the mint path can't disagree.
25325
+ */
25326
+ caveatedRuntimeGrantEntries(entries, requestedOperations, grant) {
24316
25327
  let operationIndex = 0;
24317
25328
  const caveated = [];
24318
25329
  for (const entry of entries) {
@@ -24320,7 +25331,7 @@ var _TinyCloudNode = class _TinyCloudNode {
24320
25331
  const requested = requestedOperations[operationIndex++];
24321
25332
  if (!requested) continue;
24322
25333
  const constrained = grant.operations.find(
24323
- (granted) => this.operationCovers(granted, requested) && !(0, import_sdk_core8.recapCaveatsEqual)(granted.caveats, void 0)
25334
+ (granted) => this.operationCovers(granted, requested) && !(0, import_sdk_core9.recapCaveatsEqual)(granted.caveats, void 0)
24324
25335
  );
24325
25336
  if (constrained) {
24326
25337
  caveated.push({
@@ -24331,15 +25342,13 @@ var _TinyCloudNode = class _TinyCloudNode {
24331
25342
  }
24332
25343
  }
24333
25344
  }
24334
- if (caveated.length > 0) {
24335
- throw new import_sdk_core8.CaveatedDelegationUnsupportedError(caveated);
24336
- }
25345
+ return caveated;
24337
25346
  }
24338
25347
  /** Reject caveated parent branches before action-only child signing. */
24339
25348
  assertPortableDelegationCaveatsPreservable(delegation) {
24340
25349
  const entries = [];
24341
25350
  const add3 = (service, space, path, actions, caveats) => {
24342
- if ((0, import_sdk_core8.recapCaveatsEqual)(caveats, void 0)) return;
25351
+ if ((0, import_sdk_core9.recapCaveatsEqual)(caveats, void 0)) return;
24343
25352
  entries.push({
24344
25353
  service: service.startsWith("tinycloud.") ? service : `tinycloud.${service}`,
24345
25354
  space,
@@ -24359,11 +25368,11 @@ var _TinyCloudNode = class _TinyCloudNode {
24359
25368
  add3(resource.service, resource.space, resource.path, resource.actions, resource.caveats);
24360
25369
  }
24361
25370
  if (entries.length > 0) {
24362
- throw new import_sdk_core8.CaveatedDelegationUnsupportedError(entries);
25371
+ throw new import_sdk_core9.CaveatedDelegationUnsupportedError(entries);
24363
25372
  }
24364
25373
  }
24365
25374
  shortServiceName(service) {
24366
- const short = import_sdk_core8.SERVICE_LONG_TO_SHORT[service];
25375
+ const short = import_sdk_core9.SERVICE_LONG_TO_SHORT[service];
24367
25376
  if (short === void 0) {
24368
25377
  throw new Error(
24369
25378
  `unknown service '${service}' \u2014 no short-form mapping`
@@ -24390,7 +25399,7 @@ var _TinyCloudNode = class _TinyCloudNode {
24390
25399
  return abilities;
24391
25400
  }
24392
25401
  isEncryptionPermissionEntry(entry) {
24393
- return entry.service === import_sdk_core8.ENCRYPTION_PERMISSION_SERVICE && this.isEncryptionNetworkOperation("encryption", entry.path, entry.space);
25402
+ return entry.service === import_sdk_core9.ENCRYPTION_PERMISSION_SERVICE && this.isEncryptionNetworkOperation("encryption", entry.path, entry.space);
24394
25403
  }
24395
25404
  isRawRevocationPermissionEntry(entry) {
24396
25405
  return entry.service === "tinycloud.delegation" && entry.path === "" && entry.space?.startsWith("urn:cid:") === true && entry.actions.includes("tinycloud.delegation/revoke");
@@ -24438,7 +25447,7 @@ var _TinyCloudNode = class _TinyCloudNode {
24438
25447
  const missing = requested.filter((entry) => {
24439
25448
  const raw = this.isEncryptionPermissionEntry(entry) || this.isRawRevocationPermissionEntry(entry);
24440
25449
  const comparable = raw && this.isEncryptionPermissionEntry(entry) ? { ...entry, space: "encryption" } : entry;
24441
- return !(0, import_sdk_core8.isCapabilitySubset)([comparable], raw ? rawGranted : spaceGranted).subset;
25450
+ return !(0, import_sdk_core9.isCapabilitySubset)([comparable], raw ? rawGranted : spaceGranted).subset;
24442
25451
  });
24443
25452
  return { subset: missing.length === 0, missing };
24444
25453
  }
@@ -24674,7 +25683,7 @@ var _TinyCloudNode = class _TinyCloudNode {
24674
25683
  if (granted.service !== requested.service || !this.actionContains(granted.action, requested.action)) {
24675
25684
  return false;
24676
25685
  }
24677
- if (requested.caveats !== void 0 && !(0, import_sdk_core8.recapCaveatsEqual)(granted.caveats, requested.caveats)) {
25686
+ if (requested.caveats !== void 0 && !(0, import_sdk_core9.recapCaveatsEqual)(granted.caveats, requested.caveats)) {
24678
25687
  return false;
24679
25688
  }
24680
25689
  if (granted.resource !== void 0 || requested.resource !== void 0) {
@@ -24696,7 +25705,7 @@ var _TinyCloudNode = class _TinyCloudNode {
24696
25705
  if (grantedAction === requestedAction) {
24697
25706
  return true;
24698
25707
  }
24699
- if ((0, import_sdk_core8.isExplicitOnlyAction)(requestedAction)) {
25708
+ if ((0, import_sdk_core9.isExplicitOnlyAction)(requestedAction)) {
24700
25709
  return false;
24701
25710
  }
24702
25711
  if (grantedAction.endsWith("/*")) {
@@ -24808,7 +25817,7 @@ var _TinyCloudNode = class _TinyCloudNode {
24808
25817
  if (resolvedDelegateDID.endsWith(".eth") && this.config.ensResolver) {
24809
25818
  const address = await this.config.ensResolver.resolveAddress(resolvedDelegateDID);
24810
25819
  if (!address) throw new Error(`Could not resolve ENS name: ${resolvedDelegateDID}`);
24811
- resolvedDelegateDID = (0, import_sdk_core8.pkhDid)(address, 1);
25820
+ resolvedDelegateDID = (0, import_sdk_core9.pkhDid)(address, 1);
24812
25821
  }
24813
25822
  const entries = legacyParamsToPermissionEntries(
24814
25823
  params.actions,
@@ -24823,7 +25832,7 @@ var _TinyCloudNode = class _TinyCloudNode {
24823
25832
  );
24824
25833
  return result.delegation;
24825
25834
  } catch (err) {
24826
- if (err instanceof import_sdk_core8.PermissionNotInManifestError) {
25835
+ if (err instanceof import_sdk_core9.PermissionNotInManifestError) {
24827
25836
  } else {
24828
25837
  throw err;
24829
25838
  }
@@ -24880,7 +25889,7 @@ var _TinyCloudNode = class _TinyCloudNode {
24880
25889
  ...prepared,
24881
25890
  signature: signature2
24882
25891
  });
24883
- const activateResult = await (0, import_sdk_core8.activateSessionWithHost)(
25892
+ const activateResult = await (0, import_sdk_core9.activateSessionWithHost)(
24884
25893
  this.config.host,
24885
25894
  delegationSession.delegationHeader
24886
25895
  );
@@ -24905,12 +25914,12 @@ var _TinyCloudNode = class _TinyCloudNode {
24905
25914
  };
24906
25915
  const hasKvActions = params.actions.some((a) => a.startsWith("tinycloud.kv/"));
24907
25916
  if (hasKvActions && params.includePublicSpace !== false) {
24908
- const publicSpaceId = (0, import_sdk_core8.makePublicSpaceId)(
25917
+ const publicSpaceId = (0, import_sdk_core9.makePublicSpaceId)(
24909
25918
  this.wasmBindings.ensureEip55(session.address),
24910
25919
  session.chainId
24911
25920
  );
24912
25921
  const publicAbilities = {
24913
- kv: { "": [import_sdk_core8.KV.GET, import_sdk_core8.KV.PUT, import_sdk_core8.KV.METADATA] }
25922
+ kv: { "": [import_sdk_core9.KV.GET, import_sdk_core9.KV.PUT, import_sdk_core9.KV.METADATA] }
24914
25923
  };
24915
25924
  const publicPrepared = this.wasmBindings.prepareSession({
24916
25925
  abilities: publicAbilities,
@@ -24928,7 +25937,7 @@ var _TinyCloudNode = class _TinyCloudNode {
24928
25937
  ...publicPrepared,
24929
25938
  signature: publicSignature
24930
25939
  });
24931
- const publicActivateResult = await (0, import_sdk_core8.activateSessionWithHost)(
25940
+ const publicActivateResult = await (0, import_sdk_core9.activateSessionWithHost)(
24932
25941
  this.config.host,
24933
25942
  publicSession.delegationHeader
24934
25943
  );
@@ -24938,7 +25947,7 @@ var _TinyCloudNode = class _TinyCloudNode {
24938
25947
  delegationHeader: publicSession.delegationHeader,
24939
25948
  spaceId: publicSpaceId,
24940
25949
  path: "",
24941
- actions: [import_sdk_core8.KV.GET, import_sdk_core8.KV.PUT, import_sdk_core8.KV.METADATA],
25950
+ actions: [import_sdk_core9.KV.GET, import_sdk_core9.KV.PUT, import_sdk_core9.KV.METADATA],
24942
25951
  disableSubDelegation: params.disableSubDelegation ?? false,
24943
25952
  expiry: expirationTime,
24944
25953
  delegateDID: params.delegateDID,
@@ -25033,7 +26042,7 @@ var _TinyCloudNode = class _TinyCloudNode {
25033
26042
  ...prepared,
25034
26043
  signature: signature2
25035
26044
  });
25036
- const activateResult = await (0, import_sdk_core8.activateSessionWithHost)(
26045
+ const activateResult = await (0, import_sdk_core9.activateSessionWithHost)(
25037
26046
  targetHost,
25038
26047
  invokerSession.delegationHeader
25039
26048
  );
@@ -25153,7 +26162,7 @@ var _TinyCloudNode = class _TinyCloudNode {
25153
26162
  ...prepared,
25154
26163
  signature: signature2
25155
26164
  });
25156
- const activateResult = await (0, import_sdk_core8.activateSessionWithHost)(
26165
+ const activateResult = await (0, import_sdk_core9.activateSessionWithHost)(
25157
26166
  targetHost,
25158
26167
  subDelegationSession.delegationHeader
25159
26168
  );
@@ -25203,12 +26212,18 @@ TinyCloudNode.registerNodeDefaults({
25203
26212
  createSigner: (privateKey, chainId) => new PrivateKeySigner(privateKey, chainId)
25204
26213
  });
25205
26214
 
26215
+ // src/replication/node-loader.ts
26216
+ registerReplicationLoaders({
26217
+ runtime: () => Promise.resolve().then(() => (init_runtime(), runtime_exports)),
26218
+ authority: () => Promise.resolve().then(() => (init_authority(), authority_exports))
26219
+ });
26220
+
25206
26221
  // src/index.ts
25207
- var import_sdk_core10 = require("@tinycloud/sdk-core");
25208
- var import_sdk_core11 = require("@tinycloud/sdk-core");
26222
+ var import_sdk_core14 = require("@tinycloud/sdk-core");
26223
+ var import_sdk_core15 = require("@tinycloud/sdk-core");
25209
26224
 
25210
26225
  // src/storage/FileSessionStorage.ts
25211
- var import_sdk_core9 = require("@tinycloud/sdk-core");
26226
+ var import_sdk_core12 = require("@tinycloud/sdk-core");
25212
26227
  var import_fs = require("fs");
25213
26228
  var import_path = require("path");
25214
26229
  var FileSessionStorage = class {
@@ -25263,7 +26278,7 @@ var FileSessionStorage = class {
25263
26278
  try {
25264
26279
  const data = (0, import_fs.readFileSync)(filePath, "utf-8");
25265
26280
  const parsed = JSON.parse(data);
25266
- const validation = (0, import_sdk_core9.validatePersistedSessionData)(parsed);
26281
+ const validation = (0, import_sdk_core12.validatePersistedSessionData)(parsed);
25267
26282
  if (!validation.ok) {
25268
26283
  console.warn(`Invalid session data for ${address}:`, validation.error.message);
25269
26284
  (0, import_fs.unlinkSync)(filePath);
@@ -25372,10 +26387,6 @@ function wireOpenKeyAuthorize(openkey) {
25372
26387
  }
25373
26388
 
25374
26389
  // src/index.ts
25375
- var import_sdk_core12 = require("@tinycloud/sdk-core");
25376
- var import_sdk_core13 = require("@tinycloud/sdk-core");
25377
- var import_sdk_core14 = require("@tinycloud/sdk-core");
25378
- var import_sdk_core15 = require("@tinycloud/sdk-core");
25379
26390
  var import_sdk_core16 = require("@tinycloud/sdk-core");
25380
26391
  var import_sdk_core17 = require("@tinycloud/sdk-core");
25381
26392
  var import_sdk_core18 = require("@tinycloud/sdk-core");
@@ -25384,6 +26395,848 @@ var import_sdk_core20 = require("@tinycloud/sdk-core");
25384
26395
  var import_sdk_core21 = require("@tinycloud/sdk-core");
25385
26396
  var import_sdk_core22 = require("@tinycloud/sdk-core");
25386
26397
  var import_sdk_core23 = require("@tinycloud/sdk-core");
26398
+ var import_sdk_core24 = require("@tinycloud/sdk-core");
26399
+ var import_sdk_core25 = require("@tinycloud/sdk-core");
26400
+ var import_sdk_core26 = require("@tinycloud/sdk-core");
26401
+ var import_sdk_core27 = require("@tinycloud/sdk-core");
26402
+
26403
+ // src/replication/sqlite.ts
26404
+ var import_node_crypto2 = require("crypto");
26405
+ var import_promises = require("fs/promises");
26406
+ var import_node_path = require("path");
26407
+ var import_sdk_core13 = require("@tinycloud/sdk-core");
26408
+ var import_sdk_services4 = require("@tinycloud/sdk-services");
26409
+ init_authority();
26410
+ var ReplicaStorageError = class extends Error {
26411
+ constructor(code, message, options) {
26412
+ super(message);
26413
+ this.name = "ReplicaStorageError";
26414
+ this.code = code;
26415
+ this.cause = options?.cause;
26416
+ }
26417
+ };
26418
+ function storageError(code, action, error) {
26419
+ if (error instanceof ReplicaStorageError) return error;
26420
+ const detail = error instanceof Error ? error.message : String(error);
26421
+ return new ReplicaStorageError(code, `${action} failed: ${detail}`, { cause: error });
26422
+ }
26423
+ function isNotFound(error) {
26424
+ return typeof error === "object" && error !== null && "code" in error && error.code === "ENOENT";
26425
+ }
26426
+ async function pathExists(path) {
26427
+ try {
26428
+ await (0, import_promises.stat)(path);
26429
+ return true;
26430
+ } catch (error) {
26431
+ if (isNotFound(error)) return false;
26432
+ throw storageError("STORAGE_ERROR", `Reading ${path}`, error);
26433
+ }
26434
+ }
26435
+ function principalOf(did) {
26436
+ return (0, import_sdk_core13.principalDid)(did);
26437
+ }
26438
+ var BASE32 = "abcdefghijklmnopqrstuvwxyz234567";
26439
+ function sha256Base32(material) {
26440
+ const digest = (0, import_node_crypto2.createHash)("sha256").update(material, "utf8").digest();
26441
+ let out = "";
26442
+ let buffer = 0;
26443
+ let bits = 0;
26444
+ for (const byte of digest) {
26445
+ buffer = buffer << 8 | byte;
26446
+ bits += 8;
26447
+ while (bits >= 5) {
26448
+ out += BASE32[buffer >>> bits - 5 & 31];
26449
+ bits -= 5;
26450
+ }
26451
+ }
26452
+ if (bits > 0) out += BASE32[buffer << 5 - bits & 31];
26453
+ return out.slice(0, 26);
26454
+ }
26455
+ function partitionDirOf(root, identity) {
26456
+ return (0, import_node_path.join)(root, sha256Base32((0, import_sdk_services4.replicationIdentityKey)(identity)));
26457
+ }
26458
+ function replicaHashOf(prefix, deviceDid) {
26459
+ return sha256Base32(`${prefix}
26460
+ ${principalOf(deviceDid)}`);
26461
+ }
26462
+ async function writeJsonAtomic(path, value, dirSync = fsyncDir) {
26463
+ const tmp = `${path}.${(0, import_node_crypto2.randomBytes)(6).toString("hex")}.tmp`;
26464
+ let handle;
26465
+ try {
26466
+ handle = await (0, import_promises.open)(tmp, "w", 384);
26467
+ await handle.writeFile(JSON.stringify(value), "utf8");
26468
+ await handle.sync();
26469
+ await handle.close();
26470
+ await (0, import_promises.rename)(tmp, path);
26471
+ await dirSync((0, import_node_path.dirname)(path));
26472
+ await (0, import_promises.chmod)(path, 384).catch(() => void 0);
26473
+ } catch (error) {
26474
+ try {
26475
+ await handle?.close();
26476
+ } catch {
26477
+ }
26478
+ await (0, import_promises.rm)(tmp, { force: true }).catch(() => void 0);
26479
+ throw storageError("STORAGE_ERROR", `Writing ${path}`, error);
26480
+ }
26481
+ }
26482
+ var DIR_SYNC_UNSUPPORTED = {
26483
+ ENOTSUP: true,
26484
+ ENOSYS: true,
26485
+ EINVAL: true,
26486
+ EISDIR: true,
26487
+ EPERM: true
26488
+ };
26489
+ async function fsyncDir(dir) {
26490
+ let handle;
26491
+ try {
26492
+ handle = await (0, import_promises.open)(dir, "r");
26493
+ await handle.sync();
26494
+ } catch (error) {
26495
+ const code = typeof error === "object" && error !== null && "code" in error ? error.code : void 0;
26496
+ if (typeof code === "string" && DIR_SYNC_UNSUPPORTED[code] === true) return;
26497
+ throw storageError("STORAGE_ERROR", `Syncing ${dir}`, error);
26498
+ } finally {
26499
+ await handle?.close().catch(() => void 0);
26500
+ }
26501
+ }
26502
+ async function readJsonFile(path) {
26503
+ try {
26504
+ return JSON.parse(await (0, import_promises.readFile)(path, "utf8"));
26505
+ } catch (error) {
26506
+ if (isNotFound(error)) return void 0;
26507
+ throw storageError("STORAGE_ERROR", `Reading ${path}`, error);
26508
+ }
26509
+ }
26510
+ function identityRecordOf(value) {
26511
+ if (value === null || typeof value !== "object" || Array.isArray(value)) {
26512
+ return void 0;
26513
+ }
26514
+ if (!("host" in value) || !("space" in value) || !("principal" in value) || typeof value.host !== "string" || typeof value.space !== "string" || typeof value.principal !== "string") {
26515
+ return void 0;
26516
+ }
26517
+ return { host: value.host, space: value.space, principal: value.principal };
26518
+ }
26519
+ function deviceRecordOf(value) {
26520
+ if (value === null || typeof value !== "object" || Array.isArray(value)) {
26521
+ return void 0;
26522
+ }
26523
+ if (!("did" in value) || !("jwk" in value) || typeof value.did !== "string" || value.jwk === null || typeof value.jwk !== "object") {
26524
+ return void 0;
26525
+ }
26526
+ return { did: value.did, jwk: value.jwk };
26527
+ }
26528
+ function sameIdentity(a, b) {
26529
+ try {
26530
+ const left = (0, import_sdk_services4.canonicalReplicationIdentity)(a);
26531
+ const right = (0, import_sdk_services4.canonicalReplicationIdentity)(b);
26532
+ return left.host === right.host && left.space === right.space && left.principal === right.principal;
26533
+ } catch {
26534
+ return false;
26535
+ }
26536
+ }
26537
+ async function ensurePartitionIdentity(dir, identity, dirSync) {
26538
+ try {
26539
+ await (0, import_promises.mkdir)(dir, { recursive: true, mode: 448 });
26540
+ await (0, import_promises.chmod)(dir, 448);
26541
+ } catch (error) {
26542
+ throw storageError("STORAGE_ERROR", `Creating ${dir}`, error);
26543
+ }
26544
+ const file = (0, import_node_path.join)(dir, "identity.json");
26545
+ const existing = await readJsonFile(file);
26546
+ if (existing === void 0) {
26547
+ await writeJsonAtomic(file, { v: 1, ...(0, import_sdk_services4.canonicalReplicationIdentity)(identity) }, dirSync);
26548
+ return;
26549
+ }
26550
+ const record = identityRecordOf(existing);
26551
+ if (record === void 0 || !sameIdentity(record, identity)) {
26552
+ throw new ReplicaStorageError(
26553
+ "STORAGE_ERROR",
26554
+ `The partition at ${dir} belongs to a different identity.`
26555
+ );
26556
+ }
26557
+ }
26558
+ var PENDING_WRITE_LOCKS = /* @__PURE__ */ new Map();
26559
+ function serializePendingWrite(file, section) {
26560
+ const tail = PENDING_WRITE_LOCKS.get(file) ?? Promise.resolve();
26561
+ const entered = tail.then(section);
26562
+ const next = entered.then(
26563
+ () => void 0,
26564
+ () => void 0
26565
+ );
26566
+ PENDING_WRITE_LOCKS.set(file, next);
26567
+ void next.then(() => {
26568
+ if (PENDING_WRITE_LOCKS.get(file) === next) PENDING_WRITE_LOCKS.delete(file);
26569
+ });
26570
+ return entered;
26571
+ }
26572
+ function parsePendingState(text, file, identity) {
26573
+ let state;
26574
+ try {
26575
+ state = JSON.parse(text);
26576
+ } catch (error) {
26577
+ throw storageError("STORAGE_ERROR", `Parsing ${file}`, error);
26578
+ }
26579
+ if (state === null || typeof state !== "object" || !("v" in state) || state.v !== 2 || !("identity" in state) || !("committedEpoch" in state) || typeof state.committedEpoch !== "number" || !("seq" in state) || typeof state.seq !== "number" || !("records" in state) || !Array.isArray(state.records)) {
26580
+ throw new ReplicaStorageError("STORAGE_ERROR", `Pending-write state at ${file} is corrupt.`);
26581
+ }
26582
+ const storedIdentity = identityRecordOf(state.identity);
26583
+ if (storedIdentity === void 0 || !sameIdentity(storedIdentity, identity)) {
26584
+ throw new ReplicaStorageError("STORAGE_ERROR", `Pending-write state at ${file} belongs to a different identity.`);
26585
+ }
26586
+ return state;
26587
+ }
26588
+ var _dir, _guard, _dirSync, _file, _FilePendingWriteStore_instances, canonicalFile_fn;
26589
+ var FilePendingWriteStore = class {
26590
+ constructor(identity, dir, guard, dirSync) {
26591
+ __privateAdd(this, _FilePendingWriteStore_instances);
26592
+ this.durable = true;
26593
+ __privateAdd(this, _dir);
26594
+ __privateAdd(this, _guard);
26595
+ __privateAdd(this, _dirSync);
26596
+ __privateAdd(this, _file);
26597
+ this.identity = identity;
26598
+ __privateSet(this, _dir, dir);
26599
+ __privateSet(this, _guard, guard);
26600
+ __privateSet(this, _dirSync, dirSync);
26601
+ }
26602
+ async read() {
26603
+ const file = await __privateMethod(this, _FilePendingWriteStore_instances, canonicalFile_fn).call(this);
26604
+ let text;
26605
+ try {
26606
+ text = await (0, import_promises.readFile)(file, "utf8");
26607
+ } catch (error) {
26608
+ if (isNotFound(error)) {
26609
+ return { v: 2, identity: this.identity, committedEpoch: 0, seq: 0, records: [] };
26610
+ }
26611
+ throw storageError("STORAGE_ERROR", `Reading ${file}`, error);
26612
+ }
26613
+ return parsePendingState(text, file, this.identity);
26614
+ }
26615
+ async readExisting() {
26616
+ let file;
26617
+ try {
26618
+ file = (0, import_node_path.join)(await (0, import_promises.realpath)(__privateGet(this, _dir)), "pending.json");
26619
+ } catch (error) {
26620
+ if (isNotFound(error)) return void 0;
26621
+ throw storageError("STORAGE_ERROR", `Resolving pending-write state in ${__privateGet(this, _dir)}`, error);
26622
+ }
26623
+ try {
26624
+ const text = await (0, import_promises.readFile)(file, "utf8");
26625
+ return parsePendingState(text, file, this.identity);
26626
+ } catch (error) {
26627
+ if (isNotFound(error)) return void 0;
26628
+ if (error instanceof ReplicaStorageError) throw error;
26629
+ throw storageError("STORAGE_ERROR", `Reading ${file}`, error);
26630
+ }
26631
+ }
26632
+ async update(mutate) {
26633
+ const file = await __privateMethod(this, _FilePendingWriteStore_instances, canonicalFile_fn).call(this);
26634
+ return serializePendingWrite(file, async () => {
26635
+ let currentFile;
26636
+ try {
26637
+ currentFile = (0, import_node_path.join)(await (0, import_promises.realpath)((0, import_node_path.dirname)(file)), (0, import_node_path.basename)(file));
26638
+ } catch (error) {
26639
+ throw storageError("STORAGE_ERROR", "Resolving the open pending-write partition", error);
26640
+ }
26641
+ if (currentFile !== file) {
26642
+ throw new ReplicaStorageError(
26643
+ "STORAGE_ERROR",
26644
+ `The pending-write partition changed while open: ${(0, import_node_path.dirname)(file)}.`
26645
+ );
26646
+ }
26647
+ return __privateGet(this, _guard).call(this, async () => {
26648
+ const state = await this.read();
26649
+ const result = mutate(state);
26650
+ await writeJsonAtomic(file, state, __privateGet(this, _dirSync));
26651
+ return result;
26652
+ });
26653
+ });
26654
+ }
26655
+ };
26656
+ _dir = new WeakMap();
26657
+ _guard = new WeakMap();
26658
+ _dirSync = new WeakMap();
26659
+ _file = new WeakMap();
26660
+ _FilePendingWriteStore_instances = new WeakSet();
26661
+ canonicalFile_fn = async function() {
26662
+ __privateGet(this, _file) ?? __privateSet(this, _file, (async () => {
26663
+ await ensurePartitionIdentity(__privateGet(this, _dir), this.identity, __privateGet(this, _dirSync));
26664
+ const file = (0, import_node_path.join)(__privateGet(this, _dir), "pending.json");
26665
+ try {
26666
+ return (0, import_node_path.join)(await (0, import_promises.realpath)((0, import_node_path.dirname)(file)), (0, import_node_path.basename)(file));
26667
+ } catch (error) {
26668
+ throw storageError("STORAGE_ERROR", `Resolving ${file}`, error);
26669
+ }
26670
+ })());
26671
+ return __privateGet(this, _file);
26672
+ };
26673
+ async function loadOrCreateDevice(idDir, guard, createDevice, dirSync) {
26674
+ return guard(async () => {
26675
+ try {
26676
+ await (0, import_promises.mkdir)(idDir, { recursive: true, mode: 448 });
26677
+ await (0, import_promises.chmod)(idDir, 448);
26678
+ } catch (error) {
26679
+ throw storageError("STORAGE_ERROR", `Creating ${idDir}`, error);
26680
+ }
26681
+ const file = (0, import_node_path.join)(idDir, "device.jwk");
26682
+ const existing = await readJsonFile(file);
26683
+ if (existing !== void 0) {
26684
+ const device2 = deviceRecordOf(existing);
26685
+ if (device2 === void 0) {
26686
+ throw new ReplicaStorageError(
26687
+ "STORAGE_ERROR",
26688
+ `The replica device key at ${file} is unreadable; remove the partition or restore it.`
26689
+ );
26690
+ }
26691
+ return device2;
26692
+ }
26693
+ const device = await createDevice();
26694
+ await writeJsonAtomic(file, { did: device.did, jwk: device.jwk }, dirSync);
26695
+ return device;
26696
+ });
26697
+ }
26698
+ async function createDeviceKey() {
26699
+ const wasm = await import("@tinycloud/node-sdk-wasm");
26700
+ const manager = new wasm.TCWSessionManager();
26701
+ const keyId = manager.createSessionKey("replica-device") ?? "replica-device";
26702
+ const jwkText = manager.jwk(keyId);
26703
+ if (jwkText === null || jwkText === void 0) {
26704
+ throw new ReplicaStorageError(
26705
+ "STORAGE_ERROR",
26706
+ "The session manager returned no JWK for the replica device key."
26707
+ );
26708
+ }
26709
+ return { did: manager.getDID(keyId), jwk: JSON.parse(jwkText) };
26710
+ }
26711
+ var SYNC_LEASE_TTL_MS = 12e4;
26712
+ var FENCE_FILE = "fence.json";
26713
+ async function readFence(replicaDir) {
26714
+ const fence = await readJsonFile((0, import_node_path.join)(replicaDir, FENCE_FILE));
26715
+ return typeof fence === "object" && fence !== null && "syncedThroughEpoch" in fence && typeof fence.syncedThroughEpoch === "number" ? fence.syncedThroughEpoch : 0;
26716
+ }
26717
+ function newestGrantInfo(replica, record, pending, spec) {
26718
+ if (record === null) return null;
26719
+ const parsed = replica.parseUcanGrant(record.bytes);
26720
+ return {
26721
+ cid: record.cid,
26722
+ parentCid: parsed.prf[0] ?? null,
26723
+ expiresAt: record.expiresAt === null ? null : record.expiresAt * 1e3,
26724
+ state: pending !== null && record === pending ? "pending" : "active",
26725
+ unconstrained: ucanAttUnconstrainedFor(parsed.att, spec.space, spec.prefix)
26726
+ };
26727
+ }
26728
+ var _device, _store, _replicaDir, _replica, _guard2, _dirSync2, _generation, _ino, _transportOverride, _closed, _inFlight, _transportFactory, _SqliteReplicaHandle_instances, assertOpen_fn, assertLive_fn, transports_fn;
26729
+ var SqliteReplicaHandle = class {
26730
+ constructor(input) {
26731
+ __privateAdd(this, _SqliteReplicaHandle_instances);
26732
+ __privateAdd(this, _device);
26733
+ __privateAdd(this, _store);
26734
+ __privateAdd(this, _replicaDir);
26735
+ __privateAdd(this, _replica);
26736
+ __privateAdd(this, _guard2);
26737
+ __privateAdd(this, _dirSync2);
26738
+ /** The replica row generation this handle opened under — the durable fence a purge commits past (browser-parity wipe). */
26739
+ __privateAdd(this, _generation);
26740
+ /** The inode of `replica.db` at open — a directory recreated in place is a different replica. */
26741
+ __privateAdd(this, _ino);
26742
+ __privateAdd(this, _transportOverride);
26743
+ __privateAdd(this, _closed, false);
26744
+ __privateAdd(this, _inFlight, /* @__PURE__ */ new Set());
26745
+ __privateAdd(this, _transportFactory);
26746
+ this.spec = input.spec;
26747
+ __privateSet(this, _device, input.device);
26748
+ this.deviceDid = input.device.did;
26749
+ __privateSet(this, _store, input.store);
26750
+ __privateSet(this, _replicaDir, input.replicaDir);
26751
+ __privateSet(this, _replica, input.replica);
26752
+ __privateSet(this, _guard2, input.guard);
26753
+ __privateSet(this, _transportOverride, input.transportFor);
26754
+ __privateSet(this, _dirSync2, input.dirSync);
26755
+ __privateSet(this, _generation, input.generation);
26756
+ __privateSet(this, _ino, input.ino);
26757
+ }
26758
+ async get(key2) {
26759
+ await __privateMethod(this, _SqliteReplicaHandle_instances, assertLive_fn).call(this);
26760
+ const result = await new (__privateGet(this, _replica)).Replica({ store: __privateGet(this, _store) }).get(key2);
26761
+ const meta = {
26762
+ asOf: result.meta.asOf,
26763
+ coverage: result.meta.coverage,
26764
+ authority: result.meta.authority,
26765
+ syncedThroughEpoch: await readFence(__privateGet(this, _replicaDir))
26766
+ };
26767
+ switch (result.status) {
26768
+ case "present":
26769
+ return {
26770
+ status: "present",
26771
+ key: result.key,
26772
+ value: result.value,
26773
+ etag: result.etag,
26774
+ metadata: result.metadata,
26775
+ meta
26776
+ };
26777
+ case "content_missing":
26778
+ return {
26779
+ status: "content_missing",
26780
+ key: result.key,
26781
+ etag: result.etag,
26782
+ metadata: result.metadata,
26783
+ meta
26784
+ };
26785
+ default:
26786
+ return { status: result.status, key: result.key, meta };
26787
+ }
26788
+ }
26789
+ async list(options) {
26790
+ await __privateMethod(this, _SqliteReplicaHandle_instances, assertLive_fn).call(this);
26791
+ const result = await new (__privateGet(this, _replica)).Replica({ store: __privateGet(this, _store) }).list({
26792
+ prefix: options.prefix,
26793
+ ...options.after === void 0 ? {} : { after: options.after },
26794
+ ...options.limit === void 0 ? {} : { limit: options.limit }
26795
+ });
26796
+ return {
26797
+ keys: result.entries.map((entry) => entry.key),
26798
+ meta: {
26799
+ asOf: result.meta.asOf,
26800
+ coverage: result.meta.coverage,
26801
+ authority: result.meta.authority,
26802
+ syncedThroughEpoch: await readFence(__privateGet(this, _replicaDir))
26803
+ }
26804
+ };
26805
+ }
26806
+ /**
26807
+ * The newest installed grant — the pending one when a not-yet-promoted
26808
+ * install exists — with `parentCid` = signed `prf[0]` and `unconstrained`
26809
+ * computed from the signed `att` (replica's own grantCovers ignores
26810
+ * caveats, so the adapter computes it, §2.1). A constrained installed
26811
+ * grant is still reported (unconstrained: false) and never reused.
26812
+ */
26813
+ async grant() {
26814
+ await __privateMethod(this, _SqliteReplicaHandle_instances, assertLive_fn).call(this);
26815
+ const state = await __privateGet(this, _store).open();
26816
+ if (state === null) return null;
26817
+ return newestGrantInfo(
26818
+ __privateGet(this, _replica),
26819
+ state.pendingGrant ?? state.grant,
26820
+ state.pendingGrant,
26821
+ this.spec
26822
+ );
26823
+ }
26824
+ async installGrant(ucan) {
26825
+ await __privateMethod(this, _SqliteReplicaHandle_instances, assertLive_fn).call(this);
26826
+ const parsed = __privateGet(this, _replica).parseUcanGrant(ucan);
26827
+ const state = await __privateGet(this, _store).open();
26828
+ if (state === null) {
26829
+ throw new (__privateGet(this, _replica)).ReplicaError(
26830
+ __privateGet(this, _replica).ReplicaErrorCode.NOT_FOUND,
26831
+ "The replica has not been created."
26832
+ );
26833
+ }
26834
+ __privateGet(this, _replica).assertGrantInstallable(parsed, {
26835
+ deviceDid: principalOf(__privateGet(this, _device).did),
26836
+ space: this.spec.space,
26837
+ prefix: this.spec.prefix,
26838
+ now: Date.now()
26839
+ });
26840
+ if (!ucanAttUnconstrainedFor(parsed.att, this.spec.space, this.spec.prefix)) {
26841
+ throw new (__privateGet(this, _replica)).ReplicaError(
26842
+ __privateGet(this, _replica).ReplicaErrorCode.GRANT_NOT_COVERING,
26843
+ "The grant's get or sync coverage carries caveats; re-mint instead of installing it."
26844
+ );
26845
+ }
26846
+ await __privateGet(this, _store).installGrant(parsed);
26847
+ return newestGrantInfo(__privateGet(this, _replica), parsed, parsed, this.spec);
26848
+ }
26849
+ async sync(options) {
26850
+ await __privateMethod(this, _SqliteReplicaHandle_instances, assertLive_fn).call(this);
26851
+ const transportFor = await __privateMethod(this, _SqliteReplicaHandle_instances, transports_fn).call(this);
26852
+ const abort = new AbortController();
26853
+ options.signal.throwIfAborted();
26854
+ const onAbort = () => abort.abort(options.signal.reason);
26855
+ options.signal.addEventListener("abort", onAbort, { once: true });
26856
+ const engine = new (__privateGet(this, _replica)).Replica({
26857
+ store: __privateGet(this, _store),
26858
+ transportFor
26859
+ });
26860
+ const running = engine.sync({ signal: abort.signal });
26861
+ const registration = { promise: running, abort: () => abort.abort() };
26862
+ __privateGet(this, _inFlight).add(registration);
26863
+ try {
26864
+ const report = await running;
26865
+ await __privateGet(this, _guard2).call(this, () => writeJsonAtomic(
26866
+ (0, import_node_path.join)(__privateGet(this, _replicaDir), FENCE_FILE),
26867
+ { v: 1, syncedThroughEpoch: options.syncStartEpoch },
26868
+ __privateGet(this, _dirSync2)
26869
+ ));
26870
+ return {
26871
+ status: "synced",
26872
+ pages: report.pages,
26873
+ changes: report.changes,
26874
+ deleted: report.deleted,
26875
+ fetched: report.fetched,
26876
+ contentMissing: report.contentMissing,
26877
+ coverage: report.coverage,
26878
+ syncedThroughEpoch: options.syncStartEpoch
26879
+ };
26880
+ } catch (error) {
26881
+ if (__privateGet(this, _replica).isReplicaError(error, __privateGet(this, _replica).ReplicaErrorCode.BUSY)) {
26882
+ return { status: "busy" };
26883
+ }
26884
+ throw error;
26885
+ } finally {
26886
+ __privateGet(this, _inFlight).delete(registration);
26887
+ options.signal.removeEventListener("abort", onAbort);
26888
+ }
26889
+ }
26890
+ async status() {
26891
+ await __privateMethod(this, _SqliteReplicaHandle_instances, assertLive_fn).call(this);
26892
+ const engine = new (__privateGet(this, _replica)).Replica({ store: __privateGet(this, _store) });
26893
+ const status = await engine.status();
26894
+ const syncedThroughEpoch = await readFence(__privateGet(this, _replicaDir));
26895
+ const state = await __privateGet(this, _store).open();
26896
+ const grant = state === null ? null : newestGrantInfo(
26897
+ __privateGet(this, _replica),
26898
+ state.pendingGrant ?? state.grant,
26899
+ state.pendingGrant,
26900
+ this.spec
26901
+ );
26902
+ return {
26903
+ coverage: status.coverage,
26904
+ lastSyncAt: status.lastSyncAt,
26905
+ syncedThroughEpoch,
26906
+ authority: { state: status.authority.state, expiresAt: status.authority.expiresAt },
26907
+ grant,
26908
+ counts: status.counts,
26909
+ bytes: status.bytes,
26910
+ lastError: status.lastError
26911
+ };
26912
+ }
26913
+ async close() {
26914
+ if (__privateGet(this, _closed)) return;
26915
+ __privateSet(this, _closed, true);
26916
+ for (const sync of __privateGet(this, _inFlight)) sync.abort();
26917
+ await Promise.allSettled([...__privateGet(this, _inFlight)].map((sync) => sync.promise));
26918
+ await __privateGet(this, _store).close();
26919
+ }
26920
+ };
26921
+ _device = new WeakMap();
26922
+ _store = new WeakMap();
26923
+ _replicaDir = new WeakMap();
26924
+ _replica = new WeakMap();
26925
+ _guard2 = new WeakMap();
26926
+ _dirSync2 = new WeakMap();
26927
+ _generation = new WeakMap();
26928
+ _ino = new WeakMap();
26929
+ _transportOverride = new WeakMap();
26930
+ _closed = new WeakMap();
26931
+ _inFlight = new WeakMap();
26932
+ _transportFactory = new WeakMap();
26933
+ _SqliteReplicaHandle_instances = new WeakSet();
26934
+ assertOpen_fn = function() {
26935
+ if (__privateGet(this, _closed)) {
26936
+ throw new (__privateGet(this, _replica)).ReplicaError(
26937
+ __privateGet(this, _replica).ReplicaErrorCode.CLOSED,
26938
+ "The replica handle is closed."
26939
+ );
26940
+ }
26941
+ };
26942
+ assertLive_fn = async function() {
26943
+ __privateMethod(this, _SqliteReplicaHandle_instances, assertOpen_fn).call(this);
26944
+ try {
26945
+ const stats = await (0, import_promises.stat)((0, import_node_path.join)(__privateGet(this, _replicaDir), "replica.db"));
26946
+ if (__privateGet(this, _ino) !== void 0 && stats.ino !== __privateGet(this, _ino)) {
26947
+ throw new (__privateGet(this, _replica)).ReplicaError(
26948
+ __privateGet(this, _replica).ReplicaErrorCode.RESET_REQUIRED,
26949
+ "The replica was recreated; open it again to continue."
26950
+ );
26951
+ }
26952
+ } catch (error) {
26953
+ if (isNotFound(error)) {
26954
+ throw new (__privateGet(this, _replica)).ReplicaError(
26955
+ __privateGet(this, _replica).ReplicaErrorCode.RESET_REQUIRED,
26956
+ "The replica was purged; open it again to continue."
26957
+ );
26958
+ }
26959
+ throw error;
26960
+ }
26961
+ const state = await __privateGet(this, _store).open();
26962
+ if (state !== null && state.generation !== __privateGet(this, _generation)) {
26963
+ throw new (__privateGet(this, _replica)).ReplicaError(
26964
+ __privateGet(this, _replica).ReplicaErrorCode.RESET_REQUIRED,
26965
+ "The replica was purged or reopened; open it again to continue."
26966
+ );
26967
+ }
26968
+ };
26969
+ transports_fn = async function() {
26970
+ if (__privateGet(this, _transportOverride) !== void 0) {
26971
+ const override = __privateGet(this, _transportOverride);
26972
+ const spec = this.spec;
26973
+ const device = __privateGet(this, _device);
26974
+ return (grant) => override(grant, spec, device);
26975
+ }
26976
+ __privateGet(this, _transportFactory) ?? __privateSet(this, _transportFactory, (async () => {
26977
+ const wasm = await import("@tinycloud/node-sdk-wasm");
26978
+ const kvSyncTransport = __privateGet(this, _replica).kvSyncTransport;
26979
+ const spec = this.spec;
26980
+ const device = __privateGet(this, _device);
26981
+ const fetch2 = spec.fetch ?? globalThis.fetch.bind(globalThis);
26982
+ return (grant) => {
26983
+ const context = new import_sdk_core13.ServiceContext({
26984
+ invoke: wasm.invoke,
26985
+ invokeAny: wasm.invokeAny,
26986
+ fetch: fetch2,
26987
+ hosts: [spec.identity.host]
26988
+ });
26989
+ const kv = new import_sdk_core13.KVService({});
26990
+ kv.initialize(context);
26991
+ context.registerService("kv", kv);
26992
+ context.setSession({
26993
+ delegationHeader: { Authorization: new TextDecoder().decode(grant.bytes) },
26994
+ delegationCid: grant.cid,
26995
+ spaceId: spec.space,
26996
+ verificationMethod: device.did,
26997
+ jwk: device.jwk
26998
+ });
26999
+ return kvSyncTransport(kv);
27000
+ };
27001
+ })());
27002
+ return __privateGet(this, _transportFactory);
27003
+ };
27004
+ function createSqliteReplicaStorage(options) {
27005
+ const root = options.dir;
27006
+ const guard = options.guard ?? ((section) => section());
27007
+ const createDevice = options.createDevice ?? createDeviceKey;
27008
+ async function openHandle(spec) {
27009
+ const [replica, sqlite] = await Promise.all([
27010
+ // @ts-ignore — TS2307 when replica's dist is absent (CI builds node-sdk first).
27011
+ import("@tinycloud/replica"),
27012
+ // @ts-ignore — same as above.
27013
+ import("@tinycloud/replica/sqlite")
27014
+ ]);
27015
+ if ((0, import_sdk_services4.requiresSecretsOptIn)(spec.space, spec.prefix) && spec.allowSecrets !== true) {
27016
+ throw new replica.ReplicaError(
27017
+ replica.ReplicaErrorCode.SECRETS_OPT_IN_REQUIRED,
27018
+ `Replicating ${spec.space}/kv/${spec.prefix} copies secret material to disk; pass allowSecrets to opt in.`
27019
+ );
27020
+ }
27021
+ const idDir = partitionDirOf(root, spec.identity);
27022
+ await ensurePartitionIdentity(idDir, spec.identity, options.dirSync);
27023
+ const createdDevice = spec.device ?? await loadOrCreateDevice(idDir, guard, createDevice, options.dirSync);
27024
+ const device = { ...createdDevice, did: principalOf(createdDevice.did) };
27025
+ const replicaHash = replicaHashOf(spec.prefix, device.did);
27026
+ const replicaDir = (0, import_node_path.join)(idDir, "replicas", replicaHash);
27027
+ const store = await sqlite.SqliteReplicaStore.open(replicaDir, {
27028
+ create: true,
27029
+ guard
27030
+ });
27031
+ let generation;
27032
+ try {
27033
+ try {
27034
+ await store.init({
27035
+ name: spec.prefix.replace(/\/+$/, "") || "replica",
27036
+ replicaId: replicaHash,
27037
+ host: spec.identity.host,
27038
+ space: spec.space,
27039
+ prefix: spec.prefix,
27040
+ deviceDid: device.did,
27041
+ allowSecrets: spec.allowSecrets,
27042
+ localReadPolicy: "whileGrantValid",
27043
+ retentionGrantCid: null
27044
+ });
27045
+ } catch (error) {
27046
+ if (!replica.isReplicaError(error, replica.ReplicaErrorCode.CONFIG_MISMATCH)) {
27047
+ throw error;
27048
+ }
27049
+ }
27050
+ const state = await store.open();
27051
+ if (state === null) {
27052
+ throw new replica.ReplicaError(
27053
+ replica.ReplicaErrorCode.NOT_FOUND,
27054
+ "The replica row vanished during init."
27055
+ );
27056
+ }
27057
+ const config = state.config;
27058
+ if (config.host !== spec.identity.host || config.space !== spec.space || config.prefix !== spec.prefix) {
27059
+ throw new replica.ReplicaError(
27060
+ replica.ReplicaErrorCode.CONFIG_MISMATCH,
27061
+ `This replica follows ${config.host} ${config.space}/kv/${config.prefix}, not ${spec.identity.host} ${spec.space}/kv/${spec.prefix}.`
27062
+ );
27063
+ }
27064
+ if (principalOf(config.deviceDid) !== principalOf(device.did)) {
27065
+ throw new replica.ReplicaError(
27066
+ replica.ReplicaErrorCode.CONFIG_MISMATCH,
27067
+ "The stored replica belongs to a different device key; purge the partition to rekey."
27068
+ );
27069
+ }
27070
+ generation = state.generation;
27071
+ } catch (error) {
27072
+ await store.close().catch(() => void 0);
27073
+ throw error;
27074
+ }
27075
+ let ino;
27076
+ try {
27077
+ ino = (await (0, import_promises.stat)((0, import_node_path.join)(replicaDir, "replica.db"))).ino;
27078
+ } catch (error) {
27079
+ if (!isNotFound(error)) throw error;
27080
+ }
27081
+ return new SqliteReplicaHandle({
27082
+ spec,
27083
+ device,
27084
+ store,
27085
+ replicaDir,
27086
+ replica,
27087
+ guard,
27088
+ transportFor: options.transportFor,
27089
+ dirSync: options.dirSync,
27090
+ generation,
27091
+ ino
27092
+ });
27093
+ }
27094
+ async function inspectStatus(spec, { signal }) {
27095
+ const checkAbort = () => {
27096
+ if (signal.aborted) throw signal.reason ?? Object.assign(new Error("Replica status inspection was aborted"), { code: "ABORTED" });
27097
+ };
27098
+ checkAbort();
27099
+ const idDir = partitionDirOf(root, spec.identity);
27100
+ if (!await pathExists(idDir)) return void 0;
27101
+ checkAbort();
27102
+ const identityFile = (0, import_node_path.join)(idDir, "identity.json");
27103
+ const storedIdentity = identityRecordOf(await readJsonFile(identityFile));
27104
+ if (storedIdentity === void 0 || !sameIdentity(storedIdentity, spec.identity)) {
27105
+ throw new ReplicaStorageError("STORAGE_ERROR", `The partition at ${idDir} belongs to a different identity or has no identity record.`);
27106
+ }
27107
+ checkAbort();
27108
+ let device = spec.device;
27109
+ if (device === void 0) {
27110
+ const deviceFile = (0, import_node_path.join)(idDir, "device.jwk");
27111
+ const storedDevice = await readJsonFile(deviceFile);
27112
+ if (storedDevice === void 0) return void 0;
27113
+ device = deviceRecordOf(storedDevice);
27114
+ if (device === void 0) throw new ReplicaStorageError("STORAGE_ERROR", `The replica device key at ${deviceFile} is unreadable.`);
27115
+ }
27116
+ checkAbort();
27117
+ const replicaDir = (0, import_node_path.join)(idDir, "replicas", replicaHashOf(spec.prefix, device.did));
27118
+ if (!await pathExists(replicaDir)) return void 0;
27119
+ checkAbort();
27120
+ const [replica, sqlite] = await Promise.all([
27121
+ // @ts-ignore — TS2307 when replica's dist is absent (CI builds node-sdk first).
27122
+ import("@tinycloud/replica"),
27123
+ // @ts-ignore — same as above.
27124
+ import("@tinycloud/replica/sqlite")
27125
+ ]);
27126
+ checkAbort();
27127
+ const inspected = await sqlite.SqliteReplicaStore.inspect(replicaDir, { signal });
27128
+ checkAbort();
27129
+ if (inspected === null) return void 0;
27130
+ const { state, status } = inspected;
27131
+ if (state.config.host !== spec.identity.host || state.config.space !== spec.space || state.config.prefix !== spec.prefix || principalOf(state.config.deviceDid) !== principalOf(device.did)) {
27132
+ throw new ReplicaStorageError("STORAGE_ERROR", `The replica at ${replicaDir} does not match the requested identity, space, prefix, or device.`);
27133
+ }
27134
+ const syncedThroughEpoch = await readFence(replicaDir);
27135
+ checkAbort();
27136
+ return {
27137
+ coverage: status.coverage,
27138
+ lastSyncAt: status.lastSyncAt,
27139
+ syncedThroughEpoch,
27140
+ authority: { state: status.authority.state, expiresAt: status.authority.expiresAt },
27141
+ grant: newestGrantInfo(replica, state.pendingGrant ?? state.grant, state.pendingGrant, spec),
27142
+ counts: status.counts,
27143
+ bytes: status.bytes,
27144
+ lastError: status.lastError
27145
+ };
27146
+ }
27147
+ async function purgePartition(target) {
27148
+ const [replica, sqlite] = await Promise.all([
27149
+ // @ts-ignore — TS2307 when replica's dist is absent (CI builds node-sdk first).
27150
+ import("@tinycloud/replica"),
27151
+ // @ts-ignore — same as above.
27152
+ import("@tinycloud/replica/sqlite")
27153
+ ]);
27154
+ const idDir = partitionDirOf(root, target.identity);
27155
+ if (!await pathExists(idDir)) return;
27156
+ const deviceDids = [];
27157
+ const deviceFile = (0, import_node_path.join)(idDir, "device.jwk");
27158
+ const stored = await readJsonFile(deviceFile);
27159
+ if (stored !== void 0) {
27160
+ const device = deviceRecordOf(stored);
27161
+ if (device === void 0) {
27162
+ throw new ReplicaStorageError(
27163
+ "STORAGE_ERROR",
27164
+ `The replica device key at ${deviceFile} is unreadable.`
27165
+ );
27166
+ }
27167
+ deviceDids.push(device.did);
27168
+ }
27169
+ if (target.sessionDeviceDid !== void 0) deviceDids.push(target.sessionDeviceDid);
27170
+ const devices = [...new Map(deviceDids.map((did) => [principalOf(did), did])).values()];
27171
+ let firstError;
27172
+ for (const deviceDid of devices) {
27173
+ const replicaDir = (0, import_node_path.join)(idDir, "replicas", replicaHashOf(target.prefix, deviceDid));
27174
+ if (!await pathExists(replicaDir)) continue;
27175
+ try {
27176
+ let store;
27177
+ try {
27178
+ store = await sqlite.SqliteReplicaStore.open(replicaDir, { create: false, guard });
27179
+ } catch (error) {
27180
+ if (replica.isReplicaError(error, replica.ReplicaErrorCode.NOT_FOUND)) {
27181
+ await guard(() => (0, import_promises.rm)(replicaDir, { recursive: true, force: true }));
27182
+ continue;
27183
+ }
27184
+ throw error;
27185
+ }
27186
+ try {
27187
+ const state = await store.open();
27188
+ if (state === null) {
27189
+ await store.close().catch(() => void 0);
27190
+ await guard(() => (0, import_promises.rm)(replicaDir, { recursive: true, force: true }));
27191
+ continue;
27192
+ }
27193
+ const lease = await store.acquireSyncLease(SYNC_LEASE_TTL_MS);
27194
+ if (lease === null) {
27195
+ throw new replica.ReplicaError(
27196
+ replica.ReplicaErrorCode.BUSY,
27197
+ "Another process holds this replica's sync lease."
27198
+ );
27199
+ }
27200
+ try {
27201
+ if (state.revoked === null) {
27202
+ await store.reset(lease, "purged");
27203
+ }
27204
+ await store.destroy(lease);
27205
+ } finally {
27206
+ await store.releaseLease(lease).catch(() => void 0);
27207
+ }
27208
+ } finally {
27209
+ await store.close().catch(() => void 0);
27210
+ }
27211
+ } catch (error) {
27212
+ firstError ?? (firstError = error);
27213
+ }
27214
+ }
27215
+ if (firstError !== void 0) throw firstError;
27216
+ }
27217
+ return {
27218
+ kind: "sqlite",
27219
+ open: openHandle,
27220
+ inspectStatus,
27221
+ purge: purgePartition,
27222
+ // Always the durable partitioned file store (review): the runtime
27223
+ // must never fall back to volatile in-memory pending state — a
27224
+ // restart that lost ambiguous write records would serve stale data.
27225
+ // Without a guard the file store still durably serializes each update;
27226
+ // the guard only adds cross-process read-modify-write exclusion.
27227
+ pendingWrites(identity) {
27228
+ return new FilePendingWriteStore(
27229
+ identity,
27230
+ partitionDirOf(root, identity),
27231
+ guard,
27232
+ options.dirSync
27233
+ );
27234
+ }
27235
+ };
27236
+ }
27237
+ function sqliteReplicaStorage(options) {
27238
+ return createSqliteReplicaStorage(options);
27239
+ }
25387
27240
  // Annotate the CommonJS export names for ESM import in node:
25388
27241
  0 && (module.exports = {
25389
27242
  ACCEPTED_MARKER_VERSIONS,
@@ -25540,6 +27393,7 @@ var import_sdk_core23 = require("@tinycloud/sdk-core");
25540
27393
  resourceCapabilitiesToSpaceAbilitiesMap,
25541
27394
  serializeDelegation,
25542
27395
  signedCompactUcanExpiry,
27396
+ sqliteReplicaStorage,
25543
27397
  tinyCloudDebugLogger,
25544
27398
  validateEnvelope,
25545
27399
  validateManifest,