@tinycloud/node-sdk 2.2.0-beta.6 → 2.2.0-beta.8

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,71 @@ 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
+ SQLAction: () => import_sdk_core11.SQLAction,
47
+ SQLService: () => import_sdk_core11.SQLService,
48
+ SecretsService: () => import_sdk_core13.SecretsService,
49
+ ServiceContext: () => import_sdk_core18.ServiceContext,
50
+ SessionExpiredError: () => import_sdk_core9.SessionExpiredError,
51
+ SharingService: () => import_sdk_core14.SharingService,
52
+ SilentNotificationHandler: () => import_sdk_core8.SilentNotificationHandler,
53
+ Space: () => import_sdk_core16.Space,
54
+ SpaceErrorCodes: () => import_sdk_core16.SpaceErrorCodes,
55
+ SpaceService: () => import_sdk_core16.SpaceService,
56
+ TinyCloud: () => import_sdk_core7.TinyCloud,
56
57
  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,
58
+ UnsupportedFeatureError: () => import_sdk_core17.UnsupportedFeatureError,
59
+ VaultHeaders: () => import_sdk_core13.VaultHeaders,
60
+ VaultPublicSpaceKVActions: () => import_sdk_core13.VaultPublicSpaceKVActions,
61
+ VersionCheckError: () => import_sdk_core17.VersionCheckError,
61
62
  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,
63
+ buildSpaceUri: () => import_sdk_core16.buildSpaceUri,
64
+ checkNodeInfo: () => import_sdk_core17.checkNodeInfo,
65
+ composeManifestRequest: () => import_sdk_core9.composeManifestRequest,
66
+ createCapabilityKeyRegistry: () => import_sdk_core15.createCapabilityKeyRegistry,
67
+ createSharingService: () => import_sdk_core14.createSharingService,
68
+ createSpaceService: () => import_sdk_core16.createSpaceService,
69
+ createVaultCrypto: () => import_sdk_core13.createVaultCrypto,
69
70
  createWasmKeyProvider: () => createWasmKeyProvider,
70
71
  defaultSignStrategy: () => defaultSignStrategy,
71
- defaultSpaceCreationHandler: () => import_sdk_core7.defaultSpaceCreationHandler,
72
+ defaultSpaceCreationHandler: () => import_sdk_core8.defaultSpaceCreationHandler,
72
73
  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,
74
+ expandActionShortNames: () => import_sdk_core9.expandActionShortNames,
75
+ isCapabilitySubset: () => import_sdk_core9.isCapabilitySubset,
76
+ loadManifest: () => import_sdk_core9.loadManifest,
77
+ makePublicSpaceId: () => import_sdk_core16.makePublicSpaceId,
78
+ parseExpiry: () => import_sdk_core9.parseExpiry,
79
+ parseSpaceUri: () => import_sdk_core16.parseSpaceUri,
80
+ resolveManifest: () => import_sdk_core9.resolveManifest,
81
+ resourceCapabilitiesToSpaceAbilitiesMap: () => import_sdk_core9.resourceCapabilitiesToSpaceAbilitiesMap,
81
82
  serializeDelegation: () => serializeDelegation,
82
- validateManifest: () => import_sdk_core8.validateManifest
83
+ validateManifest: () => import_sdk_core9.validateManifest
83
84
  });
84
85
  module.exports = __toCommonJS(core_exports);
85
- var import_sdk_core6 = require("@tinycloud/sdk-core");
86
86
  var import_sdk_core7 = require("@tinycloud/sdk-core");
87
+ var import_sdk_core8 = require("@tinycloud/sdk-core");
87
88
 
88
89
  // src/storage/MemorySessionStorage.ts
89
90
  var MemorySessionStorage = class {
@@ -1019,7 +1020,7 @@ var NodeUserAuthorization = class {
1019
1020
  };
1020
1021
 
1021
1022
  // src/TinyCloudNode.ts
1022
- var import_sdk_core5 = require("@tinycloud/sdk-core");
1023
+ var import_sdk_core6 = require("@tinycloud/sdk-core");
1023
1024
 
1024
1025
  // src/DelegatedAccess.ts
1025
1026
  var import_sdk_core3 = require("@tinycloud/sdk-core");
@@ -1252,6 +1253,148 @@ function extractSiweExpiration(siwe) {
1252
1253
  return d;
1253
1254
  }
1254
1255
 
1256
+ // src/NodeSecretsService.ts
1257
+ var import_sdk_core5 = require("@tinycloud/sdk-core");
1258
+ var SECRET_NAME_RE = /^[A-Z][A-Z0-9_]*$/;
1259
+ var SECRET_PREFIX = "secrets/";
1260
+ var SECRETS_SPACE = "secrets";
1261
+ function ok() {
1262
+ return { ok: true, data: void 0 };
1263
+ }
1264
+ function secretsError(code, message, cause) {
1265
+ return {
1266
+ ok: false,
1267
+ error: {
1268
+ code,
1269
+ service: "secrets",
1270
+ message,
1271
+ ...cause ? { cause } : {}
1272
+ }
1273
+ };
1274
+ }
1275
+ function actionUrn(action) {
1276
+ return `tinycloud.kv/${action}`;
1277
+ }
1278
+ function secretResourcePath(base, name) {
1279
+ return `${base}/${SECRET_PREFIX}${name}`;
1280
+ }
1281
+ function secretPermissionEntries(name, action) {
1282
+ return [
1283
+ {
1284
+ service: "tinycloud.kv",
1285
+ space: SECRETS_SPACE,
1286
+ path: secretResourcePath("keys", name),
1287
+ actions: [action],
1288
+ skipPrefix: true
1289
+ },
1290
+ {
1291
+ service: "tinycloud.kv",
1292
+ space: SECRETS_SPACE,
1293
+ path: secretResourcePath("vault", name),
1294
+ actions: [action],
1295
+ skipPrefix: true
1296
+ }
1297
+ ];
1298
+ }
1299
+ function isSecretsSpace(space) {
1300
+ return space === SECRETS_SPACE || space.endsWith(`:${SECRETS_SPACE}`);
1301
+ }
1302
+ var NodeSecretsService = class {
1303
+ constructor(config) {
1304
+ this.config = config;
1305
+ this.shouldRestoreUnlock = false;
1306
+ }
1307
+ get vault() {
1308
+ return this.service.vault;
1309
+ }
1310
+ get isUnlocked() {
1311
+ return this.service.isUnlocked;
1312
+ }
1313
+ async unlock(signer) {
1314
+ const effectiveSigner = signer ?? this.config.getUnlockSigner?.();
1315
+ if (effectiveSigner !== void 0) {
1316
+ this.unlockSigner = effectiveSigner;
1317
+ }
1318
+ const result = await this.service.unlock(effectiveSigner);
1319
+ if (result.ok) {
1320
+ this.shouldRestoreUnlock = true;
1321
+ }
1322
+ return result;
1323
+ }
1324
+ lock() {
1325
+ this.shouldRestoreUnlock = false;
1326
+ this.service.lock();
1327
+ }
1328
+ get(name) {
1329
+ return this.service.get(name);
1330
+ }
1331
+ async put(name, value) {
1332
+ const permission = await this.ensureMutationPermission(name, "put");
1333
+ if (!permission.ok) return permission;
1334
+ return this.service.put(name, value);
1335
+ }
1336
+ async delete(name) {
1337
+ const permission = await this.ensureMutationPermission(name, "del");
1338
+ if (!permission.ok) return permission;
1339
+ return this.service.delete(name);
1340
+ }
1341
+ list() {
1342
+ return this.service.list();
1343
+ }
1344
+ get service() {
1345
+ return this.config.getService();
1346
+ }
1347
+ async ensureMutationPermission(name, action) {
1348
+ if (!SECRET_NAME_RE.test(name)) {
1349
+ return secretsError(
1350
+ import_sdk_core5.ErrorCodes.INVALID_INPUT,
1351
+ `Invalid secret name ${JSON.stringify(name)}. Secret names must match ${SECRET_NAME_RE.source}.`
1352
+ );
1353
+ }
1354
+ if (this.hasMutationPermission(name, action)) {
1355
+ return ok();
1356
+ }
1357
+ if (!this.config.canEscalate()) {
1358
+ return secretsError(
1359
+ import_sdk_core5.ErrorCodes.PERMISSION_DENIED,
1360
+ `Cannot autosign ${actionUrn(action)} for ${name}; TinyCloudNode needs wallet mode with a signer or privateKey.`
1361
+ );
1362
+ }
1363
+ try {
1364
+ await this.config.grantPermissions(secretPermissionEntries(name, action));
1365
+ return this.restoreUnlockAfterEscalation();
1366
+ } catch (error) {
1367
+ return secretsError(
1368
+ import_sdk_core5.ErrorCodes.PERMISSION_DENIED,
1369
+ error instanceof Error ? error.message : `Autosign escalation for ${actionUrn(action)} on ${name} failed.`,
1370
+ error instanceof Error ? error : void 0
1371
+ );
1372
+ }
1373
+ }
1374
+ async restoreUnlockAfterEscalation() {
1375
+ if (!this.shouldRestoreUnlock) {
1376
+ return ok();
1377
+ }
1378
+ return this.service.unlock(this.unlockSigner);
1379
+ }
1380
+ hasMutationPermission(name, action) {
1381
+ const manifest = this.config.getManifest();
1382
+ if (manifest === void 0) {
1383
+ return false;
1384
+ }
1385
+ const manifests = Array.isArray(manifest) ? manifest : [manifest];
1386
+ const requiredAction = actionUrn(action);
1387
+ return manifests.some((entry) => {
1388
+ const resolved = (0, import_sdk_core5.resolveManifest)(entry);
1389
+ return ["keys", "vault"].every(
1390
+ (base) => resolved.resources.some(
1391
+ (resource) => resource.service === "tinycloud.kv" && isSecretsSpace(resource.space) && resource.path === secretResourcePath(base, name) && resource.actions.includes(requiredAction)
1392
+ )
1393
+ );
1394
+ });
1395
+ }
1396
+ };
1397
+
1255
1398
  // src/TinyCloudNode.ts
1256
1399
  var DEFAULT_HOST = "https://node.tinycloud.xyz";
1257
1400
  var _TinyCloudNode = class _TinyCloudNode {
@@ -1283,6 +1426,30 @@ var _TinyCloudNode = class _TinyCloudNode {
1283
1426
  this.auth = null;
1284
1427
  this.tc = null;
1285
1428
  this._chainId = 1;
1429
+ this.runtimePermissionGrants = [];
1430
+ this.invokeWithRuntimePermissions = (session, service, path, action, facts) => {
1431
+ return this.wasmBindings.invoke(
1432
+ this.selectInvocationSession(session, service, path, action),
1433
+ service,
1434
+ path,
1435
+ action,
1436
+ facts
1437
+ );
1438
+ };
1439
+ this.invokeAnyWithRuntimePermissions = (session, entries, facts) => {
1440
+ if (!this.wasmBindings.invokeAny) {
1441
+ throw new Error("WASM binding does not support invokeAny");
1442
+ }
1443
+ const grant = this.findGrantForOperations(
1444
+ entries.map((entry) => ({
1445
+ spaceId: entry.spaceId,
1446
+ service: this.invocationServiceName(entry.service),
1447
+ path: entry.path,
1448
+ action: entry.action
1449
+ }))
1450
+ );
1451
+ return this.wasmBindings.invokeAny(grant?.session ?? session, entries, facts);
1452
+ };
1286
1453
  this.explicitHost = config.host;
1287
1454
  this.config = {
1288
1455
  ...config,
@@ -1310,23 +1477,23 @@ var _TinyCloudNode = class _TinyCloudNode {
1310
1477
  throw new Error("Failed to get session key JWK");
1311
1478
  }
1312
1479
  this.sessionKeyJwk = JSON.parse(jwkStr);
1313
- this._capabilityRegistry = new import_sdk_core5.CapabilityKeyRegistry();
1480
+ this._capabilityRegistry = new import_sdk_core6.CapabilityKeyRegistry();
1314
1481
  this._keyProvider = new WasmKeyProvider({
1315
1482
  sessionManager: this.sessionManager
1316
1483
  });
1317
- this.notificationHandler = config.notificationHandler ?? new import_sdk_core5.SilentNotificationHandler();
1318
- this._sharingService = new import_sdk_core5.SharingService({
1484
+ this.notificationHandler = config.notificationHandler ?? new import_sdk_core6.SilentNotificationHandler();
1485
+ this._sharingService = new import_sdk_core6.SharingService({
1319
1486
  hosts: [this.config.host],
1320
1487
  // session: undefined - not needed for receive()
1321
- invoke: this.wasmBindings.invoke,
1488
+ invoke: this.invokeWithRuntimePermissions,
1322
1489
  fetch: globalThis.fetch.bind(globalThis),
1323
1490
  keyProvider: this._keyProvider,
1324
1491
  registry: this._capabilityRegistry,
1325
1492
  // delegationManager: undefined - not needed for receive()
1326
1493
  createKVService: (config2) => {
1327
1494
  const prefix = config2.pathPrefix?.replace(/\/$/, "");
1328
- const kvService = new import_sdk_core5.KVService({ prefix });
1329
- const kvContext = new import_sdk_core5.ServiceContext({
1495
+ const kvService = new import_sdk_core6.KVService({ prefix });
1496
+ const kvContext = new import_sdk_core6.ServiceContext({
1330
1497
  invoke: config2.invoke,
1331
1498
  fetch: config2.fetch ?? globalThis.fetch.bind(globalThis),
1332
1499
  hosts: config2.hosts
@@ -1385,8 +1552,8 @@ var _TinyCloudNode = class _TinyCloudNode {
1385
1552
  capabilityRequest: config.capabilityRequest,
1386
1553
  includeAccountRegistryPermissions: config.includeAccountRegistryPermissions
1387
1554
  });
1388
- this.tc = new import_sdk_core5.TinyCloud(this.auth, {
1389
- invokeAny: this.wasmBindings.invokeAny
1555
+ this.tc = new import_sdk_core6.TinyCloud(this.auth, {
1556
+ invokeAny: this.invokeAnyWithRuntimePermissions
1390
1557
  });
1391
1558
  }
1392
1559
  syncResolvedHostFromAuth() {
@@ -1506,7 +1673,12 @@ var _TinyCloudNode = class _TinyCloudNode {
1506
1673
  this._sql = void 0;
1507
1674
  this._duckdb = void 0;
1508
1675
  this._hooks = void 0;
1676
+ this._vault = void 0;
1677
+ this._baseSecrets = void 0;
1678
+ this._secrets = void 0;
1679
+ this._spaceService = void 0;
1509
1680
  this._serviceContext = void 0;
1681
+ this.runtimePermissionGrants = [];
1510
1682
  await this.tc.signIn(options);
1511
1683
  this.syncResolvedHostFromAuth();
1512
1684
  this.initializeServices();
@@ -1527,7 +1699,7 @@ var _TinyCloudNode = class _TinyCloudNode {
1527
1699
  if (!this.auth || !this.signer) {
1528
1700
  throw new Error("Manifest registry write requires wallet mode");
1529
1701
  }
1530
- const accountSpaceId = this.ownedSpaceId(import_sdk_core5.ACCOUNT_REGISTRY_SPACE);
1702
+ const accountSpaceId = this.ownedSpaceId(import_sdk_core6.ACCOUNT_REGISTRY_SPACE);
1531
1703
  await this.ensureOwnedSpaceHosted(accountSpaceId);
1532
1704
  const accountKV = this.spaces.get(accountSpaceId).kv;
1533
1705
  for (const record of request.registryRecords) {
@@ -1555,7 +1727,7 @@ var _TinyCloudNode = class _TinyCloudNode {
1555
1727
  if (!host) {
1556
1728
  throw new Error("Owned space hosting requires a TinyCloud host");
1557
1729
  }
1558
- const activation = await (0, import_sdk_core5.activateSessionWithHost)(host, session.delegationHeader);
1730
+ const activation = await (0, import_sdk_core6.activateSessionWithHost)(host, session.delegationHeader);
1559
1731
  if (activation.success && !activation.skipped?.includes(spaceId)) {
1560
1732
  return;
1561
1733
  }
@@ -1569,7 +1741,7 @@ var _TinyCloudNode = class _TinyCloudNode {
1569
1741
  throw new Error(`Failed to create owned space: ${spaceId}`);
1570
1742
  }
1571
1743
  await new Promise((resolve) => setTimeout(resolve, 100));
1572
- const retry = await (0, import_sdk_core5.activateSessionWithHost)(host, session.delegationHeader);
1744
+ const retry = await (0, import_sdk_core6.activateSessionWithHost)(host, session.delegationHeader);
1573
1745
  if (!retry.success || retry.skipped?.includes(spaceId)) {
1574
1746
  throw new Error(
1575
1747
  `Failed to activate session after creating owned space ${spaceId}: ${retry.error ?? "space was skipped"}`
@@ -1591,29 +1763,34 @@ var _TinyCloudNode = class _TinyCloudNode {
1591
1763
  this._sql = void 0;
1592
1764
  this._duckdb = void 0;
1593
1765
  this._hooks = void 0;
1766
+ this._vault = void 0;
1767
+ this._baseSecrets = void 0;
1768
+ this._secrets = void 0;
1769
+ this._spaceService = void 0;
1594
1770
  this._serviceContext = void 0;
1771
+ this.runtimePermissionGrants = [];
1595
1772
  if (sessionData.address) {
1596
1773
  this._address = sessionData.address;
1597
1774
  }
1598
1775
  if (sessionData.chainId) {
1599
1776
  this._chainId = sessionData.chainId;
1600
1777
  }
1601
- this._serviceContext = new import_sdk_core5.ServiceContext({
1602
- invoke: this.wasmBindings.invoke,
1603
- invokeAny: this.wasmBindings.invokeAny,
1778
+ this._serviceContext = new import_sdk_core6.ServiceContext({
1779
+ invoke: this.invokeWithRuntimePermissions,
1780
+ invokeAny: this.invokeAnyWithRuntimePermissions,
1604
1781
  fetch: globalThis.fetch.bind(globalThis),
1605
1782
  hosts: [this.config.host]
1606
1783
  });
1607
- this._kv = new import_sdk_core5.KVService({});
1784
+ this._kv = new import_sdk_core6.KVService({});
1608
1785
  this._kv.initialize(this._serviceContext);
1609
1786
  this._serviceContext.registerService("kv", this._kv);
1610
- this._sql = new import_sdk_core5.SQLService({});
1787
+ this._sql = new import_sdk_core6.SQLService({});
1611
1788
  this._sql.initialize(this._serviceContext);
1612
1789
  this._serviceContext.registerService("sql", this._sql);
1613
- this._duckdb = new import_sdk_core5.DuckDbService({});
1790
+ this._duckdb = new import_sdk_core6.DuckDbService({});
1614
1791
  this._duckdb.initialize(this._serviceContext);
1615
1792
  this._serviceContext.registerService("duckdb", this._duckdb);
1616
- this._hooks = new import_sdk_core5.HooksService({});
1793
+ this._hooks = new import_sdk_core6.HooksService({});
1617
1794
  this._hooks.initialize(this._serviceContext);
1618
1795
  this._serviceContext.registerService("hooks", this._hooks);
1619
1796
  const serviceSession = {
@@ -1624,41 +1801,7 @@ var _TinyCloudNode = class _TinyCloudNode {
1624
1801
  jwk: sessionData.jwk
1625
1802
  };
1626
1803
  this._serviceContext.setSession(serviceSession);
1627
- const wasm = this.wasmBindings;
1628
- const vaultCrypto = (0, import_sdk_core5.createVaultCrypto)({
1629
- vault_encrypt: wasm.vault_encrypt,
1630
- vault_decrypt: wasm.vault_decrypt,
1631
- vault_derive_key: wasm.vault_derive_key,
1632
- vault_x25519_from_seed: wasm.vault_x25519_from_seed,
1633
- vault_x25519_dh: wasm.vault_x25519_dh,
1634
- vault_random_bytes: wasm.vault_random_bytes,
1635
- vault_sha256: wasm.vault_sha256
1636
- });
1637
- const self = this;
1638
- this._vault = new import_sdk_core5.DataVaultService({
1639
- spaceId: sessionData.spaceId,
1640
- crypto: vaultCrypto,
1641
- tc: {
1642
- kv: this._kv,
1643
- ensurePublicSpace: async () => {
1644
- try {
1645
- await self.ensurePublicSpace();
1646
- return { ok: true, data: void 0 };
1647
- } catch (error) {
1648
- return { ok: false, error: { code: "STORAGE_ERROR", message: error instanceof Error ? error.message : String(error), service: "vault" } };
1649
- }
1650
- },
1651
- get publicKV() {
1652
- return self._publicKV ?? self.tc.publicKV;
1653
- },
1654
- readPublicSpace: (host, spaceId, key) => import_sdk_core5.TinyCloud.readPublicSpace(host, spaceId, key),
1655
- makePublicSpaceId: import_sdk_core5.TinyCloud.makePublicSpaceId,
1656
- did: this.did,
1657
- address: sessionData.address ?? this._address ?? "",
1658
- chainId: sessionData.chainId ?? this._chainId,
1659
- hosts: [this.config.host]
1660
- }
1661
- });
1804
+ this._vault = this.createVaultService(sessionData.spaceId, this._kv);
1662
1805
  this._vault.initialize(this._serviceContext);
1663
1806
  this._serviceContext.registerService("vault", this._vault);
1664
1807
  this.initializeV2Services(serviceSession);
@@ -1719,8 +1862,8 @@ var _TinyCloudNode = class _TinyCloudNode {
1719
1862
  capabilityRequest: this.config.capabilityRequest,
1720
1863
  includeAccountRegistryPermissions: this.config.includeAccountRegistryPermissions
1721
1864
  });
1722
- this.tc = new import_sdk_core5.TinyCloud(this.auth, {
1723
- invokeAny: this.wasmBindings.invokeAny
1865
+ this.tc = new import_sdk_core6.TinyCloud(this.auth, {
1866
+ invokeAny: this.invokeAnyWithRuntimePermissions
1724
1867
  });
1725
1868
  this.config.prefix = prefix;
1726
1869
  }
@@ -1763,8 +1906,8 @@ var _TinyCloudNode = class _TinyCloudNode {
1763
1906
  capabilityRequest: this.config.capabilityRequest,
1764
1907
  includeAccountRegistryPermissions: this.config.includeAccountRegistryPermissions
1765
1908
  });
1766
- this.tc = new import_sdk_core5.TinyCloud(this.auth, {
1767
- invokeAny: this.wasmBindings.invokeAny
1909
+ this.tc = new import_sdk_core6.TinyCloud(this.auth, {
1910
+ invokeAny: this.invokeAnyWithRuntimePermissions
1768
1911
  });
1769
1912
  this.config.prefix = prefix;
1770
1913
  }
@@ -1777,28 +1920,28 @@ var _TinyCloudNode = class _TinyCloudNode {
1777
1920
  if (!session) {
1778
1921
  return;
1779
1922
  }
1780
- this.tc.initializeServices(this.wasmBindings.invoke, [this.config.host]);
1781
- this._serviceContext = new import_sdk_core5.ServiceContext({
1782
- invoke: this.wasmBindings.invoke,
1783
- invokeAny: this.wasmBindings.invokeAny,
1923
+ this.tc.initializeServices(this.invokeWithRuntimePermissions, [this.config.host]);
1924
+ this._serviceContext = new import_sdk_core6.ServiceContext({
1925
+ invoke: this.invokeWithRuntimePermissions,
1926
+ invokeAny: this.invokeAnyWithRuntimePermissions,
1784
1927
  fetch: globalThis.fetch.bind(globalThis),
1785
1928
  hosts: [this.config.host]
1786
1929
  });
1787
- this._kv = new import_sdk_core5.KVService({});
1930
+ this._kv = new import_sdk_core6.KVService({});
1788
1931
  this._kv.initialize(this._serviceContext);
1789
1932
  this._serviceContext.registerService("kv", this._kv);
1790
1933
  const features = this.nodeFeatures;
1791
1934
  if (features.length === 0 || features.includes("sql")) {
1792
- this._sql = new import_sdk_core5.SQLService({});
1935
+ this._sql = new import_sdk_core6.SQLService({});
1793
1936
  this._sql.initialize(this._serviceContext);
1794
1937
  this._serviceContext.registerService("sql", this._sql);
1795
1938
  }
1796
1939
  if (features.length === 0 || features.includes("duckdb")) {
1797
- this._duckdb = new import_sdk_core5.DuckDbService({});
1940
+ this._duckdb = new import_sdk_core6.DuckDbService({});
1798
1941
  this._duckdb.initialize(this._serviceContext);
1799
1942
  this._serviceContext.registerService("duckdb", this._duckdb);
1800
1943
  }
1801
- this._hooks = new import_sdk_core5.HooksService({});
1944
+ this._hooks = new import_sdk_core6.HooksService({});
1802
1945
  this._hooks.initialize(this._serviceContext);
1803
1946
  this._serviceContext.registerService("hooks", this._hooks);
1804
1947
  const serviceSession = {
@@ -1810,8 +1953,30 @@ var _TinyCloudNode = class _TinyCloudNode {
1810
1953
  };
1811
1954
  this._serviceContext.setSession(serviceSession);
1812
1955
  this.tc.serviceContext.setSession(serviceSession);
1956
+ this._vault = this.createVaultService(session.spaceId, this._kv);
1957
+ this._vault.initialize(this._serviceContext);
1958
+ this._serviceContext.registerService("vault", this._vault);
1959
+ this.initializeV2Services(serviceSession);
1960
+ }
1961
+ createSpaceScopedKVService(spaceId) {
1962
+ const kvService = new import_sdk_core6.KVService({});
1963
+ if (this._serviceContext) {
1964
+ const spaceScopedContext = new import_sdk_core6.ServiceContext({
1965
+ invoke: this._serviceContext.invoke,
1966
+ fetch: this._serviceContext.fetch,
1967
+ hosts: this._serviceContext.hosts
1968
+ });
1969
+ const session = this._serviceContext.session;
1970
+ if (session) {
1971
+ spaceScopedContext.setSession({ ...session, spaceId });
1972
+ }
1973
+ kvService.initialize(spaceScopedContext);
1974
+ }
1975
+ return kvService;
1976
+ }
1977
+ createVaultService(spaceId, kv) {
1813
1978
  const wasm = this.wasmBindings;
1814
- const vaultCrypto = (0, import_sdk_core5.createVaultCrypto)({
1979
+ const vaultCrypto = (0, import_sdk_core6.createVaultCrypto)({
1815
1980
  vault_encrypt: wasm.vault_encrypt,
1816
1981
  vault_decrypt: wasm.vault_decrypt,
1817
1982
  vault_derive_key: wasm.vault_derive_key,
@@ -1821,11 +1986,11 @@ var _TinyCloudNode = class _TinyCloudNode {
1821
1986
  vault_sha256: wasm.vault_sha256
1822
1987
  });
1823
1988
  const self = this;
1824
- this._vault = new import_sdk_core5.DataVaultService({
1825
- spaceId: session.spaceId,
1989
+ return new import_sdk_core6.DataVaultService({
1990
+ spaceId,
1826
1991
  crypto: vaultCrypto,
1827
1992
  tc: {
1828
- kv: this._kv,
1993
+ kv,
1829
1994
  ensurePublicSpace: async () => {
1830
1995
  try {
1831
1996
  await self.ensurePublicSpace();
@@ -1837,24 +2002,21 @@ var _TinyCloudNode = class _TinyCloudNode {
1837
2002
  get publicKV() {
1838
2003
  return self._publicKV ?? self.tc.publicKV;
1839
2004
  },
1840
- readPublicSpace: (host, spaceId, key) => import_sdk_core5.TinyCloud.readPublicSpace(host, spaceId, key),
1841
- makePublicSpaceId: import_sdk_core5.TinyCloud.makePublicSpaceId,
2005
+ readPublicSpace: (host, targetSpaceId, key) => import_sdk_core6.TinyCloud.readPublicSpace(host, targetSpaceId, key),
2006
+ makePublicSpaceId: import_sdk_core6.TinyCloud.makePublicSpaceId,
1842
2007
  did: this.did,
1843
- address: this._address,
2008
+ address: this._address ?? "",
1844
2009
  chainId: this._chainId,
1845
2010
  hosts: [this.config.host]
1846
2011
  }
1847
2012
  });
1848
- this._vault.initialize(this._serviceContext);
1849
- this._serviceContext.registerService("vault", this._vault);
1850
- this.initializeV2Services(serviceSession);
1851
2013
  }
1852
2014
  /**
1853
2015
  * Initialize the v2 delegation system services.
1854
2016
  * @internal
1855
2017
  */
1856
2018
  initializeV2Services(serviceSession) {
1857
- this._capabilityRegistry = new import_sdk_core5.CapabilityKeyRegistry();
2019
+ this._capabilityRegistry = new import_sdk_core6.CapabilityKeyRegistry();
1858
2020
  const tcSession = this.auth?.tinyCloudSession;
1859
2021
  if (tcSession && this._address) {
1860
2022
  const sessionKey = {
@@ -1928,13 +2090,13 @@ var _TinyCloudNode = class _TinyCloudNode {
1928
2090
  }
1929
2091
  this._capabilityRegistry.registerKey(sessionKey, delegations);
1930
2092
  }
1931
- this._delegationManager = new import_sdk_core5.DelegationManager({
2093
+ this._delegationManager = new import_sdk_core6.DelegationManager({
1932
2094
  hosts: [this.config.host],
1933
2095
  session: serviceSession,
1934
- invoke: this.wasmBindings.invoke,
2096
+ invoke: this.invokeWithRuntimePermissions,
1935
2097
  fetch: globalThis.fetch.bind(globalThis)
1936
2098
  });
1937
- this._spaceService = new import_sdk_core5.SpaceService({
2099
+ this._spaceService = new import_sdk_core6.SpaceService({
1938
2100
  hosts: [this.config.host],
1939
2101
  session: serviceSession,
1940
2102
  invoke: this.wasmBindings.invoke,
@@ -1942,20 +2104,15 @@ var _TinyCloudNode = class _TinyCloudNode {
1942
2104
  capabilityRegistry: this._capabilityRegistry,
1943
2105
  userDid: this.did,
1944
2106
  createKVService: (spaceId) => {
1945
- const kvService = new import_sdk_core5.KVService({});
2107
+ return this.createSpaceScopedKVService(spaceId);
2108
+ },
2109
+ createVaultService: (spaceId) => {
2110
+ const kvService = this.createSpaceScopedKVService(spaceId);
2111
+ const vaultService = this.createVaultService(spaceId, kvService);
1946
2112
  if (this._serviceContext) {
1947
- const spaceScopedContext = new import_sdk_core5.ServiceContext({
1948
- invoke: this._serviceContext.invoke,
1949
- fetch: this._serviceContext.fetch,
1950
- hosts: this._serviceContext.hosts
1951
- });
1952
- const session = this._serviceContext.session;
1953
- if (session) {
1954
- spaceScopedContext.setSession({ ...session, spaceId });
1955
- }
1956
- kvService.initialize(spaceScopedContext);
2113
+ vaultService.initialize(this._serviceContext);
1957
2114
  }
1958
- return kvService;
2115
+ return vaultService;
1959
2116
  },
1960
2117
  // Enable space.delegations.create() via SIWE-based delegation
1961
2118
  createDelegation: async (params) => {
@@ -2096,7 +2253,7 @@ var _TinyCloudNode = class _TinyCloudNode {
2096
2253
  ...prepared,
2097
2254
  signature
2098
2255
  });
2099
- const activateResult = await (0, import_sdk_core5.activateSessionWithHost)(
2256
+ const activateResult = await (0, import_sdk_core6.activateSessionWithHost)(
2100
2257
  host,
2101
2258
  delegationSession.delegationHeader
2102
2259
  );
@@ -2163,7 +2320,7 @@ var _TinyCloudNode = class _TinyCloudNode {
2163
2320
  if (!this._sql) {
2164
2321
  const features = this.nodeFeatures;
2165
2322
  if (features.length > 0 && !features.includes("sql")) {
2166
- throw new import_sdk_core5.UnsupportedFeatureError("sql", this.config.host, features);
2323
+ throw new import_sdk_core6.UnsupportedFeatureError("sql", this.config.host, features);
2167
2324
  }
2168
2325
  throw new Error("Not signed in. Call signIn() first.");
2169
2326
  }
@@ -2176,7 +2333,7 @@ var _TinyCloudNode = class _TinyCloudNode {
2176
2333
  if (!this._duckdb) {
2177
2334
  const features = this.nodeFeatures;
2178
2335
  if (features.length > 0 && !features.includes("duckdb")) {
2179
- throw new import_sdk_core5.UnsupportedFeatureError("duckdb", this.config.host, features);
2336
+ throw new import_sdk_core6.UnsupportedFeatureError("duckdb", this.config.host, features);
2180
2337
  }
2181
2338
  throw new Error("Not signed in. Call signIn() first.");
2182
2339
  }
@@ -2192,6 +2349,33 @@ var _TinyCloudNode = class _TinyCloudNode {
2192
2349
  }
2193
2350
  return this._vault;
2194
2351
  }
2352
+ /**
2353
+ * App-facing secrets API backed by the `secrets` space vault.
2354
+ */
2355
+ get secrets() {
2356
+ if (!this._spaceService) {
2357
+ throw new Error("Not signed in. Call signIn() first.");
2358
+ }
2359
+ if (!this._secrets) {
2360
+ this._secrets = new NodeSecretsService({
2361
+ getService: () => this.getBaseSecrets(),
2362
+ getManifest: () => this.manifest,
2363
+ grantPermissions: (additional) => this.grantRuntimePermissions(additional),
2364
+ canEscalate: () => this.signer !== void 0 && this.tc !== void 0,
2365
+ getUnlockSigner: () => this.signer ?? void 0
2366
+ });
2367
+ }
2368
+ return this._secrets;
2369
+ }
2370
+ getBaseSecrets() {
2371
+ if (!this._spaceService) {
2372
+ throw new Error("Not signed in. Call signIn() first.");
2373
+ }
2374
+ if (!this._baseSecrets) {
2375
+ this._baseSecrets = new import_sdk_core6.SecretsService(() => this.space("secrets").vault);
2376
+ }
2377
+ return this._baseSecrets;
2378
+ }
2195
2379
  /**
2196
2380
  * Hooks write stream subscription API.
2197
2381
  */
@@ -2262,6 +2446,171 @@ var _TinyCloudNode = class _TinyCloudNode {
2262
2446
  }
2263
2447
  };
2264
2448
  }
2449
+ /**
2450
+ * Check whether the current session or an approved runtime delegation covers
2451
+ * every requested permission.
2452
+ */
2453
+ hasRuntimePermissions(permissions) {
2454
+ const session = this.auth?.tinyCloudSession;
2455
+ if (!session || !Array.isArray(permissions) || permissions.length === 0) {
2456
+ return false;
2457
+ }
2458
+ const expanded = this.expandPermissionEntries(permissions);
2459
+ if (this.sessionCoversPermissionEntries(session, expanded)) {
2460
+ return true;
2461
+ }
2462
+ return this.findRuntimeGrantsForPermissionEntries(expanded, session).length > 0;
2463
+ }
2464
+ /**
2465
+ * Return installed runtime permission delegations. When `permissions` is
2466
+ * provided, only delegations currently covering those permissions are
2467
+ * returned. Base-session manifest permissions are not represented here.
2468
+ */
2469
+ getRuntimePermissionDelegations(permissions) {
2470
+ this.pruneExpiredRuntimePermissionGrants();
2471
+ if (permissions === void 0) {
2472
+ return this.runtimePermissionGrants.map((grant) => grant.delegation);
2473
+ }
2474
+ const session = this.auth?.tinyCloudSession;
2475
+ if (!session || !Array.isArray(permissions) || permissions.length === 0) {
2476
+ return [];
2477
+ }
2478
+ const expanded = this.expandPermissionEntries(permissions);
2479
+ return this.findRuntimeGrantsForPermissionEntries(expanded, session).map(
2480
+ (grant) => grant.delegation
2481
+ );
2482
+ }
2483
+ /**
2484
+ * Install a portable runtime permission delegation into this SDK instance so
2485
+ * matching service calls and downstream `delegateTo()` calls can use it.
2486
+ */
2487
+ async useRuntimeDelegation(delegation) {
2488
+ const session = this.auth?.tinyCloudSession;
2489
+ if (!session) {
2490
+ throw new import_sdk_core6.SessionExpiredError(/* @__PURE__ */ new Date(0));
2491
+ }
2492
+ if (delegation.expiry.getTime() <= Date.now()) {
2493
+ throw new import_sdk_core6.SessionExpiredError(delegation.expiry);
2494
+ }
2495
+ const expectedDids = /* @__PURE__ */ new Set([session.verificationMethod, this.sessionDid]);
2496
+ if (!expectedDids.has(delegation.delegateDID)) {
2497
+ throw new Error(
2498
+ `Runtime delegation targets ${delegation.delegateDID} but this session key is ${session.verificationMethod}.`
2499
+ );
2500
+ }
2501
+ const targetHost = delegation.host ?? this.config.host;
2502
+ const activateResult = await (0, import_sdk_core6.activateSessionWithHost)(
2503
+ targetHost,
2504
+ delegation.delegationHeader
2505
+ );
2506
+ if (!activateResult.success) {
2507
+ throw new Error(
2508
+ `Failed to activate runtime permission delegation: ${activateResult.error}`
2509
+ );
2510
+ }
2511
+ this.runtimePermissionGrants = this.runtimePermissionGrants.filter(
2512
+ (grant) => grant.delegation.cid !== delegation.cid
2513
+ );
2514
+ this.runtimePermissionGrants.push(
2515
+ this.runtimeGrantFromDelegation(delegation, session)
2516
+ );
2517
+ }
2518
+ /**
2519
+ * Store additional permissions as narrow delegations to the current session
2520
+ * key. Future service invocations automatically use a stored delegation when
2521
+ * its `(space, service, path, action)` covers the request.
2522
+ */
2523
+ async grantRuntimePermissions(permissions, options) {
2524
+ if (!Array.isArray(permissions) || permissions.length === 0) {
2525
+ throw new Error("grantRuntimePermissions requires a non-empty permissions array");
2526
+ }
2527
+ const session = this.auth?.tinyCloudSession;
2528
+ if (!session) {
2529
+ throw new import_sdk_core6.SessionExpiredError(/* @__PURE__ */ new Date(0));
2530
+ }
2531
+ const sessionExpiry = extractSiweExpiration(session.siwe);
2532
+ if (sessionExpiry !== void 0) {
2533
+ const marginMs = _TinyCloudNode.SESSION_EXPIRY_SAFETY_MARGIN_MS;
2534
+ if (sessionExpiry.getTime() <= Date.now() + marginMs) {
2535
+ throw new import_sdk_core6.SessionExpiredError(sessionExpiry);
2536
+ }
2537
+ }
2538
+ const expanded = this.expandPermissionEntries(permissions);
2539
+ if (this.sessionCoversPermissionEntries(session, expanded)) {
2540
+ return [];
2541
+ }
2542
+ const existingGrants = this.findRuntimeGrantsForPermissionEntries(expanded, session);
2543
+ if (existingGrants.length > 0) {
2544
+ return existingGrants.map((grant) => grant.delegation);
2545
+ }
2546
+ if (!this.signer) {
2547
+ throw new Error(
2548
+ "grantRuntimePermissions requires wallet mode with a signer or privateKey."
2549
+ );
2550
+ }
2551
+ const bySpace = /* @__PURE__ */ new Map();
2552
+ for (const entry of expanded) {
2553
+ const spaceId = this.resolvePermissionSpace(entry.space, session);
2554
+ const current = bySpace.get(spaceId) ?? [];
2555
+ current.push(entry);
2556
+ bySpace.set(spaceId, current);
2557
+ }
2558
+ const now = /* @__PURE__ */ new Date();
2559
+ const requestedExpiryMs = resolveExpiryMs(options?.expiry);
2560
+ let expiresAt = new Date(now.getTime() + requestedExpiryMs);
2561
+ if (sessionExpiry !== void 0 && sessionExpiry < expiresAt) {
2562
+ expiresAt = sessionExpiry;
2563
+ }
2564
+ const delegations = [];
2565
+ for (const [spaceId, entries] of bySpace) {
2566
+ const abilities = this.permissionsToAbilities(entries);
2567
+ const prepared = this.wasmBindings.prepareSession({
2568
+ abilities,
2569
+ address: this.wasmBindings.ensureEip55(session.address),
2570
+ chainId: session.chainId,
2571
+ domain: this.siweDomain,
2572
+ issuedAt: now.toISOString(),
2573
+ expirationTime: expiresAt.toISOString(),
2574
+ spaceId,
2575
+ jwk: session.jwk
2576
+ });
2577
+ const signature = await this.signer.signMessage(prepared.siwe);
2578
+ const delegatedSession = this.wasmBindings.completeSessionSetup({
2579
+ ...prepared,
2580
+ signature
2581
+ });
2582
+ const activateResult = await (0, import_sdk_core6.activateSessionWithHost)(
2583
+ this.config.host,
2584
+ delegatedSession.delegationHeader
2585
+ );
2586
+ if (!activateResult.success) {
2587
+ throw new Error(
2588
+ `Failed to activate runtime permission delegation: ${activateResult.error}`
2589
+ );
2590
+ }
2591
+ const delegation = this.runtimeDelegationFromSession(
2592
+ delegatedSession,
2593
+ entries,
2594
+ spaceId,
2595
+ session,
2596
+ expiresAt
2597
+ );
2598
+ this.runtimePermissionGrants.push({
2599
+ session: {
2600
+ delegationHeader: delegatedSession.delegationHeader,
2601
+ delegationCid: delegatedSession.delegationCid,
2602
+ spaceId,
2603
+ verificationMethod: session.verificationMethod,
2604
+ jwk: session.jwk
2605
+ },
2606
+ delegation,
2607
+ operations: this.permissionOperations(entries, spaceId),
2608
+ expiresAt
2609
+ });
2610
+ delegations.push(delegation);
2611
+ }
2612
+ return delegations;
2613
+ }
2265
2614
  /**
2266
2615
  * Get the DelegationManager for delegation CRUD operations.
2267
2616
  *
@@ -2330,6 +2679,12 @@ var _TinyCloudNode = class _TinyCloudNode {
2330
2679
  get spaceService() {
2331
2680
  return this.spaces;
2332
2681
  }
2682
+ /**
2683
+ * Get a Space object by short name or full URI.
2684
+ */
2685
+ space(nameOrUri) {
2686
+ return this.spaces.get(nameOrUri);
2687
+ }
2333
2688
  /**
2334
2689
  * Get the SharingService for creating and receiving v2 sharing links.
2335
2690
  *
@@ -2415,7 +2770,7 @@ var _TinyCloudNode = class _TinyCloudNode {
2415
2770
  ...prepared,
2416
2771
  signature
2417
2772
  });
2418
- const activateResult = await (0, import_sdk_core5.activateSessionWithHost)(
2773
+ const activateResult = await (0, import_sdk_core6.activateSessionWithHost)(
2419
2774
  this.config.host,
2420
2775
  delegationSession.delegationHeader
2421
2776
  );
@@ -2442,9 +2797,9 @@ var _TinyCloudNode = class _TinyCloudNode {
2442
2797
  }]);
2443
2798
  }
2444
2799
  if (this._serviceContext) {
2445
- const publicKV = new import_sdk_core5.KVService({ prefix: "" });
2446
- const publicContext = new import_sdk_core5.ServiceContext({
2447
- invoke: this.wasmBindings.invoke,
2800
+ const publicKV = new import_sdk_core6.KVService({ prefix: "" });
2801
+ const publicContext = new import_sdk_core6.ServiceContext({
2802
+ invoke: this.invokeWithRuntimePermissions,
2448
2803
  fetch: this._serviceContext.fetch,
2449
2804
  hosts: this._serviceContext.hosts
2450
2805
  });
@@ -2532,8 +2887,9 @@ var _TinyCloudNode = class _TinyCloudNode {
2532
2887
  * Issue a delegation using the capability-chain flow.
2533
2888
  *
2534
2889
  * When every requested permission is a subset of the current
2535
- * session's recap, the delegation is signed by the session key via
2536
- * WASM no wallet prompt. When at least one is NOT derivable, a
2890
+ * session's recap, or of one installed runtime permission delegation,
2891
+ * the delegation is signed by the session key via WASM no wallet
2892
+ * prompt. When at least one is NOT derivable, a
2537
2893
  * {@link PermissionNotInManifestError} is raised (carrying the
2538
2894
  * missing entries) so the caller can trigger an escalation flow
2539
2895
  * (e.g. `TinyCloudWeb.requestPermissions`). Passing
@@ -2568,14 +2924,14 @@ var _TinyCloudNode = class _TinyCloudNode {
2568
2924
  async delegateTo(did, permissions, options) {
2569
2925
  const session = this.auth?.tinyCloudSession;
2570
2926
  if (!session) {
2571
- throw new import_sdk_core5.SessionExpiredError(/* @__PURE__ */ new Date(0));
2927
+ throw new import_sdk_core6.SessionExpiredError(/* @__PURE__ */ new Date(0));
2572
2928
  }
2573
2929
  const sessionExpiry = extractSiweExpiration(session.siwe);
2574
2930
  if (sessionExpiry !== void 0) {
2575
2931
  const now2 = Date.now();
2576
2932
  const marginMs = _TinyCloudNode.SESSION_EXPIRY_SAFETY_MARGIN_MS;
2577
2933
  if (sessionExpiry.getTime() <= now2 + marginMs) {
2578
- throw new import_sdk_core5.SessionExpiredError(sessionExpiry);
2934
+ throw new import_sdk_core6.SessionExpiredError(sessionExpiry);
2579
2935
  }
2580
2936
  }
2581
2937
  if (!Array.isArray(permissions) || permissions.length === 0) {
@@ -2585,7 +2941,7 @@ var _TinyCloudNode = class _TinyCloudNode {
2585
2941
  }
2586
2942
  const expandedEntries = permissions.map((entry) => ({
2587
2943
  ...entry,
2588
- actions: (0, import_sdk_core5.expandActionShortNames)(entry.service, entry.actions)
2944
+ actions: (0, import_sdk_core6.expandActionShortNames)(entry.service, entry.actions)
2589
2945
  }));
2590
2946
  const now = /* @__PURE__ */ new Date();
2591
2947
  const expiryMs = resolveExpiryMs(options?.expiry);
@@ -2607,13 +2963,30 @@ var _TinyCloudNode = class _TinyCloudNode {
2607
2963
  );
2608
2964
  return { delegation: delegation2, prompted: true };
2609
2965
  }
2610
- const granted = (0, import_sdk_core5.parseRecapCapabilities)(
2966
+ const granted = (0, import_sdk_core6.parseRecapCapabilities)(
2611
2967
  (siwe) => this.wasmBindings.parseRecapFromSiwe(siwe),
2612
2968
  session.siwe
2613
2969
  );
2614
- const { subset, missing } = (0, import_sdk_core5.isCapabilitySubset)(expandedEntries, granted);
2970
+ const { subset, missing } = (0, import_sdk_core6.isCapabilitySubset)(expandedEntries, granted);
2615
2971
  if (!subset) {
2616
- throw new import_sdk_core5.PermissionNotInManifestError(missing, granted);
2972
+ const runtimeGrant = this.findGrantForOperations(
2973
+ this.permissionEntriesToOperations(expandedEntries, session)
2974
+ );
2975
+ if (runtimeGrant) {
2976
+ const marginMs = _TinyCloudNode.SESSION_EXPIRY_SAFETY_MARGIN_MS;
2977
+ if (runtimeGrant.expiresAt.getTime() <= Date.now() + marginMs) {
2978
+ throw new import_sdk_core6.SessionExpiredError(runtimeGrant.expiresAt);
2979
+ }
2980
+ const runtimeExpiration = runtimeGrant.expiresAt < effectiveExpiration ? runtimeGrant.expiresAt : effectiveExpiration;
2981
+ const delegation2 = await this.createDelegationViaRuntimeGrant(
2982
+ did,
2983
+ expandedEntries,
2984
+ runtimeExpiration,
2985
+ runtimeGrant
2986
+ );
2987
+ return { delegation: delegation2, prompted: false };
2988
+ }
2989
+ throw new import_sdk_core6.PermissionNotInManifestError(missing, granted);
2617
2990
  }
2618
2991
  const delegation = await this.createDelegationViaWasmPath(
2619
2992
  did,
@@ -2693,7 +3066,7 @@ var _TinyCloudNode = class _TinyCloudNode {
2693
3066
  const spaceId = [...resolvedSpaces][0];
2694
3067
  const abilities = {};
2695
3068
  for (const entry of entries) {
2696
- const shortService = import_sdk_core5.SERVICE_LONG_TO_SHORT[entry.service];
3069
+ const shortService = import_sdk_core6.SERVICE_LONG_TO_SHORT[entry.service];
2697
3070
  if (shortService === void 0) {
2698
3071
  throw new Error(
2699
3072
  `delegateTo: unknown service '${entry.service}' \u2014 no short-form mapping`
@@ -2733,7 +3106,7 @@ var _TinyCloudNode = class _TinyCloudNode {
2733
3106
  });
2734
3107
  const primary = result.resources[0];
2735
3108
  const delegationHeader = { Authorization: result.delegation };
2736
- const activateResult = await (0, import_sdk_core5.activateSessionWithHost)(
3109
+ const activateResult = await (0, import_sdk_core6.activateSessionWithHost)(
2737
3110
  this.config.host,
2738
3111
  delegationHeader
2739
3112
  );
@@ -2757,6 +3130,41 @@ var _TinyCloudNode = class _TinyCloudNode {
2757
3130
  host: this.config.host
2758
3131
  };
2759
3132
  }
3133
+ async createDelegationViaRuntimeGrant(did, entries, expirationTime, grant) {
3134
+ const result = this.createDelegationWrapper({
3135
+ session: grant.session,
3136
+ delegateDID: did,
3137
+ spaceId: grant.session.spaceId,
3138
+ abilities: this.permissionsToAbilities(entries),
3139
+ expirationSecs: Math.floor(expirationTime.getTime() / 1e3)
3140
+ });
3141
+ const primary = result.resources[0];
3142
+ const delegationHeader = { Authorization: result.delegation };
3143
+ const targetHost = grant.delegation.host ?? this.config.host;
3144
+ const activateResult = await (0, import_sdk_core6.activateSessionWithHost)(
3145
+ targetHost,
3146
+ delegationHeader
3147
+ );
3148
+ if (!activateResult.success) {
3149
+ throw new Error(
3150
+ `Failed to activate delegation with host: ${activateResult.error}`
3151
+ );
3152
+ }
3153
+ return {
3154
+ cid: result.cid,
3155
+ delegationHeader,
3156
+ spaceId: grant.session.spaceId,
3157
+ path: primary.path,
3158
+ actions: primary.actions,
3159
+ resources: result.resources,
3160
+ disableSubDelegation: false,
3161
+ expiry: result.expiry,
3162
+ delegateDID: did,
3163
+ ownerAddress: grant.delegation.ownerAddress,
3164
+ chainId: grant.delegation.chainId,
3165
+ host: targetHost
3166
+ };
3167
+ }
2760
3168
  resolvePermissionSpace(space, session) {
2761
3169
  if (space === void 0) {
2762
3170
  return this.wasmBindings.makeSpaceId(
@@ -2773,6 +3181,223 @@ var _TinyCloudNode = class _TinyCloudNode {
2773
3181
  }
2774
3182
  return this.wasmBindings.makeSpaceId(session.address, session.chainId, space);
2775
3183
  }
3184
+ expandPermissionEntries(permissions) {
3185
+ return permissions.map((entry) => ({
3186
+ ...entry,
3187
+ actions: (0, import_sdk_core6.expandActionShortNames)(entry.service, entry.actions)
3188
+ }));
3189
+ }
3190
+ shortServiceName(service) {
3191
+ const short = import_sdk_core6.SERVICE_LONG_TO_SHORT[service];
3192
+ if (short === void 0) {
3193
+ throw new Error(
3194
+ `unknown service '${service}' \u2014 no short-form mapping`
3195
+ );
3196
+ }
3197
+ return short;
3198
+ }
3199
+ permissionsToAbilities(entries) {
3200
+ const abilities = {};
3201
+ for (const entry of entries) {
3202
+ const service = this.shortServiceName(entry.service);
3203
+ abilities[service] ?? (abilities[service] = {});
3204
+ const existing = abilities[service][entry.path] ?? [];
3205
+ const seen = new Set(existing);
3206
+ for (const action of entry.actions) {
3207
+ if (!seen.has(action)) {
3208
+ existing.push(action);
3209
+ seen.add(action);
3210
+ }
3211
+ }
3212
+ abilities[service][entry.path] = existing;
3213
+ }
3214
+ return abilities;
3215
+ }
3216
+ permissionOperations(entries, spaceId) {
3217
+ return entries.flatMap((entry) => {
3218
+ const service = this.shortServiceName(entry.service);
3219
+ return entry.actions.map((action) => ({
3220
+ spaceId,
3221
+ service,
3222
+ path: entry.path,
3223
+ action
3224
+ }));
3225
+ });
3226
+ }
3227
+ sessionCoversPermissionEntries(session, entries) {
3228
+ try {
3229
+ const granted = (0, import_sdk_core6.parseRecapCapabilities)(
3230
+ (siwe) => this.wasmBindings.parseRecapFromSiwe(siwe),
3231
+ session.siwe
3232
+ );
3233
+ return (0, import_sdk_core6.isCapabilitySubset)(entries, granted).subset;
3234
+ } catch {
3235
+ return false;
3236
+ }
3237
+ }
3238
+ permissionEntriesToOperations(entries, session) {
3239
+ return entries.flatMap((entry) => {
3240
+ const spaceId = this.resolvePermissionSpace(entry.space, session);
3241
+ const service = this.shortServiceName(entry.service);
3242
+ return entry.actions.map((action) => ({
3243
+ spaceId,
3244
+ service,
3245
+ path: entry.path,
3246
+ action
3247
+ }));
3248
+ });
3249
+ }
3250
+ findRuntimeGrantsForPermissionEntries(entries, session) {
3251
+ const grants = [];
3252
+ const operations = this.permissionEntriesToOperations(entries, session);
3253
+ if (operations.length === 0) {
3254
+ return grants;
3255
+ }
3256
+ for (const operation of operations) {
3257
+ const grant = this.findGrantForOperation(operation);
3258
+ if (!grant) {
3259
+ return [];
3260
+ }
3261
+ if (!grants.includes(grant)) {
3262
+ grants.push(grant);
3263
+ }
3264
+ }
3265
+ return grants;
3266
+ }
3267
+ runtimeDelegationFromSession(delegatedSession, entries, spaceId, session, expiresAt) {
3268
+ const resources = this.delegatedResourcesForEntries(entries, spaceId);
3269
+ const primary = resources[0];
3270
+ return {
3271
+ cid: delegatedSession.delegationCid,
3272
+ delegationHeader: delegatedSession.delegationHeader,
3273
+ spaceId,
3274
+ path: primary.path,
3275
+ actions: primary.actions,
3276
+ resources,
3277
+ disableSubDelegation: false,
3278
+ expiry: expiresAt,
3279
+ delegateDID: session.verificationMethod,
3280
+ ownerAddress: session.address,
3281
+ chainId: session.chainId,
3282
+ host: this.config.host
3283
+ };
3284
+ }
3285
+ runtimeGrantFromDelegation(delegation, session) {
3286
+ const operations = this.operationsFromDelegation(delegation);
3287
+ return {
3288
+ session: {
3289
+ delegationHeader: delegation.delegationHeader,
3290
+ delegationCid: delegation.cid,
3291
+ spaceId: delegation.spaceId,
3292
+ verificationMethod: session.verificationMethod,
3293
+ jwk: session.jwk
3294
+ },
3295
+ delegation,
3296
+ operations,
3297
+ expiresAt: delegation.expiry
3298
+ };
3299
+ }
3300
+ delegatedResourcesForEntries(entries, spaceId) {
3301
+ return entries.map((entry) => ({
3302
+ service: this.shortServiceName(entry.service),
3303
+ space: spaceId,
3304
+ path: entry.path,
3305
+ actions: [...entry.actions]
3306
+ }));
3307
+ }
3308
+ operationsFromDelegation(delegation) {
3309
+ const resources = delegation.resources !== void 0 && delegation.resources.length > 0 ? delegation.resources : this.flatDelegationResources(delegation);
3310
+ return resources.flatMap(
3311
+ (resource) => resource.actions.map((action) => ({
3312
+ spaceId: resource.space,
3313
+ service: this.invocationServiceName(resource.service),
3314
+ path: resource.path,
3315
+ action
3316
+ }))
3317
+ );
3318
+ }
3319
+ flatDelegationResources(delegation) {
3320
+ const byService = /* @__PURE__ */ new Map();
3321
+ for (const action of delegation.actions) {
3322
+ const service = this.shortServiceName(action.split("/")[0]);
3323
+ const actions = byService.get(service) ?? [];
3324
+ actions.push(action);
3325
+ byService.set(service, actions);
3326
+ }
3327
+ return [...byService.entries()].map(([service, actions]) => ({
3328
+ service,
3329
+ space: delegation.spaceId,
3330
+ path: delegation.path,
3331
+ actions
3332
+ }));
3333
+ }
3334
+ selectInvocationSession(fallback, service, path, action) {
3335
+ const grant = this.findGrantForOperation({
3336
+ spaceId: fallback.spaceId,
3337
+ service: this.invocationServiceName(service),
3338
+ path,
3339
+ action
3340
+ });
3341
+ return grant?.session ?? fallback;
3342
+ }
3343
+ findGrantForOperations(operations) {
3344
+ if (operations.length === 0) {
3345
+ return void 0;
3346
+ }
3347
+ this.pruneExpiredRuntimePermissionGrants();
3348
+ return this.runtimePermissionGrants.find((grant) => {
3349
+ return operations.every(
3350
+ (operation) => grant.operations.some(
3351
+ (granted) => this.operationCovers(granted, operation)
3352
+ )
3353
+ );
3354
+ });
3355
+ }
3356
+ findGrantForOperation(operation) {
3357
+ return this.findGrantForOperations([operation]);
3358
+ }
3359
+ pruneExpiredRuntimePermissionGrants() {
3360
+ const now = Date.now();
3361
+ this.runtimePermissionGrants = this.runtimePermissionGrants.filter(
3362
+ (grant) => grant.expiresAt.getTime() > now
3363
+ );
3364
+ }
3365
+ operationCovers(granted, requested) {
3366
+ return granted.spaceId === requested.spaceId && granted.service === requested.service && this.actionContains(granted.action, requested.action) && this.pathContains(granted.path, requested.path);
3367
+ }
3368
+ actionContains(grantedAction, requestedAction) {
3369
+ if (grantedAction === requestedAction) {
3370
+ return true;
3371
+ }
3372
+ if (grantedAction.endsWith("/*")) {
3373
+ const prefix = grantedAction.slice(0, -2);
3374
+ return requestedAction.startsWith(`${prefix}/`);
3375
+ }
3376
+ return false;
3377
+ }
3378
+ invocationServiceName(service) {
3379
+ return service.startsWith("tinycloud.") ? this.shortServiceName(service) : service;
3380
+ }
3381
+ pathContains(grantedPath, requestedPath) {
3382
+ if (grantedPath === "" || grantedPath === "/") {
3383
+ return true;
3384
+ }
3385
+ if (grantedPath.endsWith("/**")) {
3386
+ return requestedPath.startsWith(grantedPath.slice(0, -3));
3387
+ }
3388
+ if (grantedPath.endsWith("/*")) {
3389
+ const prefix = grantedPath.slice(0, -2);
3390
+ if (!requestedPath.startsWith(prefix)) {
3391
+ return false;
3392
+ }
3393
+ const remainder = requestedPath.slice(prefix.length);
3394
+ return !remainder.includes("/") || remainder === "/";
3395
+ }
3396
+ if (grantedPath.endsWith("/")) {
3397
+ return requestedPath.startsWith(grantedPath);
3398
+ }
3399
+ return grantedPath === requestedPath;
3400
+ }
2776
3401
  /**
2777
3402
  * Issue a delegation via the legacy wallet-signed SIWE path for a single
2778
3403
  * {@link PermissionEntry}. Shares the implementation with the public
@@ -2829,7 +3454,7 @@ var _TinyCloudNode = class _TinyCloudNode {
2829
3454
  );
2830
3455
  return result.delegation;
2831
3456
  } catch (err) {
2832
- if (err instanceof import_sdk_core5.PermissionNotInManifestError) {
3457
+ if (err instanceof import_sdk_core6.PermissionNotInManifestError) {
2833
3458
  } else {
2834
3459
  throw err;
2835
3460
  }
@@ -2886,7 +3511,7 @@ var _TinyCloudNode = class _TinyCloudNode {
2886
3511
  ...prepared,
2887
3512
  signature
2888
3513
  });
2889
- const activateResult = await (0, import_sdk_core5.activateSessionWithHost)(
3514
+ const activateResult = await (0, import_sdk_core6.activateSessionWithHost)(
2890
3515
  this.config.host,
2891
3516
  delegationSession.delegationHeader
2892
3517
  );
@@ -2908,7 +3533,7 @@ var _TinyCloudNode = class _TinyCloudNode {
2908
3533
  };
2909
3534
  const hasKvActions = params.actions.some((a) => a.startsWith("tinycloud.kv/"));
2910
3535
  if (hasKvActions && params.includePublicSpace !== false) {
2911
- const publicSpaceId = (0, import_sdk_core5.makePublicSpaceId)(
3536
+ const publicSpaceId = (0, import_sdk_core6.makePublicSpaceId)(
2912
3537
  this.wasmBindings.ensureEip55(session.address),
2913
3538
  session.chainId
2914
3539
  );
@@ -2931,7 +3556,7 @@ var _TinyCloudNode = class _TinyCloudNode {
2931
3556
  ...publicPrepared,
2932
3557
  signature: publicSignature
2933
3558
  });
2934
- const publicActivateResult = await (0, import_sdk_core5.activateSessionWithHost)(
3559
+ const publicActivateResult = await (0, import_sdk_core6.activateSessionWithHost)(
2935
3560
  this.config.host,
2936
3561
  publicSession.delegationHeader
2937
3562
  );
@@ -3030,7 +3655,7 @@ var _TinyCloudNode = class _TinyCloudNode {
3030
3655
  ...prepared,
3031
3656
  signature
3032
3657
  });
3033
- const activateResult = await (0, import_sdk_core5.activateSessionWithHost)(
3658
+ const activateResult = await (0, import_sdk_core6.activateSessionWithHost)(
3034
3659
  targetHost,
3035
3660
  invokerSession.delegationHeader
3036
3661
  );
@@ -3119,7 +3744,7 @@ var _TinyCloudNode = class _TinyCloudNode {
3119
3744
  ...prepared,
3120
3745
  signature
3121
3746
  });
3122
- const activateResult = await (0, import_sdk_core5.activateSessionWithHost)(
3747
+ const activateResult = await (0, import_sdk_core6.activateSessionWithHost)(
3123
3748
  targetHost,
3124
3749
  subDelegationSession.delegationHeader
3125
3750
  );
@@ -3155,7 +3780,7 @@ _TinyCloudNode.SESSION_EXPIRY_SAFETY_MARGIN_MS = 6e4;
3155
3780
  var TinyCloudNode = _TinyCloudNode;
3156
3781
 
3157
3782
  // src/core.ts
3158
- var import_sdk_core8 = require("@tinycloud/sdk-core");
3783
+ var import_sdk_core9 = require("@tinycloud/sdk-core");
3159
3784
 
3160
3785
  // src/delegation.ts
3161
3786
  function serializeDelegation(delegation) {
@@ -3174,7 +3799,6 @@ function deserializeDelegation(data) {
3174
3799
  }
3175
3800
 
3176
3801
  // src/core.ts
3177
- var import_sdk_core9 = require("@tinycloud/sdk-core");
3178
3802
  var import_sdk_core10 = require("@tinycloud/sdk-core");
3179
3803
  var import_sdk_core11 = require("@tinycloud/sdk-core");
3180
3804
  var import_sdk_core12 = require("@tinycloud/sdk-core");
@@ -3183,6 +3807,7 @@ var import_sdk_core14 = require("@tinycloud/sdk-core");
3183
3807
  var import_sdk_core15 = require("@tinycloud/sdk-core");
3184
3808
  var import_sdk_core16 = require("@tinycloud/sdk-core");
3185
3809
  var import_sdk_core17 = require("@tinycloud/sdk-core");
3810
+ var import_sdk_core18 = require("@tinycloud/sdk-core");
3186
3811
  // Annotate the CommonJS export names for ESM import in node:
3187
3812
  0 && (module.exports = {
3188
3813
  ACCOUNT_REGISTRY_PATH,
@@ -3210,6 +3835,7 @@ var import_sdk_core17 = require("@tinycloud/sdk-core");
3210
3835
  ProtocolMismatchError,
3211
3836
  SQLAction,
3212
3837
  SQLService,
3838
+ SecretsService,
3213
3839
  ServiceContext,
3214
3840
  SessionExpiredError,
3215
3841
  SharingService,