@tinycloud/node-sdk 3.2.1-beta.0 → 3.2.1
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-6_YwgSkd.d.cts → WasmKeyProvider-DRlOpvpG.d.cts} +56 -13
- package/dist/{WasmKeyProvider-6_YwgSkd.d.ts → WasmKeyProvider-DRlOpvpG.d.ts} +56 -13
- package/dist/core.cjs +131 -31
- 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 +131 -31
- package/dist/core.js.map +1 -1
- package/dist/index.cjs +130 -30
- 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 +130 -30
- package/dist/index.js.map +1 -1
- package/package.json +3 -3
package/dist/index.cjs
CHANGED
|
@@ -18494,6 +18494,11 @@ var NodeUserAuthorization = class {
|
|
|
18494
18494
|
this._nodeFeatures = [];
|
|
18495
18495
|
this._nodeFeaturesKnown = false;
|
|
18496
18496
|
this._lastActivationSkippedSpaceIds = [];
|
|
18497
|
+
/**
|
|
18498
|
+
* Spaces the sign-in activation reported hosted. Only the first POST of a
|
|
18499
|
+
* delegation lists them: the node answers a repeat with empty lists.
|
|
18500
|
+
*/
|
|
18501
|
+
this._lastActivationActivatedSpaceIds = [];
|
|
18497
18502
|
this.wasm = config.wasmBindings;
|
|
18498
18503
|
this.signer = config.signer;
|
|
18499
18504
|
this.signStrategy = config.signStrategy ?? defaultSignStrategy;
|
|
@@ -18623,6 +18628,7 @@ var NodeUserAuthorization = class {
|
|
|
18623
18628
|
this._nodeInfoIdentity = void 0;
|
|
18624
18629
|
this.tinycloudHosts = hosts && hosts.length > 0 ? [...hosts] : void 0;
|
|
18625
18630
|
this._lastActivationSkippedSpaceIds = [];
|
|
18631
|
+
this._lastActivationActivatedSpaceIds = [];
|
|
18626
18632
|
if (!session) {
|
|
18627
18633
|
this._session = void 0;
|
|
18628
18634
|
this._tinyCloudSession = void 0;
|
|
@@ -18717,6 +18723,9 @@ var NodeUserAuthorization = class {
|
|
|
18717
18723
|
get lastActivationSkippedSpaceIds() {
|
|
18718
18724
|
return [...this._lastActivationSkippedSpaceIds];
|
|
18719
18725
|
}
|
|
18726
|
+
get lastActivationActivatedSpaceIds() {
|
|
18727
|
+
return [...this._lastActivationActivatedSpaceIds];
|
|
18728
|
+
}
|
|
18720
18729
|
/**
|
|
18721
18730
|
* Compute the `abilities` map the WASM `prepareSession` call should
|
|
18722
18731
|
* see at sign-in time.
|
|
@@ -19212,8 +19221,10 @@ var NodeUserAuthorization = class {
|
|
|
19212
19221
|
recordActivationSkippedSpaces(result, primarySpaceId) {
|
|
19213
19222
|
if (result.success) {
|
|
19214
19223
|
this._lastActivationSkippedSpaceIds = result.skipped ?? [];
|
|
19224
|
+
this._lastActivationActivatedSpaceIds = result.activated ?? [];
|
|
19215
19225
|
return;
|
|
19216
19226
|
}
|
|
19227
|
+
this._lastActivationActivatedSpaceIds = [];
|
|
19217
19228
|
this._lastActivationSkippedSpaceIds = result.status === 404 ? [primarySpaceId] : [];
|
|
19218
19229
|
}
|
|
19219
19230
|
async createBootstrapSession(options) {
|
|
@@ -20943,10 +20954,26 @@ var _TinyCloudNode = class _TinyCloudNode {
|
|
|
20943
20954
|
* hosting is confirmed against the session that was active at the time.
|
|
20944
20955
|
*/
|
|
20945
20956
|
this.confirmedHostedSpaceIds = /* @__PURE__ */ new Set();
|
|
20957
|
+
/**
|
|
20958
|
+
* Owned space ids known to be hosted for the current session: the sign-in
|
|
20959
|
+
* activation listed them as `activated`, or this session hosted them. Unlike
|
|
20960
|
+
* {@link confirmedHostedSpaceIds}, nothing here is inferred from a space being
|
|
20961
|
+
* merely absent from `skipped`. Read by {@link ensureOwnedSpaceHosted}.
|
|
20962
|
+
*/
|
|
20963
|
+
this.hostedOwnedSpaceIds = /* @__PURE__ */ new Set();
|
|
20964
|
+
/**
|
|
20965
|
+
* In-flight host delegations, so concurrent callers share one approval per
|
|
20966
|
+
* space. `waiters` counts callers still waiting; the request is cancelled
|
|
20967
|
+
* once every caller with a signal has aborted and none waits without one.
|
|
20968
|
+
*/
|
|
20969
|
+
this.ownedSpaceHosts = /* @__PURE__ */ new Map();
|
|
20946
20970
|
/** Serializes account-registry writes for the active node instance. */
|
|
20947
20971
|
this.accountRegistryTail = Promise.resolve();
|
|
20948
|
-
/**
|
|
20949
|
-
|
|
20972
|
+
/**
|
|
20973
|
+
* Hang guard for the background registry sync. It is off the sign-in path,
|
|
20974
|
+
* so it must outlast a slow but healthy sync (9–18 s on prod 1.20.2, TC-998).
|
|
20975
|
+
*/
|
|
20976
|
+
this.accountRegistryDeadlineMs = 3e4;
|
|
20950
20977
|
/**
|
|
20951
20978
|
* True when the last signIn() detected an interactive signer and skipped
|
|
20952
20979
|
* client-side bootstrap. Apps can read this to know whether bootstrap was
|
|
@@ -21541,6 +21568,7 @@ var _TinyCloudNode = class _TinyCloudNode {
|
|
|
21541
21568
|
"Cannot signIn() in session-only mode. Provide a privateKey in config to create your own space."
|
|
21542
21569
|
);
|
|
21543
21570
|
}
|
|
21571
|
+
this.pendingAccountRegistrySync?.controller.abort();
|
|
21544
21572
|
await this.accountRegistryTail;
|
|
21545
21573
|
await this.wasmBindings.ensureInitialized?.();
|
|
21546
21574
|
const address = (0, import_sdk_core9.canonicalizeAddress)(await this.signer.getAddress());
|
|
@@ -21561,8 +21589,13 @@ var _TinyCloudNode = class _TinyCloudNode {
|
|
|
21561
21589
|
this._serviceContext = void 0;
|
|
21562
21590
|
this.runtimePermissionGrants = [];
|
|
21563
21591
|
this.confirmedHostedSpaceIds.clear();
|
|
21592
|
+
this.hostedOwnedSpaceIds.clear();
|
|
21564
21593
|
await this.tc.signIn(options);
|
|
21594
|
+
this.cancelOwnedSpaceHosts();
|
|
21565
21595
|
this.syncResolvedHostFromAuth();
|
|
21596
|
+
for (const spaceId of this.auth.lastActivationActivatedSpaceIds ?? []) {
|
|
21597
|
+
this.hostedOwnedSpaceIds.add(spaceId);
|
|
21598
|
+
}
|
|
21566
21599
|
this.replicationDelegateSession = void 0;
|
|
21567
21600
|
this.replicationScopeError = void 0;
|
|
21568
21601
|
if (this.replicationRuntime) await (await this.replicationRuntime).unbind();
|
|
@@ -21587,10 +21620,20 @@ var _TinyCloudNode = class _TinyCloudNode {
|
|
|
21587
21620
|
}
|
|
21588
21621
|
if (!bootstrapped) {
|
|
21589
21622
|
this.scheduleAccountRegistrySync();
|
|
21590
|
-
await this.accountRegistryTail;
|
|
21591
21623
|
}
|
|
21592
21624
|
this.notificationHandler.success("Successfully signed in");
|
|
21593
21625
|
}
|
|
21626
|
+
/**
|
|
21627
|
+
* Wait for the account-registry sync that {@link signIn} starts in the
|
|
21628
|
+
* background (account index, this app's manifest record, space list).
|
|
21629
|
+
* Resolves once it has finished, failed or hit its hang guard; it never
|
|
21630
|
+
* rejects, and failures are logged as warnings. `signIn()` does not wait for
|
|
21631
|
+
* it, so call this only when you need the registry written, or before a first
|
|
21632
|
+
* write against a SQLite-backed node older than 1.20.2 (TC-899).
|
|
21633
|
+
*/
|
|
21634
|
+
async waitForAccountRegistrySync() {
|
|
21635
|
+
await this.accountRegistryTail;
|
|
21636
|
+
}
|
|
21594
21637
|
ownedSpaceId(name) {
|
|
21595
21638
|
if (!this._address) {
|
|
21596
21639
|
throw new Error("Cannot resolve owned space before sign-in");
|
|
@@ -22196,17 +22239,17 @@ var _TinyCloudNode = class _TinyCloudNode {
|
|
|
22196
22239
|
clearTimeout(deadline);
|
|
22197
22240
|
}
|
|
22198
22241
|
});
|
|
22199
|
-
this.pendingAccountRegistrySync = { session, promise };
|
|
22200
|
-
const
|
|
22242
|
+
this.pendingAccountRegistrySync = { session, promise, controller };
|
|
22243
|
+
const settle = () => {
|
|
22244
|
+
clearTimeout(deadline);
|
|
22201
22245
|
if (this.pendingAccountRegistrySync?.promise === promise) {
|
|
22202
22246
|
this.pendingAccountRegistrySync = void 0;
|
|
22203
22247
|
}
|
|
22204
22248
|
};
|
|
22205
|
-
void promise.then(
|
|
22206
|
-
|
|
22207
|
-
(
|
|
22208
|
-
|
|
22209
|
-
);
|
|
22249
|
+
void promise.then(settle, (error) => {
|
|
22250
|
+
settle();
|
|
22251
|
+
console.warn("TinyCloud account registry sync failed", error);
|
|
22252
|
+
});
|
|
22210
22253
|
}
|
|
22211
22254
|
enqueueAccountRegistryOperation(session, task) {
|
|
22212
22255
|
const operation = this.accountRegistryTail.then(async () => {
|
|
@@ -22244,10 +22287,15 @@ var _TinyCloudNode = class _TinyCloudNode {
|
|
|
22244
22287
|
}
|
|
22245
22288
|
async withAccountRegistryRetry(task, signal) {
|
|
22246
22289
|
const delays = [250, 1e3, 3e3];
|
|
22290
|
+
const stopped = (detail) => {
|
|
22291
|
+
if (signal.reason instanceof DOMException && signal.reason.name === "TimeoutError") {
|
|
22292
|
+
console.warn("TinyCloud account registry sync stopped: deadline exceeded", detail);
|
|
22293
|
+
}
|
|
22294
|
+
};
|
|
22247
22295
|
let lastError;
|
|
22248
22296
|
for (let attempt = 0; attempt < delays.length; attempt += 1) {
|
|
22249
22297
|
if (signal.aborted) {
|
|
22250
|
-
|
|
22298
|
+
stopped(signal.reason);
|
|
22251
22299
|
return;
|
|
22252
22300
|
}
|
|
22253
22301
|
try {
|
|
@@ -22255,7 +22303,7 @@ var _TinyCloudNode = class _TinyCloudNode {
|
|
|
22255
22303
|
return;
|
|
22256
22304
|
} catch (error) {
|
|
22257
22305
|
if (signal.aborted) {
|
|
22258
|
-
|
|
22306
|
+
stopped(error);
|
|
22259
22307
|
return;
|
|
22260
22308
|
}
|
|
22261
22309
|
const verdict = (0, import_sdk_core9.authorizationVerdictOf)(error);
|
|
@@ -22348,7 +22396,7 @@ var _TinyCloudNode = class _TinyCloudNode {
|
|
|
22348
22396
|
if (!session) {
|
|
22349
22397
|
throw new Error("Owned space hosting requires an active session");
|
|
22350
22398
|
}
|
|
22351
|
-
if (this.confirmedHostedSpaceIds.has(spaceId)) {
|
|
22399
|
+
if (this.confirmedHostedSpaceIds.has(spaceId) || this.hostedOwnedSpaceIds.has(spaceId)) {
|
|
22352
22400
|
return;
|
|
22353
22401
|
}
|
|
22354
22402
|
const host = this.hosts[0] ?? this.config.host;
|
|
@@ -22366,8 +22414,7 @@ var _TinyCloudNode = class _TinyCloudNode {
|
|
|
22366
22414
|
{ cause: activation }
|
|
22367
22415
|
);
|
|
22368
22416
|
}
|
|
22369
|
-
const
|
|
22370
|
-
const created = signal ? await authorization.hostOwnedSpaceResult(spaceId, void 0, signal) : await authorization.hostOwnedSpaceResult(spaceId);
|
|
22417
|
+
const created = await this.hostOwnedSpaceOnce(spaceId, signal);
|
|
22371
22418
|
if (!created.success) {
|
|
22372
22419
|
throw Object.assign(
|
|
22373
22420
|
new Error(`Failed to create owned space ${spaceId}: ${describeHostFailure2(created)}`),
|
|
@@ -22384,7 +22431,10 @@ var _TinyCloudNode = class _TinyCloudNode {
|
|
|
22384
22431
|
{ cause: retry }
|
|
22385
22432
|
);
|
|
22386
22433
|
}
|
|
22387
|
-
this.
|
|
22434
|
+
if (this.auth.tinyCloudSession === session) {
|
|
22435
|
+
this.confirmedHostedSpaceIds.add(spaceId);
|
|
22436
|
+
this.hostedOwnedSpaceIds.add(spaceId);
|
|
22437
|
+
}
|
|
22388
22438
|
}
|
|
22389
22439
|
/**
|
|
22390
22440
|
* Host one of this user's owned spaces by name (e.g. `"applications"`).
|
|
@@ -22416,7 +22466,7 @@ var _TinyCloudNode = class _TinyCloudNode {
|
|
|
22416
22466
|
if (!host) {
|
|
22417
22467
|
throw new Error("Owned space hosting requires a TinyCloud host");
|
|
22418
22468
|
}
|
|
22419
|
-
const hosted = await this.
|
|
22469
|
+
const hosted = await this.hostOwnedSpaceOnce(spaceId);
|
|
22420
22470
|
if (!hosted.success) {
|
|
22421
22471
|
throw Object.assign(
|
|
22422
22472
|
new Error(`Failed to host owned space ${spaceId}: ${describeHostFailure2(hosted)}`),
|
|
@@ -22435,6 +22485,7 @@ var _TinyCloudNode = class _TinyCloudNode {
|
|
|
22435
22485
|
{ cause: activation }
|
|
22436
22486
|
);
|
|
22437
22487
|
}
|
|
22488
|
+
if (this.auth?.tinyCloudSession === session) this.hostedOwnedSpaceIds.add(spaceId);
|
|
22438
22489
|
try {
|
|
22439
22490
|
await this.enqueueAccountRegistryOperation(session, async () => {
|
|
22440
22491
|
await this.account.spaces.register({
|
|
@@ -22462,18 +22513,19 @@ var _TinyCloudNode = class _TinyCloudNode {
|
|
|
22462
22513
|
* registered on the node.
|
|
22463
22514
|
*
|
|
22464
22515
|
* Calling this resolves `name` to the owner's owned-space URI
|
|
22465
|
-
* (`tinycloud:pkh:eip155:<chain>:<addr>:<name>`). It
|
|
22466
|
-
*
|
|
22467
|
-
*
|
|
22468
|
-
* already
|
|
22469
|
-
*
|
|
22470
|
-
*
|
|
22471
|
-
*
|
|
22472
|
-
*
|
|
22516
|
+
* (`tinycloud:pkh:eip155:<chain>:<addr>:<name>`). It returns WITHOUT
|
|
22517
|
+
* submitting a host delegation when the space is known to be hosted: the
|
|
22518
|
+
* sign-in activation listed it as `activated` (any space the session's recap
|
|
22519
|
+
* covers), this session already hosted it, or the account-space spaces
|
|
22520
|
+
* registry (`account/spaces/{space_id}`, the canonical KV source of truth,
|
|
22521
|
+
* fronted by a best-effort SQLite index) has its record. Otherwise it falls
|
|
22522
|
+
* through to {@link hostOwnedSpace}, which asks for a signature; a host
|
|
22523
|
+
* already in flight for the same space (e.g. from the background registry
|
|
22524
|
+
* sync) is shared rather than asked for twice.
|
|
22473
22525
|
*
|
|
22474
|
-
*
|
|
22475
|
-
*
|
|
22476
|
-
*
|
|
22526
|
+
* Hosting is still needed when the space really isn't hosted, or when the
|
|
22527
|
+
* session's recap doesn't cover it and the registry has no record; the host
|
|
22528
|
+
* SIWE is idempotent server-side. Must be called after {@link signIn}.
|
|
22477
22529
|
*
|
|
22478
22530
|
* @param name - The owned space name (e.g. `"secrets"`).
|
|
22479
22531
|
* @returns The hosted owned-space URI.
|
|
@@ -22482,13 +22534,57 @@ var _TinyCloudNode = class _TinyCloudNode {
|
|
|
22482
22534
|
if (!this.auth || !this.auth.tinyCloudSession) {
|
|
22483
22535
|
throw new Error("Not signed in. Call signIn() first.");
|
|
22484
22536
|
}
|
|
22485
|
-
await this.accountRegistryTail;
|
|
22486
22537
|
const spaceId = this.ownedSpaceId(name);
|
|
22487
|
-
if (await this.isOwnedSpaceRegistered(spaceId)) {
|
|
22538
|
+
if (this.hostedOwnedSpaceIds.has(spaceId) || await this.isOwnedSpaceRegistered(spaceId)) {
|
|
22488
22539
|
return spaceId;
|
|
22489
22540
|
}
|
|
22490
22541
|
return this.hostOwnedSpace(name);
|
|
22491
22542
|
}
|
|
22543
|
+
/**
|
|
22544
|
+
* Submit the host delegation for an owned space, sharing one in-flight
|
|
22545
|
+
* request (and so one approval) between concurrent callers in this session,
|
|
22546
|
+
* such as the background registry sync and {@link ensureOwnedSpaceHosted}.
|
|
22547
|
+
* Each caller's `signal` releases only its own wait; the request itself is
|
|
22548
|
+
* cancelled once no caller is left waiting, or when the session is replaced
|
|
22549
|
+
* ({@link cancelOwnedSpaceHosts}), so a late approval is discarded.
|
|
22550
|
+
*/
|
|
22551
|
+
hostOwnedSpaceOnce(spaceId, signal) {
|
|
22552
|
+
if (signal?.aborted) return Promise.reject(signal.reason);
|
|
22553
|
+
let entry = this.ownedSpaceHosts.get(spaceId);
|
|
22554
|
+
if (!entry) {
|
|
22555
|
+
const controller = new AbortController();
|
|
22556
|
+
const promise = this.auth.hostOwnedSpaceResult(spaceId, void 0, controller.signal);
|
|
22557
|
+
const created = { promise, controller, waiters: 0 };
|
|
22558
|
+
this.ownedSpaceHosts.set(spaceId, created);
|
|
22559
|
+
const forget = () => {
|
|
22560
|
+
if (this.ownedSpaceHosts.get(spaceId) === created) this.ownedSpaceHosts.delete(spaceId);
|
|
22561
|
+
};
|
|
22562
|
+
promise.then(forget, forget);
|
|
22563
|
+
entry = created;
|
|
22564
|
+
}
|
|
22565
|
+
if (!signal) {
|
|
22566
|
+
entry.waiters = Number.POSITIVE_INFINITY;
|
|
22567
|
+
return entry.promise;
|
|
22568
|
+
}
|
|
22569
|
+
entry.waiters += 1;
|
|
22570
|
+
const shared = entry;
|
|
22571
|
+
return new Promise((resolve, reject2) => {
|
|
22572
|
+
const onAbort = () => {
|
|
22573
|
+
reject2(signal.reason);
|
|
22574
|
+
shared.waiters -= 1;
|
|
22575
|
+
if (shared.waiters !== 0) return;
|
|
22576
|
+
shared.controller.abort(signal.reason);
|
|
22577
|
+
if (this.ownedSpaceHosts.get(spaceId) === shared) this.ownedSpaceHosts.delete(spaceId);
|
|
22578
|
+
};
|
|
22579
|
+
signal.addEventListener("abort", onAbort, { once: true });
|
|
22580
|
+
shared.promise.then(resolve, reject2).finally(() => signal.removeEventListener("abort", onAbort));
|
|
22581
|
+
});
|
|
22582
|
+
}
|
|
22583
|
+
/** Session replacement: cancel the replaced session's in-flight hosts and forget them. */
|
|
22584
|
+
cancelOwnedSpaceHosts() {
|
|
22585
|
+
for (const { controller } of this.ownedSpaceHosts.values()) controller.abort();
|
|
22586
|
+
this.ownedSpaceHosts.clear();
|
|
22587
|
+
}
|
|
22492
22588
|
/** Resolve and authenticate the owner encoded by an owned-space URI. */
|
|
22493
22589
|
credentialSpaceOwnerDid(spaceId) {
|
|
22494
22590
|
const ownerDid = this.ownerDidFromSpaceId(spaceId);
|
|
@@ -22731,6 +22827,8 @@ var _TinyCloudNode = class _TinyCloudNode {
|
|
|
22731
22827
|
sessionExpiry: stagedSessionExpiry,
|
|
22732
22828
|
recap: stagedRecap
|
|
22733
22829
|
});
|
|
22830
|
+
this.pendingAccountRegistrySync?.controller.abort();
|
|
22831
|
+
await this.accountRegistryTail;
|
|
22734
22832
|
const oldGraph = this._serviceGraph;
|
|
22735
22833
|
const oldCore = this.tc;
|
|
22736
22834
|
this.sessionManager = stagedManager;
|
|
@@ -22764,6 +22862,8 @@ var _TinyCloudNode = class _TinyCloudNode {
|
|
|
22764
22862
|
this._recapOperationsCache = stagedPrimary.cache;
|
|
22765
22863
|
this.runtimePermissionGrants = stagedPrimary.grants;
|
|
22766
22864
|
this.confirmedHostedSpaceIds.clear();
|
|
22865
|
+
this.hostedOwnedSpaceIds.clear();
|
|
22866
|
+
this.cancelOwnedSpaceHosts();
|
|
22767
22867
|
this._restoredNodeFeatures = restoredNodeFeatures;
|
|
22768
22868
|
if (this.auth) {
|
|
22769
22869
|
this.auth.installRestoredSession(stagedManager, stagedTcSession, [stagedHost], restoredNodeFeatures);
|