@tinycloud/node-sdk 3.2.6-beta.6 → 3.3.0-beta.7
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/{WasmKeyProvider-DEdSyQ0I.d.cts → TinyCloudNode-BchWB_zv.d.cts} +162 -283
- package/dist/{WasmKeyProvider-DEdSyQ0I.d.ts → TinyCloudNode-BchWB_zv.d.ts} +162 -283
- package/dist/WasmKeyProvider-5Ee7fcAw.d.cts +217 -0
- package/dist/WasmKeyProvider-5Ee7fcAw.d.ts +217 -0
- package/dist/authority-4HXYteKF.d.ts +118 -0
- package/dist/authority-lrA-698X.d.cts +118 -0
- package/dist/core.cjs +368 -147
- package/dist/core.cjs.map +1 -1
- package/dist/core.d.cts +37 -4
- package/dist/core.d.ts +37 -4
- package/dist/core.js +374 -155
- package/dist/core.js.map +1 -1
- package/dist/gated-network-BEF2XSTC.d.cts +16 -0
- package/dist/gated-network-BEF2XSTC.d.ts +16 -0
- package/dist/index.cjs +2702 -524
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +35 -89
- package/dist/index.d.ts +35 -89
- package/dist/index.js +2702 -530
- package/dist/index.js.map +1 -1
- package/dist/replication/authority.cjs +153 -15
- package/dist/replication/authority.cjs.map +1 -1
- package/dist/replication/authority.d.cts +4 -1
- package/dist/replication/authority.d.ts +4 -1
- package/dist/replication/authority.js +147 -14
- package/dist/replication/authority.js.map +1 -1
- package/dist/replication/gated-network.cjs +90 -0
- package/dist/replication/gated-network.cjs.map +1 -0
- package/dist/replication/gated-network.d.cts +2 -0
- package/dist/replication/gated-network.d.ts +2 -0
- package/dist/replication/gated-network.js +65 -0
- package/dist/replication/gated-network.js.map +1 -0
- package/dist/replication/runtime.cjs +84 -6
- package/dist/replication/runtime.cjs.map +1 -1
- package/dist/replication/runtime.d.cts +2 -1
- package/dist/replication/runtime.d.ts +2 -1
- package/dist/replication/runtime.js +84 -6
- package/dist/replication/runtime.js.map +1 -1
- package/dist/{runtime-B5P5SRpC.d.ts → runtime-D1o9Eybt.d.cts} +14 -3
- package/dist/{runtime-B5P5SRpC.d.cts → runtime-v62FzQHz.d.ts} +14 -3
- package/package.json +14 -4
- package/dist/authority-DDGtccBK.d.cts +0 -96
- package/dist/authority-DDGtccBK.d.ts +0 -96
package/dist/core.cjs
CHANGED
|
@@ -106,6 +106,7 @@ __export(core_exports, {
|
|
|
106
106
|
expandActionShortNames: () => import_sdk_core13.expandActionShortNames,
|
|
107
107
|
expandPermissionEntries: () => import_sdk_core13.expandPermissionEntries,
|
|
108
108
|
expandPermissionEntry: () => import_sdk_core13.expandPermissionEntry,
|
|
109
|
+
getNodeReplicationLoaders: () => getNodeReplicationLoaders,
|
|
109
110
|
getTinyCloudDebugLogs: () => import_sdk_core12.getTinyCloudDebugLogs,
|
|
110
111
|
installTinyCloudDebugGlobals: () => import_sdk_core12.installTinyCloudDebugGlobals,
|
|
111
112
|
isCapabilitySubset: () => import_sdk_core13.isCapabilitySubset,
|
|
@@ -526,6 +527,7 @@ var NodeUserAuthorization = class {
|
|
|
526
527
|
this.siweConfig = config.siweConfig;
|
|
527
528
|
this.includeAccountRegistryPermissions = config.includeAccountRegistryPermissions ?? true;
|
|
528
529
|
this.replication = config.replication?.enabled === true ? config.replication : void 0;
|
|
530
|
+
this.establishReplicaStamp = config.establishReplicaStamp;
|
|
529
531
|
this._manifest = config.manifest;
|
|
530
532
|
this._capabilityRequest = config.capabilityRequest;
|
|
531
533
|
this.sessionManager = config.sessionManager ?? this.wasm.createSessionManager();
|
|
@@ -1295,6 +1297,27 @@ var NodeUserAuthorization = class {
|
|
|
1295
1297
|
signature
|
|
1296
1298
|
};
|
|
1297
1299
|
}
|
|
1300
|
+
persistedData(session, expiresAt, createdAt, replicaStamp) {
|
|
1301
|
+
return {
|
|
1302
|
+
address: session.address,
|
|
1303
|
+
chainId: session.chainId,
|
|
1304
|
+
sessionKey: JSON.stringify(session.jwk),
|
|
1305
|
+
siwe: session.siwe,
|
|
1306
|
+
signature: session.signature,
|
|
1307
|
+
tinycloudSession: {
|
|
1308
|
+
delegationHeader: session.delegationHeader,
|
|
1309
|
+
delegationCid: session.delegationCid,
|
|
1310
|
+
spaceId: session.spaceId,
|
|
1311
|
+
spaces: session.spaces,
|
|
1312
|
+
verificationMethod: session.verificationMethod
|
|
1313
|
+
},
|
|
1314
|
+
expiresAt,
|
|
1315
|
+
createdAt,
|
|
1316
|
+
version: "1.0",
|
|
1317
|
+
tinycloudHosts: this.tinycloudHosts,
|
|
1318
|
+
...replicaStamp ? { replicaStamp } : {}
|
|
1319
|
+
};
|
|
1320
|
+
}
|
|
1298
1321
|
/**
|
|
1299
1322
|
* Sign in and create a new session.
|
|
1300
1323
|
*
|
|
@@ -1374,24 +1397,13 @@ var NodeUserAuthorization = class {
|
|
|
1374
1397
|
siwe: prepared.siwe,
|
|
1375
1398
|
signature
|
|
1376
1399
|
};
|
|
1377
|
-
const
|
|
1378
|
-
|
|
1379
|
-
|
|
1380
|
-
|
|
1381
|
-
|
|
1382
|
-
|
|
1383
|
-
|
|
1384
|
-
delegationHeader: session.delegationHeader,
|
|
1385
|
-
delegationCid: session.delegationCid,
|
|
1386
|
-
spaceId,
|
|
1387
|
-
spaces: spacesMetadata,
|
|
1388
|
-
verificationMethod: this.sessionManager.getDID(keyId)
|
|
1389
|
-
},
|
|
1390
|
-
expiresAt: expirationTime.toISOString(),
|
|
1391
|
-
createdAt: now.toISOString(),
|
|
1392
|
-
version: "1.0",
|
|
1393
|
-
tinycloudHosts: this.tinycloudHosts
|
|
1394
|
-
};
|
|
1400
|
+
const replicaStamp = await this.establishReplicaStamp?.(tinyCloudSession);
|
|
1401
|
+
const persistedData = this.persistedData(
|
|
1402
|
+
tinyCloudSession,
|
|
1403
|
+
expirationTime.toISOString(),
|
|
1404
|
+
now.toISOString(),
|
|
1405
|
+
replicaStamp
|
|
1406
|
+
);
|
|
1395
1407
|
await this.enqueuePersistence(async () => {
|
|
1396
1408
|
await this.sessionStorage.save(address, persistedData);
|
|
1397
1409
|
if (generation !== this.sessionGeneration) {
|
|
@@ -1545,28 +1557,12 @@ var NodeUserAuthorization = class {
|
|
|
1545
1557
|
siwe: prepared.siwe,
|
|
1546
1558
|
signature
|
|
1547
1559
|
};
|
|
1548
|
-
const expirationMatch = prepared.siwe
|
|
1549
|
-
const issuedAtMatch = prepared.siwe
|
|
1560
|
+
const expirationMatch = prepared.siwe?.match(/Expiration Time: (.+)/);
|
|
1561
|
+
const issuedAtMatch = prepared.siwe?.match(/Issued At: (.+)/);
|
|
1550
1562
|
const expiresAt = expirationMatch?.[1] ?? new Date(Date.now() + this.sessionExpirationMs).toISOString();
|
|
1551
1563
|
const createdAt = issuedAtMatch?.[1] ?? (/* @__PURE__ */ new Date()).toISOString();
|
|
1552
|
-
const
|
|
1553
|
-
|
|
1554
|
-
chainId,
|
|
1555
|
-
sessionKey: JSON.stringify(jwk),
|
|
1556
|
-
siwe: prepared.siwe,
|
|
1557
|
-
signature,
|
|
1558
|
-
tinycloudSession: {
|
|
1559
|
-
delegationHeader: session.delegationHeader,
|
|
1560
|
-
delegationCid: session.delegationCid,
|
|
1561
|
-
spaceId: prepared.spaceId,
|
|
1562
|
-
spaces: spacesMetadata,
|
|
1563
|
-
verificationMethod: this.sessionManager.getDID(keyId)
|
|
1564
|
-
},
|
|
1565
|
-
expiresAt,
|
|
1566
|
-
createdAt,
|
|
1567
|
-
version: "1.0",
|
|
1568
|
-
tinycloudHosts: this.tinycloudHosts
|
|
1569
|
-
};
|
|
1564
|
+
const replicaStamp = await this.establishReplicaStamp?.(tinyCloudSession);
|
|
1565
|
+
const persistedData = this.persistedData(tinyCloudSession, expiresAt, createdAt, replicaStamp);
|
|
1570
1566
|
await this.sessionStorage.save(address, persistedData);
|
|
1571
1567
|
this._session = clientSession;
|
|
1572
1568
|
this._tinyCloudSession = tinyCloudSession;
|
|
@@ -1629,15 +1625,36 @@ var NodeUserAuthorization = class {
|
|
|
1629
1625
|
const { prepared, keyId, jwk } = await this.prepareSessionForSigning();
|
|
1630
1626
|
const presentation = this.buildPresentationEnvelope(options?.reason);
|
|
1631
1627
|
const hostHint = this.primaryTinyCloudHost;
|
|
1632
|
-
const
|
|
1628
|
+
const originalRequest = {
|
|
1633
1629
|
protocolVersion: 1,
|
|
1634
1630
|
siwe: prepared.siwe,
|
|
1635
1631
|
jwk,
|
|
1632
|
+
verificationMethod: prepared.verificationMethod,
|
|
1636
1633
|
host: hostHint,
|
|
1637
1634
|
keyId: options?.openkeyKeyId,
|
|
1638
1635
|
presentation
|
|
1639
|
-
}
|
|
1640
|
-
|
|
1636
|
+
};
|
|
1637
|
+
let result;
|
|
1638
|
+
let signed;
|
|
1639
|
+
let signature;
|
|
1640
|
+
for (let attempt = 0; ; ) {
|
|
1641
|
+
try {
|
|
1642
|
+
result ?? (result = await authorizeFn(originalRequest));
|
|
1643
|
+
signed = await this.verifyOpenKeyResult(result, prepared);
|
|
1644
|
+
signature = result.signature;
|
|
1645
|
+
break;
|
|
1646
|
+
} catch (error) {
|
|
1647
|
+
if (!options?.retryResult) throw error;
|
|
1648
|
+
const next = await options.retryResult(
|
|
1649
|
+
error instanceof Error ? error : new Error(String(error)),
|
|
1650
|
+
originalRequest,
|
|
1651
|
+
++attempt
|
|
1652
|
+
);
|
|
1653
|
+
if (next === null) throw error;
|
|
1654
|
+
result = next;
|
|
1655
|
+
}
|
|
1656
|
+
}
|
|
1657
|
+
return this.signInWithPreparedSession(signed, signature, keyId, jwk);
|
|
1641
1658
|
}
|
|
1642
1659
|
/**
|
|
1643
1660
|
* Build a `CapabilityPresentationEnvelopeV1` from `this._manifest`. The
|
|
@@ -1717,6 +1734,11 @@ var NodeUserAuthorization = class {
|
|
|
1717
1734
|
* (resource, action) pair in the returned SIWE.
|
|
1718
1735
|
*/
|
|
1719
1736
|
async signInWithOpenKeyResult(result, prepared, keyId, jwk) {
|
|
1737
|
+
const signed = await this.verifyOpenKeyResult(result, prepared);
|
|
1738
|
+
return this.signInWithPreparedSession(signed, result.signature, keyId, jwk);
|
|
1739
|
+
}
|
|
1740
|
+
/** Validate a candidate without activating a network session, so paste retries reuse one preparation. */
|
|
1741
|
+
async verifyOpenKeyResult(result, prepared) {
|
|
1720
1742
|
if (result.protocolVersion !== 1) {
|
|
1721
1743
|
throw new Error(`Unsupported OpenKey protocol version ${result.protocolVersion}`);
|
|
1722
1744
|
}
|
|
@@ -1961,17 +1983,12 @@ var NodeUserAuthorization = class {
|
|
|
1961
1983
|
}
|
|
1962
1984
|
}
|
|
1963
1985
|
void nonRequiredGrantedPairs;
|
|
1964
|
-
return
|
|
1965
|
-
|
|
1966
|
-
|
|
1967
|
-
|
|
1968
|
-
|
|
1969
|
-
|
|
1970
|
-
},
|
|
1971
|
-
result.signature,
|
|
1972
|
-
keyId,
|
|
1973
|
-
jwk
|
|
1974
|
-
);
|
|
1986
|
+
return {
|
|
1987
|
+
siwe: result.signedMessage,
|
|
1988
|
+
jwk: prepared.jwk,
|
|
1989
|
+
spaceId: prepared.spaceId,
|
|
1990
|
+
verificationMethod: prepared.verificationMethod
|
|
1991
|
+
};
|
|
1975
1992
|
}
|
|
1976
1993
|
/**
|
|
1977
1994
|
* Clear persisted session data.
|
|
@@ -2530,41 +2547,6 @@ function deserializeDelegation(data) {
|
|
|
2530
2547
|
|
|
2531
2548
|
// src/TinyCloudNode.ts
|
|
2532
2549
|
var import_siwe2 = require("siwe");
|
|
2533
|
-
|
|
2534
|
-
// src/replication/config.ts
|
|
2535
|
-
var import_prefix2 = require("@tinycloud/sdk-services/kv/replication/prefix");
|
|
2536
|
-
function assertValidReplicationConfig(replication) {
|
|
2537
|
-
if (replication === void 0 || replication.enabled !== true) return;
|
|
2538
|
-
if (replication.storage === void 0 || replication.storage === null) {
|
|
2539
|
-
throw new TypeError("replication.enabled requires replication.storage");
|
|
2540
|
-
}
|
|
2541
|
-
if (!Array.isArray(replication.prefixes) || replication.prefixes.length === 0) {
|
|
2542
|
-
throw new TypeError("replication.prefixes must be a non-empty array");
|
|
2543
|
-
}
|
|
2544
|
-
for (const prefix of replication.prefixes) {
|
|
2545
|
-
try {
|
|
2546
|
-
(0, import_prefix2.assertFolderPrefix)(prefix);
|
|
2547
|
-
} catch (error) {
|
|
2548
|
-
throw new TypeError(error instanceof Error ? error.message : String(error));
|
|
2549
|
-
}
|
|
2550
|
-
}
|
|
2551
|
-
for (const [index, prefix] of replication.prefixes.entries()) {
|
|
2552
|
-
for (const other of replication.prefixes.slice(index + 1)) {
|
|
2553
|
-
if ((0, import_prefix2.kvPrefixCovers)(prefix, other) || (0, import_prefix2.kvPrefixCovers)(other, prefix)) {
|
|
2554
|
-
throw new TypeError(
|
|
2555
|
-
`replication.prefixes must not overlap: ${JSON.stringify(prefix)} and ${JSON.stringify(other)}`
|
|
2556
|
-
);
|
|
2557
|
-
}
|
|
2558
|
-
}
|
|
2559
|
-
if ((prefix === "/" || prefix.split("/", 1)[0] === "vault") && replication.allowSecrets !== true) {
|
|
2560
|
-
throw new TypeError(
|
|
2561
|
-
`replication prefix ${JSON.stringify(prefix)} overlaps the vault namespace; pass allowSecrets to opt in`
|
|
2562
|
-
);
|
|
2563
|
-
}
|
|
2564
|
-
}
|
|
2565
|
-
}
|
|
2566
|
-
|
|
2567
|
-
// src/TinyCloudNode.ts
|
|
2568
2550
|
var import_sdk_core10 = require("@tinycloud/sdk-core");
|
|
2569
2551
|
var import_sdk_services2 = require("@tinycloud/sdk-services");
|
|
2570
2552
|
|
|
@@ -3476,6 +3458,20 @@ function accountIndexWarningDiagnostic(error) {
|
|
|
3476
3458
|
}
|
|
3477
3459
|
return diagnostic;
|
|
3478
3460
|
}
|
|
3461
|
+
function replicaRestoreRefusal(error) {
|
|
3462
|
+
if (error !== null && typeof error === "object" && "code" in error && error.code === "REPLICA_GATED" && "gate" in error) {
|
|
3463
|
+
switch (error.gate) {
|
|
3464
|
+
case "not_established":
|
|
3465
|
+
case "stamp_stale":
|
|
3466
|
+
case "principal_mismatch":
|
|
3467
|
+
case "purge_pending":
|
|
3468
|
+
case "logout_pending":
|
|
3469
|
+
case "gate_unavailable":
|
|
3470
|
+
return error.gate;
|
|
3471
|
+
}
|
|
3472
|
+
}
|
|
3473
|
+
return "gate_unavailable";
|
|
3474
|
+
}
|
|
3479
3475
|
var _TinyCloudNode = class _TinyCloudNode {
|
|
3480
3476
|
/**
|
|
3481
3477
|
* Create a new TinyCloudNode instance.
|
|
@@ -3505,6 +3501,37 @@ var _TinyCloudNode = class _TinyCloudNode {
|
|
|
3505
3501
|
this.auth = null;
|
|
3506
3502
|
this.tc = null;
|
|
3507
3503
|
this._chainId = 1;
|
|
3504
|
+
/** Mints the replica session stamp on each fresh sign-in (TC-858 §4.1). Undefined when replication is off. */
|
|
3505
|
+
this.establishReplicaStamp = async (session) => {
|
|
3506
|
+
const replication = this.config.replication;
|
|
3507
|
+
if (!replication?.enabled) return void 0;
|
|
3508
|
+
const epoch = this.sessionEpoch;
|
|
3509
|
+
const attempt = this.latestSessionAttempt;
|
|
3510
|
+
try {
|
|
3511
|
+
const { verifiedOwnerConsentAnchor, establishReplicaSessionStamp } = await getNodeReplicationLoaders().authority();
|
|
3512
|
+
if (epoch !== this.sessionEpoch || attempt !== this.latestSessionAttempt) return void 0;
|
|
3513
|
+
const anchor = verifiedOwnerConsentAnchor(session, this.wasmBindings, exactVerifiedRecap);
|
|
3514
|
+
if (anchor === null) {
|
|
3515
|
+
throw Object.assign(new Error("Replica sign-in requires a verified finite owner SIWE and exact-space KV get+sync."), {
|
|
3516
|
+
code: "REPLICA_GATED",
|
|
3517
|
+
gate: "not_established"
|
|
3518
|
+
});
|
|
3519
|
+
}
|
|
3520
|
+
const stamp = await establishReplicaSessionStamp(
|
|
3521
|
+
replication.storage,
|
|
3522
|
+
(0, import_sdk_core10.pkhDid)(session.address, session.chainId),
|
|
3523
|
+
anchor
|
|
3524
|
+
);
|
|
3525
|
+
if (epoch !== this.sessionEpoch || attempt !== this.latestSessionAttempt) return void 0;
|
|
3526
|
+
this.replicaSessionStamp = stamp;
|
|
3527
|
+
return stamp;
|
|
3528
|
+
} catch (error) {
|
|
3529
|
+
if (epoch === this.sessionEpoch && attempt === this.latestSessionAttempt) {
|
|
3530
|
+
this.replicaRestoreGate = replicaRestoreRefusal(error);
|
|
3531
|
+
}
|
|
3532
|
+
return void 0;
|
|
3533
|
+
}
|
|
3534
|
+
};
|
|
3508
3535
|
this._baseVaults = /* @__PURE__ */ new Map();
|
|
3509
3536
|
this._baseSecrets = /* @__PURE__ */ new Map();
|
|
3510
3537
|
this._secrets = /* @__PURE__ */ new Map();
|
|
@@ -3629,7 +3656,7 @@ var _TinyCloudNode = class _TinyCloudNode {
|
|
|
3629
3656
|
});
|
|
3630
3657
|
return this.wasmBindings.invokeAny(invocationSession, caveatPreservingEntries, facts);
|
|
3631
3658
|
};
|
|
3632
|
-
|
|
3659
|
+
if (config.replication?.enabled) getNodeReplicationLoaders().validateConfig(config.replication);
|
|
3633
3660
|
this.explicitHost = config.host;
|
|
3634
3661
|
this.config = {
|
|
3635
3662
|
...config,
|
|
@@ -3644,6 +3671,16 @@ var _TinyCloudNode = class _TinyCloudNode {
|
|
|
3644
3671
|
this.replicationRuntime = runtime;
|
|
3645
3672
|
this.replicationControl = {
|
|
3646
3673
|
status: async () => {
|
|
3674
|
+
const gate = this.replicaRestoreGate;
|
|
3675
|
+
if (gate) return this.config.replication.prefixes.map((prefix) => ({
|
|
3676
|
+
prefix,
|
|
3677
|
+
state: "gated",
|
|
3678
|
+
gate,
|
|
3679
|
+
errorCode: "REPLICA_GATED",
|
|
3680
|
+
pending: { inFlight: 0, committed: 0, ambiguous: 0 },
|
|
3681
|
+
pinned: [],
|
|
3682
|
+
lagMs: null
|
|
3683
|
+
}));
|
|
3647
3684
|
const status = await runtime.then((ready) => ready.control.status());
|
|
3648
3685
|
const scopeError = this.replicationScopeError;
|
|
3649
3686
|
if (!scopeError) return status;
|
|
@@ -3660,7 +3697,15 @@ var _TinyCloudNode = class _TinyCloudNode {
|
|
|
3660
3697
|
lagMs: null
|
|
3661
3698
|
}));
|
|
3662
3699
|
},
|
|
3663
|
-
sync: async (input) =>
|
|
3700
|
+
sync: async (input) => {
|
|
3701
|
+
if (this.replicaRestoreGate) {
|
|
3702
|
+
throw Object.assign(new Error("Replica restore is gated."), {
|
|
3703
|
+
code: "REPLICA_GATED",
|
|
3704
|
+
gate: this.replicaRestoreGate
|
|
3705
|
+
});
|
|
3706
|
+
}
|
|
3707
|
+
return (await runtime).control.sync(input);
|
|
3708
|
+
},
|
|
3664
3709
|
purge: (input) => {
|
|
3665
3710
|
const instance = this.replicationRuntimeInstance;
|
|
3666
3711
|
return instance ? instance.control.purge(input) : runtime.then((ready) => ready.control.purge(input));
|
|
@@ -3876,6 +3921,7 @@ var _TinyCloudNode = class _TinyCloudNode {
|
|
|
3876
3921
|
signer: this.signer,
|
|
3877
3922
|
signStrategy: config.signStrategy ?? { type: "auto-sign" },
|
|
3878
3923
|
wasmBindings: this.wasmBindings,
|
|
3924
|
+
...config.replication?.enabled === true ? { establishReplicaStamp: this.establishReplicaStamp } : {},
|
|
3879
3925
|
sessionManager: this.sessionManager,
|
|
3880
3926
|
sessionStorage: config.sessionStorage ?? new MemorySessionStorage(),
|
|
3881
3927
|
domain: this.siweDomain,
|
|
@@ -4073,11 +4119,10 @@ var _TinyCloudNode = class _TinyCloudNode {
|
|
|
4073
4119
|
return this.signer === null;
|
|
4074
4120
|
}
|
|
4075
4121
|
/**
|
|
4076
|
-
*
|
|
4077
|
-
* Available after signIn().
|
|
4122
|
+
* Primary space of the signed-in or restored network session, including compact sessions.
|
|
4078
4123
|
*/
|
|
4079
4124
|
get spaceId() {
|
|
4080
|
-
return this.auth?.tinyCloudSession?.spaceId;
|
|
4125
|
+
return this.auth?.tinyCloudSession?.spaceId ?? this._activeServiceSession?.spaceId;
|
|
4081
4126
|
}
|
|
4082
4127
|
/**
|
|
4083
4128
|
* Get the account space ID for this wallet identity.
|
|
@@ -4125,6 +4170,12 @@ var _TinyCloudNode = class _TinyCloudNode {
|
|
|
4125
4170
|
get restorableSession() {
|
|
4126
4171
|
return this.currentTinyCloudSession();
|
|
4127
4172
|
}
|
|
4173
|
+
/** The active, verified replica stamp. Undefined when the replica is refused or the session has ended. */
|
|
4174
|
+
get replicaStamp() {
|
|
4175
|
+
const stamp = this.replicaSessionStamp;
|
|
4176
|
+
if (!stamp || this.replicaRestoreGate !== void 0 || !this.currentTinyCloudSession()) return void 0;
|
|
4177
|
+
return { incarnation: stamp.incarnation, lifecycleEpoch: stamp.lifecycleEpoch };
|
|
4178
|
+
}
|
|
4128
4179
|
/**
|
|
4129
4180
|
* Sign out and end the session on this instance.
|
|
4130
4181
|
*
|
|
@@ -4145,19 +4196,61 @@ var _TinyCloudNode = class _TinyCloudNode {
|
|
|
4145
4196
|
}
|
|
4146
4197
|
async endSession() {
|
|
4147
4198
|
const leavingAddress = this.address ?? this._restoredTcSession?.address;
|
|
4199
|
+
const leavingChainId = this._chainId;
|
|
4200
|
+
const leavingPrincipal = this.replicaSessionPrincipal ?? (leavingAddress ? (0, import_sdk_core10.pkhDid)(leavingAddress, leavingChainId) : void 0);
|
|
4148
4201
|
const leavingAuth = this.auth;
|
|
4202
|
+
const leavingContext = this._serviceContext;
|
|
4203
|
+
let denied;
|
|
4149
4204
|
try {
|
|
4150
4205
|
this.teardownSession();
|
|
4151
4206
|
} finally {
|
|
4207
|
+
const denial = leavingPrincipal ? this.denyReplicaGate({ reason: "sign_out", principal: leavingPrincipal }, leavingContext) : Promise.resolve(void 0);
|
|
4152
4208
|
try {
|
|
4153
|
-
await
|
|
4154
|
-
if (this.replicationRuntime) await (await this.replicationRuntime).unbind();
|
|
4209
|
+
denied = await denial;
|
|
4155
4210
|
} finally {
|
|
4156
|
-
|
|
4157
|
-
await
|
|
4211
|
+
try {
|
|
4212
|
+
await this.accountRegistryTail;
|
|
4213
|
+
await this.quiesceReplicaRuntime();
|
|
4214
|
+
} finally {
|
|
4215
|
+
if (leavingAddress) {
|
|
4216
|
+
await (leavingAuth ? leavingAuth.clearPersistedSession(leavingAddress) : this.config.sessionStorage?.clear(leavingAddress));
|
|
4217
|
+
}
|
|
4158
4218
|
}
|
|
4159
4219
|
}
|
|
4160
4220
|
}
|
|
4221
|
+
if (denied?.status === "unguarded") {
|
|
4222
|
+
throw new Error(`Replica gate was not denied (${denied.code ?? "unknown"}); the replica may still be restorable.`);
|
|
4223
|
+
}
|
|
4224
|
+
}
|
|
4225
|
+
/**
|
|
4226
|
+
* Step 1 of replica sign-out. Never rejects: failures come back as `unguarded` so the session
|
|
4227
|
+
* is still cleared. Returns `undefined` when replication is off.
|
|
4228
|
+
*/
|
|
4229
|
+
async denyReplicaGate(input, context = this._serviceContext) {
|
|
4230
|
+
const replication = this.config.replication;
|
|
4231
|
+
if (!replication?.enabled) return void 0;
|
|
4232
|
+
try {
|
|
4233
|
+
const lifecycle = replication.storage.lifecycle;
|
|
4234
|
+
if (lifecycle?.kind !== (replication.storage.kind === "indexeddb" ? "indexeddb" : "file")) {
|
|
4235
|
+
return { status: "unguarded", code: "gate_unavailable" };
|
|
4236
|
+
}
|
|
4237
|
+
const result = await lifecycle.deny(input);
|
|
4238
|
+
if (result.status === "denied" || result.status === "deleted" || result.status === "marker") {
|
|
4239
|
+
try {
|
|
4240
|
+
(await getNodeReplicationLoaders().authority()).reportReplicaDenial(
|
|
4241
|
+
result,
|
|
4242
|
+
input.reason,
|
|
4243
|
+
replication.onEvent,
|
|
4244
|
+
context
|
|
4245
|
+
);
|
|
4246
|
+
} catch {
|
|
4247
|
+
}
|
|
4248
|
+
}
|
|
4249
|
+
return result;
|
|
4250
|
+
} catch (error) {
|
|
4251
|
+
const code = typeof error === "object" && error !== null && "code" in error && typeof error.code === "string" ? error.code : "gate_unavailable";
|
|
4252
|
+
return { status: "unguarded", code };
|
|
4253
|
+
}
|
|
4161
4254
|
}
|
|
4162
4255
|
/**
|
|
4163
4256
|
* Synchronously drop every piece of in-memory session authority and
|
|
@@ -4176,15 +4269,9 @@ var _TinyCloudNode = class _TinyCloudNode {
|
|
|
4176
4269
|
this._activeServiceSession = void 0;
|
|
4177
4270
|
oldGraph.retire();
|
|
4178
4271
|
oldCore?.retireServices();
|
|
4179
|
-
oldAuth?.resetSession(
|
|
4180
|
-
this.sessionManager,
|
|
4181
|
-
this.sessionKeyId,
|
|
4182
|
-
this.explicitHost ? [this.explicitHost] : void 0
|
|
4183
|
-
);
|
|
4184
4272
|
this.config.host = this.explicitHost ?? DEFAULT_HOST;
|
|
4185
4273
|
this._chainId = 1;
|
|
4186
4274
|
this._restoredNodeFeatures = void 0;
|
|
4187
|
-
this._activeServiceSession = void 0;
|
|
4188
4275
|
this._serviceContext = void 0;
|
|
4189
4276
|
this._kv = void 0;
|
|
4190
4277
|
this._sql = void 0;
|
|
@@ -4209,6 +4296,9 @@ var _TinyCloudNode = class _TinyCloudNode {
|
|
|
4209
4296
|
this._bootstrapStatus = { skipped: false };
|
|
4210
4297
|
this.replicationDelegateSession = void 0;
|
|
4211
4298
|
this.replicationScopeError = void 0;
|
|
4299
|
+
this.replicaSessionPrincipal = void 0;
|
|
4300
|
+
this.replicaSessionStamp = void 0;
|
|
4301
|
+
this.replicaRestoreGate = void 0;
|
|
4212
4302
|
const sessionKey = createDefaultSessionKey(this.wasmBindings);
|
|
4213
4303
|
this.sessionManager = sessionKey.manager;
|
|
4214
4304
|
this.sessionKeyId = sessionKey.keyId;
|
|
@@ -4218,6 +4308,9 @@ var _TinyCloudNode = class _TinyCloudNode {
|
|
|
4218
4308
|
sessionKey.keyId,
|
|
4219
4309
|
this.explicitHost ? [this.explicitHost] : void 0
|
|
4220
4310
|
);
|
|
4311
|
+
this.replicaSessionPrincipal = void 0;
|
|
4312
|
+
this.replicaSessionStamp = void 0;
|
|
4313
|
+
this.replicaRestoreGate = void 0;
|
|
4221
4314
|
this._serviceGraph = this.createServiceGraphLifetime();
|
|
4222
4315
|
this.auth = oldAuth;
|
|
4223
4316
|
this.tc = this.auth ? new import_sdk_core10.TinyCloud(this.auth, {
|
|
@@ -4247,11 +4340,25 @@ var _TinyCloudNode = class _TinyCloudNode {
|
|
|
4247
4340
|
"Cannot signIn() in session-only mode. Provide a privateKey in config to create your own space."
|
|
4248
4341
|
);
|
|
4249
4342
|
}
|
|
4343
|
+
await this.signInWith(() => this.tc.signIn(options));
|
|
4344
|
+
}
|
|
4345
|
+
/**
|
|
4346
|
+
* Fresh OpenKey sign-in. The callback receives the SDK's original SIWE and
|
|
4347
|
+
* session JWK before approval; the signed result is verified against those
|
|
4348
|
+
* bytes before the network session or replica stamp is committed.
|
|
4349
|
+
*/
|
|
4350
|
+
async signInWithOpenKey(authorizeFn, options) {
|
|
4351
|
+
if (!this.signer || !this.tc || !this.auth) {
|
|
4352
|
+
throw new Error("Cannot signInWithOpenKey() in session-only mode. Provide a signer in config.");
|
|
4353
|
+
}
|
|
4354
|
+
await this.signInWith(() => this.auth.signInWithOpenKey(authorizeFn, options));
|
|
4355
|
+
}
|
|
4356
|
+
async signInWith(performSignIn) {
|
|
4250
4357
|
const epoch = this.sessionEpoch;
|
|
4251
4358
|
const attempt = ++this.latestSessionAttempt;
|
|
4252
4359
|
await this.signOutInFlight;
|
|
4253
4360
|
try {
|
|
4254
|
-
await this.establishSignIn(epoch,
|
|
4361
|
+
await this.establishSignIn(epoch, performSignIn);
|
|
4255
4362
|
} catch (error) {
|
|
4256
4363
|
if (epoch !== this.sessionEpoch && attempt === this.latestSessionAttempt) {
|
|
4257
4364
|
await this.endSession();
|
|
@@ -4259,7 +4366,7 @@ var _TinyCloudNode = class _TinyCloudNode {
|
|
|
4259
4366
|
throw error;
|
|
4260
4367
|
}
|
|
4261
4368
|
}
|
|
4262
|
-
async establishSignIn(epoch,
|
|
4369
|
+
async establishSignIn(epoch, performSignIn) {
|
|
4263
4370
|
if (!this.signer || !this.tc) {
|
|
4264
4371
|
throw new Error("Not signed in. Call signIn() first.");
|
|
4265
4372
|
}
|
|
@@ -4269,6 +4376,12 @@ var _TinyCloudNode = class _TinyCloudNode {
|
|
|
4269
4376
|
const address = (0, import_sdk_core10.canonicalizeAddress)(await this.signer.getAddress());
|
|
4270
4377
|
const chainId = await this.signer.getChainId();
|
|
4271
4378
|
this.assertSessionEpoch(epoch, "Sign-in");
|
|
4379
|
+
const nextPrincipal = (0, import_sdk_core10.pkhDid)(address, chainId);
|
|
4380
|
+
const priorPrincipal = this.replicaSessionPrincipal ?? (this.address ? (0, import_sdk_core10.pkhDid)(this.address, this._chainId) : void 0);
|
|
4381
|
+
if (this.config.replication?.enabled && priorPrincipal && priorPrincipal !== nextPrincipal) {
|
|
4382
|
+
const denial = await this.denyReplicaGate({ reason: "account_switch", principal: priorPrincipal, next: nextPrincipal });
|
|
4383
|
+
this.replicaRestoreGate = denial?.status === "unguarded" ? "gate_unavailable" : "stamp_stale";
|
|
4384
|
+
}
|
|
4272
4385
|
if (address !== this._address || chainId !== this._chainId) this.storageFull.clear();
|
|
4273
4386
|
this._address = address;
|
|
4274
4387
|
this._chainId = chainId;
|
|
@@ -4286,7 +4399,20 @@ var _TinyCloudNode = class _TinyCloudNode {
|
|
|
4286
4399
|
this.runtimePermissionGrants = [];
|
|
4287
4400
|
this.confirmedHostedSpaceIds.clear();
|
|
4288
4401
|
this.hostedOwnedSpaceIds.clear();
|
|
4289
|
-
|
|
4402
|
+
const signInAttempt = this.latestSessionAttempt;
|
|
4403
|
+
const previousReplicaGate = this.replicaRestoreGate;
|
|
4404
|
+
const previousReplicaStamp = this.replicaSessionStamp;
|
|
4405
|
+
this.replicaRestoreGate = void 0;
|
|
4406
|
+
this.replicaSessionStamp = void 0;
|
|
4407
|
+
try {
|
|
4408
|
+
await performSignIn();
|
|
4409
|
+
} catch (error) {
|
|
4410
|
+
if (epoch === this.sessionEpoch && signInAttempt === this.latestSessionAttempt) {
|
|
4411
|
+
this.replicaRestoreGate = previousReplicaGate;
|
|
4412
|
+
this.replicaSessionStamp = previousReplicaStamp;
|
|
4413
|
+
}
|
|
4414
|
+
throw error;
|
|
4415
|
+
}
|
|
4290
4416
|
this.assertSessionEpoch(epoch, "Sign-in");
|
|
4291
4417
|
this.cancelOwnedSpaceHosts();
|
|
4292
4418
|
this.syncResolvedHostFromAuth();
|
|
@@ -4294,8 +4420,9 @@ var _TinyCloudNode = class _TinyCloudNode {
|
|
|
4294
4420
|
this.hostedOwnedSpaceIds.add(spaceId);
|
|
4295
4421
|
}
|
|
4296
4422
|
this.replicationDelegateSession = void 0;
|
|
4423
|
+
this.replicaSessionPrincipal = (0, import_sdk_core10.pkhDid)(address, chainId);
|
|
4297
4424
|
this.replicationScopeError = void 0;
|
|
4298
|
-
|
|
4425
|
+
await this.quiesceReplicaRuntime();
|
|
4299
4426
|
this.assertSessionEpoch(epoch, "Sign-in");
|
|
4300
4427
|
const oldGraph = this._serviceGraph;
|
|
4301
4428
|
this._serviceGraph = this.createServiceGraphLifetime();
|
|
@@ -4882,6 +5009,9 @@ var _TinyCloudNode = class _TinyCloudNode {
|
|
|
4882
5009
|
if (this.ownStorageFull) {
|
|
4883
5010
|
return;
|
|
4884
5011
|
}
|
|
5012
|
+
if (!this.currentSessionCoversAccountRegistry()) {
|
|
5013
|
+
return;
|
|
5014
|
+
}
|
|
4885
5015
|
const controller = new AbortController();
|
|
4886
5016
|
const deadline = setTimeout(
|
|
4887
5017
|
() => controller.abort(new DOMException("Account registry deadline exceeded", "TimeoutError")),
|
|
@@ -4996,6 +5126,27 @@ var _TinyCloudNode = class _TinyCloudNode {
|
|
|
4996
5126
|
(operation) => operation.service === "space" && this.actionContains(operation.action, "tinycloud.space/list")
|
|
4997
5127
|
);
|
|
4998
5128
|
}
|
|
5129
|
+
/**
|
|
5130
|
+
* Whether the current primary session's recap covers the account index read
|
|
5131
|
+
* (`tinycloud.sql/read` on the owned account space's `account` database),
|
|
5132
|
+
* the first call of every registry sync. As in
|
|
5133
|
+
* {@link currentSessionCanListSpaces}, a session with no parseable recap
|
|
5134
|
+
* keeps today's behavior.
|
|
5135
|
+
*/
|
|
5136
|
+
currentSessionCoversAccountRegistry() {
|
|
5137
|
+
const session = this.currentTinyCloudSession();
|
|
5138
|
+
const operations = session ? this.recapOperationsFromSession(session) : [];
|
|
5139
|
+
if (operations.length === 0) {
|
|
5140
|
+
return true;
|
|
5141
|
+
}
|
|
5142
|
+
const indexRead = {
|
|
5143
|
+
spaceId: this.ownedSpaceId(import_sdk_core10.ACCOUNT_REGISTRY_SPACE),
|
|
5144
|
+
service: "sql",
|
|
5145
|
+
path: "account",
|
|
5146
|
+
action: "tinycloud.sql/read"
|
|
5147
|
+
};
|
|
5148
|
+
return operations.some((granted) => this.operationCovers(granted, indexRead));
|
|
5149
|
+
}
|
|
4999
5150
|
async withAccountRegistryRetry(task, signal) {
|
|
5000
5151
|
const delays = [250, 1e3, 3e3];
|
|
5001
5152
|
const stopped = (detail) => {
|
|
@@ -5462,11 +5613,12 @@ var _TinyCloudNode = class _TinyCloudNode {
|
|
|
5462
5613
|
);
|
|
5463
5614
|
const stagedHost = resolvedHost ?? this.config.host;
|
|
5464
5615
|
let restoredNodeFeatures;
|
|
5616
|
+
let replicaProtocolMismatch = false;
|
|
5465
5617
|
if (this.config.replication?.enabled) {
|
|
5466
5618
|
try {
|
|
5467
5619
|
restoredNodeFeatures = (await (0, import_sdk_core10.checkNodeInfo)(stagedHost, this.wasmBindings.protocolVersion())).features;
|
|
5468
5620
|
} catch (error) {
|
|
5469
|
-
|
|
5621
|
+
replicaProtocolMismatch = error instanceof import_sdk_core10.ProtocolMismatchError;
|
|
5470
5622
|
}
|
|
5471
5623
|
}
|
|
5472
5624
|
const stagedAddress = restoredAddress;
|
|
@@ -5474,28 +5626,55 @@ var _TinyCloudNode = class _TinyCloudNode {
|
|
|
5474
5626
|
let replicationPrincipal;
|
|
5475
5627
|
let compactReplicationSession;
|
|
5476
5628
|
let replicationScopeError;
|
|
5629
|
+
let replicationScopeUnavailable = false;
|
|
5477
5630
|
if (this.config.replication?.enabled) {
|
|
5478
5631
|
if (stagedAddress !== void 0) {
|
|
5479
5632
|
replicationPrincipal = (0, import_sdk_core10.pkhDid)(stagedAddress, stagedChainId);
|
|
5480
5633
|
} else {
|
|
5481
|
-
|
|
5482
|
-
|
|
5483
|
-
|
|
5484
|
-
delegationCid: sessionData.delegationCid,
|
|
5485
|
-
verificationMethod: restoredVerificationMethod,
|
|
5486
|
-
persistedSpace: sessionData.spaceId
|
|
5487
|
-
});
|
|
5488
|
-
if (!signedScope) {
|
|
5489
|
-
replicationScopeError = "Persisted space does not match the locally verified delegation scope.";
|
|
5490
|
-
} else {
|
|
5491
|
-
replicationPrincipal = signedScope.principal;
|
|
5492
|
-
compactReplicationSession = {
|
|
5634
|
+
try {
|
|
5635
|
+
const { replicationScopeFromSignedSession } = await getNodeReplicationLoaders().authority();
|
|
5636
|
+
const signedScope = replicationScopeFromSignedSession({
|
|
5493
5637
|
delegationHeader: sessionData.delegationHeader,
|
|
5494
5638
|
delegationCid: sessionData.delegationCid,
|
|
5495
|
-
spaceId: signedScope.space,
|
|
5496
5639
|
verificationMethod: restoredVerificationMethod,
|
|
5497
|
-
|
|
5498
|
-
};
|
|
5640
|
+
persistedSpace: sessionData.spaceId
|
|
5641
|
+
});
|
|
5642
|
+
if (!signedScope) {
|
|
5643
|
+
replicationScopeError = "Persisted space does not match the locally verified delegation scope.";
|
|
5644
|
+
} else {
|
|
5645
|
+
replicationPrincipal = signedScope.principal;
|
|
5646
|
+
compactReplicationSession = {
|
|
5647
|
+
delegationHeader: sessionData.delegationHeader,
|
|
5648
|
+
delegationCid: sessionData.delegationCid,
|
|
5649
|
+
spaceId: signedScope.space,
|
|
5650
|
+
verificationMethod: restoredVerificationMethod,
|
|
5651
|
+
jwk: stagedJwk
|
|
5652
|
+
};
|
|
5653
|
+
}
|
|
5654
|
+
} catch {
|
|
5655
|
+
replicationScopeUnavailable = true;
|
|
5656
|
+
replicationScopeError = "Replica scope could not be verified for this network session.";
|
|
5657
|
+
}
|
|
5658
|
+
}
|
|
5659
|
+
}
|
|
5660
|
+
let replicaRestoreGate;
|
|
5661
|
+
let restoredReplicaStamp;
|
|
5662
|
+
const replication = this.config.replication;
|
|
5663
|
+
if (replication?.enabled) {
|
|
5664
|
+
if (replicaProtocolMismatch) {
|
|
5665
|
+
replicaRestoreGate = "gate_unavailable";
|
|
5666
|
+
} else if (replicationPrincipal === void 0) {
|
|
5667
|
+
replicaRestoreGate = replicationScopeUnavailable ? "gate_unavailable" : "principal_mismatch";
|
|
5668
|
+
} else {
|
|
5669
|
+
try {
|
|
5670
|
+
const { restoreReplicaSessionStamp } = await getNodeReplicationLoaders().authority();
|
|
5671
|
+
restoredReplicaStamp = await restoreReplicaSessionStamp(
|
|
5672
|
+
replication.storage,
|
|
5673
|
+
replicationPrincipal,
|
|
5674
|
+
sessionData.replicaStamp ?? void 0
|
|
5675
|
+
);
|
|
5676
|
+
} catch (error) {
|
|
5677
|
+
replicaRestoreGate = replicaRestoreRefusal(error);
|
|
5499
5678
|
}
|
|
5500
5679
|
}
|
|
5501
5680
|
}
|
|
@@ -5588,7 +5767,10 @@ var _TinyCloudNode = class _TinyCloudNode {
|
|
|
5588
5767
|
}
|
|
5589
5768
|
this.replicationDelegateSession = compactReplicationSession;
|
|
5590
5769
|
this.replicationScopeError = replicationScopeError;
|
|
5591
|
-
|
|
5770
|
+
this.replicaRestoreGate = replicaRestoreGate;
|
|
5771
|
+
this.replicaSessionPrincipal = replicationPrincipal;
|
|
5772
|
+
this.replicaSessionStamp = restoredReplicaStamp;
|
|
5773
|
+
await this.quiesceReplicaRuntime();
|
|
5592
5774
|
if (epoch !== this.sessionEpoch) {
|
|
5593
5775
|
oldGraph.retire();
|
|
5594
5776
|
oldCore?.retireServices?.();
|
|
@@ -5603,7 +5785,7 @@ var _TinyCloudNode = class _TinyCloudNode {
|
|
|
5603
5785
|
detail: replicationScopeError
|
|
5604
5786
|
});
|
|
5605
5787
|
}
|
|
5606
|
-
await this.
|
|
5788
|
+
await this.bindReplicaOrGate(stagedGraph.serviceContext, serviceSession, stagedGraph.kv, replicationPrincipal);
|
|
5607
5789
|
oldCore?.retireServices?.();
|
|
5608
5790
|
if (epoch !== this.sessionEpoch) {
|
|
5609
5791
|
if (attempt === this.latestSessionAttempt) await this.endSession();
|
|
@@ -5736,6 +5918,7 @@ var _TinyCloudNode = class _TinyCloudNode {
|
|
|
5736
5918
|
session: input.serviceSession,
|
|
5737
5919
|
invoke: graph.invoke,
|
|
5738
5920
|
invokeAny: graph.invokeAny,
|
|
5921
|
+
signOwnerRevocation: this.signer ? (cid) => this.signOwnerRevocation(cid) : void 0,
|
|
5739
5922
|
fetch: graph.fetch
|
|
5740
5923
|
});
|
|
5741
5924
|
const keyProvider = new WasmKeyProvider({ sessionManager: input.manager });
|
|
@@ -6079,6 +6262,7 @@ var _TinyCloudNode = class _TinyCloudNode {
|
|
|
6079
6262
|
signer: this.signer,
|
|
6080
6263
|
signStrategy: this.config.signStrategy ?? { type: "auto-sign" },
|
|
6081
6264
|
wasmBindings: this.wasmBindings,
|
|
6265
|
+
...this.config.replication?.enabled === true ? { establishReplicaStamp: this.establishReplicaStamp } : {},
|
|
6082
6266
|
sessionManager: this.sessionManager,
|
|
6083
6267
|
sessionStorage: options?.sessionStorage ?? this.config.sessionStorage ?? new MemorySessionStorage(),
|
|
6084
6268
|
domain: this.siweDomain,
|
|
@@ -6137,6 +6321,7 @@ var _TinyCloudNode = class _TinyCloudNode {
|
|
|
6137
6321
|
signer: this.signer,
|
|
6138
6322
|
signStrategy: this.config.signStrategy ?? { type: "auto-sign" },
|
|
6139
6323
|
wasmBindings: this.wasmBindings,
|
|
6324
|
+
...this.config.replication?.enabled === true ? { establishReplicaStamp: this.establishReplicaStamp } : {},
|
|
6140
6325
|
sessionManager: this.sessionManager,
|
|
6141
6326
|
sessionStorage: options?.sessionStorage ?? this.config.sessionStorage ?? new MemorySessionStorage(),
|
|
6142
6327
|
domain: this.siweDomain,
|
|
@@ -6217,7 +6402,7 @@ var _TinyCloudNode = class _TinyCloudNode {
|
|
|
6217
6402
|
jwk: session.jwk
|
|
6218
6403
|
};
|
|
6219
6404
|
this._serviceContext.setSession(serviceSession);
|
|
6220
|
-
await this.
|
|
6405
|
+
await this.bindReplicaOrGate(this._serviceContext, serviceSession, this._kv);
|
|
6221
6406
|
this.tc.serviceContext.setSession(serviceSession);
|
|
6222
6407
|
this._vault = this.createVaultService(session.spaceId, this._kv);
|
|
6223
6408
|
this._vault.initialize(this._serviceContext);
|
|
@@ -6611,6 +6796,7 @@ var _TinyCloudNode = class _TinyCloudNode {
|
|
|
6611
6796
|
session: serviceSession,
|
|
6612
6797
|
invoke: graph.invoke,
|
|
6613
6798
|
invokeAny: graph.invokeAny,
|
|
6799
|
+
signOwnerRevocation: this.signer ? (cid) => this.signOwnerRevocation(cid) : void 0,
|
|
6614
6800
|
fetch: graph.fetch
|
|
6615
6801
|
});
|
|
6616
6802
|
this._spaceService = new import_sdk_core10.SpaceService({
|
|
@@ -7903,7 +8089,8 @@ var _TinyCloudNode = class _TinyCloudNode {
|
|
|
7903
8089
|
return this.delegationManager.create(params);
|
|
7904
8090
|
}
|
|
7905
8091
|
/**
|
|
7906
|
-
* Revoke a delegation
|
|
8092
|
+
* Revoke a delegation with the owner wallet when available. Session-only
|
|
8093
|
+
* clients continue to use their delegated revocation authority.
|
|
7907
8094
|
*
|
|
7908
8095
|
* @param cid - The CID of the delegation to revoke
|
|
7909
8096
|
* @returns Result indicating success or failure
|
|
@@ -8178,34 +8365,67 @@ var _TinyCloudNode = class _TinyCloudNode {
|
|
|
8178
8365
|
return auth.replicationSignInEntries();
|
|
8179
8366
|
}
|
|
8180
8367
|
async replicationAuthority() {
|
|
8181
|
-
const { createReplicationAuthority } = await getNodeReplicationLoaders().authority();
|
|
8368
|
+
const { createReplicationAuthority, mintNodeReplicationGrant, verifiedOwnerConsentAnchor } = await getNodeReplicationLoaders().authority();
|
|
8182
8369
|
return createReplicationAuthority({
|
|
8183
8370
|
replicationSession: () => this.currentTinyCloudSession() ?? this.replicationDelegateSession,
|
|
8371
|
+
verifiedConsentAnchor: (session) => {
|
|
8372
|
+
const current = this.currentTinyCloudSession();
|
|
8373
|
+
return session === current && current !== void 0 ? verifiedOwnerConsentAnchor(current, this.wasmBindings, exactVerifiedRecap) : null;
|
|
8374
|
+
},
|
|
8184
8375
|
siweExpiration: (siwe) => extractSiweExpiration(siwe),
|
|
8185
8376
|
planDelegation: (entries, options) => this.planDelegation(entries, options),
|
|
8186
|
-
mintDelegation:
|
|
8187
|
-
|
|
8188
|
-
|
|
8189
|
-
|
|
8190
|
-
|
|
8191
|
-
|
|
8192
|
-
|
|
8377
|
+
mintDelegation: (deviceDid, entries, options) => mintNodeReplicationGrant(
|
|
8378
|
+
deviceDid,
|
|
8379
|
+
entries,
|
|
8380
|
+
options,
|
|
8381
|
+
options?.renewalOnly ? this.currentTinyCloudSession() : void 0,
|
|
8382
|
+
this
|
|
8383
|
+
)
|
|
8193
8384
|
});
|
|
8194
8385
|
}
|
|
8195
|
-
async
|
|
8386
|
+
async quiesceReplicaRuntime() {
|
|
8196
8387
|
if (!this.replicationRuntime) return;
|
|
8197
|
-
|
|
8198
|
-
|
|
8199
|
-
|
|
8200
|
-
|
|
8201
|
-
|
|
8202
|
-
|
|
8203
|
-
|
|
8204
|
-
|
|
8205
|
-
|
|
8206
|
-
|
|
8207
|
-
|
|
8208
|
-
|
|
8388
|
+
try {
|
|
8389
|
+
await (await this.replicationRuntime).unbind();
|
|
8390
|
+
} catch {
|
|
8391
|
+
this.replicaRestoreGate = "gate_unavailable";
|
|
8392
|
+
}
|
|
8393
|
+
}
|
|
8394
|
+
async bindReplicaOrGate(context, session, kv, principal) {
|
|
8395
|
+
if (!this.replicationRuntime) return;
|
|
8396
|
+
const gate = this.replicaRestoreGate;
|
|
8397
|
+
const epoch = this.sessionEpoch;
|
|
8398
|
+
const attempt = this.latestSessionAttempt;
|
|
8399
|
+
try {
|
|
8400
|
+
const runtime = await this.replicationRuntime;
|
|
8401
|
+
if (epoch !== this.sessionEpoch || attempt !== this.latestSessionAttempt || this._kv !== kv || this._serviceContext !== context || gate !== this.replicaRestoreGate) return;
|
|
8402
|
+
if (gate) {
|
|
8403
|
+
await runtime.bindGatedNetworkOnly({
|
|
8404
|
+
context,
|
|
8405
|
+
session,
|
|
8406
|
+
gate,
|
|
8407
|
+
primaryKV: [{ space: session.spaceId, kv }]
|
|
8408
|
+
}, getNodeReplicationLoaders().gatedNetwork);
|
|
8409
|
+
return;
|
|
8410
|
+
}
|
|
8411
|
+
const identityPrincipal = principal ?? (this._address === void 0 ? void 0 : (0, import_sdk_core10.pkhDid)(this._address, this._chainId));
|
|
8412
|
+
if (identityPrincipal === void 0) return;
|
|
8413
|
+
const authority = await this.replicationAuthority();
|
|
8414
|
+
if (epoch !== this.sessionEpoch || attempt !== this.latestSessionAttempt || this._kv !== kv || this._serviceContext !== context) return;
|
|
8415
|
+
await runtime.bind({
|
|
8416
|
+
context,
|
|
8417
|
+
session,
|
|
8418
|
+
principal: identityPrincipal,
|
|
8419
|
+
stamp: this.replicaSessionStamp,
|
|
8420
|
+
authority,
|
|
8421
|
+
nodeFeatures: this.replicationNodeFeatures,
|
|
8422
|
+
primaryKV: [{ space: session.spaceId, kv }]
|
|
8423
|
+
});
|
|
8424
|
+
} catch {
|
|
8425
|
+
if (epoch !== this.sessionEpoch || attempt !== this.latestSessionAttempt || this._kv !== kv || this._serviceContext !== context) return;
|
|
8426
|
+
this.replicaRestoreGate = "gate_unavailable";
|
|
8427
|
+
await this.quiesceReplicaRuntime();
|
|
8428
|
+
}
|
|
8209
8429
|
}
|
|
8210
8430
|
/** Stable control facade for this node's optional replication runtime. */
|
|
8211
8431
|
get replication() {
|
|
@@ -9436,6 +9656,7 @@ var import_sdk_core22 = require("@tinycloud/sdk-core");
|
|
|
9436
9656
|
expandActionShortNames,
|
|
9437
9657
|
expandPermissionEntries,
|
|
9438
9658
|
expandPermissionEntry,
|
|
9659
|
+
getNodeReplicationLoaders,
|
|
9439
9660
|
getTinyCloudDebugLogs,
|
|
9440
9661
|
installTinyCloudDebugGlobals,
|
|
9441
9662
|
isCapabilitySubset,
|