@parall/daemon 1.35.0 → 1.36.1

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.
@@ -0,0 +1,301 @@
1
+ #!/usr/bin/env node
2
+ /**
3
+ * `parall-browser-pod` — the V2 hosted-browser pod entrypoint.
4
+ *
5
+ * This is the production replacement for the Go echo-stub (server/cmd/browser-stub):
6
+ * a single-profile pod that runs the REAL browser stack (Chromium under Xvfb +
7
+ * bb-browser, started lazily by BrowserProfileManager) and registers to the Clip
8
+ * Service hub as the "browser" provider for exactly ONE profile.
9
+ *
10
+ * It is deliberately NOT the daemon supervisor. The daemon (`index.ts`) is a
11
+ * Machine: it authenticates with a 90-day `mck_`, polls `/machines/me/*`, and
12
+ * supervises per-agent subprocesses. A hosted browser pod has none of that — it
13
+ * is platform infrastructure with a short-lived, controller-minted platform
14
+ * assignment token (`pba_`) scoped to `(org_id, profile_id, pod_id)`, and serves
15
+ * a single profile until its lease is released. Per the V2 design (§3.3, §6) this
16
+ * is an **image/entrypoint-level** slim mode: it reuses the shared clip-runtime
17
+ * building blocks (ClipProvider / ClipProcessManager / BrowserProfileManager)
18
+ * without deleting anything from the shared package, so the BYOC daemon path and
19
+ * its `mck_` identity are untouched.
20
+ *
21
+ * Contract (mirrors server/cmd/browser-stub/main.go, the reference implementation):
22
+ *
23
+ * Env (injected by browser-profile-controller's pod spec):
24
+ * PRLL_ASSIGNMENT_TOKEN the pba_ platform assignment token (required)
25
+ * PRLL_CLIP_RPC in-cluster clip-service URL, e.g. http://clip-service:8095 (required)
26
+ * PRLL_PROFILE_ID the profile this pod serves (required)
27
+ * PRLL_POD_ID this pod's name → provider_name; must match the token's pod_id (required)
28
+ * PRLL_ORG_ID owning org (logging only; the hub derives org from the token)
29
+ * PRLL_HEALTH_PORT liveness/readiness listen port (default 8080)
30
+ * PRLL_BROWSER_STATE_DIR root for on-disk browser state (default $HOME/.parall-agent)
31
+ *
32
+ * Health (the contract the controller's K8s probes consume):
33
+ * GET /livez -> 200 always (process is alive; a liveness restart trigger).
34
+ * GET /readyz -> 200 only while registered to the hub AND not draining, else 503.
35
+ * Readiness is ROUTE-readiness, not mere liveness: a started-but-not-yet-
36
+ * registered (or disconnected, or token/lease-invalidated) pod reads
37
+ * NotReady, so the controller never treats pod existence as routable. The
38
+ * hub fences the ProviderStream on the pba_ token + live lease, so loss of
39
+ * either drops the registration → isConnected() → false → NotReady.
40
+ *
41
+ * Shutdown (SIGTERM, on pod deletion / lease release): fail readiness FIRST so
42
+ * K8s/controller stop routing, THEN tear down the ProviderStream (hub
43
+ * unregisters) and the bb-browser daemon — all within terminationGracePeriod.
44
+ * The authoritative lease state transition (lease -> released, quota freed) is
45
+ * still owned by the controller/api-server, never inferred from the pod exiting.
46
+ */
47
+ import * as http from 'node:http';
48
+ import { type GatewayLogger } from '@parall/agent-core';
49
+ import { type BrowserProxyConfig } from './clip-runtime/browser-profile-manager.js';
50
+ import { BrowserStateStore, type HydrateResult } from './clip-runtime/browser-state-store.js';
51
+ export interface BrowserPodConfig {
52
+ /** Controller-minted pba_ platform assignment token (ProviderStream bearer). */
53
+ assignmentToken: string;
54
+ /** Clip Service hub URL (h2c in-cluster, e.g. http://clip-service:8095). */
55
+ clipRpcUrl: string;
56
+ /** The single profile this pod serves. */
57
+ profileId: string;
58
+ /** This pod's name; becomes the provider_name and must match the token's pod_id. */
59
+ podId: string;
60
+ /** Owning org — used for local logging only; the hub derives org from the token. */
61
+ orgId: string;
62
+ /** Liveness/readiness HTTP port. */
63
+ healthPort: number;
64
+ /** Root for on-disk browser state (parent of the bb-browser user-data dir). */
65
+ stateDir: string;
66
+ /** bb-browser user-data dir (BB_BROWSER_HOME); where S3 state hydrates in a later PR. */
67
+ homeDir: string;
68
+ /** Per-profile outbound proxy (controller-injected via PRLL_BROWSER_PROXY_* env on a
69
+ * cold pod, or the /assign body on a warm one). null = direct egress. */
70
+ proxy: BrowserProxyConfig | null;
71
+ }
72
+ /**
73
+ * Resolve and validate the pod's runtime config from the environment. Throws on
74
+ * any missing required var (fail-fast: a pod missing its token / clip-rpc /
75
+ * profile / pod id can never register, so we crash now instead of starting a
76
+ * doomed reconnect loop).
77
+ */
78
+ export declare function resolveBrowserPodConfig(env?: NodeJS.ProcessEnv): BrowserPodConfig;
79
+ /** Resolved warm-pool config — the identity-less env a warm pod boots with. */
80
+ export interface PoolPodConfig {
81
+ /** Controller-minted pba_ pool bootstrap token; the bearer required on POST /assign. */
82
+ poolToken: string;
83
+ /** This warm pod's name → provider_name after assignment; matches the controller pod spec. */
84
+ podId: string;
85
+ /** Clip Service hub URL (stable per cluster; injected at pool creation, reused post-assign). */
86
+ clipRpcUrl: string;
87
+ /** Liveness/readiness/control HTTP port. */
88
+ healthPort: number;
89
+ }
90
+ /**
91
+ * Resolve a warm pod's identity-less config. Unlike resolveBrowserPodConfig this
92
+ * requires PRLL_POOL_TOKEN (not PRLL_ASSIGNMENT_TOKEN) and NO profile/org — those
93
+ * arrive later via /assign. PRLL_CLIP_RPC is injected at pool creation (stable per
94
+ * cluster) so the assigned path needs no extra wiring.
95
+ */
96
+ export declare function resolvePoolPodConfig(env?: NodeJS.ProcessEnv): PoolPodConfig;
97
+ /** Profile-scoped S3 credentials delivered in an /assign payload (mirrors the
98
+ * controller's PodStateCredentials → cold-pod env injection). */
99
+ export interface AssignStateCreds {
100
+ bucket: string;
101
+ region: string;
102
+ endpoint?: string;
103
+ accessKeyId: string;
104
+ secretAccessKey: string;
105
+ sessionToken: string;
106
+ }
107
+ /** The POST /assign body the browser-profile-controller sends to bind a warm pod
108
+ * to a profile (design §9 PR10). Wire format is snake_case (Go JSON). */
109
+ export interface AssignRequest {
110
+ assignmentToken: string;
111
+ profileId: string;
112
+ orgId: string;
113
+ leaseId: string;
114
+ generation: number;
115
+ state?: AssignStateCreds;
116
+ /** Per-profile outbound proxy (warm-pod counterpart of the cold pod's
117
+ * PRLL_BROWSER_PROXY_* env). Absent = direct egress. */
118
+ proxy?: BrowserProxyConfig;
119
+ }
120
+ type AssignParseResult = {
121
+ ok: true;
122
+ value: AssignRequest;
123
+ } | {
124
+ ok: false;
125
+ error: string;
126
+ };
127
+ /**
128
+ * Validate + normalize an /assign body (already JSON-parsed). Rejects a missing /
129
+ * non-pba_ assignment token, a missing profile/lease, and PARTIAL S3 creds (a
130
+ * half-set would build a misconfigured S3 client — worse than stateless). State is
131
+ * optional (stateless profile); when present it must be complete.
132
+ */
133
+ export declare function parseAssignRequest(body: unknown): AssignParseResult;
134
+ /**
135
+ * Apply an /assign payload to `env` (process.env in prod) so the assigned path
136
+ * reads identity + S3 creds EXACTLY as the controller injects them into a cold
137
+ * pod's spec. The AWS_* creds must land in process.env: the S3 client
138
+ * (browser-state-store buildS3Client) reads the default AWS provider chain.
139
+ */
140
+ export declare function applyAssignmentEnv(env: NodeJS.ProcessEnv, req: AssignRequest): void;
141
+ /** HTTP outcome of an /assign request. */
142
+ export type AssignOutcome = {
143
+ status: number;
144
+ message?: string;
145
+ };
146
+ /** /assign handler: bearer (already stripped of "Bearer ") + parsed-or-raw body. */
147
+ export type AssignHandler = (bearer: string | undefined, body: unknown) => Promise<AssignOutcome>;
148
+ /** Narrow runtime surface the pool path drives after an assignment lands. */
149
+ export interface AssignedRuntime {
150
+ isReady(): boolean;
151
+ drain(): Promise<void>;
152
+ }
153
+ /** A live warm-pool assignment controller — its /assign handler + readiness/drain. */
154
+ export interface PoolAssign {
155
+ handler: AssignHandler;
156
+ isReady(): boolean;
157
+ drain(): Promise<void>;
158
+ assignedLeaseId(): string | null;
159
+ }
160
+ /**
161
+ * Build the warm pod's /assign controller. The cardinal rules:
162
+ * - auth: bearer MUST equal the pool token (constant-time).
163
+ * - single-assignment: a warm pod serves ONE profile for life — a repeat for the
164
+ * same lease is idempotent (200), a different lease is a conflict (409). The
165
+ * lease is claimed SYNCHRONOUSLY so a duplicate/concurrent POST conflicts.
166
+ * - eventual readiness: identity is applied then the real runtime is started in
167
+ * the BACKGROUND (hydrate + connect take seconds); /readyz is the gate, exactly
168
+ * as a cold pod whose Create returns fast and becomes Ready later.
169
+ * `startRuntime` is injected so the assign flow is testable without a real hub.
170
+ */
171
+ export declare function createPoolAssign(opts: {
172
+ poolToken: string;
173
+ env: NodeJS.ProcessEnv;
174
+ log: Pick<GatewayLogger, 'info' | 'warn' | 'error'>;
175
+ startRuntime: (env: NodeJS.ProcessEnv) => Promise<AssignedRuntime>;
176
+ }): PoolAssign;
177
+ /** Minimal ProviderStream surface the runtime needs — kept narrow for testing. */
178
+ export interface PodProvider {
179
+ connect(): Promise<void>;
180
+ disconnect(): Promise<void>;
181
+ isConnected(): boolean;
182
+ }
183
+ /** Minimal browser-runtime surface the runtime needs — kept narrow for testing. */
184
+ export interface PodBrowser {
185
+ stop(): Promise<void>;
186
+ }
187
+ /**
188
+ * Narrow S3-checkpoint surface (kept testable, decoupled from BrowserStateStore).
189
+ * `checkpointPeriodic` runs on a timer while the pod serves; `checkpointFinal` runs
190
+ * once during drain AFTER bb-browser is stopped, for a consistent snapshot.
191
+ */
192
+ export interface PodStateCheckpointer {
193
+ checkpointPeriodic(): Promise<void>;
194
+ checkpointFinal(): Promise<void>;
195
+ }
196
+ /**
197
+ * BrowserPodRuntime owns the pod's readiness state and the ordered teardown. It
198
+ * is deliberately decoupled from the concrete ClipProvider / BrowserProfileManager
199
+ * (only the narrow PodProvider / PodBrowser surfaces) so the readiness gate and
200
+ * drain ORDER are unit-testable without a real browser or hub.
201
+ */
202
+ export declare class BrowserPodRuntime {
203
+ private readonly provider;
204
+ private readonly browser;
205
+ private readonly log;
206
+ private readonly checkpointer?;
207
+ private readonly checkpointIntervalMs;
208
+ private draining;
209
+ private drainPromise;
210
+ private checkpointTimer;
211
+ constructor(provider: PodProvider, browser: PodBrowser, log: Pick<GatewayLogger, 'info' | 'warn' | 'error'>, checkpointer?: PodStateCheckpointer | undefined, checkpointIntervalMs?: number);
212
+ /**
213
+ * Route-readiness: registered to the hub AND not draining. `draining` is checked
214
+ * first so the readiness gate flips false the instant a drain begins — before
215
+ * the (async) ProviderStream teardown completes. The hub fences the stream on
216
+ * the pba_ token + live lease, so isConnected() already encodes "token/lease
217
+ * still valid".
218
+ */
219
+ isReady(): boolean;
220
+ /** Open the ProviderStream, register as the "browser" provider, and start the
221
+ * periodic checkpoint loop (if a checkpointer was supplied). */
222
+ start(): Promise<void>;
223
+ /** Periodic S3 checkpoints while serving. Best-effort: a checkpoint error is
224
+ * logged but never throws (it must not kill the pod); the timer is unref'd so it
225
+ * never keeps the process alive on its own. */
226
+ private startCheckpointLoop;
227
+ /**
228
+ * Graceful drain (SIGTERM / lease release): fail readiness FIRST, stop the
229
+ * periodic checkpoint loop, then tear down the hub stream and the browser, and
230
+ * finally take ONE last checkpoint AFTER bb-browser is stopped (a consistent
231
+ * snapshot of the settled state — design §3.2). Idempotent — a second SIGTERM
232
+ * joins the first.
233
+ */
234
+ drain(): Promise<void>;
235
+ }
236
+ /**
237
+ * Create the liveness/readiness HTTP server. `/livez` is mere process liveness;
238
+ * `/readyz` is route-readiness driven by `isReady`. Mirrors the Go stub's health
239
+ * contract so the controller's probes are runtime-agnostic.
240
+ */
241
+ export declare function createHealthServer(opts: {
242
+ isLive: () => boolean;
243
+ isReady: () => boolean;
244
+ log: Pick<GatewayLogger, 'info' | 'warn' | 'error'>;
245
+ onAssign?: AssignHandler;
246
+ }): http.Server;
247
+ /**
248
+ * Build the S3 state store from env, or return null (stateless pod) ONLY when no
249
+ * bucket is configured (the feature is off). When a bucket IS set, state was
250
+ * REQUESTED, so the org id (part of the S3 key + the pod's STS prefix scope) and the
251
+ * activation generation (the single-writer fence) are required: a missing/invalid
252
+ * value is a controller-injection misconfiguration and FAILS CLOSED (throws) rather
253
+ * than silently registering a non-persisted profile — silent stateless serving when
254
+ * state was configured is data loss. The thrown error propagates to pod startup, so
255
+ * the pod never reaches readiness and the controller releases it on the deadline.
256
+ */
257
+ export declare function buildStateStore(config: BrowserPodConfig, env: NodeJS.ProcessEnv, log: GatewayLogger): BrowserStateStore | null;
258
+ /** Resolve the periodic checkpoint cadence (ms) from env, clamped to ≥1s. */
259
+ export declare function resolveCheckpointIntervalMs(env: NodeJS.ProcessEnv): number;
260
+ /**
261
+ * Whether it is SAFE to checkpoint after a hydrate. Checkpoint ONLY when the prior
262
+ * snapshot was loaded (hydrated) or there was genuinely none (a new profile —
263
+ * head returned null, so no flags set). If a snapshot EXISTED but could not be
264
+ * loaded (checksum mismatch, or a download/extract/HEAD error), checkpointing must
265
+ * be disabled: an empty homeDir would otherwise overwrite the good state, and the
266
+ * generation fence permits it (this pod's gen is legitimately higher than the
267
+ * snapshot's). Returns false in that case so the pod runs checkpoint-less, leaving
268
+ * the existing snapshot untouched rather than clobbering it (simplified durability:
269
+ * the prior state is preserved in place — there is no controller-side repair).
270
+ */
271
+ export declare function shouldCheckpointAfterHydrate(result: HydrateResult): boolean;
272
+ /**
273
+ * Wire the real clip-runtime stack for a hosted browser pod from a resolved config
274
+ * and return the {@link BrowserPodRuntime} — WITHOUT creating the health server,
275
+ * binding a port, or parking on a signal. Splitting this out lets the warm-pool
276
+ * path (runPoolPod) reuse the EXACT assigned-pod wiring after a `/assign` arrives,
277
+ * while keeping a single control/health server bound on healthPort (the pool path
278
+ * already owns it). hydrate() runs here — before the provider opens — because
279
+ * bb-browser launches lazily on first invoke, so the snapshot must be on disk first.
280
+ */
281
+ export declare function preparePodRuntime(config: BrowserPodConfig, env: NodeJS.ProcessEnv, log: GatewayLogger): Promise<BrowserPodRuntime>;
282
+ /**
283
+ * Wire the real clip-runtime stack for a hosted browser pod and run until the
284
+ * abort signal fires (SIGTERM). Returns after the ordered drain completes. This is
285
+ * the ASSIGNED path: PRLL_ASSIGNMENT_TOKEN + profile are already in env (the
286
+ * controller's cold-create pod spec). The warm-pool path (runPoolPod) reaches the
287
+ * same runtime via preparePodRuntime once a `/assign` delivers the identity.
288
+ */
289
+ export declare function runBrowserPod(env: NodeJS.ProcessEnv, signal: AbortSignal, log: GatewayLogger): Promise<void>;
290
+ /**
291
+ * Run a WARM pod: bind ONE control/health server (livez/readyz/assign) on
292
+ * healthPort and park — no Chromium, no profile, no hub registration — until a
293
+ * `POST /assign` delivers an identity, at which point the pod transitions into the
294
+ * exact assigned-pod runtime (preparePodRuntime, hydrating S3 like a cold pod). On
295
+ * SIGTERM, drain the started runtime (if any) then close the server. The single
296
+ * server is the reason runPoolPod reuses preparePodRuntime rather than runBrowserPod
297
+ * (which would bind its own health port).
298
+ */
299
+ export declare function runPoolPod(env: NodeJS.ProcessEnv, signal: AbortSignal, log: GatewayLogger): Promise<void>;
300
+ export {};
301
+ //# sourceMappingURL=browser-pod.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"browser-pod.d.ts","sourceRoot":"","sources":["../src/browser-pod.ts"],"names":[],"mappings":"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"}