@tinycloud/node-sdk 2.2.0-beta.1 → 2.2.0-beta.10
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-DcJ27GsA.d.cts +1538 -0
- package/dist/core-DcJ27GsA.d.ts +1538 -0
- package/dist/core.cjs +906 -183
- package/dist/core.cjs.map +1 -1
- package/dist/core.d.cts +4 -1423
- package/dist/core.d.ts +4 -1423
- package/dist/core.js +827 -93
- package/dist/core.js.map +1 -1
- package/dist/index.cjs +909 -186
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +2 -2
- package/dist/index.d.ts +2 -2
- package/dist/index.js +822 -93
- package/dist/index.js.map +1 -1
- package/package.json +4 -4
package/dist/core.js
CHANGED
|
@@ -207,7 +207,8 @@ import {
|
|
|
207
207
|
DEFAULT_MANIFEST_SPACE,
|
|
208
208
|
composeManifestRequest,
|
|
209
209
|
resourceCapabilitiesToAbilitiesMap,
|
|
210
|
-
resourceCapabilitiesToSpaceAbilitiesMap
|
|
210
|
+
resourceCapabilitiesToSpaceAbilitiesMap,
|
|
211
|
+
resolveTinyCloudHosts
|
|
211
212
|
} from "@tinycloud/sdk-core";
|
|
212
213
|
|
|
213
214
|
// src/authorization/strategies.ts
|
|
@@ -270,9 +271,9 @@ var NodeUserAuthorization = class {
|
|
|
270
271
|
this.sessionExpirationMs = config.sessionExpirationMs ?? 60 * 60 * 1e3;
|
|
271
272
|
this.autoCreateSpace = config.autoCreateSpace ?? false;
|
|
272
273
|
this.spaceCreationHandler = config.spaceCreationHandler;
|
|
273
|
-
this.tinycloudHosts = config.tinycloudHosts
|
|
274
|
-
|
|
275
|
-
|
|
274
|
+
this.tinycloudHosts = config.tinycloudHosts;
|
|
275
|
+
this.tinycloudRegistryUrl = config.tinycloudRegistryUrl;
|
|
276
|
+
this.tinycloudFallbackHosts = config.tinycloudFallbackHosts;
|
|
276
277
|
this.enablePublicSpace = config.enablePublicSpace ?? true;
|
|
277
278
|
this.nonce = config.nonce;
|
|
278
279
|
this.siweConfig = config.siweConfig;
|
|
@@ -293,6 +294,9 @@ var NodeUserAuthorization = class {
|
|
|
293
294
|
get capabilityRequest() {
|
|
294
295
|
return this.getCapabilityRequest();
|
|
295
296
|
}
|
|
297
|
+
get hosts() {
|
|
298
|
+
return this.tinycloudHosts ? [...this.tinycloudHosts] : [];
|
|
299
|
+
}
|
|
296
300
|
/**
|
|
297
301
|
* Install or replace the stored manifest. Takes effect on the next
|
|
298
302
|
* `signIn()` call — the current session (if any) is not touched.
|
|
@@ -317,6 +321,26 @@ var NodeUserAuthorization = class {
|
|
|
317
321
|
get tinyCloudSession() {
|
|
318
322
|
return this._tinyCloudSession;
|
|
319
323
|
}
|
|
324
|
+
async resolveTinyCloudHostsForSignIn(address, chainId) {
|
|
325
|
+
if (this.tinycloudHosts && this.tinycloudHosts.length > 0) {
|
|
326
|
+
return;
|
|
327
|
+
}
|
|
328
|
+
const subject = `did:pkh:eip155:${chainId}:${address}`;
|
|
329
|
+
const resolved = await resolveTinyCloudHosts(subject, {
|
|
330
|
+
registryUrl: this.tinycloudRegistryUrl,
|
|
331
|
+
fallbackHosts: this.tinycloudFallbackHosts
|
|
332
|
+
});
|
|
333
|
+
this.tinycloudHosts = resolved.hosts;
|
|
334
|
+
}
|
|
335
|
+
requireTinyCloudHosts() {
|
|
336
|
+
if (!this.tinycloudHosts || this.tinycloudHosts.length === 0) {
|
|
337
|
+
throw new Error("TinyCloud hosts have not been resolved. Call signIn() first.");
|
|
338
|
+
}
|
|
339
|
+
return this.tinycloudHosts;
|
|
340
|
+
}
|
|
341
|
+
get primaryTinyCloudHost() {
|
|
342
|
+
return this.requireTinyCloudHosts()[0];
|
|
343
|
+
}
|
|
320
344
|
get nodeFeatures() {
|
|
321
345
|
return this._nodeFeatures;
|
|
322
346
|
}
|
|
@@ -448,7 +472,7 @@ var NodeUserAuthorization = class {
|
|
|
448
472
|
if (!this._tinyCloudSession || !this._address || !this._chainId) {
|
|
449
473
|
throw new Error("Must be signed in to host space");
|
|
450
474
|
}
|
|
451
|
-
const host = this.
|
|
475
|
+
const host = this.primaryTinyCloudHost;
|
|
452
476
|
const spaceId = targetSpaceId ?? this._tinyCloudSession.spaceId;
|
|
453
477
|
const peerId = await fetchPeerId(host, spaceId);
|
|
454
478
|
const siwe = this.wasm.generateHostSIWEMessage({
|
|
@@ -490,7 +514,7 @@ var NodeUserAuthorization = class {
|
|
|
490
514
|
if (!this._tinyCloudSession) {
|
|
491
515
|
throw new Error("Must be signed in to ensure space exists");
|
|
492
516
|
}
|
|
493
|
-
const host = this.
|
|
517
|
+
const host = this.primaryTinyCloudHost;
|
|
494
518
|
const primarySpaceId = this._tinyCloudSession.spaceId;
|
|
495
519
|
const result = await activateSessionWithHost(
|
|
496
520
|
host,
|
|
@@ -599,6 +623,7 @@ var NodeUserAuthorization = class {
|
|
|
599
623
|
this._chainId = await this.signer.getChainId();
|
|
600
624
|
const address = this.wasm.ensureEip55(this._address);
|
|
601
625
|
const chainId = this._chainId;
|
|
626
|
+
await this.resolveTinyCloudHostsForSignIn(address, chainId);
|
|
602
627
|
const keyId = `session-${Date.now()}`;
|
|
603
628
|
this.sessionManager.renameSessionKeyId("default", keyId);
|
|
604
629
|
const jwkString = this.sessionManager.jwk(keyId);
|
|
@@ -677,7 +702,7 @@ var NodeUserAuthorization = class {
|
|
|
677
702
|
this._address = address;
|
|
678
703
|
this._chainId = chainId;
|
|
679
704
|
const nodeInfo = await checkNodeInfo(
|
|
680
|
-
this.
|
|
705
|
+
this.primaryTinyCloudHost,
|
|
681
706
|
this.wasm.protocolVersion()
|
|
682
707
|
);
|
|
683
708
|
this._nodeFeatures = nodeInfo.features;
|
|
@@ -793,6 +818,7 @@ var NodeUserAuthorization = class {
|
|
|
793
818
|
});
|
|
794
819
|
const address = this.wasm.ensureEip55(await this.signer.getAddress());
|
|
795
820
|
const chainId = await this.signer.getChainId();
|
|
821
|
+
await this.resolveTinyCloudHostsForSignIn(address, chainId);
|
|
796
822
|
const clientSession = {
|
|
797
823
|
address,
|
|
798
824
|
walletAddress: address,
|
|
@@ -842,7 +868,7 @@ var NodeUserAuthorization = class {
|
|
|
842
868
|
this._address = address;
|
|
843
869
|
this._chainId = chainId;
|
|
844
870
|
const nodeInfo = await checkNodeInfo(
|
|
845
|
-
this.
|
|
871
|
+
this.primaryTinyCloudHost,
|
|
846
872
|
this.wasm.protocolVersion()
|
|
847
873
|
);
|
|
848
874
|
this._nodeFeatures = nodeInfo.features;
|
|
@@ -933,6 +959,7 @@ import {
|
|
|
933
959
|
DuckDbService as DuckDbService2,
|
|
934
960
|
HooksService as HooksService2,
|
|
935
961
|
DataVaultService,
|
|
962
|
+
SecretsService,
|
|
936
963
|
createVaultCrypto,
|
|
937
964
|
ServiceContext as ServiceContext2,
|
|
938
965
|
SilentNotificationHandler,
|
|
@@ -945,7 +972,7 @@ import {
|
|
|
945
972
|
ACCOUNT_REGISTRY_SPACE,
|
|
946
973
|
PermissionNotInManifestError,
|
|
947
974
|
SessionExpiredError,
|
|
948
|
-
|
|
975
|
+
expandPermissionEntries as expandPermissionEntriesCore,
|
|
949
976
|
isCapabilitySubset,
|
|
950
977
|
parseRecapCapabilities,
|
|
951
978
|
SERVICE_LONG_TO_SHORT
|
|
@@ -1033,6 +1060,24 @@ var DelegatedAccess = class {
|
|
|
1033
1060
|
get hooks() {
|
|
1034
1061
|
return this._hooks;
|
|
1035
1062
|
}
|
|
1063
|
+
/**
|
|
1064
|
+
* Export the handles needed to rehydrate this activated delegation via
|
|
1065
|
+
* `TinyCloudNode.restoreSession(...)` in another process or after a
|
|
1066
|
+
* restart.
|
|
1067
|
+
*
|
|
1068
|
+
* See `RestorableSession` for lifetime caveats.
|
|
1069
|
+
*/
|
|
1070
|
+
get restorable() {
|
|
1071
|
+
return {
|
|
1072
|
+
delegationHeader: this.session.delegationHeader,
|
|
1073
|
+
delegationCid: this.session.delegationCid,
|
|
1074
|
+
spaceId: this.session.spaceId,
|
|
1075
|
+
jwk: this.session.jwk,
|
|
1076
|
+
verificationMethod: this.session.verificationMethod,
|
|
1077
|
+
address: this.session.address,
|
|
1078
|
+
chainId: this.session.chainId
|
|
1079
|
+
};
|
|
1080
|
+
}
|
|
1036
1081
|
};
|
|
1037
1082
|
|
|
1038
1083
|
// src/keys/WasmKeyProvider.ts
|
|
@@ -1173,6 +1218,152 @@ function extractSiweExpiration(siwe) {
|
|
|
1173
1218
|
return d;
|
|
1174
1219
|
}
|
|
1175
1220
|
|
|
1221
|
+
// src/NodeSecretsService.ts
|
|
1222
|
+
import {
|
|
1223
|
+
ErrorCodes,
|
|
1224
|
+
resolveSecretPath,
|
|
1225
|
+
resolveManifest
|
|
1226
|
+
} from "@tinycloud/sdk-core";
|
|
1227
|
+
var SECRETS_SPACE = "secrets";
|
|
1228
|
+
function ok() {
|
|
1229
|
+
return { ok: true, data: void 0 };
|
|
1230
|
+
}
|
|
1231
|
+
function secretsError(code, message, cause) {
|
|
1232
|
+
return {
|
|
1233
|
+
ok: false,
|
|
1234
|
+
error: {
|
|
1235
|
+
code,
|
|
1236
|
+
service: "secrets",
|
|
1237
|
+
message,
|
|
1238
|
+
...cause ? { cause } : {}
|
|
1239
|
+
}
|
|
1240
|
+
};
|
|
1241
|
+
}
|
|
1242
|
+
function displayActionUrn(action) {
|
|
1243
|
+
return action === "put" ? "tinycloud.vault/write" : "tinycloud.vault/delete";
|
|
1244
|
+
}
|
|
1245
|
+
function kvActionUrn(action) {
|
|
1246
|
+
return `tinycloud.kv/${action}`;
|
|
1247
|
+
}
|
|
1248
|
+
function vaultMutationAction(action) {
|
|
1249
|
+
return action === "put" ? "write" : "delete";
|
|
1250
|
+
}
|
|
1251
|
+
function secretPermissionEntries(name, options, action) {
|
|
1252
|
+
const secretPath = resolveSecretPath(name, options);
|
|
1253
|
+
return [
|
|
1254
|
+
{
|
|
1255
|
+
service: "tinycloud.vault",
|
|
1256
|
+
space: SECRETS_SPACE,
|
|
1257
|
+
path: secretPath.vaultKey,
|
|
1258
|
+
actions: [vaultMutationAction(action)],
|
|
1259
|
+
skipPrefix: true
|
|
1260
|
+
}
|
|
1261
|
+
];
|
|
1262
|
+
}
|
|
1263
|
+
function isSecretsSpace(space) {
|
|
1264
|
+
return space === SECRETS_SPACE || space.endsWith(`:${SECRETS_SPACE}`);
|
|
1265
|
+
}
|
|
1266
|
+
var NodeSecretsService = class {
|
|
1267
|
+
constructor(config) {
|
|
1268
|
+
this.config = config;
|
|
1269
|
+
this.shouldRestoreUnlock = false;
|
|
1270
|
+
}
|
|
1271
|
+
get vault() {
|
|
1272
|
+
return this.service.vault;
|
|
1273
|
+
}
|
|
1274
|
+
get isUnlocked() {
|
|
1275
|
+
return this.service.isUnlocked;
|
|
1276
|
+
}
|
|
1277
|
+
async unlock(signer) {
|
|
1278
|
+
const effectiveSigner = signer ?? this.config.getUnlockSigner?.();
|
|
1279
|
+
if (effectiveSigner !== void 0) {
|
|
1280
|
+
this.unlockSigner = effectiveSigner;
|
|
1281
|
+
}
|
|
1282
|
+
const result = await this.service.unlock(effectiveSigner);
|
|
1283
|
+
if (result.ok) {
|
|
1284
|
+
this.shouldRestoreUnlock = true;
|
|
1285
|
+
}
|
|
1286
|
+
return result;
|
|
1287
|
+
}
|
|
1288
|
+
lock() {
|
|
1289
|
+
this.shouldRestoreUnlock = false;
|
|
1290
|
+
this.service.lock();
|
|
1291
|
+
}
|
|
1292
|
+
get(name, options) {
|
|
1293
|
+
return options === void 0 ? this.service.get(name) : this.service.get(name, options);
|
|
1294
|
+
}
|
|
1295
|
+
async put(name, value, options) {
|
|
1296
|
+
const permission = await this.ensureMutationPermission(name, options, "put");
|
|
1297
|
+
if (!permission.ok) return permission;
|
|
1298
|
+
return options === void 0 ? this.service.put(name, value) : this.service.put(name, value, options);
|
|
1299
|
+
}
|
|
1300
|
+
async delete(name, options) {
|
|
1301
|
+
const permission = await this.ensureMutationPermission(name, options, "del");
|
|
1302
|
+
if (!permission.ok) return permission;
|
|
1303
|
+
return options === void 0 ? this.service.delete(name) : this.service.delete(name, options);
|
|
1304
|
+
}
|
|
1305
|
+
list(options) {
|
|
1306
|
+
return options === void 0 ? this.service.list() : this.service.list(options);
|
|
1307
|
+
}
|
|
1308
|
+
get service() {
|
|
1309
|
+
return this.config.getService();
|
|
1310
|
+
}
|
|
1311
|
+
async ensureMutationPermission(name, options, action) {
|
|
1312
|
+
let permissionEntries;
|
|
1313
|
+
try {
|
|
1314
|
+
permissionEntries = secretPermissionEntries(name, options, action);
|
|
1315
|
+
} catch (error) {
|
|
1316
|
+
return secretsError(
|
|
1317
|
+
ErrorCodes.INVALID_INPUT,
|
|
1318
|
+
error instanceof Error ? error.message : String(error),
|
|
1319
|
+
error instanceof Error ? error : void 0
|
|
1320
|
+
);
|
|
1321
|
+
}
|
|
1322
|
+
if (this.hasMutationPermission(name, options, action)) {
|
|
1323
|
+
return ok();
|
|
1324
|
+
}
|
|
1325
|
+
if (!this.config.canEscalate()) {
|
|
1326
|
+
return secretsError(
|
|
1327
|
+
ErrorCodes.PERMISSION_DENIED,
|
|
1328
|
+
`Cannot autosign ${displayActionUrn(action)} for ${name}; TinyCloudNode needs wallet mode with a signer or privateKey.`
|
|
1329
|
+
);
|
|
1330
|
+
}
|
|
1331
|
+
try {
|
|
1332
|
+
await this.config.grantPermissions(permissionEntries);
|
|
1333
|
+
return this.restoreUnlockAfterEscalation();
|
|
1334
|
+
} catch (error) {
|
|
1335
|
+
return secretsError(
|
|
1336
|
+
ErrorCodes.PERMISSION_DENIED,
|
|
1337
|
+
error instanceof Error ? error.message : `Autosign escalation for ${displayActionUrn(action)} on ${name} failed.`,
|
|
1338
|
+
error instanceof Error ? error : void 0
|
|
1339
|
+
);
|
|
1340
|
+
}
|
|
1341
|
+
}
|
|
1342
|
+
async restoreUnlockAfterEscalation() {
|
|
1343
|
+
if (!this.shouldRestoreUnlock) {
|
|
1344
|
+
return ok();
|
|
1345
|
+
}
|
|
1346
|
+
return this.service.unlock(this.unlockSigner);
|
|
1347
|
+
}
|
|
1348
|
+
hasMutationPermission(name, options, action) {
|
|
1349
|
+
const manifest = this.config.getManifest();
|
|
1350
|
+
if (manifest === void 0) {
|
|
1351
|
+
return false;
|
|
1352
|
+
}
|
|
1353
|
+
const manifests = Array.isArray(manifest) ? manifest : [manifest];
|
|
1354
|
+
const requiredAction = kvActionUrn(action);
|
|
1355
|
+
const secretPath = resolveSecretPath(name, options);
|
|
1356
|
+
return manifests.some((entry) => {
|
|
1357
|
+
const resolved = resolveManifest(entry);
|
|
1358
|
+
return ["keys", "vault"].every(
|
|
1359
|
+
(base) => resolved.resources.some(
|
|
1360
|
+
(resource) => resource.service === "tinycloud.kv" && isSecretsSpace(resource.space) && resource.path === secretPath.permissionPaths[base] && resource.actions.includes(requiredAction)
|
|
1361
|
+
)
|
|
1362
|
+
);
|
|
1363
|
+
});
|
|
1364
|
+
}
|
|
1365
|
+
};
|
|
1366
|
+
|
|
1176
1367
|
// src/TinyCloudNode.ts
|
|
1177
1368
|
var DEFAULT_HOST = "https://node.tinycloud.xyz";
|
|
1178
1369
|
var _TinyCloudNode = class _TinyCloudNode {
|
|
@@ -1204,6 +1395,31 @@ var _TinyCloudNode = class _TinyCloudNode {
|
|
|
1204
1395
|
this.auth = null;
|
|
1205
1396
|
this.tc = null;
|
|
1206
1397
|
this._chainId = 1;
|
|
1398
|
+
this.runtimePermissionGrants = [];
|
|
1399
|
+
this.invokeWithRuntimePermissions = (session, service, path, action, facts) => {
|
|
1400
|
+
return this.wasmBindings.invoke(
|
|
1401
|
+
this.selectInvocationSession(session, service, path, action),
|
|
1402
|
+
service,
|
|
1403
|
+
path,
|
|
1404
|
+
action,
|
|
1405
|
+
facts
|
|
1406
|
+
);
|
|
1407
|
+
};
|
|
1408
|
+
this.invokeAnyWithRuntimePermissions = (session, entries, facts) => {
|
|
1409
|
+
if (!this.wasmBindings.invokeAny) {
|
|
1410
|
+
throw new Error("WASM binding does not support invokeAny");
|
|
1411
|
+
}
|
|
1412
|
+
const grant = this.findGrantForOperations(
|
|
1413
|
+
entries.map((entry) => ({
|
|
1414
|
+
spaceId: entry.spaceId,
|
|
1415
|
+
service: this.invocationServiceName(entry.service),
|
|
1416
|
+
path: entry.path,
|
|
1417
|
+
action: entry.action
|
|
1418
|
+
}))
|
|
1419
|
+
);
|
|
1420
|
+
return this.wasmBindings.invokeAny(grant?.session ?? session, entries, facts);
|
|
1421
|
+
};
|
|
1422
|
+
this.explicitHost = config.host;
|
|
1207
1423
|
this.config = {
|
|
1208
1424
|
...config,
|
|
1209
1425
|
host: config.host ?? DEFAULT_HOST
|
|
@@ -1238,7 +1454,7 @@ var _TinyCloudNode = class _TinyCloudNode {
|
|
|
1238
1454
|
this._sharingService = new SharingService({
|
|
1239
1455
|
hosts: [this.config.host],
|
|
1240
1456
|
// session: undefined - not needed for receive()
|
|
1241
|
-
invoke: this.
|
|
1457
|
+
invoke: this.invokeWithRuntimePermissions,
|
|
1242
1458
|
fetch: globalThis.fetch.bind(globalThis),
|
|
1243
1459
|
keyProvider: this._keyProvider,
|
|
1244
1460
|
registry: this._capabilityRegistry,
|
|
@@ -1285,7 +1501,6 @@ var _TinyCloudNode = class _TinyCloudNode {
|
|
|
1285
1501
|
* @internal
|
|
1286
1502
|
*/
|
|
1287
1503
|
setupAuth(config) {
|
|
1288
|
-
const host = this.config.host;
|
|
1289
1504
|
this.auth = new NodeUserAuthorization({
|
|
1290
1505
|
signer: this.signer,
|
|
1291
1506
|
signStrategy: { type: "auto-sign" },
|
|
@@ -1294,7 +1509,9 @@ var _TinyCloudNode = class _TinyCloudNode {
|
|
|
1294
1509
|
domain: this.siweDomain,
|
|
1295
1510
|
spacePrefix: config.prefix,
|
|
1296
1511
|
sessionExpirationMs: config.sessionExpirationMs ?? 60 * 60 * 1e3,
|
|
1297
|
-
tinycloudHosts: [
|
|
1512
|
+
tinycloudHosts: this.explicitHost ? [this.explicitHost] : void 0,
|
|
1513
|
+
tinycloudRegistryUrl: config.tinycloudRegistryUrl,
|
|
1514
|
+
tinycloudFallbackHosts: config.tinycloudFallbackHosts,
|
|
1298
1515
|
autoCreateSpace: config.autoCreateSpace,
|
|
1299
1516
|
enablePublicSpace: config.enablePublicSpace ?? true,
|
|
1300
1517
|
spaceCreationHandler: config.spaceCreationHandler,
|
|
@@ -1305,9 +1522,15 @@ var _TinyCloudNode = class _TinyCloudNode {
|
|
|
1305
1522
|
includeAccountRegistryPermissions: config.includeAccountRegistryPermissions
|
|
1306
1523
|
});
|
|
1307
1524
|
this.tc = new TinyCloud(this.auth, {
|
|
1308
|
-
invokeAny: this.
|
|
1525
|
+
invokeAny: this.invokeAnyWithRuntimePermissions
|
|
1309
1526
|
});
|
|
1310
1527
|
}
|
|
1528
|
+
syncResolvedHostFromAuth() {
|
|
1529
|
+
const host = this.auth?.hosts[0];
|
|
1530
|
+
if (host) {
|
|
1531
|
+
this.config.host = host;
|
|
1532
|
+
}
|
|
1533
|
+
}
|
|
1311
1534
|
/**
|
|
1312
1535
|
* Install or replace the manifest that drives the SIWE recap at
|
|
1313
1536
|
* sign-in. Takes effect on the next `signIn()` call — the current
|
|
@@ -1345,6 +1568,10 @@ var _TinyCloudNode = class _TinyCloudNode {
|
|
|
1345
1568
|
get capabilityRequest() {
|
|
1346
1569
|
return this.auth?.capabilityRequest;
|
|
1347
1570
|
}
|
|
1571
|
+
get hosts() {
|
|
1572
|
+
const authHosts = this.auth?.hosts ?? [];
|
|
1573
|
+
return authHosts.length > 0 ? authHosts : [this.config.host];
|
|
1574
|
+
}
|
|
1348
1575
|
/**
|
|
1349
1576
|
* Get the primary identity DID for this user.
|
|
1350
1577
|
* - If wallet connected and signed in: returns PKH DID (did:pkh:eip155:{chainId}:{address})
|
|
@@ -1415,8 +1642,14 @@ var _TinyCloudNode = class _TinyCloudNode {
|
|
|
1415
1642
|
this._sql = void 0;
|
|
1416
1643
|
this._duckdb = void 0;
|
|
1417
1644
|
this._hooks = void 0;
|
|
1645
|
+
this._vault = void 0;
|
|
1646
|
+
this._baseSecrets = void 0;
|
|
1647
|
+
this._secrets = void 0;
|
|
1648
|
+
this._spaceService = void 0;
|
|
1418
1649
|
this._serviceContext = void 0;
|
|
1650
|
+
this.runtimePermissionGrants = [];
|
|
1419
1651
|
await this.tc.signIn(options);
|
|
1652
|
+
this.syncResolvedHostFromAuth();
|
|
1420
1653
|
this.initializeServices();
|
|
1421
1654
|
await this.writeManifestRegistryRecords();
|
|
1422
1655
|
this.notificationHandler.success("Successfully signed in");
|
|
@@ -1436,7 +1669,7 @@ var _TinyCloudNode = class _TinyCloudNode {
|
|
|
1436
1669
|
throw new Error("Manifest registry write requires wallet mode");
|
|
1437
1670
|
}
|
|
1438
1671
|
const accountSpaceId = this.ownedSpaceId(ACCOUNT_REGISTRY_SPACE);
|
|
1439
|
-
await this.
|
|
1672
|
+
await this.ensureOwnedSpaceHosted(accountSpaceId);
|
|
1440
1673
|
const accountKV = this.spaces.get(accountSpaceId).kv;
|
|
1441
1674
|
for (const record of request.registryRecords) {
|
|
1442
1675
|
const result = await accountKV.put(record.key, {
|
|
@@ -1451,6 +1684,39 @@ var _TinyCloudNode = class _TinyCloudNode {
|
|
|
1451
1684
|
}
|
|
1452
1685
|
}
|
|
1453
1686
|
}
|
|
1687
|
+
async ensureOwnedSpaceHosted(spaceId) {
|
|
1688
|
+
if (!this.auth) {
|
|
1689
|
+
throw new Error("Owned space hosting requires wallet mode");
|
|
1690
|
+
}
|
|
1691
|
+
const session = this.auth.tinyCloudSession;
|
|
1692
|
+
if (!session) {
|
|
1693
|
+
throw new Error("Owned space hosting requires an active session");
|
|
1694
|
+
}
|
|
1695
|
+
const host = this.hosts[0] ?? this.config.host;
|
|
1696
|
+
if (!host) {
|
|
1697
|
+
throw new Error("Owned space hosting requires a TinyCloud host");
|
|
1698
|
+
}
|
|
1699
|
+
const activation = await activateSessionWithHost2(host, session.delegationHeader);
|
|
1700
|
+
if (activation.success && !activation.skipped?.includes(spaceId)) {
|
|
1701
|
+
return;
|
|
1702
|
+
}
|
|
1703
|
+
if (!activation.success && activation.status !== 404) {
|
|
1704
|
+
throw new Error(
|
|
1705
|
+
`Failed to check owned space ${spaceId}: ${activation.error ?? activation.status}`
|
|
1706
|
+
);
|
|
1707
|
+
}
|
|
1708
|
+
const created = await this.auth.hostOwnedSpace(spaceId);
|
|
1709
|
+
if (!created) {
|
|
1710
|
+
throw new Error(`Failed to create owned space: ${spaceId}`);
|
|
1711
|
+
}
|
|
1712
|
+
await new Promise((resolve) => setTimeout(resolve, 100));
|
|
1713
|
+
const retry = await activateSessionWithHost2(host, session.delegationHeader);
|
|
1714
|
+
if (!retry.success || retry.skipped?.includes(spaceId)) {
|
|
1715
|
+
throw new Error(
|
|
1716
|
+
`Failed to activate session after creating owned space ${spaceId}: ${retry.error ?? "space was skipped"}`
|
|
1717
|
+
);
|
|
1718
|
+
}
|
|
1719
|
+
}
|
|
1454
1720
|
/**
|
|
1455
1721
|
* Restore a previously established session from stored delegation data.
|
|
1456
1722
|
*
|
|
@@ -1466,7 +1732,12 @@ var _TinyCloudNode = class _TinyCloudNode {
|
|
|
1466
1732
|
this._sql = void 0;
|
|
1467
1733
|
this._duckdb = void 0;
|
|
1468
1734
|
this._hooks = void 0;
|
|
1735
|
+
this._vault = void 0;
|
|
1736
|
+
this._baseSecrets = void 0;
|
|
1737
|
+
this._secrets = void 0;
|
|
1738
|
+
this._spaceService = void 0;
|
|
1469
1739
|
this._serviceContext = void 0;
|
|
1740
|
+
this.runtimePermissionGrants = [];
|
|
1470
1741
|
if (sessionData.address) {
|
|
1471
1742
|
this._address = sessionData.address;
|
|
1472
1743
|
}
|
|
@@ -1474,8 +1745,8 @@ var _TinyCloudNode = class _TinyCloudNode {
|
|
|
1474
1745
|
this._chainId = sessionData.chainId;
|
|
1475
1746
|
}
|
|
1476
1747
|
this._serviceContext = new ServiceContext2({
|
|
1477
|
-
invoke: this.
|
|
1478
|
-
invokeAny: this.
|
|
1748
|
+
invoke: this.invokeWithRuntimePermissions,
|
|
1749
|
+
invokeAny: this.invokeAnyWithRuntimePermissions,
|
|
1479
1750
|
fetch: globalThis.fetch.bind(globalThis),
|
|
1480
1751
|
hosts: [this.config.host]
|
|
1481
1752
|
});
|
|
@@ -1499,41 +1770,7 @@ var _TinyCloudNode = class _TinyCloudNode {
|
|
|
1499
1770
|
jwk: sessionData.jwk
|
|
1500
1771
|
};
|
|
1501
1772
|
this._serviceContext.setSession(serviceSession);
|
|
1502
|
-
|
|
1503
|
-
const vaultCrypto = createVaultCrypto({
|
|
1504
|
-
vault_encrypt: wasm.vault_encrypt,
|
|
1505
|
-
vault_decrypt: wasm.vault_decrypt,
|
|
1506
|
-
vault_derive_key: wasm.vault_derive_key,
|
|
1507
|
-
vault_x25519_from_seed: wasm.vault_x25519_from_seed,
|
|
1508
|
-
vault_x25519_dh: wasm.vault_x25519_dh,
|
|
1509
|
-
vault_random_bytes: wasm.vault_random_bytes,
|
|
1510
|
-
vault_sha256: wasm.vault_sha256
|
|
1511
|
-
});
|
|
1512
|
-
const self = this;
|
|
1513
|
-
this._vault = new DataVaultService({
|
|
1514
|
-
spaceId: sessionData.spaceId,
|
|
1515
|
-
crypto: vaultCrypto,
|
|
1516
|
-
tc: {
|
|
1517
|
-
kv: this._kv,
|
|
1518
|
-
ensurePublicSpace: async () => {
|
|
1519
|
-
try {
|
|
1520
|
-
await self.ensurePublicSpace();
|
|
1521
|
-
return { ok: true, data: void 0 };
|
|
1522
|
-
} catch (error) {
|
|
1523
|
-
return { ok: false, error: { code: "STORAGE_ERROR", message: error instanceof Error ? error.message : String(error), service: "vault" } };
|
|
1524
|
-
}
|
|
1525
|
-
},
|
|
1526
|
-
get publicKV() {
|
|
1527
|
-
return self._publicKV ?? self.tc.publicKV;
|
|
1528
|
-
},
|
|
1529
|
-
readPublicSpace: (host, spaceId, key) => TinyCloud.readPublicSpace(host, spaceId, key),
|
|
1530
|
-
makePublicSpaceId: TinyCloud.makePublicSpaceId,
|
|
1531
|
-
did: this.did,
|
|
1532
|
-
address: sessionData.address ?? this._address ?? "",
|
|
1533
|
-
chainId: sessionData.chainId ?? this._chainId,
|
|
1534
|
-
hosts: [this.config.host]
|
|
1535
|
-
}
|
|
1536
|
-
});
|
|
1773
|
+
this._vault = this.createVaultService(sessionData.spaceId, this._kv);
|
|
1537
1774
|
this._vault.initialize(this._serviceContext);
|
|
1538
1775
|
this._serviceContext.registerService("vault", this._vault);
|
|
1539
1776
|
this.initializeV2Services(serviceSession);
|
|
@@ -1568,7 +1805,6 @@ var _TinyCloudNode = class _TinyCloudNode {
|
|
|
1568
1805
|
throw new Error("Wallet already connected. Cannot connect another wallet.");
|
|
1569
1806
|
}
|
|
1570
1807
|
const prefix = options?.prefix ?? "default";
|
|
1571
|
-
const host = this.config.host;
|
|
1572
1808
|
if (!_TinyCloudNode.nodeDefaults) {
|
|
1573
1809
|
throw new Error(
|
|
1574
1810
|
"connectWallet() requires PrivateKeySigner. Use connectSigner() instead, or import from '@tinycloud/node-sdk' (not '/core') for automatic Node.js defaults."
|
|
@@ -1583,7 +1819,9 @@ var _TinyCloudNode = class _TinyCloudNode {
|
|
|
1583
1819
|
domain: this.siweDomain,
|
|
1584
1820
|
spacePrefix: prefix,
|
|
1585
1821
|
sessionExpirationMs: this.config.sessionExpirationMs ?? 60 * 60 * 1e3,
|
|
1586
|
-
tinycloudHosts: [
|
|
1822
|
+
tinycloudHosts: this.explicitHost ? [this.explicitHost] : void 0,
|
|
1823
|
+
tinycloudRegistryUrl: this.config.tinycloudRegistryUrl,
|
|
1824
|
+
tinycloudFallbackHosts: this.config.tinycloudFallbackHosts,
|
|
1587
1825
|
autoCreateSpace: this.config.autoCreateSpace,
|
|
1588
1826
|
enablePublicSpace: this.config.enablePublicSpace ?? true,
|
|
1589
1827
|
spaceCreationHandler: this.config.spaceCreationHandler,
|
|
@@ -1594,7 +1832,7 @@ var _TinyCloudNode = class _TinyCloudNode {
|
|
|
1594
1832
|
includeAccountRegistryPermissions: this.config.includeAccountRegistryPermissions
|
|
1595
1833
|
});
|
|
1596
1834
|
this.tc = new TinyCloud(this.auth, {
|
|
1597
|
-
invokeAny: this.
|
|
1835
|
+
invokeAny: this.invokeAnyWithRuntimePermissions
|
|
1598
1836
|
});
|
|
1599
1837
|
this.config.prefix = prefix;
|
|
1600
1838
|
}
|
|
@@ -1616,7 +1854,6 @@ var _TinyCloudNode = class _TinyCloudNode {
|
|
|
1616
1854
|
throw new Error("Signer already connected. Cannot connect another signer.");
|
|
1617
1855
|
}
|
|
1618
1856
|
const prefix = options?.prefix ?? "default";
|
|
1619
|
-
const host = this.config.host;
|
|
1620
1857
|
this.signer = signer;
|
|
1621
1858
|
this.auth = new NodeUserAuthorization({
|
|
1622
1859
|
signer: this.signer,
|
|
@@ -1626,7 +1863,9 @@ var _TinyCloudNode = class _TinyCloudNode {
|
|
|
1626
1863
|
domain: this.siweDomain,
|
|
1627
1864
|
spacePrefix: prefix,
|
|
1628
1865
|
sessionExpirationMs: this.config.sessionExpirationMs ?? 60 * 60 * 1e3,
|
|
1629
|
-
tinycloudHosts: [
|
|
1866
|
+
tinycloudHosts: this.explicitHost ? [this.explicitHost] : void 0,
|
|
1867
|
+
tinycloudRegistryUrl: this.config.tinycloudRegistryUrl,
|
|
1868
|
+
tinycloudFallbackHosts: this.config.tinycloudFallbackHosts,
|
|
1630
1869
|
autoCreateSpace: this.config.autoCreateSpace,
|
|
1631
1870
|
enablePublicSpace: this.config.enablePublicSpace ?? true,
|
|
1632
1871
|
spaceCreationHandler: this.config.spaceCreationHandler,
|
|
@@ -1637,7 +1876,7 @@ var _TinyCloudNode = class _TinyCloudNode {
|
|
|
1637
1876
|
includeAccountRegistryPermissions: this.config.includeAccountRegistryPermissions
|
|
1638
1877
|
});
|
|
1639
1878
|
this.tc = new TinyCloud(this.auth, {
|
|
1640
|
-
invokeAny: this.
|
|
1879
|
+
invokeAny: this.invokeAnyWithRuntimePermissions
|
|
1641
1880
|
});
|
|
1642
1881
|
this.config.prefix = prefix;
|
|
1643
1882
|
}
|
|
@@ -1650,10 +1889,10 @@ var _TinyCloudNode = class _TinyCloudNode {
|
|
|
1650
1889
|
if (!session) {
|
|
1651
1890
|
return;
|
|
1652
1891
|
}
|
|
1653
|
-
this.tc.initializeServices(this.
|
|
1892
|
+
this.tc.initializeServices(this.invokeWithRuntimePermissions, [this.config.host]);
|
|
1654
1893
|
this._serviceContext = new ServiceContext2({
|
|
1655
|
-
invoke: this.
|
|
1656
|
-
invokeAny: this.
|
|
1894
|
+
invoke: this.invokeWithRuntimePermissions,
|
|
1895
|
+
invokeAny: this.invokeAnyWithRuntimePermissions,
|
|
1657
1896
|
fetch: globalThis.fetch.bind(globalThis),
|
|
1658
1897
|
hosts: [this.config.host]
|
|
1659
1898
|
});
|
|
@@ -1683,6 +1922,28 @@ var _TinyCloudNode = class _TinyCloudNode {
|
|
|
1683
1922
|
};
|
|
1684
1923
|
this._serviceContext.setSession(serviceSession);
|
|
1685
1924
|
this.tc.serviceContext.setSession(serviceSession);
|
|
1925
|
+
this._vault = this.createVaultService(session.spaceId, this._kv);
|
|
1926
|
+
this._vault.initialize(this._serviceContext);
|
|
1927
|
+
this._serviceContext.registerService("vault", this._vault);
|
|
1928
|
+
this.initializeV2Services(serviceSession);
|
|
1929
|
+
}
|
|
1930
|
+
createSpaceScopedKVService(spaceId) {
|
|
1931
|
+
const kvService = new KVService2({});
|
|
1932
|
+
if (this._serviceContext) {
|
|
1933
|
+
const spaceScopedContext = new ServiceContext2({
|
|
1934
|
+
invoke: this._serviceContext.invoke,
|
|
1935
|
+
fetch: this._serviceContext.fetch,
|
|
1936
|
+
hosts: this._serviceContext.hosts
|
|
1937
|
+
});
|
|
1938
|
+
const session = this._serviceContext.session;
|
|
1939
|
+
if (session) {
|
|
1940
|
+
spaceScopedContext.setSession({ ...session, spaceId });
|
|
1941
|
+
}
|
|
1942
|
+
kvService.initialize(spaceScopedContext);
|
|
1943
|
+
}
|
|
1944
|
+
return kvService;
|
|
1945
|
+
}
|
|
1946
|
+
createVaultService(spaceId, kv) {
|
|
1686
1947
|
const wasm = this.wasmBindings;
|
|
1687
1948
|
const vaultCrypto = createVaultCrypto({
|
|
1688
1949
|
vault_encrypt: wasm.vault_encrypt,
|
|
@@ -1694,11 +1955,11 @@ var _TinyCloudNode = class _TinyCloudNode {
|
|
|
1694
1955
|
vault_sha256: wasm.vault_sha256
|
|
1695
1956
|
});
|
|
1696
1957
|
const self = this;
|
|
1697
|
-
|
|
1698
|
-
spaceId
|
|
1958
|
+
return new DataVaultService({
|
|
1959
|
+
spaceId,
|
|
1699
1960
|
crypto: vaultCrypto,
|
|
1700
1961
|
tc: {
|
|
1701
|
-
kv
|
|
1962
|
+
kv,
|
|
1702
1963
|
ensurePublicSpace: async () => {
|
|
1703
1964
|
try {
|
|
1704
1965
|
await self.ensurePublicSpace();
|
|
@@ -1710,17 +1971,14 @@ var _TinyCloudNode = class _TinyCloudNode {
|
|
|
1710
1971
|
get publicKV() {
|
|
1711
1972
|
return self._publicKV ?? self.tc.publicKV;
|
|
1712
1973
|
},
|
|
1713
|
-
readPublicSpace: (host,
|
|
1974
|
+
readPublicSpace: (host, targetSpaceId, key) => TinyCloud.readPublicSpace(host, targetSpaceId, key),
|
|
1714
1975
|
makePublicSpaceId: TinyCloud.makePublicSpaceId,
|
|
1715
1976
|
did: this.did,
|
|
1716
|
-
address: this._address,
|
|
1977
|
+
address: this._address ?? "",
|
|
1717
1978
|
chainId: this._chainId,
|
|
1718
1979
|
hosts: [this.config.host]
|
|
1719
1980
|
}
|
|
1720
1981
|
});
|
|
1721
|
-
this._vault.initialize(this._serviceContext);
|
|
1722
|
-
this._serviceContext.registerService("vault", this._vault);
|
|
1723
|
-
this.initializeV2Services(serviceSession);
|
|
1724
1982
|
}
|
|
1725
1983
|
/**
|
|
1726
1984
|
* Initialize the v2 delegation system services.
|
|
@@ -1804,7 +2062,7 @@ var _TinyCloudNode = class _TinyCloudNode {
|
|
|
1804
2062
|
this._delegationManager = new DelegationManager({
|
|
1805
2063
|
hosts: [this.config.host],
|
|
1806
2064
|
session: serviceSession,
|
|
1807
|
-
invoke: this.
|
|
2065
|
+
invoke: this.invokeWithRuntimePermissions,
|
|
1808
2066
|
fetch: globalThis.fetch.bind(globalThis)
|
|
1809
2067
|
});
|
|
1810
2068
|
this._spaceService = new SpaceService({
|
|
@@ -1815,20 +2073,15 @@ var _TinyCloudNode = class _TinyCloudNode {
|
|
|
1815
2073
|
capabilityRegistry: this._capabilityRegistry,
|
|
1816
2074
|
userDid: this.did,
|
|
1817
2075
|
createKVService: (spaceId) => {
|
|
1818
|
-
|
|
2076
|
+
return this.createSpaceScopedKVService(spaceId);
|
|
2077
|
+
},
|
|
2078
|
+
createVaultService: (spaceId) => {
|
|
2079
|
+
const kvService = this.createSpaceScopedKVService(spaceId);
|
|
2080
|
+
const vaultService = this.createVaultService(spaceId, kvService);
|
|
1819
2081
|
if (this._serviceContext) {
|
|
1820
|
-
|
|
1821
|
-
invoke: this._serviceContext.invoke,
|
|
1822
|
-
fetch: this._serviceContext.fetch,
|
|
1823
|
-
hosts: this._serviceContext.hosts
|
|
1824
|
-
});
|
|
1825
|
-
const session = this._serviceContext.session;
|
|
1826
|
-
if (session) {
|
|
1827
|
-
spaceScopedContext.setSession({ ...session, spaceId });
|
|
1828
|
-
}
|
|
1829
|
-
kvService.initialize(spaceScopedContext);
|
|
2082
|
+
vaultService.initialize(this._serviceContext);
|
|
1830
2083
|
}
|
|
1831
|
-
return
|
|
2084
|
+
return vaultService;
|
|
1832
2085
|
},
|
|
1833
2086
|
// Enable space.delegations.create() via SIWE-based delegation
|
|
1834
2087
|
createDelegation: async (params) => {
|
|
@@ -2065,6 +2318,33 @@ var _TinyCloudNode = class _TinyCloudNode {
|
|
|
2065
2318
|
}
|
|
2066
2319
|
return this._vault;
|
|
2067
2320
|
}
|
|
2321
|
+
/**
|
|
2322
|
+
* App-facing secrets API backed by the `secrets` space vault.
|
|
2323
|
+
*/
|
|
2324
|
+
get secrets() {
|
|
2325
|
+
if (!this._spaceService) {
|
|
2326
|
+
throw new Error("Not signed in. Call signIn() first.");
|
|
2327
|
+
}
|
|
2328
|
+
if (!this._secrets) {
|
|
2329
|
+
this._secrets = new NodeSecretsService({
|
|
2330
|
+
getService: () => this.getBaseSecrets(),
|
|
2331
|
+
getManifest: () => this.manifest,
|
|
2332
|
+
grantPermissions: (additional) => this.grantRuntimePermissions(additional),
|
|
2333
|
+
canEscalate: () => this.signer !== void 0 && this.tc !== void 0,
|
|
2334
|
+
getUnlockSigner: () => this.signer ?? void 0
|
|
2335
|
+
});
|
|
2336
|
+
}
|
|
2337
|
+
return this._secrets;
|
|
2338
|
+
}
|
|
2339
|
+
getBaseSecrets() {
|
|
2340
|
+
if (!this._spaceService) {
|
|
2341
|
+
throw new Error("Not signed in. Call signIn() first.");
|
|
2342
|
+
}
|
|
2343
|
+
if (!this._baseSecrets) {
|
|
2344
|
+
this._baseSecrets = new SecretsService(() => this.space("secrets").vault);
|
|
2345
|
+
}
|
|
2346
|
+
return this._baseSecrets;
|
|
2347
|
+
}
|
|
2068
2348
|
/**
|
|
2069
2349
|
* Hooks write stream subscription API.
|
|
2070
2350
|
*/
|
|
@@ -2135,6 +2415,171 @@ var _TinyCloudNode = class _TinyCloudNode {
|
|
|
2135
2415
|
}
|
|
2136
2416
|
};
|
|
2137
2417
|
}
|
|
2418
|
+
/**
|
|
2419
|
+
* Check whether the current session or an approved runtime delegation covers
|
|
2420
|
+
* every requested permission.
|
|
2421
|
+
*/
|
|
2422
|
+
hasRuntimePermissions(permissions) {
|
|
2423
|
+
const session = this.auth?.tinyCloudSession;
|
|
2424
|
+
if (!session || !Array.isArray(permissions) || permissions.length === 0) {
|
|
2425
|
+
return false;
|
|
2426
|
+
}
|
|
2427
|
+
const expanded = this.expandPermissionEntries(permissions);
|
|
2428
|
+
if (this.sessionCoversPermissionEntries(session, expanded)) {
|
|
2429
|
+
return true;
|
|
2430
|
+
}
|
|
2431
|
+
return this.findRuntimeGrantsForPermissionEntries(expanded, session).length > 0;
|
|
2432
|
+
}
|
|
2433
|
+
/**
|
|
2434
|
+
* Return installed runtime permission delegations. When `permissions` is
|
|
2435
|
+
* provided, only delegations currently covering those permissions are
|
|
2436
|
+
* returned. Base-session manifest permissions are not represented here.
|
|
2437
|
+
*/
|
|
2438
|
+
getRuntimePermissionDelegations(permissions) {
|
|
2439
|
+
this.pruneExpiredRuntimePermissionGrants();
|
|
2440
|
+
if (permissions === void 0) {
|
|
2441
|
+
return this.runtimePermissionGrants.map((grant) => grant.delegation);
|
|
2442
|
+
}
|
|
2443
|
+
const session = this.auth?.tinyCloudSession;
|
|
2444
|
+
if (!session || !Array.isArray(permissions) || permissions.length === 0) {
|
|
2445
|
+
return [];
|
|
2446
|
+
}
|
|
2447
|
+
const expanded = this.expandPermissionEntries(permissions);
|
|
2448
|
+
return this.findRuntimeGrantsForPermissionEntries(expanded, session).map(
|
|
2449
|
+
(grant) => grant.delegation
|
|
2450
|
+
);
|
|
2451
|
+
}
|
|
2452
|
+
/**
|
|
2453
|
+
* Install a portable runtime permission delegation into this SDK instance so
|
|
2454
|
+
* matching service calls and downstream `delegateTo()` calls can use it.
|
|
2455
|
+
*/
|
|
2456
|
+
async useRuntimeDelegation(delegation) {
|
|
2457
|
+
const session = this.auth?.tinyCloudSession;
|
|
2458
|
+
if (!session) {
|
|
2459
|
+
throw new SessionExpiredError(/* @__PURE__ */ new Date(0));
|
|
2460
|
+
}
|
|
2461
|
+
if (delegation.expiry.getTime() <= Date.now()) {
|
|
2462
|
+
throw new SessionExpiredError(delegation.expiry);
|
|
2463
|
+
}
|
|
2464
|
+
const expectedDids = /* @__PURE__ */ new Set([session.verificationMethod, this.sessionDid]);
|
|
2465
|
+
if (!expectedDids.has(delegation.delegateDID)) {
|
|
2466
|
+
throw new Error(
|
|
2467
|
+
`Runtime delegation targets ${delegation.delegateDID} but this session key is ${session.verificationMethod}.`
|
|
2468
|
+
);
|
|
2469
|
+
}
|
|
2470
|
+
const targetHost = delegation.host ?? this.config.host;
|
|
2471
|
+
const activateResult = await activateSessionWithHost2(
|
|
2472
|
+
targetHost,
|
|
2473
|
+
delegation.delegationHeader
|
|
2474
|
+
);
|
|
2475
|
+
if (!activateResult.success) {
|
|
2476
|
+
throw new Error(
|
|
2477
|
+
`Failed to activate runtime permission delegation: ${activateResult.error}`
|
|
2478
|
+
);
|
|
2479
|
+
}
|
|
2480
|
+
this.runtimePermissionGrants = this.runtimePermissionGrants.filter(
|
|
2481
|
+
(grant) => grant.delegation.cid !== delegation.cid
|
|
2482
|
+
);
|
|
2483
|
+
this.runtimePermissionGrants.push(
|
|
2484
|
+
this.runtimeGrantFromDelegation(delegation, session)
|
|
2485
|
+
);
|
|
2486
|
+
}
|
|
2487
|
+
/**
|
|
2488
|
+
* Store additional permissions as narrow delegations to the current session
|
|
2489
|
+
* key. Future service invocations automatically use a stored delegation when
|
|
2490
|
+
* its `(space, service, path, action)` covers the request.
|
|
2491
|
+
*/
|
|
2492
|
+
async grantRuntimePermissions(permissions, options) {
|
|
2493
|
+
if (!Array.isArray(permissions) || permissions.length === 0) {
|
|
2494
|
+
throw new Error("grantRuntimePermissions requires a non-empty permissions array");
|
|
2495
|
+
}
|
|
2496
|
+
const session = this.auth?.tinyCloudSession;
|
|
2497
|
+
if (!session) {
|
|
2498
|
+
throw new SessionExpiredError(/* @__PURE__ */ new Date(0));
|
|
2499
|
+
}
|
|
2500
|
+
const sessionExpiry = extractSiweExpiration(session.siwe);
|
|
2501
|
+
if (sessionExpiry !== void 0) {
|
|
2502
|
+
const marginMs = _TinyCloudNode.SESSION_EXPIRY_SAFETY_MARGIN_MS;
|
|
2503
|
+
if (sessionExpiry.getTime() <= Date.now() + marginMs) {
|
|
2504
|
+
throw new SessionExpiredError(sessionExpiry);
|
|
2505
|
+
}
|
|
2506
|
+
}
|
|
2507
|
+
const expanded = this.expandPermissionEntries(permissions);
|
|
2508
|
+
if (this.sessionCoversPermissionEntries(session, expanded)) {
|
|
2509
|
+
return [];
|
|
2510
|
+
}
|
|
2511
|
+
const existingGrants = this.findRuntimeGrantsForPermissionEntries(expanded, session);
|
|
2512
|
+
if (existingGrants.length > 0) {
|
|
2513
|
+
return existingGrants.map((grant) => grant.delegation);
|
|
2514
|
+
}
|
|
2515
|
+
if (!this.signer) {
|
|
2516
|
+
throw new Error(
|
|
2517
|
+
"grantRuntimePermissions requires wallet mode with a signer or privateKey."
|
|
2518
|
+
);
|
|
2519
|
+
}
|
|
2520
|
+
const bySpace = /* @__PURE__ */ new Map();
|
|
2521
|
+
for (const entry of expanded) {
|
|
2522
|
+
const spaceId = this.resolvePermissionSpace(entry.space, session);
|
|
2523
|
+
const current = bySpace.get(spaceId) ?? [];
|
|
2524
|
+
current.push(entry);
|
|
2525
|
+
bySpace.set(spaceId, current);
|
|
2526
|
+
}
|
|
2527
|
+
const now = /* @__PURE__ */ new Date();
|
|
2528
|
+
const requestedExpiryMs = resolveExpiryMs(options?.expiry);
|
|
2529
|
+
let expiresAt = new Date(now.getTime() + requestedExpiryMs);
|
|
2530
|
+
if (sessionExpiry !== void 0 && sessionExpiry < expiresAt) {
|
|
2531
|
+
expiresAt = sessionExpiry;
|
|
2532
|
+
}
|
|
2533
|
+
const delegations = [];
|
|
2534
|
+
for (const [spaceId, entries] of bySpace) {
|
|
2535
|
+
const abilities = this.permissionsToAbilities(entries);
|
|
2536
|
+
const prepared = this.wasmBindings.prepareSession({
|
|
2537
|
+
abilities,
|
|
2538
|
+
address: this.wasmBindings.ensureEip55(session.address),
|
|
2539
|
+
chainId: session.chainId,
|
|
2540
|
+
domain: this.siweDomain,
|
|
2541
|
+
issuedAt: now.toISOString(),
|
|
2542
|
+
expirationTime: expiresAt.toISOString(),
|
|
2543
|
+
spaceId,
|
|
2544
|
+
jwk: session.jwk
|
|
2545
|
+
});
|
|
2546
|
+
const signature = await this.signer.signMessage(prepared.siwe);
|
|
2547
|
+
const delegatedSession = this.wasmBindings.completeSessionSetup({
|
|
2548
|
+
...prepared,
|
|
2549
|
+
signature
|
|
2550
|
+
});
|
|
2551
|
+
const activateResult = await activateSessionWithHost2(
|
|
2552
|
+
this.config.host,
|
|
2553
|
+
delegatedSession.delegationHeader
|
|
2554
|
+
);
|
|
2555
|
+
if (!activateResult.success) {
|
|
2556
|
+
throw new Error(
|
|
2557
|
+
`Failed to activate runtime permission delegation: ${activateResult.error}`
|
|
2558
|
+
);
|
|
2559
|
+
}
|
|
2560
|
+
const delegation = this.runtimeDelegationFromSession(
|
|
2561
|
+
delegatedSession,
|
|
2562
|
+
entries,
|
|
2563
|
+
spaceId,
|
|
2564
|
+
session,
|
|
2565
|
+
expiresAt
|
|
2566
|
+
);
|
|
2567
|
+
this.runtimePermissionGrants.push({
|
|
2568
|
+
session: {
|
|
2569
|
+
delegationHeader: delegatedSession.delegationHeader,
|
|
2570
|
+
delegationCid: delegatedSession.delegationCid,
|
|
2571
|
+
spaceId,
|
|
2572
|
+
verificationMethod: session.verificationMethod,
|
|
2573
|
+
jwk: session.jwk
|
|
2574
|
+
},
|
|
2575
|
+
delegation,
|
|
2576
|
+
operations: this.permissionOperations(entries, spaceId),
|
|
2577
|
+
expiresAt
|
|
2578
|
+
});
|
|
2579
|
+
delegations.push(delegation);
|
|
2580
|
+
}
|
|
2581
|
+
return delegations;
|
|
2582
|
+
}
|
|
2138
2583
|
/**
|
|
2139
2584
|
* Get the DelegationManager for delegation CRUD operations.
|
|
2140
2585
|
*
|
|
@@ -2203,6 +2648,12 @@ var _TinyCloudNode = class _TinyCloudNode {
|
|
|
2203
2648
|
get spaceService() {
|
|
2204
2649
|
return this.spaces;
|
|
2205
2650
|
}
|
|
2651
|
+
/**
|
|
2652
|
+
* Get a Space object by short name or full URI.
|
|
2653
|
+
*/
|
|
2654
|
+
space(nameOrUri) {
|
|
2655
|
+
return this.spaces.get(nameOrUri);
|
|
2656
|
+
}
|
|
2206
2657
|
/**
|
|
2207
2658
|
* Get the SharingService for creating and receiving v2 sharing links.
|
|
2208
2659
|
*
|
|
@@ -2317,7 +2768,7 @@ var _TinyCloudNode = class _TinyCloudNode {
|
|
|
2317
2768
|
if (this._serviceContext) {
|
|
2318
2769
|
const publicKV = new KVService2({ prefix: "" });
|
|
2319
2770
|
const publicContext = new ServiceContext2({
|
|
2320
|
-
invoke: this.
|
|
2771
|
+
invoke: this.invokeWithRuntimePermissions,
|
|
2321
2772
|
fetch: this._serviceContext.fetch,
|
|
2322
2773
|
hosts: this._serviceContext.hosts
|
|
2323
2774
|
});
|
|
@@ -2405,8 +2856,9 @@ var _TinyCloudNode = class _TinyCloudNode {
|
|
|
2405
2856
|
* Issue a delegation using the capability-chain flow.
|
|
2406
2857
|
*
|
|
2407
2858
|
* When every requested permission is a subset of the current
|
|
2408
|
-
* session's recap,
|
|
2409
|
-
*
|
|
2859
|
+
* session's recap, or of one installed runtime permission delegation,
|
|
2860
|
+
* the delegation is signed by the session key via WASM — no wallet
|
|
2861
|
+
* prompt. When at least one is NOT derivable, a
|
|
2410
2862
|
* {@link PermissionNotInManifestError} is raised (carrying the
|
|
2411
2863
|
* missing entries) so the caller can trigger an escalation flow
|
|
2412
2864
|
* (e.g. `TinyCloudWeb.requestPermissions`). Passing
|
|
@@ -2456,10 +2908,7 @@ var _TinyCloudNode = class _TinyCloudNode {
|
|
|
2456
2908
|
"delegateTo requires a non-empty permissions array"
|
|
2457
2909
|
);
|
|
2458
2910
|
}
|
|
2459
|
-
const expandedEntries =
|
|
2460
|
-
...entry,
|
|
2461
|
-
actions: expandActionShortNames(entry.service, entry.actions)
|
|
2462
|
-
}));
|
|
2911
|
+
const expandedEntries = this.expandPermissionEntries(permissions);
|
|
2463
2912
|
const now = /* @__PURE__ */ new Date();
|
|
2464
2913
|
const expiryMs = resolveExpiryMs(options?.expiry);
|
|
2465
2914
|
const expirationTime = new Date(now.getTime() + expiryMs);
|
|
@@ -2486,6 +2935,23 @@ var _TinyCloudNode = class _TinyCloudNode {
|
|
|
2486
2935
|
);
|
|
2487
2936
|
const { subset, missing } = isCapabilitySubset(expandedEntries, granted);
|
|
2488
2937
|
if (!subset) {
|
|
2938
|
+
const runtimeGrant = this.findGrantForOperations(
|
|
2939
|
+
this.permissionEntriesToOperations(expandedEntries, session)
|
|
2940
|
+
);
|
|
2941
|
+
if (runtimeGrant) {
|
|
2942
|
+
const marginMs = _TinyCloudNode.SESSION_EXPIRY_SAFETY_MARGIN_MS;
|
|
2943
|
+
if (runtimeGrant.expiresAt.getTime() <= Date.now() + marginMs) {
|
|
2944
|
+
throw new SessionExpiredError(runtimeGrant.expiresAt);
|
|
2945
|
+
}
|
|
2946
|
+
const runtimeExpiration = runtimeGrant.expiresAt < effectiveExpiration ? runtimeGrant.expiresAt : effectiveExpiration;
|
|
2947
|
+
const delegation2 = await this.createDelegationViaRuntimeGrant(
|
|
2948
|
+
did,
|
|
2949
|
+
expandedEntries,
|
|
2950
|
+
runtimeExpiration,
|
|
2951
|
+
runtimeGrant
|
|
2952
|
+
);
|
|
2953
|
+
return { delegation: delegation2, prompted: false };
|
|
2954
|
+
}
|
|
2489
2955
|
throw new PermissionNotInManifestError(missing, granted);
|
|
2490
2956
|
}
|
|
2491
2957
|
const delegation = await this.createDelegationViaWasmPath(
|
|
@@ -2630,6 +3096,41 @@ var _TinyCloudNode = class _TinyCloudNode {
|
|
|
2630
3096
|
host: this.config.host
|
|
2631
3097
|
};
|
|
2632
3098
|
}
|
|
3099
|
+
async createDelegationViaRuntimeGrant(did, entries, expirationTime, grant) {
|
|
3100
|
+
const result = this.createDelegationWrapper({
|
|
3101
|
+
session: grant.session,
|
|
3102
|
+
delegateDID: did,
|
|
3103
|
+
spaceId: grant.session.spaceId,
|
|
3104
|
+
abilities: this.permissionsToAbilities(entries),
|
|
3105
|
+
expirationSecs: Math.floor(expirationTime.getTime() / 1e3)
|
|
3106
|
+
});
|
|
3107
|
+
const primary = result.resources[0];
|
|
3108
|
+
const delegationHeader = { Authorization: result.delegation };
|
|
3109
|
+
const targetHost = grant.delegation.host ?? this.config.host;
|
|
3110
|
+
const activateResult = await activateSessionWithHost2(
|
|
3111
|
+
targetHost,
|
|
3112
|
+
delegationHeader
|
|
3113
|
+
);
|
|
3114
|
+
if (!activateResult.success) {
|
|
3115
|
+
throw new Error(
|
|
3116
|
+
`Failed to activate delegation with host: ${activateResult.error}`
|
|
3117
|
+
);
|
|
3118
|
+
}
|
|
3119
|
+
return {
|
|
3120
|
+
cid: result.cid,
|
|
3121
|
+
delegationHeader,
|
|
3122
|
+
spaceId: grant.session.spaceId,
|
|
3123
|
+
path: primary.path,
|
|
3124
|
+
actions: primary.actions,
|
|
3125
|
+
resources: result.resources,
|
|
3126
|
+
disableSubDelegation: false,
|
|
3127
|
+
expiry: result.expiry,
|
|
3128
|
+
delegateDID: did,
|
|
3129
|
+
ownerAddress: grant.delegation.ownerAddress,
|
|
3130
|
+
chainId: grant.delegation.chainId,
|
|
3131
|
+
host: targetHost
|
|
3132
|
+
};
|
|
3133
|
+
}
|
|
2633
3134
|
resolvePermissionSpace(space, session) {
|
|
2634
3135
|
if (space === void 0) {
|
|
2635
3136
|
return this.wasmBindings.makeSpaceId(
|
|
@@ -2646,6 +3147,220 @@ var _TinyCloudNode = class _TinyCloudNode {
|
|
|
2646
3147
|
}
|
|
2647
3148
|
return this.wasmBindings.makeSpaceId(session.address, session.chainId, space);
|
|
2648
3149
|
}
|
|
3150
|
+
expandPermissionEntries(permissions) {
|
|
3151
|
+
return expandPermissionEntriesCore(permissions);
|
|
3152
|
+
}
|
|
3153
|
+
shortServiceName(service) {
|
|
3154
|
+
const short = SERVICE_LONG_TO_SHORT[service];
|
|
3155
|
+
if (short === void 0) {
|
|
3156
|
+
throw new Error(
|
|
3157
|
+
`unknown service '${service}' \u2014 no short-form mapping`
|
|
3158
|
+
);
|
|
3159
|
+
}
|
|
3160
|
+
return short;
|
|
3161
|
+
}
|
|
3162
|
+
permissionsToAbilities(entries) {
|
|
3163
|
+
const abilities = {};
|
|
3164
|
+
for (const entry of entries) {
|
|
3165
|
+
const service = this.shortServiceName(entry.service);
|
|
3166
|
+
abilities[service] ?? (abilities[service] = {});
|
|
3167
|
+
const existing = abilities[service][entry.path] ?? [];
|
|
3168
|
+
const seen = new Set(existing);
|
|
3169
|
+
for (const action of entry.actions) {
|
|
3170
|
+
if (!seen.has(action)) {
|
|
3171
|
+
existing.push(action);
|
|
3172
|
+
seen.add(action);
|
|
3173
|
+
}
|
|
3174
|
+
}
|
|
3175
|
+
abilities[service][entry.path] = existing;
|
|
3176
|
+
}
|
|
3177
|
+
return abilities;
|
|
3178
|
+
}
|
|
3179
|
+
permissionOperations(entries, spaceId) {
|
|
3180
|
+
return entries.flatMap((entry) => {
|
|
3181
|
+
const service = this.shortServiceName(entry.service);
|
|
3182
|
+
return entry.actions.map((action) => ({
|
|
3183
|
+
spaceId,
|
|
3184
|
+
service,
|
|
3185
|
+
path: entry.path,
|
|
3186
|
+
action
|
|
3187
|
+
}));
|
|
3188
|
+
});
|
|
3189
|
+
}
|
|
3190
|
+
sessionCoversPermissionEntries(session, entries) {
|
|
3191
|
+
try {
|
|
3192
|
+
const granted = parseRecapCapabilities(
|
|
3193
|
+
(siwe) => this.wasmBindings.parseRecapFromSiwe(siwe),
|
|
3194
|
+
session.siwe
|
|
3195
|
+
);
|
|
3196
|
+
return isCapabilitySubset(entries, granted).subset;
|
|
3197
|
+
} catch {
|
|
3198
|
+
return false;
|
|
3199
|
+
}
|
|
3200
|
+
}
|
|
3201
|
+
permissionEntriesToOperations(entries, session) {
|
|
3202
|
+
return entries.flatMap((entry) => {
|
|
3203
|
+
const spaceId = this.resolvePermissionSpace(entry.space, session);
|
|
3204
|
+
const service = this.shortServiceName(entry.service);
|
|
3205
|
+
return entry.actions.map((action) => ({
|
|
3206
|
+
spaceId,
|
|
3207
|
+
service,
|
|
3208
|
+
path: entry.path,
|
|
3209
|
+
action
|
|
3210
|
+
}));
|
|
3211
|
+
});
|
|
3212
|
+
}
|
|
3213
|
+
findRuntimeGrantsForPermissionEntries(entries, session) {
|
|
3214
|
+
const grants = [];
|
|
3215
|
+
const operations = this.permissionEntriesToOperations(entries, session);
|
|
3216
|
+
if (operations.length === 0) {
|
|
3217
|
+
return grants;
|
|
3218
|
+
}
|
|
3219
|
+
for (const operation of operations) {
|
|
3220
|
+
const grant = this.findGrantForOperation(operation);
|
|
3221
|
+
if (!grant) {
|
|
3222
|
+
return [];
|
|
3223
|
+
}
|
|
3224
|
+
if (!grants.includes(grant)) {
|
|
3225
|
+
grants.push(grant);
|
|
3226
|
+
}
|
|
3227
|
+
}
|
|
3228
|
+
return grants;
|
|
3229
|
+
}
|
|
3230
|
+
runtimeDelegationFromSession(delegatedSession, entries, spaceId, session, expiresAt) {
|
|
3231
|
+
const resources = this.delegatedResourcesForEntries(entries, spaceId);
|
|
3232
|
+
const primary = resources[0];
|
|
3233
|
+
return {
|
|
3234
|
+
cid: delegatedSession.delegationCid,
|
|
3235
|
+
delegationHeader: delegatedSession.delegationHeader,
|
|
3236
|
+
spaceId,
|
|
3237
|
+
path: primary.path,
|
|
3238
|
+
actions: primary.actions,
|
|
3239
|
+
resources,
|
|
3240
|
+
disableSubDelegation: false,
|
|
3241
|
+
expiry: expiresAt,
|
|
3242
|
+
delegateDID: session.verificationMethod,
|
|
3243
|
+
ownerAddress: session.address,
|
|
3244
|
+
chainId: session.chainId,
|
|
3245
|
+
host: this.config.host
|
|
3246
|
+
};
|
|
3247
|
+
}
|
|
3248
|
+
runtimeGrantFromDelegation(delegation, session) {
|
|
3249
|
+
const operations = this.operationsFromDelegation(delegation);
|
|
3250
|
+
return {
|
|
3251
|
+
session: {
|
|
3252
|
+
delegationHeader: delegation.delegationHeader,
|
|
3253
|
+
delegationCid: delegation.cid,
|
|
3254
|
+
spaceId: delegation.spaceId,
|
|
3255
|
+
verificationMethod: session.verificationMethod,
|
|
3256
|
+
jwk: session.jwk
|
|
3257
|
+
},
|
|
3258
|
+
delegation,
|
|
3259
|
+
operations,
|
|
3260
|
+
expiresAt: delegation.expiry
|
|
3261
|
+
};
|
|
3262
|
+
}
|
|
3263
|
+
delegatedResourcesForEntries(entries, spaceId) {
|
|
3264
|
+
return entries.map((entry) => ({
|
|
3265
|
+
service: this.shortServiceName(entry.service),
|
|
3266
|
+
space: spaceId,
|
|
3267
|
+
path: entry.path,
|
|
3268
|
+
actions: [...entry.actions]
|
|
3269
|
+
}));
|
|
3270
|
+
}
|
|
3271
|
+
operationsFromDelegation(delegation) {
|
|
3272
|
+
const resources = delegation.resources !== void 0 && delegation.resources.length > 0 ? delegation.resources : this.flatDelegationResources(delegation);
|
|
3273
|
+
return resources.flatMap(
|
|
3274
|
+
(resource) => resource.actions.map((action) => ({
|
|
3275
|
+
spaceId: resource.space,
|
|
3276
|
+
service: this.invocationServiceName(resource.service),
|
|
3277
|
+
path: resource.path,
|
|
3278
|
+
action
|
|
3279
|
+
}))
|
|
3280
|
+
);
|
|
3281
|
+
}
|
|
3282
|
+
flatDelegationResources(delegation) {
|
|
3283
|
+
const byService = /* @__PURE__ */ new Map();
|
|
3284
|
+
for (const action of delegation.actions) {
|
|
3285
|
+
const service = this.shortServiceName(action.split("/")[0]);
|
|
3286
|
+
const actions = byService.get(service) ?? [];
|
|
3287
|
+
actions.push(action);
|
|
3288
|
+
byService.set(service, actions);
|
|
3289
|
+
}
|
|
3290
|
+
return [...byService.entries()].map(([service, actions]) => ({
|
|
3291
|
+
service,
|
|
3292
|
+
space: delegation.spaceId,
|
|
3293
|
+
path: delegation.path,
|
|
3294
|
+
actions
|
|
3295
|
+
}));
|
|
3296
|
+
}
|
|
3297
|
+
selectInvocationSession(fallback, service, path, action) {
|
|
3298
|
+
const grant = this.findGrantForOperation({
|
|
3299
|
+
spaceId: fallback.spaceId,
|
|
3300
|
+
service: this.invocationServiceName(service),
|
|
3301
|
+
path,
|
|
3302
|
+
action
|
|
3303
|
+
});
|
|
3304
|
+
return grant?.session ?? fallback;
|
|
3305
|
+
}
|
|
3306
|
+
findGrantForOperations(operations) {
|
|
3307
|
+
if (operations.length === 0) {
|
|
3308
|
+
return void 0;
|
|
3309
|
+
}
|
|
3310
|
+
this.pruneExpiredRuntimePermissionGrants();
|
|
3311
|
+
return this.runtimePermissionGrants.find((grant) => {
|
|
3312
|
+
return operations.every(
|
|
3313
|
+
(operation) => grant.operations.some(
|
|
3314
|
+
(granted) => this.operationCovers(granted, operation)
|
|
3315
|
+
)
|
|
3316
|
+
);
|
|
3317
|
+
});
|
|
3318
|
+
}
|
|
3319
|
+
findGrantForOperation(operation) {
|
|
3320
|
+
return this.findGrantForOperations([operation]);
|
|
3321
|
+
}
|
|
3322
|
+
pruneExpiredRuntimePermissionGrants() {
|
|
3323
|
+
const now = Date.now();
|
|
3324
|
+
this.runtimePermissionGrants = this.runtimePermissionGrants.filter(
|
|
3325
|
+
(grant) => grant.expiresAt.getTime() > now
|
|
3326
|
+
);
|
|
3327
|
+
}
|
|
3328
|
+
operationCovers(granted, requested) {
|
|
3329
|
+
return granted.spaceId === requested.spaceId && granted.service === requested.service && this.actionContains(granted.action, requested.action) && this.pathContains(granted.path, requested.path);
|
|
3330
|
+
}
|
|
3331
|
+
actionContains(grantedAction, requestedAction) {
|
|
3332
|
+
if (grantedAction === requestedAction) {
|
|
3333
|
+
return true;
|
|
3334
|
+
}
|
|
3335
|
+
if (grantedAction.endsWith("/*")) {
|
|
3336
|
+
const prefix = grantedAction.slice(0, -2);
|
|
3337
|
+
return requestedAction.startsWith(`${prefix}/`);
|
|
3338
|
+
}
|
|
3339
|
+
return false;
|
|
3340
|
+
}
|
|
3341
|
+
invocationServiceName(service) {
|
|
3342
|
+
return service.startsWith("tinycloud.") ? this.shortServiceName(service) : service;
|
|
3343
|
+
}
|
|
3344
|
+
pathContains(grantedPath, requestedPath) {
|
|
3345
|
+
if (grantedPath === "" || grantedPath === "/") {
|
|
3346
|
+
return true;
|
|
3347
|
+
}
|
|
3348
|
+
if (grantedPath.endsWith("/**")) {
|
|
3349
|
+
return requestedPath.startsWith(grantedPath.slice(0, -3));
|
|
3350
|
+
}
|
|
3351
|
+
if (grantedPath.endsWith("/*")) {
|
|
3352
|
+
const prefix = grantedPath.slice(0, -2);
|
|
3353
|
+
if (!requestedPath.startsWith(prefix)) {
|
|
3354
|
+
return false;
|
|
3355
|
+
}
|
|
3356
|
+
const remainder = requestedPath.slice(prefix.length);
|
|
3357
|
+
return !remainder.includes("/") || remainder === "/";
|
|
3358
|
+
}
|
|
3359
|
+
if (grantedPath.endsWith("/")) {
|
|
3360
|
+
return requestedPath.startsWith(grantedPath);
|
|
3361
|
+
}
|
|
3362
|
+
return grantedPath === requestedPath;
|
|
3363
|
+
}
|
|
2649
3364
|
/**
|
|
2650
3365
|
* Issue a delegation via the legacy wallet-signed SIWE path for a single
|
|
2651
3366
|
* {@link PermissionEntry}. Shares the implementation with the public
|
|
@@ -3033,15 +3748,18 @@ import {
|
|
|
3033
3748
|
ACCOUNT_REGISTRY_SPACE as ACCOUNT_REGISTRY_SPACE2,
|
|
3034
3749
|
DEFAULT_MANIFEST_SPACE as DEFAULT_MANIFEST_SPACE2,
|
|
3035
3750
|
DEFAULT_MANIFEST_VERSION,
|
|
3751
|
+
VAULT_PERMISSION_SERVICE,
|
|
3036
3752
|
PermissionNotInManifestError as PermissionNotInManifestError2,
|
|
3037
3753
|
SessionExpiredError as SessionExpiredError2,
|
|
3038
3754
|
ManifestValidationError,
|
|
3039
3755
|
composeManifestRequest as composeManifestRequest2,
|
|
3040
|
-
resolveManifest,
|
|
3756
|
+
resolveManifest as resolveManifest2,
|
|
3041
3757
|
validateManifest,
|
|
3042
3758
|
loadManifest,
|
|
3043
3759
|
isCapabilitySubset as isCapabilitySubset2,
|
|
3044
|
-
expandActionShortNames
|
|
3760
|
+
expandActionShortNames,
|
|
3761
|
+
expandPermissionEntries,
|
|
3762
|
+
expandPermissionEntry,
|
|
3045
3763
|
parseExpiry as parseExpiry2,
|
|
3046
3764
|
resourceCapabilitiesToSpaceAbilitiesMap as resourceCapabilitiesToSpaceAbilitiesMap2
|
|
3047
3765
|
} from "@tinycloud/sdk-core";
|
|
@@ -3066,7 +3784,16 @@ function deserializeDelegation(data) {
|
|
|
3066
3784
|
import { KVService as KVService3, PrefixedKVService } from "@tinycloud/sdk-core";
|
|
3067
3785
|
import { SQLService as SQLService3, SQLAction, DatabaseHandle } from "@tinycloud/sdk-core";
|
|
3068
3786
|
import { DuckDbService as DuckDbService3, DuckDbDatabaseHandle, DuckDbAction } from "@tinycloud/sdk-core";
|
|
3069
|
-
import {
|
|
3787
|
+
import {
|
|
3788
|
+
DataVaultService as DataVaultService2,
|
|
3789
|
+
VaultHeaders,
|
|
3790
|
+
VaultPublicSpaceKVActions,
|
|
3791
|
+
createVaultCrypto as createVaultCrypto2,
|
|
3792
|
+
SecretsService as SecretsService2,
|
|
3793
|
+
SECRET_NAME_RE,
|
|
3794
|
+
canonicalizeSecretScope,
|
|
3795
|
+
resolveSecretPath as resolveSecretPath2
|
|
3796
|
+
} from "@tinycloud/sdk-core";
|
|
3070
3797
|
import {
|
|
3071
3798
|
DelegationManager as DelegationManager2,
|
|
3072
3799
|
SharingService as SharingService2,
|
|
@@ -3118,8 +3845,10 @@ export {
|
|
|
3118
3845
|
PermissionNotInManifestError2 as PermissionNotInManifestError,
|
|
3119
3846
|
PrefixedKVService,
|
|
3120
3847
|
ProtocolMismatchError,
|
|
3848
|
+
SECRET_NAME_RE,
|
|
3121
3849
|
SQLAction,
|
|
3122
3850
|
SQLService3 as SQLService,
|
|
3851
|
+
SecretsService2 as SecretsService,
|
|
3123
3852
|
ServiceContext3 as ServiceContext,
|
|
3124
3853
|
SessionExpiredError2 as SessionExpiredError,
|
|
3125
3854
|
SharingService2 as SharingService,
|
|
@@ -3130,11 +3859,13 @@ export {
|
|
|
3130
3859
|
TinyCloud2 as TinyCloud,
|
|
3131
3860
|
TinyCloudNode,
|
|
3132
3861
|
UnsupportedFeatureError2 as UnsupportedFeatureError,
|
|
3862
|
+
VAULT_PERMISSION_SERVICE,
|
|
3133
3863
|
VaultHeaders,
|
|
3134
3864
|
VaultPublicSpaceKVActions,
|
|
3135
3865
|
VersionCheckError,
|
|
3136
3866
|
WasmKeyProvider,
|
|
3137
3867
|
buildSpaceUri,
|
|
3868
|
+
canonicalizeSecretScope,
|
|
3138
3869
|
checkNodeInfo2 as checkNodeInfo,
|
|
3139
3870
|
composeManifestRequest2 as composeManifestRequest,
|
|
3140
3871
|
createCapabilityKeyRegistry,
|
|
@@ -3145,13 +3876,16 @@ export {
|
|
|
3145
3876
|
defaultSignStrategy,
|
|
3146
3877
|
defaultSpaceCreationHandler,
|
|
3147
3878
|
deserializeDelegation,
|
|
3148
|
-
|
|
3879
|
+
expandActionShortNames,
|
|
3880
|
+
expandPermissionEntries,
|
|
3881
|
+
expandPermissionEntry,
|
|
3149
3882
|
isCapabilitySubset2 as isCapabilitySubset,
|
|
3150
3883
|
loadManifest,
|
|
3151
3884
|
makePublicSpaceId2 as makePublicSpaceId,
|
|
3152
3885
|
parseExpiry2 as parseExpiry,
|
|
3153
3886
|
parseSpaceUri,
|
|
3154
|
-
resolveManifest,
|
|
3887
|
+
resolveManifest2 as resolveManifest,
|
|
3888
|
+
resolveSecretPath2 as resolveSecretPath,
|
|
3155
3889
|
resourceCapabilitiesToSpaceAbilitiesMap2 as resourceCapabilitiesToSpaceAbilitiesMap,
|
|
3156
3890
|
serializeDelegation,
|
|
3157
3891
|
validateManifest
|