@hotcell/daemon 0.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.
Files changed (142) hide show
  1. package/dist/agent-check.d.ts +1 -0
  2. package/dist/agent-check.js +105 -0
  3. package/dist/agent-check.js.map +1 -0
  4. package/dist/api/server.d.ts +64 -0
  5. package/dist/api/server.js +1368 -0
  6. package/dist/api/server.js.map +1 -0
  7. package/dist/api/ws.d.ts +14 -0
  8. package/dist/api/ws.js +214 -0
  9. package/dist/api/ws.js.map +1 -0
  10. package/dist/applevz-check.d.ts +1 -0
  11. package/dist/applevz-check.js +280 -0
  12. package/dist/applevz-check.js.map +1 -0
  13. package/dist/backups.d.ts +29 -0
  14. package/dist/backups.js +76 -0
  15. package/dist/backups.js.map +1 -0
  16. package/dist/capacity.d.ts +63 -0
  17. package/dist/capacity.js +95 -0
  18. package/dist/capacity.js.map +1 -0
  19. package/dist/config.d.ts +241 -0
  20. package/dist/config.js +152 -0
  21. package/dist/config.js.map +1 -0
  22. package/dist/cost.d.ts +9 -0
  23. package/dist/cost.js +19 -0
  24. package/dist/cost.js.map +1 -0
  25. package/dist/density-bench.d.ts +1 -0
  26. package/dist/density-bench.js +97 -0
  27. package/dist/density-bench.js.map +1 -0
  28. package/dist/driver/agent-driver.d.ts +67 -0
  29. package/dist/driver/agent-driver.js +197 -0
  30. package/dist/driver/agent-driver.js.map +1 -0
  31. package/dist/driver/agent.d.ts +94 -0
  32. package/dist/driver/agent.js +319 -0
  33. package/dist/driver/agent.js.map +1 -0
  34. package/dist/driver/applevz.d.ts +95 -0
  35. package/dist/driver/applevz.js +527 -0
  36. package/dist/driver/applevz.js.map +1 -0
  37. package/dist/driver/container.d.ts +99 -0
  38. package/dist/driver/container.js +733 -0
  39. package/dist/driver/container.js.map +1 -0
  40. package/dist/driver/fc-api.d.ts +85 -0
  41. package/dist/driver/fc-api.js +173 -0
  42. package/dist/driver/fc-api.js.map +1 -0
  43. package/dist/driver/firecracker.d.ts +126 -0
  44. package/dist/driver/firecracker.js +560 -0
  45. package/dist/driver/firecracker.js.map +1 -0
  46. package/dist/driver/index.d.ts +17 -0
  47. package/dist/driver/index.js +61 -0
  48. package/dist/driver/index.js.map +1 -0
  49. package/dist/driver/router.d.ts +82 -0
  50. package/dist/driver/router.js +159 -0
  51. package/dist/driver/router.js.map +1 -0
  52. package/dist/driver/types.d.ts +234 -0
  53. package/dist/driver/types.js +2 -0
  54. package/dist/driver/types.js.map +1 -0
  55. package/dist/driver/unsupported.d.ts +50 -0
  56. package/dist/driver/unsupported.js +81 -0
  57. package/dist/driver/unsupported.js.map +1 -0
  58. package/dist/driver/vz-image.d.ts +35 -0
  59. package/dist/driver/vz-image.js +75 -0
  60. package/dist/driver/vz-image.js.map +1 -0
  61. package/dist/e2e-harness.d.ts +1 -0
  62. package/dist/e2e-harness.js +99 -0
  63. package/dist/e2e-harness.js.map +1 -0
  64. package/dist/egress-check.d.ts +8 -0
  65. package/dist/egress-check.js +317 -0
  66. package/dist/egress-check.js.map +1 -0
  67. package/dist/fc-check.d.ts +1 -0
  68. package/dist/fc-check.js +113 -0
  69. package/dist/fc-check.js.map +1 -0
  70. package/dist/index.d.ts +2 -0
  71. package/dist/index.js +114 -0
  72. package/dist/index.js.map +1 -0
  73. package/dist/kernels.d.ts +22 -0
  74. package/dist/kernels.js +134 -0
  75. package/dist/kernels.js.map +1 -0
  76. package/dist/lifecycle.d.ts +49 -0
  77. package/dist/lifecycle.js +111 -0
  78. package/dist/lifecycle.js.map +1 -0
  79. package/dist/logger.d.ts +16 -0
  80. package/dist/logger.js +67 -0
  81. package/dist/logger.js.map +1 -0
  82. package/dist/metrics.d.ts +46 -0
  83. package/dist/metrics.js +92 -0
  84. package/dist/metrics.js.map +1 -0
  85. package/dist/net/firewall.d.ts +4 -0
  86. package/dist/net/firewall.js +80 -0
  87. package/dist/net/firewall.js.map +1 -0
  88. package/dist/pricing.d.ts +36 -0
  89. package/dist/pricing.js +81 -0
  90. package/dist/pricing.js.map +1 -0
  91. package/dist/proxy/allowlist-default.d.ts +23 -0
  92. package/dist/proxy/allowlist-default.js +53 -0
  93. package/dist/proxy/allowlist-default.js.map +1 -0
  94. package/dist/proxy/allowlist.d.ts +43 -0
  95. package/dist/proxy/allowlist.js +87 -0
  96. package/dist/proxy/allowlist.js.map +1 -0
  97. package/dist/proxy/egress.d.ts +49 -0
  98. package/dist/proxy/egress.js +599 -0
  99. package/dist/proxy/egress.js.map +1 -0
  100. package/dist/proxy/ratelimit.d.ts +49 -0
  101. package/dist/proxy/ratelimit.js +74 -0
  102. package/dist/proxy/ratelimit.js.map +1 -0
  103. package/dist/proxy/server.d.ts +26 -0
  104. package/dist/proxy/server.js +202 -0
  105. package/dist/proxy/server.js.map +1 -0
  106. package/dist/router-check.d.ts +1 -0
  107. package/dist/router-check.js +97 -0
  108. package/dist/router-check.js.map +1 -0
  109. package/dist/smoke-fc.d.ts +1 -0
  110. package/dist/smoke-fc.js +183 -0
  111. package/dist/smoke-fc.js.map +1 -0
  112. package/dist/smoke-microvm.d.ts +1 -0
  113. package/dist/smoke-microvm.js +187 -0
  114. package/dist/smoke-microvm.js.map +1 -0
  115. package/dist/smoke-remote.d.ts +20 -0
  116. package/dist/smoke-remote.js +155 -0
  117. package/dist/smoke-remote.js.map +1 -0
  118. package/dist/smoke-vz.d.ts +1 -0
  119. package/dist/smoke-vz.js +161 -0
  120. package/dist/smoke-vz.js.map +1 -0
  121. package/dist/smoke.d.ts +7 -0
  122. package/dist/smoke.js +962 -0
  123. package/dist/smoke.js.map +1 -0
  124. package/dist/store.d.ts +124 -0
  125. package/dist/store.js +578 -0
  126. package/dist/store.js.map +1 -0
  127. package/dist/tracing.d.ts +45 -0
  128. package/dist/tracing.js +144 -0
  129. package/dist/tracing.js.map +1 -0
  130. package/dist/types.d.ts +274 -0
  131. package/dist/types.js +3 -0
  132. package/dist/types.js.map +1 -0
  133. package/dist/util.d.ts +27 -0
  134. package/dist/util.js +63 -0
  135. package/dist/util.js.map +1 -0
  136. package/dist/warmpool-check.d.ts +1 -0
  137. package/dist/warmpool-check.js +83 -0
  138. package/dist/warmpool-check.js.map +1 -0
  139. package/dist/web/dashboard.d.ts +1 -0
  140. package/dist/web/dashboard.js +456 -0
  141. package/dist/web/dashboard.js.map +1 -0
  142. package/package.json +53 -0
@@ -0,0 +1,560 @@
1
+ import { execFileSync, spawn } from "node:child_process";
2
+ import { createServer as createNetServer, connect as netConnect } from "node:net";
3
+ import { closeSync, createWriteStream, existsSync, ftruncateSync, lstatSync, mkdirSync, openSync, readlinkSync, rmSync, symlinkSync, unlinkSync, } from "node:fs";
4
+ import { totalmem, cpus as osCpus } from "node:os";
5
+ import { readFileSync } from "node:fs";
6
+ import { dirname, join } from "node:path";
7
+ import { setTimeout as sleep } from "node:timers/promises";
8
+ import { AgentConn } from "./agent.js";
9
+ import { AgentDriver } from "./agent-driver.js";
10
+ import { buildFcApiCalls, buildSnapshotCreateCall, buildSnapshotLoadCall, FC_DEFAULT_BOOT_ARGS, FC_PAUSE_VM, FC_START_ACTION, FcApi, fcVsockConnect, } from "./fc-api.js";
11
+ import { VzImageCache } from "./vz-image.js";
12
+ import { log } from "../logger.js";
13
+ const AGENT_VSOCK_PORT = 1024; // the in-guest agent listens here (matches VZ)
14
+ /**
15
+ * Firecracker microVM driver (Linux, KVM). Each sandbox is a Firecracker microVM:
16
+ * the driver spawns `firecracker`, configures it over its HTTP-API-over-unix-socket
17
+ * (boot source / machine-config / drives / vsock), boots it, and reaches the
18
+ * in-guest `sbx-agent` over virtio-vsock — the **same agent and wire protocol the
19
+ * Apple VZ driver uses**, so the entire agent-served surface (exec/files/processes/
20
+ * ports/terminal/stats/backup) is inherited from {@link AgentDriver} unchanged.
21
+ *
22
+ * **Host requirement:** `/dev/kvm` + the `firecracker` binary. All the code here is
23
+ * host-agnostic and compiles/unit-tests anywhere (see `check:fc`); only the live
24
+ * boot needs a KVM (or nested-virt) Linux host, gated behind `smoke:fc`.
25
+ */
26
+ export class FirecrackerDriver extends AgentDriver {
27
+ cfg;
28
+ name = "firecracker";
29
+ vms = new Map();
30
+ images;
31
+ pool = [];
32
+ poolTarget;
33
+ poolSeq = 0;
34
+ filling = false;
35
+ poolImage;
36
+ poolDir;
37
+ constructor(cfg) {
38
+ super();
39
+ this.cfg = cfg;
40
+ // The OCI→ext4 converter + staged guest files live under `helpers/hotcell-vz`
41
+ // (shared with the VZ driver: same rootfs artifact, same agent-as-init).
42
+ const vzDir = join(dirname(dirname(cfg.rootfs)));
43
+ this.images = new VzImageCache({
44
+ vzDir: vzDir.endsWith("guest") ? dirname(vzDir) : "helpers/hotcell-vz",
45
+ cacheDir: cfg.imageCacheDir,
46
+ prebuiltRootfs: cfg.rootfs,
47
+ // Convert OCI images for the host arch (the guest runs on this KVM host).
48
+ platform: cfg.platform ?? (process.arch === "arm64" ? "linux/arm64" : "linux/amd64"),
49
+ });
50
+ this.poolTarget = Math.max(0, cfg.warmPool ?? 0);
51
+ this.poolImage = cfg.poolImage ?? "base";
52
+ this.poolDir = join(cfg.stateDir, "_pool");
53
+ if (this.poolTarget > 0) {
54
+ // Clear stale slots from a previous run (their VMMs died with the daemon).
55
+ try {
56
+ rmSync(this.poolDir, { recursive: true, force: true });
57
+ }
58
+ catch {
59
+ /* not there */
60
+ }
61
+ this.fillPool();
62
+ }
63
+ }
64
+ // --- lifecycle ------------------------------------------------------------
65
+ async create(opts) {
66
+ await this.launch(opts);
67
+ for (const command of opts.setup ?? []) {
68
+ const code = await this.exec(opts.id, command, {}, () => { }).catch(() => -1);
69
+ if (code === 0)
70
+ log.info("setup command ok", { sandbox: opts.id, command });
71
+ else
72
+ log.warn("setup command failed (continuing)", { sandbox: opts.id, command, code });
73
+ }
74
+ }
75
+ async start(opts) {
76
+ await this.launch(opts);
77
+ }
78
+ /** Bring a sandbox live: adopt a warm-pool spare when eligible (instant), else
79
+ * resume its snapshot, else cold-boot. Then apply the sandbox env. */
80
+ async launch(opts) {
81
+ const id = opts.id;
82
+ if (this.vms.has(id))
83
+ return;
84
+ const stateDir = join(this.cfg.stateDir, id);
85
+ // Warm-pool adoption — must run before the canonical dir is created, since
86
+ // adoption makes that path a symlink to the spare's slot dir.
87
+ if (this.tryAdopt(opts)) {
88
+ if (opts.env && Object.keys(opts.env).length) {
89
+ await this.withConn(id, (c) => c.setEnv(opts.env));
90
+ }
91
+ log.info("firecracker VM up", { sandbox: id, warm: true });
92
+ return;
93
+ }
94
+ mkdirSync(stateDir, { recursive: true });
95
+ // If a snapshot exists from a fast-pause, resume from it (guest RAM + device
96
+ // state restored — no kernel boot; background processes come back live).
97
+ const vmstate = join(stateDir, "snapshot.vmstate");
98
+ const memFile = join(stateDir, "snapshot.mem");
99
+ if (existsSync(vmstate) && existsSync(memFile)) {
100
+ try {
101
+ await this.resumeFromSnapshot(id, stateDir, vmstate, memFile);
102
+ log.info("firecracker VM resumed from snapshot", { sandbox: id });
103
+ return;
104
+ }
105
+ catch (err) {
106
+ // A snapshot that won't load must never brick the sandbox: discard it and
107
+ // cold-boot (workspace intact — `snapshot()` synced the guest fs first;
108
+ // only live RAM/process state is lost).
109
+ log.warn("snapshot restore failed; discarding it and cold-booting", {
110
+ sandbox: id,
111
+ error: err.message,
112
+ });
113
+ for (const f of [vmstate, memFile])
114
+ rmQuiet(f);
115
+ }
116
+ }
117
+ const vm = await this.bootMicroVm({ id, stateDir, image: opts.image, limits: opts.limits });
118
+ this.vms.set(id, vm);
119
+ try {
120
+ if (opts.env && Object.keys(opts.env).length) {
121
+ await this.withConn(id, (c) => c.setEnv(opts.env));
122
+ }
123
+ }
124
+ catch (err) {
125
+ this.vms.delete(id);
126
+ await killAndWait(vm.proc);
127
+ throw err;
128
+ }
129
+ log.info("firecracker VM up", { sandbox: id });
130
+ }
131
+ /**
132
+ * Cold-boot a microVM in `stateDir` and wait for its in-guest agent, returning
133
+ * the live FcVm. Shared by the launch path and the warm-pool filler. Does not
134
+ * touch `this.vms` or apply sandbox env — the caller owns those.
135
+ */
136
+ async bootMicroVm(p) {
137
+ mkdirSync(p.stateDir, { recursive: true });
138
+ const rootfs = await this.images.ensureRootfs(p.image);
139
+ // First boot only: give the sandbox its own workspace disk (clone the blank
140
+ // pre-formatted template; else a sparse file the guest formats).
141
+ const workspaceImg = join(p.stateDir, "workspace.img");
142
+ if (!existsSync(workspaceImg)) {
143
+ let blank = null;
144
+ try {
145
+ blank = await this.images.ensureBlankWorkspace(this.cfg.diskGb);
146
+ }
147
+ catch (err) {
148
+ log.warn("blank workspace build failed; guest will format a sparse disk", {
149
+ sandbox: p.id,
150
+ error: err.message,
151
+ });
152
+ }
153
+ if (blank)
154
+ cloneFile(blank, workspaceImg);
155
+ else
156
+ ensureSparseFile(workspaceImg, this.cfg.diskGb * 1024 ** 3);
157
+ }
158
+ const cpus = p.limits?.cpus ? Math.max(1, Math.ceil(p.limits.cpus)) : 2;
159
+ const memMib = p.limits?.memoryMb && p.limits.memoryMb > 0 ? p.limits.memoryMb : 1024;
160
+ const pidsMax = p.limits?.pidsLimit && p.limits.pidsLimit > 0 ? p.limits.pidsLimit : 0;
161
+ const bootArgs = pidsMax > 0 ? `${FC_DEFAULT_BOOT_ARGS} hotcell.pids=${pidsMax} sbx.pids=${pidsMax}` : FC_DEFAULT_BOOT_ARGS;
162
+ const configureAndBoot = async () => {
163
+ const vm = await this.spawnVmm(p.stateDir);
164
+ try {
165
+ const api = new FcApi(vm.apiSock);
166
+ await api.applyAll(buildFcApiCalls({
167
+ kernelPath: this.cfg.kernel,
168
+ rootfsPath: rootfs,
169
+ workspacePath: workspaceImg,
170
+ vcpus: cpus,
171
+ memMib,
172
+ vsockUds: vm.vsockUds,
173
+ bootArgs,
174
+ }));
175
+ await api.call(FC_START_ACTION);
176
+ return vm;
177
+ }
178
+ catch (err) {
179
+ await killAndWait(vm.proc);
180
+ throw err;
181
+ }
182
+ };
183
+ const vm = await this.withOneRetry(p.id, configureAndBoot, "boot");
184
+ try {
185
+ await this.waitForAgent(vm);
186
+ // Cold boots need the in-guest side of the egress relay started (after a
187
+ // snapshot resume it's already alive in the restored RAM).
188
+ if (this.cfg.egressPort && this.cfg.egressPort > 0) {
189
+ const { socket, leftover } = await fcVsockConnect(vm.vsockUds, AGENT_VSOCK_PORT, 15000);
190
+ const conn = await AgentConn.attach(socket, leftover, 15000);
191
+ try {
192
+ await conn.egressListen(this.cfg.egressPort);
193
+ }
194
+ finally {
195
+ conn.close();
196
+ }
197
+ }
198
+ }
199
+ catch (err) {
200
+ await killAndWait(vm.proc);
201
+ throw err;
202
+ }
203
+ return vm;
204
+ }
205
+ // --- warm pool --------------------------------------------------------------
206
+ /** Spares currently ready for adoption (used by checks). */
207
+ poolSize() {
208
+ return this.pool.length;
209
+ }
210
+ /**
211
+ * Adopt a pre-booted spare for `opts` when eligible — a plain create of the
212
+ * pool image with default limits and no prior state. Adoption moves nothing:
213
+ * the canonical state dir becomes a **symlink** to the spare's slot dir, so
214
+ * every path the daemon joins under it resolves correctly while the absolute
215
+ * slot paths Firecracker recorded at boot (drives, vsock UDS) stay real — which
216
+ * keeps a later `snapshot()`/restore of the adopted VM loadable (`/snapshot/load`
217
+ * re-opens the boot-time paths embedded in the vmstate).
218
+ */
219
+ tryAdopt(opts) {
220
+ if (this.poolTarget <= 0)
221
+ return false;
222
+ const noLimits = !opts.limits || (!opts.limits.memoryMb && !opts.limits.cpus && !opts.limits.pidsLimit);
223
+ const canonical = join(this.cfg.stateDir, opts.id);
224
+ if (opts.image !== this.poolImage || !noLimits || existsSync(canonical))
225
+ return false;
226
+ const spare = this.pool.shift();
227
+ if (!spare) {
228
+ this.fillPool(); // none ready — warm up for next time
229
+ return false;
230
+ }
231
+ mkdirSync(dirname(canonical), { recursive: true });
232
+ symlinkSync(spare.stateDir, canonical);
233
+ this.vms.set(opts.id, spare);
234
+ this.fillPool(); // replenish in the background
235
+ log.info("firecracker adopted a warm-pool microVM", { sandbox: opts.id });
236
+ return true;
237
+ }
238
+ /** Top the pool up to its target in the background (one filler at a time). */
239
+ fillPool() {
240
+ if (this.poolTarget <= 0 || this.filling)
241
+ return;
242
+ void this.doFill();
243
+ }
244
+ async doFill() {
245
+ this.filling = true;
246
+ try {
247
+ while (this.pool.length < this.poolTarget) {
248
+ const n = ++this.poolSeq;
249
+ try {
250
+ const vm = await this.bootMicroVm({
251
+ id: `pool-${n}`,
252
+ stateDir: join(this.poolDir, `slot-${n}`),
253
+ image: this.poolImage,
254
+ });
255
+ this.pool.push(vm);
256
+ log.info("warm pool: spare microVM ready", { size: this.pool.length, target: this.poolTarget });
257
+ }
258
+ catch (err) {
259
+ log.warn("warm pool: spare boot failed (will retry on next claim)", {
260
+ error: err.message,
261
+ });
262
+ break; // don't hot-loop on a persistent failure
263
+ }
264
+ }
265
+ }
266
+ finally {
267
+ this.filling = false;
268
+ }
269
+ }
270
+ /** Tear down all spare microVMs (e.g. on daemon shutdown). Idempotent. */
271
+ async drainPool() {
272
+ this.poolTarget = 0;
273
+ const spares = this.pool.splice(0);
274
+ for (const vm of spares)
275
+ await killAndWait(vm.proc);
276
+ try {
277
+ rmSync(this.poolDir, { recursive: true, force: true });
278
+ }
279
+ catch {
280
+ /* ignore */
281
+ }
282
+ }
283
+ /** Spawn a fresh VMM process for `stateDir` and wait for its API socket. */
284
+ async spawnVmm(stateDir) {
285
+ const apiSock = join(stateDir, "fc-api.sock");
286
+ const vsockUds = join(stateDir, "vsock.sock");
287
+ for (const s of [apiSock, vsockUds])
288
+ rmQuiet(s);
289
+ const proc = spawn(this.cfg.fcBin, ["--api-sock", apiSock], { stdio: ["ignore", "pipe", "pipe"] });
290
+ proc.stdout.pipe(createWriteStream(join(stateDir, "console.log"), { flags: "a" }));
291
+ proc.stderr.pipe(createWriteStream(join(stateDir, "console.log"), { flags: "a" }));
292
+ const vm = { proc, apiSock, vsockUds, workspaceImg: join(stateDir, "workspace.img"), stateDir };
293
+ this.startEgressRelay(vm);
294
+ try {
295
+ await waitForFile(apiSock, 5000); // firecracker creates the API socket on startup
296
+ }
297
+ catch (err) {
298
+ await killAndWait(proc);
299
+ throw err;
300
+ }
301
+ return vm;
302
+ }
303
+ /**
304
+ * Host side of the guest egress relay. When the guest dials vsock port P,
305
+ * firecracker connects to the unix socket `<vsockUds>_P` — so we listen there
306
+ * and splice every such connection to the egress gateway. Set up per-VMM
307
+ * (boot, snapshot-load, and pool spares alike) before the guest can dial;
308
+ * torn down automatically with the VMM process.
309
+ */
310
+ startEgressRelay(vm) {
311
+ const port = this.cfg.egressPort;
312
+ if (!port || port <= 0)
313
+ return;
314
+ const path = `${vm.vsockUds}_${port}`;
315
+ rmQuiet(path);
316
+ const srv = createNetServer((guest) => {
317
+ const up = netConnect(port, this.cfg.egressHost ?? "127.0.0.1");
318
+ const close = () => {
319
+ guest.destroy();
320
+ up.destroy();
321
+ };
322
+ guest.pipe(up);
323
+ up.pipe(guest);
324
+ guest.on("error", close);
325
+ up.on("error", close);
326
+ guest.on("close", close);
327
+ up.on("close", close);
328
+ });
329
+ srv.on("error", (err) => log.warn("egress relay listener error", { path, error: String(err) }));
330
+ srv.listen(path);
331
+ vm.proc.once("exit", () => {
332
+ srv.close();
333
+ rmQuiet(path);
334
+ });
335
+ }
336
+ /**
337
+ * Run a VMM bring-up step, retrying once on a fresh process. Rationale: a VMM
338
+ * spawned immediately after the previous one's SIGKILL can die silently before
339
+ * serving its API (a transient KVM/VMM teardown race seen on nested-virt
340
+ * hosts, ~ECONNRESET mid-configure); a single respawn reliably clears it.
341
+ */
342
+ async withOneRetry(id, step, what) {
343
+ try {
344
+ return await step();
345
+ }
346
+ catch (err) {
347
+ log.warn(`firecracker ${what} failed; retrying once on a fresh VMM`, {
348
+ sandbox: id,
349
+ error: err.message,
350
+ });
351
+ try {
352
+ return await step();
353
+ }
354
+ catch (err2) {
355
+ throw new Error(`firecracker: VM ${what} failed: ${err2.message}`);
356
+ }
357
+ }
358
+ }
359
+ /** Poll the guest vsock until the agent answers its Hello, or time out. */
360
+ async waitForAgent(vm, timeoutMs = 30000) {
361
+ const deadline = Date.now() + timeoutMs;
362
+ let lastErr;
363
+ while (Date.now() < deadline) {
364
+ if (vm.proc.exitCode !== null) {
365
+ throw new Error(`firecracker exited (code ${vm.proc.exitCode}) before the agent came up`);
366
+ }
367
+ try {
368
+ const { socket, leftover } = await fcVsockConnect(vm.vsockUds, AGENT_VSOCK_PORT, 2000);
369
+ const conn = await AgentConn.attach(socket, leftover, 2000);
370
+ conn.close();
371
+ return;
372
+ }
373
+ catch (err) {
374
+ lastErr = err;
375
+ await sleep(400);
376
+ }
377
+ }
378
+ throw new Error(`firecracker: agent never came up: ${String(lastErr?.message ?? lastErr)}`);
379
+ }
380
+ /** Boot a fresh VMM and load the saved snapshot into it (no kernel boot). The
381
+ * snapshot pins the vsock UDS path; firecracker re-binds it on load (stale
382
+ * socket files are cleared by `spawnVmm`). */
383
+ async resumeFromSnapshot(id, stateDir, vmstate, memFile) {
384
+ const loadSnapshot = async () => {
385
+ const vm = await this.spawnVmm(stateDir);
386
+ try {
387
+ await new FcApi(vm.apiSock).call(buildSnapshotLoadCall(vmstate, memFile));
388
+ return vm;
389
+ }
390
+ catch (err) {
391
+ await killAndWait(vm.proc);
392
+ throw err;
393
+ }
394
+ };
395
+ const vm = await this.withOneRetry(id, loadSnapshot, "snapshot load");
396
+ this.vms.set(id, vm);
397
+ try {
398
+ await this.waitForAgent(vm);
399
+ }
400
+ catch (err) {
401
+ this.vms.delete(id);
402
+ await killAndWait(vm.proc);
403
+ throw err;
404
+ }
405
+ // One-shot: guest state diverges the moment the VM resumes, so a second load
406
+ // from these files would resurrect a stale past. Unlinking is safe — the VMM
407
+ // maps the memory file privately (copy-on-write).
408
+ for (const f of [vmstate, memFile])
409
+ rmQuiet(f);
410
+ }
411
+ /** A live VM can always be snapshot-paused (KVM snapshots have no OS gate). */
412
+ canSnapshot(id) {
413
+ return this.vms.has(id);
414
+ }
415
+ /**
416
+ * Fast-pause (B7): pause the vCPUs, write a Full Firecracker snapshot (device
417
+ * state + guest RAM) into the sandbox's state dir, and tear the VMM down. The
418
+ * next `start` resumes from it **without a kernel boot** — background
419
+ * processes/servers come back live. Same contract as the VZ driver's
420
+ * `snapshot()`: the guest fs is synced first, so if the later restore has to
421
+ * fall back to a cold boot the workspace is still intact.
422
+ */
423
+ async snapshot(id) {
424
+ const vm = this.vms.get(id);
425
+ if (!vm)
426
+ throw new Error(`firecracker: sandbox ${id} is not running`);
427
+ await this.exec(id, "sync", {}, () => { }).catch(() => { });
428
+ const api = new FcApi(vm.apiSock);
429
+ await api.call(FC_PAUSE_VM);
430
+ await api.call(buildSnapshotCreateCall(join(vm.stateDir, "snapshot.vmstate"), join(vm.stateDir, "snapshot.mem")));
431
+ this.vms.delete(id);
432
+ await killAndWait(vm.proc); // state saved; free the compute
433
+ for (const s of [vm.apiSock, vm.vsockUds])
434
+ rmQuiet(s);
435
+ }
436
+ async stop(id) {
437
+ const vm = this.vms.get(id);
438
+ if (!vm)
439
+ return;
440
+ // Flush the guest fs so workspace writes survive the abrupt teardown.
441
+ await this.exec(id, "sync", {}, () => { }).catch(() => { });
442
+ this.vms.delete(id);
443
+ await killAndWait(vm.proc); // tears down the microVM; workspace.img persists
444
+ for (const s of [vm.apiSock, vm.vsockUds])
445
+ rmQuiet(s);
446
+ }
447
+ async destroy(id) {
448
+ await this.stop(id);
449
+ const canonical = join(this.cfg.stateDir, id);
450
+ try {
451
+ // An adopted sandbox's canonical dir is a symlink to its warm-pool slot:
452
+ // remove the real slot dir first, then the link itself.
453
+ if (lstatSync(canonical).isSymbolicLink()) {
454
+ rmSync(readlinkSync(canonical), { recursive: true, force: true });
455
+ unlinkSync(canonical);
456
+ }
457
+ else {
458
+ rmSync(canonical, { recursive: true, force: true });
459
+ }
460
+ }
461
+ catch {
462
+ /* ignore */
463
+ }
464
+ }
465
+ // --- agent transport ------------------------------------------------------
466
+ /** Open a fresh AgentConn to the guest over Firecracker's vsock UDS (CONNECT
467
+ * handshake → the live socket carries the agent wire protocol). */
468
+ async openConn(id) {
469
+ const vm = this.vms.get(id);
470
+ if (!vm)
471
+ throw new Error(`firecracker: sandbox ${id} is not running`);
472
+ const { socket, leftover } = await fcVsockConnect(vm.vsockUds, AGENT_VSOCK_PORT, 15000);
473
+ return AgentConn.attach(socket, leftover, 15000);
474
+ }
475
+ // --- host probes ----------------------------------------------------------
476
+ async ping() {
477
+ if (!existsSync("/dev/kvm")) {
478
+ throw new Error("firecracker: /dev/kvm not present — needs a Linux host with KVM (bare metal " +
479
+ "or a nested-virtualization VM, e.g. GCE N2/C3). Use SBX_DRIVER=container otherwise.");
480
+ }
481
+ try {
482
+ execFileSync(this.cfg.fcBin, ["--version"], { stdio: "ignore" });
483
+ }
484
+ catch (err) {
485
+ throw new Error(`firecracker: cannot run "${this.cfg.fcBin}" (${err.message}). ` +
486
+ "Install firecracker or set SBX_FC_BIN.");
487
+ }
488
+ }
489
+ async hostInfo() {
490
+ // Prefer /proc on Linux; fall back to the os module elsewhere (e.g. building
491
+ // on a Mac, where this driver can't actually boot but should still report).
492
+ let memoryMb = Math.round(totalmem() / (1024 * 1024));
493
+ try {
494
+ const meminfo = readFileSync("/proc/meminfo", "utf8");
495
+ const m = /MemTotal:\s+(\d+)\s+kB/.exec(meminfo);
496
+ if (m)
497
+ memoryMb = Math.round(Number(m[1]) / 1024);
498
+ }
499
+ catch {
500
+ /* not Linux; use totalmem() */
501
+ }
502
+ return { memoryMb, cpus: osCpus().length };
503
+ }
504
+ }
505
+ /** Remove a file, ignoring a missing one. */
506
+ function rmQuiet(path) {
507
+ try {
508
+ unlinkSync(path);
509
+ }
510
+ catch {
511
+ /* not there */
512
+ }
513
+ }
514
+ /** SIGKILL a VMM and wait until the process has actually exited, so the next
515
+ * spawn never overlaps the previous VM's kernel-side teardown. */
516
+ function killAndWait(proc, timeoutMs = 3000) {
517
+ return new Promise((resolve) => {
518
+ if (proc.exitCode !== null || proc.signalCode !== null)
519
+ return resolve();
520
+ const timer = setTimeout(resolve, timeoutMs);
521
+ proc.once("exit", () => {
522
+ clearTimeout(timer);
523
+ resolve();
524
+ });
525
+ proc.kill("SIGKILL");
526
+ });
527
+ }
528
+ /** Copy `src`→`dst`, preferring a CoW reflink (btrfs/xfs) and falling back to a
529
+ * plain sparse-aware copy. Gives each sandbox its own workspace disk cheaply. */
530
+ function cloneFile(src, dst) {
531
+ try {
532
+ execFileSync("cp", ["--reflink=auto", src, dst]);
533
+ }
534
+ catch {
535
+ execFileSync("cp", [src, dst]);
536
+ }
537
+ }
538
+ /** Create a sparse file of `sizeBytes` if it doesn't exist (workspace disk). */
539
+ function ensureSparseFile(path, sizeBytes) {
540
+ if (existsSync(path))
541
+ return;
542
+ const fd = openSync(path, "w");
543
+ try {
544
+ ftruncateSync(fd, sizeBytes);
545
+ }
546
+ finally {
547
+ closeSync(fd);
548
+ }
549
+ }
550
+ /** Resolve once `path` exists, polling, or reject after `timeoutMs`. */
551
+ async function waitForFile(path, timeoutMs) {
552
+ const deadline = Date.now() + timeoutMs;
553
+ while (Date.now() < deadline) {
554
+ if (existsSync(path))
555
+ return;
556
+ await sleep(50);
557
+ }
558
+ throw new Error(`timed out waiting for ${path}`);
559
+ }
560
+ //# sourceMappingURL=firecracker.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"firecracker.js","sourceRoot":"","sources":["../../src/driver/firecracker.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,YAAY,EAAE,KAAK,EAAqB,MAAM,oBAAoB,CAAC;AAC5E,OAAO,EAAE,YAAY,IAAI,eAAe,EAAE,OAAO,IAAI,UAAU,EAAE,MAAM,UAAU,CAAC;AAClF,OAAO,EACL,SAAS,EACT,iBAAiB,EACjB,UAAU,EACV,aAAa,EACb,SAAS,EACT,SAAS,EACT,QAAQ,EACR,YAAY,EACZ,MAAM,EACN,WAAW,EACX,UAAU,GACX,MAAM,SAAS,CAAC;AACjB,OAAO,EAAE,QAAQ,EAAE,IAAI,IAAI,MAAM,EAAE,MAAM,SAAS,CAAC;AACnD,OAAO,EAAE,YAAY,EAAE,MAAM,SAAS,CAAC;AACvC,OAAO,EAAE,OAAO,EAAE,IAAI,EAAE,MAAM,WAAW,CAAC;AAC1C,OAAO,EAAE,UAAU,IAAI,KAAK,EAAE,MAAM,sBAAsB,CAAC;AAC3D,OAAO,EAAE,SAAS,EAAE,MAAM,YAAY,CAAC;AACvC,OAAO,EAAE,WAAW,EAAE,MAAM,mBAAmB,CAAC;AAChD,OAAO,EACL,eAAe,EACf,uBAAuB,EACvB,qBAAqB,EACrB,oBAAoB,EACpB,WAAW,EACX,eAAe,EACf,KAAK,EACL,cAAc,GACf,MAAM,aAAa,CAAC;AACrB,OAAO,EAAE,YAAY,EAAE,MAAM,eAAe,CAAC;AAE7C,OAAO,EAAE,GAAG,EAAE,MAAM,cAAc,CAAC;AAyCnC,MAAM,gBAAgB,GAAG,IAAI,CAAC,CAAC,+CAA+C;AAE9E;;;;;;;;;;;GAWG;AACH,MAAM,OAAO,iBAAkB,SAAQ,WAAW;IAWnB;IAVpB,IAAI,GAAG,aAAa,CAAC;IACtB,GAAG,GAAG,IAAI,GAAG,EAAgB,CAAC;IAC9B,MAAM,CAAe;IACrB,IAAI,GAAW,EAAE,CAAC;IAClB,UAAU,CAAS;IACnB,OAAO,GAAG,CAAC,CAAC;IACZ,OAAO,GAAG,KAAK,CAAC;IACP,SAAS,CAAS;IAClB,OAAO,CAAS;IAEjC,YAA6B,GAAa;QACxC,KAAK,EAAE,CAAC;QADmB,QAAG,GAAH,GAAG,CAAU;QAExC,8EAA8E;QAC9E,yEAAyE;QACzE,MAAM,KAAK,GAAG,IAAI,CAAC,OAAO,CAAC,OAAO,CAAC,GAAG,CAAC,MAAM,CAAC,CAAC,CAAC,CAAC;QACjD,IAAI,CAAC,MAAM,GAAG,IAAI,YAAY,CAAC;YAC7B,KAAK,EAAE,KAAK,CAAC,QAAQ,CAAC,OAAO,CAAC,CAAC,CAAC,CAAC,OAAO,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,oBAAoB;YACtE,QAAQ,EAAE,GAAG,CAAC,aAAa;YAC3B,cAAc,EAAE,GAAG,CAAC,MAAM;YAC1B,0EAA0E;YAC1E,QAAQ,EAAE,GAAG,CAAC,QAAQ,IAAI,CAAC,OAAO,CAAC,IAAI,KAAK,OAAO,CAAC,CAAC,CAAC,aAAa,CAAC,CAAC,CAAC,aAAa,CAAC;SACrF,CAAC,CAAC;QACH,IAAI,CAAC,UAAU,GAAG,IAAI,CAAC,GAAG,CAAC,CAAC,EAAE,GAAG,CAAC,QAAQ,IAAI,CAAC,CAAC,CAAC;QACjD,IAAI,CAAC,SAAS,GAAG,GAAG,CAAC,SAAS,IAAI,MAAM,CAAC;QACzC,IAAI,CAAC,OAAO,GAAG,IAAI,CAAC,GAAG,CAAC,QAAQ,EAAE,OAAO,CAAC,CAAC;QAC3C,IAAI,IAAI,CAAC,UAAU,GAAG,CAAC,EAAE,CAAC;YACxB,2EAA2E;YAC3E,IAAI,CAAC;gBACH,MAAM,CAAC,IAAI,CAAC,OAAO,EAAE,EAAE,SAAS,EAAE,IAAI,EAAE,KAAK,EAAE,IAAI,EAAE,CAAC,CAAC;YACzD,CAAC;YAAC,MAAM,CAAC;gBACP,eAAe;YACjB,CAAC;YACD,IAAI,CAAC,QAAQ,EAAE,CAAC;QAClB,CAAC;IACH,CAAC;IAED,6EAA6E;IAE7E,KAAK,CAAC,MAAM,CAAC,IAAmB;QAC9B,MAAM,IAAI,CAAC,MAAM,CAAC,IAAI,CAAC,CAAC;QACxB,KAAK,MAAM,OAAO,IAAI,IAAI,CAAC,KAAK,IAAI,EAAE,EAAE,CAAC;YACvC,MAAM,IAAI,GAAG,MAAM,IAAI,CAAC,IAAI,CAAC,IAAI,CAAC,EAAE,EAAE,OAAO,EAAE,EAAE,EAAE,GAAG,EAAE,GAAE,CAAC,CAAC,CAAC,KAAK,CAAC,GAAG,EAAE,CAAC,CAAC,CAAC,CAAC,CAAC;YAC7E,IAAI,IAAI,KAAK,CAAC;gBAAE,GAAG,CAAC,IAAI,CAAC,kBAAkB,EAAE,EAAE,OAAO,EAAE,IAAI,CAAC,EAAE,EAAE,OAAO,EAAE,CAAC,CAAC;;gBACvE,GAAG,CAAC,IAAI,CAAC,mCAAmC,EAAE,EAAE,OAAO,EAAE,IAAI,CAAC,EAAE,EAAE,OAAO,EAAE,IAAI,EAAE,CAAC,CAAC;QAC1F,CAAC;IACH,CAAC;IAED,KAAK,CAAC,KAAK,CAAC,IAAmB;QAC7B,MAAM,IAAI,CAAC,MAAM,CAAC,IAAI,CAAC,CAAC;IAC1B,CAAC;IAED;2EACuE;IAC/D,KAAK,CAAC,MAAM,CAAC,IAAmB;QACtC,MAAM,EAAE,GAAG,IAAI,CAAC,EAAE,CAAC;QACnB,IAAI,IAAI,CAAC,GAAG,CAAC,GAAG,CAAC,EAAE,CAAC;YAAE,OAAO;QAC7B,MAAM,QAAQ,GAAG,IAAI,CAAC,IAAI,CAAC,GAAG,CAAC,QAAQ,EAAE,EAAE,CAAC,CAAC;QAE7C,2EAA2E;QAC3E,8DAA8D;QAC9D,IAAI,IAAI,CAAC,QAAQ,CAAC,IAAI,CAAC,EAAE,CAAC;YACxB,IAAI,IAAI,CAAC,GAAG,IAAI,MAAM,CAAC,IAAI,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC,MAAM,EAAE,CAAC;gBAC7C,MAAM,IAAI,CAAC,QAAQ,CAAC,EAAE,EAAE,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,MAAM,CAAC,IAAI,CAAC,GAAI,CAAC,CAAC,CAAC;YACtD,CAAC;YACD,GAAG,CAAC,IAAI,CAAC,mBAAmB,EAAE,EAAE,OAAO,EAAE,EAAE,EAAE,IAAI,EAAE,IAAI,EAAE,CAAC,CAAC;YAC3D,OAAO;QACT,CAAC;QAED,SAAS,CAAC,QAAQ,EAAE,EAAE,SAAS,EAAE,IAAI,EAAE,CAAC,CAAC;QAEzC,6EAA6E;QAC7E,yEAAyE;QACzE,MAAM,OAAO,GAAG,IAAI,CAAC,QAAQ,EAAE,kBAAkB,CAAC,CAAC;QACnD,MAAM,OAAO,GAAG,IAAI,CAAC,QAAQ,EAAE,cAAc,CAAC,CAAC;QAC/C,IAAI,UAAU,CAAC,OAAO,CAAC,IAAI,UAAU,CAAC,OAAO,CAAC,EAAE,CAAC;YAC/C,IAAI,CAAC;gBACH,MAAM,IAAI,CAAC,kBAAkB,CAAC,EAAE,EAAE,QAAQ,EAAE,OAAO,EAAE,OAAO,CAAC,CAAC;gBAC9D,GAAG,CAAC,IAAI,CAAC,sCAAsC,EAAE,EAAE,OAAO,EAAE,EAAE,EAAE,CAAC,CAAC;gBAClE,OAAO;YACT,CAAC;YAAC,OAAO,GAAG,EAAE,CAAC;gBACb,0EAA0E;gBAC1E,wEAAwE;gBACxE,wCAAwC;gBACxC,GAAG,CAAC,IAAI,CAAC,yDAAyD,EAAE;oBAClE,OAAO,EAAE,EAAE;oBACX,KAAK,EAAG,GAAa,CAAC,OAAO;iBAC9B,CAAC,CAAC;gBACH,KAAK,MAAM,CAAC,IAAI,CAAC,OAAO,EAAE,OAAO,CAAC;oBAAE,OAAO,CAAC,CAAC,CAAC,CAAC;YACjD,CAAC;QACH,CAAC;QAED,MAAM,EAAE,GAAG,MAAM,IAAI,CAAC,WAAW,CAAC,EAAE,EAAE,EAAE,QAAQ,EAAE,KAAK,EAAE,IAAI,CAAC,KAAK,EAAE,MAAM,EAAE,IAAI,CAAC,MAAM,EAAE,CAAC,CAAC;QAC5F,IAAI,CAAC,GAAG,CAAC,GAAG,CAAC,EAAE,EAAE,EAAE,CAAC,CAAC;QACrB,IAAI,CAAC;YACH,IAAI,IAAI,CAAC,GAAG,IAAI,MAAM,CAAC,IAAI,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC,MAAM,EAAE,CAAC;gBAC7C,MAAM,IAAI,CAAC,QAAQ,CAAC,EAAE,EAAE,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,MAAM,CAAC,IAAI,CAAC,GAAI,CAAC,CAAC,CAAC;YACtD,CAAC;QACH,CAAC;QAAC,OAAO,GAAG,EAAE,CAAC;YACb,IAAI,CAAC,GAAG,CAAC,MAAM,CAAC,EAAE,CAAC,CAAC;YACpB,MAAM,WAAW,CAAC,EAAE,CAAC,IAAI,CAAC,CAAC;YAC3B,MAAM,GAAG,CAAC;QACZ,CAAC;QACD,GAAG,CAAC,IAAI,CAAC,mBAAmB,EAAE,EAAE,OAAO,EAAE,EAAE,EAAE,CAAC,CAAC;IACjD,CAAC;IAED;;;;OAIG;IACK,KAAK,CAAC,WAAW,CAAC,CAKzB;QACC,SAAS,CAAC,CAAC,CAAC,QAAQ,EAAE,EAAE,SAAS,EAAE,IAAI,EAAE,CAAC,CAAC;QAC3C,MAAM,MAAM,GAAG,MAAM,IAAI,CAAC,MAAM,CAAC,YAAY,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC;QAEvD,4EAA4E;QAC5E,iEAAiE;QACjE,MAAM,YAAY,GAAG,IAAI,CAAC,CAAC,CAAC,QAAQ,EAAE,eAAe,CAAC,CAAC;QACvD,IAAI,CAAC,UAAU,CAAC,YAAY,CAAC,EAAE,CAAC;YAC9B,IAAI,KAAK,GAAkB,IAAI,CAAC;YAChC,IAAI,CAAC;gBACH,KAAK,GAAG,MAAM,IAAI,CAAC,MAAM,CAAC,oBAAoB,CAAC,IAAI,CAAC,GAAG,CAAC,MAAM,CAAC,CAAC;YAClE,CAAC;YAAC,OAAO,GAAG,EAAE,CAAC;gBACb,GAAG,CAAC,IAAI,CAAC,+DAA+D,EAAE;oBACxE,OAAO,EAAE,CAAC,CAAC,EAAE;oBACb,KAAK,EAAG,GAAa,CAAC,OAAO;iBAC9B,CAAC,CAAC;YACL,CAAC;YACD,IAAI,KAAK;gBAAE,SAAS,CAAC,KAAK,EAAE,YAAY,CAAC,CAAC;;gBACrC,gBAAgB,CAAC,YAAY,EAAE,IAAI,CAAC,GAAG,CAAC,MAAM,GAAG,IAAI,IAAI,CAAC,CAAC,CAAC;QACnE,CAAC;QAED,MAAM,IAAI,GAAG,CAAC,CAAC,MAAM,EAAE,IAAI,CAAC,CAAC,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC,EAAE,IAAI,CAAC,IAAI,CAAC,CAAC,CAAC,MAAM,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC;QACxE,MAAM,MAAM,GAAG,CAAC,CAAC,MAAM,EAAE,QAAQ,IAAI,CAAC,CAAC,MAAM,CAAC,QAAQ,GAAG,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,MAAM,CAAC,QAAQ,CAAC,CAAC,CAAC,IAAI,CAAC;QACtF,MAAM,OAAO,GAAG,CAAC,CAAC,MAAM,EAAE,SAAS,IAAI,CAAC,CAAC,MAAM,CAAC,SAAS,GAAG,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,MAAM,CAAC,SAAS,CAAC,CAAC,CAAC,CAAC,CAAC;QACvF,MAAM,QAAQ,GAAG,OAAO,GAAG,CAAC,CAAC,CAAC,CAAC,GAAG,oBAAoB,iBAAiB,OAAO,aAAa,OAAO,EAAE,CAAC,CAAC,CAAC,oBAAoB,CAAC;QAE5H,MAAM,gBAAgB,GAAG,KAAK,IAAmB,EAAE;YACjD,MAAM,EAAE,GAAG,MAAM,IAAI,CAAC,QAAQ,CAAC,CAAC,CAAC,QAAQ,CAAC,CAAC;YAC3C,IAAI,CAAC;gBACH,MAAM,GAAG,GAAG,IAAI,KAAK,CAAC,EAAE,CAAC,OAAO,CAAC,CAAC;gBAClC,MAAM,GAAG,CAAC,QAAQ,CAChB,eAAe,CAAC;oBACd,UAAU,EAAE,IAAI,CAAC,GAAG,CAAC,MAAM;oBAC3B,UAAU,EAAE,MAAM;oBAClB,aAAa,EAAE,YAAY;oBAC3B,KAAK,EAAE,IAAI;oBACX,MAAM;oBACN,QAAQ,EAAE,EAAE,CAAC,QAAQ;oBACrB,QAAQ;iBACT,CAAC,CACH,CAAC;gBACF,MAAM,GAAG,CAAC,IAAI,CAAC,eAAe,CAAC,CAAC;gBAChC,OAAO,EAAE,CAAC;YACZ,CAAC;YAAC,OAAO,GAAG,EAAE,CAAC;gBACb,MAAM,WAAW,CAAC,EAAE,CAAC,IAAI,CAAC,CAAC;gBAC3B,MAAM,GAAG,CAAC;YACZ,CAAC;QACH,CAAC,CAAC;QACF,MAAM,EAAE,GAAG,MAAM,IAAI,CAAC,YAAY,CAAC,CAAC,CAAC,EAAE,EAAE,gBAAgB,EAAE,MAAM,CAAC,CAAC;QACnE,IAAI,CAAC;YACH,MAAM,IAAI,CAAC,YAAY,CAAC,EAAE,CAAC,CAAC;YAC5B,yEAAyE;YACzE,2DAA2D;YAC3D,IAAI,IAAI,CAAC,GAAG,CAAC,UAAU,IAAI,IAAI,CAAC,GAAG,CAAC,UAAU,GAAG,CAAC,EAAE,CAAC;gBACnD,MAAM,EAAE,MAAM,EAAE,QAAQ,EAAE,GAAG,MAAM,cAAc,CAAC,EAAE,CAAC,QAAQ,EAAE,gBAAgB,EAAE,KAAK,CAAC,CAAC;gBACxF,MAAM,IAAI,GAAG,MAAM,SAAS,CAAC,MAAM,CAAC,MAAM,EAAE,QAAQ,EAAE,KAAK,CAAC,CAAC;gBAC7D,IAAI,CAAC;oBACH,MAAM,IAAI,CAAC,YAAY,CAAC,IAAI,CAAC,GAAG,CAAC,UAAU,CAAC,CAAC;gBAC/C,CAAC;wBAAS,CAAC;oBACT,IAAI,CAAC,KAAK,EAAE,CAAC;gBACf,CAAC;YACH,CAAC;QACH,CAAC;QAAC,OAAO,GAAG,EAAE,CAAC;YACb,MAAM,WAAW,CAAC,EAAE,CAAC,IAAI,CAAC,CAAC;YAC3B,MAAM,GAAG,CAAC;QACZ,CAAC;QACD,OAAO,EAAE,CAAC;IACZ,CAAC;IAED,+EAA+E;IAE/E,4DAA4D;IAC5D,QAAQ;QACN,OAAO,IAAI,CAAC,IAAI,CAAC,MAAM,CAAC;IAC1B,CAAC;IAED;;;;;;;;OAQG;IACK,QAAQ,CAAC,IAAmB;QAClC,IAAI,IAAI,CAAC,UAAU,IAAI,CAAC;YAAE,OAAO,KAAK,CAAC;QACvC,MAAM,QAAQ,GACZ,CAAC,IAAI,CAAC,MAAM,IAAI,CAAC,CAAC,IAAI,CAAC,MAAM,CAAC,QAAQ,IAAI,CAAC,IAAI,CAAC,MAAM,CAAC,IAAI,IAAI,CAAC,IAAI,CAAC,MAAM,CAAC,SAAS,CAAC,CAAC;QACzF,MAAM,SAAS,GAAG,IAAI,CAAC,IAAI,CAAC,GAAG,CAAC,QAAQ,EAAE,IAAI,CAAC,EAAE,CAAC,CAAC;QACnD,IAAI,IAAI,CAAC,KAAK,KAAK,IAAI,CAAC,SAAS,IAAI,CAAC,QAAQ,IAAI,UAAU,CAAC,SAAS,CAAC;YAAE,OAAO,KAAK,CAAC;QAEtF,MAAM,KAAK,GAAG,IAAI,CAAC,IAAI,CAAC,KAAK,EAAE,CAAC;QAChC,IAAI,CAAC,KAAK,EAAE,CAAC;YACX,IAAI,CAAC,QAAQ,EAAE,CAAC,CAAC,qCAAqC;YACtD,OAAO,KAAK,CAAC;QACf,CAAC;QACD,SAAS,CAAC,OAAO,CAAC,SAAS,CAAC,EAAE,EAAE,SAAS,EAAE,IAAI,EAAE,CAAC,CAAC;QACnD,WAAW,CAAC,KAAK,CAAC,QAAQ,EAAE,SAAS,CAAC,CAAC;QACvC,IAAI,CAAC,GAAG,CAAC,GAAG,CAAC,IAAI,CAAC,EAAE,EAAE,KAAK,CAAC,CAAC;QAC7B,IAAI,CAAC,QAAQ,EAAE,CAAC,CAAC,8BAA8B;QAC/C,GAAG,CAAC,IAAI,CAAC,yCAAyC,EAAE,EAAE,OAAO,EAAE,IAAI,CAAC,EAAE,EAAE,CAAC,CAAC;QAC1E,OAAO,IAAI,CAAC;IACd,CAAC;IAED,8EAA8E;IACtE,QAAQ;QACd,IAAI,IAAI,CAAC,UAAU,IAAI,CAAC,IAAI,IAAI,CAAC,OAAO;YAAE,OAAO;QACjD,KAAK,IAAI,CAAC,MAAM,EAAE,CAAC;IACrB,CAAC;IAEO,KAAK,CAAC,MAAM;QAClB,IAAI,CAAC,OAAO,GAAG,IAAI,CAAC;QACpB,IAAI,CAAC;YACH,OAAO,IAAI,CAAC,IAAI,CAAC,MAAM,GAAG,IAAI,CAAC,UAAU,EAAE,CAAC;gBAC1C,MAAM,CAAC,GAAG,EAAE,IAAI,CAAC,OAAO,CAAC;gBACzB,IAAI,CAAC;oBACH,MAAM,EAAE,GAAG,MAAM,IAAI,CAAC,WAAW,CAAC;wBAChC,EAAE,EAAE,QAAQ,CAAC,EAAE;wBACf,QAAQ,EAAE,IAAI,CAAC,IAAI,CAAC,OAAO,EAAE,QAAQ,CAAC,EAAE,CAAC;wBACzC,KAAK,EAAE,IAAI,CAAC,SAAS;qBACtB,CAAC,CAAC;oBACH,IAAI,CAAC,IAAI,CAAC,IAAI,CAAC,EAAE,CAAC,CAAC;oBACnB,GAAG,CAAC,IAAI,CAAC,gCAAgC,EAAE,EAAE,IAAI,EAAE,IAAI,CAAC,IAAI,CAAC,MAAM,EAAE,MAAM,EAAE,IAAI,CAAC,UAAU,EAAE,CAAC,CAAC;gBAClG,CAAC;gBAAC,OAAO,GAAG,EAAE,CAAC;oBACb,GAAG,CAAC,IAAI,CAAC,yDAAyD,EAAE;wBAClE,KAAK,EAAG,GAAa,CAAC,OAAO;qBAC9B,CAAC,CAAC;oBACH,MAAM,CAAC,yCAAyC;gBAClD,CAAC;YACH,CAAC;QACH,CAAC;gBAAS,CAAC;YACT,IAAI,CAAC,OAAO,GAAG,KAAK,CAAC;QACvB,CAAC;IACH,CAAC;IAED,0EAA0E;IAC1E,KAAK,CAAC,SAAS;QACb,IAAI,CAAC,UAAU,GAAG,CAAC,CAAC;QACpB,MAAM,MAAM,GAAG,IAAI,CAAC,IAAI,CAAC,MAAM,CAAC,CAAC,CAAC,CAAC;QACnC,KAAK,MAAM,EAAE,IAAI,MAAM;YAAE,MAAM,WAAW,CAAC,EAAE,CAAC,IAAI,CAAC,CAAC;QACpD,IAAI,CAAC;YACH,MAAM,CAAC,IAAI,CAAC,OAAO,EAAE,EAAE,SAAS,EAAE,IAAI,EAAE,KAAK,EAAE,IAAI,EAAE,CAAC,CAAC;QACzD,CAAC;QAAC,MAAM,CAAC;YACP,YAAY;QACd,CAAC;IACH,CAAC;IAED,4EAA4E;IACpE,KAAK,CAAC,QAAQ,CAAC,QAAgB;QACrC,MAAM,OAAO,GAAG,IAAI,CAAC,QAAQ,EAAE,aAAa,CAAC,CAAC;QAC9C,MAAM,QAAQ,GAAG,IAAI,CAAC,QAAQ,EAAE,YAAY,CAAC,CAAC;QAC9C,KAAK,MAAM,CAAC,IAAI,CAAC,OAAO,EAAE,QAAQ,CAAC;YAAE,OAAO,CAAC,CAAC,CAAC,CAAC;QAChD,MAAM,IAAI,GAAG,KAAK,CAAC,IAAI,CAAC,GAAG,CAAC,KAAK,EAAE,CAAC,YAAY,EAAE,OAAO,CAAC,EAAE,EAAE,KAAK,EAAE,CAAC,QAAQ,EAAE,MAAM,EAAE,MAAM,CAAC,EAAE,CAAC,CAAC;QACnG,IAAI,CAAC,MAAM,CAAC,IAAI,CAAC,iBAAiB,CAAC,IAAI,CAAC,QAAQ,EAAE,aAAa,CAAC,EAAE,EAAE,KAAK,EAAE,GAAG,EAAE,CAAC,CAAC,CAAC;QACnF,IAAI,CAAC,MAAM,CAAC,IAAI,CAAC,iBAAiB,CAAC,IAAI,CAAC,QAAQ,EAAE,aAAa,CAAC,EAAE,EAAE,KAAK,EAAE,GAAG,EAAE,CAAC,CAAC,CAAC;QACnF,MAAM,EAAE,GAAS,EAAE,IAAI,EAAE,OAAO,EAAE,QAAQ,EAAE,YAAY,EAAE,IAAI,CAAC,QAAQ,EAAE,eAAe,CAAC,EAAE,QAAQ,EAAE,CAAC;QACtG,IAAI,CAAC,gBAAgB,CAAC,EAAE,CAAC,CAAC;QAC1B,IAAI,CAAC;YACH,MAAM,WAAW,CAAC,OAAO,EAAE,IAAI,CAAC,CAAC,CAAC,gDAAgD;QACpF,CAAC;QAAC,OAAO,GAAG,EAAE,CAAC;YACb,MAAM,WAAW,CAAC,IAAI,CAAC,CAAC;YACxB,MAAM,GAAG,CAAC;QACZ,CAAC;QACD,OAAO,EAAE,CAAC;IACZ,CAAC;IAED;;;;;;OAMG;IACK,gBAAgB,CAAC,EAAQ;QAC/B,MAAM,IAAI,GAAG,IAAI,CAAC,GAAG,CAAC,UAAU,CAAC;QACjC,IAAI,CAAC,IAAI,IAAI,IAAI,IAAI,CAAC;YAAE,OAAO;QAC/B,MAAM,IAAI,GAAG,GAAG,EAAE,CAAC,QAAQ,IAAI,IAAI,EAAE,CAAC;QACtC,OAAO,CAAC,IAAI,CAAC,CAAC;QACd,MAAM,GAAG,GAAG,eAAe,CAAC,CAAC,KAAK,EAAE,EAAE;YACpC,MAAM,EAAE,GAAG,UAAU,CAAC,IAAI,EAAE,IAAI,CAAC,GAAG,CAAC,UAAU,IAAI,WAAW,CAAC,CAAC;YAChE,MAAM,KAAK,GAAG,GAAS,EAAE;gBACvB,KAAK,CAAC,OAAO,EAAE,CAAC;gBAChB,EAAE,CAAC,OAAO,EAAE,CAAC;YACf,CAAC,CAAC;YACF,KAAK,CAAC,IAAI,CAAC,EAAE,CAAC,CAAC;YACf,EAAE,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC;YACf,KAAK,CAAC,EAAE,CAAC,OAAO,EAAE,KAAK,CAAC,CAAC;YACzB,EAAE,CAAC,EAAE,CAAC,OAAO,EAAE,KAAK,CAAC,CAAC;YACtB,KAAK,CAAC,EAAE,CAAC,OAAO,EAAE,KAAK,CAAC,CAAC;YACzB,EAAE,CAAC,EAAE,CAAC,OAAO,EAAE,KAAK,CAAC,CAAC;QACxB,CAAC,CAAC,CAAC;QACH,GAAG,CAAC,EAAE,CAAC,OAAO,EAAE,CAAC,GAAG,EAAE,EAAE,CACtB,GAAG,CAAC,IAAI,CAAC,6BAA6B,EAAE,EAAE,IAAI,EAAE,KAAK,EAAE,MAAM,CAAC,GAAG,CAAC,EAAE,CAAC,CACtE,CAAC;QACF,GAAG,CAAC,MAAM,CAAC,IAAI,CAAC,CAAC;QACjB,EAAE,CAAC,IAAI,CAAC,IAAI,CAAC,MAAM,EAAE,GAAG,EAAE;YACxB,GAAG,CAAC,KAAK,EAAE,CAAC;YACZ,OAAO,CAAC,IAAI,CAAC,CAAC;QAChB,CAAC,CAAC,CAAC;IACL,CAAC;IAED;;;;;OAKG;IACK,KAAK,CAAC,YAAY,CAAI,EAAU,EAAE,IAAsB,EAAE,IAAY;QAC5E,IAAI,CAAC;YACH,OAAO,MAAM,IAAI,EAAE,CAAC;QACtB,CAAC;QAAC,OAAO,GAAG,EAAE,CAAC;YACb,GAAG,CAAC,IAAI,CAAC,eAAe,IAAI,uCAAuC,EAAE;gBACnE,OAAO,EAAE,EAAE;gBACX,KAAK,EAAG,GAAa,CAAC,OAAO;aAC9B,CAAC,CAAC;YACH,IAAI,CAAC;gBACH,OAAO,MAAM,IAAI,EAAE,CAAC;YACtB,CAAC;YAAC,OAAO,IAAI,EAAE,CAAC;gBACd,MAAM,IAAI,KAAK,CAAC,mBAAmB,IAAI,YAAa,IAAc,CAAC,OAAO,EAAE,CAAC,CAAC;YAChF,CAAC;QACH,CAAC;IACH,CAAC;IAED,2EAA2E;IACnE,KAAK,CAAC,YAAY,CAAC,EAAQ,EAAE,SAAS,GAAG,KAAK;QACpD,MAAM,QAAQ,GAAG,IAAI,CAAC,GAAG,EAAE,GAAG,SAAS,CAAC;QACxC,IAAI,OAAgB,CAAC;QACrB,OAAO,IAAI,CAAC,GAAG,EAAE,GAAG,QAAQ,EAAE,CAAC;YAC7B,IAAI,EAAE,CAAC,IAAI,CAAC,QAAQ,KAAK,IAAI,EAAE,CAAC;gBAC9B,MAAM,IAAI,KAAK,CAAC,4BAA4B,EAAE,CAAC,IAAI,CAAC,QAAQ,4BAA4B,CAAC,CAAC;YAC5F,CAAC;YACD,IAAI,CAAC;gBACH,MAAM,EAAE,MAAM,EAAE,QAAQ,EAAE,GAAG,MAAM,cAAc,CAAC,EAAE,CAAC,QAAQ,EAAE,gBAAgB,EAAE,IAAI,CAAC,CAAC;gBACvF,MAAM,IAAI,GAAG,MAAM,SAAS,CAAC,MAAM,CAAC,MAAM,EAAE,QAAQ,EAAE,IAAI,CAAC,CAAC;gBAC5D,IAAI,CAAC,KAAK,EAAE,CAAC;gBACb,OAAO;YACT,CAAC;YAAC,OAAO,GAAG,EAAE,CAAC;gBACb,OAAO,GAAG,GAAG,CAAC;gBACd,MAAM,KAAK,CAAC,GAAG,CAAC,CAAC;YACnB,CAAC;QACH,CAAC;QACD,MAAM,IAAI,KAAK,CAAC,qCAAqC,MAAM,CAAE,OAAiB,EAAE,OAAO,IAAI,OAAO,CAAC,EAAE,CAAC,CAAC;IACzG,CAAC;IAED;;mDAE+C;IACvC,KAAK,CAAC,kBAAkB,CAC9B,EAAU,EACV,QAAgB,EAChB,OAAe,EACf,OAAe;QAEf,MAAM,YAAY,GAAG,KAAK,IAAmB,EAAE;YAC7C,MAAM,EAAE,GAAG,MAAM,IAAI,CAAC,QAAQ,CAAC,QAAQ,CAAC,CAAC;YACzC,IAAI,CAAC;gBACH,MAAM,IAAI,KAAK,CAAC,EAAE,CAAC,OAAO,CAAC,CAAC,IAAI,CAAC,qBAAqB,CAAC,OAAO,EAAE,OAAO,CAAC,CAAC,CAAC;gBAC1E,OAAO,EAAE,CAAC;YACZ,CAAC;YAAC,OAAO,GAAG,EAAE,CAAC;gBACb,MAAM,WAAW,CAAC,EAAE,CAAC,IAAI,CAAC,CAAC;gBAC3B,MAAM,GAAG,CAAC;YACZ,CAAC;QACH,CAAC,CAAC;QACF,MAAM,EAAE,GAAG,MAAM,IAAI,CAAC,YAAY,CAAC,EAAE,EAAE,YAAY,EAAE,eAAe,CAAC,CAAC;QAEtE,IAAI,CAAC,GAAG,CAAC,GAAG,CAAC,EAAE,EAAE,EAAE,CAAC,CAAC;QACrB,IAAI,CAAC;YACH,MAAM,IAAI,CAAC,YAAY,CAAC,EAAE,CAAC,CAAC;QAC9B,CAAC;QAAC,OAAO,GAAG,EAAE,CAAC;YACb,IAAI,CAAC,GAAG,CAAC,MAAM,CAAC,EAAE,CAAC,CAAC;YACpB,MAAM,WAAW,CAAC,EAAE,CAAC,IAAI,CAAC,CAAC;YAC3B,MAAM,GAAG,CAAC;QACZ,CAAC;QACD,6EAA6E;QAC7E,6EAA6E;QAC7E,kDAAkD;QAClD,KAAK,MAAM,CAAC,IAAI,CAAC,OAAO,EAAE,OAAO,CAAC;YAAE,OAAO,CAAC,CAAC,CAAC,CAAC;IACjD,CAAC;IAED,+EAA+E;IAC/E,WAAW,CAAC,EAAU;QACpB,OAAO,IAAI,CAAC,GAAG,CAAC,GAAG,CAAC,EAAE,CAAC,CAAC;IAC1B,CAAC;IAED;;;;;;;OAOG;IACH,KAAK,CAAC,QAAQ,CAAC,EAAU;QACvB,MAAM,EAAE,GAAG,IAAI,CAAC,GAAG,CAAC,GAAG,CAAC,EAAE,CAAC,CAAC;QAC5B,IAAI,CAAC,EAAE;YAAE,MAAM,IAAI,KAAK,CAAC,wBAAwB,EAAE,iBAAiB,CAAC,CAAC;QACtE,MAAM,IAAI,CAAC,IAAI,CAAC,EAAE,EAAE,MAAM,EAAE,EAAE,EAAE,GAAG,EAAE,GAAE,CAAC,CAAC,CAAC,KAAK,CAAC,GAAG,EAAE,GAAE,CAAC,CAAC,CAAC;QAC1D,MAAM,GAAG,GAAG,IAAI,KAAK,CAAC,EAAE,CAAC,OAAO,CAAC,CAAC;QAClC,MAAM,GAAG,CAAC,IAAI,CAAC,WAAW,CAAC,CAAC;QAC5B,MAAM,GAAG,CAAC,IAAI,CACZ,uBAAuB,CAAC,IAAI,CAAC,EAAE,CAAC,QAAQ,EAAE,kBAAkB,CAAC,EAAE,IAAI,CAAC,EAAE,CAAC,QAAQ,EAAE,cAAc,CAAC,CAAC,CAClG,CAAC;QACF,IAAI,CAAC,GAAG,CAAC,MAAM,CAAC,EAAE,CAAC,CAAC;QACpB,MAAM,WAAW,CAAC,EAAE,CAAC,IAAI,CAAC,CAAC,CAAC,gCAAgC;QAC5D,KAAK,MAAM,CAAC,IAAI,CAAC,EAAE,CAAC,OAAO,EAAE,EAAE,CAAC,QAAQ,CAAC;YAAE,OAAO,CAAC,CAAC,CAAC,CAAC;IACxD,CAAC;IAED,KAAK,CAAC,IAAI,CAAC,EAAU;QACnB,MAAM,EAAE,GAAG,IAAI,CAAC,GAAG,CAAC,GAAG,CAAC,EAAE,CAAC,CAAC;QAC5B,IAAI,CAAC,EAAE;YAAE,OAAO;QAChB,sEAAsE;QACtE,MAAM,IAAI,CAAC,IAAI,CAAC,EAAE,EAAE,MAAM,EAAE,EAAE,EAAE,GAAG,EAAE,GAAE,CAAC,CAAC,CAAC,KAAK,CAAC,GAAG,EAAE,GAAE,CAAC,CAAC,CAAC;QAC1D,IAAI,CAAC,GAAG,CAAC,MAAM,CAAC,EAAE,CAAC,CAAC;QACpB,MAAM,WAAW,CAAC,EAAE,CAAC,IAAI,CAAC,CAAC,CAAC,iDAAiD;QAC7E,KAAK,MAAM,CAAC,IAAI,CAAC,EAAE,CAAC,OAAO,EAAE,EAAE,CAAC,QAAQ,CAAC;YAAE,OAAO,CAAC,CAAC,CAAC,CAAC;IACxD,CAAC;IAED,KAAK,CAAC,OAAO,CAAC,EAAU;QACtB,MAAM,IAAI,CAAC,IAAI,CAAC,EAAE,CAAC,CAAC;QACpB,MAAM,SAAS,GAAG,IAAI,CAAC,IAAI,CAAC,GAAG,CAAC,QAAQ,EAAE,EAAE,CAAC,CAAC;QAC9C,IAAI,CAAC;YACH,yEAAyE;YACzE,wDAAwD;YACxD,IAAI,SAAS,CAAC,SAAS,CAAC,CAAC,cAAc,EAAE,EAAE,CAAC;gBAC1C,MAAM,CAAC,YAAY,CAAC,SAAS,CAAC,EAAE,EAAE,SAAS,EAAE,IAAI,EAAE,KAAK,EAAE,IAAI,EAAE,CAAC,CAAC;gBAClE,UAAU,CAAC,SAAS,CAAC,CAAC;YACxB,CAAC;iBAAM,CAAC;gBACN,MAAM,CAAC,SAAS,EAAE,EAAE,SAAS,EAAE,IAAI,EAAE,KAAK,EAAE,IAAI,EAAE,CAAC,CAAC;YACtD,CAAC;QACH,CAAC;QAAC,MAAM,CAAC;YACP,YAAY;QACd,CAAC;IACH,CAAC;IAED,6EAA6E;IAE7E;wEACoE;IAC1D,KAAK,CAAC,QAAQ,CAAC,EAAU;QACjC,MAAM,EAAE,GAAG,IAAI,CAAC,GAAG,CAAC,GAAG,CAAC,EAAE,CAAC,CAAC;QAC5B,IAAI,CAAC,EAAE;YAAE,MAAM,IAAI,KAAK,CAAC,wBAAwB,EAAE,iBAAiB,CAAC,CAAC;QACtE,MAAM,EAAE,MAAM,EAAE,QAAQ,EAAE,GAAG,MAAM,cAAc,CAAC,EAAE,CAAC,QAAQ,EAAE,gBAAgB,EAAE,KAAK,CAAC,CAAC;QACxF,OAAO,SAAS,CAAC,MAAM,CAAC,MAAM,EAAE,QAAQ,EAAE,KAAK,CAAC,CAAC;IACnD,CAAC;IAED,6EAA6E;IAE7E,KAAK,CAAC,IAAI;QACR,IAAI,CAAC,UAAU,CAAC,UAAU,CAAC,EAAE,CAAC;YAC5B,MAAM,IAAI,KAAK,CACb,8EAA8E;gBAC5E,qFAAqF,CACxF,CAAC;QACJ,CAAC;QACD,IAAI,CAAC;YACH,YAAY,CAAC,IAAI,CAAC,GAAG,CAAC,KAAK,EAAE,CAAC,WAAW,CAAC,EAAE,EAAE,KAAK,EAAE,QAAQ,EAAE,CAAC,CAAC;QACnE,CAAC;QAAC,OAAO,GAAG,EAAE,CAAC;YACb,MAAM,IAAI,KAAK,CACb,4BAA4B,IAAI,CAAC,GAAG,CAAC,KAAK,MAAO,GAAa,CAAC,OAAO,KAAK;gBACzE,wCAAwC,CAC3C,CAAC;QACJ,CAAC;IACH,CAAC;IAED,KAAK,CAAC,QAAQ;QACZ,6EAA6E;QAC7E,4EAA4E;QAC5E,IAAI,QAAQ,GAAG,IAAI,CAAC,KAAK,CAAC,QAAQ,EAAE,GAAG,CAAC,IAAI,GAAG,IAAI,CAAC,CAAC,CAAC;QACtD,IAAI,CAAC;YACH,MAAM,OAAO,GAAG,YAAY,CAAC,eAAe,EAAE,MAAM,CAAC,CAAC;YACtD,MAAM,CAAC,GAAG,wBAAwB,CAAC,IAAI,CAAC,OAAO,CAAC,CAAC;YACjD,IAAI,CAAC;gBAAE,QAAQ,GAAG,IAAI,CAAC,KAAK,CAAC,MAAM,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,GAAG,IAAI,CAAC,CAAC;QACpD,CAAC;QAAC,MAAM,CAAC;YACP,+BAA+B;QACjC,CAAC;QACD,OAAO,EAAE,QAAQ,EAAE,IAAI,EAAE,MAAM,EAAE,CAAC,MAAM,EAAE,CAAC;IAC7C,CAAC;CACF;AAED,6CAA6C;AAC7C,SAAS,OAAO,CAAC,IAAY;IAC3B,IAAI,CAAC;QACH,UAAU,CAAC,IAAI,CAAC,CAAC;IACnB,CAAC;IAAC,MAAM,CAAC;QACP,eAAe;IACjB,CAAC;AACH,CAAC;AAED;mEACmE;AACnE,SAAS,WAAW,CAAC,IAAkB,EAAE,SAAS,GAAG,IAAI;IACvD,OAAO,IAAI,OAAO,CAAC,CAAC,OAAO,EAAE,EAAE;QAC7B,IAAI,IAAI,CAAC,QAAQ,KAAK,IAAI,IAAI,IAAI,CAAC,UAAU,KAAK,IAAI;YAAE,OAAO,OAAO,EAAE,CAAC;QACzE,MAAM,KAAK,GAAG,UAAU,CAAC,OAAO,EAAE,SAAS,CAAC,CAAC;QAC7C,IAAI,CAAC,IAAI,CAAC,MAAM,EAAE,GAAG,EAAE;YACrB,YAAY,CAAC,KAAK,CAAC,CAAC;YACpB,OAAO,EAAE,CAAC;QACZ,CAAC,CAAC,CAAC;QACH,IAAI,CAAC,IAAI,CAAC,SAAS,CAAC,CAAC;IACvB,CAAC,CAAC,CAAC;AACL,CAAC;AAED;kFACkF;AAClF,SAAS,SAAS,CAAC,GAAW,EAAE,GAAW;IACzC,IAAI,CAAC;QACH,YAAY,CAAC,IAAI,EAAE,CAAC,gBAAgB,EAAE,GAAG,EAAE,GAAG,CAAC,CAAC,CAAC;IACnD,CAAC;IAAC,MAAM,CAAC;QACP,YAAY,CAAC,IAAI,EAAE,CAAC,GAAG,EAAE,GAAG,CAAC,CAAC,CAAC;IACjC,CAAC;AACH,CAAC;AAED,gFAAgF;AAChF,SAAS,gBAAgB,CAAC,IAAY,EAAE,SAAiB;IACvD,IAAI,UAAU,CAAC,IAAI,CAAC;QAAE,OAAO;IAC7B,MAAM,EAAE,GAAG,QAAQ,CAAC,IAAI,EAAE,GAAG,CAAC,CAAC;IAC/B,IAAI,CAAC;QACH,aAAa,CAAC,EAAE,EAAE,SAAS,CAAC,CAAC;IAC/B,CAAC;YAAS,CAAC;QACT,SAAS,CAAC,EAAE,CAAC,CAAC;IAChB,CAAC;AACH,CAAC;AAED,wEAAwE;AACxE,KAAK,UAAU,WAAW,CAAC,IAAY,EAAE,SAAiB;IACxD,MAAM,QAAQ,GAAG,IAAI,CAAC,GAAG,EAAE,GAAG,SAAS,CAAC;IACxC,OAAO,IAAI,CAAC,GAAG,EAAE,GAAG,QAAQ,EAAE,CAAC;QAC7B,IAAI,UAAU,CAAC,IAAI,CAAC;YAAE,OAAO;QAC7B,MAAM,KAAK,CAAC,EAAE,CAAC,CAAC;IAClB,CAAC;IACD,MAAM,IAAI,KAAK,CAAC,yBAAyB,IAAI,EAAE,CAAC,CAAC;AACnD,CAAC"}
@@ -0,0 +1,17 @@
1
+ import type { Config } from "../config.js";
2
+ import type { Driver } from "./types.js";
3
+ /** Known driver names, in preference/isolation order. */
4
+ export declare const DRIVER_NAMES: readonly ["container", "firecracker", "applevz"];
5
+ /**
6
+ * Construct the runtime driver named by `config.driver` (`SBX_DRIVER`) — the
7
+ * daemon's default. The `DriverRouter` calls `createNamedDriver` to build other
8
+ * drivers on demand for per-sandbox isolation selection.
9
+ */
10
+ export declare function createDriver(config: Config): Driver;
11
+ /**
12
+ * Construct a specific runtime driver by name. The container driver is fully
13
+ * built; the microVM drivers compile and report a clear "needs <host>" error
14
+ * from `ping()` so a bad selection fails with guidance. Adding a real driver is
15
+ * a one-line change here.
16
+ */
17
+ export declare function createNamedDriver(name: string, config: Config): Driver;
@@ -0,0 +1,61 @@
1
+ import { AppleVzDriver } from "./applevz.js";
2
+ import { ContainerDriver } from "./container.js";
3
+ import { FirecrackerDriver } from "./firecracker.js";
4
+ /** Known driver names, in preference/isolation order. */
5
+ export const DRIVER_NAMES = ["container", "firecracker", "applevz"];
6
+ /**
7
+ * Construct the runtime driver named by `config.driver` (`SBX_DRIVER`) — the
8
+ * daemon's default. The `DriverRouter` calls `createNamedDriver` to build other
9
+ * drivers on demand for per-sandbox isolation selection.
10
+ */
11
+ export function createDriver(config) {
12
+ return createNamedDriver(config.driver, config);
13
+ }
14
+ /**
15
+ * Construct a specific runtime driver by name. The container driver is fully
16
+ * built; the microVM drivers compile and report a clear "needs <host>" error
17
+ * from `ping()` so a bad selection fails with guidance. Adding a real driver is
18
+ * a one-line change here.
19
+ */
20
+ export function createNamedDriver(name, config) {
21
+ switch (name) {
22
+ case "container":
23
+ return new ContainerDriver(undefined, {
24
+ enforce: config.egressEnforce,
25
+ network: config.egressNetwork,
26
+ subnet: config.egressSubnet,
27
+ dns: config.egressDnsResolver,
28
+ });
29
+ case "firecracker":
30
+ return new FirecrackerDriver({
31
+ fcBin: config.fcBin,
32
+ kernel: config.fcKernel,
33
+ rootfs: config.fcRootfs,
34
+ stateDir: config.fcStateDir,
35
+ diskGb: config.fcDiskGb,
36
+ imageCacheDir: config.fcImageCacheDir,
37
+ warmPool: config.fcWarmPool,
38
+ // A plain create of the daemon's default image adopts a spare.
39
+ poolImage: config.defaultImage,
40
+ // Guest egress relay target: the gateway on this host.
41
+ egressPort: config.egressPort,
42
+ egressHost: config.host,
43
+ });
44
+ case "applevz":
45
+ return new AppleVzDriver({
46
+ helperPath: config.vzHelperPath,
47
+ kernel: config.vzKernel,
48
+ rootfs: config.vzRootfs,
49
+ stateDir: config.vzStateDir,
50
+ diskGb: config.vzDiskGb,
51
+ imageCacheDir: config.vzImageCacheDir,
52
+ warmPool: config.vzWarmPool,
53
+ // Guest egress relay target: the gateway on this host.
54
+ egressPort: config.egressPort,
55
+ egressHost: config.host,
56
+ });
57
+ default:
58
+ throw new Error(`unknown driver "${name}" (expected: ${DRIVER_NAMES.join(" | ")})`);
59
+ }
60
+ }
61
+ //# sourceMappingURL=index.js.map