@tinycloud/node-sdk 2.2.0-beta.6 → 2.2.0-beta.8
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-DdMPUB5s.d.cts → core-DcJ27GsA.d.cts} +71 -4
- package/dist/{core-DdMPUB5s.d.ts → core-DcJ27GsA.d.ts} +71 -4
- package/dist/core.cjs +794 -168
- package/dist/core.cjs.map +1 -1
- package/dist/core.d.cts +2 -2
- package/dist/core.d.ts +2 -2
- package/dist/core.js +700 -71
- package/dist/core.js.map +1 -1
- package/dist/index.cjs +797 -171
- 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 +701 -71
- package/dist/index.js.map +1 -1
- package/package.json +2 -2
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,
|
|
@@ -18241,6 +18242,151 @@ function extractSiweExpiration(siwe) {
|
|
|
18241
18242
|
return d;
|
|
18242
18243
|
}
|
|
18243
18244
|
|
|
18245
|
+
// src/NodeSecretsService.ts
|
|
18246
|
+
import {
|
|
18247
|
+
ErrorCodes,
|
|
18248
|
+
resolveManifest
|
|
18249
|
+
} from "@tinycloud/sdk-core";
|
|
18250
|
+
var SECRET_NAME_RE = /^[A-Z][A-Z0-9_]*$/;
|
|
18251
|
+
var SECRET_PREFIX = "secrets/";
|
|
18252
|
+
var SECRETS_SPACE = "secrets";
|
|
18253
|
+
function ok() {
|
|
18254
|
+
return { ok: true, data: void 0 };
|
|
18255
|
+
}
|
|
18256
|
+
function secretsError(code, message, cause) {
|
|
18257
|
+
return {
|
|
18258
|
+
ok: false,
|
|
18259
|
+
error: {
|
|
18260
|
+
code,
|
|
18261
|
+
service: "secrets",
|
|
18262
|
+
message,
|
|
18263
|
+
...cause ? { cause } : {}
|
|
18264
|
+
}
|
|
18265
|
+
};
|
|
18266
|
+
}
|
|
18267
|
+
function actionUrn(action) {
|
|
18268
|
+
return `tinycloud.kv/${action}`;
|
|
18269
|
+
}
|
|
18270
|
+
function secretResourcePath(base2, name) {
|
|
18271
|
+
return `${base2}/${SECRET_PREFIX}${name}`;
|
|
18272
|
+
}
|
|
18273
|
+
function secretPermissionEntries(name, action) {
|
|
18274
|
+
return [
|
|
18275
|
+
{
|
|
18276
|
+
service: "tinycloud.kv",
|
|
18277
|
+
space: SECRETS_SPACE,
|
|
18278
|
+
path: secretResourcePath("keys", name),
|
|
18279
|
+
actions: [action],
|
|
18280
|
+
skipPrefix: true
|
|
18281
|
+
},
|
|
18282
|
+
{
|
|
18283
|
+
service: "tinycloud.kv",
|
|
18284
|
+
space: SECRETS_SPACE,
|
|
18285
|
+
path: secretResourcePath("vault", name),
|
|
18286
|
+
actions: [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) {
|
|
18321
|
+
return this.service.get(name);
|
|
18322
|
+
}
|
|
18323
|
+
async put(name, value) {
|
|
18324
|
+
const permission = await this.ensureMutationPermission(name, "put");
|
|
18325
|
+
if (!permission.ok) return permission;
|
|
18326
|
+
return this.service.put(name, value);
|
|
18327
|
+
}
|
|
18328
|
+
async delete(name) {
|
|
18329
|
+
const permission = await this.ensureMutationPermission(name, "del");
|
|
18330
|
+
if (!permission.ok) return permission;
|
|
18331
|
+
return this.service.delete(name);
|
|
18332
|
+
}
|
|
18333
|
+
list() {
|
|
18334
|
+
return this.service.list();
|
|
18335
|
+
}
|
|
18336
|
+
get service() {
|
|
18337
|
+
return this.config.getService();
|
|
18338
|
+
}
|
|
18339
|
+
async ensureMutationPermission(name, action) {
|
|
18340
|
+
if (!SECRET_NAME_RE.test(name)) {
|
|
18341
|
+
return secretsError(
|
|
18342
|
+
ErrorCodes.INVALID_INPUT,
|
|
18343
|
+
`Invalid secret name ${JSON.stringify(name)}. Secret names must match ${SECRET_NAME_RE.source}.`
|
|
18344
|
+
);
|
|
18345
|
+
}
|
|
18346
|
+
if (this.hasMutationPermission(name, action)) {
|
|
18347
|
+
return ok();
|
|
18348
|
+
}
|
|
18349
|
+
if (!this.config.canEscalate()) {
|
|
18350
|
+
return secretsError(
|
|
18351
|
+
ErrorCodes.PERMISSION_DENIED,
|
|
18352
|
+
`Cannot autosign ${actionUrn(action)} for ${name}; TinyCloudNode needs wallet mode with a signer or privateKey.`
|
|
18353
|
+
);
|
|
18354
|
+
}
|
|
18355
|
+
try {
|
|
18356
|
+
await this.config.grantPermissions(secretPermissionEntries(name, action));
|
|
18357
|
+
return this.restoreUnlockAfterEscalation();
|
|
18358
|
+
} catch (error) {
|
|
18359
|
+
return secretsError(
|
|
18360
|
+
ErrorCodes.PERMISSION_DENIED,
|
|
18361
|
+
error instanceof Error ? error.message : `Autosign escalation for ${actionUrn(action)} on ${name} failed.`,
|
|
18362
|
+
error instanceof Error ? error : void 0
|
|
18363
|
+
);
|
|
18364
|
+
}
|
|
18365
|
+
}
|
|
18366
|
+
async restoreUnlockAfterEscalation() {
|
|
18367
|
+
if (!this.shouldRestoreUnlock) {
|
|
18368
|
+
return ok();
|
|
18369
|
+
}
|
|
18370
|
+
return this.service.unlock(this.unlockSigner);
|
|
18371
|
+
}
|
|
18372
|
+
hasMutationPermission(name, action) {
|
|
18373
|
+
const manifest = this.config.getManifest();
|
|
18374
|
+
if (manifest === void 0) {
|
|
18375
|
+
return false;
|
|
18376
|
+
}
|
|
18377
|
+
const manifests = Array.isArray(manifest) ? manifest : [manifest];
|
|
18378
|
+
const requiredAction = actionUrn(action);
|
|
18379
|
+
return manifests.some((entry) => {
|
|
18380
|
+
const resolved = resolveManifest(entry);
|
|
18381
|
+
return ["keys", "vault"].every(
|
|
18382
|
+
(base2) => resolved.resources.some(
|
|
18383
|
+
(resource) => resource.service === "tinycloud.kv" && isSecretsSpace(resource.space) && resource.path === secretResourcePath(base2, name) && resource.actions.includes(requiredAction)
|
|
18384
|
+
)
|
|
18385
|
+
);
|
|
18386
|
+
});
|
|
18387
|
+
}
|
|
18388
|
+
};
|
|
18389
|
+
|
|
18244
18390
|
// src/TinyCloudNode.ts
|
|
18245
18391
|
var DEFAULT_HOST = "https://node.tinycloud.xyz";
|
|
18246
18392
|
var _TinyCloudNode = class _TinyCloudNode {
|
|
@@ -18272,6 +18418,30 @@ var _TinyCloudNode = class _TinyCloudNode {
|
|
|
18272
18418
|
this.auth = null;
|
|
18273
18419
|
this.tc = null;
|
|
18274
18420
|
this._chainId = 1;
|
|
18421
|
+
this.runtimePermissionGrants = [];
|
|
18422
|
+
this.invokeWithRuntimePermissions = (session, service, path, action, facts) => {
|
|
18423
|
+
return this.wasmBindings.invoke(
|
|
18424
|
+
this.selectInvocationSession(session, service, path, action),
|
|
18425
|
+
service,
|
|
18426
|
+
path,
|
|
18427
|
+
action,
|
|
18428
|
+
facts
|
|
18429
|
+
);
|
|
18430
|
+
};
|
|
18431
|
+
this.invokeAnyWithRuntimePermissions = (session, entries, facts) => {
|
|
18432
|
+
if (!this.wasmBindings.invokeAny) {
|
|
18433
|
+
throw new Error("WASM binding does not support invokeAny");
|
|
18434
|
+
}
|
|
18435
|
+
const grant = this.findGrantForOperations(
|
|
18436
|
+
entries.map((entry) => ({
|
|
18437
|
+
spaceId: entry.spaceId,
|
|
18438
|
+
service: this.invocationServiceName(entry.service),
|
|
18439
|
+
path: entry.path,
|
|
18440
|
+
action: entry.action
|
|
18441
|
+
}))
|
|
18442
|
+
);
|
|
18443
|
+
return this.wasmBindings.invokeAny(grant?.session ?? session, entries, facts);
|
|
18444
|
+
};
|
|
18275
18445
|
this.explicitHost = config.host;
|
|
18276
18446
|
this.config = {
|
|
18277
18447
|
...config,
|
|
@@ -18307,7 +18477,7 @@ var _TinyCloudNode = class _TinyCloudNode {
|
|
|
18307
18477
|
this._sharingService = new SharingService({
|
|
18308
18478
|
hosts: [this.config.host],
|
|
18309
18479
|
// session: undefined - not needed for receive()
|
|
18310
|
-
invoke: this.
|
|
18480
|
+
invoke: this.invokeWithRuntimePermissions,
|
|
18311
18481
|
fetch: globalThis.fetch.bind(globalThis),
|
|
18312
18482
|
keyProvider: this._keyProvider,
|
|
18313
18483
|
registry: this._capabilityRegistry,
|
|
@@ -18375,7 +18545,7 @@ var _TinyCloudNode = class _TinyCloudNode {
|
|
|
18375
18545
|
includeAccountRegistryPermissions: config.includeAccountRegistryPermissions
|
|
18376
18546
|
});
|
|
18377
18547
|
this.tc = new TinyCloud(this.auth, {
|
|
18378
|
-
invokeAny: this.
|
|
18548
|
+
invokeAny: this.invokeAnyWithRuntimePermissions
|
|
18379
18549
|
});
|
|
18380
18550
|
}
|
|
18381
18551
|
syncResolvedHostFromAuth() {
|
|
@@ -18495,7 +18665,12 @@ var _TinyCloudNode = class _TinyCloudNode {
|
|
|
18495
18665
|
this._sql = void 0;
|
|
18496
18666
|
this._duckdb = void 0;
|
|
18497
18667
|
this._hooks = void 0;
|
|
18668
|
+
this._vault = void 0;
|
|
18669
|
+
this._baseSecrets = void 0;
|
|
18670
|
+
this._secrets = void 0;
|
|
18671
|
+
this._spaceService = void 0;
|
|
18498
18672
|
this._serviceContext = void 0;
|
|
18673
|
+
this.runtimePermissionGrants = [];
|
|
18499
18674
|
await this.tc.signIn(options);
|
|
18500
18675
|
this.syncResolvedHostFromAuth();
|
|
18501
18676
|
this.initializeServices();
|
|
@@ -18580,7 +18755,12 @@ var _TinyCloudNode = class _TinyCloudNode {
|
|
|
18580
18755
|
this._sql = void 0;
|
|
18581
18756
|
this._duckdb = void 0;
|
|
18582
18757
|
this._hooks = void 0;
|
|
18758
|
+
this._vault = void 0;
|
|
18759
|
+
this._baseSecrets = void 0;
|
|
18760
|
+
this._secrets = void 0;
|
|
18761
|
+
this._spaceService = void 0;
|
|
18583
18762
|
this._serviceContext = void 0;
|
|
18763
|
+
this.runtimePermissionGrants = [];
|
|
18584
18764
|
if (sessionData.address) {
|
|
18585
18765
|
this._address = sessionData.address;
|
|
18586
18766
|
}
|
|
@@ -18588,8 +18768,8 @@ var _TinyCloudNode = class _TinyCloudNode {
|
|
|
18588
18768
|
this._chainId = sessionData.chainId;
|
|
18589
18769
|
}
|
|
18590
18770
|
this._serviceContext = new ServiceContext2({
|
|
18591
|
-
invoke: this.
|
|
18592
|
-
invokeAny: this.
|
|
18771
|
+
invoke: this.invokeWithRuntimePermissions,
|
|
18772
|
+
invokeAny: this.invokeAnyWithRuntimePermissions,
|
|
18593
18773
|
fetch: globalThis.fetch.bind(globalThis),
|
|
18594
18774
|
hosts: [this.config.host]
|
|
18595
18775
|
});
|
|
@@ -18613,41 +18793,7 @@ var _TinyCloudNode = class _TinyCloudNode {
|
|
|
18613
18793
|
jwk: sessionData.jwk
|
|
18614
18794
|
};
|
|
18615
18795
|
this._serviceContext.setSession(serviceSession);
|
|
18616
|
-
|
|
18617
|
-
const vaultCrypto = createVaultCrypto({
|
|
18618
|
-
vault_encrypt: wasm.vault_encrypt,
|
|
18619
|
-
vault_decrypt: wasm.vault_decrypt,
|
|
18620
|
-
vault_derive_key: wasm.vault_derive_key,
|
|
18621
|
-
vault_x25519_from_seed: wasm.vault_x25519_from_seed,
|
|
18622
|
-
vault_x25519_dh: wasm.vault_x25519_dh,
|
|
18623
|
-
vault_random_bytes: wasm.vault_random_bytes,
|
|
18624
|
-
vault_sha256: wasm.vault_sha256
|
|
18625
|
-
});
|
|
18626
|
-
const self2 = this;
|
|
18627
|
-
this._vault = new DataVaultService({
|
|
18628
|
-
spaceId: sessionData.spaceId,
|
|
18629
|
-
crypto: vaultCrypto,
|
|
18630
|
-
tc: {
|
|
18631
|
-
kv: this._kv,
|
|
18632
|
-
ensurePublicSpace: async () => {
|
|
18633
|
-
try {
|
|
18634
|
-
await self2.ensurePublicSpace();
|
|
18635
|
-
return { ok: true, data: void 0 };
|
|
18636
|
-
} catch (error) {
|
|
18637
|
-
return { ok: false, error: { code: "STORAGE_ERROR", message: error instanceof Error ? error.message : String(error), service: "vault" } };
|
|
18638
|
-
}
|
|
18639
|
-
},
|
|
18640
|
-
get publicKV() {
|
|
18641
|
-
return self2._publicKV ?? self2.tc.publicKV;
|
|
18642
|
-
},
|
|
18643
|
-
readPublicSpace: (host, spaceId, key2) => TinyCloud.readPublicSpace(host, spaceId, key2),
|
|
18644
|
-
makePublicSpaceId: TinyCloud.makePublicSpaceId,
|
|
18645
|
-
did: this.did,
|
|
18646
|
-
address: sessionData.address ?? this._address ?? "",
|
|
18647
|
-
chainId: sessionData.chainId ?? this._chainId,
|
|
18648
|
-
hosts: [this.config.host]
|
|
18649
|
-
}
|
|
18650
|
-
});
|
|
18796
|
+
this._vault = this.createVaultService(sessionData.spaceId, this._kv);
|
|
18651
18797
|
this._vault.initialize(this._serviceContext);
|
|
18652
18798
|
this._serviceContext.registerService("vault", this._vault);
|
|
18653
18799
|
this.initializeV2Services(serviceSession);
|
|
@@ -18709,7 +18855,7 @@ var _TinyCloudNode = class _TinyCloudNode {
|
|
|
18709
18855
|
includeAccountRegistryPermissions: this.config.includeAccountRegistryPermissions
|
|
18710
18856
|
});
|
|
18711
18857
|
this.tc = new TinyCloud(this.auth, {
|
|
18712
|
-
invokeAny: this.
|
|
18858
|
+
invokeAny: this.invokeAnyWithRuntimePermissions
|
|
18713
18859
|
});
|
|
18714
18860
|
this.config.prefix = prefix;
|
|
18715
18861
|
}
|
|
@@ -18753,7 +18899,7 @@ var _TinyCloudNode = class _TinyCloudNode {
|
|
|
18753
18899
|
includeAccountRegistryPermissions: this.config.includeAccountRegistryPermissions
|
|
18754
18900
|
});
|
|
18755
18901
|
this.tc = new TinyCloud(this.auth, {
|
|
18756
|
-
invokeAny: this.
|
|
18902
|
+
invokeAny: this.invokeAnyWithRuntimePermissions
|
|
18757
18903
|
});
|
|
18758
18904
|
this.config.prefix = prefix;
|
|
18759
18905
|
}
|
|
@@ -18766,10 +18912,10 @@ var _TinyCloudNode = class _TinyCloudNode {
|
|
|
18766
18912
|
if (!session) {
|
|
18767
18913
|
return;
|
|
18768
18914
|
}
|
|
18769
|
-
this.tc.initializeServices(this.
|
|
18915
|
+
this.tc.initializeServices(this.invokeWithRuntimePermissions, [this.config.host]);
|
|
18770
18916
|
this._serviceContext = new ServiceContext2({
|
|
18771
|
-
invoke: this.
|
|
18772
|
-
invokeAny: this.
|
|
18917
|
+
invoke: this.invokeWithRuntimePermissions,
|
|
18918
|
+
invokeAny: this.invokeAnyWithRuntimePermissions,
|
|
18773
18919
|
fetch: globalThis.fetch.bind(globalThis),
|
|
18774
18920
|
hosts: [this.config.host]
|
|
18775
18921
|
});
|
|
@@ -18799,6 +18945,28 @@ var _TinyCloudNode = class _TinyCloudNode {
|
|
|
18799
18945
|
};
|
|
18800
18946
|
this._serviceContext.setSession(serviceSession);
|
|
18801
18947
|
this.tc.serviceContext.setSession(serviceSession);
|
|
18948
|
+
this._vault = this.createVaultService(session.spaceId, this._kv);
|
|
18949
|
+
this._vault.initialize(this._serviceContext);
|
|
18950
|
+
this._serviceContext.registerService("vault", this._vault);
|
|
18951
|
+
this.initializeV2Services(serviceSession);
|
|
18952
|
+
}
|
|
18953
|
+
createSpaceScopedKVService(spaceId) {
|
|
18954
|
+
const kvService = new KVService2({});
|
|
18955
|
+
if (this._serviceContext) {
|
|
18956
|
+
const spaceScopedContext = new ServiceContext2({
|
|
18957
|
+
invoke: this._serviceContext.invoke,
|
|
18958
|
+
fetch: this._serviceContext.fetch,
|
|
18959
|
+
hosts: this._serviceContext.hosts
|
|
18960
|
+
});
|
|
18961
|
+
const session = this._serviceContext.session;
|
|
18962
|
+
if (session) {
|
|
18963
|
+
spaceScopedContext.setSession({ ...session, spaceId });
|
|
18964
|
+
}
|
|
18965
|
+
kvService.initialize(spaceScopedContext);
|
|
18966
|
+
}
|
|
18967
|
+
return kvService;
|
|
18968
|
+
}
|
|
18969
|
+
createVaultService(spaceId, kv) {
|
|
18802
18970
|
const wasm = this.wasmBindings;
|
|
18803
18971
|
const vaultCrypto = createVaultCrypto({
|
|
18804
18972
|
vault_encrypt: wasm.vault_encrypt,
|
|
@@ -18810,11 +18978,11 @@ var _TinyCloudNode = class _TinyCloudNode {
|
|
|
18810
18978
|
vault_sha256: wasm.vault_sha256
|
|
18811
18979
|
});
|
|
18812
18980
|
const self2 = this;
|
|
18813
|
-
|
|
18814
|
-
spaceId
|
|
18981
|
+
return new DataVaultService({
|
|
18982
|
+
spaceId,
|
|
18815
18983
|
crypto: vaultCrypto,
|
|
18816
18984
|
tc: {
|
|
18817
|
-
kv
|
|
18985
|
+
kv,
|
|
18818
18986
|
ensurePublicSpace: async () => {
|
|
18819
18987
|
try {
|
|
18820
18988
|
await self2.ensurePublicSpace();
|
|
@@ -18826,17 +18994,14 @@ var _TinyCloudNode = class _TinyCloudNode {
|
|
|
18826
18994
|
get publicKV() {
|
|
18827
18995
|
return self2._publicKV ?? self2.tc.publicKV;
|
|
18828
18996
|
},
|
|
18829
|
-
readPublicSpace: (host,
|
|
18997
|
+
readPublicSpace: (host, targetSpaceId, key2) => TinyCloud.readPublicSpace(host, targetSpaceId, key2),
|
|
18830
18998
|
makePublicSpaceId: TinyCloud.makePublicSpaceId,
|
|
18831
18999
|
did: this.did,
|
|
18832
|
-
address: this._address,
|
|
19000
|
+
address: this._address ?? "",
|
|
18833
19001
|
chainId: this._chainId,
|
|
18834
19002
|
hosts: [this.config.host]
|
|
18835
19003
|
}
|
|
18836
19004
|
});
|
|
18837
|
-
this._vault.initialize(this._serviceContext);
|
|
18838
|
-
this._serviceContext.registerService("vault", this._vault);
|
|
18839
|
-
this.initializeV2Services(serviceSession);
|
|
18840
19005
|
}
|
|
18841
19006
|
/**
|
|
18842
19007
|
* Initialize the v2 delegation system services.
|
|
@@ -18920,7 +19085,7 @@ var _TinyCloudNode = class _TinyCloudNode {
|
|
|
18920
19085
|
this._delegationManager = new DelegationManager({
|
|
18921
19086
|
hosts: [this.config.host],
|
|
18922
19087
|
session: serviceSession,
|
|
18923
|
-
invoke: this.
|
|
19088
|
+
invoke: this.invokeWithRuntimePermissions,
|
|
18924
19089
|
fetch: globalThis.fetch.bind(globalThis)
|
|
18925
19090
|
});
|
|
18926
19091
|
this._spaceService = new SpaceService({
|
|
@@ -18931,20 +19096,15 @@ var _TinyCloudNode = class _TinyCloudNode {
|
|
|
18931
19096
|
capabilityRegistry: this._capabilityRegistry,
|
|
18932
19097
|
userDid: this.did,
|
|
18933
19098
|
createKVService: (spaceId) => {
|
|
18934
|
-
|
|
19099
|
+
return this.createSpaceScopedKVService(spaceId);
|
|
19100
|
+
},
|
|
19101
|
+
createVaultService: (spaceId) => {
|
|
19102
|
+
const kvService = this.createSpaceScopedKVService(spaceId);
|
|
19103
|
+
const vaultService = this.createVaultService(spaceId, kvService);
|
|
18935
19104
|
if (this._serviceContext) {
|
|
18936
|
-
|
|
18937
|
-
invoke: this._serviceContext.invoke,
|
|
18938
|
-
fetch: this._serviceContext.fetch,
|
|
18939
|
-
hosts: this._serviceContext.hosts
|
|
18940
|
-
});
|
|
18941
|
-
const session = this._serviceContext.session;
|
|
18942
|
-
if (session) {
|
|
18943
|
-
spaceScopedContext.setSession({ ...session, spaceId });
|
|
18944
|
-
}
|
|
18945
|
-
kvService.initialize(spaceScopedContext);
|
|
19105
|
+
vaultService.initialize(this._serviceContext);
|
|
18946
19106
|
}
|
|
18947
|
-
return
|
|
19107
|
+
return vaultService;
|
|
18948
19108
|
},
|
|
18949
19109
|
// Enable space.delegations.create() via SIWE-based delegation
|
|
18950
19110
|
createDelegation: async (params) => {
|
|
@@ -19181,6 +19341,33 @@ var _TinyCloudNode = class _TinyCloudNode {
|
|
|
19181
19341
|
}
|
|
19182
19342
|
return this._vault;
|
|
19183
19343
|
}
|
|
19344
|
+
/**
|
|
19345
|
+
* App-facing secrets API backed by the `secrets` space vault.
|
|
19346
|
+
*/
|
|
19347
|
+
get secrets() {
|
|
19348
|
+
if (!this._spaceService) {
|
|
19349
|
+
throw new Error("Not signed in. Call signIn() first.");
|
|
19350
|
+
}
|
|
19351
|
+
if (!this._secrets) {
|
|
19352
|
+
this._secrets = new NodeSecretsService({
|
|
19353
|
+
getService: () => this.getBaseSecrets(),
|
|
19354
|
+
getManifest: () => this.manifest,
|
|
19355
|
+
grantPermissions: (additional) => this.grantRuntimePermissions(additional),
|
|
19356
|
+
canEscalate: () => this.signer !== void 0 && this.tc !== void 0,
|
|
19357
|
+
getUnlockSigner: () => this.signer ?? void 0
|
|
19358
|
+
});
|
|
19359
|
+
}
|
|
19360
|
+
return this._secrets;
|
|
19361
|
+
}
|
|
19362
|
+
getBaseSecrets() {
|
|
19363
|
+
if (!this._spaceService) {
|
|
19364
|
+
throw new Error("Not signed in. Call signIn() first.");
|
|
19365
|
+
}
|
|
19366
|
+
if (!this._baseSecrets) {
|
|
19367
|
+
this._baseSecrets = new SecretsService(() => this.space("secrets").vault);
|
|
19368
|
+
}
|
|
19369
|
+
return this._baseSecrets;
|
|
19370
|
+
}
|
|
19184
19371
|
/**
|
|
19185
19372
|
* Hooks write stream subscription API.
|
|
19186
19373
|
*/
|
|
@@ -19251,6 +19438,171 @@ var _TinyCloudNode = class _TinyCloudNode {
|
|
|
19251
19438
|
}
|
|
19252
19439
|
};
|
|
19253
19440
|
}
|
|
19441
|
+
/**
|
|
19442
|
+
* Check whether the current session or an approved runtime delegation covers
|
|
19443
|
+
* every requested permission.
|
|
19444
|
+
*/
|
|
19445
|
+
hasRuntimePermissions(permissions) {
|
|
19446
|
+
const session = this.auth?.tinyCloudSession;
|
|
19447
|
+
if (!session || !Array.isArray(permissions) || permissions.length === 0) {
|
|
19448
|
+
return false;
|
|
19449
|
+
}
|
|
19450
|
+
const expanded = this.expandPermissionEntries(permissions);
|
|
19451
|
+
if (this.sessionCoversPermissionEntries(session, expanded)) {
|
|
19452
|
+
return true;
|
|
19453
|
+
}
|
|
19454
|
+
return this.findRuntimeGrantsForPermissionEntries(expanded, session).length > 0;
|
|
19455
|
+
}
|
|
19456
|
+
/**
|
|
19457
|
+
* Return installed runtime permission delegations. When `permissions` is
|
|
19458
|
+
* provided, only delegations currently covering those permissions are
|
|
19459
|
+
* returned. Base-session manifest permissions are not represented here.
|
|
19460
|
+
*/
|
|
19461
|
+
getRuntimePermissionDelegations(permissions) {
|
|
19462
|
+
this.pruneExpiredRuntimePermissionGrants();
|
|
19463
|
+
if (permissions === void 0) {
|
|
19464
|
+
return this.runtimePermissionGrants.map((grant) => grant.delegation);
|
|
19465
|
+
}
|
|
19466
|
+
const session = this.auth?.tinyCloudSession;
|
|
19467
|
+
if (!session || !Array.isArray(permissions) || permissions.length === 0) {
|
|
19468
|
+
return [];
|
|
19469
|
+
}
|
|
19470
|
+
const expanded = this.expandPermissionEntries(permissions);
|
|
19471
|
+
return this.findRuntimeGrantsForPermissionEntries(expanded, session).map(
|
|
19472
|
+
(grant) => grant.delegation
|
|
19473
|
+
);
|
|
19474
|
+
}
|
|
19475
|
+
/**
|
|
19476
|
+
* Install a portable runtime permission delegation into this SDK instance so
|
|
19477
|
+
* matching service calls and downstream `delegateTo()` calls can use it.
|
|
19478
|
+
*/
|
|
19479
|
+
async useRuntimeDelegation(delegation) {
|
|
19480
|
+
const session = this.auth?.tinyCloudSession;
|
|
19481
|
+
if (!session) {
|
|
19482
|
+
throw new SessionExpiredError(/* @__PURE__ */ new Date(0));
|
|
19483
|
+
}
|
|
19484
|
+
if (delegation.expiry.getTime() <= Date.now()) {
|
|
19485
|
+
throw new SessionExpiredError(delegation.expiry);
|
|
19486
|
+
}
|
|
19487
|
+
const expectedDids = /* @__PURE__ */ new Set([session.verificationMethod, this.sessionDid]);
|
|
19488
|
+
if (!expectedDids.has(delegation.delegateDID)) {
|
|
19489
|
+
throw new Error(
|
|
19490
|
+
`Runtime delegation targets ${delegation.delegateDID} but this session key is ${session.verificationMethod}.`
|
|
19491
|
+
);
|
|
19492
|
+
}
|
|
19493
|
+
const targetHost = delegation.host ?? this.config.host;
|
|
19494
|
+
const activateResult = await activateSessionWithHost2(
|
|
19495
|
+
targetHost,
|
|
19496
|
+
delegation.delegationHeader
|
|
19497
|
+
);
|
|
19498
|
+
if (!activateResult.success) {
|
|
19499
|
+
throw new Error(
|
|
19500
|
+
`Failed to activate runtime permission delegation: ${activateResult.error}`
|
|
19501
|
+
);
|
|
19502
|
+
}
|
|
19503
|
+
this.runtimePermissionGrants = this.runtimePermissionGrants.filter(
|
|
19504
|
+
(grant) => grant.delegation.cid !== delegation.cid
|
|
19505
|
+
);
|
|
19506
|
+
this.runtimePermissionGrants.push(
|
|
19507
|
+
this.runtimeGrantFromDelegation(delegation, session)
|
|
19508
|
+
);
|
|
19509
|
+
}
|
|
19510
|
+
/**
|
|
19511
|
+
* Store additional permissions as narrow delegations to the current session
|
|
19512
|
+
* key. Future service invocations automatically use a stored delegation when
|
|
19513
|
+
* its `(space, service, path, action)` covers the request.
|
|
19514
|
+
*/
|
|
19515
|
+
async grantRuntimePermissions(permissions, options) {
|
|
19516
|
+
if (!Array.isArray(permissions) || permissions.length === 0) {
|
|
19517
|
+
throw new Error("grantRuntimePermissions requires a non-empty permissions array");
|
|
19518
|
+
}
|
|
19519
|
+
const session = this.auth?.tinyCloudSession;
|
|
19520
|
+
if (!session) {
|
|
19521
|
+
throw new SessionExpiredError(/* @__PURE__ */ new Date(0));
|
|
19522
|
+
}
|
|
19523
|
+
const sessionExpiry = extractSiweExpiration(session.siwe);
|
|
19524
|
+
if (sessionExpiry !== void 0) {
|
|
19525
|
+
const marginMs = _TinyCloudNode.SESSION_EXPIRY_SAFETY_MARGIN_MS;
|
|
19526
|
+
if (sessionExpiry.getTime() <= Date.now() + marginMs) {
|
|
19527
|
+
throw new SessionExpiredError(sessionExpiry);
|
|
19528
|
+
}
|
|
19529
|
+
}
|
|
19530
|
+
const expanded = this.expandPermissionEntries(permissions);
|
|
19531
|
+
if (this.sessionCoversPermissionEntries(session, expanded)) {
|
|
19532
|
+
return [];
|
|
19533
|
+
}
|
|
19534
|
+
const existingGrants = this.findRuntimeGrantsForPermissionEntries(expanded, session);
|
|
19535
|
+
if (existingGrants.length > 0) {
|
|
19536
|
+
return existingGrants.map((grant) => grant.delegation);
|
|
19537
|
+
}
|
|
19538
|
+
if (!this.signer) {
|
|
19539
|
+
throw new Error(
|
|
19540
|
+
"grantRuntimePermissions requires wallet mode with a signer or privateKey."
|
|
19541
|
+
);
|
|
19542
|
+
}
|
|
19543
|
+
const bySpace = /* @__PURE__ */ new Map();
|
|
19544
|
+
for (const entry of expanded) {
|
|
19545
|
+
const spaceId = this.resolvePermissionSpace(entry.space, session);
|
|
19546
|
+
const current = bySpace.get(spaceId) ?? [];
|
|
19547
|
+
current.push(entry);
|
|
19548
|
+
bySpace.set(spaceId, current);
|
|
19549
|
+
}
|
|
19550
|
+
const now = /* @__PURE__ */ new Date();
|
|
19551
|
+
const requestedExpiryMs = resolveExpiryMs(options?.expiry);
|
|
19552
|
+
let expiresAt = new Date(now.getTime() + requestedExpiryMs);
|
|
19553
|
+
if (sessionExpiry !== void 0 && sessionExpiry < expiresAt) {
|
|
19554
|
+
expiresAt = sessionExpiry;
|
|
19555
|
+
}
|
|
19556
|
+
const delegations = [];
|
|
19557
|
+
for (const [spaceId, entries] of bySpace) {
|
|
19558
|
+
const abilities = this.permissionsToAbilities(entries);
|
|
19559
|
+
const prepared = this.wasmBindings.prepareSession({
|
|
19560
|
+
abilities,
|
|
19561
|
+
address: this.wasmBindings.ensureEip55(session.address),
|
|
19562
|
+
chainId: session.chainId,
|
|
19563
|
+
domain: this.siweDomain,
|
|
19564
|
+
issuedAt: now.toISOString(),
|
|
19565
|
+
expirationTime: expiresAt.toISOString(),
|
|
19566
|
+
spaceId,
|
|
19567
|
+
jwk: session.jwk
|
|
19568
|
+
});
|
|
19569
|
+
const signature2 = await this.signer.signMessage(prepared.siwe);
|
|
19570
|
+
const delegatedSession = this.wasmBindings.completeSessionSetup({
|
|
19571
|
+
...prepared,
|
|
19572
|
+
signature: signature2
|
|
19573
|
+
});
|
|
19574
|
+
const activateResult = await activateSessionWithHost2(
|
|
19575
|
+
this.config.host,
|
|
19576
|
+
delegatedSession.delegationHeader
|
|
19577
|
+
);
|
|
19578
|
+
if (!activateResult.success) {
|
|
19579
|
+
throw new Error(
|
|
19580
|
+
`Failed to activate runtime permission delegation: ${activateResult.error}`
|
|
19581
|
+
);
|
|
19582
|
+
}
|
|
19583
|
+
const delegation = this.runtimeDelegationFromSession(
|
|
19584
|
+
delegatedSession,
|
|
19585
|
+
entries,
|
|
19586
|
+
spaceId,
|
|
19587
|
+
session,
|
|
19588
|
+
expiresAt
|
|
19589
|
+
);
|
|
19590
|
+
this.runtimePermissionGrants.push({
|
|
19591
|
+
session: {
|
|
19592
|
+
delegationHeader: delegatedSession.delegationHeader,
|
|
19593
|
+
delegationCid: delegatedSession.delegationCid,
|
|
19594
|
+
spaceId,
|
|
19595
|
+
verificationMethod: session.verificationMethod,
|
|
19596
|
+
jwk: session.jwk
|
|
19597
|
+
},
|
|
19598
|
+
delegation,
|
|
19599
|
+
operations: this.permissionOperations(entries, spaceId),
|
|
19600
|
+
expiresAt
|
|
19601
|
+
});
|
|
19602
|
+
delegations.push(delegation);
|
|
19603
|
+
}
|
|
19604
|
+
return delegations;
|
|
19605
|
+
}
|
|
19254
19606
|
/**
|
|
19255
19607
|
* Get the DelegationManager for delegation CRUD operations.
|
|
19256
19608
|
*
|
|
@@ -19319,6 +19671,12 @@ var _TinyCloudNode = class _TinyCloudNode {
|
|
|
19319
19671
|
get spaceService() {
|
|
19320
19672
|
return this.spaces;
|
|
19321
19673
|
}
|
|
19674
|
+
/**
|
|
19675
|
+
* Get a Space object by short name or full URI.
|
|
19676
|
+
*/
|
|
19677
|
+
space(nameOrUri) {
|
|
19678
|
+
return this.spaces.get(nameOrUri);
|
|
19679
|
+
}
|
|
19322
19680
|
/**
|
|
19323
19681
|
* Get the SharingService for creating and receiving v2 sharing links.
|
|
19324
19682
|
*
|
|
@@ -19433,7 +19791,7 @@ var _TinyCloudNode = class _TinyCloudNode {
|
|
|
19433
19791
|
if (this._serviceContext) {
|
|
19434
19792
|
const publicKV = new KVService2({ prefix: "" });
|
|
19435
19793
|
const publicContext = new ServiceContext2({
|
|
19436
|
-
invoke: this.
|
|
19794
|
+
invoke: this.invokeWithRuntimePermissions,
|
|
19437
19795
|
fetch: this._serviceContext.fetch,
|
|
19438
19796
|
hosts: this._serviceContext.hosts
|
|
19439
19797
|
});
|
|
@@ -19521,8 +19879,9 @@ var _TinyCloudNode = class _TinyCloudNode {
|
|
|
19521
19879
|
* Issue a delegation using the capability-chain flow.
|
|
19522
19880
|
*
|
|
19523
19881
|
* When every requested permission is a subset of the current
|
|
19524
|
-
* session's recap,
|
|
19525
|
-
*
|
|
19882
|
+
* session's recap, or of one installed runtime permission delegation,
|
|
19883
|
+
* the delegation is signed by the session key via WASM — no wallet
|
|
19884
|
+
* prompt. When at least one is NOT derivable, a
|
|
19526
19885
|
* {@link PermissionNotInManifestError} is raised (carrying the
|
|
19527
19886
|
* missing entries) so the caller can trigger an escalation flow
|
|
19528
19887
|
* (e.g. `TinyCloudWeb.requestPermissions`). Passing
|
|
@@ -19602,6 +19961,23 @@ var _TinyCloudNode = class _TinyCloudNode {
|
|
|
19602
19961
|
);
|
|
19603
19962
|
const { subset, missing } = isCapabilitySubset(expandedEntries, granted);
|
|
19604
19963
|
if (!subset) {
|
|
19964
|
+
const runtimeGrant = this.findGrantForOperations(
|
|
19965
|
+
this.permissionEntriesToOperations(expandedEntries, session)
|
|
19966
|
+
);
|
|
19967
|
+
if (runtimeGrant) {
|
|
19968
|
+
const marginMs = _TinyCloudNode.SESSION_EXPIRY_SAFETY_MARGIN_MS;
|
|
19969
|
+
if (runtimeGrant.expiresAt.getTime() <= Date.now() + marginMs) {
|
|
19970
|
+
throw new SessionExpiredError(runtimeGrant.expiresAt);
|
|
19971
|
+
}
|
|
19972
|
+
const runtimeExpiration = runtimeGrant.expiresAt < effectiveExpiration ? runtimeGrant.expiresAt : effectiveExpiration;
|
|
19973
|
+
const delegation2 = await this.createDelegationViaRuntimeGrant(
|
|
19974
|
+
did,
|
|
19975
|
+
expandedEntries,
|
|
19976
|
+
runtimeExpiration,
|
|
19977
|
+
runtimeGrant
|
|
19978
|
+
);
|
|
19979
|
+
return { delegation: delegation2, prompted: false };
|
|
19980
|
+
}
|
|
19605
19981
|
throw new PermissionNotInManifestError(missing, granted);
|
|
19606
19982
|
}
|
|
19607
19983
|
const delegation = await this.createDelegationViaWasmPath(
|
|
@@ -19746,6 +20122,41 @@ var _TinyCloudNode = class _TinyCloudNode {
|
|
|
19746
20122
|
host: this.config.host
|
|
19747
20123
|
};
|
|
19748
20124
|
}
|
|
20125
|
+
async createDelegationViaRuntimeGrant(did, entries, expirationTime, grant) {
|
|
20126
|
+
const result = this.createDelegationWrapper({
|
|
20127
|
+
session: grant.session,
|
|
20128
|
+
delegateDID: did,
|
|
20129
|
+
spaceId: grant.session.spaceId,
|
|
20130
|
+
abilities: this.permissionsToAbilities(entries),
|
|
20131
|
+
expirationSecs: Math.floor(expirationTime.getTime() / 1e3)
|
|
20132
|
+
});
|
|
20133
|
+
const primary = result.resources[0];
|
|
20134
|
+
const delegationHeader = { Authorization: result.delegation };
|
|
20135
|
+
const targetHost = grant.delegation.host ?? this.config.host;
|
|
20136
|
+
const activateResult = await activateSessionWithHost2(
|
|
20137
|
+
targetHost,
|
|
20138
|
+
delegationHeader
|
|
20139
|
+
);
|
|
20140
|
+
if (!activateResult.success) {
|
|
20141
|
+
throw new Error(
|
|
20142
|
+
`Failed to activate delegation with host: ${activateResult.error}`
|
|
20143
|
+
);
|
|
20144
|
+
}
|
|
20145
|
+
return {
|
|
20146
|
+
cid: result.cid,
|
|
20147
|
+
delegationHeader,
|
|
20148
|
+
spaceId: grant.session.spaceId,
|
|
20149
|
+
path: primary.path,
|
|
20150
|
+
actions: primary.actions,
|
|
20151
|
+
resources: result.resources,
|
|
20152
|
+
disableSubDelegation: false,
|
|
20153
|
+
expiry: result.expiry,
|
|
20154
|
+
delegateDID: did,
|
|
20155
|
+
ownerAddress: grant.delegation.ownerAddress,
|
|
20156
|
+
chainId: grant.delegation.chainId,
|
|
20157
|
+
host: targetHost
|
|
20158
|
+
};
|
|
20159
|
+
}
|
|
19749
20160
|
resolvePermissionSpace(space, session) {
|
|
19750
20161
|
if (space === void 0) {
|
|
19751
20162
|
return this.wasmBindings.makeSpaceId(
|
|
@@ -19762,6 +20173,223 @@ var _TinyCloudNode = class _TinyCloudNode {
|
|
|
19762
20173
|
}
|
|
19763
20174
|
return this.wasmBindings.makeSpaceId(session.address, session.chainId, space);
|
|
19764
20175
|
}
|
|
20176
|
+
expandPermissionEntries(permissions) {
|
|
20177
|
+
return permissions.map((entry) => ({
|
|
20178
|
+
...entry,
|
|
20179
|
+
actions: expandActionShortNames(entry.service, entry.actions)
|
|
20180
|
+
}));
|
|
20181
|
+
}
|
|
20182
|
+
shortServiceName(service) {
|
|
20183
|
+
const short = SERVICE_LONG_TO_SHORT[service];
|
|
20184
|
+
if (short === void 0) {
|
|
20185
|
+
throw new Error(
|
|
20186
|
+
`unknown service '${service}' \u2014 no short-form mapping`
|
|
20187
|
+
);
|
|
20188
|
+
}
|
|
20189
|
+
return short;
|
|
20190
|
+
}
|
|
20191
|
+
permissionsToAbilities(entries) {
|
|
20192
|
+
const abilities = {};
|
|
20193
|
+
for (const entry of entries) {
|
|
20194
|
+
const service = this.shortServiceName(entry.service);
|
|
20195
|
+
abilities[service] ?? (abilities[service] = {});
|
|
20196
|
+
const existing = abilities[service][entry.path] ?? [];
|
|
20197
|
+
const seen = new Set(existing);
|
|
20198
|
+
for (const action of entry.actions) {
|
|
20199
|
+
if (!seen.has(action)) {
|
|
20200
|
+
existing.push(action);
|
|
20201
|
+
seen.add(action);
|
|
20202
|
+
}
|
|
20203
|
+
}
|
|
20204
|
+
abilities[service][entry.path] = existing;
|
|
20205
|
+
}
|
|
20206
|
+
return abilities;
|
|
20207
|
+
}
|
|
20208
|
+
permissionOperations(entries, spaceId) {
|
|
20209
|
+
return entries.flatMap((entry) => {
|
|
20210
|
+
const service = this.shortServiceName(entry.service);
|
|
20211
|
+
return entry.actions.map((action) => ({
|
|
20212
|
+
spaceId,
|
|
20213
|
+
service,
|
|
20214
|
+
path: entry.path,
|
|
20215
|
+
action
|
|
20216
|
+
}));
|
|
20217
|
+
});
|
|
20218
|
+
}
|
|
20219
|
+
sessionCoversPermissionEntries(session, entries) {
|
|
20220
|
+
try {
|
|
20221
|
+
const granted = parseRecapCapabilities(
|
|
20222
|
+
(siwe) => this.wasmBindings.parseRecapFromSiwe(siwe),
|
|
20223
|
+
session.siwe
|
|
20224
|
+
);
|
|
20225
|
+
return isCapabilitySubset(entries, granted).subset;
|
|
20226
|
+
} catch {
|
|
20227
|
+
return false;
|
|
20228
|
+
}
|
|
20229
|
+
}
|
|
20230
|
+
permissionEntriesToOperations(entries, session) {
|
|
20231
|
+
return entries.flatMap((entry) => {
|
|
20232
|
+
const spaceId = this.resolvePermissionSpace(entry.space, session);
|
|
20233
|
+
const service = this.shortServiceName(entry.service);
|
|
20234
|
+
return entry.actions.map((action) => ({
|
|
20235
|
+
spaceId,
|
|
20236
|
+
service,
|
|
20237
|
+
path: entry.path,
|
|
20238
|
+
action
|
|
20239
|
+
}));
|
|
20240
|
+
});
|
|
20241
|
+
}
|
|
20242
|
+
findRuntimeGrantsForPermissionEntries(entries, session) {
|
|
20243
|
+
const grants = [];
|
|
20244
|
+
const operations = this.permissionEntriesToOperations(entries, session);
|
|
20245
|
+
if (operations.length === 0) {
|
|
20246
|
+
return grants;
|
|
20247
|
+
}
|
|
20248
|
+
for (const operation of operations) {
|
|
20249
|
+
const grant = this.findGrantForOperation(operation);
|
|
20250
|
+
if (!grant) {
|
|
20251
|
+
return [];
|
|
20252
|
+
}
|
|
20253
|
+
if (!grants.includes(grant)) {
|
|
20254
|
+
grants.push(grant);
|
|
20255
|
+
}
|
|
20256
|
+
}
|
|
20257
|
+
return grants;
|
|
20258
|
+
}
|
|
20259
|
+
runtimeDelegationFromSession(delegatedSession, entries, spaceId, session, expiresAt) {
|
|
20260
|
+
const resources = this.delegatedResourcesForEntries(entries, spaceId);
|
|
20261
|
+
const primary = resources[0];
|
|
20262
|
+
return {
|
|
20263
|
+
cid: delegatedSession.delegationCid,
|
|
20264
|
+
delegationHeader: delegatedSession.delegationHeader,
|
|
20265
|
+
spaceId,
|
|
20266
|
+
path: primary.path,
|
|
20267
|
+
actions: primary.actions,
|
|
20268
|
+
resources,
|
|
20269
|
+
disableSubDelegation: false,
|
|
20270
|
+
expiry: expiresAt,
|
|
20271
|
+
delegateDID: session.verificationMethod,
|
|
20272
|
+
ownerAddress: session.address,
|
|
20273
|
+
chainId: session.chainId,
|
|
20274
|
+
host: this.config.host
|
|
20275
|
+
};
|
|
20276
|
+
}
|
|
20277
|
+
runtimeGrantFromDelegation(delegation, session) {
|
|
20278
|
+
const operations = this.operationsFromDelegation(delegation);
|
|
20279
|
+
return {
|
|
20280
|
+
session: {
|
|
20281
|
+
delegationHeader: delegation.delegationHeader,
|
|
20282
|
+
delegationCid: delegation.cid,
|
|
20283
|
+
spaceId: delegation.spaceId,
|
|
20284
|
+
verificationMethod: session.verificationMethod,
|
|
20285
|
+
jwk: session.jwk
|
|
20286
|
+
},
|
|
20287
|
+
delegation,
|
|
20288
|
+
operations,
|
|
20289
|
+
expiresAt: delegation.expiry
|
|
20290
|
+
};
|
|
20291
|
+
}
|
|
20292
|
+
delegatedResourcesForEntries(entries, spaceId) {
|
|
20293
|
+
return entries.map((entry) => ({
|
|
20294
|
+
service: this.shortServiceName(entry.service),
|
|
20295
|
+
space: spaceId,
|
|
20296
|
+
path: entry.path,
|
|
20297
|
+
actions: [...entry.actions]
|
|
20298
|
+
}));
|
|
20299
|
+
}
|
|
20300
|
+
operationsFromDelegation(delegation) {
|
|
20301
|
+
const resources = delegation.resources !== void 0 && delegation.resources.length > 0 ? delegation.resources : this.flatDelegationResources(delegation);
|
|
20302
|
+
return resources.flatMap(
|
|
20303
|
+
(resource) => resource.actions.map((action) => ({
|
|
20304
|
+
spaceId: resource.space,
|
|
20305
|
+
service: this.invocationServiceName(resource.service),
|
|
20306
|
+
path: resource.path,
|
|
20307
|
+
action
|
|
20308
|
+
}))
|
|
20309
|
+
);
|
|
20310
|
+
}
|
|
20311
|
+
flatDelegationResources(delegation) {
|
|
20312
|
+
const byService = /* @__PURE__ */ new Map();
|
|
20313
|
+
for (const action of delegation.actions) {
|
|
20314
|
+
const service = this.shortServiceName(action.split("/")[0]);
|
|
20315
|
+
const actions = byService.get(service) ?? [];
|
|
20316
|
+
actions.push(action);
|
|
20317
|
+
byService.set(service, actions);
|
|
20318
|
+
}
|
|
20319
|
+
return [...byService.entries()].map(([service, actions]) => ({
|
|
20320
|
+
service,
|
|
20321
|
+
space: delegation.spaceId,
|
|
20322
|
+
path: delegation.path,
|
|
20323
|
+
actions
|
|
20324
|
+
}));
|
|
20325
|
+
}
|
|
20326
|
+
selectInvocationSession(fallback, service, path, action) {
|
|
20327
|
+
const grant = this.findGrantForOperation({
|
|
20328
|
+
spaceId: fallback.spaceId,
|
|
20329
|
+
service: this.invocationServiceName(service),
|
|
20330
|
+
path,
|
|
20331
|
+
action
|
|
20332
|
+
});
|
|
20333
|
+
return grant?.session ?? fallback;
|
|
20334
|
+
}
|
|
20335
|
+
findGrantForOperations(operations) {
|
|
20336
|
+
if (operations.length === 0) {
|
|
20337
|
+
return void 0;
|
|
20338
|
+
}
|
|
20339
|
+
this.pruneExpiredRuntimePermissionGrants();
|
|
20340
|
+
return this.runtimePermissionGrants.find((grant) => {
|
|
20341
|
+
return operations.every(
|
|
20342
|
+
(operation) => grant.operations.some(
|
|
20343
|
+
(granted) => this.operationCovers(granted, operation)
|
|
20344
|
+
)
|
|
20345
|
+
);
|
|
20346
|
+
});
|
|
20347
|
+
}
|
|
20348
|
+
findGrantForOperation(operation) {
|
|
20349
|
+
return this.findGrantForOperations([operation]);
|
|
20350
|
+
}
|
|
20351
|
+
pruneExpiredRuntimePermissionGrants() {
|
|
20352
|
+
const now = Date.now();
|
|
20353
|
+
this.runtimePermissionGrants = this.runtimePermissionGrants.filter(
|
|
20354
|
+
(grant) => grant.expiresAt.getTime() > now
|
|
20355
|
+
);
|
|
20356
|
+
}
|
|
20357
|
+
operationCovers(granted, requested) {
|
|
20358
|
+
return granted.spaceId === requested.spaceId && granted.service === requested.service && this.actionContains(granted.action, requested.action) && this.pathContains(granted.path, requested.path);
|
|
20359
|
+
}
|
|
20360
|
+
actionContains(grantedAction, requestedAction) {
|
|
20361
|
+
if (grantedAction === requestedAction) {
|
|
20362
|
+
return true;
|
|
20363
|
+
}
|
|
20364
|
+
if (grantedAction.endsWith("/*")) {
|
|
20365
|
+
const prefix = grantedAction.slice(0, -2);
|
|
20366
|
+
return requestedAction.startsWith(`${prefix}/`);
|
|
20367
|
+
}
|
|
20368
|
+
return false;
|
|
20369
|
+
}
|
|
20370
|
+
invocationServiceName(service) {
|
|
20371
|
+
return service.startsWith("tinycloud.") ? this.shortServiceName(service) : service;
|
|
20372
|
+
}
|
|
20373
|
+
pathContains(grantedPath, requestedPath) {
|
|
20374
|
+
if (grantedPath === "" || grantedPath === "/") {
|
|
20375
|
+
return true;
|
|
20376
|
+
}
|
|
20377
|
+
if (grantedPath.endsWith("/**")) {
|
|
20378
|
+
return requestedPath.startsWith(grantedPath.slice(0, -3));
|
|
20379
|
+
}
|
|
20380
|
+
if (grantedPath.endsWith("/*")) {
|
|
20381
|
+
const prefix = grantedPath.slice(0, -2);
|
|
20382
|
+
if (!requestedPath.startsWith(prefix)) {
|
|
20383
|
+
return false;
|
|
20384
|
+
}
|
|
20385
|
+
const remainder = requestedPath.slice(prefix.length);
|
|
20386
|
+
return !remainder.includes("/") || remainder === "/";
|
|
20387
|
+
}
|
|
20388
|
+
if (grantedPath.endsWith("/")) {
|
|
20389
|
+
return requestedPath.startsWith(grantedPath);
|
|
20390
|
+
}
|
|
20391
|
+
return grantedPath === requestedPath;
|
|
20392
|
+
}
|
|
19765
20393
|
/**
|
|
19766
20394
|
* Issue a delegation via the legacy wallet-signed SIWE path for a single
|
|
19767
20395
|
* {@link PermissionEntry}. Shares the implementation with the public
|
|
@@ -20287,7 +20915,7 @@ import {
|
|
|
20287
20915
|
SessionExpiredError as SessionExpiredError2,
|
|
20288
20916
|
ManifestValidationError,
|
|
20289
20917
|
composeManifestRequest as composeManifestRequest2,
|
|
20290
|
-
resolveManifest,
|
|
20918
|
+
resolveManifest as resolveManifest2,
|
|
20291
20919
|
validateManifest,
|
|
20292
20920
|
loadManifest,
|
|
20293
20921
|
isCapabilitySubset as isCapabilitySubset2,
|
|
@@ -20324,7 +20952,8 @@ import {
|
|
|
20324
20952
|
DataVaultService as DataVaultService2,
|
|
20325
20953
|
VaultHeaders,
|
|
20326
20954
|
VaultPublicSpaceKVActions,
|
|
20327
|
-
createVaultCrypto as createVaultCrypto2
|
|
20955
|
+
createVaultCrypto as createVaultCrypto2,
|
|
20956
|
+
SecretsService as SecretsService2
|
|
20328
20957
|
} from "@tinycloud/sdk-core";
|
|
20329
20958
|
import { HooksService as HooksService3 } from "@tinycloud/sdk-core";
|
|
20330
20959
|
import {
|
|
@@ -20383,6 +21012,7 @@ export {
|
|
|
20383
21012
|
ProtocolMismatchError,
|
|
20384
21013
|
SQLAction,
|
|
20385
21014
|
SQLService3 as SQLService,
|
|
21015
|
+
SecretsService2 as SecretsService,
|
|
20386
21016
|
ServiceContext3 as ServiceContext,
|
|
20387
21017
|
SessionExpiredError2 as SessionExpiredError,
|
|
20388
21018
|
SharingService2 as SharingService,
|
|
@@ -20414,7 +21044,7 @@ export {
|
|
|
20414
21044
|
makePublicSpaceId2 as makePublicSpaceId,
|
|
20415
21045
|
parseExpiry2 as parseExpiry,
|
|
20416
21046
|
parseSpaceUri,
|
|
20417
|
-
resolveManifest,
|
|
21047
|
+
resolveManifest2 as resolveManifest,
|
|
20418
21048
|
resourceCapabilitiesToSpaceAbilitiesMap2 as resourceCapabilitiesToSpaceAbilitiesMap,
|
|
20419
21049
|
serializeDelegation,
|
|
20420
21050
|
validateManifest
|