@tinycloud/node-sdk 2.2.0-beta.1 → 2.2.0-beta.11

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.cjs CHANGED
@@ -20,70 +20,77 @@ var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: tru
20
20
  // src/core.ts
21
21
  var core_exports = {};
22
22
  __export(core_exports, {
23
- ACCOUNT_REGISTRY_PATH: () => import_sdk_core8.ACCOUNT_REGISTRY_PATH,
24
- ACCOUNT_REGISTRY_SPACE: () => import_sdk_core8.ACCOUNT_REGISTRY_SPACE,
25
- AutoApproveSpaceCreationHandler: () => import_sdk_core7.AutoApproveSpaceCreationHandler,
26
- CapabilityKeyRegistry: () => import_sdk_core14.CapabilityKeyRegistry,
27
- CapabilityKeyRegistryErrorCodes: () => import_sdk_core14.CapabilityKeyRegistryErrorCodes,
28
- DEFAULT_MANIFEST_SPACE: () => import_sdk_core8.DEFAULT_MANIFEST_SPACE,
29
- DEFAULT_MANIFEST_VERSION: () => import_sdk_core8.DEFAULT_MANIFEST_VERSION,
30
- DataVaultService: () => import_sdk_core12.DataVaultService,
31
- DatabaseHandle: () => import_sdk_core10.DatabaseHandle,
23
+ ACCOUNT_REGISTRY_PATH: () => import_sdk_core9.ACCOUNT_REGISTRY_PATH,
24
+ ACCOUNT_REGISTRY_SPACE: () => import_sdk_core9.ACCOUNT_REGISTRY_SPACE,
25
+ AutoApproveSpaceCreationHandler: () => import_sdk_core8.AutoApproveSpaceCreationHandler,
26
+ CapabilityKeyRegistry: () => import_sdk_core15.CapabilityKeyRegistry,
27
+ CapabilityKeyRegistryErrorCodes: () => import_sdk_core15.CapabilityKeyRegistryErrorCodes,
28
+ DEFAULT_MANIFEST_SPACE: () => import_sdk_core9.DEFAULT_MANIFEST_SPACE,
29
+ DEFAULT_MANIFEST_VERSION: () => import_sdk_core9.DEFAULT_MANIFEST_VERSION,
30
+ DataVaultService: () => import_sdk_core13.DataVaultService,
31
+ DatabaseHandle: () => import_sdk_core11.DatabaseHandle,
32
32
  DelegatedAccess: () => DelegatedAccess,
33
- DelegationErrorCodes: () => import_sdk_core13.DelegationErrorCodes,
34
- DelegationManager: () => import_sdk_core13.DelegationManager,
35
- DuckDbAction: () => import_sdk_core11.DuckDbAction,
36
- DuckDbDatabaseHandle: () => import_sdk_core11.DuckDbDatabaseHandle,
37
- DuckDbService: () => import_sdk_core11.DuckDbService,
33
+ DelegationErrorCodes: () => import_sdk_core14.DelegationErrorCodes,
34
+ DelegationManager: () => import_sdk_core14.DelegationManager,
35
+ DuckDbAction: () => import_sdk_core12.DuckDbAction,
36
+ DuckDbDatabaseHandle: () => import_sdk_core12.DuckDbDatabaseHandle,
37
+ DuckDbService: () => import_sdk_core12.DuckDbService,
38
38
  FileSessionStorage: () => FileSessionStorage,
39
- KVService: () => import_sdk_core9.KVService,
40
- ManifestValidationError: () => import_sdk_core8.ManifestValidationError,
39
+ KVService: () => import_sdk_core10.KVService,
40
+ ManifestValidationError: () => import_sdk_core9.ManifestValidationError,
41
41
  MemorySessionStorage: () => MemorySessionStorage,
42
42
  NodeUserAuthorization: () => NodeUserAuthorization,
43
- PermissionNotInManifestError: () => import_sdk_core8.PermissionNotInManifestError,
44
- PrefixedKVService: () => import_sdk_core9.PrefixedKVService,
45
- ProtocolMismatchError: () => import_sdk_core16.ProtocolMismatchError,
46
- SQLAction: () => import_sdk_core10.SQLAction,
47
- SQLService: () => import_sdk_core10.SQLService,
48
- ServiceContext: () => import_sdk_core17.ServiceContext,
49
- SessionExpiredError: () => import_sdk_core8.SessionExpiredError,
50
- SharingService: () => import_sdk_core13.SharingService,
51
- SilentNotificationHandler: () => import_sdk_core7.SilentNotificationHandler,
52
- Space: () => import_sdk_core15.Space,
53
- SpaceErrorCodes: () => import_sdk_core15.SpaceErrorCodes,
54
- SpaceService: () => import_sdk_core15.SpaceService,
55
- TinyCloud: () => import_sdk_core6.TinyCloud,
43
+ PermissionNotInManifestError: () => import_sdk_core9.PermissionNotInManifestError,
44
+ PrefixedKVService: () => import_sdk_core10.PrefixedKVService,
45
+ ProtocolMismatchError: () => import_sdk_core17.ProtocolMismatchError,
46
+ SECRET_NAME_RE: () => import_sdk_core13.SECRET_NAME_RE,
47
+ SQLAction: () => import_sdk_core11.SQLAction,
48
+ SQLService: () => import_sdk_core11.SQLService,
49
+ SecretsService: () => import_sdk_core13.SecretsService,
50
+ ServiceContext: () => import_sdk_core18.ServiceContext,
51
+ SessionExpiredError: () => import_sdk_core9.SessionExpiredError,
52
+ SharingService: () => import_sdk_core14.SharingService,
53
+ SilentNotificationHandler: () => import_sdk_core8.SilentNotificationHandler,
54
+ Space: () => import_sdk_core16.Space,
55
+ SpaceErrorCodes: () => import_sdk_core16.SpaceErrorCodes,
56
+ SpaceService: () => import_sdk_core16.SpaceService,
57
+ TinyCloud: () => import_sdk_core7.TinyCloud,
56
58
  TinyCloudNode: () => TinyCloudNode,
57
- UnsupportedFeatureError: () => import_sdk_core16.UnsupportedFeatureError,
58
- VaultHeaders: () => import_sdk_core12.VaultHeaders,
59
- VaultPublicSpaceKVActions: () => import_sdk_core12.VaultPublicSpaceKVActions,
60
- VersionCheckError: () => import_sdk_core16.VersionCheckError,
59
+ UnsupportedFeatureError: () => import_sdk_core17.UnsupportedFeatureError,
60
+ VAULT_PERMISSION_SERVICE: () => import_sdk_core9.VAULT_PERMISSION_SERVICE,
61
+ VaultHeaders: () => import_sdk_core13.VaultHeaders,
62
+ VaultPublicSpaceKVActions: () => import_sdk_core13.VaultPublicSpaceKVActions,
63
+ VersionCheckError: () => import_sdk_core17.VersionCheckError,
61
64
  WasmKeyProvider: () => WasmKeyProvider,
62
- buildSpaceUri: () => import_sdk_core15.buildSpaceUri,
63
- checkNodeInfo: () => import_sdk_core16.checkNodeInfo,
64
- composeManifestRequest: () => import_sdk_core8.composeManifestRequest,
65
- createCapabilityKeyRegistry: () => import_sdk_core14.createCapabilityKeyRegistry,
66
- createSharingService: () => import_sdk_core13.createSharingService,
67
- createSpaceService: () => import_sdk_core15.createSpaceService,
68
- createVaultCrypto: () => import_sdk_core12.createVaultCrypto,
65
+ buildSpaceUri: () => import_sdk_core16.buildSpaceUri,
66
+ canonicalizeSecretScope: () => import_sdk_core13.canonicalizeSecretScope,
67
+ checkNodeInfo: () => import_sdk_core17.checkNodeInfo,
68
+ composeManifestRequest: () => import_sdk_core9.composeManifestRequest,
69
+ createCapabilityKeyRegistry: () => import_sdk_core15.createCapabilityKeyRegistry,
70
+ createSharingService: () => import_sdk_core14.createSharingService,
71
+ createSpaceService: () => import_sdk_core16.createSpaceService,
72
+ createVaultCrypto: () => import_sdk_core13.createVaultCrypto,
69
73
  createWasmKeyProvider: () => createWasmKeyProvider,
70
74
  defaultSignStrategy: () => defaultSignStrategy,
71
- defaultSpaceCreationHandler: () => import_sdk_core7.defaultSpaceCreationHandler,
75
+ defaultSpaceCreationHandler: () => import_sdk_core8.defaultSpaceCreationHandler,
72
76
  deserializeDelegation: () => deserializeDelegation,
73
- expandActionShortNames: () => import_sdk_core8.expandActionShortNames,
74
- isCapabilitySubset: () => import_sdk_core8.isCapabilitySubset,
75
- loadManifest: () => import_sdk_core8.loadManifest,
76
- makePublicSpaceId: () => import_sdk_core15.makePublicSpaceId,
77
- parseExpiry: () => import_sdk_core8.parseExpiry,
78
- parseSpaceUri: () => import_sdk_core15.parseSpaceUri,
79
- resolveManifest: () => import_sdk_core8.resolveManifest,
80
- resourceCapabilitiesToSpaceAbilitiesMap: () => import_sdk_core8.resourceCapabilitiesToSpaceAbilitiesMap,
77
+ expandActionShortNames: () => import_sdk_core9.expandActionShortNames,
78
+ expandPermissionEntries: () => import_sdk_core9.expandPermissionEntries,
79
+ expandPermissionEntry: () => import_sdk_core9.expandPermissionEntry,
80
+ isCapabilitySubset: () => import_sdk_core9.isCapabilitySubset,
81
+ loadManifest: () => import_sdk_core9.loadManifest,
82
+ makePublicSpaceId: () => import_sdk_core16.makePublicSpaceId,
83
+ parseExpiry: () => import_sdk_core9.parseExpiry,
84
+ parseSpaceUri: () => import_sdk_core16.parseSpaceUri,
85
+ resolveManifest: () => import_sdk_core9.resolveManifest,
86
+ resolveSecretPath: () => import_sdk_core13.resolveSecretPath,
87
+ resourceCapabilitiesToSpaceAbilitiesMap: () => import_sdk_core9.resourceCapabilitiesToSpaceAbilitiesMap,
81
88
  serializeDelegation: () => serializeDelegation,
82
- validateManifest: () => import_sdk_core8.validateManifest
89
+ validateManifest: () => import_sdk_core9.validateManifest
83
90
  });
84
91
  module.exports = __toCommonJS(core_exports);
85
- var import_sdk_core6 = require("@tinycloud/sdk-core");
86
92
  var import_sdk_core7 = require("@tinycloud/sdk-core");
93
+ var import_sdk_core8 = require("@tinycloud/sdk-core");
87
94
 
88
95
  // src/storage/MemorySessionStorage.ts
89
96
  var MemorySessionStorage = class {
@@ -336,12 +343,12 @@ var NodeUserAuthorization = class {
336
343
  ]
337
344
  }
338
345
  };
339
- this.sessionExpirationMs = config.sessionExpirationMs ?? 60 * 60 * 1e3;
346
+ this.sessionExpirationMs = config.sessionExpirationMs ?? import_sdk_core2.EXPIRY.SESSION_MS;
340
347
  this.autoCreateSpace = config.autoCreateSpace ?? false;
341
348
  this.spaceCreationHandler = config.spaceCreationHandler;
342
- this.tinycloudHosts = config.tinycloudHosts ?? [
343
- "https://node.tinycloud.xyz"
344
- ];
349
+ this.tinycloudHosts = config.tinycloudHosts;
350
+ this.tinycloudRegistryUrl = config.tinycloudRegistryUrl;
351
+ this.tinycloudFallbackHosts = config.tinycloudFallbackHosts;
345
352
  this.enablePublicSpace = config.enablePublicSpace ?? true;
346
353
  this.nonce = config.nonce;
347
354
  this.siweConfig = config.siweConfig;
@@ -362,6 +369,9 @@ var NodeUserAuthorization = class {
362
369
  get capabilityRequest() {
363
370
  return this.getCapabilityRequest();
364
371
  }
372
+ get hosts() {
373
+ return this.tinycloudHosts ? [...this.tinycloudHosts] : [];
374
+ }
365
375
  /**
366
376
  * Install or replace the stored manifest. Takes effect on the next
367
377
  * `signIn()` call — the current session (if any) is not touched.
@@ -386,6 +396,26 @@ var NodeUserAuthorization = class {
386
396
  get tinyCloudSession() {
387
397
  return this._tinyCloudSession;
388
398
  }
399
+ async resolveTinyCloudHostsForSignIn(address, chainId) {
400
+ if (this.tinycloudHosts && this.tinycloudHosts.length > 0) {
401
+ return;
402
+ }
403
+ const subject = `did:pkh:eip155:${chainId}:${address}`;
404
+ const resolved = await (0, import_sdk_core2.resolveTinyCloudHosts)(subject, {
405
+ registryUrl: this.tinycloudRegistryUrl,
406
+ fallbackHosts: this.tinycloudFallbackHosts
407
+ });
408
+ this.tinycloudHosts = resolved.hosts;
409
+ }
410
+ requireTinyCloudHosts() {
411
+ if (!this.tinycloudHosts || this.tinycloudHosts.length === 0) {
412
+ throw new Error("TinyCloud hosts have not been resolved. Call signIn() first.");
413
+ }
414
+ return this.tinycloudHosts;
415
+ }
416
+ get primaryTinyCloudHost() {
417
+ return this.requireTinyCloudHosts()[0];
418
+ }
389
419
  get nodeFeatures() {
390
420
  return this._nodeFeatures;
391
421
  }
@@ -517,7 +547,7 @@ var NodeUserAuthorization = class {
517
547
  if (!this._tinyCloudSession || !this._address || !this._chainId) {
518
548
  throw new Error("Must be signed in to host space");
519
549
  }
520
- const host = this.tinycloudHosts[0];
550
+ const host = this.primaryTinyCloudHost;
521
551
  const spaceId = targetSpaceId ?? this._tinyCloudSession.spaceId;
522
552
  const peerId = await (0, import_sdk_core2.fetchPeerId)(host, spaceId);
523
553
  const siwe = this.wasm.generateHostSIWEMessage({
@@ -559,7 +589,7 @@ var NodeUserAuthorization = class {
559
589
  if (!this._tinyCloudSession) {
560
590
  throw new Error("Must be signed in to ensure space exists");
561
591
  }
562
- const host = this.tinycloudHosts[0];
592
+ const host = this.primaryTinyCloudHost;
563
593
  const primarySpaceId = this._tinyCloudSession.spaceId;
564
594
  const result = await (0, import_sdk_core2.activateSessionWithHost)(
565
595
  host,
@@ -668,6 +698,7 @@ var NodeUserAuthorization = class {
668
698
  this._chainId = await this.signer.getChainId();
669
699
  const address = this.wasm.ensureEip55(this._address);
670
700
  const chainId = this._chainId;
701
+ await this.resolveTinyCloudHostsForSignIn(address, chainId);
671
702
  const keyId = `session-${Date.now()}`;
672
703
  this.sessionManager.renameSessionKeyId("default", keyId);
673
704
  const jwkString = this.sessionManager.jwk(keyId);
@@ -746,7 +777,7 @@ var NodeUserAuthorization = class {
746
777
  this._address = address;
747
778
  this._chainId = chainId;
748
779
  const nodeInfo = await (0, import_sdk_core2.checkNodeInfo)(
749
- this.tinycloudHosts[0],
780
+ this.primaryTinyCloudHost,
750
781
  this.wasm.protocolVersion()
751
782
  );
752
783
  this._nodeFeatures = nodeInfo.features;
@@ -862,6 +893,7 @@ var NodeUserAuthorization = class {
862
893
  });
863
894
  const address = this.wasm.ensureEip55(await this.signer.getAddress());
864
895
  const chainId = await this.signer.getChainId();
896
+ await this.resolveTinyCloudHostsForSignIn(address, chainId);
865
897
  const clientSession = {
866
898
  address,
867
899
  walletAddress: address,
@@ -911,7 +943,7 @@ var NodeUserAuthorization = class {
911
943
  this._address = address;
912
944
  this._chainId = chainId;
913
945
  const nodeInfo = await (0, import_sdk_core2.checkNodeInfo)(
914
- this.tinycloudHosts[0],
946
+ this.primaryTinyCloudHost,
915
947
  this.wasm.protocolVersion()
916
948
  );
917
949
  this._nodeFeatures = nodeInfo.features;
@@ -994,7 +1026,7 @@ var NodeUserAuthorization = class {
994
1026
  };
995
1027
 
996
1028
  // src/TinyCloudNode.ts
997
- var import_sdk_core5 = require("@tinycloud/sdk-core");
1029
+ var import_sdk_core6 = require("@tinycloud/sdk-core");
998
1030
 
999
1031
  // src/DelegatedAccess.ts
1000
1032
  var import_sdk_core3 = require("@tinycloud/sdk-core");
@@ -1072,6 +1104,24 @@ var DelegatedAccess = class {
1072
1104
  get hooks() {
1073
1105
  return this._hooks;
1074
1106
  }
1107
+ /**
1108
+ * Export the handles needed to rehydrate this activated delegation via
1109
+ * `TinyCloudNode.restoreSession(...)` in another process or after a
1110
+ * restart.
1111
+ *
1112
+ * See `RestorableSession` for lifetime caveats.
1113
+ */
1114
+ get restorable() {
1115
+ return {
1116
+ delegationHeader: this.session.delegationHeader,
1117
+ delegationCid: this.session.delegationCid,
1118
+ spaceId: this.session.spaceId,
1119
+ jwk: this.session.jwk,
1120
+ verificationMethod: this.session.verificationMethod,
1121
+ address: this.session.address,
1122
+ chainId: this.session.chainId
1123
+ };
1124
+ }
1075
1125
  };
1076
1126
 
1077
1127
  // src/keys/WasmKeyProvider.ts
@@ -1181,9 +1231,10 @@ function legacyParamsToPermissionEntries(actions, path, spaceIdOverride) {
1181
1231
  }
1182
1232
  return entries;
1183
1233
  }
1234
+ var DEFAULT_DELEGATION_EXPIRY_MS = import_sdk_core4.EXPIRY.SESSION_MS;
1184
1235
  function resolveExpiryMs(expiry) {
1185
1236
  if (expiry === void 0) {
1186
- return 60 * 60 * 1e3;
1237
+ return DEFAULT_DELEGATION_EXPIRY_MS;
1187
1238
  }
1188
1239
  if (typeof expiry === "number") {
1189
1240
  if (!Number.isFinite(expiry) || expiry <= 0) {
@@ -1209,8 +1260,151 @@ function extractSiweExpiration(siwe) {
1209
1260
  return d;
1210
1261
  }
1211
1262
 
1263
+ // src/NodeSecretsService.ts
1264
+ var import_sdk_core5 = require("@tinycloud/sdk-core");
1265
+ var SECRETS_SPACE = "secrets";
1266
+ function ok() {
1267
+ return { ok: true, data: void 0 };
1268
+ }
1269
+ function secretsError(code, message, cause) {
1270
+ return {
1271
+ ok: false,
1272
+ error: {
1273
+ code,
1274
+ service: "secrets",
1275
+ message,
1276
+ ...cause ? { cause } : {}
1277
+ }
1278
+ };
1279
+ }
1280
+ function displayActionUrn(action) {
1281
+ return action === "put" ? "tinycloud.vault/write" : "tinycloud.vault/delete";
1282
+ }
1283
+ function kvActionUrn(action) {
1284
+ return `tinycloud.kv/${action}`;
1285
+ }
1286
+ function vaultMutationAction(action) {
1287
+ return action === "put" ? "write" : "delete";
1288
+ }
1289
+ function secretPermissionEntries(name, options, action) {
1290
+ const secretPath = (0, import_sdk_core5.resolveSecretPath)(name, options);
1291
+ return [
1292
+ {
1293
+ service: "tinycloud.vault",
1294
+ space: SECRETS_SPACE,
1295
+ path: secretPath.vaultKey,
1296
+ actions: [vaultMutationAction(action)],
1297
+ skipPrefix: true
1298
+ }
1299
+ ];
1300
+ }
1301
+ function isSecretsSpace(space) {
1302
+ return space === SECRETS_SPACE || space.endsWith(`:${SECRETS_SPACE}`);
1303
+ }
1304
+ var NodeSecretsService = class {
1305
+ constructor(config) {
1306
+ this.config = config;
1307
+ this.shouldRestoreUnlock = false;
1308
+ }
1309
+ get vault() {
1310
+ return this.service.vault;
1311
+ }
1312
+ get isUnlocked() {
1313
+ return this.service.isUnlocked;
1314
+ }
1315
+ async unlock(signer) {
1316
+ const effectiveSigner = signer ?? this.config.getUnlockSigner?.();
1317
+ if (effectiveSigner !== void 0) {
1318
+ this.unlockSigner = effectiveSigner;
1319
+ }
1320
+ const result = await this.service.unlock(effectiveSigner);
1321
+ if (result.ok) {
1322
+ this.shouldRestoreUnlock = true;
1323
+ }
1324
+ return result;
1325
+ }
1326
+ lock() {
1327
+ this.shouldRestoreUnlock = false;
1328
+ this.service.lock();
1329
+ }
1330
+ get(name, options) {
1331
+ return options === void 0 ? this.service.get(name) : this.service.get(name, options);
1332
+ }
1333
+ async put(name, value, options) {
1334
+ const permission = await this.ensureMutationPermission(name, options, "put");
1335
+ if (!permission.ok) return permission;
1336
+ return options === void 0 ? this.service.put(name, value) : this.service.put(name, value, options);
1337
+ }
1338
+ async delete(name, options) {
1339
+ const permission = await this.ensureMutationPermission(name, options, "del");
1340
+ if (!permission.ok) return permission;
1341
+ return options === void 0 ? this.service.delete(name) : this.service.delete(name, options);
1342
+ }
1343
+ list(options) {
1344
+ return options === void 0 ? this.service.list() : this.service.list(options);
1345
+ }
1346
+ get service() {
1347
+ return this.config.getService();
1348
+ }
1349
+ async ensureMutationPermission(name, options, action) {
1350
+ let permissionEntries;
1351
+ try {
1352
+ permissionEntries = secretPermissionEntries(name, options, action);
1353
+ } catch (error) {
1354
+ return secretsError(
1355
+ import_sdk_core5.ErrorCodes.INVALID_INPUT,
1356
+ error instanceof Error ? error.message : String(error),
1357
+ error instanceof Error ? error : void 0
1358
+ );
1359
+ }
1360
+ if (this.hasMutationPermission(name, options, action)) {
1361
+ return ok();
1362
+ }
1363
+ if (!this.config.canEscalate()) {
1364
+ return secretsError(
1365
+ import_sdk_core5.ErrorCodes.PERMISSION_DENIED,
1366
+ `Cannot autosign ${displayActionUrn(action)} for ${name}; TinyCloudNode needs wallet mode with a signer or privateKey.`
1367
+ );
1368
+ }
1369
+ try {
1370
+ await this.config.grantPermissions(permissionEntries);
1371
+ return this.restoreUnlockAfterEscalation();
1372
+ } catch (error) {
1373
+ return secretsError(
1374
+ import_sdk_core5.ErrorCodes.PERMISSION_DENIED,
1375
+ error instanceof Error ? error.message : `Autosign escalation for ${displayActionUrn(action)} on ${name} failed.`,
1376
+ error instanceof Error ? error : void 0
1377
+ );
1378
+ }
1379
+ }
1380
+ async restoreUnlockAfterEscalation() {
1381
+ if (!this.shouldRestoreUnlock) {
1382
+ return ok();
1383
+ }
1384
+ return this.service.unlock(this.unlockSigner);
1385
+ }
1386
+ hasMutationPermission(name, options, action) {
1387
+ const manifest = this.config.getManifest();
1388
+ if (manifest === void 0) {
1389
+ return false;
1390
+ }
1391
+ const manifests = Array.isArray(manifest) ? manifest : [manifest];
1392
+ const requiredAction = kvActionUrn(action);
1393
+ const secretPath = (0, import_sdk_core5.resolveSecretPath)(name, options);
1394
+ return manifests.some((entry) => {
1395
+ const resolved = (0, import_sdk_core5.resolveManifest)(entry);
1396
+ return ["keys", "vault"].every(
1397
+ (base) => resolved.resources.some(
1398
+ (resource) => resource.service === "tinycloud.kv" && isSecretsSpace(resource.space) && resource.path === secretPath.permissionPaths[base] && resource.actions.includes(requiredAction)
1399
+ )
1400
+ );
1401
+ });
1402
+ }
1403
+ };
1404
+
1212
1405
  // src/TinyCloudNode.ts
1213
1406
  var DEFAULT_HOST = "https://node.tinycloud.xyz";
1407
+ var DEFAULT_SESSION_EXPIRATION_MS = import_sdk_core6.EXPIRY.SESSION_MS;
1214
1408
  var _TinyCloudNode = class _TinyCloudNode {
1215
1409
  /**
1216
1410
  * Create a new TinyCloudNode instance.
@@ -1240,6 +1434,31 @@ var _TinyCloudNode = class _TinyCloudNode {
1240
1434
  this.auth = null;
1241
1435
  this.tc = null;
1242
1436
  this._chainId = 1;
1437
+ this.runtimePermissionGrants = [];
1438
+ this.invokeWithRuntimePermissions = (session, service, path, action, facts) => {
1439
+ return this.wasmBindings.invoke(
1440
+ this.selectInvocationSession(session, service, path, action),
1441
+ service,
1442
+ path,
1443
+ action,
1444
+ facts
1445
+ );
1446
+ };
1447
+ this.invokeAnyWithRuntimePermissions = (session, entries, facts) => {
1448
+ if (!this.wasmBindings.invokeAny) {
1449
+ throw new Error("WASM binding does not support invokeAny");
1450
+ }
1451
+ const grant = this.findGrantForOperations(
1452
+ entries.map((entry) => ({
1453
+ spaceId: entry.spaceId,
1454
+ service: this.invocationServiceName(entry.service),
1455
+ path: entry.path,
1456
+ action: entry.action
1457
+ }))
1458
+ );
1459
+ return this.wasmBindings.invokeAny(grant?.session ?? session, entries, facts);
1460
+ };
1461
+ this.explicitHost = config.host;
1243
1462
  this.config = {
1244
1463
  ...config,
1245
1464
  host: config.host ?? DEFAULT_HOST
@@ -1266,23 +1485,23 @@ var _TinyCloudNode = class _TinyCloudNode {
1266
1485
  throw new Error("Failed to get session key JWK");
1267
1486
  }
1268
1487
  this.sessionKeyJwk = JSON.parse(jwkStr);
1269
- this._capabilityRegistry = new import_sdk_core5.CapabilityKeyRegistry();
1488
+ this._capabilityRegistry = new import_sdk_core6.CapabilityKeyRegistry();
1270
1489
  this._keyProvider = new WasmKeyProvider({
1271
1490
  sessionManager: this.sessionManager
1272
1491
  });
1273
- this.notificationHandler = config.notificationHandler ?? new import_sdk_core5.SilentNotificationHandler();
1274
- this._sharingService = new import_sdk_core5.SharingService({
1492
+ this.notificationHandler = config.notificationHandler ?? new import_sdk_core6.SilentNotificationHandler();
1493
+ this._sharingService = new import_sdk_core6.SharingService({
1275
1494
  hosts: [this.config.host],
1276
1495
  // session: undefined - not needed for receive()
1277
- invoke: this.wasmBindings.invoke,
1496
+ invoke: this.invokeWithRuntimePermissions,
1278
1497
  fetch: globalThis.fetch.bind(globalThis),
1279
1498
  keyProvider: this._keyProvider,
1280
1499
  registry: this._capabilityRegistry,
1281
1500
  // delegationManager: undefined - not needed for receive()
1282
1501
  createKVService: (config2) => {
1283
1502
  const prefix = config2.pathPrefix?.replace(/\/$/, "");
1284
- const kvService = new import_sdk_core5.KVService({ prefix });
1285
- const kvContext = new import_sdk_core5.ServiceContext({
1503
+ const kvService = new import_sdk_core6.KVService({ prefix });
1504
+ const kvContext = new import_sdk_core6.ServiceContext({
1286
1505
  invoke: config2.invoke,
1287
1506
  fetch: config2.fetch ?? globalThis.fetch.bind(globalThis),
1288
1507
  hosts: config2.hosts
@@ -1321,7 +1540,6 @@ var _TinyCloudNode = class _TinyCloudNode {
1321
1540
  * @internal
1322
1541
  */
1323
1542
  setupAuth(config) {
1324
- const host = this.config.host;
1325
1543
  this.auth = new NodeUserAuthorization({
1326
1544
  signer: this.signer,
1327
1545
  signStrategy: { type: "auto-sign" },
@@ -1329,8 +1547,10 @@ var _TinyCloudNode = class _TinyCloudNode {
1329
1547
  sessionStorage: config.sessionStorage ?? new MemorySessionStorage(),
1330
1548
  domain: this.siweDomain,
1331
1549
  spacePrefix: config.prefix,
1332
- sessionExpirationMs: config.sessionExpirationMs ?? 60 * 60 * 1e3,
1333
- tinycloudHosts: [host],
1550
+ sessionExpirationMs: config.sessionExpirationMs ?? DEFAULT_SESSION_EXPIRATION_MS,
1551
+ tinycloudHosts: this.explicitHost ? [this.explicitHost] : void 0,
1552
+ tinycloudRegistryUrl: config.tinycloudRegistryUrl,
1553
+ tinycloudFallbackHosts: config.tinycloudFallbackHosts,
1334
1554
  autoCreateSpace: config.autoCreateSpace,
1335
1555
  enablePublicSpace: config.enablePublicSpace ?? true,
1336
1556
  spaceCreationHandler: config.spaceCreationHandler,
@@ -1340,10 +1560,16 @@ var _TinyCloudNode = class _TinyCloudNode {
1340
1560
  capabilityRequest: config.capabilityRequest,
1341
1561
  includeAccountRegistryPermissions: config.includeAccountRegistryPermissions
1342
1562
  });
1343
- this.tc = new import_sdk_core5.TinyCloud(this.auth, {
1344
- invokeAny: this.wasmBindings.invokeAny
1563
+ this.tc = new import_sdk_core6.TinyCloud(this.auth, {
1564
+ invokeAny: this.invokeAnyWithRuntimePermissions
1345
1565
  });
1346
1566
  }
1567
+ syncResolvedHostFromAuth() {
1568
+ const host = this.auth?.hosts[0];
1569
+ if (host) {
1570
+ this.config.host = host;
1571
+ }
1572
+ }
1347
1573
  /**
1348
1574
  * Install or replace the manifest that drives the SIWE recap at
1349
1575
  * sign-in. Takes effect on the next `signIn()` call — the current
@@ -1381,6 +1607,10 @@ var _TinyCloudNode = class _TinyCloudNode {
1381
1607
  get capabilityRequest() {
1382
1608
  return this.auth?.capabilityRequest;
1383
1609
  }
1610
+ get hosts() {
1611
+ const authHosts = this.auth?.hosts ?? [];
1612
+ return authHosts.length > 0 ? authHosts : [this.config.host];
1613
+ }
1384
1614
  /**
1385
1615
  * Get the primary identity DID for this user.
1386
1616
  * - If wallet connected and signed in: returns PKH DID (did:pkh:eip155:{chainId}:{address})
@@ -1451,8 +1681,14 @@ var _TinyCloudNode = class _TinyCloudNode {
1451
1681
  this._sql = void 0;
1452
1682
  this._duckdb = void 0;
1453
1683
  this._hooks = void 0;
1684
+ this._vault = void 0;
1685
+ this._baseSecrets = void 0;
1686
+ this._secrets = void 0;
1687
+ this._spaceService = void 0;
1454
1688
  this._serviceContext = void 0;
1689
+ this.runtimePermissionGrants = [];
1455
1690
  await this.tc.signIn(options);
1691
+ this.syncResolvedHostFromAuth();
1456
1692
  this.initializeServices();
1457
1693
  await this.writeManifestRegistryRecords();
1458
1694
  this.notificationHandler.success("Successfully signed in");
@@ -1471,8 +1707,8 @@ var _TinyCloudNode = class _TinyCloudNode {
1471
1707
  if (!this.auth || !this.signer) {
1472
1708
  throw new Error("Manifest registry write requires wallet mode");
1473
1709
  }
1474
- const accountSpaceId = this.ownedSpaceId(import_sdk_core5.ACCOUNT_REGISTRY_SPACE);
1475
- await this.auth.hostOwnedSpace(accountSpaceId);
1710
+ const accountSpaceId = this.ownedSpaceId(import_sdk_core6.ACCOUNT_REGISTRY_SPACE);
1711
+ await this.ensureOwnedSpaceHosted(accountSpaceId);
1476
1712
  const accountKV = this.spaces.get(accountSpaceId).kv;
1477
1713
  for (const record of request.registryRecords) {
1478
1714
  const result = await accountKV.put(record.key, {
@@ -1487,6 +1723,39 @@ var _TinyCloudNode = class _TinyCloudNode {
1487
1723
  }
1488
1724
  }
1489
1725
  }
1726
+ async ensureOwnedSpaceHosted(spaceId) {
1727
+ if (!this.auth) {
1728
+ throw new Error("Owned space hosting requires wallet mode");
1729
+ }
1730
+ const session = this.auth.tinyCloudSession;
1731
+ if (!session) {
1732
+ throw new Error("Owned space hosting requires an active session");
1733
+ }
1734
+ const host = this.hosts[0] ?? this.config.host;
1735
+ if (!host) {
1736
+ throw new Error("Owned space hosting requires a TinyCloud host");
1737
+ }
1738
+ const activation = await (0, import_sdk_core6.activateSessionWithHost)(host, session.delegationHeader);
1739
+ if (activation.success && !activation.skipped?.includes(spaceId)) {
1740
+ return;
1741
+ }
1742
+ if (!activation.success && activation.status !== 404) {
1743
+ throw new Error(
1744
+ `Failed to check owned space ${spaceId}: ${activation.error ?? activation.status}`
1745
+ );
1746
+ }
1747
+ const created = await this.auth.hostOwnedSpace(spaceId);
1748
+ if (!created) {
1749
+ throw new Error(`Failed to create owned space: ${spaceId}`);
1750
+ }
1751
+ await new Promise((resolve) => setTimeout(resolve, 100));
1752
+ const retry = await (0, import_sdk_core6.activateSessionWithHost)(host, session.delegationHeader);
1753
+ if (!retry.success || retry.skipped?.includes(spaceId)) {
1754
+ throw new Error(
1755
+ `Failed to activate session after creating owned space ${spaceId}: ${retry.error ?? "space was skipped"}`
1756
+ );
1757
+ }
1758
+ }
1490
1759
  /**
1491
1760
  * Restore a previously established session from stored delegation data.
1492
1761
  *
@@ -1502,29 +1771,34 @@ var _TinyCloudNode = class _TinyCloudNode {
1502
1771
  this._sql = void 0;
1503
1772
  this._duckdb = void 0;
1504
1773
  this._hooks = void 0;
1774
+ this._vault = void 0;
1775
+ this._baseSecrets = void 0;
1776
+ this._secrets = void 0;
1777
+ this._spaceService = void 0;
1505
1778
  this._serviceContext = void 0;
1779
+ this.runtimePermissionGrants = [];
1506
1780
  if (sessionData.address) {
1507
1781
  this._address = sessionData.address;
1508
1782
  }
1509
1783
  if (sessionData.chainId) {
1510
1784
  this._chainId = sessionData.chainId;
1511
1785
  }
1512
- this._serviceContext = new import_sdk_core5.ServiceContext({
1513
- invoke: this.wasmBindings.invoke,
1514
- invokeAny: this.wasmBindings.invokeAny,
1786
+ this._serviceContext = new import_sdk_core6.ServiceContext({
1787
+ invoke: this.invokeWithRuntimePermissions,
1788
+ invokeAny: this.invokeAnyWithRuntimePermissions,
1515
1789
  fetch: globalThis.fetch.bind(globalThis),
1516
1790
  hosts: [this.config.host]
1517
1791
  });
1518
- this._kv = new import_sdk_core5.KVService({});
1792
+ this._kv = new import_sdk_core6.KVService({});
1519
1793
  this._kv.initialize(this._serviceContext);
1520
1794
  this._serviceContext.registerService("kv", this._kv);
1521
- this._sql = new import_sdk_core5.SQLService({});
1795
+ this._sql = new import_sdk_core6.SQLService({});
1522
1796
  this._sql.initialize(this._serviceContext);
1523
1797
  this._serviceContext.registerService("sql", this._sql);
1524
- this._duckdb = new import_sdk_core5.DuckDbService({});
1798
+ this._duckdb = new import_sdk_core6.DuckDbService({});
1525
1799
  this._duckdb.initialize(this._serviceContext);
1526
1800
  this._serviceContext.registerService("duckdb", this._duckdb);
1527
- this._hooks = new import_sdk_core5.HooksService({});
1801
+ this._hooks = new import_sdk_core6.HooksService({});
1528
1802
  this._hooks.initialize(this._serviceContext);
1529
1803
  this._serviceContext.registerService("hooks", this._hooks);
1530
1804
  const serviceSession = {
@@ -1535,41 +1809,7 @@ var _TinyCloudNode = class _TinyCloudNode {
1535
1809
  jwk: sessionData.jwk
1536
1810
  };
1537
1811
  this._serviceContext.setSession(serviceSession);
1538
- const wasm = this.wasmBindings;
1539
- const vaultCrypto = (0, import_sdk_core5.createVaultCrypto)({
1540
- vault_encrypt: wasm.vault_encrypt,
1541
- vault_decrypt: wasm.vault_decrypt,
1542
- vault_derive_key: wasm.vault_derive_key,
1543
- vault_x25519_from_seed: wasm.vault_x25519_from_seed,
1544
- vault_x25519_dh: wasm.vault_x25519_dh,
1545
- vault_random_bytes: wasm.vault_random_bytes,
1546
- vault_sha256: wasm.vault_sha256
1547
- });
1548
- const self = this;
1549
- this._vault = new import_sdk_core5.DataVaultService({
1550
- spaceId: sessionData.spaceId,
1551
- crypto: vaultCrypto,
1552
- tc: {
1553
- kv: this._kv,
1554
- ensurePublicSpace: async () => {
1555
- try {
1556
- await self.ensurePublicSpace();
1557
- return { ok: true, data: void 0 };
1558
- } catch (error) {
1559
- return { ok: false, error: { code: "STORAGE_ERROR", message: error instanceof Error ? error.message : String(error), service: "vault" } };
1560
- }
1561
- },
1562
- get publicKV() {
1563
- return self._publicKV ?? self.tc.publicKV;
1564
- },
1565
- readPublicSpace: (host, spaceId, key) => import_sdk_core5.TinyCloud.readPublicSpace(host, spaceId, key),
1566
- makePublicSpaceId: import_sdk_core5.TinyCloud.makePublicSpaceId,
1567
- did: this.did,
1568
- address: sessionData.address ?? this._address ?? "",
1569
- chainId: sessionData.chainId ?? this._chainId,
1570
- hosts: [this.config.host]
1571
- }
1572
- });
1812
+ this._vault = this.createVaultService(sessionData.spaceId, this._kv);
1573
1813
  this._vault.initialize(this._serviceContext);
1574
1814
  this._serviceContext.registerService("vault", this._vault);
1575
1815
  this.initializeV2Services(serviceSession);
@@ -1604,7 +1844,6 @@ var _TinyCloudNode = class _TinyCloudNode {
1604
1844
  throw new Error("Wallet already connected. Cannot connect another wallet.");
1605
1845
  }
1606
1846
  const prefix = options?.prefix ?? "default";
1607
- const host = this.config.host;
1608
1847
  if (!_TinyCloudNode.nodeDefaults) {
1609
1848
  throw new Error(
1610
1849
  "connectWallet() requires PrivateKeySigner. Use connectSigner() instead, or import from '@tinycloud/node-sdk' (not '/core') for automatic Node.js defaults."
@@ -1618,8 +1857,10 @@ var _TinyCloudNode = class _TinyCloudNode {
1618
1857
  sessionStorage: options?.sessionStorage ?? this.config.sessionStorage ?? new MemorySessionStorage(),
1619
1858
  domain: this.siweDomain,
1620
1859
  spacePrefix: prefix,
1621
- sessionExpirationMs: this.config.sessionExpirationMs ?? 60 * 60 * 1e3,
1622
- tinycloudHosts: [host],
1860
+ sessionExpirationMs: this.config.sessionExpirationMs ?? DEFAULT_SESSION_EXPIRATION_MS,
1861
+ tinycloudHosts: this.explicitHost ? [this.explicitHost] : void 0,
1862
+ tinycloudRegistryUrl: this.config.tinycloudRegistryUrl,
1863
+ tinycloudFallbackHosts: this.config.tinycloudFallbackHosts,
1623
1864
  autoCreateSpace: this.config.autoCreateSpace,
1624
1865
  enablePublicSpace: this.config.enablePublicSpace ?? true,
1625
1866
  spaceCreationHandler: this.config.spaceCreationHandler,
@@ -1629,8 +1870,8 @@ var _TinyCloudNode = class _TinyCloudNode {
1629
1870
  capabilityRequest: this.config.capabilityRequest,
1630
1871
  includeAccountRegistryPermissions: this.config.includeAccountRegistryPermissions
1631
1872
  });
1632
- this.tc = new import_sdk_core5.TinyCloud(this.auth, {
1633
- invokeAny: this.wasmBindings.invokeAny
1873
+ this.tc = new import_sdk_core6.TinyCloud(this.auth, {
1874
+ invokeAny: this.invokeAnyWithRuntimePermissions
1634
1875
  });
1635
1876
  this.config.prefix = prefix;
1636
1877
  }
@@ -1652,7 +1893,6 @@ var _TinyCloudNode = class _TinyCloudNode {
1652
1893
  throw new Error("Signer already connected. Cannot connect another signer.");
1653
1894
  }
1654
1895
  const prefix = options?.prefix ?? "default";
1655
- const host = this.config.host;
1656
1896
  this.signer = signer;
1657
1897
  this.auth = new NodeUserAuthorization({
1658
1898
  signer: this.signer,
@@ -1661,8 +1901,10 @@ var _TinyCloudNode = class _TinyCloudNode {
1661
1901
  sessionStorage: options?.sessionStorage ?? this.config.sessionStorage ?? new MemorySessionStorage(),
1662
1902
  domain: this.siweDomain,
1663
1903
  spacePrefix: prefix,
1664
- sessionExpirationMs: this.config.sessionExpirationMs ?? 60 * 60 * 1e3,
1665
- tinycloudHosts: [host],
1904
+ sessionExpirationMs: this.config.sessionExpirationMs ?? DEFAULT_SESSION_EXPIRATION_MS,
1905
+ tinycloudHosts: this.explicitHost ? [this.explicitHost] : void 0,
1906
+ tinycloudRegistryUrl: this.config.tinycloudRegistryUrl,
1907
+ tinycloudFallbackHosts: this.config.tinycloudFallbackHosts,
1666
1908
  autoCreateSpace: this.config.autoCreateSpace,
1667
1909
  enablePublicSpace: this.config.enablePublicSpace ?? true,
1668
1910
  spaceCreationHandler: this.config.spaceCreationHandler,
@@ -1672,8 +1914,8 @@ var _TinyCloudNode = class _TinyCloudNode {
1672
1914
  capabilityRequest: this.config.capabilityRequest,
1673
1915
  includeAccountRegistryPermissions: this.config.includeAccountRegistryPermissions
1674
1916
  });
1675
- this.tc = new import_sdk_core5.TinyCloud(this.auth, {
1676
- invokeAny: this.wasmBindings.invokeAny
1917
+ this.tc = new import_sdk_core6.TinyCloud(this.auth, {
1918
+ invokeAny: this.invokeAnyWithRuntimePermissions
1677
1919
  });
1678
1920
  this.config.prefix = prefix;
1679
1921
  }
@@ -1686,28 +1928,28 @@ var _TinyCloudNode = class _TinyCloudNode {
1686
1928
  if (!session) {
1687
1929
  return;
1688
1930
  }
1689
- this.tc.initializeServices(this.wasmBindings.invoke, [this.config.host]);
1690
- this._serviceContext = new import_sdk_core5.ServiceContext({
1691
- invoke: this.wasmBindings.invoke,
1692
- invokeAny: this.wasmBindings.invokeAny,
1931
+ this.tc.initializeServices(this.invokeWithRuntimePermissions, [this.config.host]);
1932
+ this._serviceContext = new import_sdk_core6.ServiceContext({
1933
+ invoke: this.invokeWithRuntimePermissions,
1934
+ invokeAny: this.invokeAnyWithRuntimePermissions,
1693
1935
  fetch: globalThis.fetch.bind(globalThis),
1694
1936
  hosts: [this.config.host]
1695
1937
  });
1696
- this._kv = new import_sdk_core5.KVService({});
1938
+ this._kv = new import_sdk_core6.KVService({});
1697
1939
  this._kv.initialize(this._serviceContext);
1698
1940
  this._serviceContext.registerService("kv", this._kv);
1699
1941
  const features = this.nodeFeatures;
1700
1942
  if (features.length === 0 || features.includes("sql")) {
1701
- this._sql = new import_sdk_core5.SQLService({});
1943
+ this._sql = new import_sdk_core6.SQLService({});
1702
1944
  this._sql.initialize(this._serviceContext);
1703
1945
  this._serviceContext.registerService("sql", this._sql);
1704
1946
  }
1705
1947
  if (features.length === 0 || features.includes("duckdb")) {
1706
- this._duckdb = new import_sdk_core5.DuckDbService({});
1948
+ this._duckdb = new import_sdk_core6.DuckDbService({});
1707
1949
  this._duckdb.initialize(this._serviceContext);
1708
1950
  this._serviceContext.registerService("duckdb", this._duckdb);
1709
1951
  }
1710
- this._hooks = new import_sdk_core5.HooksService({});
1952
+ this._hooks = new import_sdk_core6.HooksService({});
1711
1953
  this._hooks.initialize(this._serviceContext);
1712
1954
  this._serviceContext.registerService("hooks", this._hooks);
1713
1955
  const serviceSession = {
@@ -1719,8 +1961,30 @@ var _TinyCloudNode = class _TinyCloudNode {
1719
1961
  };
1720
1962
  this._serviceContext.setSession(serviceSession);
1721
1963
  this.tc.serviceContext.setSession(serviceSession);
1964
+ this._vault = this.createVaultService(session.spaceId, this._kv);
1965
+ this._vault.initialize(this._serviceContext);
1966
+ this._serviceContext.registerService("vault", this._vault);
1967
+ this.initializeV2Services(serviceSession);
1968
+ }
1969
+ createSpaceScopedKVService(spaceId) {
1970
+ const kvService = new import_sdk_core6.KVService({});
1971
+ if (this._serviceContext) {
1972
+ const spaceScopedContext = new import_sdk_core6.ServiceContext({
1973
+ invoke: this._serviceContext.invoke,
1974
+ fetch: this._serviceContext.fetch,
1975
+ hosts: this._serviceContext.hosts
1976
+ });
1977
+ const session = this._serviceContext.session;
1978
+ if (session) {
1979
+ spaceScopedContext.setSession({ ...session, spaceId });
1980
+ }
1981
+ kvService.initialize(spaceScopedContext);
1982
+ }
1983
+ return kvService;
1984
+ }
1985
+ createVaultService(spaceId, kv) {
1722
1986
  const wasm = this.wasmBindings;
1723
- const vaultCrypto = (0, import_sdk_core5.createVaultCrypto)({
1987
+ const vaultCrypto = (0, import_sdk_core6.createVaultCrypto)({
1724
1988
  vault_encrypt: wasm.vault_encrypt,
1725
1989
  vault_decrypt: wasm.vault_decrypt,
1726
1990
  vault_derive_key: wasm.vault_derive_key,
@@ -1730,11 +1994,11 @@ var _TinyCloudNode = class _TinyCloudNode {
1730
1994
  vault_sha256: wasm.vault_sha256
1731
1995
  });
1732
1996
  const self = this;
1733
- this._vault = new import_sdk_core5.DataVaultService({
1734
- spaceId: session.spaceId,
1997
+ return new import_sdk_core6.DataVaultService({
1998
+ spaceId,
1735
1999
  crypto: vaultCrypto,
1736
2000
  tc: {
1737
- kv: this._kv,
2001
+ kv,
1738
2002
  ensurePublicSpace: async () => {
1739
2003
  try {
1740
2004
  await self.ensurePublicSpace();
@@ -1746,24 +2010,21 @@ var _TinyCloudNode = class _TinyCloudNode {
1746
2010
  get publicKV() {
1747
2011
  return self._publicKV ?? self.tc.publicKV;
1748
2012
  },
1749
- readPublicSpace: (host, spaceId, key) => import_sdk_core5.TinyCloud.readPublicSpace(host, spaceId, key),
1750
- makePublicSpaceId: import_sdk_core5.TinyCloud.makePublicSpaceId,
2013
+ readPublicSpace: (host, targetSpaceId, key) => import_sdk_core6.TinyCloud.readPublicSpace(host, targetSpaceId, key),
2014
+ makePublicSpaceId: import_sdk_core6.TinyCloud.makePublicSpaceId,
1751
2015
  did: this.did,
1752
- address: this._address,
2016
+ address: this._address ?? "",
1753
2017
  chainId: this._chainId,
1754
2018
  hosts: [this.config.host]
1755
2019
  }
1756
2020
  });
1757
- this._vault.initialize(this._serviceContext);
1758
- this._serviceContext.registerService("vault", this._vault);
1759
- this.initializeV2Services(serviceSession);
1760
2021
  }
1761
2022
  /**
1762
2023
  * Initialize the v2 delegation system services.
1763
2024
  * @internal
1764
2025
  */
1765
2026
  initializeV2Services(serviceSession) {
1766
- this._capabilityRegistry = new import_sdk_core5.CapabilityKeyRegistry();
2027
+ this._capabilityRegistry = new import_sdk_core6.CapabilityKeyRegistry();
1767
2028
  const tcSession = this.auth?.tinyCloudSession;
1768
2029
  if (tcSession && this._address) {
1769
2030
  const sessionKey = {
@@ -1837,13 +2098,13 @@ var _TinyCloudNode = class _TinyCloudNode {
1837
2098
  }
1838
2099
  this._capabilityRegistry.registerKey(sessionKey, delegations);
1839
2100
  }
1840
- this._delegationManager = new import_sdk_core5.DelegationManager({
2101
+ this._delegationManager = new import_sdk_core6.DelegationManager({
1841
2102
  hosts: [this.config.host],
1842
2103
  session: serviceSession,
1843
- invoke: this.wasmBindings.invoke,
2104
+ invoke: this.invokeWithRuntimePermissions,
1844
2105
  fetch: globalThis.fetch.bind(globalThis)
1845
2106
  });
1846
- this._spaceService = new import_sdk_core5.SpaceService({
2107
+ this._spaceService = new import_sdk_core6.SpaceService({
1847
2108
  hosts: [this.config.host],
1848
2109
  session: serviceSession,
1849
2110
  invoke: this.wasmBindings.invoke,
@@ -1851,20 +2112,15 @@ var _TinyCloudNode = class _TinyCloudNode {
1851
2112
  capabilityRegistry: this._capabilityRegistry,
1852
2113
  userDid: this.did,
1853
2114
  createKVService: (spaceId) => {
1854
- const kvService = new import_sdk_core5.KVService({});
2115
+ return this.createSpaceScopedKVService(spaceId);
2116
+ },
2117
+ createVaultService: (spaceId) => {
2118
+ const kvService = this.createSpaceScopedKVService(spaceId);
2119
+ const vaultService = this.createVaultService(spaceId, kvService);
1855
2120
  if (this._serviceContext) {
1856
- const spaceScopedContext = new import_sdk_core5.ServiceContext({
1857
- invoke: this._serviceContext.invoke,
1858
- fetch: this._serviceContext.fetch,
1859
- hosts: this._serviceContext.hosts
1860
- });
1861
- const session = this._serviceContext.session;
1862
- if (session) {
1863
- spaceScopedContext.setSession({ ...session, spaceId });
1864
- }
1865
- kvService.initialize(spaceScopedContext);
2121
+ vaultService.initialize(this._serviceContext);
1866
2122
  }
1867
- return kvService;
2123
+ return vaultService;
1868
2124
  },
1869
2125
  // Enable space.delegations.create() via SIWE-based delegation
1870
2126
  createDelegation: async (params) => {
@@ -1921,7 +2177,7 @@ var _TinyCloudNode = class _TinyCloudNode {
1921
2177
  * @internal
1922
2178
  */
1923
2179
  getSessionExpiry() {
1924
- const expirationMs = this.config.sessionExpirationMs ?? 60 * 60 * 1e3;
2180
+ const expirationMs = this.config.sessionExpirationMs ?? DEFAULT_SESSION_EXPIRATION_MS;
1925
2181
  return new Date(Date.now() + expirationMs);
1926
2182
  }
1927
2183
  /**
@@ -2005,7 +2261,7 @@ var _TinyCloudNode = class _TinyCloudNode {
2005
2261
  ...prepared,
2006
2262
  signature
2007
2263
  });
2008
- const activateResult = await (0, import_sdk_core5.activateSessionWithHost)(
2264
+ const activateResult = await (0, import_sdk_core6.activateSessionWithHost)(
2009
2265
  host,
2010
2266
  delegationSession.delegationHeader
2011
2267
  );
@@ -2072,12 +2328,40 @@ var _TinyCloudNode = class _TinyCloudNode {
2072
2328
  if (!this._sql) {
2073
2329
  const features = this.nodeFeatures;
2074
2330
  if (features.length > 0 && !features.includes("sql")) {
2075
- throw new import_sdk_core5.UnsupportedFeatureError("sql", this.config.host, features);
2331
+ throw new import_sdk_core6.UnsupportedFeatureError("sql", this.config.host, features);
2076
2332
  }
2077
2333
  throw new Error("Not signed in. Call signIn() first.");
2078
2334
  }
2079
2335
  return this._sql;
2080
2336
  }
2337
+ /**
2338
+ * Get an SQL service scoped to a specific space.
2339
+ *
2340
+ * Mirrors {@link SpaceService}'s per-space KV factory: clones the active
2341
+ * service context and overrides its session's spaceId so that subsequent
2342
+ * `sql/<dbName>/<action>` invocations route to that space. Useful when
2343
+ * the caller already holds a delegation covering the target space (e.g.
2344
+ * via {@link grantRuntimePermissions} or {@link useRuntimeDelegation})
2345
+ * but the SDK's per-space SQL surface isn't otherwise exposed.
2346
+ *
2347
+ * Does NOT auto-create the space.
2348
+ *
2349
+ * @param spaceId - Full space URI (`tinycloud:pkh:eip155:<chain>:<addr>:<name>`).
2350
+ */
2351
+ sqlForSpace(spaceId) {
2352
+ if (!this._serviceContext || !this._serviceContext.session) {
2353
+ throw new Error("Not signed in. Call signIn() first.");
2354
+ }
2355
+ const sql = new import_sdk_core6.SQLService({});
2356
+ const spaceScopedContext = new import_sdk_core6.ServiceContext({
2357
+ invoke: this._serviceContext.invoke,
2358
+ fetch: this._serviceContext.fetch,
2359
+ hosts: this._serviceContext.hosts
2360
+ });
2361
+ spaceScopedContext.setSession({ ...this._serviceContext.session, spaceId });
2362
+ sql.initialize(spaceScopedContext);
2363
+ return sql;
2364
+ }
2081
2365
  /**
2082
2366
  * DuckDB database operations on this user's space.
2083
2367
  */
@@ -2085,7 +2369,7 @@ var _TinyCloudNode = class _TinyCloudNode {
2085
2369
  if (!this._duckdb) {
2086
2370
  const features = this.nodeFeatures;
2087
2371
  if (features.length > 0 && !features.includes("duckdb")) {
2088
- throw new import_sdk_core5.UnsupportedFeatureError("duckdb", this.config.host, features);
2372
+ throw new import_sdk_core6.UnsupportedFeatureError("duckdb", this.config.host, features);
2089
2373
  }
2090
2374
  throw new Error("Not signed in. Call signIn() first.");
2091
2375
  }
@@ -2101,6 +2385,33 @@ var _TinyCloudNode = class _TinyCloudNode {
2101
2385
  }
2102
2386
  return this._vault;
2103
2387
  }
2388
+ /**
2389
+ * App-facing secrets API backed by the `secrets` space vault.
2390
+ */
2391
+ get secrets() {
2392
+ if (!this._spaceService) {
2393
+ throw new Error("Not signed in. Call signIn() first.");
2394
+ }
2395
+ if (!this._secrets) {
2396
+ this._secrets = new NodeSecretsService({
2397
+ getService: () => this.getBaseSecrets(),
2398
+ getManifest: () => this.manifest,
2399
+ grantPermissions: (additional) => this.grantRuntimePermissions(additional),
2400
+ canEscalate: () => this.signer !== void 0 && this.tc !== void 0,
2401
+ getUnlockSigner: () => this.signer ?? void 0
2402
+ });
2403
+ }
2404
+ return this._secrets;
2405
+ }
2406
+ getBaseSecrets() {
2407
+ if (!this._spaceService) {
2408
+ throw new Error("Not signed in. Call signIn() first.");
2409
+ }
2410
+ if (!this._baseSecrets) {
2411
+ this._baseSecrets = new import_sdk_core6.SecretsService(() => this.space("secrets").vault);
2412
+ }
2413
+ return this._baseSecrets;
2414
+ }
2104
2415
  /**
2105
2416
  * Hooks write stream subscription API.
2106
2417
  */
@@ -2171,6 +2482,171 @@ var _TinyCloudNode = class _TinyCloudNode {
2171
2482
  }
2172
2483
  };
2173
2484
  }
2485
+ /**
2486
+ * Check whether the current session or an approved runtime delegation covers
2487
+ * every requested permission.
2488
+ */
2489
+ hasRuntimePermissions(permissions) {
2490
+ const session = this.auth?.tinyCloudSession;
2491
+ if (!session || !Array.isArray(permissions) || permissions.length === 0) {
2492
+ return false;
2493
+ }
2494
+ const expanded = this.expandPermissionEntries(permissions);
2495
+ if (this.sessionCoversPermissionEntries(session, expanded)) {
2496
+ return true;
2497
+ }
2498
+ return this.findRuntimeGrantsForPermissionEntries(expanded, session).length > 0;
2499
+ }
2500
+ /**
2501
+ * Return installed runtime permission delegations. When `permissions` is
2502
+ * provided, only delegations currently covering those permissions are
2503
+ * returned. Base-session manifest permissions are not represented here.
2504
+ */
2505
+ getRuntimePermissionDelegations(permissions) {
2506
+ this.pruneExpiredRuntimePermissionGrants();
2507
+ if (permissions === void 0) {
2508
+ return this.runtimePermissionGrants.map((grant) => grant.delegation);
2509
+ }
2510
+ const session = this.auth?.tinyCloudSession;
2511
+ if (!session || !Array.isArray(permissions) || permissions.length === 0) {
2512
+ return [];
2513
+ }
2514
+ const expanded = this.expandPermissionEntries(permissions);
2515
+ return this.findRuntimeGrantsForPermissionEntries(expanded, session).map(
2516
+ (grant) => grant.delegation
2517
+ );
2518
+ }
2519
+ /**
2520
+ * Install a portable runtime permission delegation into this SDK instance so
2521
+ * matching service calls and downstream `delegateTo()` calls can use it.
2522
+ */
2523
+ async useRuntimeDelegation(delegation) {
2524
+ const session = this.auth?.tinyCloudSession;
2525
+ if (!session) {
2526
+ throw new import_sdk_core6.SessionExpiredError(/* @__PURE__ */ new Date(0));
2527
+ }
2528
+ if (delegation.expiry.getTime() <= Date.now()) {
2529
+ throw new import_sdk_core6.SessionExpiredError(delegation.expiry);
2530
+ }
2531
+ const expectedDids = /* @__PURE__ */ new Set([session.verificationMethod, this.sessionDid]);
2532
+ if (!expectedDids.has(delegation.delegateDID)) {
2533
+ throw new Error(
2534
+ `Runtime delegation targets ${delegation.delegateDID} but this session key is ${session.verificationMethod}.`
2535
+ );
2536
+ }
2537
+ const targetHost = delegation.host ?? this.config.host;
2538
+ const activateResult = await (0, import_sdk_core6.activateSessionWithHost)(
2539
+ targetHost,
2540
+ delegation.delegationHeader
2541
+ );
2542
+ if (!activateResult.success) {
2543
+ throw new Error(
2544
+ `Failed to activate runtime permission delegation: ${activateResult.error}`
2545
+ );
2546
+ }
2547
+ this.runtimePermissionGrants = this.runtimePermissionGrants.filter(
2548
+ (grant) => grant.delegation.cid !== delegation.cid
2549
+ );
2550
+ this.runtimePermissionGrants.push(
2551
+ this.runtimeGrantFromDelegation(delegation, session)
2552
+ );
2553
+ }
2554
+ /**
2555
+ * Store additional permissions as narrow delegations to the current session
2556
+ * key. Future service invocations automatically use a stored delegation when
2557
+ * its `(space, service, path, action)` covers the request.
2558
+ */
2559
+ async grantRuntimePermissions(permissions, options) {
2560
+ if (!Array.isArray(permissions) || permissions.length === 0) {
2561
+ throw new Error("grantRuntimePermissions requires a non-empty permissions array");
2562
+ }
2563
+ const session = this.auth?.tinyCloudSession;
2564
+ if (!session) {
2565
+ throw new import_sdk_core6.SessionExpiredError(/* @__PURE__ */ new Date(0));
2566
+ }
2567
+ const sessionExpiry = extractSiweExpiration(session.siwe);
2568
+ if (sessionExpiry !== void 0) {
2569
+ const marginMs = _TinyCloudNode.SESSION_EXPIRY_SAFETY_MARGIN_MS;
2570
+ if (sessionExpiry.getTime() <= Date.now() + marginMs) {
2571
+ throw new import_sdk_core6.SessionExpiredError(sessionExpiry);
2572
+ }
2573
+ }
2574
+ const expanded = this.expandPermissionEntries(permissions);
2575
+ if (this.sessionCoversPermissionEntries(session, expanded)) {
2576
+ return [];
2577
+ }
2578
+ const existingGrants = this.findRuntimeGrantsForPermissionEntries(expanded, session);
2579
+ if (existingGrants.length > 0) {
2580
+ return existingGrants.map((grant) => grant.delegation);
2581
+ }
2582
+ if (!this.signer) {
2583
+ throw new Error(
2584
+ "grantRuntimePermissions requires wallet mode with a signer or privateKey."
2585
+ );
2586
+ }
2587
+ const bySpace = /* @__PURE__ */ new Map();
2588
+ for (const entry of expanded) {
2589
+ const spaceId = this.resolvePermissionSpace(entry.space, session);
2590
+ const current = bySpace.get(spaceId) ?? [];
2591
+ current.push(entry);
2592
+ bySpace.set(spaceId, current);
2593
+ }
2594
+ const now = /* @__PURE__ */ new Date();
2595
+ const requestedExpiryMs = resolveExpiryMs(options?.expiry);
2596
+ let expiresAt = new Date(now.getTime() + requestedExpiryMs);
2597
+ if (sessionExpiry !== void 0 && sessionExpiry < expiresAt) {
2598
+ expiresAt = sessionExpiry;
2599
+ }
2600
+ const delegations = [];
2601
+ for (const [spaceId, entries] of bySpace) {
2602
+ const abilities = this.permissionsToAbilities(entries);
2603
+ const prepared = this.wasmBindings.prepareSession({
2604
+ abilities,
2605
+ address: this.wasmBindings.ensureEip55(session.address),
2606
+ chainId: session.chainId,
2607
+ domain: this.siweDomain,
2608
+ issuedAt: now.toISOString(),
2609
+ expirationTime: expiresAt.toISOString(),
2610
+ spaceId,
2611
+ jwk: session.jwk
2612
+ });
2613
+ const signature = await this.signer.signMessage(prepared.siwe);
2614
+ const delegatedSession = this.wasmBindings.completeSessionSetup({
2615
+ ...prepared,
2616
+ signature
2617
+ });
2618
+ const activateResult = await (0, import_sdk_core6.activateSessionWithHost)(
2619
+ this.config.host,
2620
+ delegatedSession.delegationHeader
2621
+ );
2622
+ if (!activateResult.success) {
2623
+ throw new Error(
2624
+ `Failed to activate runtime permission delegation: ${activateResult.error}`
2625
+ );
2626
+ }
2627
+ const delegation = this.runtimeDelegationFromSession(
2628
+ delegatedSession,
2629
+ entries,
2630
+ spaceId,
2631
+ session,
2632
+ expiresAt
2633
+ );
2634
+ this.runtimePermissionGrants.push({
2635
+ session: {
2636
+ delegationHeader: delegatedSession.delegationHeader,
2637
+ delegationCid: delegatedSession.delegationCid,
2638
+ spaceId,
2639
+ verificationMethod: session.verificationMethod,
2640
+ jwk: session.jwk
2641
+ },
2642
+ delegation,
2643
+ operations: this.permissionOperations(entries, spaceId),
2644
+ expiresAt
2645
+ });
2646
+ delegations.push(delegation);
2647
+ }
2648
+ return delegations;
2649
+ }
2174
2650
  /**
2175
2651
  * Get the DelegationManager for delegation CRUD operations.
2176
2652
  *
@@ -2239,6 +2715,12 @@ var _TinyCloudNode = class _TinyCloudNode {
2239
2715
  get spaceService() {
2240
2716
  return this.spaces;
2241
2717
  }
2718
+ /**
2719
+ * Get a Space object by short name or full URI.
2720
+ */
2721
+ space(nameOrUri) {
2722
+ return this.spaces.get(nameOrUri);
2723
+ }
2242
2724
  /**
2243
2725
  * Get the SharingService for creating and receiving v2 sharing links.
2244
2726
  *
@@ -2306,7 +2788,7 @@ var _TinyCloudNode = class _TinyCloudNode {
2306
2788
  ];
2307
2789
  const abilities = { kv: { "": kvActions } };
2308
2790
  const now = /* @__PURE__ */ new Date();
2309
- const expiryMs = 60 * 60 * 1e3;
2791
+ const expiryMs = import_sdk_core6.EXPIRY.EPHEMERAL_MS;
2310
2792
  const expirationTime = new Date(now.getTime() + expiryMs);
2311
2793
  const prepared = this.wasmBindings.prepareSession({
2312
2794
  abilities,
@@ -2324,7 +2806,7 @@ var _TinyCloudNode = class _TinyCloudNode {
2324
2806
  ...prepared,
2325
2807
  signature
2326
2808
  });
2327
- const activateResult = await (0, import_sdk_core5.activateSessionWithHost)(
2809
+ const activateResult = await (0, import_sdk_core6.activateSessionWithHost)(
2328
2810
  this.config.host,
2329
2811
  delegationSession.delegationHeader
2330
2812
  );
@@ -2351,9 +2833,9 @@ var _TinyCloudNode = class _TinyCloudNode {
2351
2833
  }]);
2352
2834
  }
2353
2835
  if (this._serviceContext) {
2354
- const publicKV = new import_sdk_core5.KVService({ prefix: "" });
2355
- const publicContext = new import_sdk_core5.ServiceContext({
2356
- invoke: this.wasmBindings.invoke,
2836
+ const publicKV = new import_sdk_core6.KVService({ prefix: "" });
2837
+ const publicContext = new import_sdk_core6.ServiceContext({
2838
+ invoke: this.invokeWithRuntimePermissions,
2357
2839
  fetch: this._serviceContext.fetch,
2358
2840
  hosts: this._serviceContext.hosts
2359
2841
  });
@@ -2441,8 +2923,9 @@ var _TinyCloudNode = class _TinyCloudNode {
2441
2923
  * Issue a delegation using the capability-chain flow.
2442
2924
  *
2443
2925
  * When every requested permission is a subset of the current
2444
- * session's recap, the delegation is signed by the session key via
2445
- * WASM no wallet prompt. When at least one is NOT derivable, a
2926
+ * session's recap, or of one installed runtime permission delegation,
2927
+ * the delegation is signed by the session key via WASM no wallet
2928
+ * prompt. When at least one is NOT derivable, a
2446
2929
  * {@link PermissionNotInManifestError} is raised (carrying the
2447
2930
  * missing entries) so the caller can trigger an escalation flow
2448
2931
  * (e.g. `TinyCloudWeb.requestPermissions`). Passing
@@ -2477,14 +2960,14 @@ var _TinyCloudNode = class _TinyCloudNode {
2477
2960
  async delegateTo(did, permissions, options) {
2478
2961
  const session = this.auth?.tinyCloudSession;
2479
2962
  if (!session) {
2480
- throw new import_sdk_core5.SessionExpiredError(/* @__PURE__ */ new Date(0));
2963
+ throw new import_sdk_core6.SessionExpiredError(/* @__PURE__ */ new Date(0));
2481
2964
  }
2482
2965
  const sessionExpiry = extractSiweExpiration(session.siwe);
2483
2966
  if (sessionExpiry !== void 0) {
2484
2967
  const now2 = Date.now();
2485
2968
  const marginMs = _TinyCloudNode.SESSION_EXPIRY_SAFETY_MARGIN_MS;
2486
2969
  if (sessionExpiry.getTime() <= now2 + marginMs) {
2487
- throw new import_sdk_core5.SessionExpiredError(sessionExpiry);
2970
+ throw new import_sdk_core6.SessionExpiredError(sessionExpiry);
2488
2971
  }
2489
2972
  }
2490
2973
  if (!Array.isArray(permissions) || permissions.length === 0) {
@@ -2492,10 +2975,7 @@ var _TinyCloudNode = class _TinyCloudNode {
2492
2975
  "delegateTo requires a non-empty permissions array"
2493
2976
  );
2494
2977
  }
2495
- const expandedEntries = permissions.map((entry) => ({
2496
- ...entry,
2497
- actions: (0, import_sdk_core5.expandActionShortNames)(entry.service, entry.actions)
2498
- }));
2978
+ const expandedEntries = this.expandPermissionEntries(permissions);
2499
2979
  const now = /* @__PURE__ */ new Date();
2500
2980
  const expiryMs = resolveExpiryMs(options?.expiry);
2501
2981
  const expirationTime = new Date(now.getTime() + expiryMs);
@@ -2516,13 +2996,30 @@ var _TinyCloudNode = class _TinyCloudNode {
2516
2996
  );
2517
2997
  return { delegation: delegation2, prompted: true };
2518
2998
  }
2519
- const granted = (0, import_sdk_core5.parseRecapCapabilities)(
2999
+ const granted = (0, import_sdk_core6.parseRecapCapabilities)(
2520
3000
  (siwe) => this.wasmBindings.parseRecapFromSiwe(siwe),
2521
3001
  session.siwe
2522
3002
  );
2523
- const { subset, missing } = (0, import_sdk_core5.isCapabilitySubset)(expandedEntries, granted);
3003
+ const { subset, missing } = (0, import_sdk_core6.isCapabilitySubset)(expandedEntries, granted);
2524
3004
  if (!subset) {
2525
- throw new import_sdk_core5.PermissionNotInManifestError(missing, granted);
3005
+ const runtimeGrant = this.findGrantForOperations(
3006
+ this.permissionEntriesToOperations(expandedEntries, session)
3007
+ );
3008
+ if (runtimeGrant) {
3009
+ const marginMs = _TinyCloudNode.SESSION_EXPIRY_SAFETY_MARGIN_MS;
3010
+ if (runtimeGrant.expiresAt.getTime() <= Date.now() + marginMs) {
3011
+ throw new import_sdk_core6.SessionExpiredError(runtimeGrant.expiresAt);
3012
+ }
3013
+ const runtimeExpiration = runtimeGrant.expiresAt < effectiveExpiration ? runtimeGrant.expiresAt : effectiveExpiration;
3014
+ const delegation2 = await this.createDelegationViaRuntimeGrant(
3015
+ did,
3016
+ expandedEntries,
3017
+ runtimeExpiration,
3018
+ runtimeGrant
3019
+ );
3020
+ return { delegation: delegation2, prompted: false };
3021
+ }
3022
+ throw new import_sdk_core6.PermissionNotInManifestError(missing, granted);
2526
3023
  }
2527
3024
  const delegation = await this.createDelegationViaWasmPath(
2528
3025
  did,
@@ -2602,7 +3099,7 @@ var _TinyCloudNode = class _TinyCloudNode {
2602
3099
  const spaceId = [...resolvedSpaces][0];
2603
3100
  const abilities = {};
2604
3101
  for (const entry of entries) {
2605
- const shortService = import_sdk_core5.SERVICE_LONG_TO_SHORT[entry.service];
3102
+ const shortService = import_sdk_core6.SERVICE_LONG_TO_SHORT[entry.service];
2606
3103
  if (shortService === void 0) {
2607
3104
  throw new Error(
2608
3105
  `delegateTo: unknown service '${entry.service}' \u2014 no short-form mapping`
@@ -2642,7 +3139,7 @@ var _TinyCloudNode = class _TinyCloudNode {
2642
3139
  });
2643
3140
  const primary = result.resources[0];
2644
3141
  const delegationHeader = { Authorization: result.delegation };
2645
- const activateResult = await (0, import_sdk_core5.activateSessionWithHost)(
3142
+ const activateResult = await (0, import_sdk_core6.activateSessionWithHost)(
2646
3143
  this.config.host,
2647
3144
  delegationHeader
2648
3145
  );
@@ -2666,6 +3163,41 @@ var _TinyCloudNode = class _TinyCloudNode {
2666
3163
  host: this.config.host
2667
3164
  };
2668
3165
  }
3166
+ async createDelegationViaRuntimeGrant(did, entries, expirationTime, grant) {
3167
+ const result = this.createDelegationWrapper({
3168
+ session: grant.session,
3169
+ delegateDID: did,
3170
+ spaceId: grant.session.spaceId,
3171
+ abilities: this.permissionsToAbilities(entries),
3172
+ expirationSecs: Math.floor(expirationTime.getTime() / 1e3)
3173
+ });
3174
+ const primary = result.resources[0];
3175
+ const delegationHeader = { Authorization: result.delegation };
3176
+ const targetHost = grant.delegation.host ?? this.config.host;
3177
+ const activateResult = await (0, import_sdk_core6.activateSessionWithHost)(
3178
+ targetHost,
3179
+ delegationHeader
3180
+ );
3181
+ if (!activateResult.success) {
3182
+ throw new Error(
3183
+ `Failed to activate delegation with host: ${activateResult.error}`
3184
+ );
3185
+ }
3186
+ return {
3187
+ cid: result.cid,
3188
+ delegationHeader,
3189
+ spaceId: grant.session.spaceId,
3190
+ path: primary.path,
3191
+ actions: primary.actions,
3192
+ resources: result.resources,
3193
+ disableSubDelegation: false,
3194
+ expiry: result.expiry,
3195
+ delegateDID: did,
3196
+ ownerAddress: grant.delegation.ownerAddress,
3197
+ chainId: grant.delegation.chainId,
3198
+ host: targetHost
3199
+ };
3200
+ }
2669
3201
  resolvePermissionSpace(space, session) {
2670
3202
  if (space === void 0) {
2671
3203
  return this.wasmBindings.makeSpaceId(
@@ -2682,6 +3214,220 @@ var _TinyCloudNode = class _TinyCloudNode {
2682
3214
  }
2683
3215
  return this.wasmBindings.makeSpaceId(session.address, session.chainId, space);
2684
3216
  }
3217
+ expandPermissionEntries(permissions) {
3218
+ return (0, import_sdk_core6.expandPermissionEntries)(permissions);
3219
+ }
3220
+ shortServiceName(service) {
3221
+ const short = import_sdk_core6.SERVICE_LONG_TO_SHORT[service];
3222
+ if (short === void 0) {
3223
+ throw new Error(
3224
+ `unknown service '${service}' \u2014 no short-form mapping`
3225
+ );
3226
+ }
3227
+ return short;
3228
+ }
3229
+ permissionsToAbilities(entries) {
3230
+ const abilities = {};
3231
+ for (const entry of entries) {
3232
+ const service = this.shortServiceName(entry.service);
3233
+ abilities[service] ?? (abilities[service] = {});
3234
+ const existing = abilities[service][entry.path] ?? [];
3235
+ const seen = new Set(existing);
3236
+ for (const action of entry.actions) {
3237
+ if (!seen.has(action)) {
3238
+ existing.push(action);
3239
+ seen.add(action);
3240
+ }
3241
+ }
3242
+ abilities[service][entry.path] = existing;
3243
+ }
3244
+ return abilities;
3245
+ }
3246
+ permissionOperations(entries, spaceId) {
3247
+ return entries.flatMap((entry) => {
3248
+ const service = this.shortServiceName(entry.service);
3249
+ return entry.actions.map((action) => ({
3250
+ spaceId,
3251
+ service,
3252
+ path: entry.path,
3253
+ action
3254
+ }));
3255
+ });
3256
+ }
3257
+ sessionCoversPermissionEntries(session, entries) {
3258
+ try {
3259
+ const granted = (0, import_sdk_core6.parseRecapCapabilities)(
3260
+ (siwe) => this.wasmBindings.parseRecapFromSiwe(siwe),
3261
+ session.siwe
3262
+ );
3263
+ return (0, import_sdk_core6.isCapabilitySubset)(entries, granted).subset;
3264
+ } catch {
3265
+ return false;
3266
+ }
3267
+ }
3268
+ permissionEntriesToOperations(entries, session) {
3269
+ return entries.flatMap((entry) => {
3270
+ const spaceId = this.resolvePermissionSpace(entry.space, session);
3271
+ const service = this.shortServiceName(entry.service);
3272
+ return entry.actions.map((action) => ({
3273
+ spaceId,
3274
+ service,
3275
+ path: entry.path,
3276
+ action
3277
+ }));
3278
+ });
3279
+ }
3280
+ findRuntimeGrantsForPermissionEntries(entries, session) {
3281
+ const grants = [];
3282
+ const operations = this.permissionEntriesToOperations(entries, session);
3283
+ if (operations.length === 0) {
3284
+ return grants;
3285
+ }
3286
+ for (const operation of operations) {
3287
+ const grant = this.findGrantForOperation(operation);
3288
+ if (!grant) {
3289
+ return [];
3290
+ }
3291
+ if (!grants.includes(grant)) {
3292
+ grants.push(grant);
3293
+ }
3294
+ }
3295
+ return grants;
3296
+ }
3297
+ runtimeDelegationFromSession(delegatedSession, entries, spaceId, session, expiresAt) {
3298
+ const resources = this.delegatedResourcesForEntries(entries, spaceId);
3299
+ const primary = resources[0];
3300
+ return {
3301
+ cid: delegatedSession.delegationCid,
3302
+ delegationHeader: delegatedSession.delegationHeader,
3303
+ spaceId,
3304
+ path: primary.path,
3305
+ actions: primary.actions,
3306
+ resources,
3307
+ disableSubDelegation: false,
3308
+ expiry: expiresAt,
3309
+ delegateDID: session.verificationMethod,
3310
+ ownerAddress: session.address,
3311
+ chainId: session.chainId,
3312
+ host: this.config.host
3313
+ };
3314
+ }
3315
+ runtimeGrantFromDelegation(delegation, session) {
3316
+ const operations = this.operationsFromDelegation(delegation);
3317
+ return {
3318
+ session: {
3319
+ delegationHeader: delegation.delegationHeader,
3320
+ delegationCid: delegation.cid,
3321
+ spaceId: delegation.spaceId,
3322
+ verificationMethod: session.verificationMethod,
3323
+ jwk: session.jwk
3324
+ },
3325
+ delegation,
3326
+ operations,
3327
+ expiresAt: delegation.expiry
3328
+ };
3329
+ }
3330
+ delegatedResourcesForEntries(entries, spaceId) {
3331
+ return entries.map((entry) => ({
3332
+ service: this.shortServiceName(entry.service),
3333
+ space: spaceId,
3334
+ path: entry.path,
3335
+ actions: [...entry.actions]
3336
+ }));
3337
+ }
3338
+ operationsFromDelegation(delegation) {
3339
+ const resources = delegation.resources !== void 0 && delegation.resources.length > 0 ? delegation.resources : this.flatDelegationResources(delegation);
3340
+ return resources.flatMap(
3341
+ (resource) => resource.actions.map((action) => ({
3342
+ spaceId: resource.space,
3343
+ service: this.invocationServiceName(resource.service),
3344
+ path: resource.path,
3345
+ action
3346
+ }))
3347
+ );
3348
+ }
3349
+ flatDelegationResources(delegation) {
3350
+ const byService = /* @__PURE__ */ new Map();
3351
+ for (const action of delegation.actions) {
3352
+ const service = this.shortServiceName(action.split("/")[0]);
3353
+ const actions = byService.get(service) ?? [];
3354
+ actions.push(action);
3355
+ byService.set(service, actions);
3356
+ }
3357
+ return [...byService.entries()].map(([service, actions]) => ({
3358
+ service,
3359
+ space: delegation.spaceId,
3360
+ path: delegation.path,
3361
+ actions
3362
+ }));
3363
+ }
3364
+ selectInvocationSession(fallback, service, path, action) {
3365
+ const grant = this.findGrantForOperation({
3366
+ spaceId: fallback.spaceId,
3367
+ service: this.invocationServiceName(service),
3368
+ path,
3369
+ action
3370
+ });
3371
+ return grant?.session ?? fallback;
3372
+ }
3373
+ findGrantForOperations(operations) {
3374
+ if (operations.length === 0) {
3375
+ return void 0;
3376
+ }
3377
+ this.pruneExpiredRuntimePermissionGrants();
3378
+ return this.runtimePermissionGrants.find((grant) => {
3379
+ return operations.every(
3380
+ (operation) => grant.operations.some(
3381
+ (granted) => this.operationCovers(granted, operation)
3382
+ )
3383
+ );
3384
+ });
3385
+ }
3386
+ findGrantForOperation(operation) {
3387
+ return this.findGrantForOperations([operation]);
3388
+ }
3389
+ pruneExpiredRuntimePermissionGrants() {
3390
+ const now = Date.now();
3391
+ this.runtimePermissionGrants = this.runtimePermissionGrants.filter(
3392
+ (grant) => grant.expiresAt.getTime() > now
3393
+ );
3394
+ }
3395
+ operationCovers(granted, requested) {
3396
+ return granted.spaceId === requested.spaceId && granted.service === requested.service && this.actionContains(granted.action, requested.action) && this.pathContains(granted.path, requested.path);
3397
+ }
3398
+ actionContains(grantedAction, requestedAction) {
3399
+ if (grantedAction === requestedAction) {
3400
+ return true;
3401
+ }
3402
+ if (grantedAction.endsWith("/*")) {
3403
+ const prefix = grantedAction.slice(0, -2);
3404
+ return requestedAction.startsWith(`${prefix}/`);
3405
+ }
3406
+ return false;
3407
+ }
3408
+ invocationServiceName(service) {
3409
+ return service.startsWith("tinycloud.") ? this.shortServiceName(service) : service;
3410
+ }
3411
+ pathContains(grantedPath, requestedPath) {
3412
+ if (grantedPath === "" || grantedPath === "/") {
3413
+ return true;
3414
+ }
3415
+ if (grantedPath.endsWith("/**")) {
3416
+ return requestedPath.startsWith(grantedPath.slice(0, -3));
3417
+ }
3418
+ if (grantedPath.endsWith("/*")) {
3419
+ const prefix = grantedPath.slice(0, -2);
3420
+ if (!requestedPath.startsWith(prefix)) {
3421
+ return false;
3422
+ }
3423
+ const remainder = requestedPath.slice(prefix.length);
3424
+ return !remainder.includes("/") || remainder === "/";
3425
+ }
3426
+ if (grantedPath.endsWith("/")) {
3427
+ return requestedPath.startsWith(grantedPath);
3428
+ }
3429
+ return grantedPath === requestedPath;
3430
+ }
2685
3431
  /**
2686
3432
  * Issue a delegation via the legacy wallet-signed SIWE path for a single
2687
3433
  * {@link PermissionEntry}. Shares the implementation with the public
@@ -2738,7 +3484,7 @@ var _TinyCloudNode = class _TinyCloudNode {
2738
3484
  );
2739
3485
  return result.delegation;
2740
3486
  } catch (err) {
2741
- if (err instanceof import_sdk_core5.PermissionNotInManifestError) {
3487
+ if (err instanceof import_sdk_core6.PermissionNotInManifestError) {
2742
3488
  } else {
2743
3489
  throw err;
2744
3490
  }
@@ -2795,7 +3541,7 @@ var _TinyCloudNode = class _TinyCloudNode {
2795
3541
  ...prepared,
2796
3542
  signature
2797
3543
  });
2798
- const activateResult = await (0, import_sdk_core5.activateSessionWithHost)(
3544
+ const activateResult = await (0, import_sdk_core6.activateSessionWithHost)(
2799
3545
  this.config.host,
2800
3546
  delegationSession.delegationHeader
2801
3547
  );
@@ -2817,7 +3563,7 @@ var _TinyCloudNode = class _TinyCloudNode {
2817
3563
  };
2818
3564
  const hasKvActions = params.actions.some((a) => a.startsWith("tinycloud.kv/"));
2819
3565
  if (hasKvActions && params.includePublicSpace !== false) {
2820
- const publicSpaceId = (0, import_sdk_core5.makePublicSpaceId)(
3566
+ const publicSpaceId = (0, import_sdk_core6.makePublicSpaceId)(
2821
3567
  this.wasmBindings.ensureEip55(session.address),
2822
3568
  session.chainId
2823
3569
  );
@@ -2840,7 +3586,7 @@ var _TinyCloudNode = class _TinyCloudNode {
2840
3586
  ...publicPrepared,
2841
3587
  signature: publicSignature
2842
3588
  });
2843
- const publicActivateResult = await (0, import_sdk_core5.activateSessionWithHost)(
3589
+ const publicActivateResult = await (0, import_sdk_core6.activateSessionWithHost)(
2844
3590
  this.config.host,
2845
3591
  publicSession.delegationHeader
2846
3592
  );
@@ -2939,7 +3685,7 @@ var _TinyCloudNode = class _TinyCloudNode {
2939
3685
  ...prepared,
2940
3686
  signature
2941
3687
  });
2942
- const activateResult = await (0, import_sdk_core5.activateSessionWithHost)(
3688
+ const activateResult = await (0, import_sdk_core6.activateSessionWithHost)(
2943
3689
  targetHost,
2944
3690
  invokerSession.delegationHeader
2945
3691
  );
@@ -3028,7 +3774,7 @@ var _TinyCloudNode = class _TinyCloudNode {
3028
3774
  ...prepared,
3029
3775
  signature
3030
3776
  });
3031
- const activateResult = await (0, import_sdk_core5.activateSessionWithHost)(
3777
+ const activateResult = await (0, import_sdk_core6.activateSessionWithHost)(
3032
3778
  targetHost,
3033
3779
  subDelegationSession.delegationHeader
3034
3780
  );
@@ -3064,7 +3810,7 @@ _TinyCloudNode.SESSION_EXPIRY_SAFETY_MARGIN_MS = 6e4;
3064
3810
  var TinyCloudNode = _TinyCloudNode;
3065
3811
 
3066
3812
  // src/core.ts
3067
- var import_sdk_core8 = require("@tinycloud/sdk-core");
3813
+ var import_sdk_core9 = require("@tinycloud/sdk-core");
3068
3814
 
3069
3815
  // src/delegation.ts
3070
3816
  function serializeDelegation(delegation) {
@@ -3083,7 +3829,6 @@ function deserializeDelegation(data) {
3083
3829
  }
3084
3830
 
3085
3831
  // src/core.ts
3086
- var import_sdk_core9 = require("@tinycloud/sdk-core");
3087
3832
  var import_sdk_core10 = require("@tinycloud/sdk-core");
3088
3833
  var import_sdk_core11 = require("@tinycloud/sdk-core");
3089
3834
  var import_sdk_core12 = require("@tinycloud/sdk-core");
@@ -3092,6 +3837,7 @@ var import_sdk_core14 = require("@tinycloud/sdk-core");
3092
3837
  var import_sdk_core15 = require("@tinycloud/sdk-core");
3093
3838
  var import_sdk_core16 = require("@tinycloud/sdk-core");
3094
3839
  var import_sdk_core17 = require("@tinycloud/sdk-core");
3840
+ var import_sdk_core18 = require("@tinycloud/sdk-core");
3095
3841
  // Annotate the CommonJS export names for ESM import in node:
3096
3842
  0 && (module.exports = {
3097
3843
  ACCOUNT_REGISTRY_PATH,
@@ -3117,8 +3863,10 @@ var import_sdk_core17 = require("@tinycloud/sdk-core");
3117
3863
  PermissionNotInManifestError,
3118
3864
  PrefixedKVService,
3119
3865
  ProtocolMismatchError,
3866
+ SECRET_NAME_RE,
3120
3867
  SQLAction,
3121
3868
  SQLService,
3869
+ SecretsService,
3122
3870
  ServiceContext,
3123
3871
  SessionExpiredError,
3124
3872
  SharingService,
@@ -3129,11 +3877,13 @@ var import_sdk_core17 = require("@tinycloud/sdk-core");
3129
3877
  TinyCloud,
3130
3878
  TinyCloudNode,
3131
3879
  UnsupportedFeatureError,
3880
+ VAULT_PERMISSION_SERVICE,
3132
3881
  VaultHeaders,
3133
3882
  VaultPublicSpaceKVActions,
3134
3883
  VersionCheckError,
3135
3884
  WasmKeyProvider,
3136
3885
  buildSpaceUri,
3886
+ canonicalizeSecretScope,
3137
3887
  checkNodeInfo,
3138
3888
  composeManifestRequest,
3139
3889
  createCapabilityKeyRegistry,
@@ -3145,12 +3895,15 @@ var import_sdk_core17 = require("@tinycloud/sdk-core");
3145
3895
  defaultSpaceCreationHandler,
3146
3896
  deserializeDelegation,
3147
3897
  expandActionShortNames,
3898
+ expandPermissionEntries,
3899
+ expandPermissionEntry,
3148
3900
  isCapabilitySubset,
3149
3901
  loadManifest,
3150
3902
  makePublicSpaceId,
3151
3903
  parseExpiry,
3152
3904
  parseSpaceUri,
3153
3905
  resolveManifest,
3906
+ resolveSecretPath,
3154
3907
  resourceCapabilitiesToSpaceAbilitiesMap,
3155
3908
  serializeDelegation,
3156
3909
  validateManifest