@tinycloud/node-sdk 2.4.0-beta.9 → 2.4.1-beta.0
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-iwTdsebf.d.cts → core-D01sn2vf.d.cts} +134 -7
- package/dist/{core-iwTdsebf.d.ts → core-D01sn2vf.d.ts} +134 -7
- package/dist/core.cjs +810 -268
- 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 +601 -54
- package/dist/core.js.map +1 -1
- package/dist/index.cjs +853 -311
- 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 +601 -54
- package/dist/index.js.map +1 -1
- package/package.json +2 -2
package/dist/core.js
CHANGED
|
@@ -18,7 +18,14 @@ import {
|
|
|
18
18
|
pkhDid as pkhDid3,
|
|
19
19
|
principalDid,
|
|
20
20
|
principalDidEquals as principalDidEquals3,
|
|
21
|
-
parseCanonicalNetworkId
|
|
21
|
+
parseCanonicalNetworkId,
|
|
22
|
+
TinyCloudDebugLogger,
|
|
23
|
+
tinyCloudDebugLogger,
|
|
24
|
+
enableTinyCloudDebug,
|
|
25
|
+
disableTinyCloudDebug,
|
|
26
|
+
getTinyCloudDebugLogs,
|
|
27
|
+
clearTinyCloudDebugLogs,
|
|
28
|
+
installTinyCloudDebugGlobals
|
|
22
29
|
} from "@tinycloud/sdk-core";
|
|
23
30
|
|
|
24
31
|
// src/storage/MemorySessionStorage.ts
|
|
@@ -234,6 +241,7 @@ import {
|
|
|
234
241
|
} from "@tinycloud/sdk-core";
|
|
235
242
|
|
|
236
243
|
// src/authorization/strategies.ts
|
|
244
|
+
import { createOpenKeyCallbackSigningStrategy } from "@tinycloud/sdk-core";
|
|
237
245
|
var defaultSignStrategy = { type: "auto-sign" };
|
|
238
246
|
|
|
239
247
|
// src/authorization/NodeUserAuthorization.ts
|
|
@@ -260,6 +268,7 @@ var NodeUserAuthorization = class {
|
|
|
260
268
|
constructor(config) {
|
|
261
269
|
this.extensions = [];
|
|
262
270
|
this._nodeFeatures = [];
|
|
271
|
+
this._lastActivationSkippedSpaceIds = [];
|
|
263
272
|
this.wasm = config.wasmBindings;
|
|
264
273
|
this.signer = config.signer;
|
|
265
274
|
this.signStrategy = config.signStrategy ?? defaultSignStrategy;
|
|
@@ -282,7 +291,7 @@ var NodeUserAuthorization = class {
|
|
|
282
291
|
"": [
|
|
283
292
|
"tinycloud.sql/read",
|
|
284
293
|
"tinycloud.sql/write",
|
|
285
|
-
"tinycloud.sql/
|
|
294
|
+
"tinycloud.sql/schema",
|
|
286
295
|
"tinycloud.sql/admin",
|
|
287
296
|
"tinycloud.sql/export"
|
|
288
297
|
]
|
|
@@ -374,12 +383,48 @@ var NodeUserAuthorization = class {
|
|
|
374
383
|
* `siwe` is the load-bearing one because `extractSiweExpiration` returns
|
|
375
384
|
* undefined for missing SIWEs and the SDK then treats the session as
|
|
376
385
|
* expired-at-epoch-zero.
|
|
386
|
+
*
|
|
387
|
+
* @param hosts - The TinyCloud hosts this session was created against,
|
|
388
|
+
* as persisted in {@link PersistedSessionData.tinycloudHosts}. When
|
|
389
|
+
* present (and non-empty) they are adopted directly so the restored
|
|
390
|
+
* session resolves to the same node as the original sign-in without
|
|
391
|
+
* re-running registry/fallback resolution. When absent (old session)
|
|
392
|
+
* hosts are resolved lazily on the first host-needing call via
|
|
393
|
+
* {@link ensureTinyCloudHosts}.
|
|
377
394
|
*/
|
|
378
|
-
setRestoredTinyCloudSession(session) {
|
|
395
|
+
setRestoredTinyCloudSession(session, hosts) {
|
|
379
396
|
const address = canonicalizeAddress(session.address);
|
|
380
397
|
this._tinyCloudSession = { ...session, address };
|
|
381
398
|
this._address = address;
|
|
382
399
|
this._chainId = session.chainId;
|
|
400
|
+
if ((!this.tinycloudHosts || this.tinycloudHosts.length === 0) && hosts && hosts.length > 0) {
|
|
401
|
+
this.tinycloudHosts = [...hosts];
|
|
402
|
+
}
|
|
403
|
+
}
|
|
404
|
+
/**
|
|
405
|
+
* Ensure `tinycloudHosts` are resolved before a host-needing call.
|
|
406
|
+
*
|
|
407
|
+
* Fresh sign-in resolves hosts up front; a restored session may not have
|
|
408
|
+
* (old persisted sessions predate {@link PersistedSessionData.tinycloudHosts}).
|
|
409
|
+
* This guard makes a restored session resolve the node exactly like a fresh
|
|
410
|
+
* sign-in — persisted hosts are preferred (already set by
|
|
411
|
+
* {@link setRestoredTinyCloudSession}), otherwise the registry/fallback
|
|
412
|
+
* resolution runs lazily here. Idempotent: {@link resolveTinyCloudHostsForSignIn}
|
|
413
|
+
* early-returns when hosts are already set.
|
|
414
|
+
*
|
|
415
|
+
* Throws if hosts are unset and the restored session has no address/chainId
|
|
416
|
+
* to resolve from — a real failure that must surface, not be masked.
|
|
417
|
+
*/
|
|
418
|
+
async ensureTinyCloudHosts() {
|
|
419
|
+
if (this.tinycloudHosts && this.tinycloudHosts.length > 0) {
|
|
420
|
+
return;
|
|
421
|
+
}
|
|
422
|
+
if (this._address === void 0 || this._chainId === void 0) {
|
|
423
|
+
throw new Error(
|
|
424
|
+
"Cannot resolve TinyCloud hosts: no address/chainId available. Sign in or restore a session first."
|
|
425
|
+
);
|
|
426
|
+
}
|
|
427
|
+
await this.resolveTinyCloudHostsForSignIn(this._address, this._chainId);
|
|
383
428
|
}
|
|
384
429
|
async resolveTinyCloudHostsForSignIn(address, chainId) {
|
|
385
430
|
if (this.tinycloudHosts && this.tinycloudHosts.length > 0) {
|
|
@@ -404,6 +449,9 @@ var NodeUserAuthorization = class {
|
|
|
404
449
|
get nodeFeatures() {
|
|
405
450
|
return this._nodeFeatures;
|
|
406
451
|
}
|
|
452
|
+
get lastActivationSkippedSpaceIds() {
|
|
453
|
+
return [...this._lastActivationSkippedSpaceIds];
|
|
454
|
+
}
|
|
407
455
|
/**
|
|
408
456
|
* Compute the `abilities` map the WASM `prepareSession` call should
|
|
409
457
|
* see at sign-in time.
|
|
@@ -576,6 +624,7 @@ var NodeUserAuthorization = class {
|
|
|
576
624
|
if (!this._tinyCloudSession || !this._address || !this._chainId) {
|
|
577
625
|
throw new Error("Must be signed in to host space");
|
|
578
626
|
}
|
|
627
|
+
await this.ensureTinyCloudHosts();
|
|
579
628
|
const host = this.primaryTinyCloudHost;
|
|
580
629
|
const spaceId = targetSpaceId ?? this._tinyCloudSession.spaceId;
|
|
581
630
|
const peerId = await fetchPeerId(host, spaceId);
|
|
@@ -618,12 +667,14 @@ var NodeUserAuthorization = class {
|
|
|
618
667
|
if (!this._tinyCloudSession) {
|
|
619
668
|
throw new Error("Must be signed in to ensure space exists");
|
|
620
669
|
}
|
|
670
|
+
await this.ensureTinyCloudHosts();
|
|
621
671
|
const host = this.primaryTinyCloudHost;
|
|
622
672
|
const primarySpaceId = this._tinyCloudSession.spaceId;
|
|
623
673
|
const result = await activateSessionWithHost(
|
|
624
674
|
host,
|
|
625
675
|
this._tinyCloudSession.delegationHeader
|
|
626
676
|
);
|
|
677
|
+
this.recordActivationSkippedSpaces(result, primarySpaceId);
|
|
627
678
|
const handler = this.spaceCreationHandler ?? (this.autoCreateSpace ? new AutoApproveSpaceCreationHandler() : void 0);
|
|
628
679
|
const creationContext = {
|
|
629
680
|
spaceId: primarySpaceId,
|
|
@@ -711,6 +762,66 @@ var NodeUserAuthorization = class {
|
|
|
711
762
|
}
|
|
712
763
|
throw new Error(`Failed to activate session: ${result.error}`);
|
|
713
764
|
}
|
|
765
|
+
recordActivationSkippedSpaces(result, primarySpaceId) {
|
|
766
|
+
if (result.success) {
|
|
767
|
+
this._lastActivationSkippedSpaceIds = result.skipped ?? [];
|
|
768
|
+
return;
|
|
769
|
+
}
|
|
770
|
+
this._lastActivationSkippedSpaceIds = result.status === 404 ? [primarySpaceId] : [];
|
|
771
|
+
}
|
|
772
|
+
async createBootstrapSession(options) {
|
|
773
|
+
if (!this._address || !this._chainId) {
|
|
774
|
+
throw new Error("Must be signed in before creating bootstrap sessions");
|
|
775
|
+
}
|
|
776
|
+
const address = this._address;
|
|
777
|
+
const chainId = this._chainId;
|
|
778
|
+
const keyId = `bootstrap-${Date.now()}-${Math.random().toString(36).slice(2)}`;
|
|
779
|
+
this.sessionManager.createSessionKey(keyId);
|
|
780
|
+
const jwkString = this.sessionManager.jwk(keyId);
|
|
781
|
+
if (!jwkString) {
|
|
782
|
+
throw new Error("Failed to create bootstrap session key");
|
|
783
|
+
}
|
|
784
|
+
const jwk = JSON.parse(jwkString);
|
|
785
|
+
const now = /* @__PURE__ */ new Date();
|
|
786
|
+
const expirationTime = new Date(now.getTime() + this.sessionExpirationMs);
|
|
787
|
+
const abilities = resourceCapabilitiesToAbilitiesMap(
|
|
788
|
+
options.capabilityRequest.resources
|
|
789
|
+
);
|
|
790
|
+
const prepared = this.wasm.prepareSession({
|
|
791
|
+
abilities,
|
|
792
|
+
...options.rawAbilities !== void 0 ? { rawAbilities: options.rawAbilities } : {},
|
|
793
|
+
address,
|
|
794
|
+
chainId,
|
|
795
|
+
domain: this.domain,
|
|
796
|
+
issuedAt: now.toISOString(),
|
|
797
|
+
expirationTime: expirationTime.toISOString(),
|
|
798
|
+
spaceId: options.spaceId,
|
|
799
|
+
jwk,
|
|
800
|
+
...this.buildSiweOverrides()
|
|
801
|
+
});
|
|
802
|
+
const signature = await this.requestSignature({
|
|
803
|
+
address,
|
|
804
|
+
chainId,
|
|
805
|
+
message: prepared.siwe,
|
|
806
|
+
type: "siwe"
|
|
807
|
+
});
|
|
808
|
+
const session = this.wasm.completeSessionSetup({
|
|
809
|
+
...prepared,
|
|
810
|
+
signature
|
|
811
|
+
});
|
|
812
|
+
return {
|
|
813
|
+
address,
|
|
814
|
+
chainId,
|
|
815
|
+
sessionKey: keyId,
|
|
816
|
+
spaceId: options.spaceId,
|
|
817
|
+
delegationCid: session.delegationCid,
|
|
818
|
+
delegationHeader: session.delegationHeader,
|
|
819
|
+
verificationMethod: this.sessionManager.getDID(keyId),
|
|
820
|
+
jwk,
|
|
821
|
+
siwe: prepared.siwe,
|
|
822
|
+
signature
|
|
823
|
+
};
|
|
824
|
+
}
|
|
714
825
|
/**
|
|
715
826
|
* Sign in and create a new session.
|
|
716
827
|
*
|
|
@@ -799,7 +910,8 @@ var NodeUserAuthorization = class {
|
|
|
799
910
|
},
|
|
800
911
|
expiresAt: expirationTime.toISOString(),
|
|
801
912
|
createdAt: now.toISOString(),
|
|
802
|
-
version: "1.0"
|
|
913
|
+
version: "1.0",
|
|
914
|
+
tinycloudHosts: this.tinycloudHosts
|
|
803
915
|
};
|
|
804
916
|
await this.sessionStorage.save(address, persistedData);
|
|
805
917
|
this._session = clientSession;
|
|
@@ -966,7 +1078,8 @@ var NodeUserAuthorization = class {
|
|
|
966
1078
|
},
|
|
967
1079
|
expiresAt,
|
|
968
1080
|
createdAt,
|
|
969
|
-
version: "1.0"
|
|
1081
|
+
version: "1.0",
|
|
1082
|
+
tinycloudHosts: this.tinycloudHosts
|
|
970
1083
|
};
|
|
971
1084
|
await this.sessionStorage.save(address, persistedData);
|
|
972
1085
|
this._session = clientSession;
|
|
@@ -1077,6 +1190,11 @@ import {
|
|
|
1077
1190
|
UnsupportedFeatureError,
|
|
1078
1191
|
makePublicSpaceId,
|
|
1079
1192
|
ACCOUNT_REGISTRY_SPACE,
|
|
1193
|
+
BOOTSTRAP_SESSION_REQUESTS,
|
|
1194
|
+
SECRET_RECORDS_SCHEMA,
|
|
1195
|
+
SECRETS_SPACE as SECRETS_SPACE2,
|
|
1196
|
+
TINYCLOUD_SECRETS_BOOTSTRAP_MANIFEST,
|
|
1197
|
+
bootstrapSteps,
|
|
1080
1198
|
ENCRYPTION_PERMISSION_SERVICE as ENCRYPTION_PERMISSION_SERVICE2,
|
|
1081
1199
|
PermissionNotInManifestError,
|
|
1082
1200
|
SessionExpiredError,
|
|
@@ -1090,6 +1208,7 @@ import {
|
|
|
1090
1208
|
verifyDidKeyEd25519Signature,
|
|
1091
1209
|
canonicalizeAddress as canonicalizeAddress2,
|
|
1092
1210
|
pkhDid as pkhDid2,
|
|
1211
|
+
resolveTinyCloudHosts as resolveTinyCloudHosts2,
|
|
1093
1212
|
principalDidEquals as principalDidEquals2,
|
|
1094
1213
|
parseNetworkId as parseNetworkId2
|
|
1095
1214
|
} from "@tinycloud/sdk-core";
|
|
@@ -1106,12 +1225,13 @@ import {
|
|
|
1106
1225
|
ServiceContext
|
|
1107
1226
|
} from "@tinycloud/sdk-core";
|
|
1108
1227
|
var DelegatedAccess = class {
|
|
1109
|
-
constructor(session, delegation, host, invoke, telemetry) {
|
|
1228
|
+
constructor(session, delegation, host, invoke, invokeAny, telemetry) {
|
|
1110
1229
|
this.session = session;
|
|
1111
1230
|
this._delegation = delegation;
|
|
1112
1231
|
this.host = host;
|
|
1113
1232
|
this._serviceContext = new ServiceContext({
|
|
1114
1233
|
invoke,
|
|
1234
|
+
invokeAny,
|
|
1115
1235
|
fetch: globalThis.fetch.bind(globalThis),
|
|
1116
1236
|
hosts: [host],
|
|
1117
1237
|
telemetry
|
|
@@ -1378,12 +1498,12 @@ function displayActionUrn(action) {
|
|
|
1378
1498
|
function secretActionName(action) {
|
|
1379
1499
|
return action;
|
|
1380
1500
|
}
|
|
1381
|
-
function secretPermissionEntries(name, options, action, encryptionNetworkId) {
|
|
1501
|
+
function secretPermissionEntries(name, options, action, space, encryptionNetworkId) {
|
|
1382
1502
|
const entries = [];
|
|
1383
1503
|
const path = action === "list" ? resolveSecretListPrefix(options) : resolveSecretPath(name, options).permissionPaths.vault;
|
|
1384
1504
|
entries.push({
|
|
1385
1505
|
service: "tinycloud.kv",
|
|
1386
|
-
space
|
|
1506
|
+
space,
|
|
1387
1507
|
path,
|
|
1388
1508
|
actions: [secretActionName(action)],
|
|
1389
1509
|
skipPrefix: true
|
|
@@ -1398,11 +1518,23 @@ function secretPermissionEntries(name, options, action, encryptionNetworkId) {
|
|
|
1398
1518
|
}
|
|
1399
1519
|
return entries;
|
|
1400
1520
|
}
|
|
1521
|
+
function normalizeSpace(space, resolveSpace) {
|
|
1522
|
+
if (!space) return void 0;
|
|
1523
|
+
if (space.startsWith("tinycloud:")) return space;
|
|
1524
|
+
return resolveSpace?.(space) ?? space;
|
|
1525
|
+
}
|
|
1526
|
+
function spaceMatches(granted, requested, resolveSpace) {
|
|
1527
|
+
if (!granted || !requested) return false;
|
|
1528
|
+
return normalizeSpace(granted, resolveSpace) === normalizeSpace(requested, resolveSpace);
|
|
1529
|
+
}
|
|
1401
1530
|
var NodeSecretsService = class {
|
|
1402
1531
|
constructor(config) {
|
|
1403
1532
|
this.config = config;
|
|
1404
1533
|
this.shouldRestoreUnlock = false;
|
|
1405
1534
|
}
|
|
1535
|
+
get space() {
|
|
1536
|
+
return this.config.space ?? SECRETS_SPACE;
|
|
1537
|
+
}
|
|
1406
1538
|
get vault() {
|
|
1407
1539
|
return this.service.vault;
|
|
1408
1540
|
}
|
|
@@ -1455,6 +1587,7 @@ var NodeSecretsService = class {
|
|
|
1455
1587
|
name,
|
|
1456
1588
|
options,
|
|
1457
1589
|
action,
|
|
1590
|
+
this.space,
|
|
1458
1591
|
action === "get" ? this.config.getEncryptionNetworkId?.() : void 0
|
|
1459
1592
|
);
|
|
1460
1593
|
} catch (error) {
|
|
@@ -1504,7 +1637,7 @@ var NodeSecretsService = class {
|
|
|
1504
1637
|
(entry) => manifests.some((candidate) => {
|
|
1505
1638
|
const resolved = resolveManifest(candidate);
|
|
1506
1639
|
return resolved.resources.some(
|
|
1507
|
-
(resource) => resource.service === entry.service && resource.space
|
|
1640
|
+
(resource) => resource.service === entry.service && spaceMatches(resource.space, entry.space, this.config.resolveSpace) && resource.path === entry.path && entry.actions.every((action) => resource.actions.includes(action))
|
|
1508
1641
|
);
|
|
1509
1642
|
})
|
|
1510
1643
|
);
|
|
@@ -1518,6 +1651,9 @@ var NETWORK_CREATE_ACTION2 = "tinycloud.encryption/network.create";
|
|
|
1518
1651
|
var DECRYPT_ACTION2 = "tinycloud.encryption/decrypt";
|
|
1519
1652
|
var NETWORK_ADMIN_TYPE = "tinycloud.encryption.network-admin/v1";
|
|
1520
1653
|
var DEFAULT_SESSION_EXPIRATION_MS = EXPIRY3.SESSION_MS;
|
|
1654
|
+
function isOpenKeyAutoSignStrategy(strategy) {
|
|
1655
|
+
return strategy?.openKeyAutoSign === true;
|
|
1656
|
+
}
|
|
1521
1657
|
function didPrincipalMatches2(actual, expected) {
|
|
1522
1658
|
try {
|
|
1523
1659
|
return principalDidEquals2(actual, expected);
|
|
@@ -1525,6 +1661,20 @@ function didPrincipalMatches2(actual, expected) {
|
|
|
1525
1661
|
return actual === expected;
|
|
1526
1662
|
}
|
|
1527
1663
|
}
|
|
1664
|
+
function sharingActionsToAbilities(path, actions) {
|
|
1665
|
+
var _a;
|
|
1666
|
+
const abilities = {};
|
|
1667
|
+
for (const action of actions) {
|
|
1668
|
+
const slash = action.indexOf("/");
|
|
1669
|
+
if (slash === -1) return void 0;
|
|
1670
|
+
const shortService = SERVICE_LONG_TO_SHORT[action.slice(0, slash)];
|
|
1671
|
+
if (shortService === void 0) return void 0;
|
|
1672
|
+
abilities[shortService] ?? (abilities[shortService] = {});
|
|
1673
|
+
(_a = abilities[shortService])[path] ?? (_a[path] = []);
|
|
1674
|
+
abilities[shortService][path].push(action);
|
|
1675
|
+
}
|
|
1676
|
+
return Object.keys(abilities).length > 0 ? abilities : void 0;
|
|
1677
|
+
}
|
|
1528
1678
|
function base64UrlEncode(bytes) {
|
|
1529
1679
|
const alphabet = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789-_";
|
|
1530
1680
|
let output = "";
|
|
@@ -1637,6 +1787,8 @@ var _TinyCloudNode = class _TinyCloudNode {
|
|
|
1637
1787
|
this.auth = null;
|
|
1638
1788
|
this.tc = null;
|
|
1639
1789
|
this._chainId = 1;
|
|
1790
|
+
this._baseSecrets = /* @__PURE__ */ new Map();
|
|
1791
|
+
this._secrets = /* @__PURE__ */ new Map();
|
|
1640
1792
|
this.runtimePermissionGrants = [];
|
|
1641
1793
|
this.invokeWithRuntimePermissions = (session, service, path, action, facts) => {
|
|
1642
1794
|
return this.wasmBindings.invoke(
|
|
@@ -1742,9 +1894,10 @@ var _TinyCloudNode = class _TinyCloudNode {
|
|
|
1742
1894
|
* @internal
|
|
1743
1895
|
*/
|
|
1744
1896
|
setupAuth(config) {
|
|
1897
|
+
const useBootstrapSignInRequest = this.shouldUseBootstrapSignInRequest(config);
|
|
1745
1898
|
this.auth = new NodeUserAuthorization({
|
|
1746
1899
|
signer: this.signer,
|
|
1747
|
-
signStrategy: { type: "auto-sign" },
|
|
1900
|
+
signStrategy: config.signStrategy ?? { type: "auto-sign" },
|
|
1748
1901
|
wasmBindings: this.wasmBindings,
|
|
1749
1902
|
sessionStorage: config.sessionStorage ?? new MemorySessionStorage(),
|
|
1750
1903
|
domain: this.siweDomain,
|
|
@@ -1753,20 +1906,23 @@ var _TinyCloudNode = class _TinyCloudNode {
|
|
|
1753
1906
|
tinycloudHosts: this.explicitHost ? [this.explicitHost] : void 0,
|
|
1754
1907
|
tinycloudRegistryUrl: config.tinycloudRegistryUrl,
|
|
1755
1908
|
tinycloudFallbackHosts: config.tinycloudFallbackHosts,
|
|
1756
|
-
autoCreateSpace: config.autoCreateSpace,
|
|
1909
|
+
autoCreateSpace: useBootstrapSignInRequest ? false : config.autoCreateSpace,
|
|
1757
1910
|
enablePublicSpace: config.enablePublicSpace ?? true,
|
|
1758
|
-
spaceCreationHandler: config.spaceCreationHandler,
|
|
1911
|
+
spaceCreationHandler: useBootstrapSignInRequest ? void 0 : config.spaceCreationHandler,
|
|
1759
1912
|
nonce: config.nonce,
|
|
1760
1913
|
siweConfig: config.siweConfig,
|
|
1761
|
-
manifest: config.manifest,
|
|
1762
|
-
capabilityRequest: config.capabilityRequest,
|
|
1763
|
-
includeAccountRegistryPermissions: config.includeAccountRegistryPermissions
|
|
1914
|
+
manifest: useBootstrapSignInRequest ? void 0 : config.manifest,
|
|
1915
|
+
capabilityRequest: useBootstrapSignInRequest ? BOOTSTRAP_SESSION_REQUESTS.default : config.capabilityRequest,
|
|
1916
|
+
includeAccountRegistryPermissions: useBootstrapSignInRequest ? false : config.includeAccountRegistryPermissions
|
|
1764
1917
|
});
|
|
1765
1918
|
this.tc = new TinyCloud(this.auth, {
|
|
1766
1919
|
invokeAny: this.invokeAnyWithRuntimePermissions,
|
|
1767
1920
|
telemetry: config.telemetry
|
|
1768
1921
|
});
|
|
1769
1922
|
}
|
|
1923
|
+
shouldUseBootstrapSignInRequest(config) {
|
|
1924
|
+
return config.autoBootstrapAccount !== false && config.manifest === void 0 && config.capabilityRequest === void 0 && (config.prefix ?? "default") === "default" && isOpenKeyAutoSignStrategy(config.signStrategy);
|
|
1925
|
+
}
|
|
1770
1926
|
syncResolvedHostFromAuth() {
|
|
1771
1927
|
const host = this.auth?.hosts[0];
|
|
1772
1928
|
if (host) {
|
|
@@ -1881,7 +2037,7 @@ var _TinyCloudNode = class _TinyCloudNode {
|
|
|
1881
2037
|
getAccountDb: () => this.accountSpaceId ? this.sqlForSpace(this.accountSpaceId).db("account") : void 0,
|
|
1882
2038
|
ensureAccountSpaceHosted: async () => {
|
|
1883
2039
|
if (this.accountSpaceId && this.auth) {
|
|
1884
|
-
await this.
|
|
2040
|
+
await this.ensureOwnedSpaceHostedById(this.accountSpaceId);
|
|
1885
2041
|
}
|
|
1886
2042
|
}
|
|
1887
2043
|
});
|
|
@@ -1895,6 +2051,13 @@ var _TinyCloudNode = class _TinyCloudNode {
|
|
|
1895
2051
|
get session() {
|
|
1896
2052
|
return this.auth?.tinyCloudSession;
|
|
1897
2053
|
}
|
|
2054
|
+
/**
|
|
2055
|
+
* Get the currently active session in the shape callers can persist and later
|
|
2056
|
+
* pass back to {@link restoreSession}.
|
|
2057
|
+
*/
|
|
2058
|
+
get restorableSession() {
|
|
2059
|
+
return this.currentTinyCloudSession();
|
|
2060
|
+
}
|
|
1898
2061
|
/**
|
|
1899
2062
|
* Sign in and create a new session.
|
|
1900
2063
|
* This creates the user's space if it doesn't exist.
|
|
@@ -1917,19 +2080,22 @@ var _TinyCloudNode = class _TinyCloudNode {
|
|
|
1917
2080
|
this._hooks = void 0;
|
|
1918
2081
|
this._vault = void 0;
|
|
1919
2082
|
this._encryption = void 0;
|
|
1920
|
-
this._baseSecrets
|
|
1921
|
-
this._secrets
|
|
2083
|
+
this._baseSecrets.clear();
|
|
2084
|
+
this._secrets.clear();
|
|
1922
2085
|
this._spaceService = void 0;
|
|
1923
2086
|
this._serviceContext = void 0;
|
|
1924
2087
|
this.runtimePermissionGrants = [];
|
|
1925
2088
|
await this.tc.signIn(options);
|
|
1926
2089
|
this.syncResolvedHostFromAuth();
|
|
1927
2090
|
this.initializeServices();
|
|
2091
|
+
const bootstrapped = await this.bootstrapAccountIfNeeded();
|
|
1928
2092
|
await this.ensureRequestedEncryptionNetworks();
|
|
1929
|
-
if (this.config.manifest === void 0 && this.config.capabilityRequest === void 0) {
|
|
1930
|
-
await this.
|
|
2093
|
+
if (!bootstrapped && this.config.manifest === void 0 && this.config.capabilityRequest === void 0) {
|
|
2094
|
+
await this.ensureOwnedSpaceHostedById(this.ownedSpaceId(SECRETS_SPACE2));
|
|
2095
|
+
}
|
|
2096
|
+
if (!bootstrapped) {
|
|
2097
|
+
this.scheduleAccountRegistrySync();
|
|
1931
2098
|
}
|
|
1932
|
-
this.scheduleAccountRegistrySync();
|
|
1933
2099
|
this.notificationHandler.success("Successfully signed in");
|
|
1934
2100
|
}
|
|
1935
2101
|
ownedSpaceId(name) {
|
|
@@ -1938,6 +2104,208 @@ var _TinyCloudNode = class _TinyCloudNode {
|
|
|
1938
2104
|
}
|
|
1939
2105
|
return this.wasmBindings.makeSpaceId(this._address, this._chainId, name);
|
|
1940
2106
|
}
|
|
2107
|
+
async bootstrapAccountIfNeeded() {
|
|
2108
|
+
if (this.config.autoBootstrapAccount === false) {
|
|
2109
|
+
return false;
|
|
2110
|
+
}
|
|
2111
|
+
if (!this.auth || !this._address) {
|
|
2112
|
+
return false;
|
|
2113
|
+
}
|
|
2114
|
+
const steps = bootstrapSteps(this._address, this._chainId);
|
|
2115
|
+
if (!await this.isFreshBootstrapAccount(steps)) {
|
|
2116
|
+
return false;
|
|
2117
|
+
}
|
|
2118
|
+
await this.runAccountBootstrap(steps);
|
|
2119
|
+
return true;
|
|
2120
|
+
}
|
|
2121
|
+
async isFreshBootstrapAccount(steps) {
|
|
2122
|
+
const enshrinedSpaceIds = /* @__PURE__ */ new Set();
|
|
2123
|
+
for (const step of steps) {
|
|
2124
|
+
if (step.kind === "session") {
|
|
2125
|
+
enshrinedSpaceIds.add(step.spaceId);
|
|
2126
|
+
}
|
|
2127
|
+
}
|
|
2128
|
+
const skipped = this.auth.lastActivationSkippedSpaceIds;
|
|
2129
|
+
if (skipped.some((spaceId) => enshrinedSpaceIds.has(spaceId))) {
|
|
2130
|
+
return true;
|
|
2131
|
+
}
|
|
2132
|
+
try {
|
|
2133
|
+
const indexed = await this.account.index.spaces.list();
|
|
2134
|
+
if (indexed.ok && indexed.data.length === 0) {
|
|
2135
|
+
return true;
|
|
2136
|
+
}
|
|
2137
|
+
} catch {
|
|
2138
|
+
}
|
|
2139
|
+
try {
|
|
2140
|
+
const spaces = await this.account.spaces.list();
|
|
2141
|
+
return spaces.ok && spaces.data.length === 0;
|
|
2142
|
+
} catch {
|
|
2143
|
+
return false;
|
|
2144
|
+
}
|
|
2145
|
+
}
|
|
2146
|
+
async runAccountBootstrap(steps) {
|
|
2147
|
+
if (!this.auth || !this._address) {
|
|
2148
|
+
throw new Error("Account bootstrap requires an active wallet session");
|
|
2149
|
+
}
|
|
2150
|
+
const host = this.hosts[0] ?? this.config.host;
|
|
2151
|
+
if (!host) {
|
|
2152
|
+
throw new Error("Account bootstrap requires a TinyCloud host");
|
|
2153
|
+
}
|
|
2154
|
+
const auth = this.auth;
|
|
2155
|
+
const sessions = /* @__PURE__ */ new Map();
|
|
2156
|
+
const rawAbilitiesBySpace = /* @__PURE__ */ new Map();
|
|
2157
|
+
const primarySession = auth.tinyCloudSession;
|
|
2158
|
+
const defaultSpaceId = this.ownedSpaceId("default");
|
|
2159
|
+
const canReusePrimaryBootstrapSession = primarySession?.spaceId === defaultSpaceId && auth.capabilityRequest === BOOTSTRAP_SESSION_REQUESTS.default;
|
|
2160
|
+
for (const step of steps) {
|
|
2161
|
+
if (step.kind !== "session") continue;
|
|
2162
|
+
if (step.space === "default" && canReusePrimaryBootstrapSession && primarySession) {
|
|
2163
|
+
sessions.set(step.space, primarySession);
|
|
2164
|
+
continue;
|
|
2165
|
+
}
|
|
2166
|
+
const rawAbilities = step.rawAbilities;
|
|
2167
|
+
if (rawAbilities) {
|
|
2168
|
+
rawAbilitiesBySpace.set(step.space, rawAbilities);
|
|
2169
|
+
}
|
|
2170
|
+
const session = await auth.createBootstrapSession({
|
|
2171
|
+
spaceId: step.spaceId,
|
|
2172
|
+
capabilityRequest: step.request ?? BOOTSTRAP_SESSION_REQUESTS[step.space],
|
|
2173
|
+
rawAbilities
|
|
2174
|
+
});
|
|
2175
|
+
sessions.set(step.space, session);
|
|
2176
|
+
}
|
|
2177
|
+
for (const step of steps) {
|
|
2178
|
+
if (step.kind !== "host") continue;
|
|
2179
|
+
const hosted = await auth.hostOwnedSpace(step.spaceId);
|
|
2180
|
+
if (!hosted) {
|
|
2181
|
+
throw new Error(`Failed to host bootstrap space: ${step.spaceId}`);
|
|
2182
|
+
}
|
|
2183
|
+
}
|
|
2184
|
+
await new Promise((resolve) => setTimeout(resolve, 100));
|
|
2185
|
+
for (const step of steps) {
|
|
2186
|
+
if (step.kind !== "activate") continue;
|
|
2187
|
+
const session = sessions.get(step.space);
|
|
2188
|
+
if (!session) {
|
|
2189
|
+
throw new Error(`Missing bootstrap session for ${step.space}`);
|
|
2190
|
+
}
|
|
2191
|
+
const activated = await activateSessionWithHost2(host, session.delegationHeader);
|
|
2192
|
+
if (!activated.success || activated.skipped?.includes(step.spaceId)) {
|
|
2193
|
+
throw new Error(
|
|
2194
|
+
`Failed to activate bootstrap session for ${step.spaceId}: ${activated.error ?? "space was skipped"}`
|
|
2195
|
+
);
|
|
2196
|
+
}
|
|
2197
|
+
this.registerBootstrapRuntimeGrant(
|
|
2198
|
+
session,
|
|
2199
|
+
BOOTSTRAP_SESSION_REQUESTS[step.space],
|
|
2200
|
+
rawAbilitiesBySpace.get(step.space)
|
|
2201
|
+
);
|
|
2202
|
+
}
|
|
2203
|
+
for (const step of steps) {
|
|
2204
|
+
if (step.kind === "account-index-schema") {
|
|
2205
|
+
const ensured = await this.account.index.ensure();
|
|
2206
|
+
if (!ensured.ok) {
|
|
2207
|
+
throw new Error(`Failed to create account index schema: ${ensured.error.message}`);
|
|
2208
|
+
}
|
|
2209
|
+
}
|
|
2210
|
+
if (step.kind === "seed-spaces") {
|
|
2211
|
+
for (const space of step.spaces) {
|
|
2212
|
+
const registered = await this.account.spaces.register({
|
|
2213
|
+
spaceId: space.spaceId,
|
|
2214
|
+
name: space.name,
|
|
2215
|
+
ownerDid: this.did,
|
|
2216
|
+
type: "owned",
|
|
2217
|
+
permissions: ["*"],
|
|
2218
|
+
status: "active"
|
|
2219
|
+
});
|
|
2220
|
+
if (!registered.ok) {
|
|
2221
|
+
throw new Error(
|
|
2222
|
+
`Failed to seed account space ${space.spaceId}: ${registered.error.message}`
|
|
2223
|
+
);
|
|
2224
|
+
}
|
|
2225
|
+
}
|
|
2226
|
+
}
|
|
2227
|
+
if (step.kind === "seed-applications") {
|
|
2228
|
+
const registered = await this.account.applications.register(
|
|
2229
|
+
step.manifests.length > 0 ? [...step.manifests] : TINYCLOUD_SECRETS_BOOTSTRAP_MANIFEST
|
|
2230
|
+
);
|
|
2231
|
+
if (!registered.ok) {
|
|
2232
|
+
throw new Error(`Failed to seed bootstrap applications: ${registered.error.message}`);
|
|
2233
|
+
}
|
|
2234
|
+
}
|
|
2235
|
+
if (step.kind === "encryption-network-create") {
|
|
2236
|
+
await this.ensureEncryptionNetwork(step.networkId);
|
|
2237
|
+
}
|
|
2238
|
+
if (step.kind === "secret-records-schema") {
|
|
2239
|
+
const db = this.sqlForSpace(step.spaceId).db(step.database);
|
|
2240
|
+
const migrated = await db.migrations.apply({
|
|
2241
|
+
namespace: "tinycloud.secrets.records",
|
|
2242
|
+
migrations: [
|
|
2243
|
+
{
|
|
2244
|
+
id: "001_initial",
|
|
2245
|
+
sql: [...SECRET_RECORDS_SCHEMA]
|
|
2246
|
+
}
|
|
2247
|
+
]
|
|
2248
|
+
});
|
|
2249
|
+
if (!migrated.ok) {
|
|
2250
|
+
throw new Error(
|
|
2251
|
+
`Failed to create secret_records schema: ${migrated.error.message}`
|
|
2252
|
+
);
|
|
2253
|
+
}
|
|
2254
|
+
}
|
|
2255
|
+
}
|
|
2256
|
+
}
|
|
2257
|
+
registerBootstrapRuntimeGrant(session, request, rawAbilities) {
|
|
2258
|
+
const operations = [];
|
|
2259
|
+
for (const resource of request.resources) {
|
|
2260
|
+
const service = resource.service.startsWith("tinycloud.") ? this.shortServiceName(resource.service) : resource.service;
|
|
2261
|
+
const spaceId = resource.space.startsWith("tinycloud:") ? resource.space : this.ownedSpaceId(resource.space);
|
|
2262
|
+
for (const action of resource.actions) {
|
|
2263
|
+
operations.push({
|
|
2264
|
+
spaceId,
|
|
2265
|
+
service,
|
|
2266
|
+
path: resource.path,
|
|
2267
|
+
action
|
|
2268
|
+
});
|
|
2269
|
+
}
|
|
2270
|
+
}
|
|
2271
|
+
for (const [resource, actions2] of Object.entries(rawAbilities ?? {})) {
|
|
2272
|
+
for (const action of actions2) {
|
|
2273
|
+
operations.push({
|
|
2274
|
+
resource,
|
|
2275
|
+
service: "encryption",
|
|
2276
|
+
path: resource,
|
|
2277
|
+
action
|
|
2278
|
+
});
|
|
2279
|
+
}
|
|
2280
|
+
}
|
|
2281
|
+
const expiresAt = extractSiweExpiration(session.siwe) ?? this.getSessionExpiry();
|
|
2282
|
+
const actions = [...new Set(operations.map((operation) => operation.action))];
|
|
2283
|
+
this.runtimePermissionGrants.push({
|
|
2284
|
+
session: {
|
|
2285
|
+
delegationHeader: session.delegationHeader,
|
|
2286
|
+
delegationCid: session.delegationCid,
|
|
2287
|
+
spaceId: session.spaceId,
|
|
2288
|
+
verificationMethod: session.verificationMethod,
|
|
2289
|
+
jwk: session.jwk
|
|
2290
|
+
},
|
|
2291
|
+
delegation: {
|
|
2292
|
+
cid: session.delegationCid,
|
|
2293
|
+
delegationHeader: session.delegationHeader,
|
|
2294
|
+
delegateDID: session.verificationMethod,
|
|
2295
|
+
delegatorDID: this.did,
|
|
2296
|
+
spaceId: session.spaceId,
|
|
2297
|
+
path: "",
|
|
2298
|
+
actions,
|
|
2299
|
+
expiry: expiresAt,
|
|
2300
|
+
allowSubDelegation: true,
|
|
2301
|
+
ownerAddress: session.address,
|
|
2302
|
+
chainId: session.chainId,
|
|
2303
|
+
host: this.config.host
|
|
2304
|
+
},
|
|
2305
|
+
operations,
|
|
2306
|
+
expiresAt
|
|
2307
|
+
});
|
|
2308
|
+
}
|
|
1941
2309
|
async writeManifestRegistryRecords() {
|
|
1942
2310
|
const request = this.capabilityRequest;
|
|
1943
2311
|
if (!request || request.registryRecords.length === 0) {
|
|
@@ -1947,7 +2315,7 @@ var _TinyCloudNode = class _TinyCloudNode {
|
|
|
1947
2315
|
throw new Error("Manifest registry write requires wallet mode");
|
|
1948
2316
|
}
|
|
1949
2317
|
const accountSpaceId = this.ownedSpaceId(ACCOUNT_REGISTRY_SPACE);
|
|
1950
|
-
await this.
|
|
2318
|
+
await this.ensureOwnedSpaceHostedById(accountSpaceId);
|
|
1951
2319
|
const result = await this.account.applications.register(request.manifests);
|
|
1952
2320
|
if (!result.ok) {
|
|
1953
2321
|
throw new Error(
|
|
@@ -1957,6 +2325,7 @@ var _TinyCloudNode = class _TinyCloudNode {
|
|
|
1957
2325
|
}
|
|
1958
2326
|
scheduleAccountRegistrySync() {
|
|
1959
2327
|
void this.withAccountRegistryRetry(async () => {
|
|
2328
|
+
void this.account.index.ensure();
|
|
1960
2329
|
await this.writeManifestRegistryRecords();
|
|
1961
2330
|
const spaces = await this.account.spaces.syncAccessible();
|
|
1962
2331
|
if (!spaces.ok) {
|
|
@@ -2008,7 +2377,7 @@ var _TinyCloudNode = class _TinyCloudNode {
|
|
|
2008
2377
|
await this.ensureEncryptionNetwork(networkId);
|
|
2009
2378
|
}
|
|
2010
2379
|
}
|
|
2011
|
-
async
|
|
2380
|
+
async ensureOwnedSpaceHostedById(spaceId) {
|
|
2012
2381
|
if (!this.auth) {
|
|
2013
2382
|
throw new Error("Owned space hosting requires wallet mode");
|
|
2014
2383
|
}
|
|
@@ -2051,7 +2420,7 @@ var _TinyCloudNode = class _TinyCloudNode {
|
|
|
2051
2420
|
* caller is the root authority of their own owned spaces, so no additional
|
|
2052
2421
|
* delegation is required.
|
|
2053
2422
|
*
|
|
2054
|
-
* Unlike {@link
|
|
2423
|
+
* Unlike {@link ensureOwnedSpaceHostedById}, this always submits the host
|
|
2055
2424
|
* delegation rather than inferring hosting from session activation: a space
|
|
2056
2425
|
* the current session has never referenced is reported neither as
|
|
2057
2426
|
* `activated` nor `skipped`, so activation-based detection would wrongly
|
|
@@ -2096,6 +2465,91 @@ var _TinyCloudNode = class _TinyCloudNode {
|
|
|
2096
2465
|
});
|
|
2097
2466
|
return spaceId;
|
|
2098
2467
|
}
|
|
2468
|
+
/**
|
|
2469
|
+
* Ensure one of this user's owned spaces (e.g. `"secrets"`) is hosted on the
|
|
2470
|
+
* server.
|
|
2471
|
+
*
|
|
2472
|
+
* At sign-in, a full-authority session auto-hosts the owner's `secrets`
|
|
2473
|
+
* space, but a session created with a manifest / capabilityRequest does not.
|
|
2474
|
+
* Such a session can therefore hold valid `tinycloud.kv/*` capabilities for
|
|
2475
|
+
* the owned `secrets` space yet still fail its first scoped
|
|
2476
|
+
* `secrets.put(...)` with `404 Space not found`, because the space was never
|
|
2477
|
+
* registered on the node.
|
|
2478
|
+
*
|
|
2479
|
+
* Calling this resolves `name` to the owner's owned-space URI
|
|
2480
|
+
* (`tinycloud:pkh:eip155:<chain>:<addr>:<name>`). It first consults the
|
|
2481
|
+
* account-space spaces registry (`account/spaces/{space_id}`, the canonical
|
|
2482
|
+
* KV source of truth, fronted by a best-effort SQLite index): if the space is
|
|
2483
|
+
* already registered/hosted it returns the URI WITHOUT submitting a host
|
|
2484
|
+
* delegation, avoiding a redundant host-SIWE signature prompt for owners who
|
|
2485
|
+
* already use the space. Only when the space is absent — or the registry
|
|
2486
|
+
* check fails for any reason (e.g. a cold SQLite index reporting
|
|
2487
|
+
* `no such table: spaces`) — does it fall through to {@link hostOwnedSpace}.
|
|
2488
|
+
*
|
|
2489
|
+
* The registry check is purely an optimization: any failure falls back to
|
|
2490
|
+
* hosting, and the host SIWE is idempotent server-side, so re-hosting an
|
|
2491
|
+
* existing space remains a safe no-op. Must be called after {@link signIn}.
|
|
2492
|
+
*
|
|
2493
|
+
* @param name - The owned space name (e.g. `"secrets"`).
|
|
2494
|
+
* @returns The hosted owned-space URI.
|
|
2495
|
+
*/
|
|
2496
|
+
async ensureOwnedSpaceHosted(name) {
|
|
2497
|
+
if (!this.auth || !this.auth.tinyCloudSession) {
|
|
2498
|
+
throw new Error("Not signed in. Call signIn() first.");
|
|
2499
|
+
}
|
|
2500
|
+
const spaceId = this.ownedSpaceId(name);
|
|
2501
|
+
if (await this.isOwnedSpaceRegistered(spaceId)) {
|
|
2502
|
+
return spaceId;
|
|
2503
|
+
}
|
|
2504
|
+
const hosted = await this.hostOwnedSpace(name);
|
|
2505
|
+
try {
|
|
2506
|
+
await this.account.spaces.register({
|
|
2507
|
+
spaceId,
|
|
2508
|
+
name,
|
|
2509
|
+
ownerDid: this.did,
|
|
2510
|
+
type: "owned",
|
|
2511
|
+
permissions: ["*"],
|
|
2512
|
+
status: "active"
|
|
2513
|
+
});
|
|
2514
|
+
} catch {
|
|
2515
|
+
}
|
|
2516
|
+
return hosted;
|
|
2517
|
+
}
|
|
2518
|
+
/**
|
|
2519
|
+
* Check whether an owned space is already registered/hosted by consulting the
|
|
2520
|
+
* account spaces registry.
|
|
2521
|
+
*
|
|
2522
|
+
* Source of truth is the canonical KV registry record
|
|
2523
|
+
* `account/spaces/{space_id}`, read here via `account.spaces.get(spaceId)`.
|
|
2524
|
+
* The KV path is used (rather than `syncAccessible()`) because it works under
|
|
2525
|
+
* a manifest/recap session with NO extra prompt: the composed manifest recap
|
|
2526
|
+
* already grants `tinycloud.kv get/list` on the account space `spaces/`
|
|
2527
|
+
* prefix, whereas `syncAccessible()` depends on `tinycloud.space/list`, which
|
|
2528
|
+
* a recap session does not hold. Before reading, it consults the fast SQLite
|
|
2529
|
+
* index (`account.index.spaces.list()`) as a best-effort short-circuit; on a
|
|
2530
|
+
* cold index (`no such table: spaces`) or any other index failure it falls
|
|
2531
|
+
* back to the canonical KV read.
|
|
2532
|
+
*
|
|
2533
|
+
* This is a best-effort optimization. ANY failure of the check path (missing
|
|
2534
|
+
* table, KV error, missing record, thrown exception) resolves to `false` so
|
|
2535
|
+
* the caller falls through to hosting — per the directive, "if it fails in any
|
|
2536
|
+
* way then create the space".
|
|
2537
|
+
*/
|
|
2538
|
+
async isOwnedSpaceRegistered(spaceId) {
|
|
2539
|
+
try {
|
|
2540
|
+
const indexed = await this.account.index.spaces.list();
|
|
2541
|
+
if (indexed.ok && indexed.data.some((space) => space.spaceId === spaceId)) {
|
|
2542
|
+
return true;
|
|
2543
|
+
}
|
|
2544
|
+
} catch {
|
|
2545
|
+
}
|
|
2546
|
+
try {
|
|
2547
|
+
const record = await this.account.spaces.get(spaceId);
|
|
2548
|
+
return record.ok;
|
|
2549
|
+
} catch {
|
|
2550
|
+
return false;
|
|
2551
|
+
}
|
|
2552
|
+
}
|
|
2099
2553
|
/**
|
|
2100
2554
|
* Restore a previously established session from stored delegation data.
|
|
2101
2555
|
*
|
|
@@ -2113,8 +2567,8 @@ var _TinyCloudNode = class _TinyCloudNode {
|
|
|
2113
2567
|
this._hooks = void 0;
|
|
2114
2568
|
this._vault = void 0;
|
|
2115
2569
|
this._encryption = void 0;
|
|
2116
|
-
this._baseSecrets
|
|
2117
|
-
this._secrets
|
|
2570
|
+
this._baseSecrets.clear();
|
|
2571
|
+
this._secrets.clear();
|
|
2118
2572
|
this._spaceService = void 0;
|
|
2119
2573
|
this._serviceContext = void 0;
|
|
2120
2574
|
this.runtimePermissionGrants = [];
|
|
@@ -2125,6 +2579,14 @@ var _TinyCloudNode = class _TinyCloudNode {
|
|
|
2125
2579
|
if (sessionData.chainId) {
|
|
2126
2580
|
this._chainId = sessionData.chainId;
|
|
2127
2581
|
}
|
|
2582
|
+
const resolvedHost = await this.resolveRestoredHost(
|
|
2583
|
+
sessionData.tinycloudHosts,
|
|
2584
|
+
restoredAddress,
|
|
2585
|
+
sessionData.chainId
|
|
2586
|
+
);
|
|
2587
|
+
if (resolvedHost) {
|
|
2588
|
+
this.config.host = resolvedHost;
|
|
2589
|
+
}
|
|
2128
2590
|
this._serviceContext = new ServiceContext2({
|
|
2129
2591
|
invoke: this.invokeWithRuntimePermissions,
|
|
2130
2592
|
invokeAny: this.invokeAnyWithRuntimePermissions,
|
|
@@ -2170,12 +2632,45 @@ var _TinyCloudNode = class _TinyCloudNode {
|
|
|
2170
2632
|
signature: sessionData.signature ?? ""
|
|
2171
2633
|
};
|
|
2172
2634
|
if (this.auth) {
|
|
2173
|
-
this.auth.setRestoredTinyCloudSession(
|
|
2635
|
+
this.auth.setRestoredTinyCloudSession(
|
|
2636
|
+
tcSession,
|
|
2637
|
+
this.config.host ? [this.config.host] : void 0
|
|
2638
|
+
);
|
|
2174
2639
|
} else {
|
|
2175
2640
|
this._restoredTcSession = tcSession;
|
|
2176
2641
|
}
|
|
2177
2642
|
}
|
|
2178
2643
|
}
|
|
2644
|
+
/**
|
|
2645
|
+
* Resolve the host a restored session should target.
|
|
2646
|
+
*
|
|
2647
|
+
* Mirrors fresh sign-in host resolution but for the restore path:
|
|
2648
|
+
* an explicit/pinned host always wins, then the hosts the session was
|
|
2649
|
+
* persisted with, then a lazy registry/fallback resolution for sessions
|
|
2650
|
+
* that predate the persisted `tinycloudHosts` field. Returns `undefined`
|
|
2651
|
+
* only when there's nothing to resolve from (no explicit host, no
|
|
2652
|
+
* persisted hosts, and no address/chainId) — in which case the existing
|
|
2653
|
+
* `config.host` (default) is left in place.
|
|
2654
|
+
*
|
|
2655
|
+
* Resolution failures are surfaced, not swallowed: a genuinely broken
|
|
2656
|
+
* registry lookup throws rather than silently falling back to a wrong host.
|
|
2657
|
+
*/
|
|
2658
|
+
async resolveRestoredHost(persistedHosts, address, chainId) {
|
|
2659
|
+
if (this.explicitHost) {
|
|
2660
|
+
return this.explicitHost;
|
|
2661
|
+
}
|
|
2662
|
+
if (persistedHosts && persistedHosts.length > 0) {
|
|
2663
|
+
return persistedHosts[0];
|
|
2664
|
+
}
|
|
2665
|
+
if (address === void 0 || chainId === void 0) {
|
|
2666
|
+
return void 0;
|
|
2667
|
+
}
|
|
2668
|
+
const resolved = await resolveTinyCloudHosts2(pkhDid2(address, chainId), {
|
|
2669
|
+
registryUrl: this.config.tinycloudRegistryUrl,
|
|
2670
|
+
fallbackHosts: this.config.tinycloudFallbackHosts
|
|
2671
|
+
});
|
|
2672
|
+
return resolved.hosts[0];
|
|
2673
|
+
}
|
|
2179
2674
|
/**
|
|
2180
2675
|
* Resolve the currently-active TinyCloudSession, preferring the auth
|
|
2181
2676
|
* layer's value (wallet mode) and falling back to the node-level
|
|
@@ -2220,9 +2715,11 @@ var _TinyCloudNode = class _TinyCloudNode {
|
|
|
2220
2715
|
);
|
|
2221
2716
|
}
|
|
2222
2717
|
this.signer = _TinyCloudNode.nodeDefaults.createSigner(privateKey);
|
|
2718
|
+
const authConfig = { ...this.config, prefix };
|
|
2719
|
+
const useBootstrapSignInRequest = this.shouldUseBootstrapSignInRequest(authConfig);
|
|
2223
2720
|
this.auth = new NodeUserAuthorization({
|
|
2224
2721
|
signer: this.signer,
|
|
2225
|
-
signStrategy: { type: "auto-sign" },
|
|
2722
|
+
signStrategy: this.config.signStrategy ?? { type: "auto-sign" },
|
|
2226
2723
|
wasmBindings: this.wasmBindings,
|
|
2227
2724
|
sessionStorage: options?.sessionStorage ?? this.config.sessionStorage ?? new MemorySessionStorage(),
|
|
2228
2725
|
domain: this.siweDomain,
|
|
@@ -2231,14 +2728,14 @@ var _TinyCloudNode = class _TinyCloudNode {
|
|
|
2231
2728
|
tinycloudHosts: this.explicitHost ? [this.explicitHost] : void 0,
|
|
2232
2729
|
tinycloudRegistryUrl: this.config.tinycloudRegistryUrl,
|
|
2233
2730
|
tinycloudFallbackHosts: this.config.tinycloudFallbackHosts,
|
|
2234
|
-
autoCreateSpace: this.config.autoCreateSpace,
|
|
2731
|
+
autoCreateSpace: useBootstrapSignInRequest ? false : this.config.autoCreateSpace,
|
|
2235
2732
|
enablePublicSpace: this.config.enablePublicSpace ?? true,
|
|
2236
|
-
spaceCreationHandler: this.config.spaceCreationHandler,
|
|
2733
|
+
spaceCreationHandler: useBootstrapSignInRequest ? void 0 : this.config.spaceCreationHandler,
|
|
2237
2734
|
nonce: this.config.nonce,
|
|
2238
2735
|
siweConfig: this.config.siweConfig,
|
|
2239
|
-
manifest: this.config.manifest,
|
|
2240
|
-
capabilityRequest: this.config.capabilityRequest,
|
|
2241
|
-
includeAccountRegistryPermissions: this.config.includeAccountRegistryPermissions
|
|
2736
|
+
manifest: useBootstrapSignInRequest ? void 0 : this.config.manifest,
|
|
2737
|
+
capabilityRequest: useBootstrapSignInRequest ? BOOTSTRAP_SESSION_REQUESTS.default : this.config.capabilityRequest,
|
|
2738
|
+
includeAccountRegistryPermissions: useBootstrapSignInRequest ? false : this.config.includeAccountRegistryPermissions
|
|
2242
2739
|
});
|
|
2243
2740
|
this.tc = new TinyCloud(this.auth, {
|
|
2244
2741
|
invokeAny: this.invokeAnyWithRuntimePermissions,
|
|
@@ -2265,9 +2762,11 @@ var _TinyCloudNode = class _TinyCloudNode {
|
|
|
2265
2762
|
}
|
|
2266
2763
|
const prefix = options?.prefix ?? "default";
|
|
2267
2764
|
this.signer = signer;
|
|
2765
|
+
const authConfig = { ...this.config, prefix };
|
|
2766
|
+
const useBootstrapSignInRequest = this.shouldUseBootstrapSignInRequest(authConfig);
|
|
2268
2767
|
this.auth = new NodeUserAuthorization({
|
|
2269
2768
|
signer: this.signer,
|
|
2270
|
-
signStrategy: { type: "auto-sign" },
|
|
2769
|
+
signStrategy: this.config.signStrategy ?? { type: "auto-sign" },
|
|
2271
2770
|
wasmBindings: this.wasmBindings,
|
|
2272
2771
|
sessionStorage: options?.sessionStorage ?? this.config.sessionStorage ?? new MemorySessionStorage(),
|
|
2273
2772
|
domain: this.siweDomain,
|
|
@@ -2276,14 +2775,14 @@ var _TinyCloudNode = class _TinyCloudNode {
|
|
|
2276
2775
|
tinycloudHosts: this.explicitHost ? [this.explicitHost] : void 0,
|
|
2277
2776
|
tinycloudRegistryUrl: this.config.tinycloudRegistryUrl,
|
|
2278
2777
|
tinycloudFallbackHosts: this.config.tinycloudFallbackHosts,
|
|
2279
|
-
autoCreateSpace: this.config.autoCreateSpace,
|
|
2778
|
+
autoCreateSpace: useBootstrapSignInRequest ? false : this.config.autoCreateSpace,
|
|
2280
2779
|
enablePublicSpace: this.config.enablePublicSpace ?? true,
|
|
2281
|
-
spaceCreationHandler: this.config.spaceCreationHandler,
|
|
2780
|
+
spaceCreationHandler: useBootstrapSignInRequest ? void 0 : this.config.spaceCreationHandler,
|
|
2282
2781
|
nonce: this.config.nonce,
|
|
2283
2782
|
siweConfig: this.config.siweConfig,
|
|
2284
|
-
manifest: this.config.manifest,
|
|
2285
|
-
capabilityRequest: this.config.capabilityRequest,
|
|
2286
|
-
includeAccountRegistryPermissions: this.config.includeAccountRegistryPermissions
|
|
2783
|
+
manifest: useBootstrapSignInRequest ? void 0 : this.config.manifest,
|
|
2784
|
+
capabilityRequest: useBootstrapSignInRequest ? BOOTSTRAP_SESSION_REQUESTS.default : this.config.capabilityRequest,
|
|
2785
|
+
includeAccountRegistryPermissions: useBootstrapSignInRequest ? false : this.config.includeAccountRegistryPermissions
|
|
2287
2786
|
});
|
|
2288
2787
|
this.tc = new TinyCloud(this.auth, {
|
|
2289
2788
|
invokeAny: this.invokeAnyWithRuntimePermissions,
|
|
@@ -2359,6 +2858,20 @@ var _TinyCloudNode = class _TinyCloudNode {
|
|
|
2359
2858
|
getDefaultEncryptionNetworkId(name = DEFAULT_ENCRYPTION_NETWORK_NAME) {
|
|
2360
2859
|
return `urn:tinycloud:encryption:${this.did}:${name}`;
|
|
2361
2860
|
}
|
|
2861
|
+
getEncryptionNetworkIdForSpace(spaceId, name = DEFAULT_ENCRYPTION_NETWORK_NAME) {
|
|
2862
|
+
const ownerDid = this.ownerDidFromSpaceId(spaceId) ?? this.did;
|
|
2863
|
+
return `urn:tinycloud:encryption:${ownerDid}:${name}`;
|
|
2864
|
+
}
|
|
2865
|
+
ownerDidFromSpaceId(spaceId) {
|
|
2866
|
+
if (!spaceId.startsWith("tinycloud:")) return void 0;
|
|
2867
|
+
const body = spaceId.slice("tinycloud:".length);
|
|
2868
|
+
const lastSeparator = body.lastIndexOf(":");
|
|
2869
|
+
if (lastSeparator <= 0) return void 0;
|
|
2870
|
+
const owner = body.slice(0, lastSeparator);
|
|
2871
|
+
if (owner.startsWith("did:")) return owner;
|
|
2872
|
+
if (!owner.includes(":")) return void 0;
|
|
2873
|
+
return `did:${owner}`;
|
|
2874
|
+
}
|
|
2362
2875
|
requireServiceSession() {
|
|
2363
2876
|
const session = this._serviceContext?.session;
|
|
2364
2877
|
if (!session) {
|
|
@@ -2546,7 +3059,7 @@ var _TinyCloudNode = class _TinyCloudNode {
|
|
|
2546
3059
|
spaceId,
|
|
2547
3060
|
crypto: vaultCrypto,
|
|
2548
3061
|
encryption: {
|
|
2549
|
-
networkId: this.
|
|
3062
|
+
networkId: this.getEncryptionNetworkIdForSpace(spaceId),
|
|
2550
3063
|
service: this.getEncryptionService(),
|
|
2551
3064
|
decryptCapabilityProof: () => ({
|
|
2552
3065
|
proofs: [this.requireServiceSession().delegationCid]
|
|
@@ -2677,6 +3190,9 @@ var _TinyCloudNode = class _TinyCloudNode {
|
|
|
2677
3190
|
}
|
|
2678
3191
|
return vaultService;
|
|
2679
3192
|
},
|
|
3193
|
+
createSecretsService: (spaceId) => {
|
|
3194
|
+
return this.secretsForSpace(spaceId);
|
|
3195
|
+
},
|
|
2680
3196
|
// Enable space.delegations.create() via SIWE-based delegation
|
|
2681
3197
|
createDelegation: async (params) => {
|
|
2682
3198
|
try {
|
|
@@ -2799,11 +3315,10 @@ var _TinyCloudNode = class _TinyCloudNode {
|
|
|
2799
3315
|
try {
|
|
2800
3316
|
const host = this.config.host;
|
|
2801
3317
|
const now = /* @__PURE__ */ new Date();
|
|
2802
|
-
const abilities =
|
|
2803
|
-
|
|
2804
|
-
|
|
2805
|
-
|
|
2806
|
-
};
|
|
3318
|
+
const abilities = sharingActionsToAbilities(params.path, params.actions);
|
|
3319
|
+
if (!abilities) {
|
|
3320
|
+
return void 0;
|
|
3321
|
+
}
|
|
2807
3322
|
const prepared = this.wasmBindings.prepareSession({
|
|
2808
3323
|
abilities,
|
|
2809
3324
|
address: this.wasmBindings.ensureEip55(session.address),
|
|
@@ -3059,27 +3574,49 @@ var _TinyCloudNode = class _TinyCloudNode {
|
|
|
3059
3574
|
if (!this._spaceService) {
|
|
3060
3575
|
throw new Error("Not signed in. Call signIn() first.");
|
|
3061
3576
|
}
|
|
3062
|
-
|
|
3063
|
-
|
|
3064
|
-
|
|
3577
|
+
return this.secretsForSpace("secrets");
|
|
3578
|
+
}
|
|
3579
|
+
/**
|
|
3580
|
+
* App-facing secrets API backed by the requested space's vault.
|
|
3581
|
+
*/
|
|
3582
|
+
secretsForSpace(spaceId) {
|
|
3583
|
+
if (!this._spaceService) {
|
|
3584
|
+
throw new Error("Not signed in. Call signIn() first.");
|
|
3585
|
+
}
|
|
3586
|
+
const resolvedSpace = spaceId.startsWith("tinycloud:") ? spaceId : this.ownedSpaceId(spaceId);
|
|
3587
|
+
let secrets = this._secrets.get(resolvedSpace);
|
|
3588
|
+
if (!secrets) {
|
|
3589
|
+
secrets = new NodeSecretsService({
|
|
3590
|
+
getService: () => this.getBaseSecrets(resolvedSpace),
|
|
3591
|
+
space: resolvedSpace,
|
|
3065
3592
|
getManifest: () => this.manifest,
|
|
3066
3593
|
hasPermissions: (permissions) => this.hasRuntimePermissions(permissions),
|
|
3067
3594
|
grantPermissions: (additional) => this.grantRuntimePermissions(additional),
|
|
3068
3595
|
canEscalate: () => this.signer !== void 0 && this.tc !== void 0,
|
|
3069
|
-
getEncryptionNetworkId: () => this.
|
|
3596
|
+
getEncryptionNetworkId: () => this.getEncryptionNetworkIdForSpace(resolvedSpace),
|
|
3597
|
+
resolveSpace: (space) => space.startsWith("tinycloud:") ? space : this.ownedSpaceId(space),
|
|
3070
3598
|
getUnlockSigner: () => this.signer ?? void 0
|
|
3071
3599
|
});
|
|
3600
|
+
this._secrets.set(resolvedSpace, secrets);
|
|
3072
3601
|
}
|
|
3073
|
-
return
|
|
3602
|
+
return secrets;
|
|
3074
3603
|
}
|
|
3075
|
-
getBaseSecrets() {
|
|
3604
|
+
getBaseSecrets(spaceId) {
|
|
3076
3605
|
if (!this._spaceService) {
|
|
3077
3606
|
throw new Error("Not signed in. Call signIn() first.");
|
|
3078
3607
|
}
|
|
3079
|
-
|
|
3080
|
-
|
|
3608
|
+
const resolvedSpace = spaceId.startsWith("tinycloud:") ? spaceId : this.ownedSpaceId(spaceId);
|
|
3609
|
+
let secrets = this._baseSecrets.get(resolvedSpace);
|
|
3610
|
+
if (!secrets) {
|
|
3611
|
+
const kvService = this.createSpaceScopedKVService(resolvedSpace);
|
|
3612
|
+
const vaultService = this.createVaultService(resolvedSpace, kvService);
|
|
3613
|
+
if (this._serviceContext) {
|
|
3614
|
+
vaultService.initialize(this._serviceContext);
|
|
3615
|
+
}
|
|
3616
|
+
secrets = new SecretsService(() => vaultService);
|
|
3617
|
+
this._baseSecrets.set(resolvedSpace, secrets);
|
|
3081
3618
|
}
|
|
3082
|
-
return
|
|
3619
|
+
return secrets;
|
|
3083
3620
|
}
|
|
3084
3621
|
/**
|
|
3085
3622
|
* Hooks write stream subscription API.
|
|
@@ -4493,6 +5030,7 @@ var _TinyCloudNode = class _TinyCloudNode {
|
|
|
4493
5030
|
delegation,
|
|
4494
5031
|
targetHost,
|
|
4495
5032
|
this.wasmBindings.invoke,
|
|
5033
|
+
this.wasmBindings.invokeAny,
|
|
4496
5034
|
this.config.telemetry
|
|
4497
5035
|
);
|
|
4498
5036
|
}
|
|
@@ -4558,6 +5096,7 @@ var _TinyCloudNode = class _TinyCloudNode {
|
|
|
4558
5096
|
delegation,
|
|
4559
5097
|
targetHost,
|
|
4560
5098
|
this.wasmBindings.invoke,
|
|
5099
|
+
this.wasmBindings.invokeAny,
|
|
4561
5100
|
this.config.telemetry
|
|
4562
5101
|
);
|
|
4563
5102
|
}
|
|
@@ -4790,6 +5329,7 @@ export {
|
|
|
4790
5329
|
SpaceErrorCodes,
|
|
4791
5330
|
SpaceService2 as SpaceService,
|
|
4792
5331
|
TinyCloud2 as TinyCloud,
|
|
5332
|
+
TinyCloudDebugLogger,
|
|
4793
5333
|
TinyCloudNode,
|
|
4794
5334
|
UnsupportedFeatureError2 as UnsupportedFeatureError,
|
|
4795
5335
|
VAULT_PERMISSION_SERVICE,
|
|
@@ -4805,8 +5345,10 @@ export {
|
|
|
4805
5345
|
canonicalizeNetworkId,
|
|
4806
5346
|
canonicalizeSecretScope,
|
|
4807
5347
|
checkNodeInfo2 as checkNodeInfo,
|
|
5348
|
+
clearTinyCloudDebugLogs,
|
|
4808
5349
|
composeManifestRequest2 as composeManifestRequest,
|
|
4809
5350
|
createCapabilityKeyRegistry,
|
|
5351
|
+
createOpenKeyCallbackSigningStrategy,
|
|
4810
5352
|
createSharingService,
|
|
4811
5353
|
createSpaceService,
|
|
4812
5354
|
createVaultCrypto2 as createVaultCrypto,
|
|
@@ -4816,9 +5358,13 @@ export {
|
|
|
4816
5358
|
deserializeDelegation,
|
|
4817
5359
|
didCacheKey,
|
|
4818
5360
|
didEquals,
|
|
5361
|
+
disableTinyCloudDebug,
|
|
5362
|
+
enableTinyCloudDebug,
|
|
4819
5363
|
expandActionShortNames,
|
|
4820
5364
|
expandPermissionEntries2 as expandPermissionEntries,
|
|
4821
5365
|
expandPermissionEntry,
|
|
5366
|
+
getTinyCloudDebugLogs,
|
|
5367
|
+
installTinyCloudDebugGlobals,
|
|
4822
5368
|
isCapabilitySubset2 as isCapabilitySubset,
|
|
4823
5369
|
isEvmAddress,
|
|
4824
5370
|
loadManifest,
|
|
@@ -4836,6 +5382,7 @@ export {
|
|
|
4836
5382
|
resolveSecretPath2 as resolveSecretPath,
|
|
4837
5383
|
resourceCapabilitiesToSpaceAbilitiesMap2 as resourceCapabilitiesToSpaceAbilitiesMap,
|
|
4838
5384
|
serializeDelegation,
|
|
5385
|
+
tinyCloudDebugLogger,
|
|
4839
5386
|
validateManifest
|
|
4840
5387
|
};
|
|
4841
5388
|
//# sourceMappingURL=core.js.map
|