@forgezero/agent 0.1.33 → 0.1.35
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/README.md +21 -0
- package/dist/agent-heartbeat.js +1 -1
- package/dist/bootstrap.d.ts +128 -0
- package/dist/bootstrap.js +3361 -0
- package/dist/capacity-calibration.d.ts +51 -0
- package/dist/capacity-calibration.js +119 -0
- package/dist/cli/cloudflare-bootstrap.d.ts +11 -0
- package/dist/cloudflare-bootstrap.d.ts +218 -0
- package/dist/cloudflare-bootstrap.js +1196 -0
- package/dist/cloudflare-edge.d.ts +265 -0
- package/dist/cloudflare-edge.js +424 -0
- package/dist/definition.d.ts +3 -0
- package/dist/definition.js +174 -2
- package/dist/deploy-file.js +174 -2
- package/dist/deployment.d.ts +11 -0
- package/dist/fz-agent.js +1855 -3370
- package/dist/fz.js +8092 -6437
- package/dist/index.d.ts +2 -0
- package/dist/metal-bootstrap.d.ts +52 -0
- package/dist/metal-bootstrap.js +942 -0
- package/dist/platform-bootstrap-runtime.d.ts +161 -0
- package/dist/platform-bootstrap-runtime.js +462 -0
- package/dist/provision.js +5 -4
- package/dist/version.d.ts +1 -1
- package/package.json +26 -2
- package/schema/deploy-v2.json +14 -0
|
@@ -0,0 +1,51 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Bounded, node-local HTTP concurrency calibration.
|
|
3
|
+
*
|
|
4
|
+
* This deliberately benchmarks a real application probe rather than CPU. A
|
|
5
|
+
* database-bound API can have idle CPU while every request is waiting on I/O.
|
|
6
|
+
* The caller chooses a representative, idempotent GET endpoint; ForgeZero's
|
|
7
|
+
* cluster rehearsal uses its typed Arango read query.
|
|
8
|
+
*/
|
|
9
|
+
export interface CapacityStage {
|
|
10
|
+
concurrency: number;
|
|
11
|
+
requests: number;
|
|
12
|
+
succeeded: number;
|
|
13
|
+
failed: number;
|
|
14
|
+
overloaded: number;
|
|
15
|
+
throughputPerSecond: number;
|
|
16
|
+
p95Ms: number;
|
|
17
|
+
}
|
|
18
|
+
export interface CapacityCalibration {
|
|
19
|
+
endpoint: string;
|
|
20
|
+
recommendedConcurrency: number;
|
|
21
|
+
stopReason: 'maximum-tested' | 'latency' | 'errors' | 'throughput-regression';
|
|
22
|
+
stages: CapacityStage[];
|
|
23
|
+
}
|
|
24
|
+
export interface CapacityCalibrationOptions {
|
|
25
|
+
endpoint: string;
|
|
26
|
+
maxConcurrency?: number;
|
|
27
|
+
requestsPerWorker?: number;
|
|
28
|
+
maxP95Ms?: number;
|
|
29
|
+
maxErrorRate?: number;
|
|
30
|
+
headroomRatio?: number;
|
|
31
|
+
requestTimeoutMs?: number;
|
|
32
|
+
}
|
|
33
|
+
export interface ValidatedCapacityCalibrationOptions {
|
|
34
|
+
endpoint: URL;
|
|
35
|
+
maxConcurrency: number;
|
|
36
|
+
requestsPerWorker: number;
|
|
37
|
+
maxP95Ms: number;
|
|
38
|
+
maxErrorRate: number;
|
|
39
|
+
headroomRatio: number;
|
|
40
|
+
requestTimeoutMs: number;
|
|
41
|
+
}
|
|
42
|
+
/** Only a service on this node may be stressed by an install-time probe. */
|
|
43
|
+
export declare function localCalibrationEndpoint(value: string): URL;
|
|
44
|
+
/** Parse every bound without sending a request; deploy definitions use this fail-closed gate. */
|
|
45
|
+
export declare function validateCapacityCalibrationOptions(options: CapacityCalibrationOptions): ValidatedCapacityCalibrationOptions;
|
|
46
|
+
/**
|
|
47
|
+
* Increase load geometrically and stop at the first unsafe stage. The returned
|
|
48
|
+
* limit is the last safe stage with explicit headroom; it is evidence, not a
|
|
49
|
+
* promise that a different route or future release has the same capacity.
|
|
50
|
+
*/
|
|
51
|
+
export declare function calibrateHttpConcurrency(options: CapacityCalibrationOptions, fetcher?: typeof fetch): Promise<CapacityCalibration>;
|
|
@@ -0,0 +1,119 @@
|
|
|
1
|
+
// src/capacity-calibration.ts
|
|
2
|
+
var percentile95 = (values) => {
|
|
3
|
+
if (values.length === 0)
|
|
4
|
+
return Number.POSITIVE_INFINITY;
|
|
5
|
+
const sorted = values.toSorted((left, right) => left - right);
|
|
6
|
+
return sorted[Math.min(sorted.length - 1, Math.ceil(sorted.length * 0.95) - 1)];
|
|
7
|
+
};
|
|
8
|
+
function localCalibrationEndpoint(value) {
|
|
9
|
+
const endpoint = new URL(value);
|
|
10
|
+
if (endpoint.protocol !== "http:" || !["localhost", "127.0.0.1", "[::1]"].includes(endpoint.hostname) || !endpoint.port || endpoint.username || endpoint.password || endpoint.hash) {
|
|
11
|
+
throw new Error("Capacity calibration requires an explicit loopback HTTP endpoint and port.");
|
|
12
|
+
}
|
|
13
|
+
return endpoint;
|
|
14
|
+
}
|
|
15
|
+
function validateCapacityCalibrationOptions(options) {
|
|
16
|
+
const endpoint = localCalibrationEndpoint(options.endpoint);
|
|
17
|
+
const maxConcurrency = options.maxConcurrency ?? 256;
|
|
18
|
+
const requestsPerWorker = options.requestsPerWorker ?? 8;
|
|
19
|
+
const maxP95Ms = options.maxP95Ms ?? 250;
|
|
20
|
+
const maxErrorRate = options.maxErrorRate ?? 0.01;
|
|
21
|
+
const headroomRatio = options.headroomRatio ?? 0.8;
|
|
22
|
+
const requestTimeoutMs = options.requestTimeoutMs ?? 5000;
|
|
23
|
+
if (!Number.isSafeInteger(maxConcurrency) || maxConcurrency < 1 || maxConcurrency > 4096 || !Number.isSafeInteger(requestsPerWorker) || requestsPerWorker < 2 || requestsPerWorker > 100 || !Number.isFinite(maxP95Ms) || maxP95Ms < 1 || !Number.isFinite(maxErrorRate) || maxErrorRate < 0 || maxErrorRate > 0.2 || !Number.isFinite(headroomRatio) || headroomRatio < 0.25 || headroomRatio > 0.95 || !Number.isSafeInteger(requestTimeoutMs) || requestTimeoutMs < 100 || requestTimeoutMs > 30000) {
|
|
24
|
+
throw new Error("Capacity calibration bounds are invalid.");
|
|
25
|
+
}
|
|
26
|
+
return {
|
|
27
|
+
endpoint,
|
|
28
|
+
maxConcurrency,
|
|
29
|
+
requestsPerWorker,
|
|
30
|
+
maxP95Ms,
|
|
31
|
+
maxErrorRate,
|
|
32
|
+
headroomRatio,
|
|
33
|
+
requestTimeoutMs
|
|
34
|
+
};
|
|
35
|
+
}
|
|
36
|
+
async function stage(endpoint, concurrency, requestsPerWorker, timeoutMs, fetcher) {
|
|
37
|
+
const latencies = [];
|
|
38
|
+
let succeeded = 0;
|
|
39
|
+
let failed = 0;
|
|
40
|
+
let overloaded = 0;
|
|
41
|
+
const started = performance.now();
|
|
42
|
+
await Promise.all(Array.from({ length: concurrency }, async () => {
|
|
43
|
+
for (let request = 0;request < requestsPerWorker; request += 1) {
|
|
44
|
+
const requestStarted = performance.now();
|
|
45
|
+
try {
|
|
46
|
+
const response = await fetcher(endpoint, {
|
|
47
|
+
method: "GET",
|
|
48
|
+
headers: { accept: "application/json", "user-agent": "forgezero-capacity-calibration/1" },
|
|
49
|
+
signal: AbortSignal.timeout(timeoutMs),
|
|
50
|
+
redirect: "error"
|
|
51
|
+
});
|
|
52
|
+
await response.body?.cancel();
|
|
53
|
+
if (response.ok)
|
|
54
|
+
succeeded += 1;
|
|
55
|
+
else {
|
|
56
|
+
failed += 1;
|
|
57
|
+
if (response.status === 503)
|
|
58
|
+
overloaded += 1;
|
|
59
|
+
}
|
|
60
|
+
} catch {
|
|
61
|
+
failed += 1;
|
|
62
|
+
} finally {
|
|
63
|
+
latencies.push(performance.now() - requestStarted);
|
|
64
|
+
}
|
|
65
|
+
}
|
|
66
|
+
}));
|
|
67
|
+
const elapsedSeconds = Math.max((performance.now() - started) / 1000, 0.001);
|
|
68
|
+
return {
|
|
69
|
+
concurrency,
|
|
70
|
+
requests: concurrency * requestsPerWorker,
|
|
71
|
+
succeeded,
|
|
72
|
+
failed,
|
|
73
|
+
overloaded,
|
|
74
|
+
throughputPerSecond: Number(((succeeded + failed) / elapsedSeconds).toFixed(2)),
|
|
75
|
+
p95Ms: Number(percentile95(latencies).toFixed(2))
|
|
76
|
+
};
|
|
77
|
+
}
|
|
78
|
+
async function calibrateHttpConcurrency(options, fetcher = fetch) {
|
|
79
|
+
const {
|
|
80
|
+
endpoint,
|
|
81
|
+
maxConcurrency,
|
|
82
|
+
requestsPerWorker,
|
|
83
|
+
maxP95Ms,
|
|
84
|
+
maxErrorRate,
|
|
85
|
+
headroomRatio,
|
|
86
|
+
requestTimeoutMs: timeoutMs
|
|
87
|
+
} = validateCapacityCalibrationOptions(options);
|
|
88
|
+
const stages = [];
|
|
89
|
+
let lastSafe = 1;
|
|
90
|
+
let stopReason = "maximum-tested";
|
|
91
|
+
for (let concurrency = 1;; concurrency = Math.min(maxConcurrency, concurrency * 2)) {
|
|
92
|
+
const measured = await stage(endpoint, concurrency, requestsPerWorker, timeoutMs, fetcher);
|
|
93
|
+
stages.push(measured);
|
|
94
|
+
const errorRate = measured.failed / measured.requests;
|
|
95
|
+
const previous = stages.at(-2);
|
|
96
|
+
const throughputRegressed = Boolean(previous && concurrency > 1 && measured.throughputPerSecond < previous.throughputPerSecond * 0.9);
|
|
97
|
+
if (measured.overloaded > 0 || errorRate > maxErrorRate)
|
|
98
|
+
stopReason = "errors";
|
|
99
|
+
else if (measured.p95Ms > maxP95Ms)
|
|
100
|
+
stopReason = "latency";
|
|
101
|
+
else if (throughputRegressed)
|
|
102
|
+
stopReason = "throughput-regression";
|
|
103
|
+
else
|
|
104
|
+
lastSafe = concurrency;
|
|
105
|
+
if (stopReason !== "maximum-tested" || concurrency === maxConcurrency)
|
|
106
|
+
break;
|
|
107
|
+
}
|
|
108
|
+
return {
|
|
109
|
+
endpoint: endpoint.toString(),
|
|
110
|
+
recommendedConcurrency: Math.max(1, Math.floor(lastSafe * headroomRatio)),
|
|
111
|
+
stopReason,
|
|
112
|
+
stages
|
|
113
|
+
};
|
|
114
|
+
}
|
|
115
|
+
export {
|
|
116
|
+
validateCapacityCalibrationOptions,
|
|
117
|
+
localCalibrationEndpoint,
|
|
118
|
+
calibrateHttpConcurrency
|
|
119
|
+
};
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
import { type AttendedCloudflareBootstrapRequest, type CloudflareBootstrapEvidence, type CloudflareBootstrapPhaseRunner } from '../cloudflare-bootstrap';
|
|
2
|
+
export interface CloudflareBootstrapCommandDependencies {
|
|
3
|
+
run?: CloudflareBootstrapPhaseRunner;
|
|
4
|
+
write?: (text: string) => void;
|
|
5
|
+
}
|
|
6
|
+
/**
|
|
7
|
+
* Read reviewed non-secret coordinates and token-file paths for the attended
|
|
8
|
+
* operator phase. Raw token values and a persisted mode are not schema fields.
|
|
9
|
+
*/
|
|
10
|
+
export declare function readCloudflareBootstrapCommandConfig(path: string, mode: 'plan' | 'apply'): AttendedCloudflareBootstrapRequest;
|
|
11
|
+
export declare function runCloudflareBootstrapCommand(configPath: string, apply: boolean, dependencies?: CloudflareBootstrapCommandDependencies): Promise<CloudflareBootstrapEvidence>;
|
|
@@ -0,0 +1,218 @@
|
|
|
1
|
+
import { type CloudflareAccessCredentials, type CloudflareAccountRuntimeToken, type CloudflareApiTokens } from './cloudflare-edge';
|
|
2
|
+
export interface CloudflareBootstrapNodeCoordinates {
|
|
3
|
+
nodeName: string;
|
|
4
|
+
hostname: string;
|
|
5
|
+
service: string;
|
|
6
|
+
tunnelName: string;
|
|
7
|
+
applicationName: string;
|
|
8
|
+
/** Present only on DB nodes that publish an exact private host route. */
|
|
9
|
+
privateAddress?: string;
|
|
10
|
+
}
|
|
11
|
+
export interface CloudflarePrivateNetworkCoordinates {
|
|
12
|
+
warpOrganization: string;
|
|
13
|
+
virtualNetworkName: string;
|
|
14
|
+
deviceProfileName: string;
|
|
15
|
+
enrollmentApplicationName: string;
|
|
16
|
+
deviceProfilePrecedence?: number;
|
|
17
|
+
}
|
|
18
|
+
export interface CloudflareBootstrapCoordinates {
|
|
19
|
+
accountId: string;
|
|
20
|
+
zoneId: string;
|
|
21
|
+
/** Legacy single-node coordinates; normalized into `nodes[0]`. */
|
|
22
|
+
hostname: string;
|
|
23
|
+
service: string;
|
|
24
|
+
tunnelName: string;
|
|
25
|
+
kvNamespaceTitle: string;
|
|
26
|
+
workerScriptName: string;
|
|
27
|
+
serviceTokenName: string;
|
|
28
|
+
policyName: string;
|
|
29
|
+
applicationName: string;
|
|
30
|
+
workerDirectory: string;
|
|
31
|
+
workerMain: string;
|
|
32
|
+
workerCompatibilityDate: string;
|
|
33
|
+
publicDomains: string[];
|
|
34
|
+
createRuntimeTokens: boolean;
|
|
35
|
+
createPrivateNetworkRuntimeToken: boolean;
|
|
36
|
+
runtimeTokenNamePrefix: string;
|
|
37
|
+
nodes?: CloudflareBootstrapNodeCoordinates[];
|
|
38
|
+
privateNetwork?: CloudflarePrivateNetworkCoordinates;
|
|
39
|
+
}
|
|
40
|
+
export interface CloudflareBootstrapTokenFiles {
|
|
41
|
+
apiTokenFile?: string;
|
|
42
|
+
tunnelApiTokenFile?: string;
|
|
43
|
+
dnsApiTokenFile?: string;
|
|
44
|
+
kvApiTokenFile?: string;
|
|
45
|
+
accessApiTokenFile?: string;
|
|
46
|
+
workerApiTokenFile?: string;
|
|
47
|
+
}
|
|
48
|
+
interface CloudflareBootstrapResources {
|
|
49
|
+
tunnelId: string;
|
|
50
|
+
kvNamespaceId: string;
|
|
51
|
+
hostname: string;
|
|
52
|
+
service: string;
|
|
53
|
+
connectorToken: string;
|
|
54
|
+
access?: CloudflareAccessCredentials & {
|
|
55
|
+
policyId?: string;
|
|
56
|
+
applicationId?: string;
|
|
57
|
+
};
|
|
58
|
+
nodes: Array<{
|
|
59
|
+
nodeName: string;
|
|
60
|
+
hostname: string;
|
|
61
|
+
service: string;
|
|
62
|
+
tunnelName: string;
|
|
63
|
+
tunnelId: string;
|
|
64
|
+
connectorToken: string;
|
|
65
|
+
applicationId?: string;
|
|
66
|
+
}>;
|
|
67
|
+
worker?: {
|
|
68
|
+
scriptName: string;
|
|
69
|
+
publicDomains: string[];
|
|
70
|
+
deployed: true;
|
|
71
|
+
};
|
|
72
|
+
runtimeTokens?: {
|
|
73
|
+
kv: CloudflareAccountRuntimeToken;
|
|
74
|
+
privateNetwork?: CloudflareAccountRuntimeToken;
|
|
75
|
+
};
|
|
76
|
+
privateNetwork?: {
|
|
77
|
+
warpOrganization: string;
|
|
78
|
+
virtualNetworkId: string;
|
|
79
|
+
deviceProfileId: string;
|
|
80
|
+
enrollmentApplicationId: string;
|
|
81
|
+
routes: Array<{
|
|
82
|
+
nodeName: string;
|
|
83
|
+
routeId: string;
|
|
84
|
+
privateAddress: string;
|
|
85
|
+
}>;
|
|
86
|
+
};
|
|
87
|
+
}
|
|
88
|
+
export interface CloudflareBootstrapOutput {
|
|
89
|
+
format: 1;
|
|
90
|
+
kind: 'forgezero-cloudflare-bootstrap';
|
|
91
|
+
phase: 'edge-resources-provisioned' | 'runtime-tokens-created' | 'worker-deployed' | 'access-token-provisioned' | 'complete';
|
|
92
|
+
updatedAt: string;
|
|
93
|
+
coordinates: CloudflareBootstrapCoordinates;
|
|
94
|
+
resources: CloudflareBootstrapResources;
|
|
95
|
+
created?: {
|
|
96
|
+
tunnel: boolean;
|
|
97
|
+
kvNamespace: boolean;
|
|
98
|
+
serviceToken: boolean;
|
|
99
|
+
policy: boolean;
|
|
100
|
+
application: boolean;
|
|
101
|
+
privateNetwork: boolean;
|
|
102
|
+
workerDeployed: true;
|
|
103
|
+
nodes: Array<{
|
|
104
|
+
nodeName: string;
|
|
105
|
+
tunnel: boolean;
|
|
106
|
+
application: boolean;
|
|
107
|
+
}>;
|
|
108
|
+
};
|
|
109
|
+
}
|
|
110
|
+
export interface CloudflareBootstrapPlan {
|
|
111
|
+
format: 1;
|
|
112
|
+
kind: 'forgezero-cloudflare-bootstrap-plan';
|
|
113
|
+
mode: 'attended-token-file';
|
|
114
|
+
outputFile: string;
|
|
115
|
+
coordinates: CloudflareBootstrapCoordinates;
|
|
116
|
+
operations: readonly string[];
|
|
117
|
+
secrets: readonly string[];
|
|
118
|
+
}
|
|
119
|
+
/**
|
|
120
|
+
* The published `fz bootstrap platform` boundary. It deliberately accepts
|
|
121
|
+
* token *paths*, never token values, so a caller cannot accidentally put the
|
|
122
|
+
* Cloudflare management credential into a platform manifest, runtime config,
|
|
123
|
+
* child argv, or evidence journal.
|
|
124
|
+
*/
|
|
125
|
+
export interface AttendedCloudflareBootstrapRequest {
|
|
126
|
+
mode: 'plan' | 'apply';
|
|
127
|
+
coordinates: CloudflareBootstrapCoordinates;
|
|
128
|
+
tokenFiles?: CloudflareBootstrapTokenFiles;
|
|
129
|
+
checkpointPath: string;
|
|
130
|
+
}
|
|
131
|
+
/** Secret-free evidence safe to embed in the platform bootstrap journal. */
|
|
132
|
+
export interface CloudflareBootstrapEvidence {
|
|
133
|
+
format: 1;
|
|
134
|
+
kind: 'forgezero-cloudflare-bootstrap-evidence';
|
|
135
|
+
phase: 'planned' | 'complete';
|
|
136
|
+
checkpointFile: string;
|
|
137
|
+
kvNamespaceId?: string;
|
|
138
|
+
workerScriptName: string;
|
|
139
|
+
publicDomains: readonly string[];
|
|
140
|
+
runtimeTokenIds?: {
|
|
141
|
+
kv?: string;
|
|
142
|
+
privateNetwork?: string;
|
|
143
|
+
};
|
|
144
|
+
nodes: ReadonlyArray<{
|
|
145
|
+
nodeName: string;
|
|
146
|
+
hostname: string;
|
|
147
|
+
tunnelId?: string;
|
|
148
|
+
applicationId?: string;
|
|
149
|
+
}>;
|
|
150
|
+
}
|
|
151
|
+
export interface CloudflareBootstrapDependencies {
|
|
152
|
+
fetcher?: typeof fetch;
|
|
153
|
+
workerRunner?: CloudflareWorkerCommandRunner;
|
|
154
|
+
}
|
|
155
|
+
export type CloudflareBootstrapPhaseRunner = (request: AttendedCloudflareBootstrapRequest) => Promise<CloudflareBootstrapEvidence>;
|
|
156
|
+
/** Read exactly one API token from a non-symlinked, owner-only regular file. */
|
|
157
|
+
export declare function readOwnerApiToken(path: string): Promise<string>;
|
|
158
|
+
export declare function readCloudflareBootstrapTokens(files: CloudflareBootstrapTokenFiles): Promise<CloudflareApiTokens>;
|
|
159
|
+
export declare function validateCloudflareBootstrapCoordinates(input: CloudflareBootstrapCoordinates): CloudflareBootstrapCoordinates;
|
|
160
|
+
export declare function planCloudflareBootstrap(input: CloudflareBootstrapCoordinates, outputPath: string): CloudflareBootstrapPlan;
|
|
161
|
+
export interface CloudflareWorkerCommand {
|
|
162
|
+
command: readonly string[];
|
|
163
|
+
cwd: string;
|
|
164
|
+
env: Readonly<Record<string, string>>;
|
|
165
|
+
}
|
|
166
|
+
export type CloudflareWorkerCommandRunner = (request: CloudflareWorkerCommand) => Promise<{
|
|
167
|
+
exitCode: number;
|
|
168
|
+
stdout: string;
|
|
169
|
+
stderr: string;
|
|
170
|
+
}>;
|
|
171
|
+
/** Deploy one Worker from an ephemeral config containing the runtime-created KV id. */
|
|
172
|
+
export declare function deployCloudflareWorker(coordinates: CloudflareBootstrapCoordinates, kvNamespaceId: string, apiToken: string, runner?: CloudflareWorkerCommandRunner): Promise<void>;
|
|
173
|
+
export interface CloudflareConnectorHandoff {
|
|
174
|
+
nodeName: string;
|
|
175
|
+
hostname: string;
|
|
176
|
+
service: string;
|
|
177
|
+
tunnelId: string;
|
|
178
|
+
connectorToken: string;
|
|
179
|
+
}
|
|
180
|
+
export interface CloudflareHostHandoff extends CloudflareConnectorHandoff {
|
|
181
|
+
accountId: string;
|
|
182
|
+
zoneId: string;
|
|
183
|
+
kvNamespaceId: string;
|
|
184
|
+
kvRuntimeToken: string;
|
|
185
|
+
privateNetworkRuntimeToken?: string;
|
|
186
|
+
warp?: {
|
|
187
|
+
organization: string;
|
|
188
|
+
clientId: string;
|
|
189
|
+
clientSecret: string;
|
|
190
|
+
virtualNetworkId: string;
|
|
191
|
+
deviceProfileId: string;
|
|
192
|
+
};
|
|
193
|
+
}
|
|
194
|
+
/**
|
|
195
|
+
* Select one node's connector credential directly from the completed fleet
|
|
196
|
+
* checkpoint. Host bootstrap can pipe this value into `systemd-creds` without
|
|
197
|
+
* creating another plaintext token file or accepting the whole JSON as a
|
|
198
|
+
* connector token.
|
|
199
|
+
*/
|
|
200
|
+
export declare function readCloudflareConnectorHandoff(checkpointPath: string, nodeName: string): Promise<CloudflareConnectorHandoff>;
|
|
201
|
+
/** Complete secret-bearing handoff consumed once by root host bootstrap. */
|
|
202
|
+
export declare function readCloudflareHostHandoff(checkpointPath: string, nodeName: string): Promise<CloudflareHostHandoff>;
|
|
203
|
+
/** Atomically persist sensitive bootstrap material without making it runtime configuration. */
|
|
204
|
+
export declare function writeOwnerBootstrapOutput(path: string, output: CloudflareBootstrapOutput): Promise<void>;
|
|
205
|
+
/**
|
|
206
|
+
* Attended, resumable Cloudflare bootstrap. The output is checkpointed after
|
|
207
|
+
* every one-time secret is obtained, so a later API failure cannot orphan it.
|
|
208
|
+
*/
|
|
209
|
+
export declare function applyCloudflareBootstrap(input: CloudflareBootstrapCoordinates, tokens: CloudflareApiTokens, outputPath: string, fetcher?: typeof fetch, workerRunner?: CloudflareWorkerCommandRunner): Promise<CloudflareBootstrapOutput>;
|
|
210
|
+
/**
|
|
211
|
+
* Run the attended Cloudflare phase for `fz bootstrap platform`.
|
|
212
|
+
*
|
|
213
|
+
* Plans are offline. Applies read management tokens only inside this function,
|
|
214
|
+
* persist one-time handoff values only in the owner-only checkpoint, and return
|
|
215
|
+
* a deliberately secret-free evidence record to the outer bootstrap journal.
|
|
216
|
+
*/
|
|
217
|
+
export declare function runAttendedCloudflareBootstrap(request: AttendedCloudflareBootstrapRequest, dependencies?: CloudflareBootstrapDependencies): Promise<CloudflareBootstrapEvidence>;
|
|
218
|
+
export {};
|