@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.cjs
CHANGED
|
@@ -18494,6 +18494,13 @@ function cloneAbilitiesMap(actions) {
|
|
|
18494
18494
|
var NodeUserAuthorization = class {
|
|
18495
18495
|
constructor(config) {
|
|
18496
18496
|
this.activeSessionKeyId = "default";
|
|
18497
|
+
/** Incremented by resetSession; a sign-in started earlier publishes nothing. */
|
|
18498
|
+
this.sessionGeneration = 0;
|
|
18499
|
+
/**
|
|
18500
|
+
* Sign-in saves run one at a time, in order, each together with its own
|
|
18501
|
+
* cancellation cleanup, so no later write can land between the two.
|
|
18502
|
+
*/
|
|
18503
|
+
this.persistenceQueue = Promise.resolve();
|
|
18497
18504
|
this.extensions = [];
|
|
18498
18505
|
this._nodeFeatures = [];
|
|
18499
18506
|
this._nodeFeaturesKnown = false;
|
|
@@ -18624,6 +18631,27 @@ var NodeUserAuthorization = class {
|
|
|
18624
18631
|
this.tinycloudHosts = [...hosts];
|
|
18625
18632
|
}
|
|
18626
18633
|
}
|
|
18634
|
+
/**
|
|
18635
|
+
* @internal End the session: adopt a fresh session manager whose active key
|
|
18636
|
+
* is `sessionKeyId`, and return to the constructed state.
|
|
18637
|
+
*/
|
|
18638
|
+
resetSession(sessionManager, sessionKeyId, hosts) {
|
|
18639
|
+
this.sessionGeneration++;
|
|
18640
|
+
this.installRestoredSession(sessionManager, void 0, hosts);
|
|
18641
|
+
this.activeSessionKeyId = sessionKeyId;
|
|
18642
|
+
}
|
|
18643
|
+
/** Throws when the session was reset (signed out) after `generation` was read. */
|
|
18644
|
+
assertSignInCurrent(generation) {
|
|
18645
|
+
if (generation !== this.sessionGeneration) {
|
|
18646
|
+
throw new Error("Sign-in was cancelled by sign-out.");
|
|
18647
|
+
}
|
|
18648
|
+
}
|
|
18649
|
+
/** Runs `task` after every earlier queued persistence task has settled. */
|
|
18650
|
+
enqueuePersistence(task) {
|
|
18651
|
+
const run = this.persistenceQueue.then(task);
|
|
18652
|
+
this.persistenceQueue = run.catch(() => void 0);
|
|
18653
|
+
return run;
|
|
18654
|
+
}
|
|
18627
18655
|
/** @internal Atomically adopt the state staged by TinyCloudNode.restoreSession. */
|
|
18628
18656
|
installRestoredSession(sessionManager, session, hosts, nodeFeatures) {
|
|
18629
18657
|
this.sessionManager = sessionManager;
|
|
@@ -19312,11 +19340,14 @@ var NodeUserAuthorization = class {
|
|
|
19312
19340
|
* @param options - Optional per-call SIWE overrides for this sign-in only
|
|
19313
19341
|
*/
|
|
19314
19342
|
async signIn(options) {
|
|
19315
|
-
|
|
19316
|
-
|
|
19317
|
-
const
|
|
19318
|
-
|
|
19343
|
+
const generation = this.sessionGeneration;
|
|
19344
|
+
const address = (0, import_sdk_core4.canonicalizeAddress)(await this.signer.getAddress());
|
|
19345
|
+
const chainId = await this.signer.getChainId();
|
|
19346
|
+
this.assertSignInCurrent(generation);
|
|
19347
|
+
this._address = address;
|
|
19348
|
+
this._chainId = chainId;
|
|
19319
19349
|
await this.resolveTinyCloudHostsForSignIn(address, chainId);
|
|
19350
|
+
this.assertSignInCurrent(generation);
|
|
19320
19351
|
const keyId = `session-${Date.now()}`;
|
|
19321
19352
|
this.sessionManager.renameSessionKeyId(this.activeSessionKeyId, keyId);
|
|
19322
19353
|
this.activeSessionKeyId = keyId;
|
|
@@ -19349,6 +19380,7 @@ var NodeUserAuthorization = class {
|
|
|
19349
19380
|
type: "siwe",
|
|
19350
19381
|
purpose: "sign-in"
|
|
19351
19382
|
});
|
|
19383
|
+
this.assertSignInCurrent(generation);
|
|
19352
19384
|
const session = this.wasm.completeSessionSetup({
|
|
19353
19385
|
...prepared,
|
|
19354
19386
|
signature: signature2
|
|
@@ -19393,18 +19425,27 @@ var NodeUserAuthorization = class {
|
|
|
19393
19425
|
version: "1.0",
|
|
19394
19426
|
tinycloudHosts: this.tinycloudHosts
|
|
19395
19427
|
};
|
|
19396
|
-
await this.
|
|
19428
|
+
await this.enqueuePersistence(async () => {
|
|
19429
|
+
await this.sessionStorage.save(address, persistedData);
|
|
19430
|
+
if (generation !== this.sessionGeneration) {
|
|
19431
|
+
await this.sessionStorage.clear(address);
|
|
19432
|
+
}
|
|
19433
|
+
});
|
|
19434
|
+
this.assertSignInCurrent(generation);
|
|
19397
19435
|
this._session = clientSession;
|
|
19398
19436
|
this._tinyCloudSession = tinyCloudSession;
|
|
19399
19437
|
this._address = address;
|
|
19400
19438
|
this._chainId = chainId;
|
|
19401
19439
|
await this.refreshNodeInfo();
|
|
19440
|
+
this.assertSignInCurrent(generation);
|
|
19402
19441
|
for (const ext of this.extensions) {
|
|
19403
19442
|
if (ext.afterSignIn) {
|
|
19404
19443
|
await ext.afterSignIn(clientSession);
|
|
19444
|
+
this.assertSignInCurrent(generation);
|
|
19405
19445
|
}
|
|
19406
19446
|
}
|
|
19407
19447
|
await this.ensureSpaceExists();
|
|
19448
|
+
this.assertSignInCurrent(generation);
|
|
19408
19449
|
return clientSession;
|
|
19409
19450
|
}
|
|
19410
19451
|
/**
|
|
@@ -20041,17 +20082,24 @@ var import_sdk_core5 = require("@tinycloud/sdk-core");
|
|
|
20041
20082
|
// src/DelegatedAccess.ts
|
|
20042
20083
|
var import_sdk_core6 = require("@tinycloud/sdk-core");
|
|
20043
20084
|
var DelegatedAccess = class {
|
|
20044
|
-
|
|
20085
|
+
/**
|
|
20086
|
+
* @param lifetime - Optional owner of this access: its `fetch` is used for
|
|
20087
|
+
* requests and the service context is registered with `track`, so the
|
|
20088
|
+
* owner can cancel and retire the access (TinyCloudNode does this when its
|
|
20089
|
+
* session is replaced or signed out).
|
|
20090
|
+
*/
|
|
20091
|
+
constructor(session, delegation, host, invoke2, invokeAny2, telemetry, lifetime) {
|
|
20045
20092
|
this.session = session;
|
|
20046
20093
|
this._delegation = delegation;
|
|
20047
20094
|
this.host = host;
|
|
20048
|
-
|
|
20095
|
+
const context = new import_sdk_core6.ServiceContext({
|
|
20049
20096
|
invoke: invoke2,
|
|
20050
20097
|
invokeAny: invokeAny2,
|
|
20051
|
-
fetch: globalThis.fetch.bind(globalThis),
|
|
20098
|
+
fetch: lifetime?.fetch ?? globalThis.fetch.bind(globalThis),
|
|
20052
20099
|
hosts: [host],
|
|
20053
20100
|
telemetry
|
|
20054
20101
|
});
|
|
20102
|
+
this._serviceContext = lifetime ? lifetime.track(context) : context;
|
|
20055
20103
|
const prefix = this._delegation.path.replace(/\/$/, "");
|
|
20056
20104
|
this._kv = new import_sdk_core6.KVService({ prefix });
|
|
20057
20105
|
this._kv.initialize(this._serviceContext);
|
|
@@ -20625,6 +20673,19 @@ function exactVerifiedRecap(verified) {
|
|
|
20625
20673
|
caveats: cloneRecapCaveats(entry.caveats)
|
|
20626
20674
|
}));
|
|
20627
20675
|
}
|
|
20676
|
+
function createDefaultSessionKey(wasm) {
|
|
20677
|
+
const manager = wasm.createSessionManager();
|
|
20678
|
+
let keyId = "default";
|
|
20679
|
+
let jwkStr = manager.jwk(keyId);
|
|
20680
|
+
if (!jwkStr) {
|
|
20681
|
+
keyId = manager.createSessionKey(keyId);
|
|
20682
|
+
jwkStr = manager.jwk(keyId);
|
|
20683
|
+
}
|
|
20684
|
+
if (!jwkStr) {
|
|
20685
|
+
throw new Error("Failed to get session key JWK");
|
|
20686
|
+
}
|
|
20687
|
+
return { manager, keyId, jwk: JSON.parse(jwkStr) };
|
|
20688
|
+
}
|
|
20628
20689
|
var ServiceGraphLifetime = class {
|
|
20629
20690
|
constructor(invokeFn, invokeAnyFn, fetchFn, observeContext) {
|
|
20630
20691
|
this.invokeFn = invokeFn;
|
|
@@ -20674,9 +20735,13 @@ var ServiceGraphLifetime = class {
|
|
|
20674
20735
|
this.contexts.clear();
|
|
20675
20736
|
}
|
|
20676
20737
|
}
|
|
20738
|
+
/** Aborted when the graph retires: cancels requests made for its session. */
|
|
20739
|
+
get signal() {
|
|
20740
|
+
return this.abortController.signal;
|
|
20741
|
+
}
|
|
20677
20742
|
assertActive() {
|
|
20678
20743
|
if (this.retired) {
|
|
20679
|
-
throw new Error("Service graph has been retired
|
|
20744
|
+
throw new Error("Service graph has been retired: its session was replaced or signed out.");
|
|
20680
20745
|
}
|
|
20681
20746
|
}
|
|
20682
20747
|
combineSignals(signal) {
|
|
@@ -20978,6 +21043,16 @@ var _TinyCloudNode = class _TinyCloudNode {
|
|
|
20978
21043
|
* so it must outlast a slow but healthy sync (9–18 s on prod 1.20.2, TC-998).
|
|
20979
21044
|
*/
|
|
20980
21045
|
this.accountRegistryDeadlineMs = 3e4;
|
|
21046
|
+
/**
|
|
21047
|
+
* Incremented by every sign-out. A sign-in or restore records it when it
|
|
21048
|
+
* starts and does not establish its session once it has changed.
|
|
21049
|
+
*/
|
|
21050
|
+
this.sessionEpoch = 0;
|
|
21051
|
+
/**
|
|
21052
|
+
* Numbers sign-in and restore attempts. A cancelled attempt cleans up only
|
|
21053
|
+
* while it is still the latest, so it never ends a newer session.
|
|
21054
|
+
*/
|
|
21055
|
+
this.latestSessionAttempt = 0;
|
|
20981
21056
|
/**
|
|
20982
21057
|
* True when the last signIn() detected an interactive signer and skipped
|
|
20983
21058
|
* client-side bootstrap. Apps can read this to know whether bootstrap was
|
|
@@ -21111,54 +21186,17 @@ var _TinyCloudNode = class _TinyCloudNode {
|
|
|
21111
21186
|
"wasmBindings must be provided in config. Import from '@tinycloud/node-sdk' (not '/core') for automatic Node.js defaults."
|
|
21112
21187
|
);
|
|
21113
21188
|
}
|
|
21114
|
-
|
|
21115
|
-
|
|
21116
|
-
|
|
21117
|
-
|
|
21118
|
-
this.sessionKeyId = defaultKeyId;
|
|
21119
|
-
} else {
|
|
21120
|
-
this.sessionKeyId = this.sessionManager.createSessionKey(defaultKeyId);
|
|
21121
|
-
jwkStr = this.sessionManager.jwk(this.sessionKeyId);
|
|
21122
|
-
}
|
|
21123
|
-
if (!jwkStr) {
|
|
21124
|
-
throw new Error("Failed to get session key JWK");
|
|
21125
|
-
}
|
|
21126
|
-
this.sessionKeyJwk = JSON.parse(jwkStr);
|
|
21189
|
+
const sessionKey = createDefaultSessionKey(this.wasmBindings);
|
|
21190
|
+
this.sessionManager = sessionKey.manager;
|
|
21191
|
+
this.sessionKeyId = sessionKey.keyId;
|
|
21192
|
+
this.sessionKeyJwk = sessionKey.jwk;
|
|
21127
21193
|
this._serviceGraph = this.createServiceGraphLifetime();
|
|
21128
21194
|
this._capabilityRegistry = new import_sdk_core9.CapabilityKeyRegistry();
|
|
21129
21195
|
this._keyProvider = new WasmKeyProvider({
|
|
21130
21196
|
sessionManager: this.sessionManager
|
|
21131
21197
|
});
|
|
21132
21198
|
this.notificationHandler = config.notificationHandler ?? new import_sdk_core9.SilentNotificationHandler();
|
|
21133
|
-
|
|
21134
|
-
this._sharingService = new import_sdk_core9.SharingService({
|
|
21135
|
-
hosts: [this.config.host],
|
|
21136
|
-
// session: undefined - not needed for receive()
|
|
21137
|
-
invoke: receiveOnlyGraph.invoke,
|
|
21138
|
-
fetch: receiveOnlyGraph.fetch,
|
|
21139
|
-
assertActive: () => receiveOnlyGraph.assertActive(),
|
|
21140
|
-
keyProvider: this._keyProvider,
|
|
21141
|
-
registry: this._capabilityRegistry,
|
|
21142
|
-
createDelegationWasm: (params) => this.createDelegationWrapper(params),
|
|
21143
|
-
computeCid: (data, codec) => {
|
|
21144
|
-
if (!this.wasmBindings.computeCid) throw new Error("computeCid is unavailable");
|
|
21145
|
-
return this.wasmBindings.computeCid(data, codec);
|
|
21146
|
-
},
|
|
21147
|
-
// delegationManager: undefined - not needed for receive()
|
|
21148
|
-
createKVService: (config2) => {
|
|
21149
|
-
const prefix = config2.pathPrefix?.replace(/\/$/, "");
|
|
21150
|
-
const kvService = new import_sdk_core9.KVService({ prefix });
|
|
21151
|
-
const kvContext = receiveOnlyGraph.track(new import_sdk_core9.ServiceContext({
|
|
21152
|
-
invoke: config2.invoke,
|
|
21153
|
-
fetch: config2.fetch ?? globalThis.fetch.bind(globalThis),
|
|
21154
|
-
hosts: config2.hosts,
|
|
21155
|
-
telemetry: this.config.telemetry
|
|
21156
|
-
}));
|
|
21157
|
-
kvContext.setSession(config2.session);
|
|
21158
|
-
kvService.initialize(kvContext);
|
|
21159
|
-
return kvService;
|
|
21160
|
-
}
|
|
21161
|
-
});
|
|
21199
|
+
this._sharingService = this.createReceiveOnlySharing();
|
|
21162
21200
|
if (config.signer) {
|
|
21163
21201
|
this.signer = config.signer;
|
|
21164
21202
|
this.setupAuth(config);
|
|
@@ -21300,6 +21338,42 @@ var _TinyCloudNode = class _TinyCloudNode {
|
|
|
21300
21338
|
get siweDomain() {
|
|
21301
21339
|
return this.config.domain ?? "app.tinycloud.xyz";
|
|
21302
21340
|
}
|
|
21341
|
+
/**
|
|
21342
|
+
* SharingService for receive-only access (no session required), bound to the
|
|
21343
|
+
* current service graph. This lets session-only users receive sharing links
|
|
21344
|
+
* without signIn(); full capabilities (generate) are added after signIn().
|
|
21345
|
+
*/
|
|
21346
|
+
createReceiveOnlySharing() {
|
|
21347
|
+
const receiveOnlyGraph = this._serviceGraph;
|
|
21348
|
+
return new import_sdk_core9.SharingService({
|
|
21349
|
+
hosts: [this.config.host],
|
|
21350
|
+
// session: undefined - not needed for receive()
|
|
21351
|
+
invoke: receiveOnlyGraph.invoke,
|
|
21352
|
+
fetch: receiveOnlyGraph.fetch,
|
|
21353
|
+
assertActive: () => receiveOnlyGraph.assertActive(),
|
|
21354
|
+
keyProvider: this._keyProvider,
|
|
21355
|
+
registry: this._capabilityRegistry,
|
|
21356
|
+
createDelegationWasm: (params) => this.createDelegationWrapper(params),
|
|
21357
|
+
computeCid: (data, codec) => {
|
|
21358
|
+
if (!this.wasmBindings.computeCid) throw new Error("computeCid is unavailable");
|
|
21359
|
+
return this.wasmBindings.computeCid(data, codec);
|
|
21360
|
+
},
|
|
21361
|
+
// delegationManager: undefined - not needed for receive()
|
|
21362
|
+
createKVService: (config) => {
|
|
21363
|
+
const prefix = config.pathPrefix?.replace(/\/$/, "");
|
|
21364
|
+
const kvService = new import_sdk_core9.KVService({ prefix });
|
|
21365
|
+
const kvContext = receiveOnlyGraph.track(new import_sdk_core9.ServiceContext({
|
|
21366
|
+
invoke: config.invoke,
|
|
21367
|
+
fetch: config.fetch ?? globalThis.fetch.bind(globalThis),
|
|
21368
|
+
hosts: config.hosts,
|
|
21369
|
+
telemetry: this.config.telemetry
|
|
21370
|
+
}));
|
|
21371
|
+
kvContext.setSession(config.session);
|
|
21372
|
+
kvService.initialize(kvContext);
|
|
21373
|
+
return kvService;
|
|
21374
|
+
}
|
|
21375
|
+
});
|
|
21376
|
+
}
|
|
21303
21377
|
/**
|
|
21304
21378
|
* Set up authorization handler and TinyCloud instance.
|
|
21305
21379
|
* @internal
|
|
@@ -21559,6 +21633,115 @@ var _TinyCloudNode = class _TinyCloudNode {
|
|
|
21559
21633
|
get restorableSession() {
|
|
21560
21634
|
return this.currentTinyCloudSession();
|
|
21561
21635
|
}
|
|
21636
|
+
/**
|
|
21637
|
+
* Sign out and end the session on this instance.
|
|
21638
|
+
*
|
|
21639
|
+
* Every service built for the session (and every `useDelegation()` result)
|
|
21640
|
+
* is retired and the session key is replaced before anything is awaited, so
|
|
21641
|
+
* nothing captured from the session can sign once sign-out has started.
|
|
21642
|
+
* Pending work is aborted and the persisted session is cleared from the
|
|
21643
|
+
* configured session storage. Afterwards session accessors return
|
|
21644
|
+
* `undefined` and service calls fail with "Not signed in" until
|
|
21645
|
+
* {@link signIn} or {@link restoreSession}, which wait for a sign-out in
|
|
21646
|
+
* progress.
|
|
21647
|
+
*/
|
|
21648
|
+
signOut() {
|
|
21649
|
+
this.signOutInFlight ?? (this.signOutInFlight = this.endSession().finally(() => {
|
|
21650
|
+
this.signOutInFlight = void 0;
|
|
21651
|
+
}));
|
|
21652
|
+
return this.signOutInFlight;
|
|
21653
|
+
}
|
|
21654
|
+
async endSession() {
|
|
21655
|
+
const leavingAddress = this.address ?? this._restoredTcSession?.address;
|
|
21656
|
+
const leavingAuth = this.auth;
|
|
21657
|
+
try {
|
|
21658
|
+
this.teardownSession();
|
|
21659
|
+
} finally {
|
|
21660
|
+
try {
|
|
21661
|
+
await this.accountRegistryTail;
|
|
21662
|
+
if (this.replicationRuntime) await (await this.replicationRuntime).unbind();
|
|
21663
|
+
} finally {
|
|
21664
|
+
if (leavingAddress) {
|
|
21665
|
+
await (leavingAuth ? leavingAuth.clearPersistedSession(leavingAddress) : this.config.sessionStorage?.clear(leavingAddress));
|
|
21666
|
+
}
|
|
21667
|
+
}
|
|
21668
|
+
}
|
|
21669
|
+
}
|
|
21670
|
+
/**
|
|
21671
|
+
* Synchronously drop every piece of in-memory session authority and
|
|
21672
|
+
* invalidate sign-ins and restores still in flight (see `sessionEpoch`).
|
|
21673
|
+
*/
|
|
21674
|
+
teardownSession() {
|
|
21675
|
+
this.sessionEpoch++;
|
|
21676
|
+
this.pendingAccountRegistrySync?.controller.abort();
|
|
21677
|
+
const oldGraph = this._serviceGraph;
|
|
21678
|
+
const oldCore = this.tc;
|
|
21679
|
+
const oldAuth = this.auth;
|
|
21680
|
+
this.auth = null;
|
|
21681
|
+
this.tc = null;
|
|
21682
|
+
this._address = void 0;
|
|
21683
|
+
this._restoredTcSession = void 0;
|
|
21684
|
+
this._activeServiceSession = void 0;
|
|
21685
|
+
oldGraph.retire();
|
|
21686
|
+
oldCore?.retireServices();
|
|
21687
|
+
oldAuth?.resetSession(
|
|
21688
|
+
this.sessionManager,
|
|
21689
|
+
this.sessionKeyId,
|
|
21690
|
+
this.explicitHost ? [this.explicitHost] : void 0
|
|
21691
|
+
);
|
|
21692
|
+
this.config.host = this.explicitHost ?? DEFAULT_HOST;
|
|
21693
|
+
this._chainId = 1;
|
|
21694
|
+
this._restoredNodeFeatures = void 0;
|
|
21695
|
+
this._activeServiceSession = void 0;
|
|
21696
|
+
this._serviceContext = void 0;
|
|
21697
|
+
this._kv = void 0;
|
|
21698
|
+
this._sql = void 0;
|
|
21699
|
+
this._duckdb = void 0;
|
|
21700
|
+
this._hooks = void 0;
|
|
21701
|
+
this._vault = void 0;
|
|
21702
|
+
this._encryption = void 0;
|
|
21703
|
+
this._baseVaults.clear();
|
|
21704
|
+
this._baseSecrets.clear();
|
|
21705
|
+
this._secrets.clear();
|
|
21706
|
+
this._account = void 0;
|
|
21707
|
+
this._publicKV = void 0;
|
|
21708
|
+
this._delegationManager = void 0;
|
|
21709
|
+
this._spaceService = void 0;
|
|
21710
|
+
this.runtimePermissionGrants = [];
|
|
21711
|
+
this._recapOperationsCache = void 0;
|
|
21712
|
+
this.confirmedHostedSpaceIds.clear();
|
|
21713
|
+
this.hostedOwnedSpaceIds.clear();
|
|
21714
|
+
this.cancelOwnedSpaceHosts();
|
|
21715
|
+
this.storageFull.clear();
|
|
21716
|
+
this._bootstrapSkipped = false;
|
|
21717
|
+
this._bootstrapStatus = { skipped: false };
|
|
21718
|
+
this.replicationDelegateSession = void 0;
|
|
21719
|
+
this.replicationScopeError = void 0;
|
|
21720
|
+
const sessionKey = createDefaultSessionKey(this.wasmBindings);
|
|
21721
|
+
this.sessionManager = sessionKey.manager;
|
|
21722
|
+
this.sessionKeyId = sessionKey.keyId;
|
|
21723
|
+
this.sessionKeyJwk = sessionKey.jwk;
|
|
21724
|
+
oldAuth?.resetSession(
|
|
21725
|
+
sessionKey.manager,
|
|
21726
|
+
sessionKey.keyId,
|
|
21727
|
+
this.explicitHost ? [this.explicitHost] : void 0
|
|
21728
|
+
);
|
|
21729
|
+
this._serviceGraph = this.createServiceGraphLifetime();
|
|
21730
|
+
this.auth = oldAuth;
|
|
21731
|
+
this.tc = this.auth ? new import_sdk_core9.TinyCloud(this.auth, {
|
|
21732
|
+
invokeAny: this.invokeAnyWithRuntimePermissions,
|
|
21733
|
+
telemetry: this.config.telemetry
|
|
21734
|
+
}) : null;
|
|
21735
|
+
this._capabilityRegistry = new import_sdk_core9.CapabilityKeyRegistry();
|
|
21736
|
+
this._keyProvider = new WasmKeyProvider({ sessionManager: this.sessionManager });
|
|
21737
|
+
this._sharingService = this.createReceiveOnlySharing();
|
|
21738
|
+
}
|
|
21739
|
+
/** Throws when a sign-out started after `epoch` was read. */
|
|
21740
|
+
assertSessionEpoch(epoch, operation) {
|
|
21741
|
+
if (epoch !== this.sessionEpoch) {
|
|
21742
|
+
throw new Error(`${operation} was cancelled by sign-out.`);
|
|
21743
|
+
}
|
|
21744
|
+
}
|
|
21562
21745
|
/**
|
|
21563
21746
|
* Sign in and create a new session.
|
|
21564
21747
|
* This creates the user's space if it doesn't exist.
|
|
@@ -21572,11 +21755,28 @@ var _TinyCloudNode = class _TinyCloudNode {
|
|
|
21572
21755
|
"Cannot signIn() in session-only mode. Provide a privateKey in config to create your own space."
|
|
21573
21756
|
);
|
|
21574
21757
|
}
|
|
21758
|
+
const epoch = this.sessionEpoch;
|
|
21759
|
+
const attempt = ++this.latestSessionAttempt;
|
|
21760
|
+
await this.signOutInFlight;
|
|
21761
|
+
try {
|
|
21762
|
+
await this.establishSignIn(epoch, options);
|
|
21763
|
+
} catch (error) {
|
|
21764
|
+
if (epoch !== this.sessionEpoch && attempt === this.latestSessionAttempt) {
|
|
21765
|
+
await this.endSession();
|
|
21766
|
+
}
|
|
21767
|
+
throw error;
|
|
21768
|
+
}
|
|
21769
|
+
}
|
|
21770
|
+
async establishSignIn(epoch, options) {
|
|
21771
|
+
if (!this.signer || !this.tc) {
|
|
21772
|
+
throw new Error("Not signed in. Call signIn() first.");
|
|
21773
|
+
}
|
|
21575
21774
|
this.pendingAccountRegistrySync?.controller.abort();
|
|
21576
21775
|
await this.accountRegistryTail;
|
|
21577
21776
|
await this.wasmBindings.ensureInitialized?.();
|
|
21578
21777
|
const address = (0, import_sdk_core9.canonicalizeAddress)(await this.signer.getAddress());
|
|
21579
21778
|
const chainId = await this.signer.getChainId();
|
|
21779
|
+
this.assertSessionEpoch(epoch, "Sign-in");
|
|
21580
21780
|
if (address !== this._address || chainId !== this._chainId) this.storageFull.clear();
|
|
21581
21781
|
this._address = address;
|
|
21582
21782
|
this._chainId = chainId;
|
|
@@ -21595,6 +21795,7 @@ var _TinyCloudNode = class _TinyCloudNode {
|
|
|
21595
21795
|
this.confirmedHostedSpaceIds.clear();
|
|
21596
21796
|
this.hostedOwnedSpaceIds.clear();
|
|
21597
21797
|
await this.tc.signIn(options);
|
|
21798
|
+
this.assertSessionEpoch(epoch, "Sign-in");
|
|
21598
21799
|
this.cancelOwnedSpaceHosts();
|
|
21599
21800
|
this.syncResolvedHostFromAuth();
|
|
21600
21801
|
for (const spaceId of this.auth.lastActivationActivatedSpaceIds ?? []) {
|
|
@@ -21603,6 +21804,7 @@ var _TinyCloudNode = class _TinyCloudNode {
|
|
|
21603
21804
|
this.replicationDelegateSession = void 0;
|
|
21604
21805
|
this.replicationScopeError = void 0;
|
|
21605
21806
|
if (this.replicationRuntime) await (await this.replicationRuntime).unbind();
|
|
21807
|
+
this.assertSessionEpoch(epoch, "Sign-in");
|
|
21606
21808
|
const oldGraph = this._serviceGraph;
|
|
21607
21809
|
this._serviceGraph = this.createServiceGraphLifetime();
|
|
21608
21810
|
oldGraph.retire();
|
|
@@ -21613,15 +21815,19 @@ var _TinyCloudNode = class _TinyCloudNode {
|
|
|
21613
21815
|
this.sessionKeyJwk = signedInSession.jwk;
|
|
21614
21816
|
}
|
|
21615
21817
|
await this.initializeServices();
|
|
21818
|
+
this.assertSessionEpoch(epoch, "Sign-in");
|
|
21616
21819
|
const primarySession = this.currentTinyCloudSession();
|
|
21617
21820
|
if (primarySession) {
|
|
21618
21821
|
this.registerPrimarySessionGrant(primarySession);
|
|
21619
21822
|
}
|
|
21620
21823
|
const bootstrapped = await this.bootstrapAccountIfNeeded();
|
|
21824
|
+
this.assertSessionEpoch(epoch, "Sign-in");
|
|
21621
21825
|
await this.ensureRequestedEncryptionNetworks();
|
|
21826
|
+
this.assertSessionEpoch(epoch, "Sign-in");
|
|
21622
21827
|
if (!bootstrapped && this.config.manifest === void 0 && this.config.capabilityRequest === void 0) {
|
|
21623
21828
|
await this.ensureOwnedSpaceHostedById(this.ownedSpaceId(import_sdk_core9.SECRETS_SPACE));
|
|
21624
21829
|
}
|
|
21830
|
+
this.assertSessionEpoch(epoch, "Sign-in");
|
|
21625
21831
|
if (!bootstrapped) {
|
|
21626
21832
|
this.scheduleAccountRegistrySync();
|
|
21627
21833
|
}
|
|
@@ -21803,6 +22009,7 @@ var _TinyCloudNode = class _TinyCloudNode {
|
|
|
21803
22009
|
throw new Error("Account bootstrap requires a TinyCloud host");
|
|
21804
22010
|
}
|
|
21805
22011
|
const auth = this.auth;
|
|
22012
|
+
const graph = this._serviceGraph;
|
|
21806
22013
|
const sessions = /* @__PURE__ */ new Map();
|
|
21807
22014
|
const rawAbilitiesBySpace = /* @__PURE__ */ new Map();
|
|
21808
22015
|
const warnings = [];
|
|
@@ -21811,6 +22018,7 @@ var _TinyCloudNode = class _TinyCloudNode {
|
|
|
21811
22018
|
const canReusePrimaryBootstrapSession = primarySession?.spaceId === defaultSpaceId && auth.capabilityRequest === import_sdk_core9.BOOTSTRAP_SESSION_REQUESTS.default;
|
|
21812
22019
|
for (const step of steps) {
|
|
21813
22020
|
if (step.kind !== "session") continue;
|
|
22021
|
+
graph.assertActive();
|
|
21814
22022
|
if (step.space === "default" && canReusePrimaryBootstrapSession && primarySession) {
|
|
21815
22023
|
sessions.set(step.space, primarySession);
|
|
21816
22024
|
continue;
|
|
@@ -21838,6 +22046,7 @@ var _TinyCloudNode = class _TinyCloudNode {
|
|
|
21838
22046
|
}
|
|
21839
22047
|
for (const step of steps) {
|
|
21840
22048
|
if (step.kind !== "host") continue;
|
|
22049
|
+
graph.assertActive();
|
|
21841
22050
|
const hosted = await auth.hostOwnedSpaceResult(step.spaceId, "bootstrap-host");
|
|
21842
22051
|
if (!hosted.success) {
|
|
21843
22052
|
throw Object.assign(
|
|
@@ -21849,11 +22058,16 @@ var _TinyCloudNode = class _TinyCloudNode {
|
|
|
21849
22058
|
await new Promise((resolve) => setTimeout(resolve, 100));
|
|
21850
22059
|
for (const step of steps) {
|
|
21851
22060
|
if (step.kind !== "activate") continue;
|
|
22061
|
+
graph.assertActive();
|
|
21852
22062
|
const session = sessions.get(step.space);
|
|
21853
22063
|
if (!session) {
|
|
21854
22064
|
throw new Error(`Missing bootstrap session for ${step.space}`);
|
|
21855
22065
|
}
|
|
21856
|
-
const activated = await (0, import_sdk_core9.activateSessionWithHost)(host, session.delegationHeader)
|
|
22066
|
+
const activated = await (0, import_sdk_core9.activateSessionWithHost)(host, session.delegationHeader, graph.signal).catch((error) => {
|
|
22067
|
+
graph.assertActive();
|
|
22068
|
+
throw error;
|
|
22069
|
+
});
|
|
22070
|
+
graph.assertActive();
|
|
21857
22071
|
if (!activated.success || activated.skipped?.includes(step.spaceId)) {
|
|
21858
22072
|
throw Object.assign(
|
|
21859
22073
|
new Error(
|
|
@@ -21869,6 +22083,7 @@ var _TinyCloudNode = class _TinyCloudNode {
|
|
|
21869
22083
|
);
|
|
21870
22084
|
}
|
|
21871
22085
|
for (const step of steps) {
|
|
22086
|
+
graph.assertActive();
|
|
21872
22087
|
if (step.kind === "account-index-schema") {
|
|
21873
22088
|
const ensured = await this.account.index.ensure();
|
|
21874
22089
|
if (!ensured.ok) {
|
|
@@ -22644,6 +22859,9 @@ var _TinyCloudNode = class _TinyCloudNode {
|
|
|
22644
22859
|
* @param sessionData - The stored delegation data from the browser flow
|
|
22645
22860
|
*/
|
|
22646
22861
|
async restoreSession(sessionData) {
|
|
22862
|
+
const epoch = this.sessionEpoch;
|
|
22863
|
+
const attempt = ++this.latestSessionAttempt;
|
|
22864
|
+
await this.signOutInFlight;
|
|
22647
22865
|
await this.wasmBindings.ensureInitialized?.();
|
|
22648
22866
|
let restoredJwk;
|
|
22649
22867
|
try {
|
|
@@ -22833,6 +23051,7 @@ var _TinyCloudNode = class _TinyCloudNode {
|
|
|
22833
23051
|
});
|
|
22834
23052
|
this.pendingAccountRegistrySync?.controller.abort();
|
|
22835
23053
|
await this.accountRegistryTail;
|
|
23054
|
+
this.assertSessionEpoch(epoch, "Session restore");
|
|
22836
23055
|
const oldGraph = this._serviceGraph;
|
|
22837
23056
|
const oldCore = this.tc;
|
|
22838
23057
|
this.sessionManager = stagedManager;
|
|
@@ -22878,6 +23097,12 @@ var _TinyCloudNode = class _TinyCloudNode {
|
|
|
22878
23097
|
this.replicationDelegateSession = compactReplicationSession;
|
|
22879
23098
|
this.replicationScopeError = replicationScopeError;
|
|
22880
23099
|
if (this.replicationRuntime) await (await this.replicationRuntime).unbind();
|
|
23100
|
+
if (epoch !== this.sessionEpoch) {
|
|
23101
|
+
oldGraph.retire();
|
|
23102
|
+
oldCore?.retireServices?.();
|
|
23103
|
+
if (attempt === this.latestSessionAttempt) await this.endSession();
|
|
23104
|
+
this.assertSessionEpoch(epoch, "Session restore");
|
|
23105
|
+
}
|
|
22881
23106
|
oldGraph.retire();
|
|
22882
23107
|
if (replicationScopeError) {
|
|
22883
23108
|
stagedGraph.serviceContext.emit("replication.state", {
|
|
@@ -22888,6 +23113,10 @@ var _TinyCloudNode = class _TinyCloudNode {
|
|
|
22888
23113
|
}
|
|
22889
23114
|
await this.bindReplicationRuntime(stagedGraph.serviceContext, serviceSession, stagedGraph.kv, replicationPrincipal);
|
|
22890
23115
|
oldCore?.retireServices?.();
|
|
23116
|
+
if (epoch !== this.sessionEpoch) {
|
|
23117
|
+
if (attempt === this.latestSessionAttempt) await this.endSession();
|
|
23118
|
+
this.assertSessionEpoch(epoch, "Session restore");
|
|
23119
|
+
}
|
|
22891
23120
|
}
|
|
22892
23121
|
stagePrimarySessionState(session, verificationMethod, host, sessionExpiry, recap) {
|
|
22893
23122
|
if (!session?.siwe) return { cache: void 0, grants: [] };
|
|
@@ -24746,6 +24975,7 @@ var _TinyCloudNode = class _TinyCloudNode {
|
|
|
24746
24975
|
* matching service calls and downstream `delegateTo()` calls can use it.
|
|
24747
24976
|
*/
|
|
24748
24977
|
async useRuntimeDelegation(delegation) {
|
|
24978
|
+
const graph = this._serviceGraph;
|
|
24749
24979
|
const session = this.currentTinyCloudSession();
|
|
24750
24980
|
if (!session) {
|
|
24751
24981
|
throw new import_sdk_core9.SessionExpiredError(/* @__PURE__ */ new Date(0));
|
|
@@ -24764,9 +24994,11 @@ var _TinyCloudNode = class _TinyCloudNode {
|
|
|
24764
24994
|
try {
|
|
24765
24995
|
activateResult = await (0, import_sdk_core9.activateSessionWithHost)(
|
|
24766
24996
|
targetHost,
|
|
24767
|
-
delegation.delegationHeader
|
|
24997
|
+
delegation.delegationHeader,
|
|
24998
|
+
graph.signal
|
|
24768
24999
|
);
|
|
24769
25000
|
} catch (cause) {
|
|
25001
|
+
graph.assertActive();
|
|
24770
25002
|
throw Object.assign(
|
|
24771
25003
|
new Error("The TinyCloud host could not be reached to activate the delegation."),
|
|
24772
25004
|
{ code: "ACTIVATION_TRANSPORT_FAILED", cause }
|
|
@@ -24786,6 +25018,7 @@ var _TinyCloudNode = class _TinyCloudNode {
|
|
|
24786
25018
|
{ cause: activateResult }
|
|
24787
25019
|
);
|
|
24788
25020
|
}
|
|
25021
|
+
graph.assertActive();
|
|
24789
25022
|
this.runtimePermissionGrants = this.runtimePermissionGrants.filter(
|
|
24790
25023
|
(grant) => grant.delegation.cid !== delegation.cid
|
|
24791
25024
|
);
|
|
@@ -24802,6 +25035,7 @@ var _TinyCloudNode = class _TinyCloudNode {
|
|
|
24802
25035
|
if (!Array.isArray(permissions) || permissions.length === 0) {
|
|
24803
25036
|
throw new Error("grantRuntimePermissions requires a non-empty permissions array");
|
|
24804
25037
|
}
|
|
25038
|
+
const graph = this._serviceGraph;
|
|
24805
25039
|
const session = this.currentTinyCloudSession();
|
|
24806
25040
|
if (!session) {
|
|
24807
25041
|
throw new import_sdk_core9.SessionExpiredError(/* @__PURE__ */ new Date(0));
|
|
@@ -24882,14 +25116,19 @@ var _TinyCloudNode = class _TinyCloudNode {
|
|
|
24882
25116
|
}
|
|
24883
25117
|
})();
|
|
24884
25118
|
const signature2 = await this.signer.signMessage(prepared.siwe);
|
|
25119
|
+
graph.assertActive();
|
|
24885
25120
|
const delegatedSession = this.wasmBindings.completeSessionSetup({
|
|
24886
25121
|
...prepared,
|
|
24887
25122
|
signature: signature2
|
|
24888
25123
|
});
|
|
24889
25124
|
const activateResult = await (0, import_sdk_core9.activateSessionWithHost)(
|
|
24890
25125
|
this.config.host,
|
|
24891
|
-
delegatedSession.delegationHeader
|
|
24892
|
-
|
|
25126
|
+
delegatedSession.delegationHeader,
|
|
25127
|
+
graph.signal
|
|
25128
|
+
).catch((error) => {
|
|
25129
|
+
graph.assertActive();
|
|
25130
|
+
throw error;
|
|
25131
|
+
});
|
|
24893
25132
|
if (!activateResult.success) {
|
|
24894
25133
|
if (rawForDelegation.some((entry) => this.isRawRevocationPermissionEntry(entry)) && activateResult.status === 401 && /Cannot find parent delegation/i.test(activateResult.error ?? "")) {
|
|
24895
25134
|
throw Object.assign(
|
|
@@ -24910,6 +25149,7 @@ var _TinyCloudNode = class _TinyCloudNode {
|
|
|
24910
25149
|
expiresAt,
|
|
24911
25150
|
{ siwe: prepared.siwe, signature: signature2 }
|
|
24912
25151
|
);
|
|
25152
|
+
graph.assertActive();
|
|
24913
25153
|
this.runtimePermissionGrants.push({
|
|
24914
25154
|
session: {
|
|
24915
25155
|
delegationHeader: delegatedSession.delegationHeader,
|
|
@@ -26373,6 +26613,7 @@ var _TinyCloudNode = class _TinyCloudNode {
|
|
|
26373
26613
|
* @returns A DelegatedAccess instance for performing operations
|
|
26374
26614
|
*/
|
|
26375
26615
|
async useDelegation(delegation) {
|
|
26616
|
+
const graph = this._serviceGraph;
|
|
26376
26617
|
const delegationHeader = delegation.delegationHeader;
|
|
26377
26618
|
const targetHost = delegation.host ?? this.config.host;
|
|
26378
26619
|
if (this.isSessionOnly) {
|
|
@@ -26414,7 +26655,8 @@ var _TinyCloudNode = class _TinyCloudNode {
|
|
|
26414
26655
|
targetHost,
|
|
26415
26656
|
this.wasmBindings.invoke,
|
|
26416
26657
|
this.wasmBindings.invokeAny,
|
|
26417
|
-
this.config.telemetry
|
|
26658
|
+
this.config.telemetry,
|
|
26659
|
+
graph
|
|
26418
26660
|
);
|
|
26419
26661
|
}
|
|
26420
26662
|
const mySession = this.auth?.tinyCloudSession;
|
|
@@ -26438,14 +26680,19 @@ var _TinyCloudNode = class _TinyCloudNode {
|
|
|
26438
26680
|
...Object.keys(rawAbilities).length > 0 ? { rawAbilities } : {}
|
|
26439
26681
|
});
|
|
26440
26682
|
const signature2 = await this.signer.signMessage(prepared.siwe);
|
|
26683
|
+
graph.assertActive();
|
|
26441
26684
|
const invokerSession = this.wasmBindings.completeSessionSetup({
|
|
26442
26685
|
...prepared,
|
|
26443
26686
|
signature: signature2
|
|
26444
26687
|
});
|
|
26445
26688
|
const activateResult = await (0, import_sdk_core9.activateSessionWithHost)(
|
|
26446
26689
|
targetHost,
|
|
26447
|
-
invokerSession.delegationHeader
|
|
26448
|
-
|
|
26690
|
+
invokerSession.delegationHeader,
|
|
26691
|
+
graph.signal
|
|
26692
|
+
).catch((error) => {
|
|
26693
|
+
graph.assertActive();
|
|
26694
|
+
throw error;
|
|
26695
|
+
});
|
|
26449
26696
|
if (!activateResult.success) {
|
|
26450
26697
|
throw Object.assign(
|
|
26451
26698
|
new Error(`Failed to activate delegated session: ${describeHostFailure2(activateResult)}`),
|
|
@@ -26464,6 +26711,7 @@ var _TinyCloudNode = class _TinyCloudNode {
|
|
|
26464
26711
|
siwe: prepared.siwe,
|
|
26465
26712
|
signature: signature2
|
|
26466
26713
|
};
|
|
26714
|
+
graph.assertActive();
|
|
26467
26715
|
this.trackReceivedDelegation(delegation, jwk);
|
|
26468
26716
|
this.installRuntimeGrantFromServiceSession(
|
|
26469
26717
|
delegation,
|
|
@@ -26482,7 +26730,8 @@ var _TinyCloudNode = class _TinyCloudNode {
|
|
|
26482
26730
|
targetHost,
|
|
26483
26731
|
this.wasmBindings.invoke,
|
|
26484
26732
|
this.wasmBindings.invokeAny,
|
|
26485
|
-
this.config.telemetry
|
|
26733
|
+
this.config.telemetry,
|
|
26734
|
+
graph
|
|
26486
26735
|
);
|
|
26487
26736
|
}
|
|
26488
26737
|
/**
|