@tinycloud/node-sdk 2.2.0-beta.7 → 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-C3s0bgRe.d.cts → core-DcJ27GsA.d.cts} +58 -4
- package/dist/{core-C3s0bgRe.d.ts → core-DcJ27GsA.d.ts} +58 -4
- package/dist/core.cjs +482 -49
- package/dist/core.cjs.map +1 -1
- package/dist/core.d.cts +1 -1
- package/dist/core.d.ts +1 -1
- package/dist/core.js +482 -49
- package/dist/core.js.map +1 -1
- package/dist/index.cjs +482 -49
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +1 -1
- package/dist/index.d.ts +1 -1
- package/dist/index.js +482 -49
- package/dist/index.js.map +1 -1
- package/package.json +1 -1
package/dist/core.d.cts
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
1
|
export { ACCOUNT_REGISTRY_PATH, ACCOUNT_REGISTRY_SPACE, AutoApproveSpaceCreationHandler, AutoRejectStrategy, AutoSignStrategy, BatchOptions, BatchResponse, CallbackStrategy, CapabilityEntry, CapabilityKeyRegistry, CapabilityKeyRegistryErrorCode, CapabilityKeyRegistryErrorCodes, ClientSession, ColumnInfo, ComposeManifestOptions, ComposedManifestRequest, CreateDelegationParams, DEFAULT_MANIFEST_SPACE, DEFAULT_MANIFEST_VERSION, DataVaultConfig, DataVaultService, DatabaseHandle, Delegation, DelegationChain, DelegationChainV2, DelegationDirection, DelegationError, DelegationErrorCode, DelegationErrorCodes, DelegationFilters, DelegationManager, DelegationManagerConfig, DelegationRecord, DelegationResult, DuckDbAction, DuckDbActionType, DuckDbBatchOptions, DuckDbBatchResponse, DuckDbDatabaseHandle, DuckDbExecuteOptions, DuckDbExecuteResponse, DuckDbOptions, DuckDbQueryOptions, DuckDbQueryResponse, DuckDbService, DuckDbServiceConfig, DuckDbStatement, DuckDbValue, EncodedShareData, ExecuteOptions, ExecuteResponse, Extension, FetchFunction, GenerateShareParams, ICapabilityKeyRegistry, IDataVaultService, IDatabaseHandle, IDuckDbDatabaseHandle, IDuckDbService, IENSResolver, IKVService, INotificationHandler, IPrefixedKVService, ISQLService, ISecretsService, ISessionManager, ISessionStorage, ISharingService, ISigner, ISpace, ISpaceCreationHandler, ISpaceScopedDelegations, ISpaceScopedSharing, ISpaceService, IUserAuthorization, IWasmBindings, IngestOptions, InvokeFunction, JWK, KVResponse, KVService, KVServiceConfig, KeyInfo, KeyProvider, KeyType, Manifest, ManifestDefaults, ManifestRegistryRecord, ManifestSecretActions, ManifestValidationError, PermissionEntry, PermissionNotInManifestError, PersistedSessionData, PrefixedKVService, ProtocolMismatchError, QueryOptions, QueryResponse, ReceiveOptions, ResolvedCapabilities, ResolvedDelegate, ResourceCapability, SQLAction, SQLActionType, SQLService, SQLServiceConfig, SchemaInfo, SecretPayload, SecretsError, SecretsService, ServiceContext, ServiceContextConfig, ServiceSession, SessionExpiredError, ShareAccess, ShareLink, ShareLinkData, ShareSchema, SharingService, SharingServiceConfig, SignCallback, SignInOptions, SignRequest, SignResponse, SilentNotificationHandler, Space, SpaceAbilitiesMap, SpaceConfig, SpaceCreationContext, SpaceErrorCode, SpaceErrorCodes, SpaceInfo, SpaceOwnership, SpaceService, SpaceServiceConfig, SqlStatement, SqlValue, StoredDelegationChain, TableInfo, TinyCloud, TinyCloudConfig, TinyCloudSession, UnsupportedFeatureError, VaultCrypto, VaultEntry, VaultError, VaultGetOptions, VaultGrantOptions, VaultHeaders, VaultListOptions, VaultPublicSpaceKVActions, VaultPutOptions, VersionCheckError, ViewInfo, WasmVaultFunctions, buildSpaceUri, checkNodeInfo, composeManifestRequest, createCapabilityKeyRegistry, createSharingService, createSpaceService, createVaultCrypto, defaultSpaceCreationHandler, expandActionShortNames, isCapabilitySubset, loadManifest, makePublicSpaceId, parseExpiry, parseSpaceUri, resolveManifest, resourceCapabilitiesToSpaceAbilitiesMap, validateManifest } from '@tinycloud/sdk-core';
|
|
2
|
-
export { D as DelegateToOptions, a as DelegateToResult, b as DelegatedAccess, F as FileSessionStorage, M as MemorySessionStorage, N as NodeEventEmitterStrategy, c as NodeUserAuthorization, d as NodeUserAuthorizationConfig, P as PortableDelegation, S as SignStrategy, T as TinyCloudNode,
|
|
2
|
+
export { D as DelegateToOptions, a as DelegateToResult, b as DelegatedAccess, F as FileSessionStorage, M as MemorySessionStorage, N as NodeEventEmitterStrategy, c as NodeUserAuthorization, d as NodeUserAuthorizationConfig, P as PortableDelegation, e as RuntimePermissionGrantOptions, S as SignStrategy, T as TinyCloudNode, f as TinyCloudNodeConfig, W as WasmKeyProvider, g as WasmKeyProviderConfig, h as createWasmKeyProvider, i as defaultSignStrategy, j as deserializeDelegation, s as serializeDelegation } from './core-DcJ27GsA.cjs';
|
|
3
3
|
import 'events';
|
|
4
4
|
import '@tinycloud/sdk-services';
|
package/dist/core.d.ts
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
1
|
export { ACCOUNT_REGISTRY_PATH, ACCOUNT_REGISTRY_SPACE, AutoApproveSpaceCreationHandler, AutoRejectStrategy, AutoSignStrategy, BatchOptions, BatchResponse, CallbackStrategy, CapabilityEntry, CapabilityKeyRegistry, CapabilityKeyRegistryErrorCode, CapabilityKeyRegistryErrorCodes, ClientSession, ColumnInfo, ComposeManifestOptions, ComposedManifestRequest, CreateDelegationParams, DEFAULT_MANIFEST_SPACE, DEFAULT_MANIFEST_VERSION, DataVaultConfig, DataVaultService, DatabaseHandle, Delegation, DelegationChain, DelegationChainV2, DelegationDirection, DelegationError, DelegationErrorCode, DelegationErrorCodes, DelegationFilters, DelegationManager, DelegationManagerConfig, DelegationRecord, DelegationResult, DuckDbAction, DuckDbActionType, DuckDbBatchOptions, DuckDbBatchResponse, DuckDbDatabaseHandle, DuckDbExecuteOptions, DuckDbExecuteResponse, DuckDbOptions, DuckDbQueryOptions, DuckDbQueryResponse, DuckDbService, DuckDbServiceConfig, DuckDbStatement, DuckDbValue, EncodedShareData, ExecuteOptions, ExecuteResponse, Extension, FetchFunction, GenerateShareParams, ICapabilityKeyRegistry, IDataVaultService, IDatabaseHandle, IDuckDbDatabaseHandle, IDuckDbService, IENSResolver, IKVService, INotificationHandler, IPrefixedKVService, ISQLService, ISecretsService, ISessionManager, ISessionStorage, ISharingService, ISigner, ISpace, ISpaceCreationHandler, ISpaceScopedDelegations, ISpaceScopedSharing, ISpaceService, IUserAuthorization, IWasmBindings, IngestOptions, InvokeFunction, JWK, KVResponse, KVService, KVServiceConfig, KeyInfo, KeyProvider, KeyType, Manifest, ManifestDefaults, ManifestRegistryRecord, ManifestSecretActions, ManifestValidationError, PermissionEntry, PermissionNotInManifestError, PersistedSessionData, PrefixedKVService, ProtocolMismatchError, QueryOptions, QueryResponse, ReceiveOptions, ResolvedCapabilities, ResolvedDelegate, ResourceCapability, SQLAction, SQLActionType, SQLService, SQLServiceConfig, SchemaInfo, SecretPayload, SecretsError, SecretsService, ServiceContext, ServiceContextConfig, ServiceSession, SessionExpiredError, ShareAccess, ShareLink, ShareLinkData, ShareSchema, SharingService, SharingServiceConfig, SignCallback, SignInOptions, SignRequest, SignResponse, SilentNotificationHandler, Space, SpaceAbilitiesMap, SpaceConfig, SpaceCreationContext, SpaceErrorCode, SpaceErrorCodes, SpaceInfo, SpaceOwnership, SpaceService, SpaceServiceConfig, SqlStatement, SqlValue, StoredDelegationChain, TableInfo, TinyCloud, TinyCloudConfig, TinyCloudSession, UnsupportedFeatureError, VaultCrypto, VaultEntry, VaultError, VaultGetOptions, VaultGrantOptions, VaultHeaders, VaultListOptions, VaultPublicSpaceKVActions, VaultPutOptions, VersionCheckError, ViewInfo, WasmVaultFunctions, buildSpaceUri, checkNodeInfo, composeManifestRequest, createCapabilityKeyRegistry, createSharingService, createSpaceService, createVaultCrypto, defaultSpaceCreationHandler, expandActionShortNames, isCapabilitySubset, loadManifest, makePublicSpaceId, parseExpiry, parseSpaceUri, resolveManifest, resourceCapabilitiesToSpaceAbilitiesMap, validateManifest } from '@tinycloud/sdk-core';
|
|
2
|
-
export { D as DelegateToOptions, a as DelegateToResult, b as DelegatedAccess, F as FileSessionStorage, M as MemorySessionStorage, N as NodeEventEmitterStrategy, c as NodeUserAuthorization, d as NodeUserAuthorizationConfig, P as PortableDelegation, S as SignStrategy, T as TinyCloudNode,
|
|
2
|
+
export { D as DelegateToOptions, a as DelegateToResult, b as DelegatedAccess, F as FileSessionStorage, M as MemorySessionStorage, N as NodeEventEmitterStrategy, c as NodeUserAuthorization, d as NodeUserAuthorizationConfig, P as PortableDelegation, e as RuntimePermissionGrantOptions, S as SignStrategy, T as TinyCloudNode, f as TinyCloudNodeConfig, W as WasmKeyProvider, g as WasmKeyProviderConfig, h as createWasmKeyProvider, i as defaultSignStrategy, j as deserializeDelegation, s as serializeDelegation } from './core-DcJ27GsA.js';
|
|
3
3
|
import 'events';
|
|
4
4
|
import '@tinycloud/sdk-services';
|
package/dist/core.js
CHANGED
|
@@ -1267,22 +1267,6 @@ function secretPermissionEntries(name, action) {
|
|
|
1267
1267
|
function isSecretsSpace(space) {
|
|
1268
1268
|
return space === SECRETS_SPACE || space.endsWith(`:${SECRETS_SPACE}`);
|
|
1269
1269
|
}
|
|
1270
|
-
function composeEscalatedManifest(manifest, additional) {
|
|
1271
|
-
if (Array.isArray(manifest)) {
|
|
1272
|
-
const [primary, ...rest] = manifest;
|
|
1273
|
-
return [
|
|
1274
|
-
{
|
|
1275
|
-
...primary,
|
|
1276
|
-
permissions: [...primary.permissions ?? [], ...additional]
|
|
1277
|
-
},
|
|
1278
|
-
...rest
|
|
1279
|
-
];
|
|
1280
|
-
}
|
|
1281
|
-
return {
|
|
1282
|
-
...manifest,
|
|
1283
|
-
permissions: [...manifest.permissions ?? [], ...additional]
|
|
1284
|
-
};
|
|
1285
|
-
}
|
|
1286
1270
|
var NodeSecretsService = class {
|
|
1287
1271
|
constructor(config) {
|
|
1288
1272
|
this.config = config;
|
|
@@ -1295,10 +1279,11 @@ var NodeSecretsService = class {
|
|
|
1295
1279
|
return this.service.isUnlocked;
|
|
1296
1280
|
}
|
|
1297
1281
|
async unlock(signer) {
|
|
1298
|
-
|
|
1299
|
-
|
|
1282
|
+
const effectiveSigner = signer ?? this.config.getUnlockSigner?.();
|
|
1283
|
+
if (effectiveSigner !== void 0) {
|
|
1284
|
+
this.unlockSigner = effectiveSigner;
|
|
1300
1285
|
}
|
|
1301
|
-
const result = await this.service.unlock(
|
|
1286
|
+
const result = await this.service.unlock(effectiveSigner);
|
|
1302
1287
|
if (result.ok) {
|
|
1303
1288
|
this.shouldRestoreUnlock = true;
|
|
1304
1289
|
}
|
|
@@ -1343,21 +1328,8 @@ var NodeSecretsService = class {
|
|
|
1343
1328
|
`Cannot autosign ${actionUrn(action)} for ${name}; TinyCloudNode needs wallet mode with a signer or privateKey.`
|
|
1344
1329
|
);
|
|
1345
1330
|
}
|
|
1346
|
-
const manifest = this.config.getManifest();
|
|
1347
|
-
if (manifest === void 0) {
|
|
1348
|
-
return secretsError(
|
|
1349
|
-
ErrorCodes.PERMISSION_DENIED,
|
|
1350
|
-
`Cannot autosign ${actionUrn(action)} for ${name}; set a manifest before mutating secrets.`
|
|
1351
|
-
);
|
|
1352
|
-
}
|
|
1353
1331
|
try {
|
|
1354
|
-
this.config.
|
|
1355
|
-
composeEscalatedManifest(
|
|
1356
|
-
manifest,
|
|
1357
|
-
secretPermissionEntries(name, action)
|
|
1358
|
-
)
|
|
1359
|
-
);
|
|
1360
|
-
await this.config.signIn();
|
|
1332
|
+
await this.config.grantPermissions(secretPermissionEntries(name, action));
|
|
1361
1333
|
return this.restoreUnlockAfterEscalation();
|
|
1362
1334
|
} catch (error) {
|
|
1363
1335
|
return secretsError(
|
|
@@ -1422,6 +1394,30 @@ var _TinyCloudNode = class _TinyCloudNode {
|
|
|
1422
1394
|
this.auth = null;
|
|
1423
1395
|
this.tc = null;
|
|
1424
1396
|
this._chainId = 1;
|
|
1397
|
+
this.runtimePermissionGrants = [];
|
|
1398
|
+
this.invokeWithRuntimePermissions = (session, service, path, action, facts) => {
|
|
1399
|
+
return this.wasmBindings.invoke(
|
|
1400
|
+
this.selectInvocationSession(session, service, path, action),
|
|
1401
|
+
service,
|
|
1402
|
+
path,
|
|
1403
|
+
action,
|
|
1404
|
+
facts
|
|
1405
|
+
);
|
|
1406
|
+
};
|
|
1407
|
+
this.invokeAnyWithRuntimePermissions = (session, entries, facts) => {
|
|
1408
|
+
if (!this.wasmBindings.invokeAny) {
|
|
1409
|
+
throw new Error("WASM binding does not support invokeAny");
|
|
1410
|
+
}
|
|
1411
|
+
const grant = this.findGrantForOperations(
|
|
1412
|
+
entries.map((entry) => ({
|
|
1413
|
+
spaceId: entry.spaceId,
|
|
1414
|
+
service: this.invocationServiceName(entry.service),
|
|
1415
|
+
path: entry.path,
|
|
1416
|
+
action: entry.action
|
|
1417
|
+
}))
|
|
1418
|
+
);
|
|
1419
|
+
return this.wasmBindings.invokeAny(grant?.session ?? session, entries, facts);
|
|
1420
|
+
};
|
|
1425
1421
|
this.explicitHost = config.host;
|
|
1426
1422
|
this.config = {
|
|
1427
1423
|
...config,
|
|
@@ -1457,7 +1453,7 @@ var _TinyCloudNode = class _TinyCloudNode {
|
|
|
1457
1453
|
this._sharingService = new SharingService({
|
|
1458
1454
|
hosts: [this.config.host],
|
|
1459
1455
|
// session: undefined - not needed for receive()
|
|
1460
|
-
invoke: this.
|
|
1456
|
+
invoke: this.invokeWithRuntimePermissions,
|
|
1461
1457
|
fetch: globalThis.fetch.bind(globalThis),
|
|
1462
1458
|
keyProvider: this._keyProvider,
|
|
1463
1459
|
registry: this._capabilityRegistry,
|
|
@@ -1525,7 +1521,7 @@ var _TinyCloudNode = class _TinyCloudNode {
|
|
|
1525
1521
|
includeAccountRegistryPermissions: config.includeAccountRegistryPermissions
|
|
1526
1522
|
});
|
|
1527
1523
|
this.tc = new TinyCloud(this.auth, {
|
|
1528
|
-
invokeAny: this.
|
|
1524
|
+
invokeAny: this.invokeAnyWithRuntimePermissions
|
|
1529
1525
|
});
|
|
1530
1526
|
}
|
|
1531
1527
|
syncResolvedHostFromAuth() {
|
|
@@ -1650,6 +1646,7 @@ var _TinyCloudNode = class _TinyCloudNode {
|
|
|
1650
1646
|
this._secrets = void 0;
|
|
1651
1647
|
this._spaceService = void 0;
|
|
1652
1648
|
this._serviceContext = void 0;
|
|
1649
|
+
this.runtimePermissionGrants = [];
|
|
1653
1650
|
await this.tc.signIn(options);
|
|
1654
1651
|
this.syncResolvedHostFromAuth();
|
|
1655
1652
|
this.initializeServices();
|
|
@@ -1739,6 +1736,7 @@ var _TinyCloudNode = class _TinyCloudNode {
|
|
|
1739
1736
|
this._secrets = void 0;
|
|
1740
1737
|
this._spaceService = void 0;
|
|
1741
1738
|
this._serviceContext = void 0;
|
|
1739
|
+
this.runtimePermissionGrants = [];
|
|
1742
1740
|
if (sessionData.address) {
|
|
1743
1741
|
this._address = sessionData.address;
|
|
1744
1742
|
}
|
|
@@ -1746,8 +1744,8 @@ var _TinyCloudNode = class _TinyCloudNode {
|
|
|
1746
1744
|
this._chainId = sessionData.chainId;
|
|
1747
1745
|
}
|
|
1748
1746
|
this._serviceContext = new ServiceContext2({
|
|
1749
|
-
invoke: this.
|
|
1750
|
-
invokeAny: this.
|
|
1747
|
+
invoke: this.invokeWithRuntimePermissions,
|
|
1748
|
+
invokeAny: this.invokeAnyWithRuntimePermissions,
|
|
1751
1749
|
fetch: globalThis.fetch.bind(globalThis),
|
|
1752
1750
|
hosts: [this.config.host]
|
|
1753
1751
|
});
|
|
@@ -1833,7 +1831,7 @@ var _TinyCloudNode = class _TinyCloudNode {
|
|
|
1833
1831
|
includeAccountRegistryPermissions: this.config.includeAccountRegistryPermissions
|
|
1834
1832
|
});
|
|
1835
1833
|
this.tc = new TinyCloud(this.auth, {
|
|
1836
|
-
invokeAny: this.
|
|
1834
|
+
invokeAny: this.invokeAnyWithRuntimePermissions
|
|
1837
1835
|
});
|
|
1838
1836
|
this.config.prefix = prefix;
|
|
1839
1837
|
}
|
|
@@ -1877,7 +1875,7 @@ var _TinyCloudNode = class _TinyCloudNode {
|
|
|
1877
1875
|
includeAccountRegistryPermissions: this.config.includeAccountRegistryPermissions
|
|
1878
1876
|
});
|
|
1879
1877
|
this.tc = new TinyCloud(this.auth, {
|
|
1880
|
-
invokeAny: this.
|
|
1878
|
+
invokeAny: this.invokeAnyWithRuntimePermissions
|
|
1881
1879
|
});
|
|
1882
1880
|
this.config.prefix = prefix;
|
|
1883
1881
|
}
|
|
@@ -1890,10 +1888,10 @@ var _TinyCloudNode = class _TinyCloudNode {
|
|
|
1890
1888
|
if (!session) {
|
|
1891
1889
|
return;
|
|
1892
1890
|
}
|
|
1893
|
-
this.tc.initializeServices(this.
|
|
1891
|
+
this.tc.initializeServices(this.invokeWithRuntimePermissions, [this.config.host]);
|
|
1894
1892
|
this._serviceContext = new ServiceContext2({
|
|
1895
|
-
invoke: this.
|
|
1896
|
-
invokeAny: this.
|
|
1893
|
+
invoke: this.invokeWithRuntimePermissions,
|
|
1894
|
+
invokeAny: this.invokeAnyWithRuntimePermissions,
|
|
1897
1895
|
fetch: globalThis.fetch.bind(globalThis),
|
|
1898
1896
|
hosts: [this.config.host]
|
|
1899
1897
|
});
|
|
@@ -2063,7 +2061,7 @@ var _TinyCloudNode = class _TinyCloudNode {
|
|
|
2063
2061
|
this._delegationManager = new DelegationManager({
|
|
2064
2062
|
hosts: [this.config.host],
|
|
2065
2063
|
session: serviceSession,
|
|
2066
|
-
invoke: this.
|
|
2064
|
+
invoke: this.invokeWithRuntimePermissions,
|
|
2067
2065
|
fetch: globalThis.fetch.bind(globalThis)
|
|
2068
2066
|
});
|
|
2069
2067
|
this._spaceService = new SpaceService({
|
|
@@ -2330,9 +2328,9 @@ var _TinyCloudNode = class _TinyCloudNode {
|
|
|
2330
2328
|
this._secrets = new NodeSecretsService({
|
|
2331
2329
|
getService: () => this.getBaseSecrets(),
|
|
2332
2330
|
getManifest: () => this.manifest,
|
|
2333
|
-
|
|
2334
|
-
|
|
2335
|
-
|
|
2331
|
+
grantPermissions: (additional) => this.grantRuntimePermissions(additional),
|
|
2332
|
+
canEscalate: () => this.signer !== void 0 && this.tc !== void 0,
|
|
2333
|
+
getUnlockSigner: () => this.signer ?? void 0
|
|
2336
2334
|
});
|
|
2337
2335
|
}
|
|
2338
2336
|
return this._secrets;
|
|
@@ -2416,6 +2414,171 @@ var _TinyCloudNode = class _TinyCloudNode {
|
|
|
2416
2414
|
}
|
|
2417
2415
|
};
|
|
2418
2416
|
}
|
|
2417
|
+
/**
|
|
2418
|
+
* Check whether the current session or an approved runtime delegation covers
|
|
2419
|
+
* every requested permission.
|
|
2420
|
+
*/
|
|
2421
|
+
hasRuntimePermissions(permissions) {
|
|
2422
|
+
const session = this.auth?.tinyCloudSession;
|
|
2423
|
+
if (!session || !Array.isArray(permissions) || permissions.length === 0) {
|
|
2424
|
+
return false;
|
|
2425
|
+
}
|
|
2426
|
+
const expanded = this.expandPermissionEntries(permissions);
|
|
2427
|
+
if (this.sessionCoversPermissionEntries(session, expanded)) {
|
|
2428
|
+
return true;
|
|
2429
|
+
}
|
|
2430
|
+
return this.findRuntimeGrantsForPermissionEntries(expanded, session).length > 0;
|
|
2431
|
+
}
|
|
2432
|
+
/**
|
|
2433
|
+
* Return installed runtime permission delegations. When `permissions` is
|
|
2434
|
+
* provided, only delegations currently covering those permissions are
|
|
2435
|
+
* returned. Base-session manifest permissions are not represented here.
|
|
2436
|
+
*/
|
|
2437
|
+
getRuntimePermissionDelegations(permissions) {
|
|
2438
|
+
this.pruneExpiredRuntimePermissionGrants();
|
|
2439
|
+
if (permissions === void 0) {
|
|
2440
|
+
return this.runtimePermissionGrants.map((grant) => grant.delegation);
|
|
2441
|
+
}
|
|
2442
|
+
const session = this.auth?.tinyCloudSession;
|
|
2443
|
+
if (!session || !Array.isArray(permissions) || permissions.length === 0) {
|
|
2444
|
+
return [];
|
|
2445
|
+
}
|
|
2446
|
+
const expanded = this.expandPermissionEntries(permissions);
|
|
2447
|
+
return this.findRuntimeGrantsForPermissionEntries(expanded, session).map(
|
|
2448
|
+
(grant) => grant.delegation
|
|
2449
|
+
);
|
|
2450
|
+
}
|
|
2451
|
+
/**
|
|
2452
|
+
* Install a portable runtime permission delegation into this SDK instance so
|
|
2453
|
+
* matching service calls and downstream `delegateTo()` calls can use it.
|
|
2454
|
+
*/
|
|
2455
|
+
async useRuntimeDelegation(delegation) {
|
|
2456
|
+
const session = this.auth?.tinyCloudSession;
|
|
2457
|
+
if (!session) {
|
|
2458
|
+
throw new SessionExpiredError(/* @__PURE__ */ new Date(0));
|
|
2459
|
+
}
|
|
2460
|
+
if (delegation.expiry.getTime() <= Date.now()) {
|
|
2461
|
+
throw new SessionExpiredError(delegation.expiry);
|
|
2462
|
+
}
|
|
2463
|
+
const expectedDids = /* @__PURE__ */ new Set([session.verificationMethod, this.sessionDid]);
|
|
2464
|
+
if (!expectedDids.has(delegation.delegateDID)) {
|
|
2465
|
+
throw new Error(
|
|
2466
|
+
`Runtime delegation targets ${delegation.delegateDID} but this session key is ${session.verificationMethod}.`
|
|
2467
|
+
);
|
|
2468
|
+
}
|
|
2469
|
+
const targetHost = delegation.host ?? this.config.host;
|
|
2470
|
+
const activateResult = await activateSessionWithHost2(
|
|
2471
|
+
targetHost,
|
|
2472
|
+
delegation.delegationHeader
|
|
2473
|
+
);
|
|
2474
|
+
if (!activateResult.success) {
|
|
2475
|
+
throw new Error(
|
|
2476
|
+
`Failed to activate runtime permission delegation: ${activateResult.error}`
|
|
2477
|
+
);
|
|
2478
|
+
}
|
|
2479
|
+
this.runtimePermissionGrants = this.runtimePermissionGrants.filter(
|
|
2480
|
+
(grant) => grant.delegation.cid !== delegation.cid
|
|
2481
|
+
);
|
|
2482
|
+
this.runtimePermissionGrants.push(
|
|
2483
|
+
this.runtimeGrantFromDelegation(delegation, session)
|
|
2484
|
+
);
|
|
2485
|
+
}
|
|
2486
|
+
/**
|
|
2487
|
+
* Store additional permissions as narrow delegations to the current session
|
|
2488
|
+
* key. Future service invocations automatically use a stored delegation when
|
|
2489
|
+
* its `(space, service, path, action)` covers the request.
|
|
2490
|
+
*/
|
|
2491
|
+
async grantRuntimePermissions(permissions, options) {
|
|
2492
|
+
if (!Array.isArray(permissions) || permissions.length === 0) {
|
|
2493
|
+
throw new Error("grantRuntimePermissions requires a non-empty permissions array");
|
|
2494
|
+
}
|
|
2495
|
+
const session = this.auth?.tinyCloudSession;
|
|
2496
|
+
if (!session) {
|
|
2497
|
+
throw new SessionExpiredError(/* @__PURE__ */ new Date(0));
|
|
2498
|
+
}
|
|
2499
|
+
const sessionExpiry = extractSiweExpiration(session.siwe);
|
|
2500
|
+
if (sessionExpiry !== void 0) {
|
|
2501
|
+
const marginMs = _TinyCloudNode.SESSION_EXPIRY_SAFETY_MARGIN_MS;
|
|
2502
|
+
if (sessionExpiry.getTime() <= Date.now() + marginMs) {
|
|
2503
|
+
throw new SessionExpiredError(sessionExpiry);
|
|
2504
|
+
}
|
|
2505
|
+
}
|
|
2506
|
+
const expanded = this.expandPermissionEntries(permissions);
|
|
2507
|
+
if (this.sessionCoversPermissionEntries(session, expanded)) {
|
|
2508
|
+
return [];
|
|
2509
|
+
}
|
|
2510
|
+
const existingGrants = this.findRuntimeGrantsForPermissionEntries(expanded, session);
|
|
2511
|
+
if (existingGrants.length > 0) {
|
|
2512
|
+
return existingGrants.map((grant) => grant.delegation);
|
|
2513
|
+
}
|
|
2514
|
+
if (!this.signer) {
|
|
2515
|
+
throw new Error(
|
|
2516
|
+
"grantRuntimePermissions requires wallet mode with a signer or privateKey."
|
|
2517
|
+
);
|
|
2518
|
+
}
|
|
2519
|
+
const bySpace = /* @__PURE__ */ new Map();
|
|
2520
|
+
for (const entry of expanded) {
|
|
2521
|
+
const spaceId = this.resolvePermissionSpace(entry.space, session);
|
|
2522
|
+
const current = bySpace.get(spaceId) ?? [];
|
|
2523
|
+
current.push(entry);
|
|
2524
|
+
bySpace.set(spaceId, current);
|
|
2525
|
+
}
|
|
2526
|
+
const now = /* @__PURE__ */ new Date();
|
|
2527
|
+
const requestedExpiryMs = resolveExpiryMs(options?.expiry);
|
|
2528
|
+
let expiresAt = new Date(now.getTime() + requestedExpiryMs);
|
|
2529
|
+
if (sessionExpiry !== void 0 && sessionExpiry < expiresAt) {
|
|
2530
|
+
expiresAt = sessionExpiry;
|
|
2531
|
+
}
|
|
2532
|
+
const delegations = [];
|
|
2533
|
+
for (const [spaceId, entries] of bySpace) {
|
|
2534
|
+
const abilities = this.permissionsToAbilities(entries);
|
|
2535
|
+
const prepared = this.wasmBindings.prepareSession({
|
|
2536
|
+
abilities,
|
|
2537
|
+
address: this.wasmBindings.ensureEip55(session.address),
|
|
2538
|
+
chainId: session.chainId,
|
|
2539
|
+
domain: this.siweDomain,
|
|
2540
|
+
issuedAt: now.toISOString(),
|
|
2541
|
+
expirationTime: expiresAt.toISOString(),
|
|
2542
|
+
spaceId,
|
|
2543
|
+
jwk: session.jwk
|
|
2544
|
+
});
|
|
2545
|
+
const signature = await this.signer.signMessage(prepared.siwe);
|
|
2546
|
+
const delegatedSession = this.wasmBindings.completeSessionSetup({
|
|
2547
|
+
...prepared,
|
|
2548
|
+
signature
|
|
2549
|
+
});
|
|
2550
|
+
const activateResult = await activateSessionWithHost2(
|
|
2551
|
+
this.config.host,
|
|
2552
|
+
delegatedSession.delegationHeader
|
|
2553
|
+
);
|
|
2554
|
+
if (!activateResult.success) {
|
|
2555
|
+
throw new Error(
|
|
2556
|
+
`Failed to activate runtime permission delegation: ${activateResult.error}`
|
|
2557
|
+
);
|
|
2558
|
+
}
|
|
2559
|
+
const delegation = this.runtimeDelegationFromSession(
|
|
2560
|
+
delegatedSession,
|
|
2561
|
+
entries,
|
|
2562
|
+
spaceId,
|
|
2563
|
+
session,
|
|
2564
|
+
expiresAt
|
|
2565
|
+
);
|
|
2566
|
+
this.runtimePermissionGrants.push({
|
|
2567
|
+
session: {
|
|
2568
|
+
delegationHeader: delegatedSession.delegationHeader,
|
|
2569
|
+
delegationCid: delegatedSession.delegationCid,
|
|
2570
|
+
spaceId,
|
|
2571
|
+
verificationMethod: session.verificationMethod,
|
|
2572
|
+
jwk: session.jwk
|
|
2573
|
+
},
|
|
2574
|
+
delegation,
|
|
2575
|
+
operations: this.permissionOperations(entries, spaceId),
|
|
2576
|
+
expiresAt
|
|
2577
|
+
});
|
|
2578
|
+
delegations.push(delegation);
|
|
2579
|
+
}
|
|
2580
|
+
return delegations;
|
|
2581
|
+
}
|
|
2419
2582
|
/**
|
|
2420
2583
|
* Get the DelegationManager for delegation CRUD operations.
|
|
2421
2584
|
*
|
|
@@ -2604,7 +2767,7 @@ var _TinyCloudNode = class _TinyCloudNode {
|
|
|
2604
2767
|
if (this._serviceContext) {
|
|
2605
2768
|
const publicKV = new KVService2({ prefix: "" });
|
|
2606
2769
|
const publicContext = new ServiceContext2({
|
|
2607
|
-
invoke: this.
|
|
2770
|
+
invoke: this.invokeWithRuntimePermissions,
|
|
2608
2771
|
fetch: this._serviceContext.fetch,
|
|
2609
2772
|
hosts: this._serviceContext.hosts
|
|
2610
2773
|
});
|
|
@@ -2692,8 +2855,9 @@ var _TinyCloudNode = class _TinyCloudNode {
|
|
|
2692
2855
|
* Issue a delegation using the capability-chain flow.
|
|
2693
2856
|
*
|
|
2694
2857
|
* When every requested permission is a subset of the current
|
|
2695
|
-
* session's recap,
|
|
2696
|
-
*
|
|
2858
|
+
* session's recap, or of one installed runtime permission delegation,
|
|
2859
|
+
* the delegation is signed by the session key via WASM — no wallet
|
|
2860
|
+
* prompt. When at least one is NOT derivable, a
|
|
2697
2861
|
* {@link PermissionNotInManifestError} is raised (carrying the
|
|
2698
2862
|
* missing entries) so the caller can trigger an escalation flow
|
|
2699
2863
|
* (e.g. `TinyCloudWeb.requestPermissions`). Passing
|
|
@@ -2773,6 +2937,23 @@ var _TinyCloudNode = class _TinyCloudNode {
|
|
|
2773
2937
|
);
|
|
2774
2938
|
const { subset, missing } = isCapabilitySubset(expandedEntries, granted);
|
|
2775
2939
|
if (!subset) {
|
|
2940
|
+
const runtimeGrant = this.findGrantForOperations(
|
|
2941
|
+
this.permissionEntriesToOperations(expandedEntries, session)
|
|
2942
|
+
);
|
|
2943
|
+
if (runtimeGrant) {
|
|
2944
|
+
const marginMs = _TinyCloudNode.SESSION_EXPIRY_SAFETY_MARGIN_MS;
|
|
2945
|
+
if (runtimeGrant.expiresAt.getTime() <= Date.now() + marginMs) {
|
|
2946
|
+
throw new SessionExpiredError(runtimeGrant.expiresAt);
|
|
2947
|
+
}
|
|
2948
|
+
const runtimeExpiration = runtimeGrant.expiresAt < effectiveExpiration ? runtimeGrant.expiresAt : effectiveExpiration;
|
|
2949
|
+
const delegation2 = await this.createDelegationViaRuntimeGrant(
|
|
2950
|
+
did,
|
|
2951
|
+
expandedEntries,
|
|
2952
|
+
runtimeExpiration,
|
|
2953
|
+
runtimeGrant
|
|
2954
|
+
);
|
|
2955
|
+
return { delegation: delegation2, prompted: false };
|
|
2956
|
+
}
|
|
2776
2957
|
throw new PermissionNotInManifestError(missing, granted);
|
|
2777
2958
|
}
|
|
2778
2959
|
const delegation = await this.createDelegationViaWasmPath(
|
|
@@ -2917,6 +3098,41 @@ var _TinyCloudNode = class _TinyCloudNode {
|
|
|
2917
3098
|
host: this.config.host
|
|
2918
3099
|
};
|
|
2919
3100
|
}
|
|
3101
|
+
async createDelegationViaRuntimeGrant(did, entries, expirationTime, grant) {
|
|
3102
|
+
const result = this.createDelegationWrapper({
|
|
3103
|
+
session: grant.session,
|
|
3104
|
+
delegateDID: did,
|
|
3105
|
+
spaceId: grant.session.spaceId,
|
|
3106
|
+
abilities: this.permissionsToAbilities(entries),
|
|
3107
|
+
expirationSecs: Math.floor(expirationTime.getTime() / 1e3)
|
|
3108
|
+
});
|
|
3109
|
+
const primary = result.resources[0];
|
|
3110
|
+
const delegationHeader = { Authorization: result.delegation };
|
|
3111
|
+
const targetHost = grant.delegation.host ?? this.config.host;
|
|
3112
|
+
const activateResult = await activateSessionWithHost2(
|
|
3113
|
+
targetHost,
|
|
3114
|
+
delegationHeader
|
|
3115
|
+
);
|
|
3116
|
+
if (!activateResult.success) {
|
|
3117
|
+
throw new Error(
|
|
3118
|
+
`Failed to activate delegation with host: ${activateResult.error}`
|
|
3119
|
+
);
|
|
3120
|
+
}
|
|
3121
|
+
return {
|
|
3122
|
+
cid: result.cid,
|
|
3123
|
+
delegationHeader,
|
|
3124
|
+
spaceId: grant.session.spaceId,
|
|
3125
|
+
path: primary.path,
|
|
3126
|
+
actions: primary.actions,
|
|
3127
|
+
resources: result.resources,
|
|
3128
|
+
disableSubDelegation: false,
|
|
3129
|
+
expiry: result.expiry,
|
|
3130
|
+
delegateDID: did,
|
|
3131
|
+
ownerAddress: grant.delegation.ownerAddress,
|
|
3132
|
+
chainId: grant.delegation.chainId,
|
|
3133
|
+
host: targetHost
|
|
3134
|
+
};
|
|
3135
|
+
}
|
|
2920
3136
|
resolvePermissionSpace(space, session) {
|
|
2921
3137
|
if (space === void 0) {
|
|
2922
3138
|
return this.wasmBindings.makeSpaceId(
|
|
@@ -2933,6 +3149,223 @@ var _TinyCloudNode = class _TinyCloudNode {
|
|
|
2933
3149
|
}
|
|
2934
3150
|
return this.wasmBindings.makeSpaceId(session.address, session.chainId, space);
|
|
2935
3151
|
}
|
|
3152
|
+
expandPermissionEntries(permissions) {
|
|
3153
|
+
return permissions.map((entry) => ({
|
|
3154
|
+
...entry,
|
|
3155
|
+
actions: expandActionShortNames(entry.service, entry.actions)
|
|
3156
|
+
}));
|
|
3157
|
+
}
|
|
3158
|
+
shortServiceName(service) {
|
|
3159
|
+
const short = SERVICE_LONG_TO_SHORT[service];
|
|
3160
|
+
if (short === void 0) {
|
|
3161
|
+
throw new Error(
|
|
3162
|
+
`unknown service '${service}' \u2014 no short-form mapping`
|
|
3163
|
+
);
|
|
3164
|
+
}
|
|
3165
|
+
return short;
|
|
3166
|
+
}
|
|
3167
|
+
permissionsToAbilities(entries) {
|
|
3168
|
+
const abilities = {};
|
|
3169
|
+
for (const entry of entries) {
|
|
3170
|
+
const service = this.shortServiceName(entry.service);
|
|
3171
|
+
abilities[service] ?? (abilities[service] = {});
|
|
3172
|
+
const existing = abilities[service][entry.path] ?? [];
|
|
3173
|
+
const seen = new Set(existing);
|
|
3174
|
+
for (const action of entry.actions) {
|
|
3175
|
+
if (!seen.has(action)) {
|
|
3176
|
+
existing.push(action);
|
|
3177
|
+
seen.add(action);
|
|
3178
|
+
}
|
|
3179
|
+
}
|
|
3180
|
+
abilities[service][entry.path] = existing;
|
|
3181
|
+
}
|
|
3182
|
+
return abilities;
|
|
3183
|
+
}
|
|
3184
|
+
permissionOperations(entries, spaceId) {
|
|
3185
|
+
return entries.flatMap((entry) => {
|
|
3186
|
+
const service = this.shortServiceName(entry.service);
|
|
3187
|
+
return entry.actions.map((action) => ({
|
|
3188
|
+
spaceId,
|
|
3189
|
+
service,
|
|
3190
|
+
path: entry.path,
|
|
3191
|
+
action
|
|
3192
|
+
}));
|
|
3193
|
+
});
|
|
3194
|
+
}
|
|
3195
|
+
sessionCoversPermissionEntries(session, entries) {
|
|
3196
|
+
try {
|
|
3197
|
+
const granted = parseRecapCapabilities(
|
|
3198
|
+
(siwe) => this.wasmBindings.parseRecapFromSiwe(siwe),
|
|
3199
|
+
session.siwe
|
|
3200
|
+
);
|
|
3201
|
+
return isCapabilitySubset(entries, granted).subset;
|
|
3202
|
+
} catch {
|
|
3203
|
+
return false;
|
|
3204
|
+
}
|
|
3205
|
+
}
|
|
3206
|
+
permissionEntriesToOperations(entries, session) {
|
|
3207
|
+
return entries.flatMap((entry) => {
|
|
3208
|
+
const spaceId = this.resolvePermissionSpace(entry.space, session);
|
|
3209
|
+
const service = this.shortServiceName(entry.service);
|
|
3210
|
+
return entry.actions.map((action) => ({
|
|
3211
|
+
spaceId,
|
|
3212
|
+
service,
|
|
3213
|
+
path: entry.path,
|
|
3214
|
+
action
|
|
3215
|
+
}));
|
|
3216
|
+
});
|
|
3217
|
+
}
|
|
3218
|
+
findRuntimeGrantsForPermissionEntries(entries, session) {
|
|
3219
|
+
const grants = [];
|
|
3220
|
+
const operations = this.permissionEntriesToOperations(entries, session);
|
|
3221
|
+
if (operations.length === 0) {
|
|
3222
|
+
return grants;
|
|
3223
|
+
}
|
|
3224
|
+
for (const operation of operations) {
|
|
3225
|
+
const grant = this.findGrantForOperation(operation);
|
|
3226
|
+
if (!grant) {
|
|
3227
|
+
return [];
|
|
3228
|
+
}
|
|
3229
|
+
if (!grants.includes(grant)) {
|
|
3230
|
+
grants.push(grant);
|
|
3231
|
+
}
|
|
3232
|
+
}
|
|
3233
|
+
return grants;
|
|
3234
|
+
}
|
|
3235
|
+
runtimeDelegationFromSession(delegatedSession, entries, spaceId, session, expiresAt) {
|
|
3236
|
+
const resources = this.delegatedResourcesForEntries(entries, spaceId);
|
|
3237
|
+
const primary = resources[0];
|
|
3238
|
+
return {
|
|
3239
|
+
cid: delegatedSession.delegationCid,
|
|
3240
|
+
delegationHeader: delegatedSession.delegationHeader,
|
|
3241
|
+
spaceId,
|
|
3242
|
+
path: primary.path,
|
|
3243
|
+
actions: primary.actions,
|
|
3244
|
+
resources,
|
|
3245
|
+
disableSubDelegation: false,
|
|
3246
|
+
expiry: expiresAt,
|
|
3247
|
+
delegateDID: session.verificationMethod,
|
|
3248
|
+
ownerAddress: session.address,
|
|
3249
|
+
chainId: session.chainId,
|
|
3250
|
+
host: this.config.host
|
|
3251
|
+
};
|
|
3252
|
+
}
|
|
3253
|
+
runtimeGrantFromDelegation(delegation, session) {
|
|
3254
|
+
const operations = this.operationsFromDelegation(delegation);
|
|
3255
|
+
return {
|
|
3256
|
+
session: {
|
|
3257
|
+
delegationHeader: delegation.delegationHeader,
|
|
3258
|
+
delegationCid: delegation.cid,
|
|
3259
|
+
spaceId: delegation.spaceId,
|
|
3260
|
+
verificationMethod: session.verificationMethod,
|
|
3261
|
+
jwk: session.jwk
|
|
3262
|
+
},
|
|
3263
|
+
delegation,
|
|
3264
|
+
operations,
|
|
3265
|
+
expiresAt: delegation.expiry
|
|
3266
|
+
};
|
|
3267
|
+
}
|
|
3268
|
+
delegatedResourcesForEntries(entries, spaceId) {
|
|
3269
|
+
return entries.map((entry) => ({
|
|
3270
|
+
service: this.shortServiceName(entry.service),
|
|
3271
|
+
space: spaceId,
|
|
3272
|
+
path: entry.path,
|
|
3273
|
+
actions: [...entry.actions]
|
|
3274
|
+
}));
|
|
3275
|
+
}
|
|
3276
|
+
operationsFromDelegation(delegation) {
|
|
3277
|
+
const resources = delegation.resources !== void 0 && delegation.resources.length > 0 ? delegation.resources : this.flatDelegationResources(delegation);
|
|
3278
|
+
return resources.flatMap(
|
|
3279
|
+
(resource) => resource.actions.map((action) => ({
|
|
3280
|
+
spaceId: resource.space,
|
|
3281
|
+
service: this.invocationServiceName(resource.service),
|
|
3282
|
+
path: resource.path,
|
|
3283
|
+
action
|
|
3284
|
+
}))
|
|
3285
|
+
);
|
|
3286
|
+
}
|
|
3287
|
+
flatDelegationResources(delegation) {
|
|
3288
|
+
const byService = /* @__PURE__ */ new Map();
|
|
3289
|
+
for (const action of delegation.actions) {
|
|
3290
|
+
const service = this.shortServiceName(action.split("/")[0]);
|
|
3291
|
+
const actions = byService.get(service) ?? [];
|
|
3292
|
+
actions.push(action);
|
|
3293
|
+
byService.set(service, actions);
|
|
3294
|
+
}
|
|
3295
|
+
return [...byService.entries()].map(([service, actions]) => ({
|
|
3296
|
+
service,
|
|
3297
|
+
space: delegation.spaceId,
|
|
3298
|
+
path: delegation.path,
|
|
3299
|
+
actions
|
|
3300
|
+
}));
|
|
3301
|
+
}
|
|
3302
|
+
selectInvocationSession(fallback, service, path, action) {
|
|
3303
|
+
const grant = this.findGrantForOperation({
|
|
3304
|
+
spaceId: fallback.spaceId,
|
|
3305
|
+
service: this.invocationServiceName(service),
|
|
3306
|
+
path,
|
|
3307
|
+
action
|
|
3308
|
+
});
|
|
3309
|
+
return grant?.session ?? fallback;
|
|
3310
|
+
}
|
|
3311
|
+
findGrantForOperations(operations) {
|
|
3312
|
+
if (operations.length === 0) {
|
|
3313
|
+
return void 0;
|
|
3314
|
+
}
|
|
3315
|
+
this.pruneExpiredRuntimePermissionGrants();
|
|
3316
|
+
return this.runtimePermissionGrants.find((grant) => {
|
|
3317
|
+
return operations.every(
|
|
3318
|
+
(operation) => grant.operations.some(
|
|
3319
|
+
(granted) => this.operationCovers(granted, operation)
|
|
3320
|
+
)
|
|
3321
|
+
);
|
|
3322
|
+
});
|
|
3323
|
+
}
|
|
3324
|
+
findGrantForOperation(operation) {
|
|
3325
|
+
return this.findGrantForOperations([operation]);
|
|
3326
|
+
}
|
|
3327
|
+
pruneExpiredRuntimePermissionGrants() {
|
|
3328
|
+
const now = Date.now();
|
|
3329
|
+
this.runtimePermissionGrants = this.runtimePermissionGrants.filter(
|
|
3330
|
+
(grant) => grant.expiresAt.getTime() > now
|
|
3331
|
+
);
|
|
3332
|
+
}
|
|
3333
|
+
operationCovers(granted, requested) {
|
|
3334
|
+
return granted.spaceId === requested.spaceId && granted.service === requested.service && this.actionContains(granted.action, requested.action) && this.pathContains(granted.path, requested.path);
|
|
3335
|
+
}
|
|
3336
|
+
actionContains(grantedAction, requestedAction) {
|
|
3337
|
+
if (grantedAction === requestedAction) {
|
|
3338
|
+
return true;
|
|
3339
|
+
}
|
|
3340
|
+
if (grantedAction.endsWith("/*")) {
|
|
3341
|
+
const prefix = grantedAction.slice(0, -2);
|
|
3342
|
+
return requestedAction.startsWith(`${prefix}/`);
|
|
3343
|
+
}
|
|
3344
|
+
return false;
|
|
3345
|
+
}
|
|
3346
|
+
invocationServiceName(service) {
|
|
3347
|
+
return service.startsWith("tinycloud.") ? this.shortServiceName(service) : service;
|
|
3348
|
+
}
|
|
3349
|
+
pathContains(grantedPath, requestedPath) {
|
|
3350
|
+
if (grantedPath === "" || grantedPath === "/") {
|
|
3351
|
+
return true;
|
|
3352
|
+
}
|
|
3353
|
+
if (grantedPath.endsWith("/**")) {
|
|
3354
|
+
return requestedPath.startsWith(grantedPath.slice(0, -3));
|
|
3355
|
+
}
|
|
3356
|
+
if (grantedPath.endsWith("/*")) {
|
|
3357
|
+
const prefix = grantedPath.slice(0, -2);
|
|
3358
|
+
if (!requestedPath.startsWith(prefix)) {
|
|
3359
|
+
return false;
|
|
3360
|
+
}
|
|
3361
|
+
const remainder = requestedPath.slice(prefix.length);
|
|
3362
|
+
return !remainder.includes("/") || remainder === "/";
|
|
3363
|
+
}
|
|
3364
|
+
if (grantedPath.endsWith("/")) {
|
|
3365
|
+
return requestedPath.startsWith(grantedPath);
|
|
3366
|
+
}
|
|
3367
|
+
return grantedPath === requestedPath;
|
|
3368
|
+
}
|
|
2936
3369
|
/**
|
|
2937
3370
|
* Issue a delegation via the legacy wallet-signed SIWE path for a single
|
|
2938
3371
|
* {@link PermissionEntry}. Shares the implementation with the public
|