@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/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,115 @@ 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
|
+
const leavingAuth = this.auth;
|
|
21655
|
+
try {
|
|
21656
|
+
this.teardownSession();
|
|
21657
|
+
} finally {
|
|
21658
|
+
try {
|
|
21659
|
+
await this.accountRegistryTail;
|
|
21660
|
+
if (this.replicationRuntime) await (await this.replicationRuntime).unbind();
|
|
21661
|
+
} finally {
|
|
21662
|
+
if (leavingAddress) {
|
|
21663
|
+
await (leavingAuth ? leavingAuth.clearPersistedSession(leavingAddress) : this.config.sessionStorage?.clear(leavingAddress));
|
|
21664
|
+
}
|
|
21665
|
+
}
|
|
21666
|
+
}
|
|
21667
|
+
}
|
|
21668
|
+
/**
|
|
21669
|
+
* Synchronously drop every piece of in-memory session authority and
|
|
21670
|
+
* invalidate sign-ins and restores still in flight (see `sessionEpoch`).
|
|
21671
|
+
*/
|
|
21672
|
+
teardownSession() {
|
|
21673
|
+
this.sessionEpoch++;
|
|
21674
|
+
this.pendingAccountRegistrySync?.controller.abort();
|
|
21675
|
+
const oldGraph = this._serviceGraph;
|
|
21676
|
+
const oldCore = this.tc;
|
|
21677
|
+
const oldAuth = this.auth;
|
|
21678
|
+
this.auth = null;
|
|
21679
|
+
this.tc = null;
|
|
21680
|
+
this._address = void 0;
|
|
21681
|
+
this._restoredTcSession = void 0;
|
|
21682
|
+
this._activeServiceSession = void 0;
|
|
21683
|
+
oldGraph.retire();
|
|
21684
|
+
oldCore?.retireServices();
|
|
21685
|
+
oldAuth?.resetSession(
|
|
21686
|
+
this.sessionManager,
|
|
21687
|
+
this.sessionKeyId,
|
|
21688
|
+
this.explicitHost ? [this.explicitHost] : void 0
|
|
21689
|
+
);
|
|
21690
|
+
this.config.host = this.explicitHost ?? DEFAULT_HOST;
|
|
21691
|
+
this._chainId = 1;
|
|
21692
|
+
this._restoredNodeFeatures = void 0;
|
|
21693
|
+
this._activeServiceSession = void 0;
|
|
21694
|
+
this._serviceContext = void 0;
|
|
21695
|
+
this._kv = void 0;
|
|
21696
|
+
this._sql = void 0;
|
|
21697
|
+
this._duckdb = void 0;
|
|
21698
|
+
this._hooks = void 0;
|
|
21699
|
+
this._vault = void 0;
|
|
21700
|
+
this._encryption = void 0;
|
|
21701
|
+
this._baseVaults.clear();
|
|
21702
|
+
this._baseSecrets.clear();
|
|
21703
|
+
this._secrets.clear();
|
|
21704
|
+
this._account = void 0;
|
|
21705
|
+
this._publicKV = void 0;
|
|
21706
|
+
this._delegationManager = void 0;
|
|
21707
|
+
this._spaceService = void 0;
|
|
21708
|
+
this.runtimePermissionGrants = [];
|
|
21709
|
+
this._recapOperationsCache = void 0;
|
|
21710
|
+
this.confirmedHostedSpaceIds.clear();
|
|
21711
|
+
this.hostedOwnedSpaceIds.clear();
|
|
21712
|
+
this.cancelOwnedSpaceHosts();
|
|
21713
|
+
this.storageFull.clear();
|
|
21714
|
+
this._bootstrapSkipped = false;
|
|
21715
|
+
this._bootstrapStatus = { skipped: false };
|
|
21716
|
+
this.replicationDelegateSession = void 0;
|
|
21717
|
+
this.replicationScopeError = void 0;
|
|
21718
|
+
const sessionKey = createDefaultSessionKey(this.wasmBindings);
|
|
21719
|
+
this.sessionManager = sessionKey.manager;
|
|
21720
|
+
this.sessionKeyId = sessionKey.keyId;
|
|
21721
|
+
this.sessionKeyJwk = sessionKey.jwk;
|
|
21722
|
+
oldAuth?.resetSession(
|
|
21723
|
+
sessionKey.manager,
|
|
21724
|
+
sessionKey.keyId,
|
|
21725
|
+
this.explicitHost ? [this.explicitHost] : void 0
|
|
21726
|
+
);
|
|
21727
|
+
this._serviceGraph = this.createServiceGraphLifetime();
|
|
21728
|
+
this.auth = oldAuth;
|
|
21729
|
+
this.tc = this.auth ? new TinyCloud(this.auth, {
|
|
21730
|
+
invokeAny: this.invokeAnyWithRuntimePermissions,
|
|
21731
|
+
telemetry: this.config.telemetry
|
|
21732
|
+
}) : null;
|
|
21733
|
+
this._capabilityRegistry = new CapabilityKeyRegistry();
|
|
21734
|
+
this._keyProvider = new WasmKeyProvider({ sessionManager: this.sessionManager });
|
|
21735
|
+
this._sharingService = this.createReceiveOnlySharing();
|
|
21736
|
+
}
|
|
21737
|
+
/** Throws when a sign-out started after `epoch` was read. */
|
|
21738
|
+
assertSessionEpoch(epoch, operation) {
|
|
21739
|
+
if (epoch !== this.sessionEpoch) {
|
|
21740
|
+
throw new Error(`${operation} was cancelled by sign-out.`);
|
|
21741
|
+
}
|
|
21742
|
+
}
|
|
21560
21743
|
/**
|
|
21561
21744
|
* Sign in and create a new session.
|
|
21562
21745
|
* This creates the user's space if it doesn't exist.
|
|
@@ -21570,11 +21753,28 @@ var _TinyCloudNode = class _TinyCloudNode {
|
|
|
21570
21753
|
"Cannot signIn() in session-only mode. Provide a privateKey in config to create your own space."
|
|
21571
21754
|
);
|
|
21572
21755
|
}
|
|
21756
|
+
const epoch = this.sessionEpoch;
|
|
21757
|
+
const attempt = ++this.latestSessionAttempt;
|
|
21758
|
+
await this.signOutInFlight;
|
|
21759
|
+
try {
|
|
21760
|
+
await this.establishSignIn(epoch, options);
|
|
21761
|
+
} catch (error) {
|
|
21762
|
+
if (epoch !== this.sessionEpoch && attempt === this.latestSessionAttempt) {
|
|
21763
|
+
await this.endSession();
|
|
21764
|
+
}
|
|
21765
|
+
throw error;
|
|
21766
|
+
}
|
|
21767
|
+
}
|
|
21768
|
+
async establishSignIn(epoch, options) {
|
|
21769
|
+
if (!this.signer || !this.tc) {
|
|
21770
|
+
throw new Error("Not signed in. Call signIn() first.");
|
|
21771
|
+
}
|
|
21573
21772
|
this.pendingAccountRegistrySync?.controller.abort();
|
|
21574
21773
|
await this.accountRegistryTail;
|
|
21575
21774
|
await this.wasmBindings.ensureInitialized?.();
|
|
21576
21775
|
const address = canonicalizeAddress2(await this.signer.getAddress());
|
|
21577
21776
|
const chainId = await this.signer.getChainId();
|
|
21777
|
+
this.assertSessionEpoch(epoch, "Sign-in");
|
|
21578
21778
|
if (address !== this._address || chainId !== this._chainId) this.storageFull.clear();
|
|
21579
21779
|
this._address = address;
|
|
21580
21780
|
this._chainId = chainId;
|
|
@@ -21593,6 +21793,7 @@ var _TinyCloudNode = class _TinyCloudNode {
|
|
|
21593
21793
|
this.confirmedHostedSpaceIds.clear();
|
|
21594
21794
|
this.hostedOwnedSpaceIds.clear();
|
|
21595
21795
|
await this.tc.signIn(options);
|
|
21796
|
+
this.assertSessionEpoch(epoch, "Sign-in");
|
|
21596
21797
|
this.cancelOwnedSpaceHosts();
|
|
21597
21798
|
this.syncResolvedHostFromAuth();
|
|
21598
21799
|
for (const spaceId of this.auth.lastActivationActivatedSpaceIds ?? []) {
|
|
@@ -21601,6 +21802,7 @@ var _TinyCloudNode = class _TinyCloudNode {
|
|
|
21601
21802
|
this.replicationDelegateSession = void 0;
|
|
21602
21803
|
this.replicationScopeError = void 0;
|
|
21603
21804
|
if (this.replicationRuntime) await (await this.replicationRuntime).unbind();
|
|
21805
|
+
this.assertSessionEpoch(epoch, "Sign-in");
|
|
21604
21806
|
const oldGraph = this._serviceGraph;
|
|
21605
21807
|
this._serviceGraph = this.createServiceGraphLifetime();
|
|
21606
21808
|
oldGraph.retire();
|
|
@@ -21611,15 +21813,19 @@ var _TinyCloudNode = class _TinyCloudNode {
|
|
|
21611
21813
|
this.sessionKeyJwk = signedInSession.jwk;
|
|
21612
21814
|
}
|
|
21613
21815
|
await this.initializeServices();
|
|
21816
|
+
this.assertSessionEpoch(epoch, "Sign-in");
|
|
21614
21817
|
const primarySession = this.currentTinyCloudSession();
|
|
21615
21818
|
if (primarySession) {
|
|
21616
21819
|
this.registerPrimarySessionGrant(primarySession);
|
|
21617
21820
|
}
|
|
21618
21821
|
const bootstrapped = await this.bootstrapAccountIfNeeded();
|
|
21822
|
+
this.assertSessionEpoch(epoch, "Sign-in");
|
|
21619
21823
|
await this.ensureRequestedEncryptionNetworks();
|
|
21824
|
+
this.assertSessionEpoch(epoch, "Sign-in");
|
|
21620
21825
|
if (!bootstrapped && this.config.manifest === void 0 && this.config.capabilityRequest === void 0) {
|
|
21621
21826
|
await this.ensureOwnedSpaceHostedById(this.ownedSpaceId(SECRETS_SPACE2));
|
|
21622
21827
|
}
|
|
21828
|
+
this.assertSessionEpoch(epoch, "Sign-in");
|
|
21623
21829
|
if (!bootstrapped) {
|
|
21624
21830
|
this.scheduleAccountRegistrySync();
|
|
21625
21831
|
}
|
|
@@ -21801,6 +22007,7 @@ var _TinyCloudNode = class _TinyCloudNode {
|
|
|
21801
22007
|
throw new Error("Account bootstrap requires a TinyCloud host");
|
|
21802
22008
|
}
|
|
21803
22009
|
const auth = this.auth;
|
|
22010
|
+
const graph = this._serviceGraph;
|
|
21804
22011
|
const sessions = /* @__PURE__ */ new Map();
|
|
21805
22012
|
const rawAbilitiesBySpace = /* @__PURE__ */ new Map();
|
|
21806
22013
|
const warnings = [];
|
|
@@ -21809,6 +22016,7 @@ var _TinyCloudNode = class _TinyCloudNode {
|
|
|
21809
22016
|
const canReusePrimaryBootstrapSession = primarySession?.spaceId === defaultSpaceId && auth.capabilityRequest === BOOTSTRAP_SESSION_REQUESTS.default;
|
|
21810
22017
|
for (const step of steps) {
|
|
21811
22018
|
if (step.kind !== "session") continue;
|
|
22019
|
+
graph.assertActive();
|
|
21812
22020
|
if (step.space === "default" && canReusePrimaryBootstrapSession && primarySession) {
|
|
21813
22021
|
sessions.set(step.space, primarySession);
|
|
21814
22022
|
continue;
|
|
@@ -21836,6 +22044,7 @@ var _TinyCloudNode = class _TinyCloudNode {
|
|
|
21836
22044
|
}
|
|
21837
22045
|
for (const step of steps) {
|
|
21838
22046
|
if (step.kind !== "host") continue;
|
|
22047
|
+
graph.assertActive();
|
|
21839
22048
|
const hosted = await auth.hostOwnedSpaceResult(step.spaceId, "bootstrap-host");
|
|
21840
22049
|
if (!hosted.success) {
|
|
21841
22050
|
throw Object.assign(
|
|
@@ -21847,11 +22056,16 @@ var _TinyCloudNode = class _TinyCloudNode {
|
|
|
21847
22056
|
await new Promise((resolve) => setTimeout(resolve, 100));
|
|
21848
22057
|
for (const step of steps) {
|
|
21849
22058
|
if (step.kind !== "activate") continue;
|
|
22059
|
+
graph.assertActive();
|
|
21850
22060
|
const session = sessions.get(step.space);
|
|
21851
22061
|
if (!session) {
|
|
21852
22062
|
throw new Error(`Missing bootstrap session for ${step.space}`);
|
|
21853
22063
|
}
|
|
21854
|
-
const activated = await activateSessionWithHost2(host, session.delegationHeader)
|
|
22064
|
+
const activated = await activateSessionWithHost2(host, session.delegationHeader, graph.signal).catch((error) => {
|
|
22065
|
+
graph.assertActive();
|
|
22066
|
+
throw error;
|
|
22067
|
+
});
|
|
22068
|
+
graph.assertActive();
|
|
21855
22069
|
if (!activated.success || activated.skipped?.includes(step.spaceId)) {
|
|
21856
22070
|
throw Object.assign(
|
|
21857
22071
|
new Error(
|
|
@@ -21867,6 +22081,7 @@ var _TinyCloudNode = class _TinyCloudNode {
|
|
|
21867
22081
|
);
|
|
21868
22082
|
}
|
|
21869
22083
|
for (const step of steps) {
|
|
22084
|
+
graph.assertActive();
|
|
21870
22085
|
if (step.kind === "account-index-schema") {
|
|
21871
22086
|
const ensured = await this.account.index.ensure();
|
|
21872
22087
|
if (!ensured.ok) {
|
|
@@ -22642,6 +22857,9 @@ var _TinyCloudNode = class _TinyCloudNode {
|
|
|
22642
22857
|
* @param sessionData - The stored delegation data from the browser flow
|
|
22643
22858
|
*/
|
|
22644
22859
|
async restoreSession(sessionData) {
|
|
22860
|
+
const epoch = this.sessionEpoch;
|
|
22861
|
+
const attempt = ++this.latestSessionAttempt;
|
|
22862
|
+
await this.signOutInFlight;
|
|
22645
22863
|
await this.wasmBindings.ensureInitialized?.();
|
|
22646
22864
|
let restoredJwk;
|
|
22647
22865
|
try {
|
|
@@ -22831,6 +23049,7 @@ var _TinyCloudNode = class _TinyCloudNode {
|
|
|
22831
23049
|
});
|
|
22832
23050
|
this.pendingAccountRegistrySync?.controller.abort();
|
|
22833
23051
|
await this.accountRegistryTail;
|
|
23052
|
+
this.assertSessionEpoch(epoch, "Session restore");
|
|
22834
23053
|
const oldGraph = this._serviceGraph;
|
|
22835
23054
|
const oldCore = this.tc;
|
|
22836
23055
|
this.sessionManager = stagedManager;
|
|
@@ -22876,6 +23095,12 @@ var _TinyCloudNode = class _TinyCloudNode {
|
|
|
22876
23095
|
this.replicationDelegateSession = compactReplicationSession;
|
|
22877
23096
|
this.replicationScopeError = replicationScopeError;
|
|
22878
23097
|
if (this.replicationRuntime) await (await this.replicationRuntime).unbind();
|
|
23098
|
+
if (epoch !== this.sessionEpoch) {
|
|
23099
|
+
oldGraph.retire();
|
|
23100
|
+
oldCore?.retireServices?.();
|
|
23101
|
+
if (attempt === this.latestSessionAttempt) await this.endSession();
|
|
23102
|
+
this.assertSessionEpoch(epoch, "Session restore");
|
|
23103
|
+
}
|
|
22879
23104
|
oldGraph.retire();
|
|
22880
23105
|
if (replicationScopeError) {
|
|
22881
23106
|
stagedGraph.serviceContext.emit("replication.state", {
|
|
@@ -22886,6 +23111,10 @@ var _TinyCloudNode = class _TinyCloudNode {
|
|
|
22886
23111
|
}
|
|
22887
23112
|
await this.bindReplicationRuntime(stagedGraph.serviceContext, serviceSession, stagedGraph.kv, replicationPrincipal);
|
|
22888
23113
|
oldCore?.retireServices?.();
|
|
23114
|
+
if (epoch !== this.sessionEpoch) {
|
|
23115
|
+
if (attempt === this.latestSessionAttempt) await this.endSession();
|
|
23116
|
+
this.assertSessionEpoch(epoch, "Session restore");
|
|
23117
|
+
}
|
|
22889
23118
|
}
|
|
22890
23119
|
stagePrimarySessionState(session, verificationMethod, host, sessionExpiry, recap) {
|
|
22891
23120
|
if (!session?.siwe) return { cache: void 0, grants: [] };
|
|
@@ -24744,6 +24973,7 @@ var _TinyCloudNode = class _TinyCloudNode {
|
|
|
24744
24973
|
* matching service calls and downstream `delegateTo()` calls can use it.
|
|
24745
24974
|
*/
|
|
24746
24975
|
async useRuntimeDelegation(delegation) {
|
|
24976
|
+
const graph = this._serviceGraph;
|
|
24747
24977
|
const session = this.currentTinyCloudSession();
|
|
24748
24978
|
if (!session) {
|
|
24749
24979
|
throw new SessionExpiredError(/* @__PURE__ */ new Date(0));
|
|
@@ -24762,9 +24992,11 @@ var _TinyCloudNode = class _TinyCloudNode {
|
|
|
24762
24992
|
try {
|
|
24763
24993
|
activateResult = await activateSessionWithHost2(
|
|
24764
24994
|
targetHost,
|
|
24765
|
-
delegation.delegationHeader
|
|
24995
|
+
delegation.delegationHeader,
|
|
24996
|
+
graph.signal
|
|
24766
24997
|
);
|
|
24767
24998
|
} catch (cause) {
|
|
24999
|
+
graph.assertActive();
|
|
24768
25000
|
throw Object.assign(
|
|
24769
25001
|
new Error("The TinyCloud host could not be reached to activate the delegation."),
|
|
24770
25002
|
{ code: "ACTIVATION_TRANSPORT_FAILED", cause }
|
|
@@ -24784,6 +25016,7 @@ var _TinyCloudNode = class _TinyCloudNode {
|
|
|
24784
25016
|
{ cause: activateResult }
|
|
24785
25017
|
);
|
|
24786
25018
|
}
|
|
25019
|
+
graph.assertActive();
|
|
24787
25020
|
this.runtimePermissionGrants = this.runtimePermissionGrants.filter(
|
|
24788
25021
|
(grant) => grant.delegation.cid !== delegation.cid
|
|
24789
25022
|
);
|
|
@@ -24800,6 +25033,7 @@ var _TinyCloudNode = class _TinyCloudNode {
|
|
|
24800
25033
|
if (!Array.isArray(permissions) || permissions.length === 0) {
|
|
24801
25034
|
throw new Error("grantRuntimePermissions requires a non-empty permissions array");
|
|
24802
25035
|
}
|
|
25036
|
+
const graph = this._serviceGraph;
|
|
24803
25037
|
const session = this.currentTinyCloudSession();
|
|
24804
25038
|
if (!session) {
|
|
24805
25039
|
throw new SessionExpiredError(/* @__PURE__ */ new Date(0));
|
|
@@ -24880,14 +25114,19 @@ var _TinyCloudNode = class _TinyCloudNode {
|
|
|
24880
25114
|
}
|
|
24881
25115
|
})();
|
|
24882
25116
|
const signature2 = await this.signer.signMessage(prepared.siwe);
|
|
25117
|
+
graph.assertActive();
|
|
24883
25118
|
const delegatedSession = this.wasmBindings.completeSessionSetup({
|
|
24884
25119
|
...prepared,
|
|
24885
25120
|
signature: signature2
|
|
24886
25121
|
});
|
|
24887
25122
|
const activateResult = await activateSessionWithHost2(
|
|
24888
25123
|
this.config.host,
|
|
24889
|
-
delegatedSession.delegationHeader
|
|
24890
|
-
|
|
25124
|
+
delegatedSession.delegationHeader,
|
|
25125
|
+
graph.signal
|
|
25126
|
+
).catch((error) => {
|
|
25127
|
+
graph.assertActive();
|
|
25128
|
+
throw error;
|
|
25129
|
+
});
|
|
24891
25130
|
if (!activateResult.success) {
|
|
24892
25131
|
if (rawForDelegation.some((entry) => this.isRawRevocationPermissionEntry(entry)) && activateResult.status === 401 && /Cannot find parent delegation/i.test(activateResult.error ?? "")) {
|
|
24893
25132
|
throw Object.assign(
|
|
@@ -24908,6 +25147,7 @@ var _TinyCloudNode = class _TinyCloudNode {
|
|
|
24908
25147
|
expiresAt,
|
|
24909
25148
|
{ siwe: prepared.siwe, signature: signature2 }
|
|
24910
25149
|
);
|
|
25150
|
+
graph.assertActive();
|
|
24911
25151
|
this.runtimePermissionGrants.push({
|
|
24912
25152
|
session: {
|
|
24913
25153
|
delegationHeader: delegatedSession.delegationHeader,
|
|
@@ -26371,6 +26611,7 @@ var _TinyCloudNode = class _TinyCloudNode {
|
|
|
26371
26611
|
* @returns A DelegatedAccess instance for performing operations
|
|
26372
26612
|
*/
|
|
26373
26613
|
async useDelegation(delegation) {
|
|
26614
|
+
const graph = this._serviceGraph;
|
|
26374
26615
|
const delegationHeader = delegation.delegationHeader;
|
|
26375
26616
|
const targetHost = delegation.host ?? this.config.host;
|
|
26376
26617
|
if (this.isSessionOnly) {
|
|
@@ -26412,7 +26653,8 @@ var _TinyCloudNode = class _TinyCloudNode {
|
|
|
26412
26653
|
targetHost,
|
|
26413
26654
|
this.wasmBindings.invoke,
|
|
26414
26655
|
this.wasmBindings.invokeAny,
|
|
26415
|
-
this.config.telemetry
|
|
26656
|
+
this.config.telemetry,
|
|
26657
|
+
graph
|
|
26416
26658
|
);
|
|
26417
26659
|
}
|
|
26418
26660
|
const mySession = this.auth?.tinyCloudSession;
|
|
@@ -26436,14 +26678,19 @@ var _TinyCloudNode = class _TinyCloudNode {
|
|
|
26436
26678
|
...Object.keys(rawAbilities).length > 0 ? { rawAbilities } : {}
|
|
26437
26679
|
});
|
|
26438
26680
|
const signature2 = await this.signer.signMessage(prepared.siwe);
|
|
26681
|
+
graph.assertActive();
|
|
26439
26682
|
const invokerSession = this.wasmBindings.completeSessionSetup({
|
|
26440
26683
|
...prepared,
|
|
26441
26684
|
signature: signature2
|
|
26442
26685
|
});
|
|
26443
26686
|
const activateResult = await activateSessionWithHost2(
|
|
26444
26687
|
targetHost,
|
|
26445
|
-
invokerSession.delegationHeader
|
|
26446
|
-
|
|
26688
|
+
invokerSession.delegationHeader,
|
|
26689
|
+
graph.signal
|
|
26690
|
+
).catch((error) => {
|
|
26691
|
+
graph.assertActive();
|
|
26692
|
+
throw error;
|
|
26693
|
+
});
|
|
26447
26694
|
if (!activateResult.success) {
|
|
26448
26695
|
throw Object.assign(
|
|
26449
26696
|
new Error(`Failed to activate delegated session: ${describeHostFailure2(activateResult)}`),
|
|
@@ -26462,6 +26709,7 @@ var _TinyCloudNode = class _TinyCloudNode {
|
|
|
26462
26709
|
siwe: prepared.siwe,
|
|
26463
26710
|
signature: signature2
|
|
26464
26711
|
};
|
|
26712
|
+
graph.assertActive();
|
|
26465
26713
|
this.trackReceivedDelegation(delegation, jwk);
|
|
26466
26714
|
this.installRuntimeGrantFromServiceSession(
|
|
26467
26715
|
delegation,
|
|
@@ -26480,7 +26728,8 @@ var _TinyCloudNode = class _TinyCloudNode {
|
|
|
26480
26728
|
targetHost,
|
|
26481
26729
|
this.wasmBindings.invoke,
|
|
26482
26730
|
this.wasmBindings.invokeAny,
|
|
26483
|
-
this.config.telemetry
|
|
26731
|
+
this.config.telemetry,
|
|
26732
|
+
graph
|
|
26484
26733
|
);
|
|
26485
26734
|
}
|
|
26486
26735
|
/**
|