@tinycloud/node-sdk 2.11.0-beta.1 → 2.11.0-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/{core-CQ_5wXQT.d.cts → core-DfcWH9i4.d.cts} +66 -2
- package/dist/{core-CQ_5wXQT.d.ts → core-DfcWH9i4.d.ts} +66 -2
- package/dist/core.cjs +79 -8
- package/dist/core.cjs.map +1 -1
- package/dist/core.d.cts +2 -2
- package/dist/core.d.ts +2 -2
- package/dist/core.js +79 -8
- package/dist/core.js.map +1 -1
- package/dist/index.cjs +79 -8
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +2 -2
- package/dist/index.d.ts +2 -2
- package/dist/index.js +79 -8
- package/dist/index.js.map +1 -1
- package/package.json +2 -2
package/dist/index.cjs
CHANGED
|
@@ -17578,6 +17578,15 @@ var NodeUserAuthorization = class {
|
|
|
17578
17578
|
get nodeFeatures() {
|
|
17579
17579
|
return this._nodeFeatures;
|
|
17580
17580
|
}
|
|
17581
|
+
/**
|
|
17582
|
+
* The node DID reported by `GET /info` for `host`, if the sign-in (or
|
|
17583
|
+
* restore) that populated it targeted that same host. Returns `undefined`
|
|
17584
|
+
* for any other host, and for nodes whose `/info` omits `nodeId`, so callers
|
|
17585
|
+
* fall back to fetching it themselves rather than using a foreign node's DID.
|
|
17586
|
+
*/
|
|
17587
|
+
nodeIdForHost(host) {
|
|
17588
|
+
return this._nodeInfoIdentity?.host === host ? this._nodeInfoIdentity.nodeId : void 0;
|
|
17589
|
+
}
|
|
17581
17590
|
get lastActivationSkippedSpaceIds() {
|
|
17582
17591
|
return [...this._lastActivationSkippedSpaceIds];
|
|
17583
17592
|
}
|
|
@@ -18047,11 +18056,13 @@ var NodeUserAuthorization = class {
|
|
|
18047
18056
|
this._tinyCloudSession = tinyCloudSession;
|
|
18048
18057
|
this._address = address;
|
|
18049
18058
|
this._chainId = chainId;
|
|
18059
|
+
const infoHost = this.primaryTinyCloudHost;
|
|
18050
18060
|
const nodeInfo = await (0, import_sdk_core2.checkNodeInfo)(
|
|
18051
|
-
|
|
18061
|
+
infoHost,
|
|
18052
18062
|
this.wasm.protocolVersion()
|
|
18053
18063
|
);
|
|
18054
18064
|
this._nodeFeatures = nodeInfo.features;
|
|
18065
|
+
this._nodeInfoIdentity = nodeInfo.nodeId ? { host: infoHost, nodeId: nodeInfo.nodeId } : void 0;
|
|
18055
18066
|
for (const ext of this.extensions) {
|
|
18056
18067
|
if (ext.afterSignIn) {
|
|
18057
18068
|
await ext.afterSignIn(clientSession);
|
|
@@ -18217,11 +18228,13 @@ var NodeUserAuthorization = class {
|
|
|
18217
18228
|
this._tinyCloudSession = tinyCloudSession;
|
|
18218
18229
|
this._address = address;
|
|
18219
18230
|
this._chainId = chainId;
|
|
18231
|
+
const infoHost = this.primaryTinyCloudHost;
|
|
18220
18232
|
const nodeInfo = await (0, import_sdk_core2.checkNodeInfo)(
|
|
18221
|
-
|
|
18233
|
+
infoHost,
|
|
18222
18234
|
this.wasm.protocolVersion()
|
|
18223
18235
|
);
|
|
18224
18236
|
this._nodeFeatures = nodeInfo.features;
|
|
18237
|
+
this._nodeInfoIdentity = nodeInfo.nodeId ? { host: infoHost, nodeId: nodeInfo.nodeId } : void 0;
|
|
18225
18238
|
for (const ext of this.extensions) {
|
|
18226
18239
|
if (ext.afterSignIn) {
|
|
18227
18240
|
await ext.afterSignIn(clientSession);
|
|
@@ -19111,6 +19124,12 @@ var _TinyCloudNode = class _TinyCloudNode {
|
|
|
19111
19124
|
this._baseSecrets = /* @__PURE__ */ new Map();
|
|
19112
19125
|
this._secrets = /* @__PURE__ */ new Map();
|
|
19113
19126
|
this.runtimePermissionGrants = [];
|
|
19127
|
+
/**
|
|
19128
|
+
* Owned space ids this sign-in has already confirmed are hosted. Consulted by
|
|
19129
|
+
* {@link ensureOwnedSpaceHostedById}; cleared on every {@link signIn} because
|
|
19130
|
+
* hosting is confirmed against the session that was active at the time.
|
|
19131
|
+
*/
|
|
19132
|
+
this.confirmedHostedSpaceIds = /* @__PURE__ */ new Set();
|
|
19114
19133
|
/**
|
|
19115
19134
|
* True when the last signIn() detected an interactive signer and skipped
|
|
19116
19135
|
* client-side bootstrap. Apps can read this to know whether bootstrap was
|
|
@@ -19507,6 +19526,7 @@ var _TinyCloudNode = class _TinyCloudNode {
|
|
|
19507
19526
|
this._spaceService = void 0;
|
|
19508
19527
|
this._serviceContext = void 0;
|
|
19509
19528
|
this.runtimePermissionGrants = [];
|
|
19529
|
+
this.confirmedHostedSpaceIds.clear();
|
|
19510
19530
|
await this.tc.signIn(options);
|
|
19511
19531
|
this.syncResolvedHostFromAuth();
|
|
19512
19532
|
const oldGraph = this._serviceGraph;
|
|
@@ -19689,14 +19709,18 @@ var _TinyCloudNode = class _TinyCloudNode {
|
|
|
19689
19709
|
}
|
|
19690
19710
|
if (step.kind === "seed-applications") {
|
|
19691
19711
|
const registered = await this.account.applications.register(
|
|
19692
|
-
step.manifests.length > 0 ? [...step.manifests] : import_sdk_core7.TINYCLOUD_SECRETS_BOOTSTRAP_MANIFEST
|
|
19712
|
+
step.manifests.length > 0 ? [...step.manifests] : import_sdk_core7.TINYCLOUD_SECRETS_BOOTSTRAP_MANIFEST,
|
|
19713
|
+
// Bootstrap only runs on an account with no registry records, so the
|
|
19714
|
+
// manifest-hash pre-read is definitionally a miss. Skip it; the write
|
|
19715
|
+
// it guards is an INSERT OR REPLACE and is safe to repeat.
|
|
19716
|
+
{ assumeUnregistered: true }
|
|
19693
19717
|
);
|
|
19694
19718
|
if (!registered.ok) {
|
|
19695
19719
|
throw new Error(`Failed to seed bootstrap applications: ${registered.error.message}`);
|
|
19696
19720
|
}
|
|
19697
19721
|
}
|
|
19698
19722
|
if (step.kind === "encryption-network-create") {
|
|
19699
|
-
await this.ensureEncryptionNetwork(step.networkId);
|
|
19723
|
+
await this.ensureEncryptionNetwork(step.networkId, { assumeMissing: true });
|
|
19700
19724
|
}
|
|
19701
19725
|
if (step.kind === "secret-records-schema") {
|
|
19702
19726
|
const db = this.sqlForSpace(step.spaceId).db(step.database);
|
|
@@ -19975,6 +19999,22 @@ var _TinyCloudNode = class _TinyCloudNode {
|
|
|
19975
19999
|
await this.ensureEncryptionNetwork(networkId);
|
|
19976
20000
|
}
|
|
19977
20001
|
}
|
|
20002
|
+
/**
|
|
20003
|
+
* Ensure one of this user's owned spaces is hosted, at most once per space
|
|
20004
|
+
* per sign-in.
|
|
20005
|
+
*
|
|
20006
|
+
* Account bootstrap funnels six calls through here (via
|
|
20007
|
+
* `AccountService.ensureAccountSpaceHosted`), and each one re-submits
|
|
20008
|
+
* `activateSessionWithHost` with the *primary* session. That session's recap
|
|
20009
|
+
* covers only `default` and `secrets`, so the account space appears in
|
|
20010
|
+
* neither `activated` nor `skipped` and the guard below returns immediately
|
|
20011
|
+
* — the repeat calls cannot change the outcome, they only cost round trips.
|
|
20012
|
+
*
|
|
20013
|
+
* The memo is per sign-in ({@link confirmedHostedSpaceIds} is cleared in
|
|
20014
|
+
* `signIn`) and only records confirmed successes. A wrong skip is
|
|
20015
|
+
* self-revealing: the next write to the space fails immediately and loudly
|
|
20016
|
+
* with `404 Space not found`.
|
|
20017
|
+
*/
|
|
19978
20018
|
async ensureOwnedSpaceHostedById(spaceId) {
|
|
19979
20019
|
if (!this.auth) {
|
|
19980
20020
|
throw new Error("Owned space hosting requires wallet mode");
|
|
@@ -19983,12 +20023,16 @@ var _TinyCloudNode = class _TinyCloudNode {
|
|
|
19983
20023
|
if (!session) {
|
|
19984
20024
|
throw new Error("Owned space hosting requires an active session");
|
|
19985
20025
|
}
|
|
20026
|
+
if (this.confirmedHostedSpaceIds.has(spaceId)) {
|
|
20027
|
+
return;
|
|
20028
|
+
}
|
|
19986
20029
|
const host = this.hosts[0] ?? this.config.host;
|
|
19987
20030
|
if (!host) {
|
|
19988
20031
|
throw new Error("Owned space hosting requires a TinyCloud host");
|
|
19989
20032
|
}
|
|
19990
20033
|
const activation = await (0, import_sdk_core7.activateSessionWithHost)(host, session.delegationHeader);
|
|
19991
20034
|
if (activation.success && !activation.skipped?.includes(spaceId)) {
|
|
20035
|
+
this.confirmedHostedSpaceIds.add(spaceId);
|
|
19992
20036
|
return;
|
|
19993
20037
|
}
|
|
19994
20038
|
if (!activation.success && activation.status !== 404) {
|
|
@@ -20007,6 +20051,7 @@ var _TinyCloudNode = class _TinyCloudNode {
|
|
|
20007
20051
|
`Failed to activate session after creating owned space ${spaceId}: ${retry.error ?? "space was skipped"}`
|
|
20008
20052
|
);
|
|
20009
20053
|
}
|
|
20054
|
+
this.confirmedHostedSpaceIds.add(spaceId);
|
|
20010
20055
|
}
|
|
20011
20056
|
/**
|
|
20012
20057
|
* Host one of this user's owned spaces by name (e.g. `"applications"`).
|
|
@@ -20329,6 +20374,7 @@ var _TinyCloudNode = class _TinyCloudNode {
|
|
|
20329
20374
|
this.tc = stagedGraph.core;
|
|
20330
20375
|
this._recapOperationsCache = stagedPrimary.cache;
|
|
20331
20376
|
this.runtimePermissionGrants = stagedPrimary.grants;
|
|
20377
|
+
this.confirmedHostedSpaceIds.clear();
|
|
20332
20378
|
if (this.auth) {
|
|
20333
20379
|
this.auth.installRestoredSession(stagedManager, stagedTcSession, [stagedHost]);
|
|
20334
20380
|
this._restoredTcSession = void 0;
|
|
@@ -20911,7 +20957,17 @@ var _TinyCloudNode = class _TinyCloudNode {
|
|
|
20911
20957
|
verifyNodeSignature: (nodeId, message, signature2) => (0, import_sdk_core7.verifyDidKeyEd25519Signature)(nodeId, message, signature2)
|
|
20912
20958
|
};
|
|
20913
20959
|
}
|
|
20960
|
+
/**
|
|
20961
|
+
* The node DID for {@link config.host}.
|
|
20962
|
+
*
|
|
20963
|
+
* Sign-in already performs `GET /info` for the protocol-version check, and
|
|
20964
|
+
* that response carries `nodeId`, so reuse it rather than fetching `/info` a
|
|
20965
|
+
* second time. Only a value recorded for this exact host qualifies; older
|
|
20966
|
+
* nodes that omit `nodeId` fall through to the fetch.
|
|
20967
|
+
*/
|
|
20914
20968
|
async fetchNodeId() {
|
|
20969
|
+
const cached = this.auth?.nodeIdForHost(this.config.host);
|
|
20970
|
+
if (cached) return cached;
|
|
20915
20971
|
const response = await fetch(`${this.config.host}/info`);
|
|
20916
20972
|
if (!response.ok) {
|
|
20917
20973
|
throw new Error(`Failed to fetch node info: HTTP ${response.status}`);
|
|
@@ -21683,6 +21739,13 @@ var _TinyCloudNode = class _TinyCloudNode {
|
|
|
21683
21739
|
body
|
|
21684
21740
|
)
|
|
21685
21741
|
});
|
|
21742
|
+
if (response.status === 409) {
|
|
21743
|
+
const existing = await this.getEncryptionNetwork(networkId);
|
|
21744
|
+
if (existing) return existing;
|
|
21745
|
+
throw new Error(
|
|
21746
|
+
`Encryption network ${networkId} already exists but could not be read back`
|
|
21747
|
+
);
|
|
21748
|
+
}
|
|
21686
21749
|
if (!response.ok) {
|
|
21687
21750
|
throw new Error(
|
|
21688
21751
|
`Failed to create encryption network ${networkId}: HTTP ${response.status} ${await response.text()}`
|
|
@@ -21691,11 +21754,19 @@ var _TinyCloudNode = class _TinyCloudNode {
|
|
|
21691
21754
|
const created = await response.json();
|
|
21692
21755
|
return created.descriptor;
|
|
21693
21756
|
}
|
|
21694
|
-
|
|
21757
|
+
/**
|
|
21758
|
+
* Ensure an encryption network exists, creating it if necessary.
|
|
21759
|
+
*
|
|
21760
|
+
* @param nameOrNetworkId - Network name or full `urn:tinycloud:encryption:` id.
|
|
21761
|
+
* @param options - See {@link EnsureEncryptionNetworkOptions}.
|
|
21762
|
+
*/
|
|
21763
|
+
async ensureEncryptionNetwork(nameOrNetworkId = DEFAULT_ENCRYPTION_NETWORK_NAME, options = {}) {
|
|
21695
21764
|
const networkId = nameOrNetworkId.startsWith("urn:tinycloud:encryption:") ? nameOrNetworkId : this.getDefaultEncryptionNetworkId(nameOrNetworkId);
|
|
21696
|
-
|
|
21697
|
-
|
|
21698
|
-
|
|
21765
|
+
if (!options.assumeMissing) {
|
|
21766
|
+
const existing = await this.getEncryptionNetwork(networkId);
|
|
21767
|
+
if (existing) {
|
|
21768
|
+
return existing;
|
|
21769
|
+
}
|
|
21699
21770
|
}
|
|
21700
21771
|
const parsed = (0, import_sdk_core7.parseNetworkId)(networkId);
|
|
21701
21772
|
if (!didPrincipalMatches2(parsed.ownerDid, this.did)) {
|