@tinycloud/node-sdk 3.2.6-beta.1 → 3.2.6-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/{WasmKeyProvider-LXRTjZTA.d.cts → WasmKeyProvider-DEdSyQ0I.d.cts} +68 -3
- package/dist/{WasmKeyProvider-LXRTjZTA.d.ts → WasmKeyProvider-DEdSyQ0I.d.ts} +68 -3
- package/dist/core.cjs +308 -59
- package/dist/core.cjs.map +1 -1
- package/dist/core.d.cts +1 -1
- package/dist/core.d.ts +1 -1
- package/dist/core.js +308 -59
- package/dist/core.js.map +1 -1
- package/dist/index.cjs +308 -59
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +1 -1
- package/dist/index.d.ts +1 -1
- package/dist/index.js +308 -59
- package/dist/index.js.map +1 -1
- package/package.json +4 -4
package/dist/core.cjs
CHANGED
|
@@ -461,6 +461,13 @@ function cloneAbilitiesMap(actions) {
|
|
|
461
461
|
var NodeUserAuthorization = class {
|
|
462
462
|
constructor(config) {
|
|
463
463
|
this.activeSessionKeyId = "default";
|
|
464
|
+
/** Incremented by resetSession; a sign-in started earlier publishes nothing. */
|
|
465
|
+
this.sessionGeneration = 0;
|
|
466
|
+
/**
|
|
467
|
+
* Sign-in saves run one at a time, in order, each together with its own
|
|
468
|
+
* cancellation cleanup, so no later write can land between the two.
|
|
469
|
+
*/
|
|
470
|
+
this.persistenceQueue = Promise.resolve();
|
|
464
471
|
this.extensions = [];
|
|
465
472
|
this._nodeFeatures = [];
|
|
466
473
|
this._nodeFeaturesKnown = false;
|
|
@@ -591,6 +598,27 @@ var NodeUserAuthorization = class {
|
|
|
591
598
|
this.tinycloudHosts = [...hosts];
|
|
592
599
|
}
|
|
593
600
|
}
|
|
601
|
+
/**
|
|
602
|
+
* @internal End the session: adopt a fresh session manager whose active key
|
|
603
|
+
* is `sessionKeyId`, and return to the constructed state.
|
|
604
|
+
*/
|
|
605
|
+
resetSession(sessionManager, sessionKeyId, hosts) {
|
|
606
|
+
this.sessionGeneration++;
|
|
607
|
+
this.installRestoredSession(sessionManager, void 0, hosts);
|
|
608
|
+
this.activeSessionKeyId = sessionKeyId;
|
|
609
|
+
}
|
|
610
|
+
/** Throws when the session was reset (signed out) after `generation` was read. */
|
|
611
|
+
assertSignInCurrent(generation) {
|
|
612
|
+
if (generation !== this.sessionGeneration) {
|
|
613
|
+
throw new Error("Sign-in was cancelled by sign-out.");
|
|
614
|
+
}
|
|
615
|
+
}
|
|
616
|
+
/** Runs `task` after every earlier queued persistence task has settled. */
|
|
617
|
+
enqueuePersistence(task) {
|
|
618
|
+
const run = this.persistenceQueue.then(task);
|
|
619
|
+
this.persistenceQueue = run.catch(() => void 0);
|
|
620
|
+
return run;
|
|
621
|
+
}
|
|
594
622
|
/** @internal Atomically adopt the state staged by TinyCloudNode.restoreSession. */
|
|
595
623
|
installRestoredSession(sessionManager, session, hosts, nodeFeatures) {
|
|
596
624
|
this.sessionManager = sessionManager;
|
|
@@ -1279,11 +1307,14 @@ var NodeUserAuthorization = class {
|
|
|
1279
1307
|
* @param options - Optional per-call SIWE overrides for this sign-in only
|
|
1280
1308
|
*/
|
|
1281
1309
|
async signIn(options) {
|
|
1282
|
-
|
|
1283
|
-
|
|
1284
|
-
const
|
|
1285
|
-
|
|
1310
|
+
const generation = this.sessionGeneration;
|
|
1311
|
+
const address = (0, import_sdk_core4.canonicalizeAddress)(await this.signer.getAddress());
|
|
1312
|
+
const chainId = await this.signer.getChainId();
|
|
1313
|
+
this.assertSignInCurrent(generation);
|
|
1314
|
+
this._address = address;
|
|
1315
|
+
this._chainId = chainId;
|
|
1286
1316
|
await this.resolveTinyCloudHostsForSignIn(address, chainId);
|
|
1317
|
+
this.assertSignInCurrent(generation);
|
|
1287
1318
|
const keyId = `session-${Date.now()}`;
|
|
1288
1319
|
this.sessionManager.renameSessionKeyId(this.activeSessionKeyId, keyId);
|
|
1289
1320
|
this.activeSessionKeyId = keyId;
|
|
@@ -1316,6 +1347,7 @@ var NodeUserAuthorization = class {
|
|
|
1316
1347
|
type: "siwe",
|
|
1317
1348
|
purpose: "sign-in"
|
|
1318
1349
|
});
|
|
1350
|
+
this.assertSignInCurrent(generation);
|
|
1319
1351
|
const session = this.wasm.completeSessionSetup({
|
|
1320
1352
|
...prepared,
|
|
1321
1353
|
signature
|
|
@@ -1360,18 +1392,27 @@ var NodeUserAuthorization = class {
|
|
|
1360
1392
|
version: "1.0",
|
|
1361
1393
|
tinycloudHosts: this.tinycloudHosts
|
|
1362
1394
|
};
|
|
1363
|
-
await this.
|
|
1395
|
+
await this.enqueuePersistence(async () => {
|
|
1396
|
+
await this.sessionStorage.save(address, persistedData);
|
|
1397
|
+
if (generation !== this.sessionGeneration) {
|
|
1398
|
+
await this.sessionStorage.clear(address);
|
|
1399
|
+
}
|
|
1400
|
+
});
|
|
1401
|
+
this.assertSignInCurrent(generation);
|
|
1364
1402
|
this._session = clientSession;
|
|
1365
1403
|
this._tinyCloudSession = tinyCloudSession;
|
|
1366
1404
|
this._address = address;
|
|
1367
1405
|
this._chainId = chainId;
|
|
1368
1406
|
await this.refreshNodeInfo();
|
|
1407
|
+
this.assertSignInCurrent(generation);
|
|
1369
1408
|
for (const ext of this.extensions) {
|
|
1370
1409
|
if (ext.afterSignIn) {
|
|
1371
1410
|
await ext.afterSignIn(clientSession);
|
|
1411
|
+
this.assertSignInCurrent(generation);
|
|
1372
1412
|
}
|
|
1373
1413
|
}
|
|
1374
1414
|
await this.ensureSpaceExists();
|
|
1415
|
+
this.assertSignInCurrent(generation);
|
|
1375
1416
|
return clientSession;
|
|
1376
1417
|
}
|
|
1377
1418
|
/**
|
|
@@ -2533,17 +2574,24 @@ var import_sdk_core6 = require("@tinycloud/sdk-core");
|
|
|
2533
2574
|
// src/DelegatedAccess.ts
|
|
2534
2575
|
var import_sdk_core7 = require("@tinycloud/sdk-core");
|
|
2535
2576
|
var DelegatedAccess = class {
|
|
2536
|
-
|
|
2577
|
+
/**
|
|
2578
|
+
* @param lifetime - Optional owner of this access: its `fetch` is used for
|
|
2579
|
+
* requests and the service context is registered with `track`, so the
|
|
2580
|
+
* owner can cancel and retire the access (TinyCloudNode does this when its
|
|
2581
|
+
* session is replaced or signed out).
|
|
2582
|
+
*/
|
|
2583
|
+
constructor(session, delegation, host, invoke, invokeAny, telemetry, lifetime) {
|
|
2537
2584
|
this.session = session;
|
|
2538
2585
|
this._delegation = delegation;
|
|
2539
2586
|
this.host = host;
|
|
2540
|
-
|
|
2587
|
+
const context = new import_sdk_core7.ServiceContext({
|
|
2541
2588
|
invoke,
|
|
2542
2589
|
invokeAny,
|
|
2543
|
-
fetch: globalThis.fetch.bind(globalThis),
|
|
2590
|
+
fetch: lifetime?.fetch ?? globalThis.fetch.bind(globalThis),
|
|
2544
2591
|
hosts: [host],
|
|
2545
2592
|
telemetry
|
|
2546
2593
|
});
|
|
2594
|
+
this._serviceContext = lifetime ? lifetime.track(context) : context;
|
|
2547
2595
|
const prefix = this._delegation.path.replace(/\/$/, "");
|
|
2548
2596
|
this._kv = new import_sdk_core7.KVService({ prefix });
|
|
2549
2597
|
this._kv.initialize(this._serviceContext);
|
|
@@ -3117,6 +3165,19 @@ function exactVerifiedRecap(verified) {
|
|
|
3117
3165
|
caveats: cloneRecapCaveats(entry.caveats)
|
|
3118
3166
|
}));
|
|
3119
3167
|
}
|
|
3168
|
+
function createDefaultSessionKey(wasm) {
|
|
3169
|
+
const manager = wasm.createSessionManager();
|
|
3170
|
+
let keyId = "default";
|
|
3171
|
+
let jwkStr = manager.jwk(keyId);
|
|
3172
|
+
if (!jwkStr) {
|
|
3173
|
+
keyId = manager.createSessionKey(keyId);
|
|
3174
|
+
jwkStr = manager.jwk(keyId);
|
|
3175
|
+
}
|
|
3176
|
+
if (!jwkStr) {
|
|
3177
|
+
throw new Error("Failed to get session key JWK");
|
|
3178
|
+
}
|
|
3179
|
+
return { manager, keyId, jwk: JSON.parse(jwkStr) };
|
|
3180
|
+
}
|
|
3120
3181
|
var ServiceGraphLifetime = class {
|
|
3121
3182
|
constructor(invokeFn, invokeAnyFn, fetchFn, observeContext) {
|
|
3122
3183
|
this.invokeFn = invokeFn;
|
|
@@ -3166,9 +3227,13 @@ var ServiceGraphLifetime = class {
|
|
|
3166
3227
|
this.contexts.clear();
|
|
3167
3228
|
}
|
|
3168
3229
|
}
|
|
3230
|
+
/** Aborted when the graph retires: cancels requests made for its session. */
|
|
3231
|
+
get signal() {
|
|
3232
|
+
return this.abortController.signal;
|
|
3233
|
+
}
|
|
3169
3234
|
assertActive() {
|
|
3170
3235
|
if (this.retired) {
|
|
3171
|
-
throw new Error("Service graph has been retired
|
|
3236
|
+
throw new Error("Service graph has been retired: its session was replaced or signed out.");
|
|
3172
3237
|
}
|
|
3173
3238
|
}
|
|
3174
3239
|
combineSignals(signal) {
|
|
@@ -3470,6 +3535,16 @@ var _TinyCloudNode = class _TinyCloudNode {
|
|
|
3470
3535
|
* so it must outlast a slow but healthy sync (9–18 s on prod 1.20.2, TC-998).
|
|
3471
3536
|
*/
|
|
3472
3537
|
this.accountRegistryDeadlineMs = 3e4;
|
|
3538
|
+
/**
|
|
3539
|
+
* Incremented by every sign-out. A sign-in or restore records it when it
|
|
3540
|
+
* starts and does not establish its session once it has changed.
|
|
3541
|
+
*/
|
|
3542
|
+
this.sessionEpoch = 0;
|
|
3543
|
+
/**
|
|
3544
|
+
* Numbers sign-in and restore attempts. A cancelled attempt cleans up only
|
|
3545
|
+
* while it is still the latest, so it never ends a newer session.
|
|
3546
|
+
*/
|
|
3547
|
+
this.latestSessionAttempt = 0;
|
|
3473
3548
|
/**
|
|
3474
3549
|
* True when the last signIn() detected an interactive signer and skipped
|
|
3475
3550
|
* client-side bootstrap. Apps can read this to know whether bootstrap was
|
|
@@ -3603,54 +3678,17 @@ var _TinyCloudNode = class _TinyCloudNode {
|
|
|
3603
3678
|
"wasmBindings must be provided in config. Import from '@tinycloud/node-sdk' (not '/core') for automatic Node.js defaults."
|
|
3604
3679
|
);
|
|
3605
3680
|
}
|
|
3606
|
-
|
|
3607
|
-
|
|
3608
|
-
|
|
3609
|
-
|
|
3610
|
-
this.sessionKeyId = defaultKeyId;
|
|
3611
|
-
} else {
|
|
3612
|
-
this.sessionKeyId = this.sessionManager.createSessionKey(defaultKeyId);
|
|
3613
|
-
jwkStr = this.sessionManager.jwk(this.sessionKeyId);
|
|
3614
|
-
}
|
|
3615
|
-
if (!jwkStr) {
|
|
3616
|
-
throw new Error("Failed to get session key JWK");
|
|
3617
|
-
}
|
|
3618
|
-
this.sessionKeyJwk = JSON.parse(jwkStr);
|
|
3681
|
+
const sessionKey = createDefaultSessionKey(this.wasmBindings);
|
|
3682
|
+
this.sessionManager = sessionKey.manager;
|
|
3683
|
+
this.sessionKeyId = sessionKey.keyId;
|
|
3684
|
+
this.sessionKeyJwk = sessionKey.jwk;
|
|
3619
3685
|
this._serviceGraph = this.createServiceGraphLifetime();
|
|
3620
3686
|
this._capabilityRegistry = new import_sdk_core10.CapabilityKeyRegistry();
|
|
3621
3687
|
this._keyProvider = new WasmKeyProvider({
|
|
3622
3688
|
sessionManager: this.sessionManager
|
|
3623
3689
|
});
|
|
3624
3690
|
this.notificationHandler = config.notificationHandler ?? new import_sdk_core10.SilentNotificationHandler();
|
|
3625
|
-
|
|
3626
|
-
this._sharingService = new import_sdk_core10.SharingService({
|
|
3627
|
-
hosts: [this.config.host],
|
|
3628
|
-
// session: undefined - not needed for receive()
|
|
3629
|
-
invoke: receiveOnlyGraph.invoke,
|
|
3630
|
-
fetch: receiveOnlyGraph.fetch,
|
|
3631
|
-
assertActive: () => receiveOnlyGraph.assertActive(),
|
|
3632
|
-
keyProvider: this._keyProvider,
|
|
3633
|
-
registry: this._capabilityRegistry,
|
|
3634
|
-
createDelegationWasm: (params) => this.createDelegationWrapper(params),
|
|
3635
|
-
computeCid: (data, codec) => {
|
|
3636
|
-
if (!this.wasmBindings.computeCid) throw new Error("computeCid is unavailable");
|
|
3637
|
-
return this.wasmBindings.computeCid(data, codec);
|
|
3638
|
-
},
|
|
3639
|
-
// delegationManager: undefined - not needed for receive()
|
|
3640
|
-
createKVService: (config2) => {
|
|
3641
|
-
const prefix = config2.pathPrefix?.replace(/\/$/, "");
|
|
3642
|
-
const kvService = new import_sdk_core10.KVService({ prefix });
|
|
3643
|
-
const kvContext = receiveOnlyGraph.track(new import_sdk_core10.ServiceContext({
|
|
3644
|
-
invoke: config2.invoke,
|
|
3645
|
-
fetch: config2.fetch ?? globalThis.fetch.bind(globalThis),
|
|
3646
|
-
hosts: config2.hosts,
|
|
3647
|
-
telemetry: this.config.telemetry
|
|
3648
|
-
}));
|
|
3649
|
-
kvContext.setSession(config2.session);
|
|
3650
|
-
kvService.initialize(kvContext);
|
|
3651
|
-
return kvService;
|
|
3652
|
-
}
|
|
3653
|
-
});
|
|
3691
|
+
this._sharingService = this.createReceiveOnlySharing();
|
|
3654
3692
|
if (config.signer) {
|
|
3655
3693
|
this.signer = config.signer;
|
|
3656
3694
|
this.setupAuth(config);
|
|
@@ -3792,6 +3830,42 @@ var _TinyCloudNode = class _TinyCloudNode {
|
|
|
3792
3830
|
get siweDomain() {
|
|
3793
3831
|
return this.config.domain ?? "app.tinycloud.xyz";
|
|
3794
3832
|
}
|
|
3833
|
+
/**
|
|
3834
|
+
* SharingService for receive-only access (no session required), bound to the
|
|
3835
|
+
* current service graph. This lets session-only users receive sharing links
|
|
3836
|
+
* without signIn(); full capabilities (generate) are added after signIn().
|
|
3837
|
+
*/
|
|
3838
|
+
createReceiveOnlySharing() {
|
|
3839
|
+
const receiveOnlyGraph = this._serviceGraph;
|
|
3840
|
+
return new import_sdk_core10.SharingService({
|
|
3841
|
+
hosts: [this.config.host],
|
|
3842
|
+
// session: undefined - not needed for receive()
|
|
3843
|
+
invoke: receiveOnlyGraph.invoke,
|
|
3844
|
+
fetch: receiveOnlyGraph.fetch,
|
|
3845
|
+
assertActive: () => receiveOnlyGraph.assertActive(),
|
|
3846
|
+
keyProvider: this._keyProvider,
|
|
3847
|
+
registry: this._capabilityRegistry,
|
|
3848
|
+
createDelegationWasm: (params) => this.createDelegationWrapper(params),
|
|
3849
|
+
computeCid: (data, codec) => {
|
|
3850
|
+
if (!this.wasmBindings.computeCid) throw new Error("computeCid is unavailable");
|
|
3851
|
+
return this.wasmBindings.computeCid(data, codec);
|
|
3852
|
+
},
|
|
3853
|
+
// delegationManager: undefined - not needed for receive()
|
|
3854
|
+
createKVService: (config) => {
|
|
3855
|
+
const prefix = config.pathPrefix?.replace(/\/$/, "");
|
|
3856
|
+
const kvService = new import_sdk_core10.KVService({ prefix });
|
|
3857
|
+
const kvContext = receiveOnlyGraph.track(new import_sdk_core10.ServiceContext({
|
|
3858
|
+
invoke: config.invoke,
|
|
3859
|
+
fetch: config.fetch ?? globalThis.fetch.bind(globalThis),
|
|
3860
|
+
hosts: config.hosts,
|
|
3861
|
+
telemetry: this.config.telemetry
|
|
3862
|
+
}));
|
|
3863
|
+
kvContext.setSession(config.session);
|
|
3864
|
+
kvService.initialize(kvContext);
|
|
3865
|
+
return kvService;
|
|
3866
|
+
}
|
|
3867
|
+
});
|
|
3868
|
+
}
|
|
3795
3869
|
/**
|
|
3796
3870
|
* Set up authorization handler and TinyCloud instance.
|
|
3797
3871
|
* @internal
|
|
@@ -4051,6 +4125,115 @@ var _TinyCloudNode = class _TinyCloudNode {
|
|
|
4051
4125
|
get restorableSession() {
|
|
4052
4126
|
return this.currentTinyCloudSession();
|
|
4053
4127
|
}
|
|
4128
|
+
/**
|
|
4129
|
+
* Sign out and end the session on this instance.
|
|
4130
|
+
*
|
|
4131
|
+
* Every service built for the session (and every `useDelegation()` result)
|
|
4132
|
+
* is retired and the session key is replaced before anything is awaited, so
|
|
4133
|
+
* nothing captured from the session can sign once sign-out has started.
|
|
4134
|
+
* Pending work is aborted and the persisted session is cleared from the
|
|
4135
|
+
* configured session storage. Afterwards session accessors return
|
|
4136
|
+
* `undefined` and service calls fail with "Not signed in" until
|
|
4137
|
+
* {@link signIn} or {@link restoreSession}, which wait for a sign-out in
|
|
4138
|
+
* progress.
|
|
4139
|
+
*/
|
|
4140
|
+
signOut() {
|
|
4141
|
+
this.signOutInFlight ?? (this.signOutInFlight = this.endSession().finally(() => {
|
|
4142
|
+
this.signOutInFlight = void 0;
|
|
4143
|
+
}));
|
|
4144
|
+
return this.signOutInFlight;
|
|
4145
|
+
}
|
|
4146
|
+
async endSession() {
|
|
4147
|
+
const leavingAddress = this.address ?? this._restoredTcSession?.address;
|
|
4148
|
+
const leavingAuth = this.auth;
|
|
4149
|
+
try {
|
|
4150
|
+
this.teardownSession();
|
|
4151
|
+
} finally {
|
|
4152
|
+
try {
|
|
4153
|
+
await this.accountRegistryTail;
|
|
4154
|
+
if (this.replicationRuntime) await (await this.replicationRuntime).unbind();
|
|
4155
|
+
} finally {
|
|
4156
|
+
if (leavingAddress) {
|
|
4157
|
+
await (leavingAuth ? leavingAuth.clearPersistedSession(leavingAddress) : this.config.sessionStorage?.clear(leavingAddress));
|
|
4158
|
+
}
|
|
4159
|
+
}
|
|
4160
|
+
}
|
|
4161
|
+
}
|
|
4162
|
+
/**
|
|
4163
|
+
* Synchronously drop every piece of in-memory session authority and
|
|
4164
|
+
* invalidate sign-ins and restores still in flight (see `sessionEpoch`).
|
|
4165
|
+
*/
|
|
4166
|
+
teardownSession() {
|
|
4167
|
+
this.sessionEpoch++;
|
|
4168
|
+
this.pendingAccountRegistrySync?.controller.abort();
|
|
4169
|
+
const oldGraph = this._serviceGraph;
|
|
4170
|
+
const oldCore = this.tc;
|
|
4171
|
+
const oldAuth = this.auth;
|
|
4172
|
+
this.auth = null;
|
|
4173
|
+
this.tc = null;
|
|
4174
|
+
this._address = void 0;
|
|
4175
|
+
this._restoredTcSession = void 0;
|
|
4176
|
+
this._activeServiceSession = void 0;
|
|
4177
|
+
oldGraph.retire();
|
|
4178
|
+
oldCore?.retireServices();
|
|
4179
|
+
oldAuth?.resetSession(
|
|
4180
|
+
this.sessionManager,
|
|
4181
|
+
this.sessionKeyId,
|
|
4182
|
+
this.explicitHost ? [this.explicitHost] : void 0
|
|
4183
|
+
);
|
|
4184
|
+
this.config.host = this.explicitHost ?? DEFAULT_HOST;
|
|
4185
|
+
this._chainId = 1;
|
|
4186
|
+
this._restoredNodeFeatures = void 0;
|
|
4187
|
+
this._activeServiceSession = void 0;
|
|
4188
|
+
this._serviceContext = void 0;
|
|
4189
|
+
this._kv = void 0;
|
|
4190
|
+
this._sql = void 0;
|
|
4191
|
+
this._duckdb = void 0;
|
|
4192
|
+
this._hooks = void 0;
|
|
4193
|
+
this._vault = void 0;
|
|
4194
|
+
this._encryption = void 0;
|
|
4195
|
+
this._baseVaults.clear();
|
|
4196
|
+
this._baseSecrets.clear();
|
|
4197
|
+
this._secrets.clear();
|
|
4198
|
+
this._account = void 0;
|
|
4199
|
+
this._publicKV = void 0;
|
|
4200
|
+
this._delegationManager = void 0;
|
|
4201
|
+
this._spaceService = void 0;
|
|
4202
|
+
this.runtimePermissionGrants = [];
|
|
4203
|
+
this._recapOperationsCache = void 0;
|
|
4204
|
+
this.confirmedHostedSpaceIds.clear();
|
|
4205
|
+
this.hostedOwnedSpaceIds.clear();
|
|
4206
|
+
this.cancelOwnedSpaceHosts();
|
|
4207
|
+
this.storageFull.clear();
|
|
4208
|
+
this._bootstrapSkipped = false;
|
|
4209
|
+
this._bootstrapStatus = { skipped: false };
|
|
4210
|
+
this.replicationDelegateSession = void 0;
|
|
4211
|
+
this.replicationScopeError = void 0;
|
|
4212
|
+
const sessionKey = createDefaultSessionKey(this.wasmBindings);
|
|
4213
|
+
this.sessionManager = sessionKey.manager;
|
|
4214
|
+
this.sessionKeyId = sessionKey.keyId;
|
|
4215
|
+
this.sessionKeyJwk = sessionKey.jwk;
|
|
4216
|
+
oldAuth?.resetSession(
|
|
4217
|
+
sessionKey.manager,
|
|
4218
|
+
sessionKey.keyId,
|
|
4219
|
+
this.explicitHost ? [this.explicitHost] : void 0
|
|
4220
|
+
);
|
|
4221
|
+
this._serviceGraph = this.createServiceGraphLifetime();
|
|
4222
|
+
this.auth = oldAuth;
|
|
4223
|
+
this.tc = this.auth ? new import_sdk_core10.TinyCloud(this.auth, {
|
|
4224
|
+
invokeAny: this.invokeAnyWithRuntimePermissions,
|
|
4225
|
+
telemetry: this.config.telemetry
|
|
4226
|
+
}) : null;
|
|
4227
|
+
this._capabilityRegistry = new import_sdk_core10.CapabilityKeyRegistry();
|
|
4228
|
+
this._keyProvider = new WasmKeyProvider({ sessionManager: this.sessionManager });
|
|
4229
|
+
this._sharingService = this.createReceiveOnlySharing();
|
|
4230
|
+
}
|
|
4231
|
+
/** Throws when a sign-out started after `epoch` was read. */
|
|
4232
|
+
assertSessionEpoch(epoch, operation) {
|
|
4233
|
+
if (epoch !== this.sessionEpoch) {
|
|
4234
|
+
throw new Error(`${operation} was cancelled by sign-out.`);
|
|
4235
|
+
}
|
|
4236
|
+
}
|
|
4054
4237
|
/**
|
|
4055
4238
|
* Sign in and create a new session.
|
|
4056
4239
|
* This creates the user's space if it doesn't exist.
|
|
@@ -4064,11 +4247,28 @@ var _TinyCloudNode = class _TinyCloudNode {
|
|
|
4064
4247
|
"Cannot signIn() in session-only mode. Provide a privateKey in config to create your own space."
|
|
4065
4248
|
);
|
|
4066
4249
|
}
|
|
4250
|
+
const epoch = this.sessionEpoch;
|
|
4251
|
+
const attempt = ++this.latestSessionAttempt;
|
|
4252
|
+
await this.signOutInFlight;
|
|
4253
|
+
try {
|
|
4254
|
+
await this.establishSignIn(epoch, options);
|
|
4255
|
+
} catch (error) {
|
|
4256
|
+
if (epoch !== this.sessionEpoch && attempt === this.latestSessionAttempt) {
|
|
4257
|
+
await this.endSession();
|
|
4258
|
+
}
|
|
4259
|
+
throw error;
|
|
4260
|
+
}
|
|
4261
|
+
}
|
|
4262
|
+
async establishSignIn(epoch, options) {
|
|
4263
|
+
if (!this.signer || !this.tc) {
|
|
4264
|
+
throw new Error("Not signed in. Call signIn() first.");
|
|
4265
|
+
}
|
|
4067
4266
|
this.pendingAccountRegistrySync?.controller.abort();
|
|
4068
4267
|
await this.accountRegistryTail;
|
|
4069
4268
|
await this.wasmBindings.ensureInitialized?.();
|
|
4070
4269
|
const address = (0, import_sdk_core10.canonicalizeAddress)(await this.signer.getAddress());
|
|
4071
4270
|
const chainId = await this.signer.getChainId();
|
|
4271
|
+
this.assertSessionEpoch(epoch, "Sign-in");
|
|
4072
4272
|
if (address !== this._address || chainId !== this._chainId) this.storageFull.clear();
|
|
4073
4273
|
this._address = address;
|
|
4074
4274
|
this._chainId = chainId;
|
|
@@ -4087,6 +4287,7 @@ var _TinyCloudNode = class _TinyCloudNode {
|
|
|
4087
4287
|
this.confirmedHostedSpaceIds.clear();
|
|
4088
4288
|
this.hostedOwnedSpaceIds.clear();
|
|
4089
4289
|
await this.tc.signIn(options);
|
|
4290
|
+
this.assertSessionEpoch(epoch, "Sign-in");
|
|
4090
4291
|
this.cancelOwnedSpaceHosts();
|
|
4091
4292
|
this.syncResolvedHostFromAuth();
|
|
4092
4293
|
for (const spaceId of this.auth.lastActivationActivatedSpaceIds ?? []) {
|
|
@@ -4095,6 +4296,7 @@ var _TinyCloudNode = class _TinyCloudNode {
|
|
|
4095
4296
|
this.replicationDelegateSession = void 0;
|
|
4096
4297
|
this.replicationScopeError = void 0;
|
|
4097
4298
|
if (this.replicationRuntime) await (await this.replicationRuntime).unbind();
|
|
4299
|
+
this.assertSessionEpoch(epoch, "Sign-in");
|
|
4098
4300
|
const oldGraph = this._serviceGraph;
|
|
4099
4301
|
this._serviceGraph = this.createServiceGraphLifetime();
|
|
4100
4302
|
oldGraph.retire();
|
|
@@ -4105,15 +4307,19 @@ var _TinyCloudNode = class _TinyCloudNode {
|
|
|
4105
4307
|
this.sessionKeyJwk = signedInSession.jwk;
|
|
4106
4308
|
}
|
|
4107
4309
|
await this.initializeServices();
|
|
4310
|
+
this.assertSessionEpoch(epoch, "Sign-in");
|
|
4108
4311
|
const primarySession = this.currentTinyCloudSession();
|
|
4109
4312
|
if (primarySession) {
|
|
4110
4313
|
this.registerPrimarySessionGrant(primarySession);
|
|
4111
4314
|
}
|
|
4112
4315
|
const bootstrapped = await this.bootstrapAccountIfNeeded();
|
|
4316
|
+
this.assertSessionEpoch(epoch, "Sign-in");
|
|
4113
4317
|
await this.ensureRequestedEncryptionNetworks();
|
|
4318
|
+
this.assertSessionEpoch(epoch, "Sign-in");
|
|
4114
4319
|
if (!bootstrapped && this.config.manifest === void 0 && this.config.capabilityRequest === void 0) {
|
|
4115
4320
|
await this.ensureOwnedSpaceHostedById(this.ownedSpaceId(import_sdk_core10.SECRETS_SPACE));
|
|
4116
4321
|
}
|
|
4322
|
+
this.assertSessionEpoch(epoch, "Sign-in");
|
|
4117
4323
|
if (!bootstrapped) {
|
|
4118
4324
|
this.scheduleAccountRegistrySync();
|
|
4119
4325
|
}
|
|
@@ -4295,6 +4501,7 @@ var _TinyCloudNode = class _TinyCloudNode {
|
|
|
4295
4501
|
throw new Error("Account bootstrap requires a TinyCloud host");
|
|
4296
4502
|
}
|
|
4297
4503
|
const auth = this.auth;
|
|
4504
|
+
const graph = this._serviceGraph;
|
|
4298
4505
|
const sessions = /* @__PURE__ */ new Map();
|
|
4299
4506
|
const rawAbilitiesBySpace = /* @__PURE__ */ new Map();
|
|
4300
4507
|
const warnings = [];
|
|
@@ -4303,6 +4510,7 @@ var _TinyCloudNode = class _TinyCloudNode {
|
|
|
4303
4510
|
const canReusePrimaryBootstrapSession = primarySession?.spaceId === defaultSpaceId && auth.capabilityRequest === import_sdk_core10.BOOTSTRAP_SESSION_REQUESTS.default;
|
|
4304
4511
|
for (const step of steps) {
|
|
4305
4512
|
if (step.kind !== "session") continue;
|
|
4513
|
+
graph.assertActive();
|
|
4306
4514
|
if (step.space === "default" && canReusePrimaryBootstrapSession && primarySession) {
|
|
4307
4515
|
sessions.set(step.space, primarySession);
|
|
4308
4516
|
continue;
|
|
@@ -4330,6 +4538,7 @@ var _TinyCloudNode = class _TinyCloudNode {
|
|
|
4330
4538
|
}
|
|
4331
4539
|
for (const step of steps) {
|
|
4332
4540
|
if (step.kind !== "host") continue;
|
|
4541
|
+
graph.assertActive();
|
|
4333
4542
|
const hosted = await auth.hostOwnedSpaceResult(step.spaceId, "bootstrap-host");
|
|
4334
4543
|
if (!hosted.success) {
|
|
4335
4544
|
throw Object.assign(
|
|
@@ -4341,11 +4550,16 @@ var _TinyCloudNode = class _TinyCloudNode {
|
|
|
4341
4550
|
await new Promise((resolve) => setTimeout(resolve, 100));
|
|
4342
4551
|
for (const step of steps) {
|
|
4343
4552
|
if (step.kind !== "activate") continue;
|
|
4553
|
+
graph.assertActive();
|
|
4344
4554
|
const session = sessions.get(step.space);
|
|
4345
4555
|
if (!session) {
|
|
4346
4556
|
throw new Error(`Missing bootstrap session for ${step.space}`);
|
|
4347
4557
|
}
|
|
4348
|
-
const activated = await (0, import_sdk_core10.activateSessionWithHost)(host, session.delegationHeader)
|
|
4558
|
+
const activated = await (0, import_sdk_core10.activateSessionWithHost)(host, session.delegationHeader, graph.signal).catch((error) => {
|
|
4559
|
+
graph.assertActive();
|
|
4560
|
+
throw error;
|
|
4561
|
+
});
|
|
4562
|
+
graph.assertActive();
|
|
4349
4563
|
if (!activated.success || activated.skipped?.includes(step.spaceId)) {
|
|
4350
4564
|
throw Object.assign(
|
|
4351
4565
|
new Error(
|
|
@@ -4361,6 +4575,7 @@ var _TinyCloudNode = class _TinyCloudNode {
|
|
|
4361
4575
|
);
|
|
4362
4576
|
}
|
|
4363
4577
|
for (const step of steps) {
|
|
4578
|
+
graph.assertActive();
|
|
4364
4579
|
if (step.kind === "account-index-schema") {
|
|
4365
4580
|
const ensured = await this.account.index.ensure();
|
|
4366
4581
|
if (!ensured.ok) {
|
|
@@ -5136,6 +5351,9 @@ var _TinyCloudNode = class _TinyCloudNode {
|
|
|
5136
5351
|
* @param sessionData - The stored delegation data from the browser flow
|
|
5137
5352
|
*/
|
|
5138
5353
|
async restoreSession(sessionData) {
|
|
5354
|
+
const epoch = this.sessionEpoch;
|
|
5355
|
+
const attempt = ++this.latestSessionAttempt;
|
|
5356
|
+
await this.signOutInFlight;
|
|
5139
5357
|
await this.wasmBindings.ensureInitialized?.();
|
|
5140
5358
|
let restoredJwk;
|
|
5141
5359
|
try {
|
|
@@ -5325,6 +5543,7 @@ var _TinyCloudNode = class _TinyCloudNode {
|
|
|
5325
5543
|
});
|
|
5326
5544
|
this.pendingAccountRegistrySync?.controller.abort();
|
|
5327
5545
|
await this.accountRegistryTail;
|
|
5546
|
+
this.assertSessionEpoch(epoch, "Session restore");
|
|
5328
5547
|
const oldGraph = this._serviceGraph;
|
|
5329
5548
|
const oldCore = this.tc;
|
|
5330
5549
|
this.sessionManager = stagedManager;
|
|
@@ -5370,6 +5589,12 @@ var _TinyCloudNode = class _TinyCloudNode {
|
|
|
5370
5589
|
this.replicationDelegateSession = compactReplicationSession;
|
|
5371
5590
|
this.replicationScopeError = replicationScopeError;
|
|
5372
5591
|
if (this.replicationRuntime) await (await this.replicationRuntime).unbind();
|
|
5592
|
+
if (epoch !== this.sessionEpoch) {
|
|
5593
|
+
oldGraph.retire();
|
|
5594
|
+
oldCore?.retireServices?.();
|
|
5595
|
+
if (attempt === this.latestSessionAttempt) await this.endSession();
|
|
5596
|
+
this.assertSessionEpoch(epoch, "Session restore");
|
|
5597
|
+
}
|
|
5373
5598
|
oldGraph.retire();
|
|
5374
5599
|
if (replicationScopeError) {
|
|
5375
5600
|
stagedGraph.serviceContext.emit("replication.state", {
|
|
@@ -5380,6 +5605,10 @@ var _TinyCloudNode = class _TinyCloudNode {
|
|
|
5380
5605
|
}
|
|
5381
5606
|
await this.bindReplicationRuntime(stagedGraph.serviceContext, serviceSession, stagedGraph.kv, replicationPrincipal);
|
|
5382
5607
|
oldCore?.retireServices?.();
|
|
5608
|
+
if (epoch !== this.sessionEpoch) {
|
|
5609
|
+
if (attempt === this.latestSessionAttempt) await this.endSession();
|
|
5610
|
+
this.assertSessionEpoch(epoch, "Session restore");
|
|
5611
|
+
}
|
|
5383
5612
|
}
|
|
5384
5613
|
stagePrimarySessionState(session, verificationMethod, host, sessionExpiry, recap) {
|
|
5385
5614
|
if (!session?.siwe) return { cache: void 0, grants: [] };
|
|
@@ -7238,6 +7467,7 @@ var _TinyCloudNode = class _TinyCloudNode {
|
|
|
7238
7467
|
* matching service calls and downstream `delegateTo()` calls can use it.
|
|
7239
7468
|
*/
|
|
7240
7469
|
async useRuntimeDelegation(delegation) {
|
|
7470
|
+
const graph = this._serviceGraph;
|
|
7241
7471
|
const session = this.currentTinyCloudSession();
|
|
7242
7472
|
if (!session) {
|
|
7243
7473
|
throw new import_sdk_core10.SessionExpiredError(/* @__PURE__ */ new Date(0));
|
|
@@ -7256,9 +7486,11 @@ var _TinyCloudNode = class _TinyCloudNode {
|
|
|
7256
7486
|
try {
|
|
7257
7487
|
activateResult = await (0, import_sdk_core10.activateSessionWithHost)(
|
|
7258
7488
|
targetHost,
|
|
7259
|
-
delegation.delegationHeader
|
|
7489
|
+
delegation.delegationHeader,
|
|
7490
|
+
graph.signal
|
|
7260
7491
|
);
|
|
7261
7492
|
} catch (cause) {
|
|
7493
|
+
graph.assertActive();
|
|
7262
7494
|
throw Object.assign(
|
|
7263
7495
|
new Error("The TinyCloud host could not be reached to activate the delegation."),
|
|
7264
7496
|
{ code: "ACTIVATION_TRANSPORT_FAILED", cause }
|
|
@@ -7278,6 +7510,7 @@ var _TinyCloudNode = class _TinyCloudNode {
|
|
|
7278
7510
|
{ cause: activateResult }
|
|
7279
7511
|
);
|
|
7280
7512
|
}
|
|
7513
|
+
graph.assertActive();
|
|
7281
7514
|
this.runtimePermissionGrants = this.runtimePermissionGrants.filter(
|
|
7282
7515
|
(grant) => grant.delegation.cid !== delegation.cid
|
|
7283
7516
|
);
|
|
@@ -7294,6 +7527,7 @@ var _TinyCloudNode = class _TinyCloudNode {
|
|
|
7294
7527
|
if (!Array.isArray(permissions) || permissions.length === 0) {
|
|
7295
7528
|
throw new Error("grantRuntimePermissions requires a non-empty permissions array");
|
|
7296
7529
|
}
|
|
7530
|
+
const graph = this._serviceGraph;
|
|
7297
7531
|
const session = this.currentTinyCloudSession();
|
|
7298
7532
|
if (!session) {
|
|
7299
7533
|
throw new import_sdk_core10.SessionExpiredError(/* @__PURE__ */ new Date(0));
|
|
@@ -7374,14 +7608,19 @@ var _TinyCloudNode = class _TinyCloudNode {
|
|
|
7374
7608
|
}
|
|
7375
7609
|
})();
|
|
7376
7610
|
const signature = await this.signer.signMessage(prepared.siwe);
|
|
7611
|
+
graph.assertActive();
|
|
7377
7612
|
const delegatedSession = this.wasmBindings.completeSessionSetup({
|
|
7378
7613
|
...prepared,
|
|
7379
7614
|
signature
|
|
7380
7615
|
});
|
|
7381
7616
|
const activateResult = await (0, import_sdk_core10.activateSessionWithHost)(
|
|
7382
7617
|
this.config.host,
|
|
7383
|
-
delegatedSession.delegationHeader
|
|
7384
|
-
|
|
7618
|
+
delegatedSession.delegationHeader,
|
|
7619
|
+
graph.signal
|
|
7620
|
+
).catch((error) => {
|
|
7621
|
+
graph.assertActive();
|
|
7622
|
+
throw error;
|
|
7623
|
+
});
|
|
7385
7624
|
if (!activateResult.success) {
|
|
7386
7625
|
if (rawForDelegation.some((entry) => this.isRawRevocationPermissionEntry(entry)) && activateResult.status === 401 && /Cannot find parent delegation/i.test(activateResult.error ?? "")) {
|
|
7387
7626
|
throw Object.assign(
|
|
@@ -7402,6 +7641,7 @@ var _TinyCloudNode = class _TinyCloudNode {
|
|
|
7402
7641
|
expiresAt,
|
|
7403
7642
|
{ siwe: prepared.siwe, signature }
|
|
7404
7643
|
);
|
|
7644
|
+
graph.assertActive();
|
|
7405
7645
|
this.runtimePermissionGrants.push({
|
|
7406
7646
|
session: {
|
|
7407
7647
|
delegationHeader: delegatedSession.delegationHeader,
|
|
@@ -8865,6 +9105,7 @@ var _TinyCloudNode = class _TinyCloudNode {
|
|
|
8865
9105
|
* @returns A DelegatedAccess instance for performing operations
|
|
8866
9106
|
*/
|
|
8867
9107
|
async useDelegation(delegation) {
|
|
9108
|
+
const graph = this._serviceGraph;
|
|
8868
9109
|
const delegationHeader = delegation.delegationHeader;
|
|
8869
9110
|
const targetHost = delegation.host ?? this.config.host;
|
|
8870
9111
|
if (this.isSessionOnly) {
|
|
@@ -8906,7 +9147,8 @@ var _TinyCloudNode = class _TinyCloudNode {
|
|
|
8906
9147
|
targetHost,
|
|
8907
9148
|
this.wasmBindings.invoke,
|
|
8908
9149
|
this.wasmBindings.invokeAny,
|
|
8909
|
-
this.config.telemetry
|
|
9150
|
+
this.config.telemetry,
|
|
9151
|
+
graph
|
|
8910
9152
|
);
|
|
8911
9153
|
}
|
|
8912
9154
|
const mySession = this.auth?.tinyCloudSession;
|
|
@@ -8930,14 +9172,19 @@ var _TinyCloudNode = class _TinyCloudNode {
|
|
|
8930
9172
|
...Object.keys(rawAbilities).length > 0 ? { rawAbilities } : {}
|
|
8931
9173
|
});
|
|
8932
9174
|
const signature = await this.signer.signMessage(prepared.siwe);
|
|
9175
|
+
graph.assertActive();
|
|
8933
9176
|
const invokerSession = this.wasmBindings.completeSessionSetup({
|
|
8934
9177
|
...prepared,
|
|
8935
9178
|
signature
|
|
8936
9179
|
});
|
|
8937
9180
|
const activateResult = await (0, import_sdk_core10.activateSessionWithHost)(
|
|
8938
9181
|
targetHost,
|
|
8939
|
-
invokerSession.delegationHeader
|
|
8940
|
-
|
|
9182
|
+
invokerSession.delegationHeader,
|
|
9183
|
+
graph.signal
|
|
9184
|
+
).catch((error) => {
|
|
9185
|
+
graph.assertActive();
|
|
9186
|
+
throw error;
|
|
9187
|
+
});
|
|
8941
9188
|
if (!activateResult.success) {
|
|
8942
9189
|
throw Object.assign(
|
|
8943
9190
|
new Error(`Failed to activate delegated session: ${describeHostFailure2(activateResult)}`),
|
|
@@ -8956,6 +9203,7 @@ var _TinyCloudNode = class _TinyCloudNode {
|
|
|
8956
9203
|
siwe: prepared.siwe,
|
|
8957
9204
|
signature
|
|
8958
9205
|
};
|
|
9206
|
+
graph.assertActive();
|
|
8959
9207
|
this.trackReceivedDelegation(delegation, jwk);
|
|
8960
9208
|
this.installRuntimeGrantFromServiceSession(
|
|
8961
9209
|
delegation,
|
|
@@ -8974,7 +9222,8 @@ var _TinyCloudNode = class _TinyCloudNode {
|
|
|
8974
9222
|
targetHost,
|
|
8975
9223
|
this.wasmBindings.invoke,
|
|
8976
9224
|
this.wasmBindings.invokeAny,
|
|
8977
|
-
this.config.telemetry
|
|
9225
|
+
this.config.telemetry,
|
|
9226
|
+
graph
|
|
8978
9227
|
);
|
|
8979
9228
|
}
|
|
8980
9229
|
/**
|