@tinycloud/node-sdk 2.1.0-beta.0 → 2.1.0-beta.2

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,55 +20,64 @@ var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: tru
20
20
  // src/core.ts
21
21
  var core_exports = {};
22
22
  __export(core_exports, {
23
- AutoApproveSpaceCreationHandler: () => import_sdk_core6.AutoApproveSpaceCreationHandler,
24
- CapabilityKeyRegistry: () => import_sdk_core12.CapabilityKeyRegistry,
25
- CapabilityKeyRegistryErrorCodes: () => import_sdk_core12.CapabilityKeyRegistryErrorCodes,
26
- DataVaultService: () => import_sdk_core10.DataVaultService,
27
- DatabaseHandle: () => import_sdk_core8.DatabaseHandle,
23
+ AutoApproveSpaceCreationHandler: () => import_sdk_core7.AutoApproveSpaceCreationHandler,
24
+ CapabilityKeyRegistry: () => import_sdk_core14.CapabilityKeyRegistry,
25
+ CapabilityKeyRegistryErrorCodes: () => import_sdk_core14.CapabilityKeyRegistryErrorCodes,
26
+ DataVaultService: () => import_sdk_core12.DataVaultService,
27
+ DatabaseHandle: () => import_sdk_core10.DatabaseHandle,
28
28
  DelegatedAccess: () => DelegatedAccess,
29
- DelegationErrorCodes: () => import_sdk_core11.DelegationErrorCodes,
30
- DelegationManager: () => import_sdk_core11.DelegationManager,
31
- DuckDbAction: () => import_sdk_core9.DuckDbAction,
32
- DuckDbDatabaseHandle: () => import_sdk_core9.DuckDbDatabaseHandle,
33
- DuckDbService: () => import_sdk_core9.DuckDbService,
29
+ DelegationErrorCodes: () => import_sdk_core13.DelegationErrorCodes,
30
+ DelegationManager: () => import_sdk_core13.DelegationManager,
31
+ DuckDbAction: () => import_sdk_core11.DuckDbAction,
32
+ DuckDbDatabaseHandle: () => import_sdk_core11.DuckDbDatabaseHandle,
33
+ DuckDbService: () => import_sdk_core11.DuckDbService,
34
34
  FileSessionStorage: () => FileSessionStorage,
35
- KVService: () => import_sdk_core7.KVService,
35
+ KVService: () => import_sdk_core9.KVService,
36
+ ManifestValidationError: () => import_sdk_core8.ManifestValidationError,
36
37
  MemorySessionStorage: () => MemorySessionStorage,
37
38
  NodeUserAuthorization: () => NodeUserAuthorization,
38
- PrefixedKVService: () => import_sdk_core7.PrefixedKVService,
39
- ProtocolMismatchError: () => import_sdk_core14.ProtocolMismatchError,
40
- SQLAction: () => import_sdk_core8.SQLAction,
41
- SQLService: () => import_sdk_core8.SQLService,
42
- ServiceContext: () => import_sdk_core15.ServiceContext,
43
- SharingService: () => import_sdk_core11.SharingService,
44
- SilentNotificationHandler: () => import_sdk_core6.SilentNotificationHandler,
45
- Space: () => import_sdk_core13.Space,
46
- SpaceErrorCodes: () => import_sdk_core13.SpaceErrorCodes,
47
- SpaceService: () => import_sdk_core13.SpaceService,
48
- TinyCloud: () => import_sdk_core5.TinyCloud,
39
+ PermissionNotInManifestError: () => import_sdk_core8.PermissionNotInManifestError,
40
+ PrefixedKVService: () => import_sdk_core9.PrefixedKVService,
41
+ ProtocolMismatchError: () => import_sdk_core16.ProtocolMismatchError,
42
+ SQLAction: () => import_sdk_core10.SQLAction,
43
+ SQLService: () => import_sdk_core10.SQLService,
44
+ ServiceContext: () => import_sdk_core17.ServiceContext,
45
+ SessionExpiredError: () => import_sdk_core8.SessionExpiredError,
46
+ SharingService: () => import_sdk_core13.SharingService,
47
+ SilentNotificationHandler: () => import_sdk_core7.SilentNotificationHandler,
48
+ Space: () => import_sdk_core15.Space,
49
+ SpaceErrorCodes: () => import_sdk_core15.SpaceErrorCodes,
50
+ SpaceService: () => import_sdk_core15.SpaceService,
51
+ TinyCloud: () => import_sdk_core6.TinyCloud,
49
52
  TinyCloudNode: () => TinyCloudNode,
50
- UnsupportedFeatureError: () => import_sdk_core14.UnsupportedFeatureError,
51
- VaultHeaders: () => import_sdk_core10.VaultHeaders,
52
- VaultPublicSpaceKVActions: () => import_sdk_core10.VaultPublicSpaceKVActions,
53
- VersionCheckError: () => import_sdk_core14.VersionCheckError,
53
+ UnsupportedFeatureError: () => import_sdk_core16.UnsupportedFeatureError,
54
+ VaultHeaders: () => import_sdk_core12.VaultHeaders,
55
+ VaultPublicSpaceKVActions: () => import_sdk_core12.VaultPublicSpaceKVActions,
56
+ VersionCheckError: () => import_sdk_core16.VersionCheckError,
54
57
  WasmKeyProvider: () => WasmKeyProvider,
55
- buildSpaceUri: () => import_sdk_core13.buildSpaceUri,
56
- checkNodeInfo: () => import_sdk_core14.checkNodeInfo,
57
- createCapabilityKeyRegistry: () => import_sdk_core12.createCapabilityKeyRegistry,
58
- createSharingService: () => import_sdk_core11.createSharingService,
59
- createSpaceService: () => import_sdk_core13.createSpaceService,
60
- createVaultCrypto: () => import_sdk_core10.createVaultCrypto,
58
+ buildSpaceUri: () => import_sdk_core15.buildSpaceUri,
59
+ checkNodeInfo: () => import_sdk_core16.checkNodeInfo,
60
+ createCapabilityKeyRegistry: () => import_sdk_core14.createCapabilityKeyRegistry,
61
+ createSharingService: () => import_sdk_core13.createSharingService,
62
+ createSpaceService: () => import_sdk_core15.createSpaceService,
63
+ createVaultCrypto: () => import_sdk_core12.createVaultCrypto,
61
64
  createWasmKeyProvider: () => createWasmKeyProvider,
62
65
  defaultSignStrategy: () => defaultSignStrategy,
63
- defaultSpaceCreationHandler: () => import_sdk_core6.defaultSpaceCreationHandler,
66
+ defaultSpaceCreationHandler: () => import_sdk_core7.defaultSpaceCreationHandler,
64
67
  deserializeDelegation: () => deserializeDelegation,
65
- makePublicSpaceId: () => import_sdk_core13.makePublicSpaceId,
66
- parseSpaceUri: () => import_sdk_core13.parseSpaceUri,
67
- serializeDelegation: () => serializeDelegation
68
+ expandActionShortNames: () => import_sdk_core8.expandActionShortNames,
69
+ isCapabilitySubset: () => import_sdk_core8.isCapabilitySubset,
70
+ loadManifest: () => import_sdk_core8.loadManifest,
71
+ makePublicSpaceId: () => import_sdk_core15.makePublicSpaceId,
72
+ parseExpiry: () => import_sdk_core8.parseExpiry,
73
+ parseSpaceUri: () => import_sdk_core15.parseSpaceUri,
74
+ resolveManifest: () => import_sdk_core8.resolveManifest,
75
+ serializeDelegation: () => serializeDelegation,
76
+ validateManifest: () => import_sdk_core8.validateManifest
68
77
  });
69
78
  module.exports = __toCommonJS(core_exports);
70
- var import_sdk_core5 = require("@tinycloud/sdk-core");
71
79
  var import_sdk_core6 = require("@tinycloud/sdk-core");
80
+ var import_sdk_core7 = require("@tinycloud/sdk-core");
72
81
 
73
82
  // src/storage/MemorySessionStorage.ts
74
83
  var MemorySessionStorage = class {
@@ -330,8 +339,25 @@ var NodeUserAuthorization = class {
330
339
  this.enablePublicSpace = config.enablePublicSpace ?? true;
331
340
  this.nonce = config.nonce;
332
341
  this.siweConfig = config.siweConfig;
342
+ this._manifest = config.manifest;
333
343
  this.sessionManager = this.wasm.createSessionManager();
334
344
  }
345
+ /**
346
+ * Return the manifest currently driving sign-in behavior, or
347
+ * `undefined` if none is set. Used by TinyCloudWeb/TinyCloudNode
348
+ * internals to surface the manifest for requestPermissions flows
349
+ * without forcing the caller to track it separately.
350
+ */
351
+ get manifest() {
352
+ return this._manifest;
353
+ }
354
+ /**
355
+ * Install or replace the stored manifest. Takes effect on the next
356
+ * `signIn()` call — the current session (if any) is not touched.
357
+ */
358
+ setManifest(manifest) {
359
+ this._manifest = manifest;
360
+ }
335
361
  /**
336
362
  * The current active session (web-core compatible).
337
363
  */
@@ -348,6 +374,39 @@ var NodeUserAuthorization = class {
348
374
  get nodeFeatures() {
349
375
  return this._nodeFeatures;
350
376
  }
377
+ /**
378
+ * Compute the `abilities` map the WASM `prepareSession` call should
379
+ * see at sign-in time.
380
+ *
381
+ * When a manifest is installed, we resolve it and union together:
382
+ * - the app's own `resources` (what it needs at runtime)
383
+ * - every `additionalDelegates[*].permissions` list (what it will
384
+ * re-delegate to other DIDs post sign-in)
385
+ *
386
+ * into the short-service / path / full-URN-actions shape the WASM
387
+ * layer expects. This is the key invariant that lets
388
+ * {@link TinyCloudNode.delegateTo} issue manifest-declared
389
+ * delegations via the session key (no wallet prompt): the session's
390
+ * own recap already covers every action those delegations need.
391
+ *
392
+ * When no manifest is installed, we fall back to the
393
+ * {@link defaultActions} table so existing callers see no change.
394
+ *
395
+ * This is a pure function of `this._manifest` + `this.defaultActions`
396
+ * — the manifest resolution performs no I/O and throws a
397
+ * {@link ManifestValidationError} on structural problems (missing
398
+ * id/name, unparseable expiry, etc), which will surface at sign-in
399
+ * rather than being silently swallowed.
400
+ *
401
+ * @internal
402
+ */
403
+ resolveSignInAbilities() {
404
+ if (this._manifest === void 0) {
405
+ return this.defaultActions;
406
+ }
407
+ const resolved = (0, import_sdk_core2.resolveManifest)(this._manifest);
408
+ return (0, import_sdk_core2.manifestAbilitiesUnion)(resolved);
409
+ }
351
410
  /**
352
411
  * Build SIWE overrides from the top-level nonce and siweConfig.
353
412
  * - Top-level `nonce` is seeded first so `siweConfig.nonce` wins if both are set.
@@ -551,7 +610,7 @@ var NodeUserAuthorization = class {
551
610
  const now = /* @__PURE__ */ new Date();
552
611
  const expirationTime = new Date(now.getTime() + this.sessionExpirationMs);
553
612
  const prepared = this.wasm.prepareSession({
554
- abilities: this.defaultActions,
613
+ abilities: this.resolveSignInAbilities(),
555
614
  address,
556
615
  chainId,
557
616
  domain: this.domain,
@@ -694,7 +753,7 @@ var NodeUserAuthorization = class {
694
753
  const now = /* @__PURE__ */ new Date();
695
754
  const expirationTime = new Date(now.getTime() + this.sessionExpirationMs);
696
755
  const prepared = this.wasm.prepareSession({
697
- abilities: this.defaultActions,
756
+ abilities: this.resolveSignInAbilities(),
698
757
  address,
699
758
  chainId,
700
759
  domain: this.domain,
@@ -862,7 +921,7 @@ var NodeUserAuthorization = class {
862
921
  };
863
922
 
864
923
  // src/TinyCloudNode.ts
865
- var import_sdk_core4 = require("@tinycloud/sdk-core");
924
+ var import_sdk_core5 = require("@tinycloud/sdk-core");
866
925
 
867
926
  // src/DelegatedAccess.ts
868
927
  var import_sdk_core3 = require("@tinycloud/sdk-core");
@@ -1017,9 +1076,69 @@ function createWasmKeyProvider(sessionManager) {
1017
1076
  return new WasmKeyProvider({ sessionManager });
1018
1077
  }
1019
1078
 
1079
+ // src/delegateToHelpers.ts
1080
+ var import_sdk_core4 = require("@tinycloud/sdk-core");
1081
+ function legacyParamsToPermissionEntries(actions, path, spaceIdOverride) {
1082
+ const byService = /* @__PURE__ */ new Map();
1083
+ for (const a of actions) {
1084
+ const slashIdx = a.indexOf("/");
1085
+ if (slashIdx === -1) {
1086
+ continue;
1087
+ }
1088
+ const service = a.slice(0, slashIdx);
1089
+ if (!service.startsWith("tinycloud.")) {
1090
+ continue;
1091
+ }
1092
+ const list = byService.get(service);
1093
+ if (list === void 0) {
1094
+ byService.set(service, [a]);
1095
+ } else {
1096
+ list.push(a);
1097
+ }
1098
+ }
1099
+ const space = spaceIdOverride ?? "default";
1100
+ const entries = [];
1101
+ for (const [service, actionList] of byService) {
1102
+ entries.push({
1103
+ service,
1104
+ space,
1105
+ path,
1106
+ actions: actionList
1107
+ });
1108
+ }
1109
+ return entries;
1110
+ }
1111
+ function resolveExpiryMs(expiry) {
1112
+ if (expiry === void 0) {
1113
+ return 60 * 60 * 1e3;
1114
+ }
1115
+ if (typeof expiry === "number") {
1116
+ if (!Number.isFinite(expiry) || expiry <= 0) {
1117
+ throw new Error(
1118
+ `delegateTo expiry must be a positive finite number (got ${expiry})`
1119
+ );
1120
+ }
1121
+ return expiry;
1122
+ }
1123
+ return (0, import_sdk_core4.parseExpiry)(expiry);
1124
+ }
1125
+ function extractSiweExpiration(siwe) {
1126
+ const parsed = new import_sdk_core4.SiweMessage(siwe);
1127
+ if (parsed.expirationTime === void 0 || parsed.expirationTime === null) {
1128
+ return void 0;
1129
+ }
1130
+ const d = new Date(parsed.expirationTime);
1131
+ if (Number.isNaN(d.getTime())) {
1132
+ throw new Error(
1133
+ `Session SIWE has unparseable expirationTime: ${parsed.expirationTime}`
1134
+ );
1135
+ }
1136
+ return d;
1137
+ }
1138
+
1020
1139
  // src/TinyCloudNode.ts
1021
1140
  var DEFAULT_HOST = "https://node.tinycloud.xyz";
1022
- var TinyCloudNode = class _TinyCloudNode {
1141
+ var _TinyCloudNode = class _TinyCloudNode {
1023
1142
  /**
1024
1143
  * Create a new TinyCloudNode instance.
1025
1144
  *
@@ -1074,12 +1193,12 @@ var TinyCloudNode = class _TinyCloudNode {
1074
1193
  throw new Error("Failed to get session key JWK");
1075
1194
  }
1076
1195
  this.sessionKeyJwk = JSON.parse(jwkStr);
1077
- this._capabilityRegistry = new import_sdk_core4.CapabilityKeyRegistry();
1196
+ this._capabilityRegistry = new import_sdk_core5.CapabilityKeyRegistry();
1078
1197
  this._keyProvider = new WasmKeyProvider({
1079
1198
  sessionManager: this.sessionManager
1080
1199
  });
1081
- this.notificationHandler = config.notificationHandler ?? new import_sdk_core4.SilentNotificationHandler();
1082
- this._sharingService = new import_sdk_core4.SharingService({
1200
+ this.notificationHandler = config.notificationHandler ?? new import_sdk_core5.SilentNotificationHandler();
1201
+ this._sharingService = new import_sdk_core5.SharingService({
1083
1202
  hosts: [this.config.host],
1084
1203
  // session: undefined - not needed for receive()
1085
1204
  invoke: this.wasmBindings.invoke,
@@ -1089,8 +1208,8 @@ var TinyCloudNode = class _TinyCloudNode {
1089
1208
  // delegationManager: undefined - not needed for receive()
1090
1209
  createKVService: (config2) => {
1091
1210
  const prefix = config2.pathPrefix?.replace(/\/$/, "");
1092
- const kvService = new import_sdk_core4.KVService({ prefix });
1093
- const kvContext = new import_sdk_core4.ServiceContext({
1211
+ const kvService = new import_sdk_core5.KVService({ prefix });
1212
+ const kvContext = new import_sdk_core5.ServiceContext({
1094
1213
  invoke: config2.invoke,
1095
1214
  fetch: config2.fetch ?? globalThis.fetch.bind(globalThis),
1096
1215
  hosts: config2.hosts
@@ -1143,12 +1262,35 @@ var TinyCloudNode = class _TinyCloudNode {
1143
1262
  enablePublicSpace: config.enablePublicSpace ?? true,
1144
1263
  spaceCreationHandler: config.spaceCreationHandler,
1145
1264
  nonce: config.nonce,
1146
- siweConfig: config.siweConfig
1265
+ siweConfig: config.siweConfig,
1266
+ manifest: config.manifest
1147
1267
  });
1148
- this.tc = new import_sdk_core4.TinyCloud(this.auth, {
1268
+ this.tc = new import_sdk_core5.TinyCloud(this.auth, {
1149
1269
  invokeAny: this.wasmBindings.invokeAny
1150
1270
  });
1151
1271
  }
1272
+ /**
1273
+ * Install or replace the manifest that drives the SIWE recap at
1274
+ * sign-in. Takes effect on the next `signIn()` call — the current
1275
+ * session (if any) is not touched. Wire this up from a higher
1276
+ * layer (e.g. TinyCloudWeb.setManifest) so the manifest is kept
1277
+ * in sync across the stack.
1278
+ */
1279
+ setManifest(manifest) {
1280
+ if (!this.auth) {
1281
+ throw new Error(
1282
+ "setManifest requires wallet mode. Provide a signer or privateKey in the TinyCloudNode config."
1283
+ );
1284
+ }
1285
+ this.auth.setManifest(manifest);
1286
+ }
1287
+ /**
1288
+ * Return the manifest currently installed on the auth handler,
1289
+ * or `undefined` if none is set.
1290
+ */
1291
+ get manifest() {
1292
+ return this.auth?.manifest;
1293
+ }
1152
1294
  /**
1153
1295
  * Get the primary identity DID for this user.
1154
1296
  * - If wallet connected and signed in: returns PKH DID (did:pkh:eip155:{chainId}:{address})
@@ -1244,22 +1386,22 @@ var TinyCloudNode = class _TinyCloudNode {
1244
1386
  if (sessionData.chainId) {
1245
1387
  this._chainId = sessionData.chainId;
1246
1388
  }
1247
- this._serviceContext = new import_sdk_core4.ServiceContext({
1389
+ this._serviceContext = new import_sdk_core5.ServiceContext({
1248
1390
  invoke: this.wasmBindings.invoke,
1249
1391
  invokeAny: this.wasmBindings.invokeAny,
1250
1392
  fetch: globalThis.fetch.bind(globalThis),
1251
1393
  hosts: [this.config.host]
1252
1394
  });
1253
- this._kv = new import_sdk_core4.KVService({});
1395
+ this._kv = new import_sdk_core5.KVService({});
1254
1396
  this._kv.initialize(this._serviceContext);
1255
1397
  this._serviceContext.registerService("kv", this._kv);
1256
- this._sql = new import_sdk_core4.SQLService({});
1398
+ this._sql = new import_sdk_core5.SQLService({});
1257
1399
  this._sql.initialize(this._serviceContext);
1258
1400
  this._serviceContext.registerService("sql", this._sql);
1259
- this._duckdb = new import_sdk_core4.DuckDbService({});
1401
+ this._duckdb = new import_sdk_core5.DuckDbService({});
1260
1402
  this._duckdb.initialize(this._serviceContext);
1261
1403
  this._serviceContext.registerService("duckdb", this._duckdb);
1262
- this._hooks = new import_sdk_core4.HooksService({});
1404
+ this._hooks = new import_sdk_core5.HooksService({});
1263
1405
  this._hooks.initialize(this._serviceContext);
1264
1406
  this._serviceContext.registerService("hooks", this._hooks);
1265
1407
  const serviceSession = {
@@ -1271,7 +1413,7 @@ var TinyCloudNode = class _TinyCloudNode {
1271
1413
  };
1272
1414
  this._serviceContext.setSession(serviceSession);
1273
1415
  const wasm = this.wasmBindings;
1274
- const vaultCrypto = (0, import_sdk_core4.createVaultCrypto)({
1416
+ const vaultCrypto = (0, import_sdk_core5.createVaultCrypto)({
1275
1417
  vault_encrypt: wasm.vault_encrypt,
1276
1418
  vault_decrypt: wasm.vault_decrypt,
1277
1419
  vault_derive_key: wasm.vault_derive_key,
@@ -1281,7 +1423,7 @@ var TinyCloudNode = class _TinyCloudNode {
1281
1423
  vault_sha256: wasm.vault_sha256
1282
1424
  });
1283
1425
  const self = this;
1284
- this._vault = new import_sdk_core4.DataVaultService({
1426
+ this._vault = new import_sdk_core5.DataVaultService({
1285
1427
  spaceId: sessionData.spaceId,
1286
1428
  crypto: vaultCrypto,
1287
1429
  tc: {
@@ -1297,8 +1439,8 @@ var TinyCloudNode = class _TinyCloudNode {
1297
1439
  get publicKV() {
1298
1440
  return self._publicKV ?? self.tc.publicKV;
1299
1441
  },
1300
- readPublicSpace: (host, spaceId, key) => import_sdk_core4.TinyCloud.readPublicSpace(host, spaceId, key),
1301
- makePublicSpaceId: import_sdk_core4.TinyCloud.makePublicSpaceId,
1442
+ readPublicSpace: (host, spaceId, key) => import_sdk_core5.TinyCloud.readPublicSpace(host, spaceId, key),
1443
+ makePublicSpaceId: import_sdk_core5.TinyCloud.makePublicSpaceId,
1302
1444
  did: this.did,
1303
1445
  address: sessionData.address ?? this._address ?? "",
1304
1446
  chainId: sessionData.chainId ?? this._chainId,
@@ -1361,7 +1503,7 @@ var TinyCloudNode = class _TinyCloudNode {
1361
1503
  nonce: this.config.nonce,
1362
1504
  siweConfig: this.config.siweConfig
1363
1505
  });
1364
- this.tc = new import_sdk_core4.TinyCloud(this.auth, {
1506
+ this.tc = new import_sdk_core5.TinyCloud(this.auth, {
1365
1507
  invokeAny: this.wasmBindings.invokeAny
1366
1508
  });
1367
1509
  this.config.prefix = prefix;
@@ -1401,7 +1543,7 @@ var TinyCloudNode = class _TinyCloudNode {
1401
1543
  nonce: this.config.nonce,
1402
1544
  siweConfig: this.config.siweConfig
1403
1545
  });
1404
- this.tc = new import_sdk_core4.TinyCloud(this.auth, {
1546
+ this.tc = new import_sdk_core5.TinyCloud(this.auth, {
1405
1547
  invokeAny: this.wasmBindings.invokeAny
1406
1548
  });
1407
1549
  this.config.prefix = prefix;
@@ -1416,27 +1558,27 @@ var TinyCloudNode = class _TinyCloudNode {
1416
1558
  return;
1417
1559
  }
1418
1560
  this.tc.initializeServices(this.wasmBindings.invoke, [this.config.host]);
1419
- this._serviceContext = new import_sdk_core4.ServiceContext({
1561
+ this._serviceContext = new import_sdk_core5.ServiceContext({
1420
1562
  invoke: this.wasmBindings.invoke,
1421
1563
  invokeAny: this.wasmBindings.invokeAny,
1422
1564
  fetch: globalThis.fetch.bind(globalThis),
1423
1565
  hosts: [this.config.host]
1424
1566
  });
1425
- this._kv = new import_sdk_core4.KVService({});
1567
+ this._kv = new import_sdk_core5.KVService({});
1426
1568
  this._kv.initialize(this._serviceContext);
1427
1569
  this._serviceContext.registerService("kv", this._kv);
1428
1570
  const features = this.nodeFeatures;
1429
1571
  if (features.length === 0 || features.includes("sql")) {
1430
- this._sql = new import_sdk_core4.SQLService({});
1572
+ this._sql = new import_sdk_core5.SQLService({});
1431
1573
  this._sql.initialize(this._serviceContext);
1432
1574
  this._serviceContext.registerService("sql", this._sql);
1433
1575
  }
1434
1576
  if (features.length === 0 || features.includes("duckdb")) {
1435
- this._duckdb = new import_sdk_core4.DuckDbService({});
1577
+ this._duckdb = new import_sdk_core5.DuckDbService({});
1436
1578
  this._duckdb.initialize(this._serviceContext);
1437
1579
  this._serviceContext.registerService("duckdb", this._duckdb);
1438
1580
  }
1439
- this._hooks = new import_sdk_core4.HooksService({});
1581
+ this._hooks = new import_sdk_core5.HooksService({});
1440
1582
  this._hooks.initialize(this._serviceContext);
1441
1583
  this._serviceContext.registerService("hooks", this._hooks);
1442
1584
  const serviceSession = {
@@ -1449,7 +1591,7 @@ var TinyCloudNode = class _TinyCloudNode {
1449
1591
  this._serviceContext.setSession(serviceSession);
1450
1592
  this.tc.serviceContext.setSession(serviceSession);
1451
1593
  const wasm = this.wasmBindings;
1452
- const vaultCrypto = (0, import_sdk_core4.createVaultCrypto)({
1594
+ const vaultCrypto = (0, import_sdk_core5.createVaultCrypto)({
1453
1595
  vault_encrypt: wasm.vault_encrypt,
1454
1596
  vault_decrypt: wasm.vault_decrypt,
1455
1597
  vault_derive_key: wasm.vault_derive_key,
@@ -1459,7 +1601,7 @@ var TinyCloudNode = class _TinyCloudNode {
1459
1601
  vault_sha256: wasm.vault_sha256
1460
1602
  });
1461
1603
  const self = this;
1462
- this._vault = new import_sdk_core4.DataVaultService({
1604
+ this._vault = new import_sdk_core5.DataVaultService({
1463
1605
  spaceId: session.spaceId,
1464
1606
  crypto: vaultCrypto,
1465
1607
  tc: {
@@ -1475,8 +1617,8 @@ var TinyCloudNode = class _TinyCloudNode {
1475
1617
  get publicKV() {
1476
1618
  return self._publicKV ?? self.tc.publicKV;
1477
1619
  },
1478
- readPublicSpace: (host, spaceId, key) => import_sdk_core4.TinyCloud.readPublicSpace(host, spaceId, key),
1479
- makePublicSpaceId: import_sdk_core4.TinyCloud.makePublicSpaceId,
1620
+ readPublicSpace: (host, spaceId, key) => import_sdk_core5.TinyCloud.readPublicSpace(host, spaceId, key),
1621
+ makePublicSpaceId: import_sdk_core5.TinyCloud.makePublicSpaceId,
1480
1622
  did: this.did,
1481
1623
  address: this._address,
1482
1624
  chainId: this._chainId,
@@ -1492,7 +1634,7 @@ var TinyCloudNode = class _TinyCloudNode {
1492
1634
  * @internal
1493
1635
  */
1494
1636
  initializeV2Services(serviceSession) {
1495
- this._capabilityRegistry = new import_sdk_core4.CapabilityKeyRegistry();
1637
+ this._capabilityRegistry = new import_sdk_core5.CapabilityKeyRegistry();
1496
1638
  const tcSession = this.auth?.tinyCloudSession;
1497
1639
  if (tcSession && this._address) {
1498
1640
  const sessionKey = {
@@ -1566,13 +1708,13 @@ var TinyCloudNode = class _TinyCloudNode {
1566
1708
  }
1567
1709
  this._capabilityRegistry.registerKey(sessionKey, delegations);
1568
1710
  }
1569
- this._delegationManager = new import_sdk_core4.DelegationManager({
1711
+ this._delegationManager = new import_sdk_core5.DelegationManager({
1570
1712
  hosts: [this.config.host],
1571
1713
  session: serviceSession,
1572
1714
  invoke: this.wasmBindings.invoke,
1573
1715
  fetch: globalThis.fetch.bind(globalThis)
1574
1716
  });
1575
- this._spaceService = new import_sdk_core4.SpaceService({
1717
+ this._spaceService = new import_sdk_core5.SpaceService({
1576
1718
  hosts: [this.config.host],
1577
1719
  session: serviceSession,
1578
1720
  invoke: this.wasmBindings.invoke,
@@ -1580,9 +1722,9 @@ var TinyCloudNode = class _TinyCloudNode {
1580
1722
  capabilityRegistry: this._capabilityRegistry,
1581
1723
  userDid: this.did,
1582
1724
  createKVService: (spaceId) => {
1583
- const kvService = new import_sdk_core4.KVService({});
1725
+ const kvService = new import_sdk_core5.KVService({});
1584
1726
  if (this._serviceContext) {
1585
- const spaceScopedContext = new import_sdk_core4.ServiceContext({
1727
+ const spaceScopedContext = new import_sdk_core5.ServiceContext({
1586
1728
  invoke: this._serviceContext.invoke,
1587
1729
  fetch: this._serviceContext.fetch,
1588
1730
  hosts: this._serviceContext.hosts
@@ -1655,7 +1797,19 @@ var TinyCloudNode = class _TinyCloudNode {
1655
1797
  }
1656
1798
  /**
1657
1799
  * Wrapper for the WASM createDelegation function.
1658
- * Adapts the WASM interface to what SharingService expects.
1800
+ *
1801
+ * The WASM call now takes a multi-resource `abilities` map
1802
+ * (matching `prepareSession`'s shape) and emits ONE UCAN that
1803
+ * covers every `(service, path, actions)` entry. We mirror the raw
1804
+ * result back through `CreateDelegationWasmResult`, converting the
1805
+ * seconds-since-epoch `expiry` to a Date and normalizing the
1806
+ * `delegateDid` → `delegateDID` case.
1807
+ *
1808
+ * Both SharingService (single-entry) and
1809
+ * {@link TinyCloudNode.delegateTo} (multi-entry) drive this through
1810
+ * the same code path so there's exactly one place that touches the
1811
+ * WASM boundary.
1812
+ *
1659
1813
  * @internal
1660
1814
  */
1661
1815
  createDelegationWrapper(params) {
@@ -1670,18 +1824,19 @@ var TinyCloudNode = class _TinyCloudNode {
1670
1824
  wasmSession,
1671
1825
  params.delegateDID,
1672
1826
  params.spaceId,
1673
- params.path,
1674
- params.actions,
1827
+ params.abilities,
1675
1828
  params.expirationSecs,
1676
1829
  params.notBeforeSecs
1677
1830
  );
1678
1831
  return {
1679
1832
  delegation: result.delegation,
1680
1833
  cid: result.cid,
1681
- delegateDID: result.delegateDid,
1682
- path: result.path,
1683
- actions: result.actions,
1684
- expiry: new Date(result.expiry * 1e3)
1834
+ // Rust serde `rename_all = "camelCase"` emits `delegateDid`
1835
+ // (lowercase d); the TypeScript interface uses `delegateDID`
1836
+ // (historical, matches Delegation.delegateDID). Normalize here.
1837
+ delegateDID: result.delegateDid ?? result.delegateDID,
1838
+ expiry: new Date(result.expiry * 1e3),
1839
+ resources: result.resources
1685
1840
  };
1686
1841
  }
1687
1842
  /**
@@ -1721,7 +1876,7 @@ var TinyCloudNode = class _TinyCloudNode {
1721
1876
  ...prepared,
1722
1877
  signature
1723
1878
  });
1724
- const activateResult = await (0, import_sdk_core4.activateSessionWithHost)(
1879
+ const activateResult = await (0, import_sdk_core5.activateSessionWithHost)(
1725
1880
  host,
1726
1881
  delegationSession.delegationHeader
1727
1882
  );
@@ -1788,7 +1943,7 @@ var TinyCloudNode = class _TinyCloudNode {
1788
1943
  if (!this._sql) {
1789
1944
  const features = this.nodeFeatures;
1790
1945
  if (features.length > 0 && !features.includes("sql")) {
1791
- throw new import_sdk_core4.UnsupportedFeatureError("sql", this.config.host, features);
1946
+ throw new import_sdk_core5.UnsupportedFeatureError("sql", this.config.host, features);
1792
1947
  }
1793
1948
  throw new Error("Not signed in. Call signIn() first.");
1794
1949
  }
@@ -1801,7 +1956,7 @@ var TinyCloudNode = class _TinyCloudNode {
1801
1956
  if (!this._duckdb) {
1802
1957
  const features = this.nodeFeatures;
1803
1958
  if (features.length > 0 && !features.includes("duckdb")) {
1804
- throw new import_sdk_core4.UnsupportedFeatureError("duckdb", this.config.host, features);
1959
+ throw new import_sdk_core5.UnsupportedFeatureError("duckdb", this.config.host, features);
1805
1960
  }
1806
1961
  throw new Error("Not signed in. Call signIn() first.");
1807
1962
  }
@@ -2040,7 +2195,7 @@ var TinyCloudNode = class _TinyCloudNode {
2040
2195
  ...prepared,
2041
2196
  signature
2042
2197
  });
2043
- const activateResult = await (0, import_sdk_core4.activateSessionWithHost)(
2198
+ const activateResult = await (0, import_sdk_core5.activateSessionWithHost)(
2044
2199
  this.config.host,
2045
2200
  delegationSession.delegationHeader
2046
2201
  );
@@ -2067,8 +2222,8 @@ var TinyCloudNode = class _TinyCloudNode {
2067
2222
  }]);
2068
2223
  }
2069
2224
  if (this._serviceContext) {
2070
- const publicKV = new import_sdk_core4.KVService({ prefix: "" });
2071
- const publicContext = new import_sdk_core4.ServiceContext({
2225
+ const publicKV = new import_sdk_core5.KVService({ prefix: "" });
2226
+ const publicContext = new import_sdk_core5.ServiceContext({
2072
2227
  invoke: this.wasmBindings.invoke,
2073
2228
  fetch: this._serviceContext.fetch,
2074
2229
  hosts: this._serviceContext.hosts
@@ -2153,6 +2308,209 @@ var TinyCloudNode = class _TinyCloudNode {
2153
2308
  async checkPermission(path, action) {
2154
2309
  return this.delegationManager.checkPermission(path, action);
2155
2310
  }
2311
+ /**
2312
+ * Issue a delegation using the capability-chain flow.
2313
+ *
2314
+ * When every requested permission is a subset of the current
2315
+ * session's recap, the delegation is signed by the session key via
2316
+ * WASM — no wallet prompt. When at least one is NOT derivable, a
2317
+ * {@link PermissionNotInManifestError} is raised (carrying the
2318
+ * missing entries) so the caller can trigger an escalation flow
2319
+ * (e.g. `TinyCloudWeb.requestPermissions`). Passing
2320
+ * `forceWalletSign: true` bypasses the derivability check and
2321
+ * always uses the wallet-signed SIWE path — used by the legacy
2322
+ * `createDelegation` fallback and by callers that want explicit
2323
+ * wallet confirmation.
2324
+ *
2325
+ * Multi-entry delegations are now emitted as **one** signed UCAN:
2326
+ * the underlying WASM `createDelegation` takes a full
2327
+ * `HashMap<Service, HashMap<Path, Vec<Ability>>>` abilities map
2328
+ * and produces a single attenuation carrying every
2329
+ * `(service, path, actions)` entry. The returned
2330
+ * {@link DelegateToResult.delegation} is that single blob, and
2331
+ * apps can POST it to their backend exactly like a single-entry
2332
+ * delegation (the server verifies all granted resources from one
2333
+ * UCAN).
2334
+ *
2335
+ * For single-entry requests the `PortableDelegation.path` and
2336
+ * `.actions` fields mirror the one granted entry. For
2337
+ * multi-entry requests they mirror the **first** entry (stable
2338
+ * lexicographic order from the Rust side); consumers that need
2339
+ * the full picture read `PortableDelegation.resources`.
2340
+ *
2341
+ * @throws {@link SessionExpiredError} when there is no session or
2342
+ * the current session has expired (or will within the 60s
2343
+ * safety margin).
2344
+ * @throws {@link PermissionNotInManifestError} when any requested
2345
+ * entry is not a subset of the granted session capabilities and
2346
+ * `forceWalletSign` is not set.
2347
+ */
2348
+ async delegateTo(did, permissions, options) {
2349
+ const session = this.auth?.tinyCloudSession;
2350
+ if (!session) {
2351
+ throw new import_sdk_core5.SessionExpiredError(/* @__PURE__ */ new Date(0));
2352
+ }
2353
+ const sessionExpiry = extractSiweExpiration(session.siwe);
2354
+ if (sessionExpiry !== void 0) {
2355
+ const now2 = Date.now();
2356
+ const marginMs = _TinyCloudNode.SESSION_EXPIRY_SAFETY_MARGIN_MS;
2357
+ if (sessionExpiry.getTime() <= now2 + marginMs) {
2358
+ throw new import_sdk_core5.SessionExpiredError(sessionExpiry);
2359
+ }
2360
+ }
2361
+ if (!Array.isArray(permissions) || permissions.length === 0) {
2362
+ throw new Error(
2363
+ "delegateTo requires a non-empty permissions array"
2364
+ );
2365
+ }
2366
+ const expandedEntries = permissions.map((entry) => ({
2367
+ ...entry,
2368
+ actions: (0, import_sdk_core5.expandActionShortNames)(entry.service, entry.actions)
2369
+ }));
2370
+ const now = /* @__PURE__ */ new Date();
2371
+ const expiryMs = resolveExpiryMs(options?.expiry);
2372
+ const expirationTime = new Date(now.getTime() + expiryMs);
2373
+ let effectiveExpiration = expirationTime;
2374
+ if (sessionExpiry !== void 0 && sessionExpiry < expirationTime) {
2375
+ effectiveExpiration = sessionExpiry;
2376
+ }
2377
+ if (options?.forceWalletSign) {
2378
+ if (expandedEntries.length > 1) {
2379
+ throw new Error(
2380
+ "delegateTo with forceWalletSign=true supports at most one PermissionEntry. Multi-entry requests must go through the session-key UCAN path (drop forceWalletSign) or the legacy createDelegation method."
2381
+ );
2382
+ }
2383
+ const delegation2 = await this.createDelegationLegacyWalletPath(
2384
+ did,
2385
+ expandedEntries[0],
2386
+ effectiveExpiration
2387
+ );
2388
+ return { delegation: delegation2, prompted: true };
2389
+ }
2390
+ const granted = (0, import_sdk_core5.parseRecapCapabilities)(
2391
+ (siwe) => this.wasmBindings.parseRecapFromSiwe(siwe),
2392
+ session.siwe
2393
+ );
2394
+ const { subset, missing } = (0, import_sdk_core5.isCapabilitySubset)(expandedEntries, granted);
2395
+ if (!subset) {
2396
+ throw new import_sdk_core5.PermissionNotInManifestError(missing, granted);
2397
+ }
2398
+ const delegation = await this.createDelegationViaWasmPath(
2399
+ did,
2400
+ expandedEntries,
2401
+ effectiveExpiration,
2402
+ session
2403
+ );
2404
+ return { delegation, prompted: false };
2405
+ }
2406
+ /**
2407
+ * Issue a delegation via the session-key UCAN WASM path.
2408
+ *
2409
+ * The caller has already verified every entry is derivable from
2410
+ * the current session; we build one multi-resource abilities map
2411
+ * and emit one signed UCAN covering them all.
2412
+ *
2413
+ * All entries must share the same target space (the UCAN is
2414
+ * scoped to a single space). If they don't, this throws — mixing
2415
+ * spaces in a single delegation is not supported by the underlying
2416
+ * Rust create_delegation call and the resulting UCAN would be
2417
+ * under-specified.
2418
+ *
2419
+ * @internal
2420
+ */
2421
+ async createDelegationViaWasmPath(did, entries, expirationTime, session) {
2422
+ if (entries.length === 0) {
2423
+ throw new Error(
2424
+ "createDelegationViaWasmPath requires a non-empty entries array"
2425
+ );
2426
+ }
2427
+ const resolvedSpaces = /* @__PURE__ */ new Set();
2428
+ for (const entry of entries) {
2429
+ const spaceId2 = entry.space === "default" ? session.spaceId : entry.space;
2430
+ resolvedSpaces.add(spaceId2);
2431
+ }
2432
+ if (resolvedSpaces.size !== 1) {
2433
+ throw new Error(
2434
+ `delegateTo: all permission entries must target the same space, got ${resolvedSpaces.size}: ${JSON.stringify([...resolvedSpaces])}`
2435
+ );
2436
+ }
2437
+ const spaceId = [...resolvedSpaces][0];
2438
+ const abilities = {};
2439
+ for (const entry of entries) {
2440
+ const shortService = import_sdk_core5.SERVICE_LONG_TO_SHORT[entry.service];
2441
+ if (shortService === void 0) {
2442
+ throw new Error(
2443
+ `delegateTo: unknown service '${entry.service}' \u2014 no short-form mapping`
2444
+ );
2445
+ }
2446
+ if (abilities[shortService] === void 0) {
2447
+ abilities[shortService] = {};
2448
+ }
2449
+ const pathsMap = abilities[shortService];
2450
+ const existing = pathsMap[entry.path];
2451
+ if (existing === void 0) {
2452
+ pathsMap[entry.path] = [...entry.actions];
2453
+ } else {
2454
+ const seen = new Set(existing);
2455
+ for (const action of entry.actions) {
2456
+ if (!seen.has(action)) {
2457
+ existing.push(action);
2458
+ seen.add(action);
2459
+ }
2460
+ }
2461
+ }
2462
+ }
2463
+ const serviceSession = {
2464
+ delegationHeader: session.delegationHeader,
2465
+ delegationCid: session.delegationCid,
2466
+ jwk: session.jwk,
2467
+ spaceId,
2468
+ verificationMethod: session.verificationMethod
2469
+ };
2470
+ const expirationSecs = Math.floor(expirationTime.getTime() / 1e3);
2471
+ const result = this.createDelegationWrapper({
2472
+ session: serviceSession,
2473
+ delegateDID: did,
2474
+ spaceId,
2475
+ abilities,
2476
+ expirationSecs
2477
+ });
2478
+ const primary = result.resources[0];
2479
+ return {
2480
+ cid: result.cid,
2481
+ delegationHeader: { Authorization: `Bearer ${result.delegation}` },
2482
+ spaceId,
2483
+ path: primary.path,
2484
+ actions: primary.actions,
2485
+ resources: result.resources,
2486
+ disableSubDelegation: false,
2487
+ expiry: result.expiry,
2488
+ delegateDID: did,
2489
+ ownerAddress: session.address,
2490
+ chainId: session.chainId,
2491
+ host: this.config.host
2492
+ };
2493
+ }
2494
+ /**
2495
+ * Issue a delegation via the legacy wallet-signed SIWE path for a single
2496
+ * {@link PermissionEntry}. Shares the implementation with the public
2497
+ * `createDelegation` method via {@link createDelegationWalletPath} so
2498
+ * both entry points hit exactly the same SIWE / signer / public-space
2499
+ * logic without mutual recursion.
2500
+ *
2501
+ * @internal
2502
+ */
2503
+ async createDelegationLegacyWalletPath(delegateDID, entry, expirationTime) {
2504
+ const spaceIdOverride = entry.space === "default" ? void 0 : entry.space;
2505
+ return this.createDelegationWalletPath({
2506
+ path: entry.path,
2507
+ actions: entry.actions,
2508
+ delegateDID,
2509
+ includePublicSpace: true,
2510
+ expiryMs: Math.max(0, expirationTime.getTime() - Date.now()),
2511
+ spaceIdOverride
2512
+ });
2513
+ }
2156
2514
  /**
2157
2515
  * Create a delegation from this user to another user.
2158
2516
  *
@@ -2163,6 +2521,49 @@ var TinyCloudNode = class _TinyCloudNode {
2163
2521
  * @returns A portable delegation that can be sent to the recipient
2164
2522
  */
2165
2523
  async createDelegation(params) {
2524
+ if (!this.signer) {
2525
+ throw new Error("Cannot createDelegation() in session-only mode. Requires wallet mode.");
2526
+ }
2527
+ if (!this.auth?.tinyCloudSession) {
2528
+ throw new Error("Not signed in. Call signIn() first.");
2529
+ }
2530
+ let resolvedDelegateDID = params.delegateDID;
2531
+ if (resolvedDelegateDID.endsWith(".eth") && this.config.ensResolver) {
2532
+ const address = await this.config.ensResolver.resolveAddress(resolvedDelegateDID);
2533
+ if (!address) throw new Error(`Could not resolve ENS name: ${resolvedDelegateDID}`);
2534
+ resolvedDelegateDID = `did:pkh:eip155:1:${address}`;
2535
+ }
2536
+ const entries = legacyParamsToPermissionEntries(
2537
+ params.actions,
2538
+ params.path,
2539
+ params.spaceIdOverride
2540
+ );
2541
+ try {
2542
+ const result = await this.delegateTo(
2543
+ resolvedDelegateDID,
2544
+ entries,
2545
+ params.expiryMs !== void 0 ? { expiry: params.expiryMs } : void 0
2546
+ );
2547
+ return result.delegation;
2548
+ } catch (err) {
2549
+ if (err instanceof import_sdk_core5.PermissionNotInManifestError) {
2550
+ } else {
2551
+ throw err;
2552
+ }
2553
+ }
2554
+ return this.createDelegationWalletPath({
2555
+ ...params,
2556
+ delegateDID: resolvedDelegateDID
2557
+ });
2558
+ }
2559
+ /**
2560
+ * Legacy wallet-signed SIWE delegation path. Lifted from the original
2561
+ * `createDelegation` body verbatim so both the legacy public method and
2562
+ * `delegateTo({ forceWalletSign: true })` hit the same code.
2563
+ *
2564
+ * @internal
2565
+ */
2566
+ async createDelegationWalletPath(params) {
2166
2567
  if (!this.signer) {
2167
2568
  throw new Error("Cannot createDelegation() in session-only mode. Requires wallet mode.");
2168
2569
  }
@@ -2170,11 +2571,6 @@ var TinyCloudNode = class _TinyCloudNode {
2170
2571
  if (!session) {
2171
2572
  throw new Error("Not signed in. Call signIn() first.");
2172
2573
  }
2173
- if (params.delegateDID.endsWith(".eth") && this.config.ensResolver) {
2174
- const address = await this.config.ensResolver.resolveAddress(params.delegateDID);
2175
- if (!address) throw new Error(`Could not resolve ENS name: ${params.delegateDID}`);
2176
- params = { ...params, delegateDID: `did:pkh:eip155:1:${address}` };
2177
- }
2178
2574
  const abilities = {};
2179
2575
  const kvActions = params.actions.filter((a) => a.startsWith("tinycloud.kv/"));
2180
2576
  const sqlActions = params.actions.filter((a) => a.startsWith("tinycloud.sql/"));
@@ -2207,7 +2603,7 @@ var TinyCloudNode = class _TinyCloudNode {
2207
2603
  ...prepared,
2208
2604
  signature
2209
2605
  });
2210
- const activateResult = await (0, import_sdk_core4.activateSessionWithHost)(
2606
+ const activateResult = await (0, import_sdk_core5.activateSessionWithHost)(
2211
2607
  this.config.host,
2212
2608
  delegationSession.delegationHeader
2213
2609
  );
@@ -2229,7 +2625,7 @@ var TinyCloudNode = class _TinyCloudNode {
2229
2625
  };
2230
2626
  const hasKvActions = params.actions.some((a) => a.startsWith("tinycloud.kv/"));
2231
2627
  if (hasKvActions && params.includePublicSpace !== false) {
2232
- const publicSpaceId = (0, import_sdk_core4.makePublicSpaceId)(
2628
+ const publicSpaceId = (0, import_sdk_core5.makePublicSpaceId)(
2233
2629
  this.wasmBindings.ensureEip55(session.address),
2234
2630
  session.chainId
2235
2631
  );
@@ -2252,7 +2648,7 @@ var TinyCloudNode = class _TinyCloudNode {
2252
2648
  ...publicPrepared,
2253
2649
  signature: publicSignature
2254
2650
  });
2255
- const publicActivateResult = await (0, import_sdk_core4.activateSessionWithHost)(
2651
+ const publicActivateResult = await (0, import_sdk_core5.activateSessionWithHost)(
2256
2652
  this.config.host,
2257
2653
  publicSession.delegationHeader
2258
2654
  );
@@ -2351,7 +2747,7 @@ var TinyCloudNode = class _TinyCloudNode {
2351
2747
  ...prepared,
2352
2748
  signature
2353
2749
  });
2354
- const activateResult = await (0, import_sdk_core4.activateSessionWithHost)(
2750
+ const activateResult = await (0, import_sdk_core5.activateSessionWithHost)(
2355
2751
  targetHost,
2356
2752
  invokerSession.delegationHeader
2357
2753
  );
@@ -2440,7 +2836,7 @@ var TinyCloudNode = class _TinyCloudNode {
2440
2836
  ...prepared,
2441
2837
  signature
2442
2838
  });
2443
- const activateResult = await (0, import_sdk_core4.activateSessionWithHost)(
2839
+ const activateResult = await (0, import_sdk_core5.activateSessionWithHost)(
2444
2840
  targetHost,
2445
2841
  subDelegationSession.delegationHeader
2446
2842
  );
@@ -2462,6 +2858,21 @@ var TinyCloudNode = class _TinyCloudNode {
2462
2858
  };
2463
2859
  }
2464
2860
  };
2861
+ // ===========================================================================
2862
+ // Capability-chain delegation (spec: .claude/specs/capability-chain.md)
2863
+ // ===========================================================================
2864
+ /**
2865
+ * Safety margin before the session's own expiry at which {@link delegateTo}
2866
+ * will refuse to issue a derived delegation. Prevents issuing sub-delegations
2867
+ * that would be invalid by the time the recipient used them. Spec: 60 seconds.
2868
+ *
2869
+ * @internal
2870
+ */
2871
+ _TinyCloudNode.SESSION_EXPIRY_SAFETY_MARGIN_MS = 6e4;
2872
+ var TinyCloudNode = _TinyCloudNode;
2873
+
2874
+ // src/core.ts
2875
+ var import_sdk_core8 = require("@tinycloud/sdk-core");
2465
2876
 
2466
2877
  // src/delegation.ts
2467
2878
  function serializeDelegation(delegation) {
@@ -2480,8 +2891,6 @@ function deserializeDelegation(data) {
2480
2891
  }
2481
2892
 
2482
2893
  // src/core.ts
2483
- var import_sdk_core7 = require("@tinycloud/sdk-core");
2484
- var import_sdk_core8 = require("@tinycloud/sdk-core");
2485
2894
  var import_sdk_core9 = require("@tinycloud/sdk-core");
2486
2895
  var import_sdk_core10 = require("@tinycloud/sdk-core");
2487
2896
  var import_sdk_core11 = require("@tinycloud/sdk-core");
@@ -2489,6 +2898,8 @@ var import_sdk_core12 = require("@tinycloud/sdk-core");
2489
2898
  var import_sdk_core13 = require("@tinycloud/sdk-core");
2490
2899
  var import_sdk_core14 = require("@tinycloud/sdk-core");
2491
2900
  var import_sdk_core15 = require("@tinycloud/sdk-core");
2901
+ var import_sdk_core16 = require("@tinycloud/sdk-core");
2902
+ var import_sdk_core17 = require("@tinycloud/sdk-core");
2492
2903
  // Annotate the CommonJS export names for ESM import in node:
2493
2904
  0 && (module.exports = {
2494
2905
  AutoApproveSpaceCreationHandler,
@@ -2504,13 +2915,16 @@ var import_sdk_core15 = require("@tinycloud/sdk-core");
2504
2915
  DuckDbService,
2505
2916
  FileSessionStorage,
2506
2917
  KVService,
2918
+ ManifestValidationError,
2507
2919
  MemorySessionStorage,
2508
2920
  NodeUserAuthorization,
2921
+ PermissionNotInManifestError,
2509
2922
  PrefixedKVService,
2510
2923
  ProtocolMismatchError,
2511
2924
  SQLAction,
2512
2925
  SQLService,
2513
2926
  ServiceContext,
2927
+ SessionExpiredError,
2514
2928
  SharingService,
2515
2929
  SilentNotificationHandler,
2516
2930
  Space,
@@ -2533,8 +2947,14 @@ var import_sdk_core15 = require("@tinycloud/sdk-core");
2533
2947
  defaultSignStrategy,
2534
2948
  defaultSpaceCreationHandler,
2535
2949
  deserializeDelegation,
2950
+ expandActionShortNames,
2951
+ isCapabilitySubset,
2952
+ loadManifest,
2536
2953
  makePublicSpaceId,
2954
+ parseExpiry,
2537
2955
  parseSpaceUri,
2538
- serializeDelegation
2956
+ resolveManifest,
2957
+ serializeDelegation,
2958
+ validateManifest
2539
2959
  });
2540
2960
  //# sourceMappingURL=core.cjs.map