@tinycloud/node-sdk 2.11.0-beta.10 → 2.11.0-beta.11
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/{core-BypriIWK.d.cts → core-9mWw3N8i.d.cts} +30 -7
- package/dist/{core-BypriIWK.d.ts → core-9mWw3N8i.d.ts} +30 -7
- package/dist/core.cjs +180 -67
- 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 +189 -72
- package/dist/core.js.map +1 -1
- package/dist/index.cjs +186 -67
- 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 +192 -72
- package/dist/index.js.map +1 -1
- package/package.json +3 -3
|
@@ -239,7 +239,7 @@ interface NodeUserAuthorizationConfig {
|
|
|
239
239
|
manifest?: Manifest | Manifest[];
|
|
240
240
|
/** Pre-composed manifest request. Takes precedence over `manifest`. */
|
|
241
241
|
capabilityRequest?: ComposedManifestRequest;
|
|
242
|
-
/** Include
|
|
242
|
+
/** Include canonical account registry read/create-update/list permissions when composing `manifest` and plain sign-in. Default true. */
|
|
243
243
|
includeAccountRegistryPermissions?: boolean;
|
|
244
244
|
}
|
|
245
245
|
interface CreateBootstrapSessionOptions {
|
|
@@ -975,6 +975,9 @@ declare class DelegatedAccess {
|
|
|
975
975
|
* ```
|
|
976
976
|
*/
|
|
977
977
|
|
|
978
|
+
declare const BOOTSTRAP_COMPLETION_MARKER_KEY = "system/bootstrap/complete";
|
|
979
|
+
declare const BOOTSTRAP_COMPLETION_MARKER_VERSION = 1;
|
|
980
|
+
declare const ACCEPTED_MARKER_VERSIONS: readonly number[];
|
|
978
981
|
/** Input for {@link TinyCloudNode.readSecret}. The target space is required. */
|
|
979
982
|
interface SecretReadInput {
|
|
980
983
|
/** Explicit full space URI or an owned-space name. */
|
|
@@ -1104,7 +1107,7 @@ interface TinyCloudNodeConfig {
|
|
|
1104
1107
|
manifest?: Manifest | Manifest[];
|
|
1105
1108
|
/** Pre-composed manifest request. Takes precedence over `manifest`. */
|
|
1106
1109
|
capabilityRequest?: ComposedManifestRequest;
|
|
1107
|
-
/** Include
|
|
1110
|
+
/** Include account bootstrap support in plain sessions and implicit manifest permissions. Default true. */
|
|
1108
1111
|
includeAccountRegistryPermissions?: boolean;
|
|
1109
1112
|
/** Run canonical first-account bootstrap when fresh account state is detected. Default true. */
|
|
1110
1113
|
autoBootstrapAccount?: boolean;
|
|
@@ -1190,6 +1193,12 @@ interface BootstrapWarning {
|
|
|
1190
1193
|
/** Human-readable detail. Diagnostics only — never parse this. */
|
|
1191
1194
|
message: string;
|
|
1192
1195
|
}
|
|
1196
|
+
/** Durable attestation that the canonical account bootstrap ceremony completed. */
|
|
1197
|
+
interface BootstrapCompletionMarker {
|
|
1198
|
+
v: number;
|
|
1199
|
+
stepIds: string[];
|
|
1200
|
+
completedAt: string;
|
|
1201
|
+
}
|
|
1193
1202
|
declare class TinyCloudNode {
|
|
1194
1203
|
/** @internal Registered by importing @tinycloud/node-sdk (not /core) */
|
|
1195
1204
|
private static nodeDefaults?;
|
|
@@ -1258,9 +1267,12 @@ declare class TinyCloudNode {
|
|
|
1258
1267
|
private _bootstrapSkipped;
|
|
1259
1268
|
/**
|
|
1260
1269
|
* Outcome of the last signIn()'s account-bootstrap attempt. `skipped` is
|
|
1261
|
-
* true when bootstrap did not complete (interactive signer,
|
|
1262
|
-
*
|
|
1263
|
-
*
|
|
1270
|
+
* true when bootstrap did not complete in this invocation (interactive signer,
|
|
1271
|
+
* auto-bootstrap disabled, already provisioned, or a decision/provisioning
|
|
1272
|
+
* step failed). `already-provisioned` means the bootstrap was not run here;
|
|
1273
|
+
* it does not mean a prior provisioning attempt failed to complete.
|
|
1274
|
+
* `reason` carries the cause so apps can surface a "finish account setup"
|
|
1275
|
+
* call-to-action. `warnings` is
|
|
1264
1276
|
* present when bootstrap completed, but one or more steps recovered from
|
|
1265
1277
|
* an ambiguous failure (e.g. a KV batch write reconciled via per-space
|
|
1266
1278
|
* fallback) — clean vs. recovered runs are otherwise byte-identical.
|
|
@@ -1396,7 +1408,11 @@ declare class TinyCloudNode {
|
|
|
1396
1408
|
signIn(options?: SignInOptions): Promise<void>;
|
|
1397
1409
|
private ownedSpaceId;
|
|
1398
1410
|
private bootstrapAccountIfNeeded;
|
|
1399
|
-
private
|
|
1411
|
+
private resolveBootstrapDecision;
|
|
1412
|
+
private readBootstrapCompletionMarker;
|
|
1413
|
+
private writeBootstrapCompletionMarker;
|
|
1414
|
+
private isAcceptedBootstrapCompletionMarker;
|
|
1415
|
+
private markerReadIsUnhostedSpace;
|
|
1400
1416
|
private runAccountBootstrap;
|
|
1401
1417
|
private registerBootstrapRuntimeGrant;
|
|
1402
1418
|
/**
|
|
@@ -2301,6 +2317,13 @@ declare class TinyCloudNode {
|
|
|
2301
2317
|
disableSubDelegation?: boolean;
|
|
2302
2318
|
/** Expiration time in milliseconds from now (must be before parent's expiry) */
|
|
2303
2319
|
expiryMs?: number;
|
|
2320
|
+
/** Explicit multi-resource projection, including encryption networks. */
|
|
2321
|
+
resources?: Array<{
|
|
2322
|
+
service: string;
|
|
2323
|
+
space?: string;
|
|
2324
|
+
path: string;
|
|
2325
|
+
actions: string[];
|
|
2326
|
+
}>;
|
|
2304
2327
|
}): Promise<PortableDelegation>;
|
|
2305
2328
|
}
|
|
2306
2329
|
|
|
@@ -2412,4 +2435,4 @@ declare class WasmKeyProvider implements KeyProvider {
|
|
|
2412
2435
|
*/
|
|
2413
2436
|
declare function createWasmKeyProvider(sessionManager: SessionManagerWithListing): WasmKeyProvider;
|
|
2414
2437
|
|
|
2415
|
-
export {
|
|
2438
|
+
export { ACCEPTED_MARKER_VERSIONS as A, BOOTSTRAP_COMPLETION_MARKER_KEY as B, type CreateOwnerDelegationParams as C, type DelegateToOptions as D, type EnsureEncryptionNetworkOptions as E, FileSessionStorage as F, MemorySessionStorage as M, type NodeEventEmitterStrategy as N, type OwnerDelegationReceipt as O, type PortableDelegation as P, type RestorableSession as R, type SecretPermissionHint as S, TinyCloudNode as T, UnsupportedSessionRestoreError as U, type ValidatedRuntimeDelegation as V, WasmKeyProvider as W, type AuthDelegationArtifact as a, type AuthRequestArtifact as b, BOOTSTRAP_COMPLETION_MARKER_VERSION as c, type BootstrapCompletionMarker as d, type BootstrapWarning as e, type DelegateToResult as f, DelegatedAccess as g, type DelegationAuthority as h, NodeUserAuthorization as i, type NodeUserAuthorizationConfig as j, type RuntimeDelegationActivator as k, type RuntimePermissionGrantOptions as l, type SecretReadInput as m, type SecretReadResult as n, type SignStrategy as o, type TinyCloudNodeConfig as p, type WasmKeyProviderConfig as q, activateValidatedRuntimeDelegation as r, createWasmKeyProvider as s, defaultSignStrategy as t, deserializeDelegation as u, grantAuthRequest as v, serializeDelegation as w };
|
|
@@ -239,7 +239,7 @@ interface NodeUserAuthorizationConfig {
|
|
|
239
239
|
manifest?: Manifest | Manifest[];
|
|
240
240
|
/** Pre-composed manifest request. Takes precedence over `manifest`. */
|
|
241
241
|
capabilityRequest?: ComposedManifestRequest;
|
|
242
|
-
/** Include
|
|
242
|
+
/** Include canonical account registry read/create-update/list permissions when composing `manifest` and plain sign-in. Default true. */
|
|
243
243
|
includeAccountRegistryPermissions?: boolean;
|
|
244
244
|
}
|
|
245
245
|
interface CreateBootstrapSessionOptions {
|
|
@@ -975,6 +975,9 @@ declare class DelegatedAccess {
|
|
|
975
975
|
* ```
|
|
976
976
|
*/
|
|
977
977
|
|
|
978
|
+
declare const BOOTSTRAP_COMPLETION_MARKER_KEY = "system/bootstrap/complete";
|
|
979
|
+
declare const BOOTSTRAP_COMPLETION_MARKER_VERSION = 1;
|
|
980
|
+
declare const ACCEPTED_MARKER_VERSIONS: readonly number[];
|
|
978
981
|
/** Input for {@link TinyCloudNode.readSecret}. The target space is required. */
|
|
979
982
|
interface SecretReadInput {
|
|
980
983
|
/** Explicit full space URI or an owned-space name. */
|
|
@@ -1104,7 +1107,7 @@ interface TinyCloudNodeConfig {
|
|
|
1104
1107
|
manifest?: Manifest | Manifest[];
|
|
1105
1108
|
/** Pre-composed manifest request. Takes precedence over `manifest`. */
|
|
1106
1109
|
capabilityRequest?: ComposedManifestRequest;
|
|
1107
|
-
/** Include
|
|
1110
|
+
/** Include account bootstrap support in plain sessions and implicit manifest permissions. Default true. */
|
|
1108
1111
|
includeAccountRegistryPermissions?: boolean;
|
|
1109
1112
|
/** Run canonical first-account bootstrap when fresh account state is detected. Default true. */
|
|
1110
1113
|
autoBootstrapAccount?: boolean;
|
|
@@ -1190,6 +1193,12 @@ interface BootstrapWarning {
|
|
|
1190
1193
|
/** Human-readable detail. Diagnostics only — never parse this. */
|
|
1191
1194
|
message: string;
|
|
1192
1195
|
}
|
|
1196
|
+
/** Durable attestation that the canonical account bootstrap ceremony completed. */
|
|
1197
|
+
interface BootstrapCompletionMarker {
|
|
1198
|
+
v: number;
|
|
1199
|
+
stepIds: string[];
|
|
1200
|
+
completedAt: string;
|
|
1201
|
+
}
|
|
1193
1202
|
declare class TinyCloudNode {
|
|
1194
1203
|
/** @internal Registered by importing @tinycloud/node-sdk (not /core) */
|
|
1195
1204
|
private static nodeDefaults?;
|
|
@@ -1258,9 +1267,12 @@ declare class TinyCloudNode {
|
|
|
1258
1267
|
private _bootstrapSkipped;
|
|
1259
1268
|
/**
|
|
1260
1269
|
* Outcome of the last signIn()'s account-bootstrap attempt. `skipped` is
|
|
1261
|
-
* true when bootstrap did not complete (interactive signer,
|
|
1262
|
-
*
|
|
1263
|
-
*
|
|
1270
|
+
* true when bootstrap did not complete in this invocation (interactive signer,
|
|
1271
|
+
* auto-bootstrap disabled, already provisioned, or a decision/provisioning
|
|
1272
|
+
* step failed). `already-provisioned` means the bootstrap was not run here;
|
|
1273
|
+
* it does not mean a prior provisioning attempt failed to complete.
|
|
1274
|
+
* `reason` carries the cause so apps can surface a "finish account setup"
|
|
1275
|
+
* call-to-action. `warnings` is
|
|
1264
1276
|
* present when bootstrap completed, but one or more steps recovered from
|
|
1265
1277
|
* an ambiguous failure (e.g. a KV batch write reconciled via per-space
|
|
1266
1278
|
* fallback) — clean vs. recovered runs are otherwise byte-identical.
|
|
@@ -1396,7 +1408,11 @@ declare class TinyCloudNode {
|
|
|
1396
1408
|
signIn(options?: SignInOptions): Promise<void>;
|
|
1397
1409
|
private ownedSpaceId;
|
|
1398
1410
|
private bootstrapAccountIfNeeded;
|
|
1399
|
-
private
|
|
1411
|
+
private resolveBootstrapDecision;
|
|
1412
|
+
private readBootstrapCompletionMarker;
|
|
1413
|
+
private writeBootstrapCompletionMarker;
|
|
1414
|
+
private isAcceptedBootstrapCompletionMarker;
|
|
1415
|
+
private markerReadIsUnhostedSpace;
|
|
1400
1416
|
private runAccountBootstrap;
|
|
1401
1417
|
private registerBootstrapRuntimeGrant;
|
|
1402
1418
|
/**
|
|
@@ -2301,6 +2317,13 @@ declare class TinyCloudNode {
|
|
|
2301
2317
|
disableSubDelegation?: boolean;
|
|
2302
2318
|
/** Expiration time in milliseconds from now (must be before parent's expiry) */
|
|
2303
2319
|
expiryMs?: number;
|
|
2320
|
+
/** Explicit multi-resource projection, including encryption networks. */
|
|
2321
|
+
resources?: Array<{
|
|
2322
|
+
service: string;
|
|
2323
|
+
space?: string;
|
|
2324
|
+
path: string;
|
|
2325
|
+
actions: string[];
|
|
2326
|
+
}>;
|
|
2304
2327
|
}): Promise<PortableDelegation>;
|
|
2305
2328
|
}
|
|
2306
2329
|
|
|
@@ -2412,4 +2435,4 @@ declare class WasmKeyProvider implements KeyProvider {
|
|
|
2412
2435
|
*/
|
|
2413
2436
|
declare function createWasmKeyProvider(sessionManager: SessionManagerWithListing): WasmKeyProvider;
|
|
2414
2437
|
|
|
2415
|
-
export {
|
|
2438
|
+
export { ACCEPTED_MARKER_VERSIONS as A, BOOTSTRAP_COMPLETION_MARKER_KEY as B, type CreateOwnerDelegationParams as C, type DelegateToOptions as D, type EnsureEncryptionNetworkOptions as E, FileSessionStorage as F, MemorySessionStorage as M, type NodeEventEmitterStrategy as N, type OwnerDelegationReceipt as O, type PortableDelegation as P, type RestorableSession as R, type SecretPermissionHint as S, TinyCloudNode as T, UnsupportedSessionRestoreError as U, type ValidatedRuntimeDelegation as V, WasmKeyProvider as W, type AuthDelegationArtifact as a, type AuthRequestArtifact as b, BOOTSTRAP_COMPLETION_MARKER_VERSION as c, type BootstrapCompletionMarker as d, type BootstrapWarning as e, type DelegateToResult as f, DelegatedAccess as g, type DelegationAuthority as h, NodeUserAuthorization as i, type NodeUserAuthorizationConfig as j, type RuntimeDelegationActivator as k, type RuntimePermissionGrantOptions as l, type SecretReadInput as m, type SecretReadResult as n, type SignStrategy as o, type TinyCloudNodeConfig as p, type WasmKeyProviderConfig as q, activateValidatedRuntimeDelegation as r, createWasmKeyProvider as s, defaultSignStrategy as t, deserializeDelegation as u, grantAuthRequest as v, serializeDelegation as w };
|
package/dist/core.cjs
CHANGED
|
@@ -371,6 +371,16 @@ function addRawAbility(rawAbilities, resource, action) {
|
|
|
371
371
|
actions.push(action);
|
|
372
372
|
}
|
|
373
373
|
}
|
|
374
|
+
function cloneAbilitiesMap(actions) {
|
|
375
|
+
return Object.fromEntries(
|
|
376
|
+
Object.entries(actions).map(([service, paths]) => [
|
|
377
|
+
service,
|
|
378
|
+
Object.fromEntries(
|
|
379
|
+
Object.entries(paths).map(([path, pathActions]) => [path, [...pathActions]])
|
|
380
|
+
)
|
|
381
|
+
])
|
|
382
|
+
);
|
|
383
|
+
}
|
|
374
384
|
var NodeUserAuthorization = class {
|
|
375
385
|
constructor(config) {
|
|
376
386
|
this.activeSessionKeyId = "default";
|
|
@@ -642,23 +652,41 @@ var NodeUserAuthorization = class {
|
|
|
642
652
|
const defaultNetworkId = this.defaultEncryptionNetworkId(address, chainId);
|
|
643
653
|
const primarySpaceId2 = (0, import_sdk_core3.makePkhSpaceId)(address, chainId, this.spacePrefix);
|
|
644
654
|
const secretsSpaceId = (0, import_sdk_core3.makePkhSpaceId)(address, chainId, "secrets");
|
|
645
|
-
|
|
646
|
-
|
|
647
|
-
|
|
648
|
-
|
|
649
|
-
|
|
650
|
-
|
|
651
|
-
|
|
652
|
-
|
|
653
|
-
|
|
654
|
-
|
|
655
|
-
|
|
656
|
-
|
|
657
|
-
|
|
658
|
-
|
|
655
|
+
const primaryActions = this.includeAccountRegistryPermissions && this.spacePrefix === import_sdk_core3.ACCOUNT_REGISTRY_SPACE ? cloneAbilitiesMap(this.defaultActions) : this.defaultActions;
|
|
656
|
+
const spaceAbilities2 = {
|
|
657
|
+
[primarySpaceId2]: primaryActions,
|
|
658
|
+
[secretsSpaceId]: {
|
|
659
|
+
kv: {
|
|
660
|
+
"vault/secrets/": [
|
|
661
|
+
import_sdk_core3.KV.GET,
|
|
662
|
+
import_sdk_core3.KV.PUT,
|
|
663
|
+
import_sdk_core3.KV.DEL,
|
|
664
|
+
import_sdk_core3.KV.LIST,
|
|
665
|
+
import_sdk_core3.KV.METADATA
|
|
666
|
+
]
|
|
667
|
+
}
|
|
668
|
+
}
|
|
669
|
+
};
|
|
670
|
+
if (this.includeAccountRegistryPermissions && this.spacePrefix !== import_sdk_core3.ACCOUNT_REGISTRY_SPACE) {
|
|
671
|
+
spaceAbilities2[(0, import_sdk_core3.makePkhSpaceId)(address, chainId, import_sdk_core3.ACCOUNT_REGISTRY_SPACE)] = (0, import_sdk_core3.resourceCapabilitiesToAbilitiesMap)(import_sdk_core3.ACCOUNT_MANIFEST_PERMISSIONS);
|
|
672
|
+
} else if (this.includeAccountRegistryPermissions) {
|
|
673
|
+
const accountAbilities = (0, import_sdk_core3.resourceCapabilitiesToAbilitiesMap)(
|
|
674
|
+
import_sdk_core3.ACCOUNT_MANIFEST_PERMISSIONS
|
|
675
|
+
);
|
|
676
|
+
for (const [service, paths] of Object.entries(accountAbilities)) {
|
|
677
|
+
const existingPaths = primaryActions[service] ?? (primaryActions[service] = {});
|
|
678
|
+
for (const [path, actions] of Object.entries(paths)) {
|
|
679
|
+
const existingActions = existingPaths[path] ?? (existingPaths[path] = []);
|
|
680
|
+
for (const action of actions) {
|
|
681
|
+
if (!existingActions.includes(action)) existingActions.push(action);
|
|
659
682
|
}
|
|
660
683
|
}
|
|
661
|
-
}
|
|
684
|
+
}
|
|
685
|
+
}
|
|
686
|
+
return {
|
|
687
|
+
abilities: primaryActions,
|
|
688
|
+
spaceId: primarySpaceId2,
|
|
689
|
+
spaceAbilities: spaceAbilities2,
|
|
662
690
|
rawAbilities: {
|
|
663
691
|
[defaultNetworkId]: [DECRYPT_ACTION, NETWORK_CREATE_ACTION]
|
|
664
692
|
}
|
|
@@ -2125,6 +2153,9 @@ var DEFAULT_HOST = "https://node.tinycloud.xyz";
|
|
|
2125
2153
|
var DEFAULT_ENCRYPTION_NETWORK_NAME = "default";
|
|
2126
2154
|
var NETWORK_CREATE_ACTION2 = import_sdk_core8.ENCRYPTION.NETWORK_CREATE;
|
|
2127
2155
|
var DECRYPT_ACTION2 = import_sdk_core8.ENCRYPTION.DECRYPT;
|
|
2156
|
+
var BOOTSTRAP_COMPLETION_MARKER_KEY = "system/bootstrap/complete";
|
|
2157
|
+
var BOOTSTRAP_COMPLETION_MARKER_VERSION = 1;
|
|
2158
|
+
var ACCEPTED_MARKER_VERSIONS = [BOOTSTRAP_COMPLETION_MARKER_VERSION];
|
|
2128
2159
|
var NETWORK_ADMIN_TYPE = "tinycloud.encryption.network-admin/v1";
|
|
2129
2160
|
function isSecretPayload(value) {
|
|
2130
2161
|
return typeof value === "object" && value !== null && "value" in value && typeof value.value === "string" && "createdAt" in value && typeof value.createdAt === "string" && "updatedAt" in value && typeof value.updatedAt === "string";
|
|
@@ -2532,9 +2563,12 @@ var _TinyCloudNode = class _TinyCloudNode {
|
|
|
2532
2563
|
this._bootstrapSkipped = false;
|
|
2533
2564
|
/**
|
|
2534
2565
|
* Outcome of the last signIn()'s account-bootstrap attempt. `skipped` is
|
|
2535
|
-
* true when bootstrap did not complete (interactive signer,
|
|
2536
|
-
*
|
|
2537
|
-
*
|
|
2566
|
+
* true when bootstrap did not complete in this invocation (interactive signer,
|
|
2567
|
+
* auto-bootstrap disabled, already provisioned, or a decision/provisioning
|
|
2568
|
+
* step failed). `already-provisioned` means the bootstrap was not run here;
|
|
2569
|
+
* it does not mean a prior provisioning attempt failed to complete.
|
|
2570
|
+
* `reason` carries the cause so apps can surface a "finish account setup"
|
|
2571
|
+
* call-to-action. `warnings` is
|
|
2538
2572
|
* present when bootstrap completed, but one or more steps recovered from
|
|
2539
2573
|
* an ambiguous failure (e.g. a KV batch write reconciled via per-space
|
|
2540
2574
|
* fallback) — clean vs. recovered runs are otherwise byte-identical.
|
|
@@ -2717,7 +2751,7 @@ var _TinyCloudNode = class _TinyCloudNode {
|
|
|
2717
2751
|
nonce: config.nonce,
|
|
2718
2752
|
siweConfig: config.siweConfig,
|
|
2719
2753
|
manifest: useBootstrapSignInRequest ? void 0 : config.manifest,
|
|
2720
|
-
capabilityRequest: useBootstrapSignInRequest ? import_sdk_core8.BOOTSTRAP_SESSION_REQUESTS.default : config.capabilityRequest,
|
|
2754
|
+
capabilityRequest: useBootstrapSignInRequest ? config.includeAccountRegistryPermissions === false ? import_sdk_core8.BOOTSTRAP_DEFAULT_ONLY_SESSION_REQUEST : import_sdk_core8.BOOTSTRAP_SESSION_REQUESTS.default : config.capabilityRequest,
|
|
2721
2755
|
includeAccountRegistryPermissions: useBootstrapSignInRequest ? false : config.includeAccountRegistryPermissions
|
|
2722
2756
|
});
|
|
2723
2757
|
this.tc = new import_sdk_core8.TinyCloud(this.auth, {
|
|
@@ -2960,6 +2994,7 @@ var _TinyCloudNode = class _TinyCloudNode {
|
|
|
2960
2994
|
this._bootstrapSkipped = false;
|
|
2961
2995
|
this._bootstrapStatus = { skipped: false };
|
|
2962
2996
|
if (this.config.autoBootstrapAccount === false) {
|
|
2997
|
+
this._bootstrapStatus = { skipped: true, reason: "auto-bootstrap-disabled" };
|
|
2963
2998
|
return false;
|
|
2964
2999
|
}
|
|
2965
3000
|
if (!this.auth || !this._address) {
|
|
@@ -2974,11 +3009,14 @@ var _TinyCloudNode = class _TinyCloudNode {
|
|
|
2974
3009
|
return false;
|
|
2975
3010
|
}
|
|
2976
3011
|
const steps = (0, import_sdk_core8.bootstrapSteps)(this._address, this._chainId);
|
|
2977
|
-
if (!await this.isFreshBootstrapAccount(steps)) {
|
|
2978
|
-
return false;
|
|
2979
|
-
}
|
|
2980
3012
|
try {
|
|
2981
|
-
const
|
|
3013
|
+
const decision = await this.resolveBootstrapDecision(steps);
|
|
3014
|
+
if (decision.action === "skip") {
|
|
3015
|
+
this._bootstrapStatus = { skipped: true, reason: "already-provisioned" };
|
|
3016
|
+
return false;
|
|
3017
|
+
}
|
|
3018
|
+
const warnings = await this.runAccountBootstrap(steps, { mode: decision.mode });
|
|
3019
|
+
await this.writeBootstrapCompletionMarker(steps);
|
|
2982
3020
|
if (warnings.length > 0) {
|
|
2983
3021
|
this._bootstrapStatus = { skipped: false, warnings };
|
|
2984
3022
|
this.notificationHandler.warning(
|
|
@@ -2997,32 +3035,92 @@ var _TinyCloudNode = class _TinyCloudNode {
|
|
|
2997
3035
|
}
|
|
2998
3036
|
return true;
|
|
2999
3037
|
}
|
|
3000
|
-
async
|
|
3038
|
+
async resolveBootstrapDecision(steps) {
|
|
3001
3039
|
const enshrinedSpaceIds = /* @__PURE__ */ new Set();
|
|
3002
3040
|
for (const step of steps) {
|
|
3003
3041
|
if (step.kind === "session") {
|
|
3004
3042
|
enshrinedSpaceIds.add(step.spaceId);
|
|
3005
3043
|
}
|
|
3006
3044
|
}
|
|
3007
|
-
const
|
|
3045
|
+
const auth = this.auth;
|
|
3046
|
+
if (!auth) {
|
|
3047
|
+
throw new Error("Account bootstrap requires an active wallet session");
|
|
3048
|
+
}
|
|
3049
|
+
const skipped = auth.lastActivationSkippedSpaceIds;
|
|
3008
3050
|
if (skipped.some((spaceId) => enshrinedSpaceIds.has(spaceId))) {
|
|
3009
|
-
return
|
|
3051
|
+
return { action: "run", mode: "fresh" };
|
|
3010
3052
|
}
|
|
3011
3053
|
try {
|
|
3012
|
-
const
|
|
3013
|
-
|
|
3014
|
-
|
|
3054
|
+
const accountSpaceId = this.ownedSpaceId(import_sdk_core8.ACCOUNT_REGISTRY_SPACE);
|
|
3055
|
+
const markerPermission = {
|
|
3056
|
+
service: "tinycloud.kv",
|
|
3057
|
+
space: accountSpaceId,
|
|
3058
|
+
path: BOOTSTRAP_COMPLETION_MARKER_KEY,
|
|
3059
|
+
actions: ["get"]
|
|
3060
|
+
};
|
|
3061
|
+
if (!this.hasRuntimePermissions([markerPermission])) {
|
|
3062
|
+
return { action: "run", mode: "repair" };
|
|
3015
3063
|
}
|
|
3016
|
-
|
|
3064
|
+
const marker = await this.readBootstrapCompletionMarker();
|
|
3065
|
+
if (marker.ok) {
|
|
3066
|
+
if (this.isAcceptedBootstrapCompletionMarker(marker.data.data)) {
|
|
3067
|
+
return { action: "skip" };
|
|
3068
|
+
}
|
|
3069
|
+
return { action: "run", mode: "repair" };
|
|
3070
|
+
}
|
|
3071
|
+
if (marker.error.code === import_sdk_core8.ErrorCodes.KV_NOT_FOUND && this.markerReadIsUnhostedSpace(marker.error.meta)) {
|
|
3072
|
+
return { action: "run", mode: "fresh" };
|
|
3073
|
+
}
|
|
3074
|
+
} catch (err) {
|
|
3075
|
+
const reason = err instanceof Error ? err.message : String(err);
|
|
3076
|
+
this.notificationHandler.warning(
|
|
3077
|
+
`Account bootstrap decision failed; attempting one bounded repair: ${reason}`
|
|
3078
|
+
);
|
|
3079
|
+
console.warn(`[TinyCloudNode] account bootstrap decision failed: ${reason}`);
|
|
3080
|
+
return { action: "run", mode: "repair" };
|
|
3017
3081
|
}
|
|
3018
|
-
|
|
3019
|
-
|
|
3020
|
-
|
|
3021
|
-
|
|
3022
|
-
|
|
3082
|
+
return { action: "run", mode: "repair" };
|
|
3083
|
+
}
|
|
3084
|
+
async readBootstrapCompletionMarker() {
|
|
3085
|
+
return this.kvForSpace(this.ownedSpaceId(import_sdk_core8.ACCOUNT_REGISTRY_SPACE)).get(
|
|
3086
|
+
BOOTSTRAP_COMPLETION_MARKER_KEY
|
|
3087
|
+
);
|
|
3088
|
+
}
|
|
3089
|
+
async writeBootstrapCompletionMarker(steps) {
|
|
3090
|
+
if (!this._address) {
|
|
3091
|
+
throw new Error("Bootstrap completion marker requires an active wallet session");
|
|
3023
3092
|
}
|
|
3093
|
+
const canonicalStepIds = new Set(
|
|
3094
|
+
(0, import_sdk_core8.bootstrapSteps)(this._address, this._chainId).map((step) => step.id)
|
|
3095
|
+
);
|
|
3096
|
+
const providedStepIds = new Set(steps.map((step) => step.id));
|
|
3097
|
+
if (canonicalStepIds.size !== providedStepIds.size || [...canonicalStepIds].some((stepId) => !providedStepIds.has(stepId))) {
|
|
3098
|
+
throw new Error("Bootstrap completion marker requires the canonical bootstrap step set");
|
|
3099
|
+
}
|
|
3100
|
+
const marker = {
|
|
3101
|
+
v: BOOTSTRAP_COMPLETION_MARKER_VERSION,
|
|
3102
|
+
stepIds: [...canonicalStepIds],
|
|
3103
|
+
completedAt: (/* @__PURE__ */ new Date()).toISOString()
|
|
3104
|
+
};
|
|
3105
|
+
const written = await this.kvForSpace(this.ownedSpaceId(import_sdk_core8.ACCOUNT_REGISTRY_SPACE)).put(
|
|
3106
|
+
BOOTSTRAP_COMPLETION_MARKER_KEY,
|
|
3107
|
+
marker
|
|
3108
|
+
);
|
|
3109
|
+
if (!written.ok) {
|
|
3110
|
+
throw new Error(`Failed to write bootstrap completion marker: ${written.error.message}`);
|
|
3111
|
+
}
|
|
3112
|
+
}
|
|
3113
|
+
isAcceptedBootstrapCompletionMarker(value) {
|
|
3114
|
+
if (typeof value !== "object" || value === null) return false;
|
|
3115
|
+
const entries = Object.entries(value);
|
|
3116
|
+
const markerValue = (name) => entries.find(([key]) => key === name)?.[1];
|
|
3117
|
+
const version = markerValue("v");
|
|
3118
|
+
return typeof version === "number" && Number.isInteger(version) && ACCEPTED_MARKER_VERSIONS.some((acceptedVersion) => acceptedVersion === version);
|
|
3119
|
+
}
|
|
3120
|
+
markerReadIsUnhostedSpace(meta) {
|
|
3121
|
+
return meta?.status === 404;
|
|
3024
3122
|
}
|
|
3025
|
-
async runAccountBootstrap(steps) {
|
|
3123
|
+
async runAccountBootstrap(steps, { mode } = { mode: "fresh" }) {
|
|
3026
3124
|
if (!this.auth || !this._address) {
|
|
3027
3125
|
throw new Error("Account bootstrap requires an active wallet session");
|
|
3028
3126
|
}
|
|
@@ -3123,9 +3221,8 @@ var _TinyCloudNode = class _TinyCloudNode {
|
|
|
3123
3221
|
if (step.kind === "seed-applications") {
|
|
3124
3222
|
const registered = await this.account.applications.register(
|
|
3125
3223
|
step.manifests.length > 0 ? [...step.manifests] : import_sdk_core8.TINYCLOUD_SECRETS_BOOTSTRAP_MANIFEST,
|
|
3126
|
-
//
|
|
3127
|
-
// manifest-hash pre-read
|
|
3128
|
-
// it guards is an INSERT OR REPLACE and is safe to repeat.
|
|
3224
|
+
// The write is an INSERT OR REPLACE and is safe to repeat during a
|
|
3225
|
+
// repair, so skip the manifest-hash pre-read.
|
|
3129
3226
|
{ assumeUnregistered: true }
|
|
3130
3227
|
);
|
|
3131
3228
|
if (!registered.ok) {
|
|
@@ -3133,7 +3230,7 @@ var _TinyCloudNode = class _TinyCloudNode {
|
|
|
3133
3230
|
}
|
|
3134
3231
|
}
|
|
3135
3232
|
if (step.kind === "encryption-network-create") {
|
|
3136
|
-
await this.ensureEncryptionNetwork(step.networkId, { assumeMissing:
|
|
3233
|
+
await this.ensureEncryptionNetwork(step.networkId, { assumeMissing: mode === "fresh" });
|
|
3137
3234
|
}
|
|
3138
3235
|
if (step.kind === "secret-records-schema") {
|
|
3139
3236
|
const db = this.sqlForSpace(step.spaceId).db(step.database);
|
|
@@ -4182,7 +4279,7 @@ var _TinyCloudNode = class _TinyCloudNode {
|
|
|
4182
4279
|
nonce: this.config.nonce,
|
|
4183
4280
|
siweConfig: this.config.siweConfig,
|
|
4184
4281
|
manifest: useBootstrapSignInRequest ? void 0 : this.config.manifest,
|
|
4185
|
-
capabilityRequest: useBootstrapSignInRequest ? import_sdk_core8.BOOTSTRAP_SESSION_REQUESTS.default : this.config.capabilityRequest,
|
|
4282
|
+
capabilityRequest: useBootstrapSignInRequest ? this.config.includeAccountRegistryPermissions === false ? import_sdk_core8.BOOTSTRAP_DEFAULT_ONLY_SESSION_REQUEST : import_sdk_core8.BOOTSTRAP_SESSION_REQUESTS.default : this.config.capabilityRequest,
|
|
4186
4283
|
includeAccountRegistryPermissions: useBootstrapSignInRequest ? false : this.config.includeAccountRegistryPermissions
|
|
4187
4284
|
});
|
|
4188
4285
|
this.tc = new import_sdk_core8.TinyCloud(this.auth, {
|
|
@@ -4235,7 +4332,7 @@ var _TinyCloudNode = class _TinyCloudNode {
|
|
|
4235
4332
|
nonce: this.config.nonce,
|
|
4236
4333
|
siweConfig: this.config.siweConfig,
|
|
4237
4334
|
manifest: useBootstrapSignInRequest ? void 0 : this.config.manifest,
|
|
4238
|
-
capabilityRequest: useBootstrapSignInRequest ? import_sdk_core8.BOOTSTRAP_SESSION_REQUESTS.default : this.config.capabilityRequest,
|
|
4335
|
+
capabilityRequest: useBootstrapSignInRequest ? this.config.includeAccountRegistryPermissions === false ? import_sdk_core8.BOOTSTRAP_DEFAULT_ONLY_SESSION_REQUEST : import_sdk_core8.BOOTSTRAP_SESSION_REQUESTS.default : this.config.capabilityRequest,
|
|
4239
4336
|
includeAccountRegistryPermissions: useBootstrapSignInRequest ? false : this.config.includeAccountRegistryPermissions
|
|
4240
4337
|
});
|
|
4241
4338
|
this.tc = new import_sdk_core8.TinyCloud(this.auth, {
|
|
@@ -6984,35 +7081,44 @@ var _TinyCloudNode = class _TinyCloudNode {
|
|
|
6984
7081
|
if (parentDelegation.disableSubDelegation) {
|
|
6985
7082
|
throw new Error("Parent delegation does not allow sub-delegation");
|
|
6986
7083
|
}
|
|
6987
|
-
|
|
7084
|
+
const parentResources = parentDelegation.resources ?? [{
|
|
7085
|
+
service: parentDelegation.actions[0]?.split("/", 1)[0]?.replace(/^tinycloud\./, "") ?? "kv",
|
|
7086
|
+
space: parentDelegation.spaceId,
|
|
7087
|
+
path: parentDelegation.path,
|
|
7088
|
+
actions: parentDelegation.actions
|
|
7089
|
+
}];
|
|
7090
|
+
const requestedResources = params.resources ?? [{
|
|
7091
|
+
service: params.actions[0]?.split("/", 1)[0]?.replace(/^tinycloud\./, "") ?? "kv",
|
|
7092
|
+
space: parentDelegation.spaceId,
|
|
7093
|
+
path: params.path,
|
|
7094
|
+
actions: params.actions
|
|
7095
|
+
}];
|
|
7096
|
+
const resourceIsContained = (parent, child) => {
|
|
7097
|
+
const parentEncryption = parent.service === "encryption" || parent.service === "tinycloud.encryption";
|
|
7098
|
+
const childEncryption = child.service === "encryption" || child.service === "tinycloud.encryption";
|
|
7099
|
+
if (parentEncryption || childEncryption) return parentEncryption && childEncryption && parent.path === child.path && child.actions.every((action) => parent.actions.includes(action));
|
|
7100
|
+
const pathContained = parent.path === child.path || parent.path.endsWith("/") && child.path.startsWith(parent.path) || child.path.startsWith(`${parent.path}/`);
|
|
7101
|
+
return pathContained && child.actions.every((action) => parent.actions.includes(action));
|
|
7102
|
+
};
|
|
7103
|
+
if (requestedResources.length === 0 || requestedResources.some((child) => !parentResources.some((parent) => resourceIsContained(parent, child)))) {
|
|
6988
7104
|
throw new Error(
|
|
6989
|
-
|
|
7105
|
+
"Sub-delegation resources exceed the received delegation"
|
|
6990
7106
|
);
|
|
6991
7107
|
}
|
|
6992
|
-
const parentActions = new Set(parentDelegation.actions);
|
|
6993
|
-
for (const action of params.actions) {
|
|
6994
|
-
if (!parentActions.has(action)) {
|
|
6995
|
-
throw new Error(
|
|
6996
|
-
`Sub-delegation action "${action}" is not in parent's actions: ${parentDelegation.actions.join(", ")}`
|
|
6997
|
-
);
|
|
6998
|
-
}
|
|
6999
|
-
}
|
|
7000
7108
|
const now = /* @__PURE__ */ new Date();
|
|
7001
7109
|
const expiryMs = params.expiryMs ?? 60 * 60 * 1e3;
|
|
7002
7110
|
const requestedExpiry = new Date(now.getTime() + expiryMs);
|
|
7003
7111
|
const actualExpiry = requestedExpiry > parentDelegation.expiry ? parentDelegation.expiry : requestedExpiry;
|
|
7004
7112
|
const abilities = {};
|
|
7005
|
-
const
|
|
7006
|
-
const
|
|
7007
|
-
|
|
7008
|
-
|
|
7009
|
-
|
|
7010
|
-
|
|
7011
|
-
|
|
7012
|
-
abilities
|
|
7013
|
-
|
|
7014
|
-
if (duckdbActions.length > 0) {
|
|
7015
|
-
abilities.duckdb = { [params.path]: duckdbActions };
|
|
7113
|
+
const rawAbilities = {};
|
|
7114
|
+
for (const resource of requestedResources) {
|
|
7115
|
+
const service = resource.service.replace(/^tinycloud\./, "");
|
|
7116
|
+
if (service === "encryption") {
|
|
7117
|
+
rawAbilities[resource.path] = [...resource.actions];
|
|
7118
|
+
continue;
|
|
7119
|
+
}
|
|
7120
|
+
abilities[service] ?? (abilities[service] = {});
|
|
7121
|
+
abilities[service][resource.path] = [...resource.actions];
|
|
7016
7122
|
}
|
|
7017
7123
|
const targetHost = parentDelegation.host ?? this.config.host;
|
|
7018
7124
|
const prepared = this.wasmBindings.prepareSession({
|
|
@@ -7024,7 +7130,8 @@ var _TinyCloudNode = class _TinyCloudNode {
|
|
|
7024
7130
|
expirationTime: actualExpiry.toISOString(),
|
|
7025
7131
|
spaceId: parentDelegation.spaceId,
|
|
7026
7132
|
delegateUri: params.delegateDID,
|
|
7027
|
-
parents: [parentDelegation.cid]
|
|
7133
|
+
parents: [parentDelegation.cid],
|
|
7134
|
+
...Object.keys(rawAbilities).length > 0 ? { rawAbilities } : {}
|
|
7028
7135
|
});
|
|
7029
7136
|
const signature = await this.signer.signMessage(prepared.siwe);
|
|
7030
7137
|
const subDelegationSession = this.wasmBindings.completeSessionSetup({
|
|
@@ -7042,14 +7149,20 @@ var _TinyCloudNode = class _TinyCloudNode {
|
|
|
7042
7149
|
cid: subDelegationSession.delegationCid,
|
|
7043
7150
|
delegationHeader: subDelegationSession.delegationHeader,
|
|
7044
7151
|
spaceId: parentDelegation.spaceId,
|
|
7045
|
-
path:
|
|
7046
|
-
actions:
|
|
7152
|
+
path: requestedResources[0].path,
|
|
7153
|
+
actions: requestedResources[0].actions,
|
|
7047
7154
|
disableSubDelegation: params.disableSubDelegation ?? false,
|
|
7048
7155
|
expiry: actualExpiry,
|
|
7049
7156
|
delegateDID: params.delegateDID,
|
|
7050
7157
|
ownerAddress: parentDelegation.ownerAddress,
|
|
7051
7158
|
chainId: parentDelegation.chainId,
|
|
7052
|
-
host: targetHost
|
|
7159
|
+
host: targetHost,
|
|
7160
|
+
resources: requestedResources.map((resource) => ({
|
|
7161
|
+
service: resource.service.replace(/^tinycloud\./, ""),
|
|
7162
|
+
space: resource.service.replace(/^tinycloud\./, "") === "encryption" ? "encryption" : resource.space ?? parentDelegation.spaceId,
|
|
7163
|
+
path: resource.path,
|
|
7164
|
+
actions: [...resource.actions]
|
|
7165
|
+
}))
|
|
7053
7166
|
};
|
|
7054
7167
|
}
|
|
7055
7168
|
};
|