@tinycloud/node-sdk 2.2.0-beta.1 → 2.2.0-beta.11
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/core-BSqBtkg3.d.cts +1553 -0
- package/dist/core-BSqBtkg3.d.ts +1553 -0
- package/dist/core.cjs +943 -190
- 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 +869 -102
- package/dist/core.js.map +1 -1
- package/dist/index.cjs +946 -193
- 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 +864 -102
- package/dist/index.js.map +1 -1
- package/package.json +4 -4
package/dist/core.js
CHANGED
|
@@ -207,7 +207,9 @@ import {
|
|
|
207
207
|
DEFAULT_MANIFEST_SPACE,
|
|
208
208
|
composeManifestRequest,
|
|
209
209
|
resourceCapabilitiesToAbilitiesMap,
|
|
210
|
-
resourceCapabilitiesToSpaceAbilitiesMap
|
|
210
|
+
resourceCapabilitiesToSpaceAbilitiesMap,
|
|
211
|
+
resolveTinyCloudHosts,
|
|
212
|
+
EXPIRY
|
|
211
213
|
} from "@tinycloud/sdk-core";
|
|
212
214
|
|
|
213
215
|
// src/authorization/strategies.ts
|
|
@@ -267,12 +269,12 @@ var NodeUserAuthorization = class {
|
|
|
267
269
|
]
|
|
268
270
|
}
|
|
269
271
|
};
|
|
270
|
-
this.sessionExpirationMs = config.sessionExpirationMs ??
|
|
272
|
+
this.sessionExpirationMs = config.sessionExpirationMs ?? EXPIRY.SESSION_MS;
|
|
271
273
|
this.autoCreateSpace = config.autoCreateSpace ?? false;
|
|
272
274
|
this.spaceCreationHandler = config.spaceCreationHandler;
|
|
273
|
-
this.tinycloudHosts = config.tinycloudHosts
|
|
274
|
-
|
|
275
|
-
|
|
275
|
+
this.tinycloudHosts = config.tinycloudHosts;
|
|
276
|
+
this.tinycloudRegistryUrl = config.tinycloudRegistryUrl;
|
|
277
|
+
this.tinycloudFallbackHosts = config.tinycloudFallbackHosts;
|
|
276
278
|
this.enablePublicSpace = config.enablePublicSpace ?? true;
|
|
277
279
|
this.nonce = config.nonce;
|
|
278
280
|
this.siweConfig = config.siweConfig;
|
|
@@ -293,6 +295,9 @@ var NodeUserAuthorization = class {
|
|
|
293
295
|
get capabilityRequest() {
|
|
294
296
|
return this.getCapabilityRequest();
|
|
295
297
|
}
|
|
298
|
+
get hosts() {
|
|
299
|
+
return this.tinycloudHosts ? [...this.tinycloudHosts] : [];
|
|
300
|
+
}
|
|
296
301
|
/**
|
|
297
302
|
* Install or replace the stored manifest. Takes effect on the next
|
|
298
303
|
* `signIn()` call — the current session (if any) is not touched.
|
|
@@ -317,6 +322,26 @@ var NodeUserAuthorization = class {
|
|
|
317
322
|
get tinyCloudSession() {
|
|
318
323
|
return this._tinyCloudSession;
|
|
319
324
|
}
|
|
325
|
+
async resolveTinyCloudHostsForSignIn(address, chainId) {
|
|
326
|
+
if (this.tinycloudHosts && this.tinycloudHosts.length > 0) {
|
|
327
|
+
return;
|
|
328
|
+
}
|
|
329
|
+
const subject = `did:pkh:eip155:${chainId}:${address}`;
|
|
330
|
+
const resolved = await resolveTinyCloudHosts(subject, {
|
|
331
|
+
registryUrl: this.tinycloudRegistryUrl,
|
|
332
|
+
fallbackHosts: this.tinycloudFallbackHosts
|
|
333
|
+
});
|
|
334
|
+
this.tinycloudHosts = resolved.hosts;
|
|
335
|
+
}
|
|
336
|
+
requireTinyCloudHosts() {
|
|
337
|
+
if (!this.tinycloudHosts || this.tinycloudHosts.length === 0) {
|
|
338
|
+
throw new Error("TinyCloud hosts have not been resolved. Call signIn() first.");
|
|
339
|
+
}
|
|
340
|
+
return this.tinycloudHosts;
|
|
341
|
+
}
|
|
342
|
+
get primaryTinyCloudHost() {
|
|
343
|
+
return this.requireTinyCloudHosts()[0];
|
|
344
|
+
}
|
|
320
345
|
get nodeFeatures() {
|
|
321
346
|
return this._nodeFeatures;
|
|
322
347
|
}
|
|
@@ -448,7 +473,7 @@ var NodeUserAuthorization = class {
|
|
|
448
473
|
if (!this._tinyCloudSession || !this._address || !this._chainId) {
|
|
449
474
|
throw new Error("Must be signed in to host space");
|
|
450
475
|
}
|
|
451
|
-
const host = this.
|
|
476
|
+
const host = this.primaryTinyCloudHost;
|
|
452
477
|
const spaceId = targetSpaceId ?? this._tinyCloudSession.spaceId;
|
|
453
478
|
const peerId = await fetchPeerId(host, spaceId);
|
|
454
479
|
const siwe = this.wasm.generateHostSIWEMessage({
|
|
@@ -490,7 +515,7 @@ var NodeUserAuthorization = class {
|
|
|
490
515
|
if (!this._tinyCloudSession) {
|
|
491
516
|
throw new Error("Must be signed in to ensure space exists");
|
|
492
517
|
}
|
|
493
|
-
const host = this.
|
|
518
|
+
const host = this.primaryTinyCloudHost;
|
|
494
519
|
const primarySpaceId = this._tinyCloudSession.spaceId;
|
|
495
520
|
const result = await activateSessionWithHost(
|
|
496
521
|
host,
|
|
@@ -599,6 +624,7 @@ var NodeUserAuthorization = class {
|
|
|
599
624
|
this._chainId = await this.signer.getChainId();
|
|
600
625
|
const address = this.wasm.ensureEip55(this._address);
|
|
601
626
|
const chainId = this._chainId;
|
|
627
|
+
await this.resolveTinyCloudHostsForSignIn(address, chainId);
|
|
602
628
|
const keyId = `session-${Date.now()}`;
|
|
603
629
|
this.sessionManager.renameSessionKeyId("default", keyId);
|
|
604
630
|
const jwkString = this.sessionManager.jwk(keyId);
|
|
@@ -677,7 +703,7 @@ var NodeUserAuthorization = class {
|
|
|
677
703
|
this._address = address;
|
|
678
704
|
this._chainId = chainId;
|
|
679
705
|
const nodeInfo = await checkNodeInfo(
|
|
680
|
-
this.
|
|
706
|
+
this.primaryTinyCloudHost,
|
|
681
707
|
this.wasm.protocolVersion()
|
|
682
708
|
);
|
|
683
709
|
this._nodeFeatures = nodeInfo.features;
|
|
@@ -793,6 +819,7 @@ var NodeUserAuthorization = class {
|
|
|
793
819
|
});
|
|
794
820
|
const address = this.wasm.ensureEip55(await this.signer.getAddress());
|
|
795
821
|
const chainId = await this.signer.getChainId();
|
|
822
|
+
await this.resolveTinyCloudHostsForSignIn(address, chainId);
|
|
796
823
|
const clientSession = {
|
|
797
824
|
address,
|
|
798
825
|
walletAddress: address,
|
|
@@ -842,7 +869,7 @@ var NodeUserAuthorization = class {
|
|
|
842
869
|
this._address = address;
|
|
843
870
|
this._chainId = chainId;
|
|
844
871
|
const nodeInfo = await checkNodeInfo(
|
|
845
|
-
this.
|
|
872
|
+
this.primaryTinyCloudHost,
|
|
846
873
|
this.wasm.protocolVersion()
|
|
847
874
|
);
|
|
848
875
|
this._nodeFeatures = nodeInfo.features;
|
|
@@ -933,6 +960,7 @@ import {
|
|
|
933
960
|
DuckDbService as DuckDbService2,
|
|
934
961
|
HooksService as HooksService2,
|
|
935
962
|
DataVaultService,
|
|
963
|
+
SecretsService,
|
|
936
964
|
createVaultCrypto,
|
|
937
965
|
ServiceContext as ServiceContext2,
|
|
938
966
|
SilentNotificationHandler,
|
|
@@ -945,10 +973,11 @@ import {
|
|
|
945
973
|
ACCOUNT_REGISTRY_SPACE,
|
|
946
974
|
PermissionNotInManifestError,
|
|
947
975
|
SessionExpiredError,
|
|
948
|
-
|
|
976
|
+
expandPermissionEntries as expandPermissionEntriesCore,
|
|
949
977
|
isCapabilitySubset,
|
|
950
978
|
parseRecapCapabilities,
|
|
951
|
-
SERVICE_LONG_TO_SHORT
|
|
979
|
+
SERVICE_LONG_TO_SHORT,
|
|
980
|
+
EXPIRY as EXPIRY3
|
|
952
981
|
} from "@tinycloud/sdk-core";
|
|
953
982
|
|
|
954
983
|
// src/DelegatedAccess.ts
|
|
@@ -1033,6 +1062,24 @@ var DelegatedAccess = class {
|
|
|
1033
1062
|
get hooks() {
|
|
1034
1063
|
return this._hooks;
|
|
1035
1064
|
}
|
|
1065
|
+
/**
|
|
1066
|
+
* Export the handles needed to rehydrate this activated delegation via
|
|
1067
|
+
* `TinyCloudNode.restoreSession(...)` in another process or after a
|
|
1068
|
+
* restart.
|
|
1069
|
+
*
|
|
1070
|
+
* See `RestorableSession` for lifetime caveats.
|
|
1071
|
+
*/
|
|
1072
|
+
get restorable() {
|
|
1073
|
+
return {
|
|
1074
|
+
delegationHeader: this.session.delegationHeader,
|
|
1075
|
+
delegationCid: this.session.delegationCid,
|
|
1076
|
+
spaceId: this.session.spaceId,
|
|
1077
|
+
jwk: this.session.jwk,
|
|
1078
|
+
verificationMethod: this.session.verificationMethod,
|
|
1079
|
+
address: this.session.address,
|
|
1080
|
+
chainId: this.session.chainId
|
|
1081
|
+
};
|
|
1082
|
+
}
|
|
1036
1083
|
};
|
|
1037
1084
|
|
|
1038
1085
|
// src/keys/WasmKeyProvider.ts
|
|
@@ -1113,7 +1160,8 @@ function createWasmKeyProvider(sessionManager) {
|
|
|
1113
1160
|
// src/delegateToHelpers.ts
|
|
1114
1161
|
import {
|
|
1115
1162
|
parseExpiry,
|
|
1116
|
-
SiweMessage
|
|
1163
|
+
SiweMessage,
|
|
1164
|
+
EXPIRY as EXPIRY2
|
|
1117
1165
|
} from "@tinycloud/sdk-core";
|
|
1118
1166
|
function legacyParamsToPermissionEntries(actions, path, spaceIdOverride) {
|
|
1119
1167
|
const byService = /* @__PURE__ */ new Map();
|
|
@@ -1145,9 +1193,10 @@ function legacyParamsToPermissionEntries(actions, path, spaceIdOverride) {
|
|
|
1145
1193
|
}
|
|
1146
1194
|
return entries;
|
|
1147
1195
|
}
|
|
1196
|
+
var DEFAULT_DELEGATION_EXPIRY_MS = EXPIRY2.SESSION_MS;
|
|
1148
1197
|
function resolveExpiryMs(expiry) {
|
|
1149
1198
|
if (expiry === void 0) {
|
|
1150
|
-
return
|
|
1199
|
+
return DEFAULT_DELEGATION_EXPIRY_MS;
|
|
1151
1200
|
}
|
|
1152
1201
|
if (typeof expiry === "number") {
|
|
1153
1202
|
if (!Number.isFinite(expiry) || expiry <= 0) {
|
|
@@ -1173,8 +1222,155 @@ function extractSiweExpiration(siwe) {
|
|
|
1173
1222
|
return d;
|
|
1174
1223
|
}
|
|
1175
1224
|
|
|
1225
|
+
// src/NodeSecretsService.ts
|
|
1226
|
+
import {
|
|
1227
|
+
ErrorCodes,
|
|
1228
|
+
resolveSecretPath,
|
|
1229
|
+
resolveManifest
|
|
1230
|
+
} from "@tinycloud/sdk-core";
|
|
1231
|
+
var SECRETS_SPACE = "secrets";
|
|
1232
|
+
function ok() {
|
|
1233
|
+
return { ok: true, data: void 0 };
|
|
1234
|
+
}
|
|
1235
|
+
function secretsError(code, message, cause) {
|
|
1236
|
+
return {
|
|
1237
|
+
ok: false,
|
|
1238
|
+
error: {
|
|
1239
|
+
code,
|
|
1240
|
+
service: "secrets",
|
|
1241
|
+
message,
|
|
1242
|
+
...cause ? { cause } : {}
|
|
1243
|
+
}
|
|
1244
|
+
};
|
|
1245
|
+
}
|
|
1246
|
+
function displayActionUrn(action) {
|
|
1247
|
+
return action === "put" ? "tinycloud.vault/write" : "tinycloud.vault/delete";
|
|
1248
|
+
}
|
|
1249
|
+
function kvActionUrn(action) {
|
|
1250
|
+
return `tinycloud.kv/${action}`;
|
|
1251
|
+
}
|
|
1252
|
+
function vaultMutationAction(action) {
|
|
1253
|
+
return action === "put" ? "write" : "delete";
|
|
1254
|
+
}
|
|
1255
|
+
function secretPermissionEntries(name, options, action) {
|
|
1256
|
+
const secretPath = resolveSecretPath(name, options);
|
|
1257
|
+
return [
|
|
1258
|
+
{
|
|
1259
|
+
service: "tinycloud.vault",
|
|
1260
|
+
space: SECRETS_SPACE,
|
|
1261
|
+
path: secretPath.vaultKey,
|
|
1262
|
+
actions: [vaultMutationAction(action)],
|
|
1263
|
+
skipPrefix: true
|
|
1264
|
+
}
|
|
1265
|
+
];
|
|
1266
|
+
}
|
|
1267
|
+
function isSecretsSpace(space) {
|
|
1268
|
+
return space === SECRETS_SPACE || space.endsWith(`:${SECRETS_SPACE}`);
|
|
1269
|
+
}
|
|
1270
|
+
var NodeSecretsService = class {
|
|
1271
|
+
constructor(config) {
|
|
1272
|
+
this.config = config;
|
|
1273
|
+
this.shouldRestoreUnlock = false;
|
|
1274
|
+
}
|
|
1275
|
+
get vault() {
|
|
1276
|
+
return this.service.vault;
|
|
1277
|
+
}
|
|
1278
|
+
get isUnlocked() {
|
|
1279
|
+
return this.service.isUnlocked;
|
|
1280
|
+
}
|
|
1281
|
+
async unlock(signer) {
|
|
1282
|
+
const effectiveSigner = signer ?? this.config.getUnlockSigner?.();
|
|
1283
|
+
if (effectiveSigner !== void 0) {
|
|
1284
|
+
this.unlockSigner = effectiveSigner;
|
|
1285
|
+
}
|
|
1286
|
+
const result = await this.service.unlock(effectiveSigner);
|
|
1287
|
+
if (result.ok) {
|
|
1288
|
+
this.shouldRestoreUnlock = true;
|
|
1289
|
+
}
|
|
1290
|
+
return result;
|
|
1291
|
+
}
|
|
1292
|
+
lock() {
|
|
1293
|
+
this.shouldRestoreUnlock = false;
|
|
1294
|
+
this.service.lock();
|
|
1295
|
+
}
|
|
1296
|
+
get(name, options) {
|
|
1297
|
+
return options === void 0 ? this.service.get(name) : this.service.get(name, options);
|
|
1298
|
+
}
|
|
1299
|
+
async put(name, value, options) {
|
|
1300
|
+
const permission = await this.ensureMutationPermission(name, options, "put");
|
|
1301
|
+
if (!permission.ok) return permission;
|
|
1302
|
+
return options === void 0 ? this.service.put(name, value) : this.service.put(name, value, options);
|
|
1303
|
+
}
|
|
1304
|
+
async delete(name, options) {
|
|
1305
|
+
const permission = await this.ensureMutationPermission(name, options, "del");
|
|
1306
|
+
if (!permission.ok) return permission;
|
|
1307
|
+
return options === void 0 ? this.service.delete(name) : this.service.delete(name, options);
|
|
1308
|
+
}
|
|
1309
|
+
list(options) {
|
|
1310
|
+
return options === void 0 ? this.service.list() : this.service.list(options);
|
|
1311
|
+
}
|
|
1312
|
+
get service() {
|
|
1313
|
+
return this.config.getService();
|
|
1314
|
+
}
|
|
1315
|
+
async ensureMutationPermission(name, options, action) {
|
|
1316
|
+
let permissionEntries;
|
|
1317
|
+
try {
|
|
1318
|
+
permissionEntries = secretPermissionEntries(name, options, action);
|
|
1319
|
+
} catch (error) {
|
|
1320
|
+
return secretsError(
|
|
1321
|
+
ErrorCodes.INVALID_INPUT,
|
|
1322
|
+
error instanceof Error ? error.message : String(error),
|
|
1323
|
+
error instanceof Error ? error : void 0
|
|
1324
|
+
);
|
|
1325
|
+
}
|
|
1326
|
+
if (this.hasMutationPermission(name, options, action)) {
|
|
1327
|
+
return ok();
|
|
1328
|
+
}
|
|
1329
|
+
if (!this.config.canEscalate()) {
|
|
1330
|
+
return secretsError(
|
|
1331
|
+
ErrorCodes.PERMISSION_DENIED,
|
|
1332
|
+
`Cannot autosign ${displayActionUrn(action)} for ${name}; TinyCloudNode needs wallet mode with a signer or privateKey.`
|
|
1333
|
+
);
|
|
1334
|
+
}
|
|
1335
|
+
try {
|
|
1336
|
+
await this.config.grantPermissions(permissionEntries);
|
|
1337
|
+
return this.restoreUnlockAfterEscalation();
|
|
1338
|
+
} catch (error) {
|
|
1339
|
+
return secretsError(
|
|
1340
|
+
ErrorCodes.PERMISSION_DENIED,
|
|
1341
|
+
error instanceof Error ? error.message : `Autosign escalation for ${displayActionUrn(action)} on ${name} failed.`,
|
|
1342
|
+
error instanceof Error ? error : void 0
|
|
1343
|
+
);
|
|
1344
|
+
}
|
|
1345
|
+
}
|
|
1346
|
+
async restoreUnlockAfterEscalation() {
|
|
1347
|
+
if (!this.shouldRestoreUnlock) {
|
|
1348
|
+
return ok();
|
|
1349
|
+
}
|
|
1350
|
+
return this.service.unlock(this.unlockSigner);
|
|
1351
|
+
}
|
|
1352
|
+
hasMutationPermission(name, options, action) {
|
|
1353
|
+
const manifest = this.config.getManifest();
|
|
1354
|
+
if (manifest === void 0) {
|
|
1355
|
+
return false;
|
|
1356
|
+
}
|
|
1357
|
+
const manifests = Array.isArray(manifest) ? manifest : [manifest];
|
|
1358
|
+
const requiredAction = kvActionUrn(action);
|
|
1359
|
+
const secretPath = resolveSecretPath(name, options);
|
|
1360
|
+
return manifests.some((entry) => {
|
|
1361
|
+
const resolved = resolveManifest(entry);
|
|
1362
|
+
return ["keys", "vault"].every(
|
|
1363
|
+
(base) => resolved.resources.some(
|
|
1364
|
+
(resource) => resource.service === "tinycloud.kv" && isSecretsSpace(resource.space) && resource.path === secretPath.permissionPaths[base] && resource.actions.includes(requiredAction)
|
|
1365
|
+
)
|
|
1366
|
+
);
|
|
1367
|
+
});
|
|
1368
|
+
}
|
|
1369
|
+
};
|
|
1370
|
+
|
|
1176
1371
|
// src/TinyCloudNode.ts
|
|
1177
1372
|
var DEFAULT_HOST = "https://node.tinycloud.xyz";
|
|
1373
|
+
var DEFAULT_SESSION_EXPIRATION_MS = EXPIRY3.SESSION_MS;
|
|
1178
1374
|
var _TinyCloudNode = class _TinyCloudNode {
|
|
1179
1375
|
/**
|
|
1180
1376
|
* Create a new TinyCloudNode instance.
|
|
@@ -1204,6 +1400,31 @@ var _TinyCloudNode = class _TinyCloudNode {
|
|
|
1204
1400
|
this.auth = null;
|
|
1205
1401
|
this.tc = null;
|
|
1206
1402
|
this._chainId = 1;
|
|
1403
|
+
this.runtimePermissionGrants = [];
|
|
1404
|
+
this.invokeWithRuntimePermissions = (session, service, path, action, facts) => {
|
|
1405
|
+
return this.wasmBindings.invoke(
|
|
1406
|
+
this.selectInvocationSession(session, service, path, action),
|
|
1407
|
+
service,
|
|
1408
|
+
path,
|
|
1409
|
+
action,
|
|
1410
|
+
facts
|
|
1411
|
+
);
|
|
1412
|
+
};
|
|
1413
|
+
this.invokeAnyWithRuntimePermissions = (session, entries, facts) => {
|
|
1414
|
+
if (!this.wasmBindings.invokeAny) {
|
|
1415
|
+
throw new Error("WASM binding does not support invokeAny");
|
|
1416
|
+
}
|
|
1417
|
+
const grant = this.findGrantForOperations(
|
|
1418
|
+
entries.map((entry) => ({
|
|
1419
|
+
spaceId: entry.spaceId,
|
|
1420
|
+
service: this.invocationServiceName(entry.service),
|
|
1421
|
+
path: entry.path,
|
|
1422
|
+
action: entry.action
|
|
1423
|
+
}))
|
|
1424
|
+
);
|
|
1425
|
+
return this.wasmBindings.invokeAny(grant?.session ?? session, entries, facts);
|
|
1426
|
+
};
|
|
1427
|
+
this.explicitHost = config.host;
|
|
1207
1428
|
this.config = {
|
|
1208
1429
|
...config,
|
|
1209
1430
|
host: config.host ?? DEFAULT_HOST
|
|
@@ -1238,7 +1459,7 @@ var _TinyCloudNode = class _TinyCloudNode {
|
|
|
1238
1459
|
this._sharingService = new SharingService({
|
|
1239
1460
|
hosts: [this.config.host],
|
|
1240
1461
|
// session: undefined - not needed for receive()
|
|
1241
|
-
invoke: this.
|
|
1462
|
+
invoke: this.invokeWithRuntimePermissions,
|
|
1242
1463
|
fetch: globalThis.fetch.bind(globalThis),
|
|
1243
1464
|
keyProvider: this._keyProvider,
|
|
1244
1465
|
registry: this._capabilityRegistry,
|
|
@@ -1285,7 +1506,6 @@ var _TinyCloudNode = class _TinyCloudNode {
|
|
|
1285
1506
|
* @internal
|
|
1286
1507
|
*/
|
|
1287
1508
|
setupAuth(config) {
|
|
1288
|
-
const host = this.config.host;
|
|
1289
1509
|
this.auth = new NodeUserAuthorization({
|
|
1290
1510
|
signer: this.signer,
|
|
1291
1511
|
signStrategy: { type: "auto-sign" },
|
|
@@ -1293,8 +1513,10 @@ var _TinyCloudNode = class _TinyCloudNode {
|
|
|
1293
1513
|
sessionStorage: config.sessionStorage ?? new MemorySessionStorage(),
|
|
1294
1514
|
domain: this.siweDomain,
|
|
1295
1515
|
spacePrefix: config.prefix,
|
|
1296
|
-
sessionExpirationMs: config.sessionExpirationMs ??
|
|
1297
|
-
tinycloudHosts: [
|
|
1516
|
+
sessionExpirationMs: config.sessionExpirationMs ?? DEFAULT_SESSION_EXPIRATION_MS,
|
|
1517
|
+
tinycloudHosts: this.explicitHost ? [this.explicitHost] : void 0,
|
|
1518
|
+
tinycloudRegistryUrl: config.tinycloudRegistryUrl,
|
|
1519
|
+
tinycloudFallbackHosts: config.tinycloudFallbackHosts,
|
|
1298
1520
|
autoCreateSpace: config.autoCreateSpace,
|
|
1299
1521
|
enablePublicSpace: config.enablePublicSpace ?? true,
|
|
1300
1522
|
spaceCreationHandler: config.spaceCreationHandler,
|
|
@@ -1305,9 +1527,15 @@ var _TinyCloudNode = class _TinyCloudNode {
|
|
|
1305
1527
|
includeAccountRegistryPermissions: config.includeAccountRegistryPermissions
|
|
1306
1528
|
});
|
|
1307
1529
|
this.tc = new TinyCloud(this.auth, {
|
|
1308
|
-
invokeAny: this.
|
|
1530
|
+
invokeAny: this.invokeAnyWithRuntimePermissions
|
|
1309
1531
|
});
|
|
1310
1532
|
}
|
|
1533
|
+
syncResolvedHostFromAuth() {
|
|
1534
|
+
const host = this.auth?.hosts[0];
|
|
1535
|
+
if (host) {
|
|
1536
|
+
this.config.host = host;
|
|
1537
|
+
}
|
|
1538
|
+
}
|
|
1311
1539
|
/**
|
|
1312
1540
|
* Install or replace the manifest that drives the SIWE recap at
|
|
1313
1541
|
* sign-in. Takes effect on the next `signIn()` call — the current
|
|
@@ -1345,6 +1573,10 @@ var _TinyCloudNode = class _TinyCloudNode {
|
|
|
1345
1573
|
get capabilityRequest() {
|
|
1346
1574
|
return this.auth?.capabilityRequest;
|
|
1347
1575
|
}
|
|
1576
|
+
get hosts() {
|
|
1577
|
+
const authHosts = this.auth?.hosts ?? [];
|
|
1578
|
+
return authHosts.length > 0 ? authHosts : [this.config.host];
|
|
1579
|
+
}
|
|
1348
1580
|
/**
|
|
1349
1581
|
* Get the primary identity DID for this user.
|
|
1350
1582
|
* - If wallet connected and signed in: returns PKH DID (did:pkh:eip155:{chainId}:{address})
|
|
@@ -1415,8 +1647,14 @@ var _TinyCloudNode = class _TinyCloudNode {
|
|
|
1415
1647
|
this._sql = void 0;
|
|
1416
1648
|
this._duckdb = void 0;
|
|
1417
1649
|
this._hooks = void 0;
|
|
1650
|
+
this._vault = void 0;
|
|
1651
|
+
this._baseSecrets = void 0;
|
|
1652
|
+
this._secrets = void 0;
|
|
1653
|
+
this._spaceService = void 0;
|
|
1418
1654
|
this._serviceContext = void 0;
|
|
1655
|
+
this.runtimePermissionGrants = [];
|
|
1419
1656
|
await this.tc.signIn(options);
|
|
1657
|
+
this.syncResolvedHostFromAuth();
|
|
1420
1658
|
this.initializeServices();
|
|
1421
1659
|
await this.writeManifestRegistryRecords();
|
|
1422
1660
|
this.notificationHandler.success("Successfully signed in");
|
|
@@ -1436,7 +1674,7 @@ var _TinyCloudNode = class _TinyCloudNode {
|
|
|
1436
1674
|
throw new Error("Manifest registry write requires wallet mode");
|
|
1437
1675
|
}
|
|
1438
1676
|
const accountSpaceId = this.ownedSpaceId(ACCOUNT_REGISTRY_SPACE);
|
|
1439
|
-
await this.
|
|
1677
|
+
await this.ensureOwnedSpaceHosted(accountSpaceId);
|
|
1440
1678
|
const accountKV = this.spaces.get(accountSpaceId).kv;
|
|
1441
1679
|
for (const record of request.registryRecords) {
|
|
1442
1680
|
const result = await accountKV.put(record.key, {
|
|
@@ -1451,6 +1689,39 @@ var _TinyCloudNode = class _TinyCloudNode {
|
|
|
1451
1689
|
}
|
|
1452
1690
|
}
|
|
1453
1691
|
}
|
|
1692
|
+
async ensureOwnedSpaceHosted(spaceId) {
|
|
1693
|
+
if (!this.auth) {
|
|
1694
|
+
throw new Error("Owned space hosting requires wallet mode");
|
|
1695
|
+
}
|
|
1696
|
+
const session = this.auth.tinyCloudSession;
|
|
1697
|
+
if (!session) {
|
|
1698
|
+
throw new Error("Owned space hosting requires an active session");
|
|
1699
|
+
}
|
|
1700
|
+
const host = this.hosts[0] ?? this.config.host;
|
|
1701
|
+
if (!host) {
|
|
1702
|
+
throw new Error("Owned space hosting requires a TinyCloud host");
|
|
1703
|
+
}
|
|
1704
|
+
const activation = await activateSessionWithHost2(host, session.delegationHeader);
|
|
1705
|
+
if (activation.success && !activation.skipped?.includes(spaceId)) {
|
|
1706
|
+
return;
|
|
1707
|
+
}
|
|
1708
|
+
if (!activation.success && activation.status !== 404) {
|
|
1709
|
+
throw new Error(
|
|
1710
|
+
`Failed to check owned space ${spaceId}: ${activation.error ?? activation.status}`
|
|
1711
|
+
);
|
|
1712
|
+
}
|
|
1713
|
+
const created = await this.auth.hostOwnedSpace(spaceId);
|
|
1714
|
+
if (!created) {
|
|
1715
|
+
throw new Error(`Failed to create owned space: ${spaceId}`);
|
|
1716
|
+
}
|
|
1717
|
+
await new Promise((resolve) => setTimeout(resolve, 100));
|
|
1718
|
+
const retry = await activateSessionWithHost2(host, session.delegationHeader);
|
|
1719
|
+
if (!retry.success || retry.skipped?.includes(spaceId)) {
|
|
1720
|
+
throw new Error(
|
|
1721
|
+
`Failed to activate session after creating owned space ${spaceId}: ${retry.error ?? "space was skipped"}`
|
|
1722
|
+
);
|
|
1723
|
+
}
|
|
1724
|
+
}
|
|
1454
1725
|
/**
|
|
1455
1726
|
* Restore a previously established session from stored delegation data.
|
|
1456
1727
|
*
|
|
@@ -1466,7 +1737,12 @@ var _TinyCloudNode = class _TinyCloudNode {
|
|
|
1466
1737
|
this._sql = void 0;
|
|
1467
1738
|
this._duckdb = void 0;
|
|
1468
1739
|
this._hooks = void 0;
|
|
1740
|
+
this._vault = void 0;
|
|
1741
|
+
this._baseSecrets = void 0;
|
|
1742
|
+
this._secrets = void 0;
|
|
1743
|
+
this._spaceService = void 0;
|
|
1469
1744
|
this._serviceContext = void 0;
|
|
1745
|
+
this.runtimePermissionGrants = [];
|
|
1470
1746
|
if (sessionData.address) {
|
|
1471
1747
|
this._address = sessionData.address;
|
|
1472
1748
|
}
|
|
@@ -1474,8 +1750,8 @@ var _TinyCloudNode = class _TinyCloudNode {
|
|
|
1474
1750
|
this._chainId = sessionData.chainId;
|
|
1475
1751
|
}
|
|
1476
1752
|
this._serviceContext = new ServiceContext2({
|
|
1477
|
-
invoke: this.
|
|
1478
|
-
invokeAny: this.
|
|
1753
|
+
invoke: this.invokeWithRuntimePermissions,
|
|
1754
|
+
invokeAny: this.invokeAnyWithRuntimePermissions,
|
|
1479
1755
|
fetch: globalThis.fetch.bind(globalThis),
|
|
1480
1756
|
hosts: [this.config.host]
|
|
1481
1757
|
});
|
|
@@ -1499,41 +1775,7 @@ var _TinyCloudNode = class _TinyCloudNode {
|
|
|
1499
1775
|
jwk: sessionData.jwk
|
|
1500
1776
|
};
|
|
1501
1777
|
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
|
-
});
|
|
1778
|
+
this._vault = this.createVaultService(sessionData.spaceId, this._kv);
|
|
1537
1779
|
this._vault.initialize(this._serviceContext);
|
|
1538
1780
|
this._serviceContext.registerService("vault", this._vault);
|
|
1539
1781
|
this.initializeV2Services(serviceSession);
|
|
@@ -1568,7 +1810,6 @@ var _TinyCloudNode = class _TinyCloudNode {
|
|
|
1568
1810
|
throw new Error("Wallet already connected. Cannot connect another wallet.");
|
|
1569
1811
|
}
|
|
1570
1812
|
const prefix = options?.prefix ?? "default";
|
|
1571
|
-
const host = this.config.host;
|
|
1572
1813
|
if (!_TinyCloudNode.nodeDefaults) {
|
|
1573
1814
|
throw new Error(
|
|
1574
1815
|
"connectWallet() requires PrivateKeySigner. Use connectSigner() instead, or import from '@tinycloud/node-sdk' (not '/core') for automatic Node.js defaults."
|
|
@@ -1582,8 +1823,10 @@ var _TinyCloudNode = class _TinyCloudNode {
|
|
|
1582
1823
|
sessionStorage: options?.sessionStorage ?? this.config.sessionStorage ?? new MemorySessionStorage(),
|
|
1583
1824
|
domain: this.siweDomain,
|
|
1584
1825
|
spacePrefix: prefix,
|
|
1585
|
-
sessionExpirationMs: this.config.sessionExpirationMs ??
|
|
1586
|
-
tinycloudHosts: [
|
|
1826
|
+
sessionExpirationMs: this.config.sessionExpirationMs ?? DEFAULT_SESSION_EXPIRATION_MS,
|
|
1827
|
+
tinycloudHosts: this.explicitHost ? [this.explicitHost] : void 0,
|
|
1828
|
+
tinycloudRegistryUrl: this.config.tinycloudRegistryUrl,
|
|
1829
|
+
tinycloudFallbackHosts: this.config.tinycloudFallbackHosts,
|
|
1587
1830
|
autoCreateSpace: this.config.autoCreateSpace,
|
|
1588
1831
|
enablePublicSpace: this.config.enablePublicSpace ?? true,
|
|
1589
1832
|
spaceCreationHandler: this.config.spaceCreationHandler,
|
|
@@ -1594,7 +1837,7 @@ var _TinyCloudNode = class _TinyCloudNode {
|
|
|
1594
1837
|
includeAccountRegistryPermissions: this.config.includeAccountRegistryPermissions
|
|
1595
1838
|
});
|
|
1596
1839
|
this.tc = new TinyCloud(this.auth, {
|
|
1597
|
-
invokeAny: this.
|
|
1840
|
+
invokeAny: this.invokeAnyWithRuntimePermissions
|
|
1598
1841
|
});
|
|
1599
1842
|
this.config.prefix = prefix;
|
|
1600
1843
|
}
|
|
@@ -1616,7 +1859,6 @@ var _TinyCloudNode = class _TinyCloudNode {
|
|
|
1616
1859
|
throw new Error("Signer already connected. Cannot connect another signer.");
|
|
1617
1860
|
}
|
|
1618
1861
|
const prefix = options?.prefix ?? "default";
|
|
1619
|
-
const host = this.config.host;
|
|
1620
1862
|
this.signer = signer;
|
|
1621
1863
|
this.auth = new NodeUserAuthorization({
|
|
1622
1864
|
signer: this.signer,
|
|
@@ -1625,8 +1867,10 @@ var _TinyCloudNode = class _TinyCloudNode {
|
|
|
1625
1867
|
sessionStorage: options?.sessionStorage ?? this.config.sessionStorage ?? new MemorySessionStorage(),
|
|
1626
1868
|
domain: this.siweDomain,
|
|
1627
1869
|
spacePrefix: prefix,
|
|
1628
|
-
sessionExpirationMs: this.config.sessionExpirationMs ??
|
|
1629
|
-
tinycloudHosts: [
|
|
1870
|
+
sessionExpirationMs: this.config.sessionExpirationMs ?? DEFAULT_SESSION_EXPIRATION_MS,
|
|
1871
|
+
tinycloudHosts: this.explicitHost ? [this.explicitHost] : void 0,
|
|
1872
|
+
tinycloudRegistryUrl: this.config.tinycloudRegistryUrl,
|
|
1873
|
+
tinycloudFallbackHosts: this.config.tinycloudFallbackHosts,
|
|
1630
1874
|
autoCreateSpace: this.config.autoCreateSpace,
|
|
1631
1875
|
enablePublicSpace: this.config.enablePublicSpace ?? true,
|
|
1632
1876
|
spaceCreationHandler: this.config.spaceCreationHandler,
|
|
@@ -1637,7 +1881,7 @@ var _TinyCloudNode = class _TinyCloudNode {
|
|
|
1637
1881
|
includeAccountRegistryPermissions: this.config.includeAccountRegistryPermissions
|
|
1638
1882
|
});
|
|
1639
1883
|
this.tc = new TinyCloud(this.auth, {
|
|
1640
|
-
invokeAny: this.
|
|
1884
|
+
invokeAny: this.invokeAnyWithRuntimePermissions
|
|
1641
1885
|
});
|
|
1642
1886
|
this.config.prefix = prefix;
|
|
1643
1887
|
}
|
|
@@ -1650,10 +1894,10 @@ var _TinyCloudNode = class _TinyCloudNode {
|
|
|
1650
1894
|
if (!session) {
|
|
1651
1895
|
return;
|
|
1652
1896
|
}
|
|
1653
|
-
this.tc.initializeServices(this.
|
|
1897
|
+
this.tc.initializeServices(this.invokeWithRuntimePermissions, [this.config.host]);
|
|
1654
1898
|
this._serviceContext = new ServiceContext2({
|
|
1655
|
-
invoke: this.
|
|
1656
|
-
invokeAny: this.
|
|
1899
|
+
invoke: this.invokeWithRuntimePermissions,
|
|
1900
|
+
invokeAny: this.invokeAnyWithRuntimePermissions,
|
|
1657
1901
|
fetch: globalThis.fetch.bind(globalThis),
|
|
1658
1902
|
hosts: [this.config.host]
|
|
1659
1903
|
});
|
|
@@ -1683,6 +1927,28 @@ var _TinyCloudNode = class _TinyCloudNode {
|
|
|
1683
1927
|
};
|
|
1684
1928
|
this._serviceContext.setSession(serviceSession);
|
|
1685
1929
|
this.tc.serviceContext.setSession(serviceSession);
|
|
1930
|
+
this._vault = this.createVaultService(session.spaceId, this._kv);
|
|
1931
|
+
this._vault.initialize(this._serviceContext);
|
|
1932
|
+
this._serviceContext.registerService("vault", this._vault);
|
|
1933
|
+
this.initializeV2Services(serviceSession);
|
|
1934
|
+
}
|
|
1935
|
+
createSpaceScopedKVService(spaceId) {
|
|
1936
|
+
const kvService = new KVService2({});
|
|
1937
|
+
if (this._serviceContext) {
|
|
1938
|
+
const spaceScopedContext = new ServiceContext2({
|
|
1939
|
+
invoke: this._serviceContext.invoke,
|
|
1940
|
+
fetch: this._serviceContext.fetch,
|
|
1941
|
+
hosts: this._serviceContext.hosts
|
|
1942
|
+
});
|
|
1943
|
+
const session = this._serviceContext.session;
|
|
1944
|
+
if (session) {
|
|
1945
|
+
spaceScopedContext.setSession({ ...session, spaceId });
|
|
1946
|
+
}
|
|
1947
|
+
kvService.initialize(spaceScopedContext);
|
|
1948
|
+
}
|
|
1949
|
+
return kvService;
|
|
1950
|
+
}
|
|
1951
|
+
createVaultService(spaceId, kv) {
|
|
1686
1952
|
const wasm = this.wasmBindings;
|
|
1687
1953
|
const vaultCrypto = createVaultCrypto({
|
|
1688
1954
|
vault_encrypt: wasm.vault_encrypt,
|
|
@@ -1694,11 +1960,11 @@ var _TinyCloudNode = class _TinyCloudNode {
|
|
|
1694
1960
|
vault_sha256: wasm.vault_sha256
|
|
1695
1961
|
});
|
|
1696
1962
|
const self = this;
|
|
1697
|
-
|
|
1698
|
-
spaceId
|
|
1963
|
+
return new DataVaultService({
|
|
1964
|
+
spaceId,
|
|
1699
1965
|
crypto: vaultCrypto,
|
|
1700
1966
|
tc: {
|
|
1701
|
-
kv
|
|
1967
|
+
kv,
|
|
1702
1968
|
ensurePublicSpace: async () => {
|
|
1703
1969
|
try {
|
|
1704
1970
|
await self.ensurePublicSpace();
|
|
@@ -1710,17 +1976,14 @@ var _TinyCloudNode = class _TinyCloudNode {
|
|
|
1710
1976
|
get publicKV() {
|
|
1711
1977
|
return self._publicKV ?? self.tc.publicKV;
|
|
1712
1978
|
},
|
|
1713
|
-
readPublicSpace: (host,
|
|
1979
|
+
readPublicSpace: (host, targetSpaceId, key) => TinyCloud.readPublicSpace(host, targetSpaceId, key),
|
|
1714
1980
|
makePublicSpaceId: TinyCloud.makePublicSpaceId,
|
|
1715
1981
|
did: this.did,
|
|
1716
|
-
address: this._address,
|
|
1982
|
+
address: this._address ?? "",
|
|
1717
1983
|
chainId: this._chainId,
|
|
1718
1984
|
hosts: [this.config.host]
|
|
1719
1985
|
}
|
|
1720
1986
|
});
|
|
1721
|
-
this._vault.initialize(this._serviceContext);
|
|
1722
|
-
this._serviceContext.registerService("vault", this._vault);
|
|
1723
|
-
this.initializeV2Services(serviceSession);
|
|
1724
1987
|
}
|
|
1725
1988
|
/**
|
|
1726
1989
|
* Initialize the v2 delegation system services.
|
|
@@ -1804,7 +2067,7 @@ var _TinyCloudNode = class _TinyCloudNode {
|
|
|
1804
2067
|
this._delegationManager = new DelegationManager({
|
|
1805
2068
|
hosts: [this.config.host],
|
|
1806
2069
|
session: serviceSession,
|
|
1807
|
-
invoke: this.
|
|
2070
|
+
invoke: this.invokeWithRuntimePermissions,
|
|
1808
2071
|
fetch: globalThis.fetch.bind(globalThis)
|
|
1809
2072
|
});
|
|
1810
2073
|
this._spaceService = new SpaceService({
|
|
@@ -1815,20 +2078,15 @@ var _TinyCloudNode = class _TinyCloudNode {
|
|
|
1815
2078
|
capabilityRegistry: this._capabilityRegistry,
|
|
1816
2079
|
userDid: this.did,
|
|
1817
2080
|
createKVService: (spaceId) => {
|
|
1818
|
-
|
|
2081
|
+
return this.createSpaceScopedKVService(spaceId);
|
|
2082
|
+
},
|
|
2083
|
+
createVaultService: (spaceId) => {
|
|
2084
|
+
const kvService = this.createSpaceScopedKVService(spaceId);
|
|
2085
|
+
const vaultService = this.createVaultService(spaceId, kvService);
|
|
1819
2086
|
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);
|
|
2087
|
+
vaultService.initialize(this._serviceContext);
|
|
1830
2088
|
}
|
|
1831
|
-
return
|
|
2089
|
+
return vaultService;
|
|
1832
2090
|
},
|
|
1833
2091
|
// Enable space.delegations.create() via SIWE-based delegation
|
|
1834
2092
|
createDelegation: async (params) => {
|
|
@@ -1885,7 +2143,7 @@ var _TinyCloudNode = class _TinyCloudNode {
|
|
|
1885
2143
|
* @internal
|
|
1886
2144
|
*/
|
|
1887
2145
|
getSessionExpiry() {
|
|
1888
|
-
const expirationMs = this.config.sessionExpirationMs ??
|
|
2146
|
+
const expirationMs = this.config.sessionExpirationMs ?? DEFAULT_SESSION_EXPIRATION_MS;
|
|
1889
2147
|
return new Date(Date.now() + expirationMs);
|
|
1890
2148
|
}
|
|
1891
2149
|
/**
|
|
@@ -2042,6 +2300,34 @@ var _TinyCloudNode = class _TinyCloudNode {
|
|
|
2042
2300
|
}
|
|
2043
2301
|
return this._sql;
|
|
2044
2302
|
}
|
|
2303
|
+
/**
|
|
2304
|
+
* Get an SQL service scoped to a specific space.
|
|
2305
|
+
*
|
|
2306
|
+
* Mirrors {@link SpaceService}'s per-space KV factory: clones the active
|
|
2307
|
+
* service context and overrides its session's spaceId so that subsequent
|
|
2308
|
+
* `sql/<dbName>/<action>` invocations route to that space. Useful when
|
|
2309
|
+
* the caller already holds a delegation covering the target space (e.g.
|
|
2310
|
+
* via {@link grantRuntimePermissions} or {@link useRuntimeDelegation})
|
|
2311
|
+
* but the SDK's per-space SQL surface isn't otherwise exposed.
|
|
2312
|
+
*
|
|
2313
|
+
* Does NOT auto-create the space.
|
|
2314
|
+
*
|
|
2315
|
+
* @param spaceId - Full space URI (`tinycloud:pkh:eip155:<chain>:<addr>:<name>`).
|
|
2316
|
+
*/
|
|
2317
|
+
sqlForSpace(spaceId) {
|
|
2318
|
+
if (!this._serviceContext || !this._serviceContext.session) {
|
|
2319
|
+
throw new Error("Not signed in. Call signIn() first.");
|
|
2320
|
+
}
|
|
2321
|
+
const sql = new SQLService2({});
|
|
2322
|
+
const spaceScopedContext = new ServiceContext2({
|
|
2323
|
+
invoke: this._serviceContext.invoke,
|
|
2324
|
+
fetch: this._serviceContext.fetch,
|
|
2325
|
+
hosts: this._serviceContext.hosts
|
|
2326
|
+
});
|
|
2327
|
+
spaceScopedContext.setSession({ ...this._serviceContext.session, spaceId });
|
|
2328
|
+
sql.initialize(spaceScopedContext);
|
|
2329
|
+
return sql;
|
|
2330
|
+
}
|
|
2045
2331
|
/**
|
|
2046
2332
|
* DuckDB database operations on this user's space.
|
|
2047
2333
|
*/
|
|
@@ -2065,6 +2351,33 @@ var _TinyCloudNode = class _TinyCloudNode {
|
|
|
2065
2351
|
}
|
|
2066
2352
|
return this._vault;
|
|
2067
2353
|
}
|
|
2354
|
+
/**
|
|
2355
|
+
* App-facing secrets API backed by the `secrets` space vault.
|
|
2356
|
+
*/
|
|
2357
|
+
get secrets() {
|
|
2358
|
+
if (!this._spaceService) {
|
|
2359
|
+
throw new Error("Not signed in. Call signIn() first.");
|
|
2360
|
+
}
|
|
2361
|
+
if (!this._secrets) {
|
|
2362
|
+
this._secrets = new NodeSecretsService({
|
|
2363
|
+
getService: () => this.getBaseSecrets(),
|
|
2364
|
+
getManifest: () => this.manifest,
|
|
2365
|
+
grantPermissions: (additional) => this.grantRuntimePermissions(additional),
|
|
2366
|
+
canEscalate: () => this.signer !== void 0 && this.tc !== void 0,
|
|
2367
|
+
getUnlockSigner: () => this.signer ?? void 0
|
|
2368
|
+
});
|
|
2369
|
+
}
|
|
2370
|
+
return this._secrets;
|
|
2371
|
+
}
|
|
2372
|
+
getBaseSecrets() {
|
|
2373
|
+
if (!this._spaceService) {
|
|
2374
|
+
throw new Error("Not signed in. Call signIn() first.");
|
|
2375
|
+
}
|
|
2376
|
+
if (!this._baseSecrets) {
|
|
2377
|
+
this._baseSecrets = new SecretsService(() => this.space("secrets").vault);
|
|
2378
|
+
}
|
|
2379
|
+
return this._baseSecrets;
|
|
2380
|
+
}
|
|
2068
2381
|
/**
|
|
2069
2382
|
* Hooks write stream subscription API.
|
|
2070
2383
|
*/
|
|
@@ -2135,6 +2448,171 @@ var _TinyCloudNode = class _TinyCloudNode {
|
|
|
2135
2448
|
}
|
|
2136
2449
|
};
|
|
2137
2450
|
}
|
|
2451
|
+
/**
|
|
2452
|
+
* Check whether the current session or an approved runtime delegation covers
|
|
2453
|
+
* every requested permission.
|
|
2454
|
+
*/
|
|
2455
|
+
hasRuntimePermissions(permissions) {
|
|
2456
|
+
const session = this.auth?.tinyCloudSession;
|
|
2457
|
+
if (!session || !Array.isArray(permissions) || permissions.length === 0) {
|
|
2458
|
+
return false;
|
|
2459
|
+
}
|
|
2460
|
+
const expanded = this.expandPermissionEntries(permissions);
|
|
2461
|
+
if (this.sessionCoversPermissionEntries(session, expanded)) {
|
|
2462
|
+
return true;
|
|
2463
|
+
}
|
|
2464
|
+
return this.findRuntimeGrantsForPermissionEntries(expanded, session).length > 0;
|
|
2465
|
+
}
|
|
2466
|
+
/**
|
|
2467
|
+
* Return installed runtime permission delegations. When `permissions` is
|
|
2468
|
+
* provided, only delegations currently covering those permissions are
|
|
2469
|
+
* returned. Base-session manifest permissions are not represented here.
|
|
2470
|
+
*/
|
|
2471
|
+
getRuntimePermissionDelegations(permissions) {
|
|
2472
|
+
this.pruneExpiredRuntimePermissionGrants();
|
|
2473
|
+
if (permissions === void 0) {
|
|
2474
|
+
return this.runtimePermissionGrants.map((grant) => grant.delegation);
|
|
2475
|
+
}
|
|
2476
|
+
const session = this.auth?.tinyCloudSession;
|
|
2477
|
+
if (!session || !Array.isArray(permissions) || permissions.length === 0) {
|
|
2478
|
+
return [];
|
|
2479
|
+
}
|
|
2480
|
+
const expanded = this.expandPermissionEntries(permissions);
|
|
2481
|
+
return this.findRuntimeGrantsForPermissionEntries(expanded, session).map(
|
|
2482
|
+
(grant) => grant.delegation
|
|
2483
|
+
);
|
|
2484
|
+
}
|
|
2485
|
+
/**
|
|
2486
|
+
* Install a portable runtime permission delegation into this SDK instance so
|
|
2487
|
+
* matching service calls and downstream `delegateTo()` calls can use it.
|
|
2488
|
+
*/
|
|
2489
|
+
async useRuntimeDelegation(delegation) {
|
|
2490
|
+
const session = this.auth?.tinyCloudSession;
|
|
2491
|
+
if (!session) {
|
|
2492
|
+
throw new SessionExpiredError(/* @__PURE__ */ new Date(0));
|
|
2493
|
+
}
|
|
2494
|
+
if (delegation.expiry.getTime() <= Date.now()) {
|
|
2495
|
+
throw new SessionExpiredError(delegation.expiry);
|
|
2496
|
+
}
|
|
2497
|
+
const expectedDids = /* @__PURE__ */ new Set([session.verificationMethod, this.sessionDid]);
|
|
2498
|
+
if (!expectedDids.has(delegation.delegateDID)) {
|
|
2499
|
+
throw new Error(
|
|
2500
|
+
`Runtime delegation targets ${delegation.delegateDID} but this session key is ${session.verificationMethod}.`
|
|
2501
|
+
);
|
|
2502
|
+
}
|
|
2503
|
+
const targetHost = delegation.host ?? this.config.host;
|
|
2504
|
+
const activateResult = await activateSessionWithHost2(
|
|
2505
|
+
targetHost,
|
|
2506
|
+
delegation.delegationHeader
|
|
2507
|
+
);
|
|
2508
|
+
if (!activateResult.success) {
|
|
2509
|
+
throw new Error(
|
|
2510
|
+
`Failed to activate runtime permission delegation: ${activateResult.error}`
|
|
2511
|
+
);
|
|
2512
|
+
}
|
|
2513
|
+
this.runtimePermissionGrants = this.runtimePermissionGrants.filter(
|
|
2514
|
+
(grant) => grant.delegation.cid !== delegation.cid
|
|
2515
|
+
);
|
|
2516
|
+
this.runtimePermissionGrants.push(
|
|
2517
|
+
this.runtimeGrantFromDelegation(delegation, session)
|
|
2518
|
+
);
|
|
2519
|
+
}
|
|
2520
|
+
/**
|
|
2521
|
+
* Store additional permissions as narrow delegations to the current session
|
|
2522
|
+
* key. Future service invocations automatically use a stored delegation when
|
|
2523
|
+
* its `(space, service, path, action)` covers the request.
|
|
2524
|
+
*/
|
|
2525
|
+
async grantRuntimePermissions(permissions, options) {
|
|
2526
|
+
if (!Array.isArray(permissions) || permissions.length === 0) {
|
|
2527
|
+
throw new Error("grantRuntimePermissions requires a non-empty permissions array");
|
|
2528
|
+
}
|
|
2529
|
+
const session = this.auth?.tinyCloudSession;
|
|
2530
|
+
if (!session) {
|
|
2531
|
+
throw new SessionExpiredError(/* @__PURE__ */ new Date(0));
|
|
2532
|
+
}
|
|
2533
|
+
const sessionExpiry = extractSiweExpiration(session.siwe);
|
|
2534
|
+
if (sessionExpiry !== void 0) {
|
|
2535
|
+
const marginMs = _TinyCloudNode.SESSION_EXPIRY_SAFETY_MARGIN_MS;
|
|
2536
|
+
if (sessionExpiry.getTime() <= Date.now() + marginMs) {
|
|
2537
|
+
throw new SessionExpiredError(sessionExpiry);
|
|
2538
|
+
}
|
|
2539
|
+
}
|
|
2540
|
+
const expanded = this.expandPermissionEntries(permissions);
|
|
2541
|
+
if (this.sessionCoversPermissionEntries(session, expanded)) {
|
|
2542
|
+
return [];
|
|
2543
|
+
}
|
|
2544
|
+
const existingGrants = this.findRuntimeGrantsForPermissionEntries(expanded, session);
|
|
2545
|
+
if (existingGrants.length > 0) {
|
|
2546
|
+
return existingGrants.map((grant) => grant.delegation);
|
|
2547
|
+
}
|
|
2548
|
+
if (!this.signer) {
|
|
2549
|
+
throw new Error(
|
|
2550
|
+
"grantRuntimePermissions requires wallet mode with a signer or privateKey."
|
|
2551
|
+
);
|
|
2552
|
+
}
|
|
2553
|
+
const bySpace = /* @__PURE__ */ new Map();
|
|
2554
|
+
for (const entry of expanded) {
|
|
2555
|
+
const spaceId = this.resolvePermissionSpace(entry.space, session);
|
|
2556
|
+
const current = bySpace.get(spaceId) ?? [];
|
|
2557
|
+
current.push(entry);
|
|
2558
|
+
bySpace.set(spaceId, current);
|
|
2559
|
+
}
|
|
2560
|
+
const now = /* @__PURE__ */ new Date();
|
|
2561
|
+
const requestedExpiryMs = resolveExpiryMs(options?.expiry);
|
|
2562
|
+
let expiresAt = new Date(now.getTime() + requestedExpiryMs);
|
|
2563
|
+
if (sessionExpiry !== void 0 && sessionExpiry < expiresAt) {
|
|
2564
|
+
expiresAt = sessionExpiry;
|
|
2565
|
+
}
|
|
2566
|
+
const delegations = [];
|
|
2567
|
+
for (const [spaceId, entries] of bySpace) {
|
|
2568
|
+
const abilities = this.permissionsToAbilities(entries);
|
|
2569
|
+
const prepared = this.wasmBindings.prepareSession({
|
|
2570
|
+
abilities,
|
|
2571
|
+
address: this.wasmBindings.ensureEip55(session.address),
|
|
2572
|
+
chainId: session.chainId,
|
|
2573
|
+
domain: this.siweDomain,
|
|
2574
|
+
issuedAt: now.toISOString(),
|
|
2575
|
+
expirationTime: expiresAt.toISOString(),
|
|
2576
|
+
spaceId,
|
|
2577
|
+
jwk: session.jwk
|
|
2578
|
+
});
|
|
2579
|
+
const signature = await this.signer.signMessage(prepared.siwe);
|
|
2580
|
+
const delegatedSession = this.wasmBindings.completeSessionSetup({
|
|
2581
|
+
...prepared,
|
|
2582
|
+
signature
|
|
2583
|
+
});
|
|
2584
|
+
const activateResult = await activateSessionWithHost2(
|
|
2585
|
+
this.config.host,
|
|
2586
|
+
delegatedSession.delegationHeader
|
|
2587
|
+
);
|
|
2588
|
+
if (!activateResult.success) {
|
|
2589
|
+
throw new Error(
|
|
2590
|
+
`Failed to activate runtime permission delegation: ${activateResult.error}`
|
|
2591
|
+
);
|
|
2592
|
+
}
|
|
2593
|
+
const delegation = this.runtimeDelegationFromSession(
|
|
2594
|
+
delegatedSession,
|
|
2595
|
+
entries,
|
|
2596
|
+
spaceId,
|
|
2597
|
+
session,
|
|
2598
|
+
expiresAt
|
|
2599
|
+
);
|
|
2600
|
+
this.runtimePermissionGrants.push({
|
|
2601
|
+
session: {
|
|
2602
|
+
delegationHeader: delegatedSession.delegationHeader,
|
|
2603
|
+
delegationCid: delegatedSession.delegationCid,
|
|
2604
|
+
spaceId,
|
|
2605
|
+
verificationMethod: session.verificationMethod,
|
|
2606
|
+
jwk: session.jwk
|
|
2607
|
+
},
|
|
2608
|
+
delegation,
|
|
2609
|
+
operations: this.permissionOperations(entries, spaceId),
|
|
2610
|
+
expiresAt
|
|
2611
|
+
});
|
|
2612
|
+
delegations.push(delegation);
|
|
2613
|
+
}
|
|
2614
|
+
return delegations;
|
|
2615
|
+
}
|
|
2138
2616
|
/**
|
|
2139
2617
|
* Get the DelegationManager for delegation CRUD operations.
|
|
2140
2618
|
*
|
|
@@ -2203,6 +2681,12 @@ var _TinyCloudNode = class _TinyCloudNode {
|
|
|
2203
2681
|
get spaceService() {
|
|
2204
2682
|
return this.spaces;
|
|
2205
2683
|
}
|
|
2684
|
+
/**
|
|
2685
|
+
* Get a Space object by short name or full URI.
|
|
2686
|
+
*/
|
|
2687
|
+
space(nameOrUri) {
|
|
2688
|
+
return this.spaces.get(nameOrUri);
|
|
2689
|
+
}
|
|
2206
2690
|
/**
|
|
2207
2691
|
* Get the SharingService for creating and receiving v2 sharing links.
|
|
2208
2692
|
*
|
|
@@ -2270,7 +2754,7 @@ var _TinyCloudNode = class _TinyCloudNode {
|
|
|
2270
2754
|
];
|
|
2271
2755
|
const abilities = { kv: { "": kvActions } };
|
|
2272
2756
|
const now = /* @__PURE__ */ new Date();
|
|
2273
|
-
const expiryMs =
|
|
2757
|
+
const expiryMs = EXPIRY3.EPHEMERAL_MS;
|
|
2274
2758
|
const expirationTime = new Date(now.getTime() + expiryMs);
|
|
2275
2759
|
const prepared = this.wasmBindings.prepareSession({
|
|
2276
2760
|
abilities,
|
|
@@ -2317,7 +2801,7 @@ var _TinyCloudNode = class _TinyCloudNode {
|
|
|
2317
2801
|
if (this._serviceContext) {
|
|
2318
2802
|
const publicKV = new KVService2({ prefix: "" });
|
|
2319
2803
|
const publicContext = new ServiceContext2({
|
|
2320
|
-
invoke: this.
|
|
2804
|
+
invoke: this.invokeWithRuntimePermissions,
|
|
2321
2805
|
fetch: this._serviceContext.fetch,
|
|
2322
2806
|
hosts: this._serviceContext.hosts
|
|
2323
2807
|
});
|
|
@@ -2405,8 +2889,9 @@ var _TinyCloudNode = class _TinyCloudNode {
|
|
|
2405
2889
|
* Issue a delegation using the capability-chain flow.
|
|
2406
2890
|
*
|
|
2407
2891
|
* When every requested permission is a subset of the current
|
|
2408
|
-
* session's recap,
|
|
2409
|
-
*
|
|
2892
|
+
* session's recap, or of one installed runtime permission delegation,
|
|
2893
|
+
* the delegation is signed by the session key via WASM — no wallet
|
|
2894
|
+
* prompt. When at least one is NOT derivable, a
|
|
2410
2895
|
* {@link PermissionNotInManifestError} is raised (carrying the
|
|
2411
2896
|
* missing entries) so the caller can trigger an escalation flow
|
|
2412
2897
|
* (e.g. `TinyCloudWeb.requestPermissions`). Passing
|
|
@@ -2456,10 +2941,7 @@ var _TinyCloudNode = class _TinyCloudNode {
|
|
|
2456
2941
|
"delegateTo requires a non-empty permissions array"
|
|
2457
2942
|
);
|
|
2458
2943
|
}
|
|
2459
|
-
const expandedEntries =
|
|
2460
|
-
...entry,
|
|
2461
|
-
actions: expandActionShortNames(entry.service, entry.actions)
|
|
2462
|
-
}));
|
|
2944
|
+
const expandedEntries = this.expandPermissionEntries(permissions);
|
|
2463
2945
|
const now = /* @__PURE__ */ new Date();
|
|
2464
2946
|
const expiryMs = resolveExpiryMs(options?.expiry);
|
|
2465
2947
|
const expirationTime = new Date(now.getTime() + expiryMs);
|
|
@@ -2486,6 +2968,23 @@ var _TinyCloudNode = class _TinyCloudNode {
|
|
|
2486
2968
|
);
|
|
2487
2969
|
const { subset, missing } = isCapabilitySubset(expandedEntries, granted);
|
|
2488
2970
|
if (!subset) {
|
|
2971
|
+
const runtimeGrant = this.findGrantForOperations(
|
|
2972
|
+
this.permissionEntriesToOperations(expandedEntries, session)
|
|
2973
|
+
);
|
|
2974
|
+
if (runtimeGrant) {
|
|
2975
|
+
const marginMs = _TinyCloudNode.SESSION_EXPIRY_SAFETY_MARGIN_MS;
|
|
2976
|
+
if (runtimeGrant.expiresAt.getTime() <= Date.now() + marginMs) {
|
|
2977
|
+
throw new SessionExpiredError(runtimeGrant.expiresAt);
|
|
2978
|
+
}
|
|
2979
|
+
const runtimeExpiration = runtimeGrant.expiresAt < effectiveExpiration ? runtimeGrant.expiresAt : effectiveExpiration;
|
|
2980
|
+
const delegation2 = await this.createDelegationViaRuntimeGrant(
|
|
2981
|
+
did,
|
|
2982
|
+
expandedEntries,
|
|
2983
|
+
runtimeExpiration,
|
|
2984
|
+
runtimeGrant
|
|
2985
|
+
);
|
|
2986
|
+
return { delegation: delegation2, prompted: false };
|
|
2987
|
+
}
|
|
2489
2988
|
throw new PermissionNotInManifestError(missing, granted);
|
|
2490
2989
|
}
|
|
2491
2990
|
const delegation = await this.createDelegationViaWasmPath(
|
|
@@ -2630,6 +3129,41 @@ var _TinyCloudNode = class _TinyCloudNode {
|
|
|
2630
3129
|
host: this.config.host
|
|
2631
3130
|
};
|
|
2632
3131
|
}
|
|
3132
|
+
async createDelegationViaRuntimeGrant(did, entries, expirationTime, grant) {
|
|
3133
|
+
const result = this.createDelegationWrapper({
|
|
3134
|
+
session: grant.session,
|
|
3135
|
+
delegateDID: did,
|
|
3136
|
+
spaceId: grant.session.spaceId,
|
|
3137
|
+
abilities: this.permissionsToAbilities(entries),
|
|
3138
|
+
expirationSecs: Math.floor(expirationTime.getTime() / 1e3)
|
|
3139
|
+
});
|
|
3140
|
+
const primary = result.resources[0];
|
|
3141
|
+
const delegationHeader = { Authorization: result.delegation };
|
|
3142
|
+
const targetHost = grant.delegation.host ?? this.config.host;
|
|
3143
|
+
const activateResult = await activateSessionWithHost2(
|
|
3144
|
+
targetHost,
|
|
3145
|
+
delegationHeader
|
|
3146
|
+
);
|
|
3147
|
+
if (!activateResult.success) {
|
|
3148
|
+
throw new Error(
|
|
3149
|
+
`Failed to activate delegation with host: ${activateResult.error}`
|
|
3150
|
+
);
|
|
3151
|
+
}
|
|
3152
|
+
return {
|
|
3153
|
+
cid: result.cid,
|
|
3154
|
+
delegationHeader,
|
|
3155
|
+
spaceId: grant.session.spaceId,
|
|
3156
|
+
path: primary.path,
|
|
3157
|
+
actions: primary.actions,
|
|
3158
|
+
resources: result.resources,
|
|
3159
|
+
disableSubDelegation: false,
|
|
3160
|
+
expiry: result.expiry,
|
|
3161
|
+
delegateDID: did,
|
|
3162
|
+
ownerAddress: grant.delegation.ownerAddress,
|
|
3163
|
+
chainId: grant.delegation.chainId,
|
|
3164
|
+
host: targetHost
|
|
3165
|
+
};
|
|
3166
|
+
}
|
|
2633
3167
|
resolvePermissionSpace(space, session) {
|
|
2634
3168
|
if (space === void 0) {
|
|
2635
3169
|
return this.wasmBindings.makeSpaceId(
|
|
@@ -2646,6 +3180,220 @@ var _TinyCloudNode = class _TinyCloudNode {
|
|
|
2646
3180
|
}
|
|
2647
3181
|
return this.wasmBindings.makeSpaceId(session.address, session.chainId, space);
|
|
2648
3182
|
}
|
|
3183
|
+
expandPermissionEntries(permissions) {
|
|
3184
|
+
return expandPermissionEntriesCore(permissions);
|
|
3185
|
+
}
|
|
3186
|
+
shortServiceName(service) {
|
|
3187
|
+
const short = SERVICE_LONG_TO_SHORT[service];
|
|
3188
|
+
if (short === void 0) {
|
|
3189
|
+
throw new Error(
|
|
3190
|
+
`unknown service '${service}' \u2014 no short-form mapping`
|
|
3191
|
+
);
|
|
3192
|
+
}
|
|
3193
|
+
return short;
|
|
3194
|
+
}
|
|
3195
|
+
permissionsToAbilities(entries) {
|
|
3196
|
+
const abilities = {};
|
|
3197
|
+
for (const entry of entries) {
|
|
3198
|
+
const service = this.shortServiceName(entry.service);
|
|
3199
|
+
abilities[service] ?? (abilities[service] = {});
|
|
3200
|
+
const existing = abilities[service][entry.path] ?? [];
|
|
3201
|
+
const seen = new Set(existing);
|
|
3202
|
+
for (const action of entry.actions) {
|
|
3203
|
+
if (!seen.has(action)) {
|
|
3204
|
+
existing.push(action);
|
|
3205
|
+
seen.add(action);
|
|
3206
|
+
}
|
|
3207
|
+
}
|
|
3208
|
+
abilities[service][entry.path] = existing;
|
|
3209
|
+
}
|
|
3210
|
+
return abilities;
|
|
3211
|
+
}
|
|
3212
|
+
permissionOperations(entries, spaceId) {
|
|
3213
|
+
return entries.flatMap((entry) => {
|
|
3214
|
+
const service = this.shortServiceName(entry.service);
|
|
3215
|
+
return entry.actions.map((action) => ({
|
|
3216
|
+
spaceId,
|
|
3217
|
+
service,
|
|
3218
|
+
path: entry.path,
|
|
3219
|
+
action
|
|
3220
|
+
}));
|
|
3221
|
+
});
|
|
3222
|
+
}
|
|
3223
|
+
sessionCoversPermissionEntries(session, entries) {
|
|
3224
|
+
try {
|
|
3225
|
+
const granted = parseRecapCapabilities(
|
|
3226
|
+
(siwe) => this.wasmBindings.parseRecapFromSiwe(siwe),
|
|
3227
|
+
session.siwe
|
|
3228
|
+
);
|
|
3229
|
+
return isCapabilitySubset(entries, granted).subset;
|
|
3230
|
+
} catch {
|
|
3231
|
+
return false;
|
|
3232
|
+
}
|
|
3233
|
+
}
|
|
3234
|
+
permissionEntriesToOperations(entries, session) {
|
|
3235
|
+
return entries.flatMap((entry) => {
|
|
3236
|
+
const spaceId = this.resolvePermissionSpace(entry.space, session);
|
|
3237
|
+
const service = this.shortServiceName(entry.service);
|
|
3238
|
+
return entry.actions.map((action) => ({
|
|
3239
|
+
spaceId,
|
|
3240
|
+
service,
|
|
3241
|
+
path: entry.path,
|
|
3242
|
+
action
|
|
3243
|
+
}));
|
|
3244
|
+
});
|
|
3245
|
+
}
|
|
3246
|
+
findRuntimeGrantsForPermissionEntries(entries, session) {
|
|
3247
|
+
const grants = [];
|
|
3248
|
+
const operations = this.permissionEntriesToOperations(entries, session);
|
|
3249
|
+
if (operations.length === 0) {
|
|
3250
|
+
return grants;
|
|
3251
|
+
}
|
|
3252
|
+
for (const operation of operations) {
|
|
3253
|
+
const grant = this.findGrantForOperation(operation);
|
|
3254
|
+
if (!grant) {
|
|
3255
|
+
return [];
|
|
3256
|
+
}
|
|
3257
|
+
if (!grants.includes(grant)) {
|
|
3258
|
+
grants.push(grant);
|
|
3259
|
+
}
|
|
3260
|
+
}
|
|
3261
|
+
return grants;
|
|
3262
|
+
}
|
|
3263
|
+
runtimeDelegationFromSession(delegatedSession, entries, spaceId, session, expiresAt) {
|
|
3264
|
+
const resources = this.delegatedResourcesForEntries(entries, spaceId);
|
|
3265
|
+
const primary = resources[0];
|
|
3266
|
+
return {
|
|
3267
|
+
cid: delegatedSession.delegationCid,
|
|
3268
|
+
delegationHeader: delegatedSession.delegationHeader,
|
|
3269
|
+
spaceId,
|
|
3270
|
+
path: primary.path,
|
|
3271
|
+
actions: primary.actions,
|
|
3272
|
+
resources,
|
|
3273
|
+
disableSubDelegation: false,
|
|
3274
|
+
expiry: expiresAt,
|
|
3275
|
+
delegateDID: session.verificationMethod,
|
|
3276
|
+
ownerAddress: session.address,
|
|
3277
|
+
chainId: session.chainId,
|
|
3278
|
+
host: this.config.host
|
|
3279
|
+
};
|
|
3280
|
+
}
|
|
3281
|
+
runtimeGrantFromDelegation(delegation, session) {
|
|
3282
|
+
const operations = this.operationsFromDelegation(delegation);
|
|
3283
|
+
return {
|
|
3284
|
+
session: {
|
|
3285
|
+
delegationHeader: delegation.delegationHeader,
|
|
3286
|
+
delegationCid: delegation.cid,
|
|
3287
|
+
spaceId: delegation.spaceId,
|
|
3288
|
+
verificationMethod: session.verificationMethod,
|
|
3289
|
+
jwk: session.jwk
|
|
3290
|
+
},
|
|
3291
|
+
delegation,
|
|
3292
|
+
operations,
|
|
3293
|
+
expiresAt: delegation.expiry
|
|
3294
|
+
};
|
|
3295
|
+
}
|
|
3296
|
+
delegatedResourcesForEntries(entries, spaceId) {
|
|
3297
|
+
return entries.map((entry) => ({
|
|
3298
|
+
service: this.shortServiceName(entry.service),
|
|
3299
|
+
space: spaceId,
|
|
3300
|
+
path: entry.path,
|
|
3301
|
+
actions: [...entry.actions]
|
|
3302
|
+
}));
|
|
3303
|
+
}
|
|
3304
|
+
operationsFromDelegation(delegation) {
|
|
3305
|
+
const resources = delegation.resources !== void 0 && delegation.resources.length > 0 ? delegation.resources : this.flatDelegationResources(delegation);
|
|
3306
|
+
return resources.flatMap(
|
|
3307
|
+
(resource) => resource.actions.map((action) => ({
|
|
3308
|
+
spaceId: resource.space,
|
|
3309
|
+
service: this.invocationServiceName(resource.service),
|
|
3310
|
+
path: resource.path,
|
|
3311
|
+
action
|
|
3312
|
+
}))
|
|
3313
|
+
);
|
|
3314
|
+
}
|
|
3315
|
+
flatDelegationResources(delegation) {
|
|
3316
|
+
const byService = /* @__PURE__ */ new Map();
|
|
3317
|
+
for (const action of delegation.actions) {
|
|
3318
|
+
const service = this.shortServiceName(action.split("/")[0]);
|
|
3319
|
+
const actions = byService.get(service) ?? [];
|
|
3320
|
+
actions.push(action);
|
|
3321
|
+
byService.set(service, actions);
|
|
3322
|
+
}
|
|
3323
|
+
return [...byService.entries()].map(([service, actions]) => ({
|
|
3324
|
+
service,
|
|
3325
|
+
space: delegation.spaceId,
|
|
3326
|
+
path: delegation.path,
|
|
3327
|
+
actions
|
|
3328
|
+
}));
|
|
3329
|
+
}
|
|
3330
|
+
selectInvocationSession(fallback, service, path, action) {
|
|
3331
|
+
const grant = this.findGrantForOperation({
|
|
3332
|
+
spaceId: fallback.spaceId,
|
|
3333
|
+
service: this.invocationServiceName(service),
|
|
3334
|
+
path,
|
|
3335
|
+
action
|
|
3336
|
+
});
|
|
3337
|
+
return grant?.session ?? fallback;
|
|
3338
|
+
}
|
|
3339
|
+
findGrantForOperations(operations) {
|
|
3340
|
+
if (operations.length === 0) {
|
|
3341
|
+
return void 0;
|
|
3342
|
+
}
|
|
3343
|
+
this.pruneExpiredRuntimePermissionGrants();
|
|
3344
|
+
return this.runtimePermissionGrants.find((grant) => {
|
|
3345
|
+
return operations.every(
|
|
3346
|
+
(operation) => grant.operations.some(
|
|
3347
|
+
(granted) => this.operationCovers(granted, operation)
|
|
3348
|
+
)
|
|
3349
|
+
);
|
|
3350
|
+
});
|
|
3351
|
+
}
|
|
3352
|
+
findGrantForOperation(operation) {
|
|
3353
|
+
return this.findGrantForOperations([operation]);
|
|
3354
|
+
}
|
|
3355
|
+
pruneExpiredRuntimePermissionGrants() {
|
|
3356
|
+
const now = Date.now();
|
|
3357
|
+
this.runtimePermissionGrants = this.runtimePermissionGrants.filter(
|
|
3358
|
+
(grant) => grant.expiresAt.getTime() > now
|
|
3359
|
+
);
|
|
3360
|
+
}
|
|
3361
|
+
operationCovers(granted, requested) {
|
|
3362
|
+
return granted.spaceId === requested.spaceId && granted.service === requested.service && this.actionContains(granted.action, requested.action) && this.pathContains(granted.path, requested.path);
|
|
3363
|
+
}
|
|
3364
|
+
actionContains(grantedAction, requestedAction) {
|
|
3365
|
+
if (grantedAction === requestedAction) {
|
|
3366
|
+
return true;
|
|
3367
|
+
}
|
|
3368
|
+
if (grantedAction.endsWith("/*")) {
|
|
3369
|
+
const prefix = grantedAction.slice(0, -2);
|
|
3370
|
+
return requestedAction.startsWith(`${prefix}/`);
|
|
3371
|
+
}
|
|
3372
|
+
return false;
|
|
3373
|
+
}
|
|
3374
|
+
invocationServiceName(service) {
|
|
3375
|
+
return service.startsWith("tinycloud.") ? this.shortServiceName(service) : service;
|
|
3376
|
+
}
|
|
3377
|
+
pathContains(grantedPath, requestedPath) {
|
|
3378
|
+
if (grantedPath === "" || grantedPath === "/") {
|
|
3379
|
+
return true;
|
|
3380
|
+
}
|
|
3381
|
+
if (grantedPath.endsWith("/**")) {
|
|
3382
|
+
return requestedPath.startsWith(grantedPath.slice(0, -3));
|
|
3383
|
+
}
|
|
3384
|
+
if (grantedPath.endsWith("/*")) {
|
|
3385
|
+
const prefix = grantedPath.slice(0, -2);
|
|
3386
|
+
if (!requestedPath.startsWith(prefix)) {
|
|
3387
|
+
return false;
|
|
3388
|
+
}
|
|
3389
|
+
const remainder = requestedPath.slice(prefix.length);
|
|
3390
|
+
return !remainder.includes("/") || remainder === "/";
|
|
3391
|
+
}
|
|
3392
|
+
if (grantedPath.endsWith("/")) {
|
|
3393
|
+
return requestedPath.startsWith(grantedPath);
|
|
3394
|
+
}
|
|
3395
|
+
return grantedPath === requestedPath;
|
|
3396
|
+
}
|
|
2649
3397
|
/**
|
|
2650
3398
|
* Issue a delegation via the legacy wallet-signed SIWE path for a single
|
|
2651
3399
|
* {@link PermissionEntry}. Shares the implementation with the public
|
|
@@ -3033,15 +3781,18 @@ import {
|
|
|
3033
3781
|
ACCOUNT_REGISTRY_SPACE as ACCOUNT_REGISTRY_SPACE2,
|
|
3034
3782
|
DEFAULT_MANIFEST_SPACE as DEFAULT_MANIFEST_SPACE2,
|
|
3035
3783
|
DEFAULT_MANIFEST_VERSION,
|
|
3784
|
+
VAULT_PERMISSION_SERVICE,
|
|
3036
3785
|
PermissionNotInManifestError as PermissionNotInManifestError2,
|
|
3037
3786
|
SessionExpiredError as SessionExpiredError2,
|
|
3038
3787
|
ManifestValidationError,
|
|
3039
3788
|
composeManifestRequest as composeManifestRequest2,
|
|
3040
|
-
resolveManifest,
|
|
3789
|
+
resolveManifest as resolveManifest2,
|
|
3041
3790
|
validateManifest,
|
|
3042
3791
|
loadManifest,
|
|
3043
3792
|
isCapabilitySubset as isCapabilitySubset2,
|
|
3044
|
-
expandActionShortNames
|
|
3793
|
+
expandActionShortNames,
|
|
3794
|
+
expandPermissionEntries,
|
|
3795
|
+
expandPermissionEntry,
|
|
3045
3796
|
parseExpiry as parseExpiry2,
|
|
3046
3797
|
resourceCapabilitiesToSpaceAbilitiesMap as resourceCapabilitiesToSpaceAbilitiesMap2
|
|
3047
3798
|
} from "@tinycloud/sdk-core";
|
|
@@ -3066,7 +3817,16 @@ function deserializeDelegation(data) {
|
|
|
3066
3817
|
import { KVService as KVService3, PrefixedKVService } from "@tinycloud/sdk-core";
|
|
3067
3818
|
import { SQLService as SQLService3, SQLAction, DatabaseHandle } from "@tinycloud/sdk-core";
|
|
3068
3819
|
import { DuckDbService as DuckDbService3, DuckDbDatabaseHandle, DuckDbAction } from "@tinycloud/sdk-core";
|
|
3069
|
-
import {
|
|
3820
|
+
import {
|
|
3821
|
+
DataVaultService as DataVaultService2,
|
|
3822
|
+
VaultHeaders,
|
|
3823
|
+
VaultPublicSpaceKVActions,
|
|
3824
|
+
createVaultCrypto as createVaultCrypto2,
|
|
3825
|
+
SecretsService as SecretsService2,
|
|
3826
|
+
SECRET_NAME_RE,
|
|
3827
|
+
canonicalizeSecretScope,
|
|
3828
|
+
resolveSecretPath as resolveSecretPath2
|
|
3829
|
+
} from "@tinycloud/sdk-core";
|
|
3070
3830
|
import {
|
|
3071
3831
|
DelegationManager as DelegationManager2,
|
|
3072
3832
|
SharingService as SharingService2,
|
|
@@ -3118,8 +3878,10 @@ export {
|
|
|
3118
3878
|
PermissionNotInManifestError2 as PermissionNotInManifestError,
|
|
3119
3879
|
PrefixedKVService,
|
|
3120
3880
|
ProtocolMismatchError,
|
|
3881
|
+
SECRET_NAME_RE,
|
|
3121
3882
|
SQLAction,
|
|
3122
3883
|
SQLService3 as SQLService,
|
|
3884
|
+
SecretsService2 as SecretsService,
|
|
3123
3885
|
ServiceContext3 as ServiceContext,
|
|
3124
3886
|
SessionExpiredError2 as SessionExpiredError,
|
|
3125
3887
|
SharingService2 as SharingService,
|
|
@@ -3130,11 +3892,13 @@ export {
|
|
|
3130
3892
|
TinyCloud2 as TinyCloud,
|
|
3131
3893
|
TinyCloudNode,
|
|
3132
3894
|
UnsupportedFeatureError2 as UnsupportedFeatureError,
|
|
3895
|
+
VAULT_PERMISSION_SERVICE,
|
|
3133
3896
|
VaultHeaders,
|
|
3134
3897
|
VaultPublicSpaceKVActions,
|
|
3135
3898
|
VersionCheckError,
|
|
3136
3899
|
WasmKeyProvider,
|
|
3137
3900
|
buildSpaceUri,
|
|
3901
|
+
canonicalizeSecretScope,
|
|
3138
3902
|
checkNodeInfo2 as checkNodeInfo,
|
|
3139
3903
|
composeManifestRequest2 as composeManifestRequest,
|
|
3140
3904
|
createCapabilityKeyRegistry,
|
|
@@ -3145,13 +3909,16 @@ export {
|
|
|
3145
3909
|
defaultSignStrategy,
|
|
3146
3910
|
defaultSpaceCreationHandler,
|
|
3147
3911
|
deserializeDelegation,
|
|
3148
|
-
|
|
3912
|
+
expandActionShortNames,
|
|
3913
|
+
expandPermissionEntries,
|
|
3914
|
+
expandPermissionEntry,
|
|
3149
3915
|
isCapabilitySubset2 as isCapabilitySubset,
|
|
3150
3916
|
loadManifest,
|
|
3151
3917
|
makePublicSpaceId2 as makePublicSpaceId,
|
|
3152
3918
|
parseExpiry2 as parseExpiry,
|
|
3153
3919
|
parseSpaceUri,
|
|
3154
|
-
resolveManifest,
|
|
3920
|
+
resolveManifest2 as resolveManifest,
|
|
3921
|
+
resolveSecretPath2 as resolveSecretPath,
|
|
3155
3922
|
resourceCapabilitiesToSpaceAbilitiesMap2 as resourceCapabilitiesToSpaceAbilitiesMap,
|
|
3156
3923
|
serializeDelegation,
|
|
3157
3924
|
validateManifest
|