@tinycloud/node-sdk 3.2.6-beta.1 → 3.2.6-beta.2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/{WasmKeyProvider-LXRTjZTA.d.cts → WasmKeyProvider-CYU_dqOx.d.cts} +69 -3
- package/dist/{WasmKeyProvider-LXRTjZTA.d.ts → WasmKeyProvider-CYU_dqOx.d.ts} +69 -3
- package/dist/core.cjs +295 -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 +295 -59
- package/dist/core.js.map +1 -1
- package/dist/index.cjs +295 -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 +295 -59
- package/dist/index.js.map +1 -1
- package/package.json +4 -4
package/dist/index.js
CHANGED
|
@@ -18476,6 +18476,13 @@ function cloneAbilitiesMap(actions) {
|
|
|
18476
18476
|
var NodeUserAuthorization = class {
|
|
18477
18477
|
constructor(config) {
|
|
18478
18478
|
this.activeSessionKeyId = "default";
|
|
18479
|
+
/** Incremented by resetSession; a sign-in started earlier publishes nothing. */
|
|
18480
|
+
this.sessionGeneration = 0;
|
|
18481
|
+
/**
|
|
18482
|
+
* Sign-in saves run one at a time, in order, each together with its own
|
|
18483
|
+
* cancellation cleanup, so no later write can land between the two.
|
|
18484
|
+
*/
|
|
18485
|
+
this.persistenceQueue = Promise.resolve();
|
|
18479
18486
|
this.extensions = [];
|
|
18480
18487
|
this._nodeFeatures = [];
|
|
18481
18488
|
this._nodeFeaturesKnown = false;
|
|
@@ -18606,6 +18613,27 @@ var NodeUserAuthorization = class {
|
|
|
18606
18613
|
this.tinycloudHosts = [...hosts];
|
|
18607
18614
|
}
|
|
18608
18615
|
}
|
|
18616
|
+
/**
|
|
18617
|
+
* @internal End the session: adopt a fresh session manager whose active key
|
|
18618
|
+
* is `sessionKeyId`, and return to the constructed state.
|
|
18619
|
+
*/
|
|
18620
|
+
resetSession(sessionManager, sessionKeyId, hosts) {
|
|
18621
|
+
this.sessionGeneration++;
|
|
18622
|
+
this.installRestoredSession(sessionManager, void 0, hosts);
|
|
18623
|
+
this.activeSessionKeyId = sessionKeyId;
|
|
18624
|
+
}
|
|
18625
|
+
/** Throws when the session was reset (signed out) after `generation` was read. */
|
|
18626
|
+
assertSignInCurrent(generation) {
|
|
18627
|
+
if (generation !== this.sessionGeneration) {
|
|
18628
|
+
throw new Error("Sign-in was cancelled by sign-out.");
|
|
18629
|
+
}
|
|
18630
|
+
}
|
|
18631
|
+
/** Runs `task` after every earlier queued persistence task has settled. */
|
|
18632
|
+
enqueuePersistence(task) {
|
|
18633
|
+
const run = this.persistenceQueue.then(task);
|
|
18634
|
+
this.persistenceQueue = run.catch(() => void 0);
|
|
18635
|
+
return run;
|
|
18636
|
+
}
|
|
18609
18637
|
/** @internal Atomically adopt the state staged by TinyCloudNode.restoreSession. */
|
|
18610
18638
|
installRestoredSession(sessionManager, session, hosts, nodeFeatures) {
|
|
18611
18639
|
this.sessionManager = sessionManager;
|
|
@@ -19294,11 +19322,14 @@ var NodeUserAuthorization = class {
|
|
|
19294
19322
|
* @param options - Optional per-call SIWE overrides for this sign-in only
|
|
19295
19323
|
*/
|
|
19296
19324
|
async signIn(options) {
|
|
19297
|
-
|
|
19298
|
-
|
|
19299
|
-
const
|
|
19300
|
-
|
|
19325
|
+
const generation = this.sessionGeneration;
|
|
19326
|
+
const address = canonicalizeAddress(await this.signer.getAddress());
|
|
19327
|
+
const chainId = await this.signer.getChainId();
|
|
19328
|
+
this.assertSignInCurrent(generation);
|
|
19329
|
+
this._address = address;
|
|
19330
|
+
this._chainId = chainId;
|
|
19301
19331
|
await this.resolveTinyCloudHostsForSignIn(address, chainId);
|
|
19332
|
+
this.assertSignInCurrent(generation);
|
|
19302
19333
|
const keyId = `session-${Date.now()}`;
|
|
19303
19334
|
this.sessionManager.renameSessionKeyId(this.activeSessionKeyId, keyId);
|
|
19304
19335
|
this.activeSessionKeyId = keyId;
|
|
@@ -19331,6 +19362,7 @@ var NodeUserAuthorization = class {
|
|
|
19331
19362
|
type: "siwe",
|
|
19332
19363
|
purpose: "sign-in"
|
|
19333
19364
|
});
|
|
19365
|
+
this.assertSignInCurrent(generation);
|
|
19334
19366
|
const session = this.wasm.completeSessionSetup({
|
|
19335
19367
|
...prepared,
|
|
19336
19368
|
signature: signature2
|
|
@@ -19375,18 +19407,27 @@ var NodeUserAuthorization = class {
|
|
|
19375
19407
|
version: "1.0",
|
|
19376
19408
|
tinycloudHosts: this.tinycloudHosts
|
|
19377
19409
|
};
|
|
19378
|
-
await this.
|
|
19410
|
+
await this.enqueuePersistence(async () => {
|
|
19411
|
+
await this.sessionStorage.save(address, persistedData);
|
|
19412
|
+
if (generation !== this.sessionGeneration) {
|
|
19413
|
+
await this.sessionStorage.clear(address);
|
|
19414
|
+
}
|
|
19415
|
+
});
|
|
19416
|
+
this.assertSignInCurrent(generation);
|
|
19379
19417
|
this._session = clientSession;
|
|
19380
19418
|
this._tinyCloudSession = tinyCloudSession;
|
|
19381
19419
|
this._address = address;
|
|
19382
19420
|
this._chainId = chainId;
|
|
19383
19421
|
await this.refreshNodeInfo();
|
|
19422
|
+
this.assertSignInCurrent(generation);
|
|
19384
19423
|
for (const ext of this.extensions) {
|
|
19385
19424
|
if (ext.afterSignIn) {
|
|
19386
19425
|
await ext.afterSignIn(clientSession);
|
|
19426
|
+
this.assertSignInCurrent(generation);
|
|
19387
19427
|
}
|
|
19388
19428
|
}
|
|
19389
19429
|
await this.ensureSpaceExists();
|
|
19430
|
+
this.assertSignInCurrent(generation);
|
|
19390
19431
|
return clientSession;
|
|
19391
19432
|
}
|
|
19392
19433
|
/**
|
|
@@ -20029,17 +20070,24 @@ import {
|
|
|
20029
20070
|
ServiceContext
|
|
20030
20071
|
} from "@tinycloud/sdk-core";
|
|
20031
20072
|
var DelegatedAccess = class {
|
|
20032
|
-
|
|
20073
|
+
/**
|
|
20074
|
+
* @param lifetime - Optional owner of this access: its `fetch` is used for
|
|
20075
|
+
* requests and the service context is registered with `track`, so the
|
|
20076
|
+
* owner can cancel and retire the access (TinyCloudNode does this when its
|
|
20077
|
+
* session is replaced or signed out).
|
|
20078
|
+
*/
|
|
20079
|
+
constructor(session, delegation, host, invoke2, invokeAny2, telemetry, lifetime) {
|
|
20033
20080
|
this.session = session;
|
|
20034
20081
|
this._delegation = delegation;
|
|
20035
20082
|
this.host = host;
|
|
20036
|
-
|
|
20083
|
+
const context = new ServiceContext({
|
|
20037
20084
|
invoke: invoke2,
|
|
20038
20085
|
invokeAny: invokeAny2,
|
|
20039
|
-
fetch: globalThis.fetch.bind(globalThis),
|
|
20086
|
+
fetch: lifetime?.fetch ?? globalThis.fetch.bind(globalThis),
|
|
20040
20087
|
hosts: [host],
|
|
20041
20088
|
telemetry
|
|
20042
20089
|
});
|
|
20090
|
+
this._serviceContext = lifetime ? lifetime.track(context) : context;
|
|
20043
20091
|
const prefix = this._delegation.path.replace(/\/$/, "");
|
|
20044
20092
|
this._kv = new KVService({ prefix });
|
|
20045
20093
|
this._kv.initialize(this._serviceContext);
|
|
@@ -20623,6 +20671,19 @@ function exactVerifiedRecap(verified) {
|
|
|
20623
20671
|
caveats: cloneRecapCaveats(entry.caveats)
|
|
20624
20672
|
}));
|
|
20625
20673
|
}
|
|
20674
|
+
function createDefaultSessionKey(wasm) {
|
|
20675
|
+
const manager = wasm.createSessionManager();
|
|
20676
|
+
let keyId = "default";
|
|
20677
|
+
let jwkStr = manager.jwk(keyId);
|
|
20678
|
+
if (!jwkStr) {
|
|
20679
|
+
keyId = manager.createSessionKey(keyId);
|
|
20680
|
+
jwkStr = manager.jwk(keyId);
|
|
20681
|
+
}
|
|
20682
|
+
if (!jwkStr) {
|
|
20683
|
+
throw new Error("Failed to get session key JWK");
|
|
20684
|
+
}
|
|
20685
|
+
return { manager, keyId, jwk: JSON.parse(jwkStr) };
|
|
20686
|
+
}
|
|
20626
20687
|
var ServiceGraphLifetime = class {
|
|
20627
20688
|
constructor(invokeFn, invokeAnyFn, fetchFn, observeContext) {
|
|
20628
20689
|
this.invokeFn = invokeFn;
|
|
@@ -20672,9 +20733,13 @@ var ServiceGraphLifetime = class {
|
|
|
20672
20733
|
this.contexts.clear();
|
|
20673
20734
|
}
|
|
20674
20735
|
}
|
|
20736
|
+
/** Aborted when the graph retires: cancels requests made for its session. */
|
|
20737
|
+
get signal() {
|
|
20738
|
+
return this.abortController.signal;
|
|
20739
|
+
}
|
|
20675
20740
|
assertActive() {
|
|
20676
20741
|
if (this.retired) {
|
|
20677
|
-
throw new Error("Service graph has been retired
|
|
20742
|
+
throw new Error("Service graph has been retired: its session was replaced or signed out.");
|
|
20678
20743
|
}
|
|
20679
20744
|
}
|
|
20680
20745
|
combineSignals(signal) {
|
|
@@ -20976,6 +21041,16 @@ var _TinyCloudNode = class _TinyCloudNode {
|
|
|
20976
21041
|
* so it must outlast a slow but healthy sync (9–18 s on prod 1.20.2, TC-998).
|
|
20977
21042
|
*/
|
|
20978
21043
|
this.accountRegistryDeadlineMs = 3e4;
|
|
21044
|
+
/**
|
|
21045
|
+
* Incremented by every sign-out. A sign-in or restore records it when it
|
|
21046
|
+
* starts and does not establish its session once it has changed.
|
|
21047
|
+
*/
|
|
21048
|
+
this.sessionEpoch = 0;
|
|
21049
|
+
/**
|
|
21050
|
+
* Numbers sign-in and restore attempts. A cancelled attempt cleans up only
|
|
21051
|
+
* while it is still the latest, so it never ends a newer session.
|
|
21052
|
+
*/
|
|
21053
|
+
this.latestSessionAttempt = 0;
|
|
20979
21054
|
/**
|
|
20980
21055
|
* True when the last signIn() detected an interactive signer and skipped
|
|
20981
21056
|
* client-side bootstrap. Apps can read this to know whether bootstrap was
|
|
@@ -21109,54 +21184,17 @@ var _TinyCloudNode = class _TinyCloudNode {
|
|
|
21109
21184
|
"wasmBindings must be provided in config. Import from '@tinycloud/node-sdk' (not '/core') for automatic Node.js defaults."
|
|
21110
21185
|
);
|
|
21111
21186
|
}
|
|
21112
|
-
|
|
21113
|
-
|
|
21114
|
-
|
|
21115
|
-
|
|
21116
|
-
this.sessionKeyId = defaultKeyId;
|
|
21117
|
-
} else {
|
|
21118
|
-
this.sessionKeyId = this.sessionManager.createSessionKey(defaultKeyId);
|
|
21119
|
-
jwkStr = this.sessionManager.jwk(this.sessionKeyId);
|
|
21120
|
-
}
|
|
21121
|
-
if (!jwkStr) {
|
|
21122
|
-
throw new Error("Failed to get session key JWK");
|
|
21123
|
-
}
|
|
21124
|
-
this.sessionKeyJwk = JSON.parse(jwkStr);
|
|
21187
|
+
const sessionKey = createDefaultSessionKey(this.wasmBindings);
|
|
21188
|
+
this.sessionManager = sessionKey.manager;
|
|
21189
|
+
this.sessionKeyId = sessionKey.keyId;
|
|
21190
|
+
this.sessionKeyJwk = sessionKey.jwk;
|
|
21125
21191
|
this._serviceGraph = this.createServiceGraphLifetime();
|
|
21126
21192
|
this._capabilityRegistry = new CapabilityKeyRegistry();
|
|
21127
21193
|
this._keyProvider = new WasmKeyProvider({
|
|
21128
21194
|
sessionManager: this.sessionManager
|
|
21129
21195
|
});
|
|
21130
21196
|
this.notificationHandler = config.notificationHandler ?? new SilentNotificationHandler();
|
|
21131
|
-
|
|
21132
|
-
this._sharingService = new SharingService({
|
|
21133
|
-
hosts: [this.config.host],
|
|
21134
|
-
// session: undefined - not needed for receive()
|
|
21135
|
-
invoke: receiveOnlyGraph.invoke,
|
|
21136
|
-
fetch: receiveOnlyGraph.fetch,
|
|
21137
|
-
assertActive: () => receiveOnlyGraph.assertActive(),
|
|
21138
|
-
keyProvider: this._keyProvider,
|
|
21139
|
-
registry: this._capabilityRegistry,
|
|
21140
|
-
createDelegationWasm: (params) => this.createDelegationWrapper(params),
|
|
21141
|
-
computeCid: (data, codec) => {
|
|
21142
|
-
if (!this.wasmBindings.computeCid) throw new Error("computeCid is unavailable");
|
|
21143
|
-
return this.wasmBindings.computeCid(data, codec);
|
|
21144
|
-
},
|
|
21145
|
-
// delegationManager: undefined - not needed for receive()
|
|
21146
|
-
createKVService: (config2) => {
|
|
21147
|
-
const prefix = config2.pathPrefix?.replace(/\/$/, "");
|
|
21148
|
-
const kvService = new KVService2({ prefix });
|
|
21149
|
-
const kvContext = receiveOnlyGraph.track(new ServiceContext2({
|
|
21150
|
-
invoke: config2.invoke,
|
|
21151
|
-
fetch: config2.fetch ?? globalThis.fetch.bind(globalThis),
|
|
21152
|
-
hosts: config2.hosts,
|
|
21153
|
-
telemetry: this.config.telemetry
|
|
21154
|
-
}));
|
|
21155
|
-
kvContext.setSession(config2.session);
|
|
21156
|
-
kvService.initialize(kvContext);
|
|
21157
|
-
return kvService;
|
|
21158
|
-
}
|
|
21159
|
-
});
|
|
21197
|
+
this._sharingService = this.createReceiveOnlySharing();
|
|
21160
21198
|
if (config.signer) {
|
|
21161
21199
|
this.signer = config.signer;
|
|
21162
21200
|
this.setupAuth(config);
|
|
@@ -21298,6 +21336,42 @@ var _TinyCloudNode = class _TinyCloudNode {
|
|
|
21298
21336
|
get siweDomain() {
|
|
21299
21337
|
return this.config.domain ?? "app.tinycloud.xyz";
|
|
21300
21338
|
}
|
|
21339
|
+
/**
|
|
21340
|
+
* SharingService for receive-only access (no session required), bound to the
|
|
21341
|
+
* current service graph. This lets session-only users receive sharing links
|
|
21342
|
+
* without signIn(); full capabilities (generate) are added after signIn().
|
|
21343
|
+
*/
|
|
21344
|
+
createReceiveOnlySharing() {
|
|
21345
|
+
const receiveOnlyGraph = this._serviceGraph;
|
|
21346
|
+
return new SharingService({
|
|
21347
|
+
hosts: [this.config.host],
|
|
21348
|
+
// session: undefined - not needed for receive()
|
|
21349
|
+
invoke: receiveOnlyGraph.invoke,
|
|
21350
|
+
fetch: receiveOnlyGraph.fetch,
|
|
21351
|
+
assertActive: () => receiveOnlyGraph.assertActive(),
|
|
21352
|
+
keyProvider: this._keyProvider,
|
|
21353
|
+
registry: this._capabilityRegistry,
|
|
21354
|
+
createDelegationWasm: (params) => this.createDelegationWrapper(params),
|
|
21355
|
+
computeCid: (data, codec) => {
|
|
21356
|
+
if (!this.wasmBindings.computeCid) throw new Error("computeCid is unavailable");
|
|
21357
|
+
return this.wasmBindings.computeCid(data, codec);
|
|
21358
|
+
},
|
|
21359
|
+
// delegationManager: undefined - not needed for receive()
|
|
21360
|
+
createKVService: (config) => {
|
|
21361
|
+
const prefix = config.pathPrefix?.replace(/\/$/, "");
|
|
21362
|
+
const kvService = new KVService2({ prefix });
|
|
21363
|
+
const kvContext = receiveOnlyGraph.track(new ServiceContext2({
|
|
21364
|
+
invoke: config.invoke,
|
|
21365
|
+
fetch: config.fetch ?? globalThis.fetch.bind(globalThis),
|
|
21366
|
+
hosts: config.hosts,
|
|
21367
|
+
telemetry: this.config.telemetry
|
|
21368
|
+
}));
|
|
21369
|
+
kvContext.setSession(config.session);
|
|
21370
|
+
kvService.initialize(kvContext);
|
|
21371
|
+
return kvService;
|
|
21372
|
+
}
|
|
21373
|
+
});
|
|
21374
|
+
}
|
|
21301
21375
|
/**
|
|
21302
21376
|
* Set up authorization handler and TinyCloud instance.
|
|
21303
21377
|
* @internal
|
|
@@ -21557,6 +21631,102 @@ var _TinyCloudNode = class _TinyCloudNode {
|
|
|
21557
21631
|
get restorableSession() {
|
|
21558
21632
|
return this.currentTinyCloudSession();
|
|
21559
21633
|
}
|
|
21634
|
+
/**
|
|
21635
|
+
* Sign out and end the session on this instance.
|
|
21636
|
+
*
|
|
21637
|
+
* Every service built for the session (and every `useDelegation()` result)
|
|
21638
|
+
* is retired and the session key is replaced before anything is awaited, so
|
|
21639
|
+
* nothing captured from the session can sign once sign-out has started.
|
|
21640
|
+
* Pending work is aborted and the persisted session is cleared from the
|
|
21641
|
+
* configured session storage. Afterwards session accessors return
|
|
21642
|
+
* `undefined` and service calls fail with "Not signed in" until
|
|
21643
|
+
* {@link signIn} or {@link restoreSession}, which wait for a sign-out in
|
|
21644
|
+
* progress.
|
|
21645
|
+
*/
|
|
21646
|
+
signOut() {
|
|
21647
|
+
this.signOutInFlight ?? (this.signOutInFlight = this.endSession().finally(() => {
|
|
21648
|
+
this.signOutInFlight = void 0;
|
|
21649
|
+
}));
|
|
21650
|
+
return this.signOutInFlight;
|
|
21651
|
+
}
|
|
21652
|
+
async endSession() {
|
|
21653
|
+
const leavingAddress = this.address ?? this._restoredTcSession?.address;
|
|
21654
|
+
this.teardownSession();
|
|
21655
|
+
try {
|
|
21656
|
+
await this.accountRegistryTail;
|
|
21657
|
+
if (this.replicationRuntime) await (await this.replicationRuntime).unbind();
|
|
21658
|
+
} finally {
|
|
21659
|
+
if (leavingAddress) await this.clearPersistedSessionFor(leavingAddress);
|
|
21660
|
+
}
|
|
21661
|
+
}
|
|
21662
|
+
/**
|
|
21663
|
+
* Synchronously drop every piece of in-memory session authority and
|
|
21664
|
+
* invalidate sign-ins and restores still in flight (see `sessionEpoch`).
|
|
21665
|
+
*/
|
|
21666
|
+
teardownSession() {
|
|
21667
|
+
this.sessionEpoch++;
|
|
21668
|
+
this.pendingAccountRegistrySync?.controller.abort();
|
|
21669
|
+
const oldGraph = this._serviceGraph;
|
|
21670
|
+
const oldCore = this.tc;
|
|
21671
|
+
const sessionKey = createDefaultSessionKey(this.wasmBindings);
|
|
21672
|
+
this.sessionManager = sessionKey.manager;
|
|
21673
|
+
this.sessionKeyId = sessionKey.keyId;
|
|
21674
|
+
this.sessionKeyJwk = sessionKey.jwk;
|
|
21675
|
+
this.auth?.resetSession(
|
|
21676
|
+
sessionKey.manager,
|
|
21677
|
+
sessionKey.keyId,
|
|
21678
|
+
this.explicitHost ? [this.explicitHost] : void 0
|
|
21679
|
+
);
|
|
21680
|
+
this.config.host = this.explicitHost ?? DEFAULT_HOST;
|
|
21681
|
+
this._address = void 0;
|
|
21682
|
+
this._chainId = 1;
|
|
21683
|
+
this._restoredTcSession = void 0;
|
|
21684
|
+
this._restoredNodeFeatures = void 0;
|
|
21685
|
+
this._activeServiceSession = void 0;
|
|
21686
|
+
this._serviceContext = void 0;
|
|
21687
|
+
this._kv = void 0;
|
|
21688
|
+
this._sql = void 0;
|
|
21689
|
+
this._duckdb = void 0;
|
|
21690
|
+
this._hooks = void 0;
|
|
21691
|
+
this._vault = void 0;
|
|
21692
|
+
this._encryption = void 0;
|
|
21693
|
+
this._baseVaults.clear();
|
|
21694
|
+
this._baseSecrets.clear();
|
|
21695
|
+
this._secrets.clear();
|
|
21696
|
+
this._account = void 0;
|
|
21697
|
+
this._publicKV = void 0;
|
|
21698
|
+
this._delegationManager = void 0;
|
|
21699
|
+
this._spaceService = void 0;
|
|
21700
|
+
this.runtimePermissionGrants = [];
|
|
21701
|
+
this._recapOperationsCache = void 0;
|
|
21702
|
+
this.confirmedHostedSpaceIds.clear();
|
|
21703
|
+
this.hostedOwnedSpaceIds.clear();
|
|
21704
|
+
this.cancelOwnedSpaceHosts();
|
|
21705
|
+
this.storageFull.clear();
|
|
21706
|
+
this._bootstrapSkipped = false;
|
|
21707
|
+
this._bootstrapStatus = { skipped: false };
|
|
21708
|
+
this.replicationDelegateSession = void 0;
|
|
21709
|
+
this.replicationScopeError = void 0;
|
|
21710
|
+
this._serviceGraph = this.createServiceGraphLifetime();
|
|
21711
|
+
oldGraph.retire();
|
|
21712
|
+
this.tc = this.auth ? new TinyCloud(this.auth, {
|
|
21713
|
+
invokeAny: this.invokeAnyWithRuntimePermissions,
|
|
21714
|
+
telemetry: this.config.telemetry
|
|
21715
|
+
}) : null;
|
|
21716
|
+
oldCore?.retireServices();
|
|
21717
|
+
this._capabilityRegistry = new CapabilityKeyRegistry();
|
|
21718
|
+
this._keyProvider = new WasmKeyProvider({ sessionManager: this.sessionManager });
|
|
21719
|
+
this._sharingService = this.createReceiveOnlySharing();
|
|
21720
|
+
}
|
|
21721
|
+
async clearPersistedSessionFor(address) {
|
|
21722
|
+
await (this.auth ? this.auth.clearPersistedSession(address) : this.config.sessionStorage?.clear(address));
|
|
21723
|
+
}
|
|
21724
|
+
/** Throws when a sign-out started after `epoch` was read. */
|
|
21725
|
+
assertSessionEpoch(epoch, operation) {
|
|
21726
|
+
if (epoch !== this.sessionEpoch) {
|
|
21727
|
+
throw new Error(`${operation} was cancelled by sign-out.`);
|
|
21728
|
+
}
|
|
21729
|
+
}
|
|
21560
21730
|
/**
|
|
21561
21731
|
* Sign in and create a new session.
|
|
21562
21732
|
* This creates the user's space if it doesn't exist.
|
|
@@ -21570,11 +21740,28 @@ var _TinyCloudNode = class _TinyCloudNode {
|
|
|
21570
21740
|
"Cannot signIn() in session-only mode. Provide a privateKey in config to create your own space."
|
|
21571
21741
|
);
|
|
21572
21742
|
}
|
|
21743
|
+
const epoch = this.sessionEpoch;
|
|
21744
|
+
const attempt = ++this.latestSessionAttempt;
|
|
21745
|
+
await this.signOutInFlight;
|
|
21746
|
+
try {
|
|
21747
|
+
await this.establishSignIn(epoch, options);
|
|
21748
|
+
} catch (error) {
|
|
21749
|
+
if (epoch !== this.sessionEpoch && attempt === this.latestSessionAttempt) {
|
|
21750
|
+
await this.endSession();
|
|
21751
|
+
}
|
|
21752
|
+
throw error;
|
|
21753
|
+
}
|
|
21754
|
+
}
|
|
21755
|
+
async establishSignIn(epoch, options) {
|
|
21756
|
+
if (!this.signer || !this.tc) {
|
|
21757
|
+
throw new Error("Not signed in. Call signIn() first.");
|
|
21758
|
+
}
|
|
21573
21759
|
this.pendingAccountRegistrySync?.controller.abort();
|
|
21574
21760
|
await this.accountRegistryTail;
|
|
21575
21761
|
await this.wasmBindings.ensureInitialized?.();
|
|
21576
21762
|
const address = canonicalizeAddress2(await this.signer.getAddress());
|
|
21577
21763
|
const chainId = await this.signer.getChainId();
|
|
21764
|
+
this.assertSessionEpoch(epoch, "Sign-in");
|
|
21578
21765
|
if (address !== this._address || chainId !== this._chainId) this.storageFull.clear();
|
|
21579
21766
|
this._address = address;
|
|
21580
21767
|
this._chainId = chainId;
|
|
@@ -21593,6 +21780,7 @@ var _TinyCloudNode = class _TinyCloudNode {
|
|
|
21593
21780
|
this.confirmedHostedSpaceIds.clear();
|
|
21594
21781
|
this.hostedOwnedSpaceIds.clear();
|
|
21595
21782
|
await this.tc.signIn(options);
|
|
21783
|
+
this.assertSessionEpoch(epoch, "Sign-in");
|
|
21596
21784
|
this.cancelOwnedSpaceHosts();
|
|
21597
21785
|
this.syncResolvedHostFromAuth();
|
|
21598
21786
|
for (const spaceId of this.auth.lastActivationActivatedSpaceIds ?? []) {
|
|
@@ -21601,6 +21789,7 @@ var _TinyCloudNode = class _TinyCloudNode {
|
|
|
21601
21789
|
this.replicationDelegateSession = void 0;
|
|
21602
21790
|
this.replicationScopeError = void 0;
|
|
21603
21791
|
if (this.replicationRuntime) await (await this.replicationRuntime).unbind();
|
|
21792
|
+
this.assertSessionEpoch(epoch, "Sign-in");
|
|
21604
21793
|
const oldGraph = this._serviceGraph;
|
|
21605
21794
|
this._serviceGraph = this.createServiceGraphLifetime();
|
|
21606
21795
|
oldGraph.retire();
|
|
@@ -21611,15 +21800,19 @@ var _TinyCloudNode = class _TinyCloudNode {
|
|
|
21611
21800
|
this.sessionKeyJwk = signedInSession.jwk;
|
|
21612
21801
|
}
|
|
21613
21802
|
await this.initializeServices();
|
|
21803
|
+
this.assertSessionEpoch(epoch, "Sign-in");
|
|
21614
21804
|
const primarySession = this.currentTinyCloudSession();
|
|
21615
21805
|
if (primarySession) {
|
|
21616
21806
|
this.registerPrimarySessionGrant(primarySession);
|
|
21617
21807
|
}
|
|
21618
21808
|
const bootstrapped = await this.bootstrapAccountIfNeeded();
|
|
21809
|
+
this.assertSessionEpoch(epoch, "Sign-in");
|
|
21619
21810
|
await this.ensureRequestedEncryptionNetworks();
|
|
21811
|
+
this.assertSessionEpoch(epoch, "Sign-in");
|
|
21620
21812
|
if (!bootstrapped && this.config.manifest === void 0 && this.config.capabilityRequest === void 0) {
|
|
21621
21813
|
await this.ensureOwnedSpaceHostedById(this.ownedSpaceId(SECRETS_SPACE2));
|
|
21622
21814
|
}
|
|
21815
|
+
this.assertSessionEpoch(epoch, "Sign-in");
|
|
21623
21816
|
if (!bootstrapped) {
|
|
21624
21817
|
this.scheduleAccountRegistrySync();
|
|
21625
21818
|
}
|
|
@@ -21801,6 +21994,7 @@ var _TinyCloudNode = class _TinyCloudNode {
|
|
|
21801
21994
|
throw new Error("Account bootstrap requires a TinyCloud host");
|
|
21802
21995
|
}
|
|
21803
21996
|
const auth = this.auth;
|
|
21997
|
+
const graph = this._serviceGraph;
|
|
21804
21998
|
const sessions = /* @__PURE__ */ new Map();
|
|
21805
21999
|
const rawAbilitiesBySpace = /* @__PURE__ */ new Map();
|
|
21806
22000
|
const warnings = [];
|
|
@@ -21809,6 +22003,7 @@ var _TinyCloudNode = class _TinyCloudNode {
|
|
|
21809
22003
|
const canReusePrimaryBootstrapSession = primarySession?.spaceId === defaultSpaceId && auth.capabilityRequest === BOOTSTRAP_SESSION_REQUESTS.default;
|
|
21810
22004
|
for (const step of steps) {
|
|
21811
22005
|
if (step.kind !== "session") continue;
|
|
22006
|
+
graph.assertActive();
|
|
21812
22007
|
if (step.space === "default" && canReusePrimaryBootstrapSession && primarySession) {
|
|
21813
22008
|
sessions.set(step.space, primarySession);
|
|
21814
22009
|
continue;
|
|
@@ -21836,6 +22031,7 @@ var _TinyCloudNode = class _TinyCloudNode {
|
|
|
21836
22031
|
}
|
|
21837
22032
|
for (const step of steps) {
|
|
21838
22033
|
if (step.kind !== "host") continue;
|
|
22034
|
+
graph.assertActive();
|
|
21839
22035
|
const hosted = await auth.hostOwnedSpaceResult(step.spaceId, "bootstrap-host");
|
|
21840
22036
|
if (!hosted.success) {
|
|
21841
22037
|
throw Object.assign(
|
|
@@ -21847,11 +22043,16 @@ var _TinyCloudNode = class _TinyCloudNode {
|
|
|
21847
22043
|
await new Promise((resolve) => setTimeout(resolve, 100));
|
|
21848
22044
|
for (const step of steps) {
|
|
21849
22045
|
if (step.kind !== "activate") continue;
|
|
22046
|
+
graph.assertActive();
|
|
21850
22047
|
const session = sessions.get(step.space);
|
|
21851
22048
|
if (!session) {
|
|
21852
22049
|
throw new Error(`Missing bootstrap session for ${step.space}`);
|
|
21853
22050
|
}
|
|
21854
|
-
const activated = await activateSessionWithHost2(host, session.delegationHeader)
|
|
22051
|
+
const activated = await activateSessionWithHost2(host, session.delegationHeader, graph.signal).catch((error) => {
|
|
22052
|
+
graph.assertActive();
|
|
22053
|
+
throw error;
|
|
22054
|
+
});
|
|
22055
|
+
graph.assertActive();
|
|
21855
22056
|
if (!activated.success || activated.skipped?.includes(step.spaceId)) {
|
|
21856
22057
|
throw Object.assign(
|
|
21857
22058
|
new Error(
|
|
@@ -21867,6 +22068,7 @@ var _TinyCloudNode = class _TinyCloudNode {
|
|
|
21867
22068
|
);
|
|
21868
22069
|
}
|
|
21869
22070
|
for (const step of steps) {
|
|
22071
|
+
graph.assertActive();
|
|
21870
22072
|
if (step.kind === "account-index-schema") {
|
|
21871
22073
|
const ensured = await this.account.index.ensure();
|
|
21872
22074
|
if (!ensured.ok) {
|
|
@@ -22642,6 +22844,9 @@ var _TinyCloudNode = class _TinyCloudNode {
|
|
|
22642
22844
|
* @param sessionData - The stored delegation data from the browser flow
|
|
22643
22845
|
*/
|
|
22644
22846
|
async restoreSession(sessionData) {
|
|
22847
|
+
const epoch = this.sessionEpoch;
|
|
22848
|
+
const attempt = ++this.latestSessionAttempt;
|
|
22849
|
+
await this.signOutInFlight;
|
|
22645
22850
|
await this.wasmBindings.ensureInitialized?.();
|
|
22646
22851
|
let restoredJwk;
|
|
22647
22852
|
try {
|
|
@@ -22831,6 +23036,7 @@ var _TinyCloudNode = class _TinyCloudNode {
|
|
|
22831
23036
|
});
|
|
22832
23037
|
this.pendingAccountRegistrySync?.controller.abort();
|
|
22833
23038
|
await this.accountRegistryTail;
|
|
23039
|
+
this.assertSessionEpoch(epoch, "Session restore");
|
|
22834
23040
|
const oldGraph = this._serviceGraph;
|
|
22835
23041
|
const oldCore = this.tc;
|
|
22836
23042
|
this.sessionManager = stagedManager;
|
|
@@ -22876,6 +23082,12 @@ var _TinyCloudNode = class _TinyCloudNode {
|
|
|
22876
23082
|
this.replicationDelegateSession = compactReplicationSession;
|
|
22877
23083
|
this.replicationScopeError = replicationScopeError;
|
|
22878
23084
|
if (this.replicationRuntime) await (await this.replicationRuntime).unbind();
|
|
23085
|
+
if (epoch !== this.sessionEpoch) {
|
|
23086
|
+
oldGraph.retire();
|
|
23087
|
+
oldCore?.retireServices?.();
|
|
23088
|
+
if (attempt === this.latestSessionAttempt) await this.endSession();
|
|
23089
|
+
this.assertSessionEpoch(epoch, "Session restore");
|
|
23090
|
+
}
|
|
22879
23091
|
oldGraph.retire();
|
|
22880
23092
|
if (replicationScopeError) {
|
|
22881
23093
|
stagedGraph.serviceContext.emit("replication.state", {
|
|
@@ -22886,6 +23098,10 @@ var _TinyCloudNode = class _TinyCloudNode {
|
|
|
22886
23098
|
}
|
|
22887
23099
|
await this.bindReplicationRuntime(stagedGraph.serviceContext, serviceSession, stagedGraph.kv, replicationPrincipal);
|
|
22888
23100
|
oldCore?.retireServices?.();
|
|
23101
|
+
if (epoch !== this.sessionEpoch) {
|
|
23102
|
+
if (attempt === this.latestSessionAttempt) await this.endSession();
|
|
23103
|
+
this.assertSessionEpoch(epoch, "Session restore");
|
|
23104
|
+
}
|
|
22889
23105
|
}
|
|
22890
23106
|
stagePrimarySessionState(session, verificationMethod, host, sessionExpiry, recap) {
|
|
22891
23107
|
if (!session?.siwe) return { cache: void 0, grants: [] };
|
|
@@ -24744,6 +24960,7 @@ var _TinyCloudNode = class _TinyCloudNode {
|
|
|
24744
24960
|
* matching service calls and downstream `delegateTo()` calls can use it.
|
|
24745
24961
|
*/
|
|
24746
24962
|
async useRuntimeDelegation(delegation) {
|
|
24963
|
+
const graph = this._serviceGraph;
|
|
24747
24964
|
const session = this.currentTinyCloudSession();
|
|
24748
24965
|
if (!session) {
|
|
24749
24966
|
throw new SessionExpiredError(/* @__PURE__ */ new Date(0));
|
|
@@ -24762,9 +24979,11 @@ var _TinyCloudNode = class _TinyCloudNode {
|
|
|
24762
24979
|
try {
|
|
24763
24980
|
activateResult = await activateSessionWithHost2(
|
|
24764
24981
|
targetHost,
|
|
24765
|
-
delegation.delegationHeader
|
|
24982
|
+
delegation.delegationHeader,
|
|
24983
|
+
graph.signal
|
|
24766
24984
|
);
|
|
24767
24985
|
} catch (cause) {
|
|
24986
|
+
graph.assertActive();
|
|
24768
24987
|
throw Object.assign(
|
|
24769
24988
|
new Error("The TinyCloud host could not be reached to activate the delegation."),
|
|
24770
24989
|
{ code: "ACTIVATION_TRANSPORT_FAILED", cause }
|
|
@@ -24784,6 +25003,7 @@ var _TinyCloudNode = class _TinyCloudNode {
|
|
|
24784
25003
|
{ cause: activateResult }
|
|
24785
25004
|
);
|
|
24786
25005
|
}
|
|
25006
|
+
graph.assertActive();
|
|
24787
25007
|
this.runtimePermissionGrants = this.runtimePermissionGrants.filter(
|
|
24788
25008
|
(grant) => grant.delegation.cid !== delegation.cid
|
|
24789
25009
|
);
|
|
@@ -24800,6 +25020,7 @@ var _TinyCloudNode = class _TinyCloudNode {
|
|
|
24800
25020
|
if (!Array.isArray(permissions) || permissions.length === 0) {
|
|
24801
25021
|
throw new Error("grantRuntimePermissions requires a non-empty permissions array");
|
|
24802
25022
|
}
|
|
25023
|
+
const graph = this._serviceGraph;
|
|
24803
25024
|
const session = this.currentTinyCloudSession();
|
|
24804
25025
|
if (!session) {
|
|
24805
25026
|
throw new SessionExpiredError(/* @__PURE__ */ new Date(0));
|
|
@@ -24880,14 +25101,19 @@ var _TinyCloudNode = class _TinyCloudNode {
|
|
|
24880
25101
|
}
|
|
24881
25102
|
})();
|
|
24882
25103
|
const signature2 = await this.signer.signMessage(prepared.siwe);
|
|
25104
|
+
graph.assertActive();
|
|
24883
25105
|
const delegatedSession = this.wasmBindings.completeSessionSetup({
|
|
24884
25106
|
...prepared,
|
|
24885
25107
|
signature: signature2
|
|
24886
25108
|
});
|
|
24887
25109
|
const activateResult = await activateSessionWithHost2(
|
|
24888
25110
|
this.config.host,
|
|
24889
|
-
delegatedSession.delegationHeader
|
|
24890
|
-
|
|
25111
|
+
delegatedSession.delegationHeader,
|
|
25112
|
+
graph.signal
|
|
25113
|
+
).catch((error) => {
|
|
25114
|
+
graph.assertActive();
|
|
25115
|
+
throw error;
|
|
25116
|
+
});
|
|
24891
25117
|
if (!activateResult.success) {
|
|
24892
25118
|
if (rawForDelegation.some((entry) => this.isRawRevocationPermissionEntry(entry)) && activateResult.status === 401 && /Cannot find parent delegation/i.test(activateResult.error ?? "")) {
|
|
24893
25119
|
throw Object.assign(
|
|
@@ -24908,6 +25134,7 @@ var _TinyCloudNode = class _TinyCloudNode {
|
|
|
24908
25134
|
expiresAt,
|
|
24909
25135
|
{ siwe: prepared.siwe, signature: signature2 }
|
|
24910
25136
|
);
|
|
25137
|
+
graph.assertActive();
|
|
24911
25138
|
this.runtimePermissionGrants.push({
|
|
24912
25139
|
session: {
|
|
24913
25140
|
delegationHeader: delegatedSession.delegationHeader,
|
|
@@ -26371,6 +26598,7 @@ var _TinyCloudNode = class _TinyCloudNode {
|
|
|
26371
26598
|
* @returns A DelegatedAccess instance for performing operations
|
|
26372
26599
|
*/
|
|
26373
26600
|
async useDelegation(delegation) {
|
|
26601
|
+
const graph = this._serviceGraph;
|
|
26374
26602
|
const delegationHeader = delegation.delegationHeader;
|
|
26375
26603
|
const targetHost = delegation.host ?? this.config.host;
|
|
26376
26604
|
if (this.isSessionOnly) {
|
|
@@ -26412,7 +26640,8 @@ var _TinyCloudNode = class _TinyCloudNode {
|
|
|
26412
26640
|
targetHost,
|
|
26413
26641
|
this.wasmBindings.invoke,
|
|
26414
26642
|
this.wasmBindings.invokeAny,
|
|
26415
|
-
this.config.telemetry
|
|
26643
|
+
this.config.telemetry,
|
|
26644
|
+
graph
|
|
26416
26645
|
);
|
|
26417
26646
|
}
|
|
26418
26647
|
const mySession = this.auth?.tinyCloudSession;
|
|
@@ -26436,14 +26665,19 @@ var _TinyCloudNode = class _TinyCloudNode {
|
|
|
26436
26665
|
...Object.keys(rawAbilities).length > 0 ? { rawAbilities } : {}
|
|
26437
26666
|
});
|
|
26438
26667
|
const signature2 = await this.signer.signMessage(prepared.siwe);
|
|
26668
|
+
graph.assertActive();
|
|
26439
26669
|
const invokerSession = this.wasmBindings.completeSessionSetup({
|
|
26440
26670
|
...prepared,
|
|
26441
26671
|
signature: signature2
|
|
26442
26672
|
});
|
|
26443
26673
|
const activateResult = await activateSessionWithHost2(
|
|
26444
26674
|
targetHost,
|
|
26445
|
-
invokerSession.delegationHeader
|
|
26446
|
-
|
|
26675
|
+
invokerSession.delegationHeader,
|
|
26676
|
+
graph.signal
|
|
26677
|
+
).catch((error) => {
|
|
26678
|
+
graph.assertActive();
|
|
26679
|
+
throw error;
|
|
26680
|
+
});
|
|
26447
26681
|
if (!activateResult.success) {
|
|
26448
26682
|
throw Object.assign(
|
|
26449
26683
|
new Error(`Failed to activate delegated session: ${describeHostFailure2(activateResult)}`),
|
|
@@ -26462,6 +26696,7 @@ var _TinyCloudNode = class _TinyCloudNode {
|
|
|
26462
26696
|
siwe: prepared.siwe,
|
|
26463
26697
|
signature: signature2
|
|
26464
26698
|
};
|
|
26699
|
+
graph.assertActive();
|
|
26465
26700
|
this.trackReceivedDelegation(delegation, jwk);
|
|
26466
26701
|
this.installRuntimeGrantFromServiceSession(
|
|
26467
26702
|
delegation,
|
|
@@ -26480,7 +26715,8 @@ var _TinyCloudNode = class _TinyCloudNode {
|
|
|
26480
26715
|
targetHost,
|
|
26481
26716
|
this.wasmBindings.invoke,
|
|
26482
26717
|
this.wasmBindings.invokeAny,
|
|
26483
|
-
this.config.telemetry
|
|
26718
|
+
this.config.telemetry,
|
|
26719
|
+
graph
|
|
26484
26720
|
);
|
|
26485
26721
|
}
|
|
26486
26722
|
/**
|