@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/index.js
CHANGED
|
@@ -17159,6 +17159,7 @@ import {
|
|
|
17159
17159
|
DuckDbService as DuckDbService2,
|
|
17160
17160
|
HooksService as HooksService2,
|
|
17161
17161
|
DataVaultService,
|
|
17162
|
+
SecretsService,
|
|
17162
17163
|
createVaultCrypto,
|
|
17163
17164
|
ServiceContext as ServiceContext2,
|
|
17164
17165
|
SilentNotificationHandler,
|
|
@@ -17171,10 +17172,11 @@ import {
|
|
|
17171
17172
|
ACCOUNT_REGISTRY_SPACE,
|
|
17172
17173
|
PermissionNotInManifestError,
|
|
17173
17174
|
SessionExpiredError,
|
|
17174
|
-
|
|
17175
|
+
expandPermissionEntries as expandPermissionEntriesCore,
|
|
17175
17176
|
isCapabilitySubset,
|
|
17176
17177
|
parseRecapCapabilities,
|
|
17177
|
-
SERVICE_LONG_TO_SHORT
|
|
17178
|
+
SERVICE_LONG_TO_SHORT,
|
|
17179
|
+
EXPIRY as EXPIRY3
|
|
17178
17180
|
} from "@tinycloud/sdk-core";
|
|
17179
17181
|
|
|
17180
17182
|
// src/authorization/NodeUserAuthorization.ts
|
|
@@ -17187,7 +17189,9 @@ import {
|
|
|
17187
17189
|
DEFAULT_MANIFEST_SPACE,
|
|
17188
17190
|
composeManifestRequest,
|
|
17189
17191
|
resourceCapabilitiesToAbilitiesMap,
|
|
17190
|
-
resourceCapabilitiesToSpaceAbilitiesMap
|
|
17192
|
+
resourceCapabilitiesToSpaceAbilitiesMap,
|
|
17193
|
+
resolveTinyCloudHosts,
|
|
17194
|
+
EXPIRY
|
|
17191
17195
|
} from "@tinycloud/sdk-core";
|
|
17192
17196
|
|
|
17193
17197
|
// src/authorization/strategies.ts
|
|
@@ -17318,12 +17322,12 @@ var NodeUserAuthorization = class {
|
|
|
17318
17322
|
]
|
|
17319
17323
|
}
|
|
17320
17324
|
};
|
|
17321
|
-
this.sessionExpirationMs = config.sessionExpirationMs ??
|
|
17325
|
+
this.sessionExpirationMs = config.sessionExpirationMs ?? EXPIRY.SESSION_MS;
|
|
17322
17326
|
this.autoCreateSpace = config.autoCreateSpace ?? false;
|
|
17323
17327
|
this.spaceCreationHandler = config.spaceCreationHandler;
|
|
17324
|
-
this.tinycloudHosts = config.tinycloudHosts
|
|
17325
|
-
|
|
17326
|
-
|
|
17328
|
+
this.tinycloudHosts = config.tinycloudHosts;
|
|
17329
|
+
this.tinycloudRegistryUrl = config.tinycloudRegistryUrl;
|
|
17330
|
+
this.tinycloudFallbackHosts = config.tinycloudFallbackHosts;
|
|
17327
17331
|
this.enablePublicSpace = config.enablePublicSpace ?? true;
|
|
17328
17332
|
this.nonce = config.nonce;
|
|
17329
17333
|
this.siweConfig = config.siweConfig;
|
|
@@ -17344,6 +17348,9 @@ var NodeUserAuthorization = class {
|
|
|
17344
17348
|
get capabilityRequest() {
|
|
17345
17349
|
return this.getCapabilityRequest();
|
|
17346
17350
|
}
|
|
17351
|
+
get hosts() {
|
|
17352
|
+
return this.tinycloudHosts ? [...this.tinycloudHosts] : [];
|
|
17353
|
+
}
|
|
17347
17354
|
/**
|
|
17348
17355
|
* Install or replace the stored manifest. Takes effect on the next
|
|
17349
17356
|
* `signIn()` call — the current session (if any) is not touched.
|
|
@@ -17368,6 +17375,26 @@ var NodeUserAuthorization = class {
|
|
|
17368
17375
|
get tinyCloudSession() {
|
|
17369
17376
|
return this._tinyCloudSession;
|
|
17370
17377
|
}
|
|
17378
|
+
async resolveTinyCloudHostsForSignIn(address, chainId) {
|
|
17379
|
+
if (this.tinycloudHosts && this.tinycloudHosts.length > 0) {
|
|
17380
|
+
return;
|
|
17381
|
+
}
|
|
17382
|
+
const subject = `did:pkh:eip155:${chainId}:${address}`;
|
|
17383
|
+
const resolved = await resolveTinyCloudHosts(subject, {
|
|
17384
|
+
registryUrl: this.tinycloudRegistryUrl,
|
|
17385
|
+
fallbackHosts: this.tinycloudFallbackHosts
|
|
17386
|
+
});
|
|
17387
|
+
this.tinycloudHosts = resolved.hosts;
|
|
17388
|
+
}
|
|
17389
|
+
requireTinyCloudHosts() {
|
|
17390
|
+
if (!this.tinycloudHosts || this.tinycloudHosts.length === 0) {
|
|
17391
|
+
throw new Error("TinyCloud hosts have not been resolved. Call signIn() first.");
|
|
17392
|
+
}
|
|
17393
|
+
return this.tinycloudHosts;
|
|
17394
|
+
}
|
|
17395
|
+
get primaryTinyCloudHost() {
|
|
17396
|
+
return this.requireTinyCloudHosts()[0];
|
|
17397
|
+
}
|
|
17371
17398
|
get nodeFeatures() {
|
|
17372
17399
|
return this._nodeFeatures;
|
|
17373
17400
|
}
|
|
@@ -17499,7 +17526,7 @@ var NodeUserAuthorization = class {
|
|
|
17499
17526
|
if (!this._tinyCloudSession || !this._address || !this._chainId) {
|
|
17500
17527
|
throw new Error("Must be signed in to host space");
|
|
17501
17528
|
}
|
|
17502
|
-
const host = this.
|
|
17529
|
+
const host = this.primaryTinyCloudHost;
|
|
17503
17530
|
const spaceId = targetSpaceId ?? this._tinyCloudSession.spaceId;
|
|
17504
17531
|
const peerId = await fetchPeerId(host, spaceId);
|
|
17505
17532
|
const siwe = this.wasm.generateHostSIWEMessage({
|
|
@@ -17541,7 +17568,7 @@ var NodeUserAuthorization = class {
|
|
|
17541
17568
|
if (!this._tinyCloudSession) {
|
|
17542
17569
|
throw new Error("Must be signed in to ensure space exists");
|
|
17543
17570
|
}
|
|
17544
|
-
const host = this.
|
|
17571
|
+
const host = this.primaryTinyCloudHost;
|
|
17545
17572
|
const primarySpaceId = this._tinyCloudSession.spaceId;
|
|
17546
17573
|
const result = await activateSessionWithHost(
|
|
17547
17574
|
host,
|
|
@@ -17650,6 +17677,7 @@ var NodeUserAuthorization = class {
|
|
|
17650
17677
|
this._chainId = await this.signer.getChainId();
|
|
17651
17678
|
const address = this.wasm.ensureEip55(this._address);
|
|
17652
17679
|
const chainId = this._chainId;
|
|
17680
|
+
await this.resolveTinyCloudHostsForSignIn(address, chainId);
|
|
17653
17681
|
const keyId = `session-${Date.now()}`;
|
|
17654
17682
|
this.sessionManager.renameSessionKeyId("default", keyId);
|
|
17655
17683
|
const jwkString = this.sessionManager.jwk(keyId);
|
|
@@ -17728,7 +17756,7 @@ var NodeUserAuthorization = class {
|
|
|
17728
17756
|
this._address = address;
|
|
17729
17757
|
this._chainId = chainId;
|
|
17730
17758
|
const nodeInfo = await checkNodeInfo(
|
|
17731
|
-
this.
|
|
17759
|
+
this.primaryTinyCloudHost,
|
|
17732
17760
|
this.wasm.protocolVersion()
|
|
17733
17761
|
);
|
|
17734
17762
|
this._nodeFeatures = nodeInfo.features;
|
|
@@ -17844,6 +17872,7 @@ var NodeUserAuthorization = class {
|
|
|
17844
17872
|
});
|
|
17845
17873
|
const address = this.wasm.ensureEip55(await this.signer.getAddress());
|
|
17846
17874
|
const chainId = await this.signer.getChainId();
|
|
17875
|
+
await this.resolveTinyCloudHostsForSignIn(address, chainId);
|
|
17847
17876
|
const clientSession = {
|
|
17848
17877
|
address,
|
|
17849
17878
|
walletAddress: address,
|
|
@@ -17893,7 +17922,7 @@ var NodeUserAuthorization = class {
|
|
|
17893
17922
|
this._address = address;
|
|
17894
17923
|
this._chainId = chainId;
|
|
17895
17924
|
const nodeInfo = await checkNodeInfo(
|
|
17896
|
-
this.
|
|
17925
|
+
this.primaryTinyCloudHost,
|
|
17897
17926
|
this.wasm.protocolVersion()
|
|
17898
17927
|
);
|
|
17899
17928
|
this._nodeFeatures = nodeInfo.features;
|
|
@@ -18057,6 +18086,24 @@ var DelegatedAccess = class {
|
|
|
18057
18086
|
get hooks() {
|
|
18058
18087
|
return this._hooks;
|
|
18059
18088
|
}
|
|
18089
|
+
/**
|
|
18090
|
+
* Export the handles needed to rehydrate this activated delegation via
|
|
18091
|
+
* `TinyCloudNode.restoreSession(...)` in another process or after a
|
|
18092
|
+
* restart.
|
|
18093
|
+
*
|
|
18094
|
+
* See `RestorableSession` for lifetime caveats.
|
|
18095
|
+
*/
|
|
18096
|
+
get restorable() {
|
|
18097
|
+
return {
|
|
18098
|
+
delegationHeader: this.session.delegationHeader,
|
|
18099
|
+
delegationCid: this.session.delegationCid,
|
|
18100
|
+
spaceId: this.session.spaceId,
|
|
18101
|
+
jwk: this.session.jwk,
|
|
18102
|
+
verificationMethod: this.session.verificationMethod,
|
|
18103
|
+
address: this.session.address,
|
|
18104
|
+
chainId: this.session.chainId
|
|
18105
|
+
};
|
|
18106
|
+
}
|
|
18060
18107
|
};
|
|
18061
18108
|
|
|
18062
18109
|
// src/keys/WasmKeyProvider.ts
|
|
@@ -18137,7 +18184,8 @@ function createWasmKeyProvider(sessionManager) {
|
|
|
18137
18184
|
// src/delegateToHelpers.ts
|
|
18138
18185
|
import {
|
|
18139
18186
|
parseExpiry,
|
|
18140
|
-
SiweMessage
|
|
18187
|
+
SiweMessage,
|
|
18188
|
+
EXPIRY as EXPIRY2
|
|
18141
18189
|
} from "@tinycloud/sdk-core";
|
|
18142
18190
|
function legacyParamsToPermissionEntries(actions, path, spaceIdOverride) {
|
|
18143
18191
|
const byService = /* @__PURE__ */ new Map();
|
|
@@ -18169,9 +18217,10 @@ function legacyParamsToPermissionEntries(actions, path, spaceIdOverride) {
|
|
|
18169
18217
|
}
|
|
18170
18218
|
return entries;
|
|
18171
18219
|
}
|
|
18220
|
+
var DEFAULT_DELEGATION_EXPIRY_MS = EXPIRY2.SESSION_MS;
|
|
18172
18221
|
function resolveExpiryMs(expiry) {
|
|
18173
18222
|
if (expiry === void 0) {
|
|
18174
|
-
return
|
|
18223
|
+
return DEFAULT_DELEGATION_EXPIRY_MS;
|
|
18175
18224
|
}
|
|
18176
18225
|
if (typeof expiry === "number") {
|
|
18177
18226
|
if (!Number.isFinite(expiry) || expiry <= 0) {
|
|
@@ -18197,8 +18246,155 @@ function extractSiweExpiration(siwe) {
|
|
|
18197
18246
|
return d;
|
|
18198
18247
|
}
|
|
18199
18248
|
|
|
18249
|
+
// src/NodeSecretsService.ts
|
|
18250
|
+
import {
|
|
18251
|
+
ErrorCodes,
|
|
18252
|
+
resolveSecretPath,
|
|
18253
|
+
resolveManifest
|
|
18254
|
+
} from "@tinycloud/sdk-core";
|
|
18255
|
+
var SECRETS_SPACE = "secrets";
|
|
18256
|
+
function ok() {
|
|
18257
|
+
return { ok: true, data: void 0 };
|
|
18258
|
+
}
|
|
18259
|
+
function secretsError(code, message, cause) {
|
|
18260
|
+
return {
|
|
18261
|
+
ok: false,
|
|
18262
|
+
error: {
|
|
18263
|
+
code,
|
|
18264
|
+
service: "secrets",
|
|
18265
|
+
message,
|
|
18266
|
+
...cause ? { cause } : {}
|
|
18267
|
+
}
|
|
18268
|
+
};
|
|
18269
|
+
}
|
|
18270
|
+
function displayActionUrn(action) {
|
|
18271
|
+
return action === "put" ? "tinycloud.vault/write" : "tinycloud.vault/delete";
|
|
18272
|
+
}
|
|
18273
|
+
function kvActionUrn(action) {
|
|
18274
|
+
return `tinycloud.kv/${action}`;
|
|
18275
|
+
}
|
|
18276
|
+
function vaultMutationAction(action) {
|
|
18277
|
+
return action === "put" ? "write" : "delete";
|
|
18278
|
+
}
|
|
18279
|
+
function secretPermissionEntries(name, options, action) {
|
|
18280
|
+
const secretPath = resolveSecretPath(name, options);
|
|
18281
|
+
return [
|
|
18282
|
+
{
|
|
18283
|
+
service: "tinycloud.vault",
|
|
18284
|
+
space: SECRETS_SPACE,
|
|
18285
|
+
path: secretPath.vaultKey,
|
|
18286
|
+
actions: [vaultMutationAction(action)],
|
|
18287
|
+
skipPrefix: true
|
|
18288
|
+
}
|
|
18289
|
+
];
|
|
18290
|
+
}
|
|
18291
|
+
function isSecretsSpace(space) {
|
|
18292
|
+
return space === SECRETS_SPACE || space.endsWith(`:${SECRETS_SPACE}`);
|
|
18293
|
+
}
|
|
18294
|
+
var NodeSecretsService = class {
|
|
18295
|
+
constructor(config) {
|
|
18296
|
+
this.config = config;
|
|
18297
|
+
this.shouldRestoreUnlock = false;
|
|
18298
|
+
}
|
|
18299
|
+
get vault() {
|
|
18300
|
+
return this.service.vault;
|
|
18301
|
+
}
|
|
18302
|
+
get isUnlocked() {
|
|
18303
|
+
return this.service.isUnlocked;
|
|
18304
|
+
}
|
|
18305
|
+
async unlock(signer) {
|
|
18306
|
+
const effectiveSigner = signer ?? this.config.getUnlockSigner?.();
|
|
18307
|
+
if (effectiveSigner !== void 0) {
|
|
18308
|
+
this.unlockSigner = effectiveSigner;
|
|
18309
|
+
}
|
|
18310
|
+
const result = await this.service.unlock(effectiveSigner);
|
|
18311
|
+
if (result.ok) {
|
|
18312
|
+
this.shouldRestoreUnlock = true;
|
|
18313
|
+
}
|
|
18314
|
+
return result;
|
|
18315
|
+
}
|
|
18316
|
+
lock() {
|
|
18317
|
+
this.shouldRestoreUnlock = false;
|
|
18318
|
+
this.service.lock();
|
|
18319
|
+
}
|
|
18320
|
+
get(name, options) {
|
|
18321
|
+
return options === void 0 ? this.service.get(name) : this.service.get(name, options);
|
|
18322
|
+
}
|
|
18323
|
+
async put(name, value, options) {
|
|
18324
|
+
const permission = await this.ensureMutationPermission(name, options, "put");
|
|
18325
|
+
if (!permission.ok) return permission;
|
|
18326
|
+
return options === void 0 ? this.service.put(name, value) : this.service.put(name, value, options);
|
|
18327
|
+
}
|
|
18328
|
+
async delete(name, options) {
|
|
18329
|
+
const permission = await this.ensureMutationPermission(name, options, "del");
|
|
18330
|
+
if (!permission.ok) return permission;
|
|
18331
|
+
return options === void 0 ? this.service.delete(name) : this.service.delete(name, options);
|
|
18332
|
+
}
|
|
18333
|
+
list(options) {
|
|
18334
|
+
return options === void 0 ? this.service.list() : this.service.list(options);
|
|
18335
|
+
}
|
|
18336
|
+
get service() {
|
|
18337
|
+
return this.config.getService();
|
|
18338
|
+
}
|
|
18339
|
+
async ensureMutationPermission(name, options, action) {
|
|
18340
|
+
let permissionEntries;
|
|
18341
|
+
try {
|
|
18342
|
+
permissionEntries = secretPermissionEntries(name, options, action);
|
|
18343
|
+
} catch (error) {
|
|
18344
|
+
return secretsError(
|
|
18345
|
+
ErrorCodes.INVALID_INPUT,
|
|
18346
|
+
error instanceof Error ? error.message : String(error),
|
|
18347
|
+
error instanceof Error ? error : void 0
|
|
18348
|
+
);
|
|
18349
|
+
}
|
|
18350
|
+
if (this.hasMutationPermission(name, options, action)) {
|
|
18351
|
+
return ok();
|
|
18352
|
+
}
|
|
18353
|
+
if (!this.config.canEscalate()) {
|
|
18354
|
+
return secretsError(
|
|
18355
|
+
ErrorCodes.PERMISSION_DENIED,
|
|
18356
|
+
`Cannot autosign ${displayActionUrn(action)} for ${name}; TinyCloudNode needs wallet mode with a signer or privateKey.`
|
|
18357
|
+
);
|
|
18358
|
+
}
|
|
18359
|
+
try {
|
|
18360
|
+
await this.config.grantPermissions(permissionEntries);
|
|
18361
|
+
return this.restoreUnlockAfterEscalation();
|
|
18362
|
+
} catch (error) {
|
|
18363
|
+
return secretsError(
|
|
18364
|
+
ErrorCodes.PERMISSION_DENIED,
|
|
18365
|
+
error instanceof Error ? error.message : `Autosign escalation for ${displayActionUrn(action)} on ${name} failed.`,
|
|
18366
|
+
error instanceof Error ? error : void 0
|
|
18367
|
+
);
|
|
18368
|
+
}
|
|
18369
|
+
}
|
|
18370
|
+
async restoreUnlockAfterEscalation() {
|
|
18371
|
+
if (!this.shouldRestoreUnlock) {
|
|
18372
|
+
return ok();
|
|
18373
|
+
}
|
|
18374
|
+
return this.service.unlock(this.unlockSigner);
|
|
18375
|
+
}
|
|
18376
|
+
hasMutationPermission(name, options, action) {
|
|
18377
|
+
const manifest = this.config.getManifest();
|
|
18378
|
+
if (manifest === void 0) {
|
|
18379
|
+
return false;
|
|
18380
|
+
}
|
|
18381
|
+
const manifests = Array.isArray(manifest) ? manifest : [manifest];
|
|
18382
|
+
const requiredAction = kvActionUrn(action);
|
|
18383
|
+
const secretPath = resolveSecretPath(name, options);
|
|
18384
|
+
return manifests.some((entry) => {
|
|
18385
|
+
const resolved = resolveManifest(entry);
|
|
18386
|
+
return ["keys", "vault"].every(
|
|
18387
|
+
(base2) => resolved.resources.some(
|
|
18388
|
+
(resource) => resource.service === "tinycloud.kv" && isSecretsSpace(resource.space) && resource.path === secretPath.permissionPaths[base2] && resource.actions.includes(requiredAction)
|
|
18389
|
+
)
|
|
18390
|
+
);
|
|
18391
|
+
});
|
|
18392
|
+
}
|
|
18393
|
+
};
|
|
18394
|
+
|
|
18200
18395
|
// src/TinyCloudNode.ts
|
|
18201
18396
|
var DEFAULT_HOST = "https://node.tinycloud.xyz";
|
|
18397
|
+
var DEFAULT_SESSION_EXPIRATION_MS = EXPIRY3.SESSION_MS;
|
|
18202
18398
|
var _TinyCloudNode = class _TinyCloudNode {
|
|
18203
18399
|
/**
|
|
18204
18400
|
* Create a new TinyCloudNode instance.
|
|
@@ -18228,6 +18424,31 @@ var _TinyCloudNode = class _TinyCloudNode {
|
|
|
18228
18424
|
this.auth = null;
|
|
18229
18425
|
this.tc = null;
|
|
18230
18426
|
this._chainId = 1;
|
|
18427
|
+
this.runtimePermissionGrants = [];
|
|
18428
|
+
this.invokeWithRuntimePermissions = (session, service, path, action, facts) => {
|
|
18429
|
+
return this.wasmBindings.invoke(
|
|
18430
|
+
this.selectInvocationSession(session, service, path, action),
|
|
18431
|
+
service,
|
|
18432
|
+
path,
|
|
18433
|
+
action,
|
|
18434
|
+
facts
|
|
18435
|
+
);
|
|
18436
|
+
};
|
|
18437
|
+
this.invokeAnyWithRuntimePermissions = (session, entries, facts) => {
|
|
18438
|
+
if (!this.wasmBindings.invokeAny) {
|
|
18439
|
+
throw new Error("WASM binding does not support invokeAny");
|
|
18440
|
+
}
|
|
18441
|
+
const grant = this.findGrantForOperations(
|
|
18442
|
+
entries.map((entry) => ({
|
|
18443
|
+
spaceId: entry.spaceId,
|
|
18444
|
+
service: this.invocationServiceName(entry.service),
|
|
18445
|
+
path: entry.path,
|
|
18446
|
+
action: entry.action
|
|
18447
|
+
}))
|
|
18448
|
+
);
|
|
18449
|
+
return this.wasmBindings.invokeAny(grant?.session ?? session, entries, facts);
|
|
18450
|
+
};
|
|
18451
|
+
this.explicitHost = config.host;
|
|
18231
18452
|
this.config = {
|
|
18232
18453
|
...config,
|
|
18233
18454
|
host: config.host ?? DEFAULT_HOST
|
|
@@ -18262,7 +18483,7 @@ var _TinyCloudNode = class _TinyCloudNode {
|
|
|
18262
18483
|
this._sharingService = new SharingService({
|
|
18263
18484
|
hosts: [this.config.host],
|
|
18264
18485
|
// session: undefined - not needed for receive()
|
|
18265
|
-
invoke: this.
|
|
18486
|
+
invoke: this.invokeWithRuntimePermissions,
|
|
18266
18487
|
fetch: globalThis.fetch.bind(globalThis),
|
|
18267
18488
|
keyProvider: this._keyProvider,
|
|
18268
18489
|
registry: this._capabilityRegistry,
|
|
@@ -18309,7 +18530,6 @@ var _TinyCloudNode = class _TinyCloudNode {
|
|
|
18309
18530
|
* @internal
|
|
18310
18531
|
*/
|
|
18311
18532
|
setupAuth(config) {
|
|
18312
|
-
const host = this.config.host;
|
|
18313
18533
|
this.auth = new NodeUserAuthorization({
|
|
18314
18534
|
signer: this.signer,
|
|
18315
18535
|
signStrategy: { type: "auto-sign" },
|
|
@@ -18317,8 +18537,10 @@ var _TinyCloudNode = class _TinyCloudNode {
|
|
|
18317
18537
|
sessionStorage: config.sessionStorage ?? new MemorySessionStorage(),
|
|
18318
18538
|
domain: this.siweDomain,
|
|
18319
18539
|
spacePrefix: config.prefix,
|
|
18320
|
-
sessionExpirationMs: config.sessionExpirationMs ??
|
|
18321
|
-
tinycloudHosts: [
|
|
18540
|
+
sessionExpirationMs: config.sessionExpirationMs ?? DEFAULT_SESSION_EXPIRATION_MS,
|
|
18541
|
+
tinycloudHosts: this.explicitHost ? [this.explicitHost] : void 0,
|
|
18542
|
+
tinycloudRegistryUrl: config.tinycloudRegistryUrl,
|
|
18543
|
+
tinycloudFallbackHosts: config.tinycloudFallbackHosts,
|
|
18322
18544
|
autoCreateSpace: config.autoCreateSpace,
|
|
18323
18545
|
enablePublicSpace: config.enablePublicSpace ?? true,
|
|
18324
18546
|
spaceCreationHandler: config.spaceCreationHandler,
|
|
@@ -18329,9 +18551,15 @@ var _TinyCloudNode = class _TinyCloudNode {
|
|
|
18329
18551
|
includeAccountRegistryPermissions: config.includeAccountRegistryPermissions
|
|
18330
18552
|
});
|
|
18331
18553
|
this.tc = new TinyCloud(this.auth, {
|
|
18332
|
-
invokeAny: this.
|
|
18554
|
+
invokeAny: this.invokeAnyWithRuntimePermissions
|
|
18333
18555
|
});
|
|
18334
18556
|
}
|
|
18557
|
+
syncResolvedHostFromAuth() {
|
|
18558
|
+
const host = this.auth?.hosts[0];
|
|
18559
|
+
if (host) {
|
|
18560
|
+
this.config.host = host;
|
|
18561
|
+
}
|
|
18562
|
+
}
|
|
18335
18563
|
/**
|
|
18336
18564
|
* Install or replace the manifest that drives the SIWE recap at
|
|
18337
18565
|
* sign-in. Takes effect on the next `signIn()` call — the current
|
|
@@ -18369,6 +18597,10 @@ var _TinyCloudNode = class _TinyCloudNode {
|
|
|
18369
18597
|
get capabilityRequest() {
|
|
18370
18598
|
return this.auth?.capabilityRequest;
|
|
18371
18599
|
}
|
|
18600
|
+
get hosts() {
|
|
18601
|
+
const authHosts = this.auth?.hosts ?? [];
|
|
18602
|
+
return authHosts.length > 0 ? authHosts : [this.config.host];
|
|
18603
|
+
}
|
|
18372
18604
|
/**
|
|
18373
18605
|
* Get the primary identity DID for this user.
|
|
18374
18606
|
* - If wallet connected and signed in: returns PKH DID (did:pkh:eip155:{chainId}:{address})
|
|
@@ -18439,8 +18671,14 @@ var _TinyCloudNode = class _TinyCloudNode {
|
|
|
18439
18671
|
this._sql = void 0;
|
|
18440
18672
|
this._duckdb = void 0;
|
|
18441
18673
|
this._hooks = void 0;
|
|
18674
|
+
this._vault = void 0;
|
|
18675
|
+
this._baseSecrets = void 0;
|
|
18676
|
+
this._secrets = void 0;
|
|
18677
|
+
this._spaceService = void 0;
|
|
18442
18678
|
this._serviceContext = void 0;
|
|
18679
|
+
this.runtimePermissionGrants = [];
|
|
18443
18680
|
await this.tc.signIn(options);
|
|
18681
|
+
this.syncResolvedHostFromAuth();
|
|
18444
18682
|
this.initializeServices();
|
|
18445
18683
|
await this.writeManifestRegistryRecords();
|
|
18446
18684
|
this.notificationHandler.success("Successfully signed in");
|
|
@@ -18460,7 +18698,7 @@ var _TinyCloudNode = class _TinyCloudNode {
|
|
|
18460
18698
|
throw new Error("Manifest registry write requires wallet mode");
|
|
18461
18699
|
}
|
|
18462
18700
|
const accountSpaceId = this.ownedSpaceId(ACCOUNT_REGISTRY_SPACE);
|
|
18463
|
-
await this.
|
|
18701
|
+
await this.ensureOwnedSpaceHosted(accountSpaceId);
|
|
18464
18702
|
const accountKV = this.spaces.get(accountSpaceId).kv;
|
|
18465
18703
|
for (const record of request.registryRecords) {
|
|
18466
18704
|
const result = await accountKV.put(record.key, {
|
|
@@ -18475,6 +18713,39 @@ var _TinyCloudNode = class _TinyCloudNode {
|
|
|
18475
18713
|
}
|
|
18476
18714
|
}
|
|
18477
18715
|
}
|
|
18716
|
+
async ensureOwnedSpaceHosted(spaceId) {
|
|
18717
|
+
if (!this.auth) {
|
|
18718
|
+
throw new Error("Owned space hosting requires wallet mode");
|
|
18719
|
+
}
|
|
18720
|
+
const session = this.auth.tinyCloudSession;
|
|
18721
|
+
if (!session) {
|
|
18722
|
+
throw new Error("Owned space hosting requires an active session");
|
|
18723
|
+
}
|
|
18724
|
+
const host = this.hosts[0] ?? this.config.host;
|
|
18725
|
+
if (!host) {
|
|
18726
|
+
throw new Error("Owned space hosting requires a TinyCloud host");
|
|
18727
|
+
}
|
|
18728
|
+
const activation = await activateSessionWithHost2(host, session.delegationHeader);
|
|
18729
|
+
if (activation.success && !activation.skipped?.includes(spaceId)) {
|
|
18730
|
+
return;
|
|
18731
|
+
}
|
|
18732
|
+
if (!activation.success && activation.status !== 404) {
|
|
18733
|
+
throw new Error(
|
|
18734
|
+
`Failed to check owned space ${spaceId}: ${activation.error ?? activation.status}`
|
|
18735
|
+
);
|
|
18736
|
+
}
|
|
18737
|
+
const created = await this.auth.hostOwnedSpace(spaceId);
|
|
18738
|
+
if (!created) {
|
|
18739
|
+
throw new Error(`Failed to create owned space: ${spaceId}`);
|
|
18740
|
+
}
|
|
18741
|
+
await new Promise((resolve) => setTimeout(resolve, 100));
|
|
18742
|
+
const retry = await activateSessionWithHost2(host, session.delegationHeader);
|
|
18743
|
+
if (!retry.success || retry.skipped?.includes(spaceId)) {
|
|
18744
|
+
throw new Error(
|
|
18745
|
+
`Failed to activate session after creating owned space ${spaceId}: ${retry.error ?? "space was skipped"}`
|
|
18746
|
+
);
|
|
18747
|
+
}
|
|
18748
|
+
}
|
|
18478
18749
|
/**
|
|
18479
18750
|
* Restore a previously established session from stored delegation data.
|
|
18480
18751
|
*
|
|
@@ -18490,7 +18761,12 @@ var _TinyCloudNode = class _TinyCloudNode {
|
|
|
18490
18761
|
this._sql = void 0;
|
|
18491
18762
|
this._duckdb = void 0;
|
|
18492
18763
|
this._hooks = void 0;
|
|
18764
|
+
this._vault = void 0;
|
|
18765
|
+
this._baseSecrets = void 0;
|
|
18766
|
+
this._secrets = void 0;
|
|
18767
|
+
this._spaceService = void 0;
|
|
18493
18768
|
this._serviceContext = void 0;
|
|
18769
|
+
this.runtimePermissionGrants = [];
|
|
18494
18770
|
if (sessionData.address) {
|
|
18495
18771
|
this._address = sessionData.address;
|
|
18496
18772
|
}
|
|
@@ -18498,8 +18774,8 @@ var _TinyCloudNode = class _TinyCloudNode {
|
|
|
18498
18774
|
this._chainId = sessionData.chainId;
|
|
18499
18775
|
}
|
|
18500
18776
|
this._serviceContext = new ServiceContext2({
|
|
18501
|
-
invoke: this.
|
|
18502
|
-
invokeAny: this.
|
|
18777
|
+
invoke: this.invokeWithRuntimePermissions,
|
|
18778
|
+
invokeAny: this.invokeAnyWithRuntimePermissions,
|
|
18503
18779
|
fetch: globalThis.fetch.bind(globalThis),
|
|
18504
18780
|
hosts: [this.config.host]
|
|
18505
18781
|
});
|
|
@@ -18523,41 +18799,7 @@ var _TinyCloudNode = class _TinyCloudNode {
|
|
|
18523
18799
|
jwk: sessionData.jwk
|
|
18524
18800
|
};
|
|
18525
18801
|
this._serviceContext.setSession(serviceSession);
|
|
18526
|
-
|
|
18527
|
-
const vaultCrypto = createVaultCrypto({
|
|
18528
|
-
vault_encrypt: wasm.vault_encrypt,
|
|
18529
|
-
vault_decrypt: wasm.vault_decrypt,
|
|
18530
|
-
vault_derive_key: wasm.vault_derive_key,
|
|
18531
|
-
vault_x25519_from_seed: wasm.vault_x25519_from_seed,
|
|
18532
|
-
vault_x25519_dh: wasm.vault_x25519_dh,
|
|
18533
|
-
vault_random_bytes: wasm.vault_random_bytes,
|
|
18534
|
-
vault_sha256: wasm.vault_sha256
|
|
18535
|
-
});
|
|
18536
|
-
const self2 = this;
|
|
18537
|
-
this._vault = new DataVaultService({
|
|
18538
|
-
spaceId: sessionData.spaceId,
|
|
18539
|
-
crypto: vaultCrypto,
|
|
18540
|
-
tc: {
|
|
18541
|
-
kv: this._kv,
|
|
18542
|
-
ensurePublicSpace: async () => {
|
|
18543
|
-
try {
|
|
18544
|
-
await self2.ensurePublicSpace();
|
|
18545
|
-
return { ok: true, data: void 0 };
|
|
18546
|
-
} catch (error) {
|
|
18547
|
-
return { ok: false, error: { code: "STORAGE_ERROR", message: error instanceof Error ? error.message : String(error), service: "vault" } };
|
|
18548
|
-
}
|
|
18549
|
-
},
|
|
18550
|
-
get publicKV() {
|
|
18551
|
-
return self2._publicKV ?? self2.tc.publicKV;
|
|
18552
|
-
},
|
|
18553
|
-
readPublicSpace: (host, spaceId, key2) => TinyCloud.readPublicSpace(host, spaceId, key2),
|
|
18554
|
-
makePublicSpaceId: TinyCloud.makePublicSpaceId,
|
|
18555
|
-
did: this.did,
|
|
18556
|
-
address: sessionData.address ?? this._address ?? "",
|
|
18557
|
-
chainId: sessionData.chainId ?? this._chainId,
|
|
18558
|
-
hosts: [this.config.host]
|
|
18559
|
-
}
|
|
18560
|
-
});
|
|
18802
|
+
this._vault = this.createVaultService(sessionData.spaceId, this._kv);
|
|
18561
18803
|
this._vault.initialize(this._serviceContext);
|
|
18562
18804
|
this._serviceContext.registerService("vault", this._vault);
|
|
18563
18805
|
this.initializeV2Services(serviceSession);
|
|
@@ -18592,7 +18834,6 @@ var _TinyCloudNode = class _TinyCloudNode {
|
|
|
18592
18834
|
throw new Error("Wallet already connected. Cannot connect another wallet.");
|
|
18593
18835
|
}
|
|
18594
18836
|
const prefix = options?.prefix ?? "default";
|
|
18595
|
-
const host = this.config.host;
|
|
18596
18837
|
if (!_TinyCloudNode.nodeDefaults) {
|
|
18597
18838
|
throw new Error(
|
|
18598
18839
|
"connectWallet() requires PrivateKeySigner. Use connectSigner() instead, or import from '@tinycloud/node-sdk' (not '/core') for automatic Node.js defaults."
|
|
@@ -18606,8 +18847,10 @@ var _TinyCloudNode = class _TinyCloudNode {
|
|
|
18606
18847
|
sessionStorage: options?.sessionStorage ?? this.config.sessionStorage ?? new MemorySessionStorage(),
|
|
18607
18848
|
domain: this.siweDomain,
|
|
18608
18849
|
spacePrefix: prefix,
|
|
18609
|
-
sessionExpirationMs: this.config.sessionExpirationMs ??
|
|
18610
|
-
tinycloudHosts: [
|
|
18850
|
+
sessionExpirationMs: this.config.sessionExpirationMs ?? DEFAULT_SESSION_EXPIRATION_MS,
|
|
18851
|
+
tinycloudHosts: this.explicitHost ? [this.explicitHost] : void 0,
|
|
18852
|
+
tinycloudRegistryUrl: this.config.tinycloudRegistryUrl,
|
|
18853
|
+
tinycloudFallbackHosts: this.config.tinycloudFallbackHosts,
|
|
18611
18854
|
autoCreateSpace: this.config.autoCreateSpace,
|
|
18612
18855
|
enablePublicSpace: this.config.enablePublicSpace ?? true,
|
|
18613
18856
|
spaceCreationHandler: this.config.spaceCreationHandler,
|
|
@@ -18618,7 +18861,7 @@ var _TinyCloudNode = class _TinyCloudNode {
|
|
|
18618
18861
|
includeAccountRegistryPermissions: this.config.includeAccountRegistryPermissions
|
|
18619
18862
|
});
|
|
18620
18863
|
this.tc = new TinyCloud(this.auth, {
|
|
18621
|
-
invokeAny: this.
|
|
18864
|
+
invokeAny: this.invokeAnyWithRuntimePermissions
|
|
18622
18865
|
});
|
|
18623
18866
|
this.config.prefix = prefix;
|
|
18624
18867
|
}
|
|
@@ -18640,7 +18883,6 @@ var _TinyCloudNode = class _TinyCloudNode {
|
|
|
18640
18883
|
throw new Error("Signer already connected. Cannot connect another signer.");
|
|
18641
18884
|
}
|
|
18642
18885
|
const prefix = options?.prefix ?? "default";
|
|
18643
|
-
const host = this.config.host;
|
|
18644
18886
|
this.signer = signer;
|
|
18645
18887
|
this.auth = new NodeUserAuthorization({
|
|
18646
18888
|
signer: this.signer,
|
|
@@ -18649,8 +18891,10 @@ var _TinyCloudNode = class _TinyCloudNode {
|
|
|
18649
18891
|
sessionStorage: options?.sessionStorage ?? this.config.sessionStorage ?? new MemorySessionStorage(),
|
|
18650
18892
|
domain: this.siweDomain,
|
|
18651
18893
|
spacePrefix: prefix,
|
|
18652
|
-
sessionExpirationMs: this.config.sessionExpirationMs ??
|
|
18653
|
-
tinycloudHosts: [
|
|
18894
|
+
sessionExpirationMs: this.config.sessionExpirationMs ?? DEFAULT_SESSION_EXPIRATION_MS,
|
|
18895
|
+
tinycloudHosts: this.explicitHost ? [this.explicitHost] : void 0,
|
|
18896
|
+
tinycloudRegistryUrl: this.config.tinycloudRegistryUrl,
|
|
18897
|
+
tinycloudFallbackHosts: this.config.tinycloudFallbackHosts,
|
|
18654
18898
|
autoCreateSpace: this.config.autoCreateSpace,
|
|
18655
18899
|
enablePublicSpace: this.config.enablePublicSpace ?? true,
|
|
18656
18900
|
spaceCreationHandler: this.config.spaceCreationHandler,
|
|
@@ -18661,7 +18905,7 @@ var _TinyCloudNode = class _TinyCloudNode {
|
|
|
18661
18905
|
includeAccountRegistryPermissions: this.config.includeAccountRegistryPermissions
|
|
18662
18906
|
});
|
|
18663
18907
|
this.tc = new TinyCloud(this.auth, {
|
|
18664
|
-
invokeAny: this.
|
|
18908
|
+
invokeAny: this.invokeAnyWithRuntimePermissions
|
|
18665
18909
|
});
|
|
18666
18910
|
this.config.prefix = prefix;
|
|
18667
18911
|
}
|
|
@@ -18674,10 +18918,10 @@ var _TinyCloudNode = class _TinyCloudNode {
|
|
|
18674
18918
|
if (!session) {
|
|
18675
18919
|
return;
|
|
18676
18920
|
}
|
|
18677
|
-
this.tc.initializeServices(this.
|
|
18921
|
+
this.tc.initializeServices(this.invokeWithRuntimePermissions, [this.config.host]);
|
|
18678
18922
|
this._serviceContext = new ServiceContext2({
|
|
18679
|
-
invoke: this.
|
|
18680
|
-
invokeAny: this.
|
|
18923
|
+
invoke: this.invokeWithRuntimePermissions,
|
|
18924
|
+
invokeAny: this.invokeAnyWithRuntimePermissions,
|
|
18681
18925
|
fetch: globalThis.fetch.bind(globalThis),
|
|
18682
18926
|
hosts: [this.config.host]
|
|
18683
18927
|
});
|
|
@@ -18707,6 +18951,28 @@ var _TinyCloudNode = class _TinyCloudNode {
|
|
|
18707
18951
|
};
|
|
18708
18952
|
this._serviceContext.setSession(serviceSession);
|
|
18709
18953
|
this.tc.serviceContext.setSession(serviceSession);
|
|
18954
|
+
this._vault = this.createVaultService(session.spaceId, this._kv);
|
|
18955
|
+
this._vault.initialize(this._serviceContext);
|
|
18956
|
+
this._serviceContext.registerService("vault", this._vault);
|
|
18957
|
+
this.initializeV2Services(serviceSession);
|
|
18958
|
+
}
|
|
18959
|
+
createSpaceScopedKVService(spaceId) {
|
|
18960
|
+
const kvService = new KVService2({});
|
|
18961
|
+
if (this._serviceContext) {
|
|
18962
|
+
const spaceScopedContext = new ServiceContext2({
|
|
18963
|
+
invoke: this._serviceContext.invoke,
|
|
18964
|
+
fetch: this._serviceContext.fetch,
|
|
18965
|
+
hosts: this._serviceContext.hosts
|
|
18966
|
+
});
|
|
18967
|
+
const session = this._serviceContext.session;
|
|
18968
|
+
if (session) {
|
|
18969
|
+
spaceScopedContext.setSession({ ...session, spaceId });
|
|
18970
|
+
}
|
|
18971
|
+
kvService.initialize(spaceScopedContext);
|
|
18972
|
+
}
|
|
18973
|
+
return kvService;
|
|
18974
|
+
}
|
|
18975
|
+
createVaultService(spaceId, kv) {
|
|
18710
18976
|
const wasm = this.wasmBindings;
|
|
18711
18977
|
const vaultCrypto = createVaultCrypto({
|
|
18712
18978
|
vault_encrypt: wasm.vault_encrypt,
|
|
@@ -18718,11 +18984,11 @@ var _TinyCloudNode = class _TinyCloudNode {
|
|
|
18718
18984
|
vault_sha256: wasm.vault_sha256
|
|
18719
18985
|
});
|
|
18720
18986
|
const self2 = this;
|
|
18721
|
-
|
|
18722
|
-
spaceId
|
|
18987
|
+
return new DataVaultService({
|
|
18988
|
+
spaceId,
|
|
18723
18989
|
crypto: vaultCrypto,
|
|
18724
18990
|
tc: {
|
|
18725
|
-
kv
|
|
18991
|
+
kv,
|
|
18726
18992
|
ensurePublicSpace: async () => {
|
|
18727
18993
|
try {
|
|
18728
18994
|
await self2.ensurePublicSpace();
|
|
@@ -18734,17 +19000,14 @@ var _TinyCloudNode = class _TinyCloudNode {
|
|
|
18734
19000
|
get publicKV() {
|
|
18735
19001
|
return self2._publicKV ?? self2.tc.publicKV;
|
|
18736
19002
|
},
|
|
18737
|
-
readPublicSpace: (host,
|
|
19003
|
+
readPublicSpace: (host, targetSpaceId, key2) => TinyCloud.readPublicSpace(host, targetSpaceId, key2),
|
|
18738
19004
|
makePublicSpaceId: TinyCloud.makePublicSpaceId,
|
|
18739
19005
|
did: this.did,
|
|
18740
|
-
address: this._address,
|
|
19006
|
+
address: this._address ?? "",
|
|
18741
19007
|
chainId: this._chainId,
|
|
18742
19008
|
hosts: [this.config.host]
|
|
18743
19009
|
}
|
|
18744
19010
|
});
|
|
18745
|
-
this._vault.initialize(this._serviceContext);
|
|
18746
|
-
this._serviceContext.registerService("vault", this._vault);
|
|
18747
|
-
this.initializeV2Services(serviceSession);
|
|
18748
19011
|
}
|
|
18749
19012
|
/**
|
|
18750
19013
|
* Initialize the v2 delegation system services.
|
|
@@ -18828,7 +19091,7 @@ var _TinyCloudNode = class _TinyCloudNode {
|
|
|
18828
19091
|
this._delegationManager = new DelegationManager({
|
|
18829
19092
|
hosts: [this.config.host],
|
|
18830
19093
|
session: serviceSession,
|
|
18831
|
-
invoke: this.
|
|
19094
|
+
invoke: this.invokeWithRuntimePermissions,
|
|
18832
19095
|
fetch: globalThis.fetch.bind(globalThis)
|
|
18833
19096
|
});
|
|
18834
19097
|
this._spaceService = new SpaceService({
|
|
@@ -18839,20 +19102,15 @@ var _TinyCloudNode = class _TinyCloudNode {
|
|
|
18839
19102
|
capabilityRegistry: this._capabilityRegistry,
|
|
18840
19103
|
userDid: this.did,
|
|
18841
19104
|
createKVService: (spaceId) => {
|
|
18842
|
-
|
|
19105
|
+
return this.createSpaceScopedKVService(spaceId);
|
|
19106
|
+
},
|
|
19107
|
+
createVaultService: (spaceId) => {
|
|
19108
|
+
const kvService = this.createSpaceScopedKVService(spaceId);
|
|
19109
|
+
const vaultService = this.createVaultService(spaceId, kvService);
|
|
18843
19110
|
if (this._serviceContext) {
|
|
18844
|
-
|
|
18845
|
-
invoke: this._serviceContext.invoke,
|
|
18846
|
-
fetch: this._serviceContext.fetch,
|
|
18847
|
-
hosts: this._serviceContext.hosts
|
|
18848
|
-
});
|
|
18849
|
-
const session = this._serviceContext.session;
|
|
18850
|
-
if (session) {
|
|
18851
|
-
spaceScopedContext.setSession({ ...session, spaceId });
|
|
18852
|
-
}
|
|
18853
|
-
kvService.initialize(spaceScopedContext);
|
|
19111
|
+
vaultService.initialize(this._serviceContext);
|
|
18854
19112
|
}
|
|
18855
|
-
return
|
|
19113
|
+
return vaultService;
|
|
18856
19114
|
},
|
|
18857
19115
|
// Enable space.delegations.create() via SIWE-based delegation
|
|
18858
19116
|
createDelegation: async (params) => {
|
|
@@ -18909,7 +19167,7 @@ var _TinyCloudNode = class _TinyCloudNode {
|
|
|
18909
19167
|
* @internal
|
|
18910
19168
|
*/
|
|
18911
19169
|
getSessionExpiry() {
|
|
18912
|
-
const expirationMs = this.config.sessionExpirationMs ??
|
|
19170
|
+
const expirationMs = this.config.sessionExpirationMs ?? DEFAULT_SESSION_EXPIRATION_MS;
|
|
18913
19171
|
return new Date(Date.now() + expirationMs);
|
|
18914
19172
|
}
|
|
18915
19173
|
/**
|
|
@@ -19066,6 +19324,34 @@ var _TinyCloudNode = class _TinyCloudNode {
|
|
|
19066
19324
|
}
|
|
19067
19325
|
return this._sql;
|
|
19068
19326
|
}
|
|
19327
|
+
/**
|
|
19328
|
+
* Get an SQL service scoped to a specific space.
|
|
19329
|
+
*
|
|
19330
|
+
* Mirrors {@link SpaceService}'s per-space KV factory: clones the active
|
|
19331
|
+
* service context and overrides its session's spaceId so that subsequent
|
|
19332
|
+
* `sql/<dbName>/<action>` invocations route to that space. Useful when
|
|
19333
|
+
* the caller already holds a delegation covering the target space (e.g.
|
|
19334
|
+
* via {@link grantRuntimePermissions} or {@link useRuntimeDelegation})
|
|
19335
|
+
* but the SDK's per-space SQL surface isn't otherwise exposed.
|
|
19336
|
+
*
|
|
19337
|
+
* Does NOT auto-create the space.
|
|
19338
|
+
*
|
|
19339
|
+
* @param spaceId - Full space URI (`tinycloud:pkh:eip155:<chain>:<addr>:<name>`).
|
|
19340
|
+
*/
|
|
19341
|
+
sqlForSpace(spaceId) {
|
|
19342
|
+
if (!this._serviceContext || !this._serviceContext.session) {
|
|
19343
|
+
throw new Error("Not signed in. Call signIn() first.");
|
|
19344
|
+
}
|
|
19345
|
+
const sql = new SQLService2({});
|
|
19346
|
+
const spaceScopedContext = new ServiceContext2({
|
|
19347
|
+
invoke: this._serviceContext.invoke,
|
|
19348
|
+
fetch: this._serviceContext.fetch,
|
|
19349
|
+
hosts: this._serviceContext.hosts
|
|
19350
|
+
});
|
|
19351
|
+
spaceScopedContext.setSession({ ...this._serviceContext.session, spaceId });
|
|
19352
|
+
sql.initialize(spaceScopedContext);
|
|
19353
|
+
return sql;
|
|
19354
|
+
}
|
|
19069
19355
|
/**
|
|
19070
19356
|
* DuckDB database operations on this user's space.
|
|
19071
19357
|
*/
|
|
@@ -19089,6 +19375,33 @@ var _TinyCloudNode = class _TinyCloudNode {
|
|
|
19089
19375
|
}
|
|
19090
19376
|
return this._vault;
|
|
19091
19377
|
}
|
|
19378
|
+
/**
|
|
19379
|
+
* App-facing secrets API backed by the `secrets` space vault.
|
|
19380
|
+
*/
|
|
19381
|
+
get secrets() {
|
|
19382
|
+
if (!this._spaceService) {
|
|
19383
|
+
throw new Error("Not signed in. Call signIn() first.");
|
|
19384
|
+
}
|
|
19385
|
+
if (!this._secrets) {
|
|
19386
|
+
this._secrets = new NodeSecretsService({
|
|
19387
|
+
getService: () => this.getBaseSecrets(),
|
|
19388
|
+
getManifest: () => this.manifest,
|
|
19389
|
+
grantPermissions: (additional) => this.grantRuntimePermissions(additional),
|
|
19390
|
+
canEscalate: () => this.signer !== void 0 && this.tc !== void 0,
|
|
19391
|
+
getUnlockSigner: () => this.signer ?? void 0
|
|
19392
|
+
});
|
|
19393
|
+
}
|
|
19394
|
+
return this._secrets;
|
|
19395
|
+
}
|
|
19396
|
+
getBaseSecrets() {
|
|
19397
|
+
if (!this._spaceService) {
|
|
19398
|
+
throw new Error("Not signed in. Call signIn() first.");
|
|
19399
|
+
}
|
|
19400
|
+
if (!this._baseSecrets) {
|
|
19401
|
+
this._baseSecrets = new SecretsService(() => this.space("secrets").vault);
|
|
19402
|
+
}
|
|
19403
|
+
return this._baseSecrets;
|
|
19404
|
+
}
|
|
19092
19405
|
/**
|
|
19093
19406
|
* Hooks write stream subscription API.
|
|
19094
19407
|
*/
|
|
@@ -19159,6 +19472,171 @@ var _TinyCloudNode = class _TinyCloudNode {
|
|
|
19159
19472
|
}
|
|
19160
19473
|
};
|
|
19161
19474
|
}
|
|
19475
|
+
/**
|
|
19476
|
+
* Check whether the current session or an approved runtime delegation covers
|
|
19477
|
+
* every requested permission.
|
|
19478
|
+
*/
|
|
19479
|
+
hasRuntimePermissions(permissions) {
|
|
19480
|
+
const session = this.auth?.tinyCloudSession;
|
|
19481
|
+
if (!session || !Array.isArray(permissions) || permissions.length === 0) {
|
|
19482
|
+
return false;
|
|
19483
|
+
}
|
|
19484
|
+
const expanded = this.expandPermissionEntries(permissions);
|
|
19485
|
+
if (this.sessionCoversPermissionEntries(session, expanded)) {
|
|
19486
|
+
return true;
|
|
19487
|
+
}
|
|
19488
|
+
return this.findRuntimeGrantsForPermissionEntries(expanded, session).length > 0;
|
|
19489
|
+
}
|
|
19490
|
+
/**
|
|
19491
|
+
* Return installed runtime permission delegations. When `permissions` is
|
|
19492
|
+
* provided, only delegations currently covering those permissions are
|
|
19493
|
+
* returned. Base-session manifest permissions are not represented here.
|
|
19494
|
+
*/
|
|
19495
|
+
getRuntimePermissionDelegations(permissions) {
|
|
19496
|
+
this.pruneExpiredRuntimePermissionGrants();
|
|
19497
|
+
if (permissions === void 0) {
|
|
19498
|
+
return this.runtimePermissionGrants.map((grant) => grant.delegation);
|
|
19499
|
+
}
|
|
19500
|
+
const session = this.auth?.tinyCloudSession;
|
|
19501
|
+
if (!session || !Array.isArray(permissions) || permissions.length === 0) {
|
|
19502
|
+
return [];
|
|
19503
|
+
}
|
|
19504
|
+
const expanded = this.expandPermissionEntries(permissions);
|
|
19505
|
+
return this.findRuntimeGrantsForPermissionEntries(expanded, session).map(
|
|
19506
|
+
(grant) => grant.delegation
|
|
19507
|
+
);
|
|
19508
|
+
}
|
|
19509
|
+
/**
|
|
19510
|
+
* Install a portable runtime permission delegation into this SDK instance so
|
|
19511
|
+
* matching service calls and downstream `delegateTo()` calls can use it.
|
|
19512
|
+
*/
|
|
19513
|
+
async useRuntimeDelegation(delegation) {
|
|
19514
|
+
const session = this.auth?.tinyCloudSession;
|
|
19515
|
+
if (!session) {
|
|
19516
|
+
throw new SessionExpiredError(/* @__PURE__ */ new Date(0));
|
|
19517
|
+
}
|
|
19518
|
+
if (delegation.expiry.getTime() <= Date.now()) {
|
|
19519
|
+
throw new SessionExpiredError(delegation.expiry);
|
|
19520
|
+
}
|
|
19521
|
+
const expectedDids = /* @__PURE__ */ new Set([session.verificationMethod, this.sessionDid]);
|
|
19522
|
+
if (!expectedDids.has(delegation.delegateDID)) {
|
|
19523
|
+
throw new Error(
|
|
19524
|
+
`Runtime delegation targets ${delegation.delegateDID} but this session key is ${session.verificationMethod}.`
|
|
19525
|
+
);
|
|
19526
|
+
}
|
|
19527
|
+
const targetHost = delegation.host ?? this.config.host;
|
|
19528
|
+
const activateResult = await activateSessionWithHost2(
|
|
19529
|
+
targetHost,
|
|
19530
|
+
delegation.delegationHeader
|
|
19531
|
+
);
|
|
19532
|
+
if (!activateResult.success) {
|
|
19533
|
+
throw new Error(
|
|
19534
|
+
`Failed to activate runtime permission delegation: ${activateResult.error}`
|
|
19535
|
+
);
|
|
19536
|
+
}
|
|
19537
|
+
this.runtimePermissionGrants = this.runtimePermissionGrants.filter(
|
|
19538
|
+
(grant) => grant.delegation.cid !== delegation.cid
|
|
19539
|
+
);
|
|
19540
|
+
this.runtimePermissionGrants.push(
|
|
19541
|
+
this.runtimeGrantFromDelegation(delegation, session)
|
|
19542
|
+
);
|
|
19543
|
+
}
|
|
19544
|
+
/**
|
|
19545
|
+
* Store additional permissions as narrow delegations to the current session
|
|
19546
|
+
* key. Future service invocations automatically use a stored delegation when
|
|
19547
|
+
* its `(space, service, path, action)` covers the request.
|
|
19548
|
+
*/
|
|
19549
|
+
async grantRuntimePermissions(permissions, options) {
|
|
19550
|
+
if (!Array.isArray(permissions) || permissions.length === 0) {
|
|
19551
|
+
throw new Error("grantRuntimePermissions requires a non-empty permissions array");
|
|
19552
|
+
}
|
|
19553
|
+
const session = this.auth?.tinyCloudSession;
|
|
19554
|
+
if (!session) {
|
|
19555
|
+
throw new SessionExpiredError(/* @__PURE__ */ new Date(0));
|
|
19556
|
+
}
|
|
19557
|
+
const sessionExpiry = extractSiweExpiration(session.siwe);
|
|
19558
|
+
if (sessionExpiry !== void 0) {
|
|
19559
|
+
const marginMs = _TinyCloudNode.SESSION_EXPIRY_SAFETY_MARGIN_MS;
|
|
19560
|
+
if (sessionExpiry.getTime() <= Date.now() + marginMs) {
|
|
19561
|
+
throw new SessionExpiredError(sessionExpiry);
|
|
19562
|
+
}
|
|
19563
|
+
}
|
|
19564
|
+
const expanded = this.expandPermissionEntries(permissions);
|
|
19565
|
+
if (this.sessionCoversPermissionEntries(session, expanded)) {
|
|
19566
|
+
return [];
|
|
19567
|
+
}
|
|
19568
|
+
const existingGrants = this.findRuntimeGrantsForPermissionEntries(expanded, session);
|
|
19569
|
+
if (existingGrants.length > 0) {
|
|
19570
|
+
return existingGrants.map((grant) => grant.delegation);
|
|
19571
|
+
}
|
|
19572
|
+
if (!this.signer) {
|
|
19573
|
+
throw new Error(
|
|
19574
|
+
"grantRuntimePermissions requires wallet mode with a signer or privateKey."
|
|
19575
|
+
);
|
|
19576
|
+
}
|
|
19577
|
+
const bySpace = /* @__PURE__ */ new Map();
|
|
19578
|
+
for (const entry of expanded) {
|
|
19579
|
+
const spaceId = this.resolvePermissionSpace(entry.space, session);
|
|
19580
|
+
const current = bySpace.get(spaceId) ?? [];
|
|
19581
|
+
current.push(entry);
|
|
19582
|
+
bySpace.set(spaceId, current);
|
|
19583
|
+
}
|
|
19584
|
+
const now = /* @__PURE__ */ new Date();
|
|
19585
|
+
const requestedExpiryMs = resolveExpiryMs(options?.expiry);
|
|
19586
|
+
let expiresAt = new Date(now.getTime() + requestedExpiryMs);
|
|
19587
|
+
if (sessionExpiry !== void 0 && sessionExpiry < expiresAt) {
|
|
19588
|
+
expiresAt = sessionExpiry;
|
|
19589
|
+
}
|
|
19590
|
+
const delegations = [];
|
|
19591
|
+
for (const [spaceId, entries] of bySpace) {
|
|
19592
|
+
const abilities = this.permissionsToAbilities(entries);
|
|
19593
|
+
const prepared = this.wasmBindings.prepareSession({
|
|
19594
|
+
abilities,
|
|
19595
|
+
address: this.wasmBindings.ensureEip55(session.address),
|
|
19596
|
+
chainId: session.chainId,
|
|
19597
|
+
domain: this.siweDomain,
|
|
19598
|
+
issuedAt: now.toISOString(),
|
|
19599
|
+
expirationTime: expiresAt.toISOString(),
|
|
19600
|
+
spaceId,
|
|
19601
|
+
jwk: session.jwk
|
|
19602
|
+
});
|
|
19603
|
+
const signature2 = await this.signer.signMessage(prepared.siwe);
|
|
19604
|
+
const delegatedSession = this.wasmBindings.completeSessionSetup({
|
|
19605
|
+
...prepared,
|
|
19606
|
+
signature: signature2
|
|
19607
|
+
});
|
|
19608
|
+
const activateResult = await activateSessionWithHost2(
|
|
19609
|
+
this.config.host,
|
|
19610
|
+
delegatedSession.delegationHeader
|
|
19611
|
+
);
|
|
19612
|
+
if (!activateResult.success) {
|
|
19613
|
+
throw new Error(
|
|
19614
|
+
`Failed to activate runtime permission delegation: ${activateResult.error}`
|
|
19615
|
+
);
|
|
19616
|
+
}
|
|
19617
|
+
const delegation = this.runtimeDelegationFromSession(
|
|
19618
|
+
delegatedSession,
|
|
19619
|
+
entries,
|
|
19620
|
+
spaceId,
|
|
19621
|
+
session,
|
|
19622
|
+
expiresAt
|
|
19623
|
+
);
|
|
19624
|
+
this.runtimePermissionGrants.push({
|
|
19625
|
+
session: {
|
|
19626
|
+
delegationHeader: delegatedSession.delegationHeader,
|
|
19627
|
+
delegationCid: delegatedSession.delegationCid,
|
|
19628
|
+
spaceId,
|
|
19629
|
+
verificationMethod: session.verificationMethod,
|
|
19630
|
+
jwk: session.jwk
|
|
19631
|
+
},
|
|
19632
|
+
delegation,
|
|
19633
|
+
operations: this.permissionOperations(entries, spaceId),
|
|
19634
|
+
expiresAt
|
|
19635
|
+
});
|
|
19636
|
+
delegations.push(delegation);
|
|
19637
|
+
}
|
|
19638
|
+
return delegations;
|
|
19639
|
+
}
|
|
19162
19640
|
/**
|
|
19163
19641
|
* Get the DelegationManager for delegation CRUD operations.
|
|
19164
19642
|
*
|
|
@@ -19227,6 +19705,12 @@ var _TinyCloudNode = class _TinyCloudNode {
|
|
|
19227
19705
|
get spaceService() {
|
|
19228
19706
|
return this.spaces;
|
|
19229
19707
|
}
|
|
19708
|
+
/**
|
|
19709
|
+
* Get a Space object by short name or full URI.
|
|
19710
|
+
*/
|
|
19711
|
+
space(nameOrUri) {
|
|
19712
|
+
return this.spaces.get(nameOrUri);
|
|
19713
|
+
}
|
|
19230
19714
|
/**
|
|
19231
19715
|
* Get the SharingService for creating and receiving v2 sharing links.
|
|
19232
19716
|
*
|
|
@@ -19294,7 +19778,7 @@ var _TinyCloudNode = class _TinyCloudNode {
|
|
|
19294
19778
|
];
|
|
19295
19779
|
const abilities = { kv: { "": kvActions } };
|
|
19296
19780
|
const now = /* @__PURE__ */ new Date();
|
|
19297
|
-
const expiryMs =
|
|
19781
|
+
const expiryMs = EXPIRY3.EPHEMERAL_MS;
|
|
19298
19782
|
const expirationTime = new Date(now.getTime() + expiryMs);
|
|
19299
19783
|
const prepared = this.wasmBindings.prepareSession({
|
|
19300
19784
|
abilities,
|
|
@@ -19341,7 +19825,7 @@ var _TinyCloudNode = class _TinyCloudNode {
|
|
|
19341
19825
|
if (this._serviceContext) {
|
|
19342
19826
|
const publicKV = new KVService2({ prefix: "" });
|
|
19343
19827
|
const publicContext = new ServiceContext2({
|
|
19344
|
-
invoke: this.
|
|
19828
|
+
invoke: this.invokeWithRuntimePermissions,
|
|
19345
19829
|
fetch: this._serviceContext.fetch,
|
|
19346
19830
|
hosts: this._serviceContext.hosts
|
|
19347
19831
|
});
|
|
@@ -19429,8 +19913,9 @@ var _TinyCloudNode = class _TinyCloudNode {
|
|
|
19429
19913
|
* Issue a delegation using the capability-chain flow.
|
|
19430
19914
|
*
|
|
19431
19915
|
* When every requested permission is a subset of the current
|
|
19432
|
-
* session's recap,
|
|
19433
|
-
*
|
|
19916
|
+
* session's recap, or of one installed runtime permission delegation,
|
|
19917
|
+
* the delegation is signed by the session key via WASM — no wallet
|
|
19918
|
+
* prompt. When at least one is NOT derivable, a
|
|
19434
19919
|
* {@link PermissionNotInManifestError} is raised (carrying the
|
|
19435
19920
|
* missing entries) so the caller can trigger an escalation flow
|
|
19436
19921
|
* (e.g. `TinyCloudWeb.requestPermissions`). Passing
|
|
@@ -19480,10 +19965,7 @@ var _TinyCloudNode = class _TinyCloudNode {
|
|
|
19480
19965
|
"delegateTo requires a non-empty permissions array"
|
|
19481
19966
|
);
|
|
19482
19967
|
}
|
|
19483
|
-
const expandedEntries =
|
|
19484
|
-
...entry,
|
|
19485
|
-
actions: expandActionShortNames(entry.service, entry.actions)
|
|
19486
|
-
}));
|
|
19968
|
+
const expandedEntries = this.expandPermissionEntries(permissions);
|
|
19487
19969
|
const now = /* @__PURE__ */ new Date();
|
|
19488
19970
|
const expiryMs = resolveExpiryMs(options?.expiry);
|
|
19489
19971
|
const expirationTime = new Date(now.getTime() + expiryMs);
|
|
@@ -19510,6 +19992,23 @@ var _TinyCloudNode = class _TinyCloudNode {
|
|
|
19510
19992
|
);
|
|
19511
19993
|
const { subset, missing } = isCapabilitySubset(expandedEntries, granted);
|
|
19512
19994
|
if (!subset) {
|
|
19995
|
+
const runtimeGrant = this.findGrantForOperations(
|
|
19996
|
+
this.permissionEntriesToOperations(expandedEntries, session)
|
|
19997
|
+
);
|
|
19998
|
+
if (runtimeGrant) {
|
|
19999
|
+
const marginMs = _TinyCloudNode.SESSION_EXPIRY_SAFETY_MARGIN_MS;
|
|
20000
|
+
if (runtimeGrant.expiresAt.getTime() <= Date.now() + marginMs) {
|
|
20001
|
+
throw new SessionExpiredError(runtimeGrant.expiresAt);
|
|
20002
|
+
}
|
|
20003
|
+
const runtimeExpiration = runtimeGrant.expiresAt < effectiveExpiration ? runtimeGrant.expiresAt : effectiveExpiration;
|
|
20004
|
+
const delegation2 = await this.createDelegationViaRuntimeGrant(
|
|
20005
|
+
did,
|
|
20006
|
+
expandedEntries,
|
|
20007
|
+
runtimeExpiration,
|
|
20008
|
+
runtimeGrant
|
|
20009
|
+
);
|
|
20010
|
+
return { delegation: delegation2, prompted: false };
|
|
20011
|
+
}
|
|
19513
20012
|
throw new PermissionNotInManifestError(missing, granted);
|
|
19514
20013
|
}
|
|
19515
20014
|
const delegation = await this.createDelegationViaWasmPath(
|
|
@@ -19654,6 +20153,41 @@ var _TinyCloudNode = class _TinyCloudNode {
|
|
|
19654
20153
|
host: this.config.host
|
|
19655
20154
|
};
|
|
19656
20155
|
}
|
|
20156
|
+
async createDelegationViaRuntimeGrant(did, entries, expirationTime, grant) {
|
|
20157
|
+
const result = this.createDelegationWrapper({
|
|
20158
|
+
session: grant.session,
|
|
20159
|
+
delegateDID: did,
|
|
20160
|
+
spaceId: grant.session.spaceId,
|
|
20161
|
+
abilities: this.permissionsToAbilities(entries),
|
|
20162
|
+
expirationSecs: Math.floor(expirationTime.getTime() / 1e3)
|
|
20163
|
+
});
|
|
20164
|
+
const primary = result.resources[0];
|
|
20165
|
+
const delegationHeader = { Authorization: result.delegation };
|
|
20166
|
+
const targetHost = grant.delegation.host ?? this.config.host;
|
|
20167
|
+
const activateResult = await activateSessionWithHost2(
|
|
20168
|
+
targetHost,
|
|
20169
|
+
delegationHeader
|
|
20170
|
+
);
|
|
20171
|
+
if (!activateResult.success) {
|
|
20172
|
+
throw new Error(
|
|
20173
|
+
`Failed to activate delegation with host: ${activateResult.error}`
|
|
20174
|
+
);
|
|
20175
|
+
}
|
|
20176
|
+
return {
|
|
20177
|
+
cid: result.cid,
|
|
20178
|
+
delegationHeader,
|
|
20179
|
+
spaceId: grant.session.spaceId,
|
|
20180
|
+
path: primary.path,
|
|
20181
|
+
actions: primary.actions,
|
|
20182
|
+
resources: result.resources,
|
|
20183
|
+
disableSubDelegation: false,
|
|
20184
|
+
expiry: result.expiry,
|
|
20185
|
+
delegateDID: did,
|
|
20186
|
+
ownerAddress: grant.delegation.ownerAddress,
|
|
20187
|
+
chainId: grant.delegation.chainId,
|
|
20188
|
+
host: targetHost
|
|
20189
|
+
};
|
|
20190
|
+
}
|
|
19657
20191
|
resolvePermissionSpace(space, session) {
|
|
19658
20192
|
if (space === void 0) {
|
|
19659
20193
|
return this.wasmBindings.makeSpaceId(
|
|
@@ -19670,6 +20204,220 @@ var _TinyCloudNode = class _TinyCloudNode {
|
|
|
19670
20204
|
}
|
|
19671
20205
|
return this.wasmBindings.makeSpaceId(session.address, session.chainId, space);
|
|
19672
20206
|
}
|
|
20207
|
+
expandPermissionEntries(permissions) {
|
|
20208
|
+
return expandPermissionEntriesCore(permissions);
|
|
20209
|
+
}
|
|
20210
|
+
shortServiceName(service) {
|
|
20211
|
+
const short = SERVICE_LONG_TO_SHORT[service];
|
|
20212
|
+
if (short === void 0) {
|
|
20213
|
+
throw new Error(
|
|
20214
|
+
`unknown service '${service}' \u2014 no short-form mapping`
|
|
20215
|
+
);
|
|
20216
|
+
}
|
|
20217
|
+
return short;
|
|
20218
|
+
}
|
|
20219
|
+
permissionsToAbilities(entries) {
|
|
20220
|
+
const abilities = {};
|
|
20221
|
+
for (const entry of entries) {
|
|
20222
|
+
const service = this.shortServiceName(entry.service);
|
|
20223
|
+
abilities[service] ?? (abilities[service] = {});
|
|
20224
|
+
const existing = abilities[service][entry.path] ?? [];
|
|
20225
|
+
const seen = new Set(existing);
|
|
20226
|
+
for (const action of entry.actions) {
|
|
20227
|
+
if (!seen.has(action)) {
|
|
20228
|
+
existing.push(action);
|
|
20229
|
+
seen.add(action);
|
|
20230
|
+
}
|
|
20231
|
+
}
|
|
20232
|
+
abilities[service][entry.path] = existing;
|
|
20233
|
+
}
|
|
20234
|
+
return abilities;
|
|
20235
|
+
}
|
|
20236
|
+
permissionOperations(entries, spaceId) {
|
|
20237
|
+
return entries.flatMap((entry) => {
|
|
20238
|
+
const service = this.shortServiceName(entry.service);
|
|
20239
|
+
return entry.actions.map((action) => ({
|
|
20240
|
+
spaceId,
|
|
20241
|
+
service,
|
|
20242
|
+
path: entry.path,
|
|
20243
|
+
action
|
|
20244
|
+
}));
|
|
20245
|
+
});
|
|
20246
|
+
}
|
|
20247
|
+
sessionCoversPermissionEntries(session, entries) {
|
|
20248
|
+
try {
|
|
20249
|
+
const granted = parseRecapCapabilities(
|
|
20250
|
+
(siwe) => this.wasmBindings.parseRecapFromSiwe(siwe),
|
|
20251
|
+
session.siwe
|
|
20252
|
+
);
|
|
20253
|
+
return isCapabilitySubset(entries, granted).subset;
|
|
20254
|
+
} catch {
|
|
20255
|
+
return false;
|
|
20256
|
+
}
|
|
20257
|
+
}
|
|
20258
|
+
permissionEntriesToOperations(entries, session) {
|
|
20259
|
+
return entries.flatMap((entry) => {
|
|
20260
|
+
const spaceId = this.resolvePermissionSpace(entry.space, session);
|
|
20261
|
+
const service = this.shortServiceName(entry.service);
|
|
20262
|
+
return entry.actions.map((action) => ({
|
|
20263
|
+
spaceId,
|
|
20264
|
+
service,
|
|
20265
|
+
path: entry.path,
|
|
20266
|
+
action
|
|
20267
|
+
}));
|
|
20268
|
+
});
|
|
20269
|
+
}
|
|
20270
|
+
findRuntimeGrantsForPermissionEntries(entries, session) {
|
|
20271
|
+
const grants = [];
|
|
20272
|
+
const operations = this.permissionEntriesToOperations(entries, session);
|
|
20273
|
+
if (operations.length === 0) {
|
|
20274
|
+
return grants;
|
|
20275
|
+
}
|
|
20276
|
+
for (const operation of operations) {
|
|
20277
|
+
const grant = this.findGrantForOperation(operation);
|
|
20278
|
+
if (!grant) {
|
|
20279
|
+
return [];
|
|
20280
|
+
}
|
|
20281
|
+
if (!grants.includes(grant)) {
|
|
20282
|
+
grants.push(grant);
|
|
20283
|
+
}
|
|
20284
|
+
}
|
|
20285
|
+
return grants;
|
|
20286
|
+
}
|
|
20287
|
+
runtimeDelegationFromSession(delegatedSession, entries, spaceId, session, expiresAt) {
|
|
20288
|
+
const resources = this.delegatedResourcesForEntries(entries, spaceId);
|
|
20289
|
+
const primary = resources[0];
|
|
20290
|
+
return {
|
|
20291
|
+
cid: delegatedSession.delegationCid,
|
|
20292
|
+
delegationHeader: delegatedSession.delegationHeader,
|
|
20293
|
+
spaceId,
|
|
20294
|
+
path: primary.path,
|
|
20295
|
+
actions: primary.actions,
|
|
20296
|
+
resources,
|
|
20297
|
+
disableSubDelegation: false,
|
|
20298
|
+
expiry: expiresAt,
|
|
20299
|
+
delegateDID: session.verificationMethod,
|
|
20300
|
+
ownerAddress: session.address,
|
|
20301
|
+
chainId: session.chainId,
|
|
20302
|
+
host: this.config.host
|
|
20303
|
+
};
|
|
20304
|
+
}
|
|
20305
|
+
runtimeGrantFromDelegation(delegation, session) {
|
|
20306
|
+
const operations = this.operationsFromDelegation(delegation);
|
|
20307
|
+
return {
|
|
20308
|
+
session: {
|
|
20309
|
+
delegationHeader: delegation.delegationHeader,
|
|
20310
|
+
delegationCid: delegation.cid,
|
|
20311
|
+
spaceId: delegation.spaceId,
|
|
20312
|
+
verificationMethod: session.verificationMethod,
|
|
20313
|
+
jwk: session.jwk
|
|
20314
|
+
},
|
|
20315
|
+
delegation,
|
|
20316
|
+
operations,
|
|
20317
|
+
expiresAt: delegation.expiry
|
|
20318
|
+
};
|
|
20319
|
+
}
|
|
20320
|
+
delegatedResourcesForEntries(entries, spaceId) {
|
|
20321
|
+
return entries.map((entry) => ({
|
|
20322
|
+
service: this.shortServiceName(entry.service),
|
|
20323
|
+
space: spaceId,
|
|
20324
|
+
path: entry.path,
|
|
20325
|
+
actions: [...entry.actions]
|
|
20326
|
+
}));
|
|
20327
|
+
}
|
|
20328
|
+
operationsFromDelegation(delegation) {
|
|
20329
|
+
const resources = delegation.resources !== void 0 && delegation.resources.length > 0 ? delegation.resources : this.flatDelegationResources(delegation);
|
|
20330
|
+
return resources.flatMap(
|
|
20331
|
+
(resource) => resource.actions.map((action) => ({
|
|
20332
|
+
spaceId: resource.space,
|
|
20333
|
+
service: this.invocationServiceName(resource.service),
|
|
20334
|
+
path: resource.path,
|
|
20335
|
+
action
|
|
20336
|
+
}))
|
|
20337
|
+
);
|
|
20338
|
+
}
|
|
20339
|
+
flatDelegationResources(delegation) {
|
|
20340
|
+
const byService = /* @__PURE__ */ new Map();
|
|
20341
|
+
for (const action of delegation.actions) {
|
|
20342
|
+
const service = this.shortServiceName(action.split("/")[0]);
|
|
20343
|
+
const actions = byService.get(service) ?? [];
|
|
20344
|
+
actions.push(action);
|
|
20345
|
+
byService.set(service, actions);
|
|
20346
|
+
}
|
|
20347
|
+
return [...byService.entries()].map(([service, actions]) => ({
|
|
20348
|
+
service,
|
|
20349
|
+
space: delegation.spaceId,
|
|
20350
|
+
path: delegation.path,
|
|
20351
|
+
actions
|
|
20352
|
+
}));
|
|
20353
|
+
}
|
|
20354
|
+
selectInvocationSession(fallback, service, path, action) {
|
|
20355
|
+
const grant = this.findGrantForOperation({
|
|
20356
|
+
spaceId: fallback.spaceId,
|
|
20357
|
+
service: this.invocationServiceName(service),
|
|
20358
|
+
path,
|
|
20359
|
+
action
|
|
20360
|
+
});
|
|
20361
|
+
return grant?.session ?? fallback;
|
|
20362
|
+
}
|
|
20363
|
+
findGrantForOperations(operations) {
|
|
20364
|
+
if (operations.length === 0) {
|
|
20365
|
+
return void 0;
|
|
20366
|
+
}
|
|
20367
|
+
this.pruneExpiredRuntimePermissionGrants();
|
|
20368
|
+
return this.runtimePermissionGrants.find((grant) => {
|
|
20369
|
+
return operations.every(
|
|
20370
|
+
(operation) => grant.operations.some(
|
|
20371
|
+
(granted) => this.operationCovers(granted, operation)
|
|
20372
|
+
)
|
|
20373
|
+
);
|
|
20374
|
+
});
|
|
20375
|
+
}
|
|
20376
|
+
findGrantForOperation(operation) {
|
|
20377
|
+
return this.findGrantForOperations([operation]);
|
|
20378
|
+
}
|
|
20379
|
+
pruneExpiredRuntimePermissionGrants() {
|
|
20380
|
+
const now = Date.now();
|
|
20381
|
+
this.runtimePermissionGrants = this.runtimePermissionGrants.filter(
|
|
20382
|
+
(grant) => grant.expiresAt.getTime() > now
|
|
20383
|
+
);
|
|
20384
|
+
}
|
|
20385
|
+
operationCovers(granted, requested) {
|
|
20386
|
+
return granted.spaceId === requested.spaceId && granted.service === requested.service && this.actionContains(granted.action, requested.action) && this.pathContains(granted.path, requested.path);
|
|
20387
|
+
}
|
|
20388
|
+
actionContains(grantedAction, requestedAction) {
|
|
20389
|
+
if (grantedAction === requestedAction) {
|
|
20390
|
+
return true;
|
|
20391
|
+
}
|
|
20392
|
+
if (grantedAction.endsWith("/*")) {
|
|
20393
|
+
const prefix = grantedAction.slice(0, -2);
|
|
20394
|
+
return requestedAction.startsWith(`${prefix}/`);
|
|
20395
|
+
}
|
|
20396
|
+
return false;
|
|
20397
|
+
}
|
|
20398
|
+
invocationServiceName(service) {
|
|
20399
|
+
return service.startsWith("tinycloud.") ? this.shortServiceName(service) : service;
|
|
20400
|
+
}
|
|
20401
|
+
pathContains(grantedPath, requestedPath) {
|
|
20402
|
+
if (grantedPath === "" || grantedPath === "/") {
|
|
20403
|
+
return true;
|
|
20404
|
+
}
|
|
20405
|
+
if (grantedPath.endsWith("/**")) {
|
|
20406
|
+
return requestedPath.startsWith(grantedPath.slice(0, -3));
|
|
20407
|
+
}
|
|
20408
|
+
if (grantedPath.endsWith("/*")) {
|
|
20409
|
+
const prefix = grantedPath.slice(0, -2);
|
|
20410
|
+
if (!requestedPath.startsWith(prefix)) {
|
|
20411
|
+
return false;
|
|
20412
|
+
}
|
|
20413
|
+
const remainder = requestedPath.slice(prefix.length);
|
|
20414
|
+
return !remainder.includes("/") || remainder === "/";
|
|
20415
|
+
}
|
|
20416
|
+
if (grantedPath.endsWith("/")) {
|
|
20417
|
+
return requestedPath.startsWith(grantedPath);
|
|
20418
|
+
}
|
|
20419
|
+
return grantedPath === requestedPath;
|
|
20420
|
+
}
|
|
19673
20421
|
/**
|
|
19674
20422
|
* Issue a delegation via the legacy wallet-signed SIWE path for a single
|
|
19675
20423
|
* {@link PermissionEntry}. Shares the implementation with the public
|
|
@@ -20191,15 +20939,18 @@ import {
|
|
|
20191
20939
|
ACCOUNT_REGISTRY_SPACE as ACCOUNT_REGISTRY_SPACE2,
|
|
20192
20940
|
DEFAULT_MANIFEST_SPACE as DEFAULT_MANIFEST_SPACE2,
|
|
20193
20941
|
DEFAULT_MANIFEST_VERSION,
|
|
20942
|
+
VAULT_PERMISSION_SERVICE,
|
|
20194
20943
|
PermissionNotInManifestError as PermissionNotInManifestError2,
|
|
20195
20944
|
SessionExpiredError as SessionExpiredError2,
|
|
20196
20945
|
ManifestValidationError,
|
|
20197
20946
|
composeManifestRequest as composeManifestRequest2,
|
|
20198
|
-
resolveManifest,
|
|
20947
|
+
resolveManifest as resolveManifest2,
|
|
20199
20948
|
validateManifest,
|
|
20200
20949
|
loadManifest,
|
|
20201
20950
|
isCapabilitySubset as isCapabilitySubset2,
|
|
20202
|
-
expandActionShortNames
|
|
20951
|
+
expandActionShortNames,
|
|
20952
|
+
expandPermissionEntries,
|
|
20953
|
+
expandPermissionEntry,
|
|
20203
20954
|
parseExpiry as parseExpiry2,
|
|
20204
20955
|
resourceCapabilitiesToSpaceAbilitiesMap as resourceCapabilitiesToSpaceAbilitiesMap2
|
|
20205
20956
|
} from "@tinycloud/sdk-core";
|
|
@@ -20232,7 +20983,11 @@ import {
|
|
|
20232
20983
|
DataVaultService as DataVaultService2,
|
|
20233
20984
|
VaultHeaders,
|
|
20234
20985
|
VaultPublicSpaceKVActions,
|
|
20235
|
-
createVaultCrypto as createVaultCrypto2
|
|
20986
|
+
createVaultCrypto as createVaultCrypto2,
|
|
20987
|
+
SecretsService as SecretsService2,
|
|
20988
|
+
SECRET_NAME_RE,
|
|
20989
|
+
canonicalizeSecretScope,
|
|
20990
|
+
resolveSecretPath as resolveSecretPath2
|
|
20236
20991
|
} from "@tinycloud/sdk-core";
|
|
20237
20992
|
import { HooksService as HooksService3 } from "@tinycloud/sdk-core";
|
|
20238
20993
|
import {
|
|
@@ -20289,8 +21044,10 @@ export {
|
|
|
20289
21044
|
PrefixedKVService,
|
|
20290
21045
|
PrivateKeySigner,
|
|
20291
21046
|
ProtocolMismatchError,
|
|
21047
|
+
SECRET_NAME_RE,
|
|
20292
21048
|
SQLAction,
|
|
20293
21049
|
SQLService3 as SQLService,
|
|
21050
|
+
SecretsService2 as SecretsService,
|
|
20294
21051
|
ServiceContext3 as ServiceContext,
|
|
20295
21052
|
SessionExpiredError2 as SessionExpiredError,
|
|
20296
21053
|
SharingService2 as SharingService,
|
|
@@ -20301,11 +21058,13 @@ export {
|
|
|
20301
21058
|
TinyCloud2 as TinyCloud,
|
|
20302
21059
|
TinyCloudNode,
|
|
20303
21060
|
UnsupportedFeatureError2 as UnsupportedFeatureError,
|
|
21061
|
+
VAULT_PERMISSION_SERVICE,
|
|
20304
21062
|
VaultHeaders,
|
|
20305
21063
|
VaultPublicSpaceKVActions,
|
|
20306
21064
|
VersionCheckError,
|
|
20307
21065
|
WasmKeyProvider,
|
|
20308
21066
|
buildSpaceUri,
|
|
21067
|
+
canonicalizeSecretScope,
|
|
20309
21068
|
checkNodeInfo2 as checkNodeInfo,
|
|
20310
21069
|
composeManifestRequest2 as composeManifestRequest,
|
|
20311
21070
|
createCapabilityKeyRegistry,
|
|
@@ -20316,13 +21075,16 @@ export {
|
|
|
20316
21075
|
defaultSignStrategy,
|
|
20317
21076
|
defaultSpaceCreationHandler,
|
|
20318
21077
|
deserializeDelegation,
|
|
20319
|
-
|
|
21078
|
+
expandActionShortNames,
|
|
21079
|
+
expandPermissionEntries,
|
|
21080
|
+
expandPermissionEntry,
|
|
20320
21081
|
isCapabilitySubset2 as isCapabilitySubset,
|
|
20321
21082
|
loadManifest,
|
|
20322
21083
|
makePublicSpaceId2 as makePublicSpaceId,
|
|
20323
21084
|
parseExpiry2 as parseExpiry,
|
|
20324
21085
|
parseSpaceUri,
|
|
20325
|
-
resolveManifest,
|
|
21086
|
+
resolveManifest2 as resolveManifest,
|
|
21087
|
+
resolveSecretPath2 as resolveSecretPath,
|
|
20326
21088
|
resourceCapabilitiesToSpaceAbilitiesMap2 as resourceCapabilitiesToSpaceAbilitiesMap,
|
|
20327
21089
|
serializeDelegation,
|
|
20328
21090
|
validateManifest
|