@tinycloud/node-sdk 3.1.0-beta.8 → 3.1.0
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-CC7uDKZP.d.cts → core-AEx5vAa8.d.cts} +21 -0
- package/dist/{core-CC7uDKZP.d.ts → core-AEx5vAa8.d.ts} +21 -0
- package/dist/core.cjs +174 -85
- 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 +175 -85
- package/dist/core.js.map +1 -1
- package/dist/index.cjs +174 -85
- 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 +175 -85
- package/dist/index.js.map +1 -1
- package/package.json +4 -4
|
@@ -1201,12 +1201,25 @@ interface TinyCloudNodeConfig {
|
|
|
1201
1201
|
* delegation through the legacy wallet-signed SIWE path, which always
|
|
1202
1202
|
* triggers a wallet prompt. Used for testing, for explicit wallet
|
|
1203
1203
|
* confirmation flows, and by the legacy `createDelegation` fallback.
|
|
1204
|
+
*
|
|
1205
|
+
* `onPrepared` runs after the delegation is fully built and signed (CID
|
|
1206
|
+
* included) and before it is activated with the host. It receives the same
|
|
1207
|
+
* `PortableDelegation` object that `delegateTo` returns as
|
|
1208
|
+
* `result.delegation`, so callers can durably record the grant before it
|
|
1209
|
+
* goes live. If the hook rejects, the delegation is not activated and
|
|
1210
|
+
* `delegateTo` rejects with the same error. It cannot be combined with
|
|
1211
|
+
* `forceWalletSign`, whose wallet path activates as part of signing.
|
|
1204
1212
|
*/
|
|
1205
1213
|
interface DelegateToOptions {
|
|
1206
1214
|
/** Override expiry. ms-format string ("7d", "1h") or raw milliseconds. */
|
|
1207
1215
|
expiry?: string | number;
|
|
1208
1216
|
/** Force the wallet-signed SIWE path even if the caps are derivable. Default false. */
|
|
1209
1217
|
forceWalletSign?: boolean;
|
|
1218
|
+
/**
|
|
1219
|
+
* Called with the prepared delegation before host activation. A rejection
|
|
1220
|
+
* aborts activation and propagates from `delegateTo`.
|
|
1221
|
+
*/
|
|
1222
|
+
onPrepared?: (prepared: PortableDelegation) => Promise<void>;
|
|
1210
1223
|
}
|
|
1211
1224
|
/**
|
|
1212
1225
|
* Result of {@link TinyCloudNode.delegateTo}.
|
|
@@ -1504,6 +1517,9 @@ declare class TinyCloudNode {
|
|
|
1504
1517
|
private resolveBootstrapDecision;
|
|
1505
1518
|
private readBootstrapCompletionMarker;
|
|
1506
1519
|
private writeBootstrapCompletionMarker;
|
|
1520
|
+
/**
|
|
1521
|
+
* A marker written before a canonical space was added triggers one bounded repair.
|
|
1522
|
+
*/
|
|
1507
1523
|
private isAcceptedBootstrapCompletionMarker;
|
|
1508
1524
|
private markerReadIsUnhostedSpace;
|
|
1509
1525
|
private runAccountBootstrap;
|
|
@@ -2250,6 +2266,10 @@ declare class TinyCloudNode {
|
|
|
2250
2266
|
* @throws {@link PermissionNotInManifestError} when any requested
|
|
2251
2267
|
* entry is not a subset of the granted session capabilities and
|
|
2252
2268
|
* `forceWalletSign` is not set.
|
|
2269
|
+
* @throws when `onPrepared` is combined with `forceWalletSign: true`,
|
|
2270
|
+
* before anything is signed.
|
|
2271
|
+
* @throws the `onPrepared` rejection, unchanged, without activating the
|
|
2272
|
+
* delegation.
|
|
2253
2273
|
*/
|
|
2254
2274
|
delegateTo(did: string, permissions: PermissionEntry[], options?: DelegateToOptions): Promise<DelegateToResult>;
|
|
2255
2275
|
/**
|
|
@@ -2300,6 +2320,7 @@ declare class TinyCloudNode {
|
|
|
2300
2320
|
private shortServiceName;
|
|
2301
2321
|
private permissionsToAbilities;
|
|
2302
2322
|
private isEncryptionPermissionEntry;
|
|
2323
|
+
private isRawRevocationPermissionEntry;
|
|
2303
2324
|
private permissionsToRawAbilities;
|
|
2304
2325
|
private permissionOperations;
|
|
2305
2326
|
/** Raw network authority cannot be covered by a nested encryption space. */
|
|
@@ -1201,12 +1201,25 @@ interface TinyCloudNodeConfig {
|
|
|
1201
1201
|
* delegation through the legacy wallet-signed SIWE path, which always
|
|
1202
1202
|
* triggers a wallet prompt. Used for testing, for explicit wallet
|
|
1203
1203
|
* confirmation flows, and by the legacy `createDelegation` fallback.
|
|
1204
|
+
*
|
|
1205
|
+
* `onPrepared` runs after the delegation is fully built and signed (CID
|
|
1206
|
+
* included) and before it is activated with the host. It receives the same
|
|
1207
|
+
* `PortableDelegation` object that `delegateTo` returns as
|
|
1208
|
+
* `result.delegation`, so callers can durably record the grant before it
|
|
1209
|
+
* goes live. If the hook rejects, the delegation is not activated and
|
|
1210
|
+
* `delegateTo` rejects with the same error. It cannot be combined with
|
|
1211
|
+
* `forceWalletSign`, whose wallet path activates as part of signing.
|
|
1204
1212
|
*/
|
|
1205
1213
|
interface DelegateToOptions {
|
|
1206
1214
|
/** Override expiry. ms-format string ("7d", "1h") or raw milliseconds. */
|
|
1207
1215
|
expiry?: string | number;
|
|
1208
1216
|
/** Force the wallet-signed SIWE path even if the caps are derivable. Default false. */
|
|
1209
1217
|
forceWalletSign?: boolean;
|
|
1218
|
+
/**
|
|
1219
|
+
* Called with the prepared delegation before host activation. A rejection
|
|
1220
|
+
* aborts activation and propagates from `delegateTo`.
|
|
1221
|
+
*/
|
|
1222
|
+
onPrepared?: (prepared: PortableDelegation) => Promise<void>;
|
|
1210
1223
|
}
|
|
1211
1224
|
/**
|
|
1212
1225
|
* Result of {@link TinyCloudNode.delegateTo}.
|
|
@@ -1504,6 +1517,9 @@ declare class TinyCloudNode {
|
|
|
1504
1517
|
private resolveBootstrapDecision;
|
|
1505
1518
|
private readBootstrapCompletionMarker;
|
|
1506
1519
|
private writeBootstrapCompletionMarker;
|
|
1520
|
+
/**
|
|
1521
|
+
* A marker written before a canonical space was added triggers one bounded repair.
|
|
1522
|
+
*/
|
|
1507
1523
|
private isAcceptedBootstrapCompletionMarker;
|
|
1508
1524
|
private markerReadIsUnhostedSpace;
|
|
1509
1525
|
private runAccountBootstrap;
|
|
@@ -2250,6 +2266,10 @@ declare class TinyCloudNode {
|
|
|
2250
2266
|
* @throws {@link PermissionNotInManifestError} when any requested
|
|
2251
2267
|
* entry is not a subset of the granted session capabilities and
|
|
2252
2268
|
* `forceWalletSign` is not set.
|
|
2269
|
+
* @throws when `onPrepared` is combined with `forceWalletSign: true`,
|
|
2270
|
+
* before anything is signed.
|
|
2271
|
+
* @throws the `onPrepared` rejection, unchanged, without activating the
|
|
2272
|
+
* delegation.
|
|
2253
2273
|
*/
|
|
2254
2274
|
delegateTo(did: string, permissions: PermissionEntry[], options?: DelegateToOptions): Promise<DelegateToResult>;
|
|
2255
2275
|
/**
|
|
@@ -2300,6 +2320,7 @@ declare class TinyCloudNode {
|
|
|
2300
2320
|
private shortServiceName;
|
|
2301
2321
|
private permissionsToAbilities;
|
|
2302
2322
|
private isEncryptionPermissionEntry;
|
|
2323
|
+
private isRawRevocationPermissionEntry;
|
|
2303
2324
|
private permissionsToRawAbilities;
|
|
2304
2325
|
private permissionOperations;
|
|
2305
2326
|
/** Raw network authority cannot be covered by a nested encryption space. */
|
package/dist/core.cjs
CHANGED
|
@@ -2699,15 +2699,21 @@ var _TinyCloudNode = class _TinyCloudNode {
|
|
|
2699
2699
|
if (!this.wasmBindings.invokeAny) {
|
|
2700
2700
|
throw new Error("WASM binding does not support invokeAny");
|
|
2701
2701
|
}
|
|
2702
|
-
const
|
|
2702
|
+
const routedEntries = entries;
|
|
2703
|
+
const operations = routedEntries.flatMap((entry) => {
|
|
2703
2704
|
const operation = this.operationFromInvokeAnyEntry(entry);
|
|
2704
2705
|
return operation ? [operation] : [];
|
|
2705
2706
|
});
|
|
2706
|
-
const
|
|
2707
|
-
const
|
|
2708
|
-
|
|
2707
|
+
const authorityCid = routedEntries.length === 1 ? routedEntries[0]?.revokeAuthorityCid : void 0;
|
|
2708
|
+
const explicitGrant = authorityCid === void 0 ? void 0 : this.runtimePermissionGrants.find((grant2) => grant2.delegation.cid === authorityCid);
|
|
2709
|
+
if (authorityCid !== void 0 && !explicitGrant) {
|
|
2710
|
+
throw new Error(`Explicit revocation authority ${authorityCid} is not installed.`);
|
|
2711
|
+
}
|
|
2712
|
+
const grant = explicitGrant ?? this.findGrantForOperations(operations);
|
|
2713
|
+
const invocationSession = explicitGrant ? explicitGrant.session : !grant || grant.provenance === "primary" ? session : grant.session;
|
|
2714
|
+
const caveatPreservingEntries = routedEntries.map(({ revokeAuthorityCid: _cid, ...entry }) => {
|
|
2709
2715
|
const requested = this.operationFromInvokeAnyEntry(entry);
|
|
2710
|
-
const granted = requested && grant.operations.find(
|
|
2716
|
+
const granted = grant && requested && grant.operations.find(
|
|
2711
2717
|
(candidate) => this.operationCovers(candidate, requested)
|
|
2712
2718
|
);
|
|
2713
2719
|
if (!granted?.caveats?.length) {
|
|
@@ -2717,7 +2723,7 @@ var _TinyCloudNode = class _TinyCloudNode {
|
|
|
2717
2723
|
throw new Error("Invocation caveats do not match signed ReCap authority.");
|
|
2718
2724
|
}
|
|
2719
2725
|
return { ...entry, caveats: cloneRecapCaveats(granted.caveats) };
|
|
2720
|
-
})
|
|
2726
|
+
});
|
|
2721
2727
|
return this.wasmBindings.invokeAny(invocationSession, caveatPreservingEntries, facts);
|
|
2722
2728
|
};
|
|
2723
2729
|
this.explicitHost = config.host;
|
|
@@ -3182,12 +3188,13 @@ var _TinyCloudNode = class _TinyCloudNode {
|
|
|
3182
3188
|
if (!auth) {
|
|
3183
3189
|
throw new Error("Account bootstrap requires an active wallet session");
|
|
3184
3190
|
}
|
|
3191
|
+
const accountSpaceId = this.ownedSpaceId(import_sdk_core8.ACCOUNT_REGISTRY_SPACE);
|
|
3185
3192
|
const skipped = auth.lastActivationSkippedSpaceIds;
|
|
3193
|
+
if (skipped.includes(accountSpaceId)) return { action: "run", mode: "fresh" };
|
|
3186
3194
|
if (skipped.some((spaceId) => enshrinedSpaceIds.has(spaceId))) {
|
|
3187
|
-
return { action: "run", mode: "
|
|
3195
|
+
return { action: "run", mode: "repair" };
|
|
3188
3196
|
}
|
|
3189
3197
|
try {
|
|
3190
|
-
const accountSpaceId = this.ownedSpaceId(import_sdk_core8.ACCOUNT_REGISTRY_SPACE);
|
|
3191
3198
|
const markerPermission = {
|
|
3192
3199
|
service: "tinycloud.kv",
|
|
3193
3200
|
space: accountSpaceId,
|
|
@@ -3199,7 +3206,7 @@ var _TinyCloudNode = class _TinyCloudNode {
|
|
|
3199
3206
|
}
|
|
3200
3207
|
const marker = await this.readBootstrapCompletionMarker();
|
|
3201
3208
|
if (marker.ok) {
|
|
3202
|
-
if (this.isAcceptedBootstrapCompletionMarker(marker.data.data)) {
|
|
3209
|
+
if (this.isAcceptedBootstrapCompletionMarker(marker.data.data, steps.map((step) => step.id))) {
|
|
3203
3210
|
return { action: "skip" };
|
|
3204
3211
|
}
|
|
3205
3212
|
return { action: "run", mode: "repair" };
|
|
@@ -3249,12 +3256,16 @@ var _TinyCloudNode = class _TinyCloudNode {
|
|
|
3249
3256
|
);
|
|
3250
3257
|
}
|
|
3251
3258
|
}
|
|
3252
|
-
|
|
3259
|
+
/**
|
|
3260
|
+
* A marker written before a canonical space was added triggers one bounded repair.
|
|
3261
|
+
*/
|
|
3262
|
+
isAcceptedBootstrapCompletionMarker(value, canonicalStepIds) {
|
|
3253
3263
|
if (typeof value !== "object" || value === null) return false;
|
|
3254
3264
|
const entries = Object.entries(value);
|
|
3255
3265
|
const markerValue = (name) => entries.find(([key]) => key === name)?.[1];
|
|
3256
3266
|
const version = markerValue("v");
|
|
3257
|
-
|
|
3267
|
+
const stepIds = markerValue("stepIds");
|
|
3268
|
+
return typeof version === "number" && Number.isInteger(version) && ACCEPTED_MARKER_VERSIONS.some((acceptedVersion) => acceptedVersion === version) && Array.isArray(stepIds) && canonicalStepIds.every((stepId) => stepIds.includes(stepId));
|
|
3258
3269
|
}
|
|
3259
3270
|
markerReadIsUnhostedSpace(meta) {
|
|
3260
3271
|
return meta?.status === 404;
|
|
@@ -3341,30 +3352,39 @@ var _TinyCloudNode = class _TinyCloudNode {
|
|
|
3341
3352
|
}
|
|
3342
3353
|
}
|
|
3343
3354
|
if (step.kind === "seed-spaces") {
|
|
3344
|
-
const
|
|
3345
|
-
|
|
3346
|
-
|
|
3347
|
-
|
|
3348
|
-
|
|
3349
|
-
|
|
3350
|
-
|
|
3351
|
-
|
|
3352
|
-
|
|
3353
|
-
|
|
3354
|
-
|
|
3355
|
-
|
|
3356
|
-
|
|
3357
|
-
|
|
3358
|
-
|
|
3359
|
-
|
|
3360
|
-
|
|
3361
|
-
|
|
3362
|
-
|
|
3363
|
-
|
|
3364
|
-
|
|
3365
|
-
|
|
3366
|
-
|
|
3367
|
-
|
|
3355
|
+
const inputs = step.spaces.map((space) => ({
|
|
3356
|
+
spaceId: space.spaceId,
|
|
3357
|
+
name: space.name,
|
|
3358
|
+
ownerDid: this.did,
|
|
3359
|
+
type: "owned",
|
|
3360
|
+
permissions: ["*"],
|
|
3361
|
+
status: "active"
|
|
3362
|
+
}));
|
|
3363
|
+
if (mode === "fresh") {
|
|
3364
|
+
const registered = await this.account.spaces.registerBatch(inputs);
|
|
3365
|
+
if (!registered.ok) {
|
|
3366
|
+
throw Object.assign(
|
|
3367
|
+
new Error(`Failed to seed account spaces: ${registered.error.message}`),
|
|
3368
|
+
{ cause: registered.error }
|
|
3369
|
+
);
|
|
3370
|
+
}
|
|
3371
|
+
const batchError = registered.data.recoveredFromBatchError;
|
|
3372
|
+
if (batchError) {
|
|
3373
|
+
warnings.push({
|
|
3374
|
+
stepId: step.id,
|
|
3375
|
+
kind: "batch-write-reconciled",
|
|
3376
|
+
code: batchError.code,
|
|
3377
|
+
message: batchError.message
|
|
3378
|
+
});
|
|
3379
|
+
}
|
|
3380
|
+
} else {
|
|
3381
|
+
const ensured = await this.account.spaces.registerMissing(inputs);
|
|
3382
|
+
if (!ensured.ok) {
|
|
3383
|
+
throw Object.assign(
|
|
3384
|
+
new Error(`Failed to seed account spaces: ${ensured.error.message}`),
|
|
3385
|
+
{ cause: ensured.error }
|
|
3386
|
+
);
|
|
3387
|
+
}
|
|
3368
3388
|
}
|
|
3369
3389
|
}
|
|
3370
3390
|
if (step.kind === "seed-applications") {
|
|
@@ -4049,6 +4069,7 @@ var _TinyCloudNode = class _TinyCloudNode {
|
|
|
4049
4069
|
stagedSessionExpiry,
|
|
4050
4070
|
stagedRecap
|
|
4051
4071
|
);
|
|
4072
|
+
const stagedAccountSpaceId = stagedAddress ? this.wasmBindings.makeSpaceId(stagedAddress, stagedChainId, import_sdk_core8.ACCOUNT_REGISTRY_SPACE) : void 0;
|
|
4052
4073
|
const stagedGraph = this.stageRestoredServiceGraph({
|
|
4053
4074
|
host: stagedHost,
|
|
4054
4075
|
manager: stagedManager,
|
|
@@ -4057,6 +4078,7 @@ var _TinyCloudNode = class _TinyCloudNode {
|
|
|
4057
4078
|
nodeDid: stagedNodeDid,
|
|
4058
4079
|
address: stagedAddress,
|
|
4059
4080
|
chainId: stagedChainId,
|
|
4081
|
+
accountSpaceId: stagedAccountSpaceId,
|
|
4060
4082
|
tinyCloudSession: stagedTcSession,
|
|
4061
4083
|
sessionExpiry: stagedSessionExpiry,
|
|
4062
4084
|
recap: stagedRecap
|
|
@@ -4222,6 +4244,7 @@ var _TinyCloudNode = class _TinyCloudNode {
|
|
|
4222
4244
|
}
|
|
4223
4245
|
const delegationManager = new import_sdk_core8.DelegationManager({
|
|
4224
4246
|
hosts: [input.host],
|
|
4247
|
+
accountSpaceId: input.accountSpaceId,
|
|
4225
4248
|
session: input.serviceSession,
|
|
4226
4249
|
invoke: graph.invoke,
|
|
4227
4250
|
invokeAny: graph.invokeAny,
|
|
@@ -5926,6 +5949,14 @@ var _TinyCloudNode = class _TinyCloudNode {
|
|
|
5926
5949
|
delegation.delegationHeader
|
|
5927
5950
|
);
|
|
5928
5951
|
if (!activateResult.success) {
|
|
5952
|
+
if (this.operationsFromDelegation(delegation).some(
|
|
5953
|
+
(operation) => operation.resource?.startsWith("urn:cid:") === true && operation.service === "delegation" && operation.action === "tinycloud.delegation/revoke"
|
|
5954
|
+
) && activateResult.status === 401 && /Cannot find parent delegation/i.test(activateResult.error ?? "")) {
|
|
5955
|
+
throw Object.assign(
|
|
5956
|
+
new Error("The host cannot activate a root raw-CID revoke authority without a parent delegation."),
|
|
5957
|
+
{ code: "RAW_RECAP_RESOURCE_UNSUPPORTED", cause: activateResult }
|
|
5958
|
+
);
|
|
5959
|
+
}
|
|
5929
5960
|
throw Object.assign(
|
|
5930
5961
|
new Error(`Failed to activate runtime permission delegation: ${describeHostFailure2(activateResult)}`),
|
|
5931
5962
|
{ cause: activateResult }
|
|
@@ -5973,10 +6004,10 @@ var _TinyCloudNode = class _TinyCloudNode {
|
|
|
5973
6004
|
}
|
|
5974
6005
|
this.assertDelegationCaveatsPreservable(expanded);
|
|
5975
6006
|
const rawEntries = expanded.filter(
|
|
5976
|
-
(entry) => this.isEncryptionPermissionEntry(entry)
|
|
6007
|
+
(entry) => this.isEncryptionPermissionEntry(entry) || this.isRawRevocationPermissionEntry(entry)
|
|
5977
6008
|
);
|
|
5978
6009
|
const spaceEntries = expanded.filter(
|
|
5979
|
-
(entry) => !this.isEncryptionPermissionEntry(entry)
|
|
6010
|
+
(entry) => !this.isEncryptionPermissionEntry(entry) && !this.isRawRevocationPermissionEntry(entry)
|
|
5980
6011
|
);
|
|
5981
6012
|
const bySpace = /* @__PURE__ */ new Map();
|
|
5982
6013
|
for (const entry of spaceEntries) {
|
|
@@ -6003,17 +6034,29 @@ var _TinyCloudNode = class _TinyCloudNode {
|
|
|
6003
6034
|
}
|
|
6004
6035
|
const delegatedEntries = [...entries, ...rawForDelegation];
|
|
6005
6036
|
const abilities = this.permissionsToAbilities(entries);
|
|
6006
|
-
const prepared =
|
|
6007
|
-
|
|
6008
|
-
|
|
6009
|
-
|
|
6010
|
-
|
|
6011
|
-
|
|
6012
|
-
|
|
6013
|
-
|
|
6014
|
-
|
|
6015
|
-
|
|
6016
|
-
|
|
6037
|
+
const prepared = (() => {
|
|
6038
|
+
try {
|
|
6039
|
+
return this.wasmBindings.prepareSession({
|
|
6040
|
+
abilities,
|
|
6041
|
+
...rawForDelegation.length > 0 ? { rawAbilities: this.permissionsToRawAbilities(rawForDelegation) } : {},
|
|
6042
|
+
address: this.wasmBindings.ensureEip55(session.address),
|
|
6043
|
+
chainId: session.chainId,
|
|
6044
|
+
domain: this.siweDomain,
|
|
6045
|
+
issuedAt: now.toISOString(),
|
|
6046
|
+
expirationTime: expiresAt.toISOString(),
|
|
6047
|
+
spaceId,
|
|
6048
|
+
jwk: session.jwk
|
|
6049
|
+
});
|
|
6050
|
+
} catch (error) {
|
|
6051
|
+
if (rawForDelegation.some((entry) => this.isRawRevocationPermissionEntry(entry)) && /invalid ReCap resource URI/i.test(error instanceof Error ? error.message : String(error))) {
|
|
6052
|
+
throw Object.assign(
|
|
6053
|
+
new Error("This WASM build cannot encode raw urn:cid ReCap resources."),
|
|
6054
|
+
{ code: "RAW_RECAP_RESOURCE_UNSUPPORTED", cause: error }
|
|
6055
|
+
);
|
|
6056
|
+
}
|
|
6057
|
+
throw error;
|
|
6058
|
+
}
|
|
6059
|
+
})();
|
|
6017
6060
|
const signature = await this.signer.signMessage(prepared.siwe);
|
|
6018
6061
|
const delegatedSession = this.wasmBindings.completeSessionSetup({
|
|
6019
6062
|
...prepared,
|
|
@@ -6024,6 +6067,12 @@ var _TinyCloudNode = class _TinyCloudNode {
|
|
|
6024
6067
|
delegatedSession.delegationHeader
|
|
6025
6068
|
);
|
|
6026
6069
|
if (!activateResult.success) {
|
|
6070
|
+
if (rawForDelegation.some((entry) => this.isRawRevocationPermissionEntry(entry)) && activateResult.status === 401 && /Cannot find parent delegation/i.test(activateResult.error ?? "")) {
|
|
6071
|
+
throw Object.assign(
|
|
6072
|
+
new Error("The host cannot activate a root raw-CID revoke authority without a parent delegation."),
|
|
6073
|
+
{ code: "RAW_RECAP_RESOURCE_UNSUPPORTED", cause: activateResult }
|
|
6074
|
+
);
|
|
6075
|
+
}
|
|
6027
6076
|
throw Object.assign(
|
|
6028
6077
|
new Error(`Failed to activate runtime permission delegation: ${describeHostFailure2(activateResult)}`),
|
|
6029
6078
|
{ cause: activateResult }
|
|
@@ -6376,8 +6425,18 @@ var _TinyCloudNode = class _TinyCloudNode {
|
|
|
6376
6425
|
* @throws {@link PermissionNotInManifestError} when any requested
|
|
6377
6426
|
* entry is not a subset of the granted session capabilities and
|
|
6378
6427
|
* `forceWalletSign` is not set.
|
|
6428
|
+
* @throws when `onPrepared` is combined with `forceWalletSign: true`,
|
|
6429
|
+
* before anything is signed.
|
|
6430
|
+
* @throws the `onPrepared` rejection, unchanged, without activating the
|
|
6431
|
+
* delegation.
|
|
6379
6432
|
*/
|
|
6380
6433
|
async delegateTo(did, permissions, options) {
|
|
6434
|
+
const onPrepared = options?.onPrepared;
|
|
6435
|
+
if (onPrepared && options?.forceWalletSign) {
|
|
6436
|
+
throw new Error(
|
|
6437
|
+
"delegateTo: onPrepared cannot be combined with forceWalletSign=true; the wallet-signed path activates the delegation before it could be handed to onPrepared."
|
|
6438
|
+
);
|
|
6439
|
+
}
|
|
6381
6440
|
const session = this.currentTinyCloudSession();
|
|
6382
6441
|
if (!session) {
|
|
6383
6442
|
throw new import_sdk_core8.SessionExpiredError(/* @__PURE__ */ new Date(0));
|
|
@@ -6436,7 +6495,8 @@ var _TinyCloudNode = class _TinyCloudNode {
|
|
|
6436
6495
|
expandedEntries,
|
|
6437
6496
|
runtimeExpiration,
|
|
6438
6497
|
runtimeGrant,
|
|
6439
|
-
runtimeOperations
|
|
6498
|
+
runtimeOperations,
|
|
6499
|
+
onPrepared
|
|
6440
6500
|
);
|
|
6441
6501
|
return { delegation: delegation2, prompted: false };
|
|
6442
6502
|
}
|
|
@@ -6446,7 +6506,8 @@ var _TinyCloudNode = class _TinyCloudNode {
|
|
|
6446
6506
|
did,
|
|
6447
6507
|
expandedEntries,
|
|
6448
6508
|
effectiveExpiration,
|
|
6449
|
-
session
|
|
6509
|
+
session,
|
|
6510
|
+
onPrepared
|
|
6450
6511
|
);
|
|
6451
6512
|
return { delegation, prompted: false };
|
|
6452
6513
|
}
|
|
@@ -6500,7 +6561,7 @@ var _TinyCloudNode = class _TinyCloudNode {
|
|
|
6500
6561
|
*
|
|
6501
6562
|
* @internal
|
|
6502
6563
|
*/
|
|
6503
|
-
async createDelegationViaWasmPath(did, entries, expirationTime, session) {
|
|
6564
|
+
async createDelegationViaWasmPath(did, entries, expirationTime, session, onPrepared) {
|
|
6504
6565
|
if (entries.length === 0) {
|
|
6505
6566
|
throw new Error(
|
|
6506
6567
|
"createDelegationViaWasmPath requires a non-empty entries array"
|
|
@@ -6563,17 +6624,7 @@ var _TinyCloudNode = class _TinyCloudNode {
|
|
|
6563
6624
|
});
|
|
6564
6625
|
const primary = result.resources[0];
|
|
6565
6626
|
const delegationHeader = { Authorization: result.delegation };
|
|
6566
|
-
const
|
|
6567
|
-
this.config.host,
|
|
6568
|
-
delegationHeader
|
|
6569
|
-
);
|
|
6570
|
-
if (!activateResult.success) {
|
|
6571
|
-
throw Object.assign(
|
|
6572
|
-
new Error(`Failed to activate delegation with host: ${describeHostFailure2(activateResult)}`),
|
|
6573
|
-
{ cause: activateResult }
|
|
6574
|
-
);
|
|
6575
|
-
}
|
|
6576
|
-
return {
|
|
6627
|
+
const delegation = {
|
|
6577
6628
|
cid: result.cid,
|
|
6578
6629
|
delegationHeader,
|
|
6579
6630
|
spaceId,
|
|
@@ -6587,8 +6638,22 @@ var _TinyCloudNode = class _TinyCloudNode {
|
|
|
6587
6638
|
chainId: session.chainId,
|
|
6588
6639
|
host: this.config.host
|
|
6589
6640
|
};
|
|
6641
|
+
if (onPrepared) {
|
|
6642
|
+
await onPrepared(delegation);
|
|
6643
|
+
}
|
|
6644
|
+
const activateResult = await (0, import_sdk_core8.activateSessionWithHost)(
|
|
6645
|
+
this.config.host,
|
|
6646
|
+
delegationHeader
|
|
6647
|
+
);
|
|
6648
|
+
if (!activateResult.success) {
|
|
6649
|
+
throw Object.assign(
|
|
6650
|
+
new Error(`Failed to activate delegation with host: ${describeHostFailure2(activateResult)}`),
|
|
6651
|
+
{ cause: activateResult }
|
|
6652
|
+
);
|
|
6653
|
+
}
|
|
6654
|
+
return delegation;
|
|
6590
6655
|
}
|
|
6591
|
-
async createDelegationViaRuntimeGrant(did, entries, expirationTime, grant, requestedOperations) {
|
|
6656
|
+
async createDelegationViaRuntimeGrant(did, entries, expirationTime, grant, requestedOperations, onPrepared) {
|
|
6592
6657
|
this.assertRuntimeGrantCaveatsPreservable(entries, requestedOperations, grant);
|
|
6593
6658
|
this.assertDelegationCaveatsPreservable(entries);
|
|
6594
6659
|
const result = this.createDelegationWrapper({
|
|
@@ -6601,17 +6666,7 @@ var _TinyCloudNode = class _TinyCloudNode {
|
|
|
6601
6666
|
const primary = result.resources[0];
|
|
6602
6667
|
const delegationHeader = { Authorization: result.delegation };
|
|
6603
6668
|
const targetHost = grant.delegation.host ?? this.config.host;
|
|
6604
|
-
const
|
|
6605
|
-
targetHost,
|
|
6606
|
-
delegationHeader
|
|
6607
|
-
);
|
|
6608
|
-
if (!activateResult.success) {
|
|
6609
|
-
throw Object.assign(
|
|
6610
|
-
new Error(`Failed to activate delegation with host: ${describeHostFailure2(activateResult)}`),
|
|
6611
|
-
{ cause: activateResult }
|
|
6612
|
-
);
|
|
6613
|
-
}
|
|
6614
|
-
return {
|
|
6669
|
+
const delegation = {
|
|
6615
6670
|
cid: result.cid,
|
|
6616
6671
|
delegationHeader,
|
|
6617
6672
|
spaceId: grant.session.spaceId,
|
|
@@ -6625,6 +6680,20 @@ var _TinyCloudNode = class _TinyCloudNode {
|
|
|
6625
6680
|
chainId: grant.delegation.chainId,
|
|
6626
6681
|
host: targetHost
|
|
6627
6682
|
};
|
|
6683
|
+
if (onPrepared) {
|
|
6684
|
+
await onPrepared(delegation);
|
|
6685
|
+
}
|
|
6686
|
+
const activateResult = await (0, import_sdk_core8.activateSessionWithHost)(
|
|
6687
|
+
targetHost,
|
|
6688
|
+
delegationHeader
|
|
6689
|
+
);
|
|
6690
|
+
if (!activateResult.success) {
|
|
6691
|
+
throw Object.assign(
|
|
6692
|
+
new Error(`Failed to activate delegation with host: ${describeHostFailure2(activateResult)}`),
|
|
6693
|
+
{ cause: activateResult }
|
|
6694
|
+
);
|
|
6695
|
+
}
|
|
6696
|
+
return delegation;
|
|
6628
6697
|
}
|
|
6629
6698
|
resolvePermissionSpace(space, session) {
|
|
6630
6699
|
if (space === void 0) {
|
|
@@ -6725,6 +6794,7 @@ var _TinyCloudNode = class _TinyCloudNode {
|
|
|
6725
6794
|
permissionsToAbilities(entries) {
|
|
6726
6795
|
const abilities = {};
|
|
6727
6796
|
for (const entry of entries) {
|
|
6797
|
+
if (this.isRawRevocationPermissionEntry(entry)) continue;
|
|
6728
6798
|
const service = this.shortServiceName(entry.service);
|
|
6729
6799
|
abilities[service] ?? (abilities[service] = {});
|
|
6730
6800
|
const existing = abilities[service][entry.path] ?? [];
|
|
@@ -6742,9 +6812,16 @@ var _TinyCloudNode = class _TinyCloudNode {
|
|
|
6742
6812
|
isEncryptionPermissionEntry(entry) {
|
|
6743
6813
|
return entry.service === import_sdk_core8.ENCRYPTION_PERMISSION_SERVICE && this.isEncryptionNetworkOperation("encryption", entry.path, entry.space);
|
|
6744
6814
|
}
|
|
6815
|
+
isRawRevocationPermissionEntry(entry) {
|
|
6816
|
+
return entry.service === "tinycloud.delegation" && entry.path === "" && entry.space?.startsWith("urn:cid:") === true && entry.actions.includes("tinycloud.delegation/revoke");
|
|
6817
|
+
}
|
|
6745
6818
|
permissionsToRawAbilities(entries) {
|
|
6746
6819
|
const rawAbilities = {};
|
|
6747
6820
|
for (const entry of entries) {
|
|
6821
|
+
if (this.isRawRevocationPermissionEntry(entry)) {
|
|
6822
|
+
rawAbilities[entry.space] = [...new Set(entry.actions)];
|
|
6823
|
+
continue;
|
|
6824
|
+
}
|
|
6748
6825
|
if (!this.isEncryptionPermissionEntry(entry)) {
|
|
6749
6826
|
continue;
|
|
6750
6827
|
}
|
|
@@ -6764,7 +6841,7 @@ var _TinyCloudNode = class _TinyCloudNode {
|
|
|
6764
6841
|
return entries.flatMap((entry) => {
|
|
6765
6842
|
const service = this.shortServiceName(entry.service);
|
|
6766
6843
|
return entry.actions.map((action) => ({
|
|
6767
|
-
...this.isEncryptionNetworkOperation(service, entry.path, entry.space) ? { resource: entry.path } : { spaceId },
|
|
6844
|
+
...this.isRawRevocationPermissionEntry(entry) ? { resource: entry.space } : this.isEncryptionNetworkOperation(service, entry.path, entry.space) ? { resource: entry.path } : { spaceId },
|
|
6768
6845
|
service,
|
|
6769
6846
|
path: entry.path,
|
|
6770
6847
|
action,
|
|
@@ -6774,11 +6851,13 @@ var _TinyCloudNode = class _TinyCloudNode {
|
|
|
6774
6851
|
}
|
|
6775
6852
|
/** Raw network authority cannot be covered by a nested encryption space. */
|
|
6776
6853
|
signedCapabilitySubset(requested, granted) {
|
|
6777
|
-
const rawGranted = granted.filter((entry) => this.isEncryptionPermissionEntry(entry)).map((entry) => ({ ...entry, space: "encryption" })
|
|
6778
|
-
const spaceGranted = granted.filter(
|
|
6854
|
+
const rawGranted = granted.filter((entry) => this.isEncryptionPermissionEntry(entry) || this.isRawRevocationPermissionEntry(entry)).map((entry) => this.isEncryptionPermissionEntry(entry) ? { ...entry, space: "encryption" } : entry);
|
|
6855
|
+
const spaceGranted = granted.filter(
|
|
6856
|
+
(entry) => !this.isEncryptionPermissionEntry(entry) && !this.isRawRevocationPermissionEntry(entry)
|
|
6857
|
+
);
|
|
6779
6858
|
const missing = requested.filter((entry) => {
|
|
6780
|
-
const raw = this.isEncryptionPermissionEntry(entry);
|
|
6781
|
-
const comparable = raw ? { ...entry, space: "encryption" } : entry;
|
|
6859
|
+
const raw = this.isEncryptionPermissionEntry(entry) || this.isRawRevocationPermissionEntry(entry);
|
|
6860
|
+
const comparable = raw && this.isEncryptionPermissionEntry(entry) ? { ...entry, space: "encryption" } : entry;
|
|
6782
6861
|
return !(0, import_sdk_core8.isCapabilitySubset)([comparable], raw ? rawGranted : spaceGranted).subset;
|
|
6783
6862
|
});
|
|
6784
6863
|
return { subset: missing.length === 0, missing };
|
|
@@ -6793,10 +6872,11 @@ var _TinyCloudNode = class _TinyCloudNode {
|
|
|
6793
6872
|
}
|
|
6794
6873
|
permissionEntriesToOperations(entries, session) {
|
|
6795
6874
|
return entries.flatMap((entry) => {
|
|
6796
|
-
const
|
|
6875
|
+
const rawRevocation = this.isRawRevocationPermissionEntry(entry);
|
|
6876
|
+
const spaceId = rawRevocation ? void 0 : this.resolvePermissionSpace(entry.space, session);
|
|
6797
6877
|
const service = this.shortServiceName(entry.service);
|
|
6798
6878
|
return entry.actions.map((action) => ({
|
|
6799
|
-
...this.isEncryptionNetworkOperation(service, entry.path, entry.space) ? { resource: entry.path } : { spaceId },
|
|
6879
|
+
...rawRevocation ? { resource: entry.space } : this.isEncryptionNetworkOperation(service, entry.path, entry.space) ? { resource: entry.path } : { spaceId },
|
|
6800
6880
|
service,
|
|
6801
6881
|
path: entry.path,
|
|
6802
6882
|
action,
|
|
@@ -6875,7 +6955,7 @@ var _TinyCloudNode = class _TinyCloudNode {
|
|
|
6875
6955
|
delegatedResourcesForEntries(entries, spaceId) {
|
|
6876
6956
|
return entries.map((entry) => ({
|
|
6877
6957
|
service: this.shortServiceName(entry.service),
|
|
6878
|
-
space: this.isEncryptionPermissionEntry(entry) ? "encryption" : spaceId,
|
|
6958
|
+
space: this.isRawRevocationPermissionEntry(entry) ? entry.space : this.isEncryptionPermissionEntry(entry) ? "encryption" : spaceId,
|
|
6879
6959
|
path: entry.path,
|
|
6880
6960
|
actions: [...entry.actions],
|
|
6881
6961
|
...entry.caveats === void 0 ? {} : { caveats: cloneRecapCaveats(entry.caveats) }
|
|
@@ -6885,8 +6965,9 @@ var _TinyCloudNode = class _TinyCloudNode {
|
|
|
6885
6965
|
const resources = delegation.resources !== void 0 && delegation.resources.length > 0 ? delegation.resources : this.flatDelegationResources(delegation);
|
|
6886
6966
|
return resources.flatMap((resource) => {
|
|
6887
6967
|
const service = this.invocationServiceName(resource.service);
|
|
6968
|
+
const rawRevocation = service === "delegation" && resource.space.startsWith("urn:cid:") && resource.path === "";
|
|
6888
6969
|
return resource.actions.map((action) => ({
|
|
6889
|
-
...this.isEncryptionNetworkOperation(service, resource.path, resource.space) ? { resource: resource.path } : { spaceId: resource.space },
|
|
6970
|
+
...rawRevocation ? { resource: resource.space } : this.isEncryptionNetworkOperation(service, resource.path, resource.space) ? { resource: resource.path } : { spaceId: resource.space },
|
|
6890
6971
|
service,
|
|
6891
6972
|
path: resource.path,
|
|
6892
6973
|
action,
|
|
@@ -6932,7 +7013,7 @@ var _TinyCloudNode = class _TinyCloudNode {
|
|
|
6932
7013
|
* @internal
|
|
6933
7014
|
*/
|
|
6934
7015
|
buildActivationAbilities(delegation) {
|
|
6935
|
-
var _a, _b, _c;
|
|
7016
|
+
var _a, _b, _c, _d;
|
|
6936
7017
|
const resources = delegation.resources !== void 0 && delegation.resources.length > 0 ? delegation.resources : this.flatDelegationResources(delegation);
|
|
6937
7018
|
const abilities = {};
|
|
6938
7019
|
const rawAbilities = {};
|
|
@@ -6952,13 +7033,18 @@ var _TinyCloudNode = class _TinyCloudNode {
|
|
|
6952
7033
|
addActions(rawAbilities[resource.path], resource.actions);
|
|
6953
7034
|
continue;
|
|
6954
7035
|
}
|
|
7036
|
+
if (service === "delegation" && resource.space.startsWith("urn:cid:") && resource.path === "") {
|
|
7037
|
+
rawAbilities[_b = resource.space] ?? (rawAbilities[_b] = []);
|
|
7038
|
+
addActions(rawAbilities[resource.space], resource.actions);
|
|
7039
|
+
continue;
|
|
7040
|
+
}
|
|
6955
7041
|
if (resource.space !== delegation.spaceId) {
|
|
6956
7042
|
throw new Error(
|
|
6957
7043
|
`useDelegation: resource targets space '${resource.space}' but the delegation activates space '${delegation.spaceId}'. Multi-space delegations cannot be activated in a single useDelegation call.`
|
|
6958
7044
|
);
|
|
6959
7045
|
}
|
|
6960
7046
|
abilities[service] ?? (abilities[service] = {});
|
|
6961
|
-
(
|
|
7047
|
+
(_c = abilities[service])[_d = resource.path] ?? (_c[_d] = []);
|
|
6962
7048
|
addActions(abilities[service][resource.path], resource.actions);
|
|
6963
7049
|
}
|
|
6964
7050
|
return { abilities, rawAbilities };
|
|
@@ -7030,6 +7116,9 @@ var _TinyCloudNode = class _TinyCloudNode {
|
|
|
7030
7116
|
if (grantedAction === requestedAction) {
|
|
7031
7117
|
return true;
|
|
7032
7118
|
}
|
|
7119
|
+
if ((0, import_sdk_core8.isExplicitOnlyAction)(requestedAction)) {
|
|
7120
|
+
return false;
|
|
7121
|
+
}
|
|
7033
7122
|
if (grantedAction.endsWith("/*")) {
|
|
7034
7123
|
const prefix = grantedAction.slice(0, -2);
|
|
7035
7124
|
return requestedAction.startsWith(`${prefix}/`);
|