@tinycloud/node-sdk 2.0.4 → 2.1.0-beta.1
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 +428 -93
- package/dist/core.cjs.map +1 -1
- package/dist/core.d.cts +102 -3
- package/dist/core.d.ts +102 -3
- package/dist/core.js +363 -17
- package/dist/core.js.map +1 -1
- package/dist/index.cjs +435 -95
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +5 -3
- package/dist/index.d.ts +5 -3
- package/dist/index.js +380 -19
- package/dist/index.js.map +1 -1
- package/package.json +5 -4
package/dist/core.js
CHANGED
|
@@ -253,12 +253,22 @@ var NodeUserAuthorization = class {
|
|
|
253
253
|
},
|
|
254
254
|
capabilities: {
|
|
255
255
|
"": ["tinycloud.capabilities/read"]
|
|
256
|
+
},
|
|
257
|
+
hooks: {
|
|
258
|
+
"": [
|
|
259
|
+
"tinycloud.hooks/subscribe",
|
|
260
|
+
"tinycloud.hooks/register",
|
|
261
|
+
"tinycloud.hooks/list",
|
|
262
|
+
"tinycloud.hooks/unregister"
|
|
263
|
+
]
|
|
256
264
|
}
|
|
257
265
|
};
|
|
258
266
|
this.sessionExpirationMs = config.sessionExpirationMs ?? 60 * 60 * 1e3;
|
|
259
267
|
this.autoCreateSpace = config.autoCreateSpace ?? false;
|
|
260
268
|
this.spaceCreationHandler = config.spaceCreationHandler;
|
|
261
|
-
this.tinycloudHosts = config.tinycloudHosts ?? [
|
|
269
|
+
this.tinycloudHosts = config.tinycloudHosts ?? [
|
|
270
|
+
"https://node.tinycloud.xyz"
|
|
271
|
+
];
|
|
262
272
|
this.enablePublicSpace = config.enablePublicSpace ?? true;
|
|
263
273
|
this.nonce = config.nonce;
|
|
264
274
|
this.siweConfig = config.siweConfig;
|
|
@@ -398,7 +408,10 @@ var NodeUserAuthorization = class {
|
|
|
398
408
|
throw err;
|
|
399
409
|
}
|
|
400
410
|
} catch (error) {
|
|
401
|
-
handler.onSpaceCreationFailed?.(
|
|
411
|
+
handler.onSpaceCreationFailed?.(
|
|
412
|
+
creationContext,
|
|
413
|
+
error instanceof Error ? error : new Error(String(error))
|
|
414
|
+
);
|
|
402
415
|
throw error;
|
|
403
416
|
}
|
|
404
417
|
await new Promise((resolve) => setTimeout(resolve, 100));
|
|
@@ -432,7 +445,10 @@ var NodeUserAuthorization = class {
|
|
|
432
445
|
throw err;
|
|
433
446
|
}
|
|
434
447
|
} catch (error) {
|
|
435
|
-
handler.onSpaceCreationFailed?.(
|
|
448
|
+
handler.onSpaceCreationFailed?.(
|
|
449
|
+
creationContext,
|
|
450
|
+
error instanceof Error ? error : new Error(String(error))
|
|
451
|
+
);
|
|
436
452
|
throw error;
|
|
437
453
|
}
|
|
438
454
|
await new Promise((resolve) => setTimeout(resolve, 100));
|
|
@@ -541,7 +557,10 @@ var NodeUserAuthorization = class {
|
|
|
541
557
|
this._tinyCloudSession = tinyCloudSession;
|
|
542
558
|
this._address = address;
|
|
543
559
|
this._chainId = chainId;
|
|
544
|
-
const nodeInfo = await checkNodeInfo(
|
|
560
|
+
const nodeInfo = await checkNodeInfo(
|
|
561
|
+
this.tinycloudHosts[0],
|
|
562
|
+
this.wasm.protocolVersion()
|
|
563
|
+
);
|
|
545
564
|
this._nodeFeatures = nodeInfo.features;
|
|
546
565
|
for (const ext of this.extensions) {
|
|
547
566
|
if (ext.afterSignIn) {
|
|
@@ -701,7 +720,10 @@ var NodeUserAuthorization = class {
|
|
|
701
720
|
this._tinyCloudSession = tinyCloudSession;
|
|
702
721
|
this._address = address;
|
|
703
722
|
this._chainId = chainId;
|
|
704
|
-
const nodeInfo = await checkNodeInfo(
|
|
723
|
+
const nodeInfo = await checkNodeInfo(
|
|
724
|
+
this.tinycloudHosts[0],
|
|
725
|
+
this.wasm.protocolVersion()
|
|
726
|
+
);
|
|
705
727
|
this._nodeFeatures = nodeInfo.features;
|
|
706
728
|
for (const ext of this.extensions) {
|
|
707
729
|
if (ext.afterSignIn) {
|
|
@@ -752,7 +774,9 @@ var NodeUserAuthorization = class {
|
|
|
752
774
|
);
|
|
753
775
|
}
|
|
754
776
|
default:
|
|
755
|
-
throw new Error(
|
|
777
|
+
throw new Error(
|
|
778
|
+
`Unknown sign strategy: ${this.signStrategy.type}`
|
|
779
|
+
);
|
|
756
780
|
}
|
|
757
781
|
}
|
|
758
782
|
/**
|
|
@@ -786,6 +810,7 @@ import {
|
|
|
786
810
|
KVService as KVService2,
|
|
787
811
|
SQLService as SQLService2,
|
|
788
812
|
DuckDbService as DuckDbService2,
|
|
813
|
+
HooksService as HooksService2,
|
|
789
814
|
DataVaultService,
|
|
790
815
|
createVaultCrypto,
|
|
791
816
|
ServiceContext as ServiceContext2,
|
|
@@ -795,12 +820,18 @@ import {
|
|
|
795
820
|
CapabilityKeyRegistry,
|
|
796
821
|
SharingService,
|
|
797
822
|
UnsupportedFeatureError,
|
|
798
|
-
makePublicSpaceId
|
|
823
|
+
makePublicSpaceId,
|
|
824
|
+
PermissionNotInManifestError,
|
|
825
|
+
SessionExpiredError,
|
|
826
|
+
expandActionShortNames,
|
|
827
|
+
isCapabilitySubset,
|
|
828
|
+
parseRecapCapabilities
|
|
799
829
|
} from "@tinycloud/sdk-core";
|
|
800
830
|
|
|
801
831
|
// src/DelegatedAccess.ts
|
|
802
832
|
import {
|
|
803
833
|
KVService,
|
|
834
|
+
HooksService,
|
|
804
835
|
SQLService,
|
|
805
836
|
DuckDbService,
|
|
806
837
|
ServiceContext
|
|
@@ -825,6 +856,9 @@ var DelegatedAccess = class {
|
|
|
825
856
|
this._duckdb = new DuckDbService({});
|
|
826
857
|
this._duckdb.initialize(this._serviceContext);
|
|
827
858
|
this._serviceContext.registerService("duckdb", this._duckdb);
|
|
859
|
+
this._hooks = new HooksService({});
|
|
860
|
+
this._hooks.initialize(this._serviceContext);
|
|
861
|
+
this._serviceContext.registerService("hooks", this._hooks);
|
|
828
862
|
const serviceSession = {
|
|
829
863
|
delegationHeader: session.delegationHeader,
|
|
830
864
|
delegationCid: session.delegationCid,
|
|
@@ -870,6 +904,12 @@ var DelegatedAccess = class {
|
|
|
870
904
|
get duckdb() {
|
|
871
905
|
return this._duckdb;
|
|
872
906
|
}
|
|
907
|
+
/**
|
|
908
|
+
* Hooks write-stream subscriptions on the delegated space.
|
|
909
|
+
*/
|
|
910
|
+
get hooks() {
|
|
911
|
+
return this._hooks;
|
|
912
|
+
}
|
|
873
913
|
};
|
|
874
914
|
|
|
875
915
|
// src/keys/WasmKeyProvider.ts
|
|
@@ -947,9 +987,72 @@ function createWasmKeyProvider(sessionManager) {
|
|
|
947
987
|
return new WasmKeyProvider({ sessionManager });
|
|
948
988
|
}
|
|
949
989
|
|
|
990
|
+
// src/delegateToHelpers.ts
|
|
991
|
+
import {
|
|
992
|
+
parseExpiry,
|
|
993
|
+
SiweMessage
|
|
994
|
+
} from "@tinycloud/sdk-core";
|
|
995
|
+
function legacyParamsToPermissionEntries(actions, path, spaceIdOverride) {
|
|
996
|
+
const byService = /* @__PURE__ */ new Map();
|
|
997
|
+
for (const a of actions) {
|
|
998
|
+
const slashIdx = a.indexOf("/");
|
|
999
|
+
if (slashIdx === -1) {
|
|
1000
|
+
continue;
|
|
1001
|
+
}
|
|
1002
|
+
const service = a.slice(0, slashIdx);
|
|
1003
|
+
if (!service.startsWith("tinycloud.")) {
|
|
1004
|
+
continue;
|
|
1005
|
+
}
|
|
1006
|
+
const list = byService.get(service);
|
|
1007
|
+
if (list === void 0) {
|
|
1008
|
+
byService.set(service, [a]);
|
|
1009
|
+
} else {
|
|
1010
|
+
list.push(a);
|
|
1011
|
+
}
|
|
1012
|
+
}
|
|
1013
|
+
const space = spaceIdOverride ?? "default";
|
|
1014
|
+
const entries = [];
|
|
1015
|
+
for (const [service, actionList] of byService) {
|
|
1016
|
+
entries.push({
|
|
1017
|
+
service,
|
|
1018
|
+
space,
|
|
1019
|
+
path,
|
|
1020
|
+
actions: actionList
|
|
1021
|
+
});
|
|
1022
|
+
}
|
|
1023
|
+
return entries;
|
|
1024
|
+
}
|
|
1025
|
+
function resolveExpiryMs(expiry) {
|
|
1026
|
+
if (expiry === void 0) {
|
|
1027
|
+
return 60 * 60 * 1e3;
|
|
1028
|
+
}
|
|
1029
|
+
if (typeof expiry === "number") {
|
|
1030
|
+
if (!Number.isFinite(expiry) || expiry <= 0) {
|
|
1031
|
+
throw new Error(
|
|
1032
|
+
`delegateTo expiry must be a positive finite number (got ${expiry})`
|
|
1033
|
+
);
|
|
1034
|
+
}
|
|
1035
|
+
return expiry;
|
|
1036
|
+
}
|
|
1037
|
+
return parseExpiry(expiry);
|
|
1038
|
+
}
|
|
1039
|
+
function extractSiweExpiration(siwe) {
|
|
1040
|
+
const parsed = new SiweMessage(siwe);
|
|
1041
|
+
if (parsed.expirationTime === void 0 || parsed.expirationTime === null) {
|
|
1042
|
+
return void 0;
|
|
1043
|
+
}
|
|
1044
|
+
const d = new Date(parsed.expirationTime);
|
|
1045
|
+
if (Number.isNaN(d.getTime())) {
|
|
1046
|
+
throw new Error(
|
|
1047
|
+
`Session SIWE has unparseable expirationTime: ${parsed.expirationTime}`
|
|
1048
|
+
);
|
|
1049
|
+
}
|
|
1050
|
+
return d;
|
|
1051
|
+
}
|
|
1052
|
+
|
|
950
1053
|
// src/TinyCloudNode.ts
|
|
951
1054
|
var DEFAULT_HOST = "https://node.tinycloud.xyz";
|
|
952
|
-
var
|
|
1055
|
+
var _TinyCloudNode = class _TinyCloudNode {
|
|
953
1056
|
/**
|
|
954
1057
|
* Create a new TinyCloudNode instance.
|
|
955
1058
|
*
|
|
@@ -1075,7 +1178,9 @@ var TinyCloudNode = class _TinyCloudNode {
|
|
|
1075
1178
|
nonce: config.nonce,
|
|
1076
1179
|
siweConfig: config.siweConfig
|
|
1077
1180
|
});
|
|
1078
|
-
this.tc = new TinyCloud(this.auth
|
|
1181
|
+
this.tc = new TinyCloud(this.auth, {
|
|
1182
|
+
invokeAny: this.wasmBindings.invokeAny
|
|
1183
|
+
});
|
|
1079
1184
|
}
|
|
1080
1185
|
/**
|
|
1081
1186
|
* Get the primary identity DID for this user.
|
|
@@ -1144,6 +1249,7 @@ var TinyCloudNode = class _TinyCloudNode {
|
|
|
1144
1249
|
this._kv = void 0;
|
|
1145
1250
|
this._sql = void 0;
|
|
1146
1251
|
this._duckdb = void 0;
|
|
1252
|
+
this._hooks = void 0;
|
|
1147
1253
|
this._serviceContext = void 0;
|
|
1148
1254
|
await this.tc.signIn();
|
|
1149
1255
|
this.initializeServices();
|
|
@@ -1163,6 +1269,7 @@ var TinyCloudNode = class _TinyCloudNode {
|
|
|
1163
1269
|
this._kv = void 0;
|
|
1164
1270
|
this._sql = void 0;
|
|
1165
1271
|
this._duckdb = void 0;
|
|
1272
|
+
this._hooks = void 0;
|
|
1166
1273
|
this._serviceContext = void 0;
|
|
1167
1274
|
if (sessionData.address) {
|
|
1168
1275
|
this._address = sessionData.address;
|
|
@@ -1172,6 +1279,7 @@ var TinyCloudNode = class _TinyCloudNode {
|
|
|
1172
1279
|
}
|
|
1173
1280
|
this._serviceContext = new ServiceContext2({
|
|
1174
1281
|
invoke: this.wasmBindings.invoke,
|
|
1282
|
+
invokeAny: this.wasmBindings.invokeAny,
|
|
1175
1283
|
fetch: globalThis.fetch.bind(globalThis),
|
|
1176
1284
|
hosts: [this.config.host]
|
|
1177
1285
|
});
|
|
@@ -1184,6 +1292,9 @@ var TinyCloudNode = class _TinyCloudNode {
|
|
|
1184
1292
|
this._duckdb = new DuckDbService2({});
|
|
1185
1293
|
this._duckdb.initialize(this._serviceContext);
|
|
1186
1294
|
this._serviceContext.registerService("duckdb", this._duckdb);
|
|
1295
|
+
this._hooks = new HooksService2({});
|
|
1296
|
+
this._hooks.initialize(this._serviceContext);
|
|
1297
|
+
this._serviceContext.registerService("hooks", this._hooks);
|
|
1187
1298
|
const serviceSession = {
|
|
1188
1299
|
delegationHeader: sessionData.delegationHeader,
|
|
1189
1300
|
delegationCid: sessionData.delegationCid,
|
|
@@ -1283,7 +1394,9 @@ var TinyCloudNode = class _TinyCloudNode {
|
|
|
1283
1394
|
nonce: this.config.nonce,
|
|
1284
1395
|
siweConfig: this.config.siweConfig
|
|
1285
1396
|
});
|
|
1286
|
-
this.tc = new TinyCloud(this.auth
|
|
1397
|
+
this.tc = new TinyCloud(this.auth, {
|
|
1398
|
+
invokeAny: this.wasmBindings.invokeAny
|
|
1399
|
+
});
|
|
1287
1400
|
this.config.prefix = prefix;
|
|
1288
1401
|
}
|
|
1289
1402
|
/**
|
|
@@ -1321,7 +1434,9 @@ var TinyCloudNode = class _TinyCloudNode {
|
|
|
1321
1434
|
nonce: this.config.nonce,
|
|
1322
1435
|
siweConfig: this.config.siweConfig
|
|
1323
1436
|
});
|
|
1324
|
-
this.tc = new TinyCloud(this.auth
|
|
1437
|
+
this.tc = new TinyCloud(this.auth, {
|
|
1438
|
+
invokeAny: this.wasmBindings.invokeAny
|
|
1439
|
+
});
|
|
1325
1440
|
this.config.prefix = prefix;
|
|
1326
1441
|
}
|
|
1327
1442
|
/**
|
|
@@ -1336,6 +1451,7 @@ var TinyCloudNode = class _TinyCloudNode {
|
|
|
1336
1451
|
this.tc.initializeServices(this.wasmBindings.invoke, [this.config.host]);
|
|
1337
1452
|
this._serviceContext = new ServiceContext2({
|
|
1338
1453
|
invoke: this.wasmBindings.invoke,
|
|
1454
|
+
invokeAny: this.wasmBindings.invokeAny,
|
|
1339
1455
|
fetch: globalThis.fetch.bind(globalThis),
|
|
1340
1456
|
hosts: [this.config.host]
|
|
1341
1457
|
});
|
|
@@ -1353,6 +1469,9 @@ var TinyCloudNode = class _TinyCloudNode {
|
|
|
1353
1469
|
this._duckdb.initialize(this._serviceContext);
|
|
1354
1470
|
this._serviceContext.registerService("duckdb", this._duckdb);
|
|
1355
1471
|
}
|
|
1472
|
+
this._hooks = new HooksService2({});
|
|
1473
|
+
this._hooks.initialize(this._serviceContext);
|
|
1474
|
+
this._serviceContext.registerService("hooks", this._hooks);
|
|
1356
1475
|
const serviceSession = {
|
|
1357
1476
|
delegationHeader: session.delegationHeader,
|
|
1358
1477
|
delegationCid: session.delegationCid,
|
|
@@ -1731,6 +1850,15 @@ var TinyCloudNode = class _TinyCloudNode {
|
|
|
1731
1850
|
}
|
|
1732
1851
|
return this._vault;
|
|
1733
1852
|
}
|
|
1853
|
+
/**
|
|
1854
|
+
* Hooks write stream subscription API.
|
|
1855
|
+
*/
|
|
1856
|
+
get hooks() {
|
|
1857
|
+
if (!this._hooks) {
|
|
1858
|
+
throw new Error("Not signed in. Call signIn() first.");
|
|
1859
|
+
}
|
|
1860
|
+
return this._hooks;
|
|
1861
|
+
}
|
|
1734
1862
|
// ===========================================================================
|
|
1735
1863
|
// v2 Service Accessors
|
|
1736
1864
|
// ===========================================================================
|
|
@@ -2058,6 +2186,150 @@ var TinyCloudNode = class _TinyCloudNode {
|
|
|
2058
2186
|
async checkPermission(path, action) {
|
|
2059
2187
|
return this.delegationManager.checkPermission(path, action);
|
|
2060
2188
|
}
|
|
2189
|
+
/**
|
|
2190
|
+
* Issue a delegation using the capability-chain flow.
|
|
2191
|
+
*
|
|
2192
|
+
* When the requested permissions are a subset of the current session's
|
|
2193
|
+
* recap, the delegation is signed by the session key via WASM — no wallet
|
|
2194
|
+
* prompt. When they are not, a {@link PermissionNotInManifestError} is
|
|
2195
|
+
* raised so the caller can trigger an escalation flow (e.g.
|
|
2196
|
+
* `TinyCloudWeb.requestPermissions`). Passing `forceWalletSign: true`
|
|
2197
|
+
* bypasses the derivability check and always uses the wallet-signed SIWE
|
|
2198
|
+
* path — used by the legacy `createDelegation` fallback and by callers
|
|
2199
|
+
* that want explicit wallet confirmation.
|
|
2200
|
+
*
|
|
2201
|
+
* Current limitation: exactly one {@link PermissionEntry} per call. For
|
|
2202
|
+
* multi-resource delegation, call `delegateTo` multiple times. This keeps
|
|
2203
|
+
* each delegation a single `(spaceId, path)` grant, which matches the
|
|
2204
|
+
* underlying `PortableDelegation` shape.
|
|
2205
|
+
*
|
|
2206
|
+
* @throws {@link SessionExpiredError} when there is no session or the
|
|
2207
|
+
* current session has expired (or will within the 60s safety margin).
|
|
2208
|
+
* @throws {@link PermissionNotInManifestError} when the requested entries
|
|
2209
|
+
* are not a subset of the granted session capabilities and
|
|
2210
|
+
* `forceWalletSign` is not set.
|
|
2211
|
+
*/
|
|
2212
|
+
async delegateTo(did, permissions, options) {
|
|
2213
|
+
const session = this.auth?.tinyCloudSession;
|
|
2214
|
+
if (!session) {
|
|
2215
|
+
throw new SessionExpiredError(/* @__PURE__ */ new Date(0));
|
|
2216
|
+
}
|
|
2217
|
+
const sessionExpiry = extractSiweExpiration(session.siwe);
|
|
2218
|
+
if (sessionExpiry !== void 0) {
|
|
2219
|
+
const now2 = Date.now();
|
|
2220
|
+
const marginMs = _TinyCloudNode.SESSION_EXPIRY_SAFETY_MARGIN_MS;
|
|
2221
|
+
if (sessionExpiry.getTime() <= now2 + marginMs) {
|
|
2222
|
+
throw new SessionExpiredError(sessionExpiry);
|
|
2223
|
+
}
|
|
2224
|
+
}
|
|
2225
|
+
if (!Array.isArray(permissions) || permissions.length === 0) {
|
|
2226
|
+
throw new Error(
|
|
2227
|
+
"delegateTo requires a non-empty permissions array"
|
|
2228
|
+
);
|
|
2229
|
+
}
|
|
2230
|
+
if (permissions.length > 1) {
|
|
2231
|
+
throw new Error(
|
|
2232
|
+
"delegateTo currently supports one permission entry per call. Call delegateTo multiple times for multi-resource delegation."
|
|
2233
|
+
);
|
|
2234
|
+
}
|
|
2235
|
+
const entry = permissions[0];
|
|
2236
|
+
const expandedEntry = {
|
|
2237
|
+
...entry,
|
|
2238
|
+
actions: expandActionShortNames(entry.service, entry.actions)
|
|
2239
|
+
};
|
|
2240
|
+
const now = /* @__PURE__ */ new Date();
|
|
2241
|
+
const expiryMs = resolveExpiryMs(options?.expiry);
|
|
2242
|
+
const expirationTime = new Date(now.getTime() + expiryMs);
|
|
2243
|
+
let effectiveExpiration = expirationTime;
|
|
2244
|
+
if (sessionExpiry !== void 0 && sessionExpiry < expirationTime) {
|
|
2245
|
+
effectiveExpiration = sessionExpiry;
|
|
2246
|
+
}
|
|
2247
|
+
if (options?.forceWalletSign) {
|
|
2248
|
+
const delegation2 = await this.createDelegationLegacyWalletPath(
|
|
2249
|
+
did,
|
|
2250
|
+
expandedEntry,
|
|
2251
|
+
effectiveExpiration
|
|
2252
|
+
);
|
|
2253
|
+
return { delegation: delegation2, prompted: true };
|
|
2254
|
+
}
|
|
2255
|
+
const granted = parseRecapCapabilities(
|
|
2256
|
+
(siwe) => this.wasmBindings.parseRecapFromSiwe(siwe),
|
|
2257
|
+
session.siwe
|
|
2258
|
+
);
|
|
2259
|
+
const requested = [expandedEntry];
|
|
2260
|
+
const { subset, missing } = isCapabilitySubset(requested, granted);
|
|
2261
|
+
if (!subset) {
|
|
2262
|
+
throw new PermissionNotInManifestError(missing, granted);
|
|
2263
|
+
}
|
|
2264
|
+
const delegation = await this.createDelegationViaWasmPath(
|
|
2265
|
+
did,
|
|
2266
|
+
expandedEntry,
|
|
2267
|
+
effectiveExpiration,
|
|
2268
|
+
session
|
|
2269
|
+
);
|
|
2270
|
+
return { delegation, prompted: false };
|
|
2271
|
+
}
|
|
2272
|
+
/**
|
|
2273
|
+
* Issue a delegation via the session-key UCAN WASM path.
|
|
2274
|
+
*
|
|
2275
|
+
* The caller has already verified the request is derivable from the
|
|
2276
|
+
* current session; we just need to shape the inputs for
|
|
2277
|
+
* {@link createDelegationWrapper}.
|
|
2278
|
+
*
|
|
2279
|
+
* @internal
|
|
2280
|
+
*/
|
|
2281
|
+
async createDelegationViaWasmPath(did, entry, expirationTime, session) {
|
|
2282
|
+
const spaceId = entry.space === "default" ? session.spaceId : entry.space;
|
|
2283
|
+
const serviceSession = {
|
|
2284
|
+
delegationHeader: session.delegationHeader,
|
|
2285
|
+
delegationCid: session.delegationCid,
|
|
2286
|
+
jwk: session.jwk,
|
|
2287
|
+
spaceId,
|
|
2288
|
+
verificationMethod: session.verificationMethod
|
|
2289
|
+
};
|
|
2290
|
+
const expirationSecs = Math.floor(expirationTime.getTime() / 1e3);
|
|
2291
|
+
const result = this.createDelegationWrapper({
|
|
2292
|
+
session: serviceSession,
|
|
2293
|
+
delegateDID: did,
|
|
2294
|
+
spaceId,
|
|
2295
|
+
path: entry.path,
|
|
2296
|
+
actions: entry.actions,
|
|
2297
|
+
expirationSecs
|
|
2298
|
+
});
|
|
2299
|
+
return {
|
|
2300
|
+
cid: result.cid,
|
|
2301
|
+
delegationHeader: { Authorization: `Bearer ${result.delegation}` },
|
|
2302
|
+
spaceId,
|
|
2303
|
+
path: entry.path,
|
|
2304
|
+
actions: entry.actions,
|
|
2305
|
+
disableSubDelegation: false,
|
|
2306
|
+
expiry: result.expiry,
|
|
2307
|
+
delegateDID: did,
|
|
2308
|
+
ownerAddress: session.address,
|
|
2309
|
+
chainId: session.chainId,
|
|
2310
|
+
host: this.config.host
|
|
2311
|
+
};
|
|
2312
|
+
}
|
|
2313
|
+
/**
|
|
2314
|
+
* Issue a delegation via the legacy wallet-signed SIWE path for a single
|
|
2315
|
+
* {@link PermissionEntry}. Shares the implementation with the public
|
|
2316
|
+
* `createDelegation` method via {@link createDelegationWalletPath} so
|
|
2317
|
+
* both entry points hit exactly the same SIWE / signer / public-space
|
|
2318
|
+
* logic without mutual recursion.
|
|
2319
|
+
*
|
|
2320
|
+
* @internal
|
|
2321
|
+
*/
|
|
2322
|
+
async createDelegationLegacyWalletPath(delegateDID, entry, expirationTime) {
|
|
2323
|
+
const spaceIdOverride = entry.space === "default" ? void 0 : entry.space;
|
|
2324
|
+
return this.createDelegationWalletPath({
|
|
2325
|
+
path: entry.path,
|
|
2326
|
+
actions: entry.actions,
|
|
2327
|
+
delegateDID,
|
|
2328
|
+
includePublicSpace: true,
|
|
2329
|
+
expiryMs: Math.max(0, expirationTime.getTime() - Date.now()),
|
|
2330
|
+
spaceIdOverride
|
|
2331
|
+
});
|
|
2332
|
+
}
|
|
2061
2333
|
/**
|
|
2062
2334
|
* Create a delegation from this user to another user.
|
|
2063
2335
|
*
|
|
@@ -2068,6 +2340,51 @@ var TinyCloudNode = class _TinyCloudNode {
|
|
|
2068
2340
|
* @returns A portable delegation that can be sent to the recipient
|
|
2069
2341
|
*/
|
|
2070
2342
|
async createDelegation(params) {
|
|
2343
|
+
if (!this.signer) {
|
|
2344
|
+
throw new Error("Cannot createDelegation() in session-only mode. Requires wallet mode.");
|
|
2345
|
+
}
|
|
2346
|
+
if (!this.auth?.tinyCloudSession) {
|
|
2347
|
+
throw new Error("Not signed in. Call signIn() first.");
|
|
2348
|
+
}
|
|
2349
|
+
let resolvedDelegateDID = params.delegateDID;
|
|
2350
|
+
if (resolvedDelegateDID.endsWith(".eth") && this.config.ensResolver) {
|
|
2351
|
+
const address = await this.config.ensResolver.resolveAddress(resolvedDelegateDID);
|
|
2352
|
+
if (!address) throw new Error(`Could not resolve ENS name: ${resolvedDelegateDID}`);
|
|
2353
|
+
resolvedDelegateDID = `did:pkh:eip155:1:${address}`;
|
|
2354
|
+
}
|
|
2355
|
+
const entries = legacyParamsToPermissionEntries(
|
|
2356
|
+
params.actions,
|
|
2357
|
+
params.path,
|
|
2358
|
+
params.spaceIdOverride
|
|
2359
|
+
);
|
|
2360
|
+
if (entries.length === 1) {
|
|
2361
|
+
try {
|
|
2362
|
+
const result = await this.delegateTo(
|
|
2363
|
+
resolvedDelegateDID,
|
|
2364
|
+
[entries[0]],
|
|
2365
|
+
params.expiryMs !== void 0 ? { expiry: params.expiryMs } : void 0
|
|
2366
|
+
);
|
|
2367
|
+
return result.delegation;
|
|
2368
|
+
} catch (err) {
|
|
2369
|
+
if (err instanceof PermissionNotInManifestError) {
|
|
2370
|
+
} else {
|
|
2371
|
+
throw err;
|
|
2372
|
+
}
|
|
2373
|
+
}
|
|
2374
|
+
}
|
|
2375
|
+
return this.createDelegationWalletPath({
|
|
2376
|
+
...params,
|
|
2377
|
+
delegateDID: resolvedDelegateDID
|
|
2378
|
+
});
|
|
2379
|
+
}
|
|
2380
|
+
/**
|
|
2381
|
+
* Legacy wallet-signed SIWE delegation path. Lifted from the original
|
|
2382
|
+
* `createDelegation` body verbatim so both the legacy public method and
|
|
2383
|
+
* `delegateTo({ forceWalletSign: true })` hit the same code.
|
|
2384
|
+
*
|
|
2385
|
+
* @internal
|
|
2386
|
+
*/
|
|
2387
|
+
async createDelegationWalletPath(params) {
|
|
2071
2388
|
if (!this.signer) {
|
|
2072
2389
|
throw new Error("Cannot createDelegation() in session-only mode. Requires wallet mode.");
|
|
2073
2390
|
}
|
|
@@ -2075,11 +2392,6 @@ var TinyCloudNode = class _TinyCloudNode {
|
|
|
2075
2392
|
if (!session) {
|
|
2076
2393
|
throw new Error("Not signed in. Call signIn() first.");
|
|
2077
2394
|
}
|
|
2078
|
-
if (params.delegateDID.endsWith(".eth") && this.config.ensResolver) {
|
|
2079
|
-
const address = await this.config.ensResolver.resolveAddress(params.delegateDID);
|
|
2080
|
-
if (!address) throw new Error(`Could not resolve ENS name: ${params.delegateDID}`);
|
|
2081
|
-
params = { ...params, delegateDID: `did:pkh:eip155:1:${address}` };
|
|
2082
|
-
}
|
|
2083
2395
|
const abilities = {};
|
|
2084
2396
|
const kvActions = params.actions.filter((a) => a.startsWith("tinycloud.kv/"));
|
|
2085
2397
|
const sqlActions = params.actions.filter((a) => a.startsWith("tinycloud.sql/"));
|
|
@@ -2367,6 +2679,31 @@ var TinyCloudNode = class _TinyCloudNode {
|
|
|
2367
2679
|
};
|
|
2368
2680
|
}
|
|
2369
2681
|
};
|
|
2682
|
+
// ===========================================================================
|
|
2683
|
+
// Capability-chain delegation (spec: .claude/specs/capability-chain.md)
|
|
2684
|
+
// ===========================================================================
|
|
2685
|
+
/**
|
|
2686
|
+
* Safety margin before the session's own expiry at which {@link delegateTo}
|
|
2687
|
+
* will refuse to issue a derived delegation. Prevents issuing sub-delegations
|
|
2688
|
+
* that would be invalid by the time the recipient used them. Spec: 60 seconds.
|
|
2689
|
+
*
|
|
2690
|
+
* @internal
|
|
2691
|
+
*/
|
|
2692
|
+
_TinyCloudNode.SESSION_EXPIRY_SAFETY_MARGIN_MS = 6e4;
|
|
2693
|
+
var TinyCloudNode = _TinyCloudNode;
|
|
2694
|
+
|
|
2695
|
+
// src/core.ts
|
|
2696
|
+
import {
|
|
2697
|
+
PermissionNotInManifestError as PermissionNotInManifestError2,
|
|
2698
|
+
SessionExpiredError as SessionExpiredError2,
|
|
2699
|
+
ManifestValidationError,
|
|
2700
|
+
resolveManifest,
|
|
2701
|
+
validateManifest,
|
|
2702
|
+
loadManifest,
|
|
2703
|
+
isCapabilitySubset as isCapabilitySubset2,
|
|
2704
|
+
expandActionShortNames as expandActionShortNames2,
|
|
2705
|
+
parseExpiry as parseExpiry2
|
|
2706
|
+
} from "@tinycloud/sdk-core";
|
|
2370
2707
|
|
|
2371
2708
|
// src/delegation.ts
|
|
2372
2709
|
function serializeDelegation(delegation) {
|
|
@@ -2430,13 +2767,16 @@ export {
|
|
|
2430
2767
|
DuckDbService3 as DuckDbService,
|
|
2431
2768
|
FileSessionStorage,
|
|
2432
2769
|
KVService3 as KVService,
|
|
2770
|
+
ManifestValidationError,
|
|
2433
2771
|
MemorySessionStorage,
|
|
2434
2772
|
NodeUserAuthorization,
|
|
2773
|
+
PermissionNotInManifestError2 as PermissionNotInManifestError,
|
|
2435
2774
|
PrefixedKVService,
|
|
2436
2775
|
ProtocolMismatchError,
|
|
2437
2776
|
SQLAction,
|
|
2438
2777
|
SQLService3 as SQLService,
|
|
2439
2778
|
ServiceContext3 as ServiceContext,
|
|
2779
|
+
SessionExpiredError2 as SessionExpiredError,
|
|
2440
2780
|
SharingService2 as SharingService,
|
|
2441
2781
|
SilentNotificationHandler2 as SilentNotificationHandler,
|
|
2442
2782
|
Space,
|
|
@@ -2459,8 +2799,14 @@ export {
|
|
|
2459
2799
|
defaultSignStrategy,
|
|
2460
2800
|
defaultSpaceCreationHandler,
|
|
2461
2801
|
deserializeDelegation,
|
|
2802
|
+
expandActionShortNames2 as expandActionShortNames,
|
|
2803
|
+
isCapabilitySubset2 as isCapabilitySubset,
|
|
2804
|
+
loadManifest,
|
|
2462
2805
|
makePublicSpaceId2 as makePublicSpaceId,
|
|
2806
|
+
parseExpiry2 as parseExpiry,
|
|
2463
2807
|
parseSpaceUri,
|
|
2464
|
-
|
|
2808
|
+
resolveManifest,
|
|
2809
|
+
serializeDelegation,
|
|
2810
|
+
validateManifest
|
|
2465
2811
|
};
|
|
2466
2812
|
//# sourceMappingURL=core.js.map
|