@supermachine/core 0.4.25

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/index.d.ts ADDED
@@ -0,0 +1,532 @@
1
+ /* tslint:disable */
2
+ /* eslint-disable */
3
+
4
+ /* auto-generated by scripts/gen-dts.js from napi-derive's TYPE_DEF_TMP_PATH output */
5
+ /* DO NOT EDIT — regenerate via `npm run build`. */
6
+
7
+ /**
8
+ * VM-shaped handle passed to a `warmup` callback. Only valid
9
+ * during the callback's lifetime — `exec` errors after return.
10
+ */
11
+ export interface WarmupVm {
12
+ exec(options: ExecOptions): Promise<ExecOutput>
13
+ }
14
+
15
+ /**
16
+ * One staged host file → guest path mapping for `extraFiles`. See
17
+ * [`BuildOptions::extra_files`].
18
+ */
19
+ export interface ExtraFileSpec {
20
+ /**
21
+ * Host filesystem path. File contents are read at bake time
22
+ * and folded into the snapshot's input-hash, so changes
23
+ * re-bake.
24
+ */
25
+ hostPath: string
26
+ /** Where the file appears inside the guest's root filesystem. */
27
+ guestPath: string
28
+ }
29
+
30
+ /**
31
+ * Options for [`Image.build`]. Mirrors `OciImageBuilder` in the
32
+ * Rust crate. All fields optional except `ref` (the OCI image
33
+ * reference).
34
+ */
35
+ export interface BuildOptions {
36
+ /**
37
+ * OCI image reference, e.g. `"rust:1-slim"`,
38
+ * `"ghcr.io/owner/image@sha256:..."`.
39
+ */
40
+ ref: string
41
+ /**
42
+ * Stable snapshot name. Defaults to a sha-derived name based
43
+ * on the image reference.
44
+ */
45
+ name?: string
46
+ /**
47
+ * Guest memory in MiB. Default 256. Note: allocation is lazy
48
+ * (CoW page-fault); this is the guest-visible ceiling, not
49
+ * host commit.
50
+ */
51
+ memoryMib?: number
52
+ /** vCPUs per VM. Default 1. */
53
+ vcpus?: number
54
+ /** `"always"` | `"missing"` | `"never"`. Default `"missing"`. */
55
+ pullPolicy?: string
56
+ /**
57
+ * Workload listener port. Default 80. Used by service-image
58
+ * bakes (see `listenerRequired`).
59
+ */
60
+ guestPort?: number
61
+ /** Override the image's CMD/ENTRYPOINT. */
62
+ cmd?: Array<string>
63
+ /** Extra environment variables for the workload. */
64
+ env?: Record<string, string>
65
+ /**
66
+ * When `true`, wait for the workload's listener to bind before
67
+ * capturing the snapshot — v0.4.22 behavior. Default `false`
68
+ * uses the pre-exec trigger (v0.4.23+): fast bake, workload
69
+ * starts fresh on each restore. Set `true` for service-image
70
+ * bakes (nginx, redis) where you want the listener pre-bound.
71
+ */
72
+ listenerRequired?: boolean
73
+ /**
74
+ * Directory for the snapshot artifact. Default
75
+ * `~/.local/supermachine-snapshots`.
76
+ */
77
+ snapshotsDir?: string
78
+ /**
79
+ * Files to bake into the delta layer at fixed guest paths.
80
+ * Bytes read from `hostPath` at bake time; the host file's
81
+ * contents are folded into the snapshot's input-hash so any
82
+ * change re-bakes. Common pattern: ship per-snapshot
83
+ * kernel modules, certs, configuration files. Maps to
84
+ * `OciImageBuilder::with_extra_file`.
85
+ */
86
+ extraFiles?: Array<ExtraFileSpec>
87
+ /**
88
+ * Stable tag for the warmup callback (see the `warmup`
89
+ * parameter on [`Image.build`]). Folded into the snapshot's
90
+ * cached fingerprint so changing the warmup body invalidates
91
+ * the previous warm snapshot. Default `"default"` — set a
92
+ * versioned tag (`"v1"`, `"v2"`) when you mutate the warmup.
93
+ * Ignored when no warmup function is provided.
94
+ */
95
+ warmupTag?: string
96
+ /**
97
+ * Post-bake warmup callback. Receives a [`WarmupVm`] bound to a
98
+ * freshly-booted guest; run `vm.exec()` calls to populate state,
99
+ * then return. The bake captures the post-warmup snapshot.
100
+ *
101
+ * The Vm is invalidated after the callback returns.
102
+ */
103
+ warmup?: (vm: WarmupVm) => Promise<void>
104
+ }
105
+
106
+ export interface PoolOptions {
107
+ /**
108
+ * Minimum idle VMs to keep warm. Spawned eagerly at pool
109
+ * build time. Default 1.
110
+ */
111
+ min?: number
112
+ /**
113
+ * Maximum total VMs (active + idle). Pool grows up to this
114
+ * under load. Default 1.
115
+ */
116
+ max?: number
117
+ /**
118
+ * Max wait for `acquire()` when the pool is saturated.
119
+ * Default 60_000 (60 s).
120
+ *
121
+ * Special value: pass `0` for "no timeout — block forever".
122
+ * Useful for batch workloads that prefer waiting over
123
+ * failing. Mirrors `PoolBuilder::no_acquire_timeout()` on the
124
+ * Rust side.
125
+ */
126
+ acquireTimeoutMs?: number
127
+ /**
128
+ * Idle VM lifetime before janitor evicts above `min`. Defaults
129
+ * to no eviction.
130
+ */
131
+ idleTimeoutMs?: number
132
+ /** If `true` (default), cycle-restore the VM on release. */
133
+ restoreOnRelease?: boolean
134
+ /**
135
+ * Runtime memory ceiling override for this pool's workers
136
+ * (in MiB). Defaults to the value baked into the snapshot.
137
+ * Pure runtime — doesn't re-bake. Pages are lazy-committed,
138
+ * so raising the ceiling above the baked value doesn't
139
+ * increase host commit unless the guest actually writes to
140
+ * the new pages.
141
+ */
142
+ memoryMib?: number
143
+ /**
144
+ * Runtime vCPU count override for this pool's workers.
145
+ * Defaults to the value baked into the snapshot.
146
+ */
147
+ vcpus?: number
148
+ /**
149
+ * Per-worker snapshot-restore timeout (ms). Default 30_000.
150
+ * Bump for slow disks or large RAM snapshots — restore time
151
+ * scales roughly linearly with snapshot size. Forwards to
152
+ * `VmConfig::with_restore_timeout` via PoolBuilder.
153
+ */
154
+ restoreTimeoutMs?: number
155
+ }
156
+
157
+ /**
158
+ * Returned by [`Pool.stats`]. Pool observability for monitoring,
159
+ * autoscaling decisions, and capacity tuning.
160
+ */
161
+ export interface PoolStats {
162
+ /** Total workers the pool has spawned (idle + checked-out). */
163
+ alive: number
164
+ /** Workers currently checked out via `acquire()`. */
165
+ inUse: number
166
+ /** Workers sitting in the idle queue. */
167
+ idle: number
168
+ /**
169
+ * Number of callers currently blocked in `acquire()` waiting
170
+ * for an idle worker to free up.
171
+ */
172
+ waiting: number
173
+ /** Configured `min` from PoolOptions. */
174
+ min: number
175
+ /** Configured `max` from PoolOptions. */
176
+ max: number
177
+ }
178
+
179
+ /**
180
+ * One file → bytes mapping for `stageFilesMode` (variant of
181
+ * `stageFiles` that also lets you set the guest-side file mode,
182
+ * e.g. 0o755 for shipping executable scripts inline with an exec).
183
+ */
184
+ export interface StagedFileMode {
185
+ guestPath: string
186
+ bytes: Buffer
187
+ /**
188
+ * Unix file mode (e.g. `0o755`, written as `493` if you can't
189
+ * use octal literals in your JS engine). When `null`, the
190
+ * agent uses 0o644 (same as the plain `stageFiles` entry).
191
+ */
192
+ mode?: number
193
+ }
194
+
195
+ export interface ExecOptions {
196
+ argv: Array<string>
197
+ /**
198
+ * Files to stage at fixed paths inside the guest before the
199
+ * command runs. Mode defaults to 0o644. Use `stageFilesMode`
200
+ * instead when you need to set the executable bit (or any
201
+ * other mode).
202
+ */
203
+ stageFiles?: Record<string, Buffer>
204
+ /**
205
+ * Like `stageFiles` but with explicit per-file Unix modes.
206
+ * Useful for shipping executable scripts (`0o755`) or
207
+ * read-only secrets (`0o400`). Entries here are unioned with
208
+ * `stageFiles` — same `guestPath` in both is undefined order;
209
+ * pick one.
210
+ */
211
+ stageFilesMode?: Array<StagedFileMode>
212
+ timeoutMs?: number
213
+ env?: Record<string, string>
214
+ cwd?: string
215
+ chain?: Array<string>
216
+ /**
217
+ * Allocate a pseudo-terminal for the guest process. With
218
+ * `tty: true`, stdout/stdin pass through the pty master and
219
+ * stderr is empty (the pty merges fd 1 + fd 2). Use this for
220
+ * interactive REPLs, shells, or any process that expects a
221
+ * real terminal (e.g. progress bars that detect isatty).
222
+ */
223
+ tty?: boolean
224
+ /**
225
+ * Initial window size for tty mode. Ignored when `tty` is
226
+ * false. Call `ExecChild.resize(cols, rows)` to change it
227
+ * later from the streaming `spawn()` path.
228
+ */
229
+ winsize?: Winsize
230
+ }
231
+
232
+ /**
233
+ * Terminal window size for `ExecOptions.winsize`. Both fields are
234
+ * in character cells (not pixels). Use 0/0 to let the agent pick
235
+ * a default (80x24 in practice).
236
+ */
237
+ export interface Winsize {
238
+ cols: number
239
+ rows: number
240
+ }
241
+
242
+ export interface ExecOutput {
243
+ stdout: Buffer
244
+ stderr: Buffer
245
+ exitCode: number
246
+ }
247
+
248
+ /**
249
+ * Result of [`ExecChild.wait`]. Mirrors `ExecOutcome` minus the
250
+ * stdout/stderr buffers (those were already streamed via
251
+ * `readStdout`/`readStderr`).
252
+ */
253
+ export interface ExecWaitResult {
254
+ /** `-1` if killed by signal / timeout / agent disconnect. */
255
+ exitCode: number
256
+ /**
257
+ * `true` if the process exited because the spawn-time
258
+ * `timeoutMs` watchdog killed it.
259
+ */
260
+ timedOut: boolean
261
+ /**
262
+ * Peak resident-set size in KiB during the process's life,
263
+ * as reported by the in-guest agent's wait4(rusage). `null`
264
+ * when not reported.
265
+ */
266
+ peakRssKib?: number
267
+ }
268
+
269
+ /**
270
+ * A baked OCI image. Returned by [`Image.build`] (bakes or
271
+ * cache-hits) and by [`Image.fromSnapshot`].
272
+ */
273
+ export declare class Image {
274
+ /**
275
+ * Build an image from an OCI reference, or return the cached
276
+ * snapshot if one already exists. Async: runs the bake
277
+ * pipeline on a libuv worker thread.
278
+ *
279
+ * **Cold first-time bake of `alpine:latest` on Apple Silicon
280
+ * takes ~400 ms**. Cache-hit is ~15 ms.
281
+ *
282
+ * `warmup` is an optional async callback that receives a [`Vm`]
283
+ * after the guest is booted. Use it to pre-populate guest
284
+ * state (compile a seed program, warm a page cache) — the
285
+ * bake captures the post-warmup snapshot, so restores land in
286
+ * the warm state. Pair with `warmupTag` in `options` to
287
+ * version-tag the warmup for cache invalidation.
288
+ *
289
+ * The Vm passed to the warmup is invalidated after the
290
+ * callback returns; holding a reference past return is safe
291
+ * (won't crash) but `vm.exec()` will error.
292
+ *
293
+ * We take `warmup` as a separate positional argument rather
294
+ * than as a field on `options` because napi-rs's async-fn
295
+ * support requires all parameters to be `Send`. Plain
296
+ * `JsFunction` isn't `Send`; here we use `AsyncTask` (which
297
+ * splits sync-setup from sync-compute) to keep the JsFunction
298
+ * → TSFn conversion on the JS thread while the bake runs on
299
+ * a worker. The JS shim in index.js wraps this back into a
300
+ * natural `Image.build({...})` API.
301
+ */
302
+ static build(options: BuildOptions): Promise<Image>
303
+ /**
304
+ * Load an image from a previously-baked snapshot directory or
305
+ * `restore.snap` file path. No bake — just reads metadata.json
306
+ * and validates the snapshot file exists.
307
+ */
308
+ static fromSnapshot(path: string): Promise<Image>
309
+ /**
310
+ * Create a VM pool for this image. `min`/`max` are the most
311
+ * important — `min=max=N` pre-spawns N VMs eagerly and caps
312
+ * total at N.
313
+ *
314
+ * Memory: each idle VM costs ~3 MiB host phys_footprint
315
+ * (measured). The `memoryMib` build option is a guest-visible
316
+ * ceiling, not host commit.
317
+ */
318
+ pool(options?: PoolOptions | undefined | null): Promise<Pool>
319
+ /**
320
+ * On-disk snapshot directory backing this Image. Same as
321
+ * `supermachine::Image::snapshot_path` in Rust. Useful for
322
+ * diagnostics, log lines, or chaining a second image off the
323
+ * same snapshot via `Image.fromSnapshot`.
324
+ */
325
+ get snapshotPath(): string
326
+ /** Guest memory (MiB) as baked into the snapshot's metadata. */
327
+ get memoryMib(): number
328
+ /** vCPU count as baked into the snapshot's metadata. */
329
+ get vcpus(): number
330
+ }
331
+
332
+ export declare class Pool {
333
+ /**
334
+ * Acquire a VM from the pool. Blocks (async) up to
335
+ * `acquireTimeoutMs`. ~0 ms warm-handoff / ~5 ms cycle-restore
336
+ * / ~22 ms spawn-from-disk.
337
+ */
338
+ acquire(): Promise<Vm>
339
+ /** Best-effort pool shutdown. Pool also shuts down on GC. */
340
+ shutdown(): Promise<void>
341
+ /**
342
+ * Snapshot of the pool's current state. Cheap (~1 µs, just a
343
+ * mutex lock) — safe to poll frequently for monitoring /
344
+ * autoscaling decisions.
345
+ */
346
+ stats(): PoolStats
347
+ }
348
+
349
+ /**
350
+ * Streaming exec handle returned by [`Vm.spawn`]. Pull-style API:
351
+ * caller polls `readStdout()` / `readStderr()` for chunks, writes
352
+ * to stdin via `writeStdin()`, sends signals via `signal()`, and
353
+ * awaits exit via `wait()`. Mirrors the Rust `ExecChild`.
354
+ *
355
+ * Pull-style was chosen over Node `ReadableStream`/`WritableStream`
356
+ * for two reasons: (1) the underlying Rust types are sync
357
+ * `Read`/`Write`, so wrapping in stream adapters would require
358
+ * per-chunk napi roundtrips anyway, and (2) pull-style is the
359
+ * minimum-surface-area API that covers all use cases (LLM-style
360
+ * streaming output, interactive REPLs, anything you can build
361
+ * with `for await (const chunk of pull()) ...`).
362
+ */
363
+ export declare class ExecChild {
364
+ /**
365
+ * Write a chunk to the process's stdin. Returns when the
366
+ * bytes have been queued on the host-side socket; the guest
367
+ * agent forwards them to the process asynchronously. Multiple
368
+ * calls append.
369
+ */
370
+ writeStdin(bytes: Buffer): Promise<void>
371
+ /** Close stdin (send EOF to the process). Idempotent. */
372
+ closeStdin(): Promise<void>
373
+ /**
374
+ * Read up to `maxBytes` (default 64 KiB) from stdout. Returns
375
+ * an empty Buffer when stdout has closed (process exited and
376
+ * drained); the caller's `for await` loop should terminate on
377
+ * `buf.length === 0`.
378
+ *
379
+ * Blocks the libuv worker thread; the JS event loop stays
380
+ * free for other work.
381
+ */
382
+ readStdout(maxBytes?: number | undefined | null): Promise<Buffer>
383
+ /** Same as [`readStdout`] for stderr. */
384
+ readStderr(maxBytes?: number | undefined | null): Promise<Buffer>
385
+ /**
386
+ * Resize the pty (tty mode only). No-op when the process was
387
+ * spawned without `tty: true` — the guest agent ignores RESIZE
388
+ * frames if no pty is attached. Use this from the JS side to
389
+ * react to host terminal resize events (e.g. SIGWINCH on
390
+ * process.stdout).
391
+ */
392
+ resize(cols: number, rows: number): Promise<void>
393
+ /**
394
+ * Send a signal to the guest-side process. Common values:
395
+ * 1=SIGHUP, 2=SIGINT, 9=SIGKILL, 15=SIGTERM.
396
+ */
397
+ signal(signum: number): Promise<void>
398
+ /**
399
+ * Wait for the guest-side process to exit and return its
400
+ * status. Consumes the underlying ExecChild — subsequent
401
+ * calls error with "already waited". Drains any unread
402
+ * stdout/stderr (caller should pull them out FIRST if they
403
+ * care about full output).
404
+ */
405
+ wait(): Promise<ExecWaitResult>
406
+ }
407
+
408
+ /**
409
+ * VM handle. Drop or `release()` to return to the pool. With Node
410
+ * 20+, use the `using` keyword + `Symbol.asyncDispose`.
411
+ */
412
+ export declare class Vm {
413
+ /** Run a process inside the guest via the in-guest exec agent. */
414
+ exec(options: ExecOptions): Promise<ExecOutput>
415
+ /** Return the VM to the pool. Idempotent. */
416
+ release(): Promise<void>
417
+ /**
418
+ * Alias for `release()`. Wired up to `Symbol.asyncDispose` in
419
+ * the JS shim for the TC39 explicit-resource-management
420
+ * `using` keyword (Node 20+).
421
+ */
422
+ dispose(): Promise<void>
423
+ /**
424
+ * Write `bytes` to `path` inside the guest. Native vsock RPC,
425
+ * ~100 µs round-trip. Complement to `exec({stageFiles})` —
426
+ * use this when you want to drop a file without running a
427
+ * command (or between commands on the same vm).
428
+ *
429
+ * 4 MiB default cap on file size; stream larger files via
430
+ * `exec` with `stageFiles` instead.
431
+ */
432
+ writeFile(path: string, bytes: Buffer): Promise<void>
433
+ /**
434
+ * Read `path` from inside the guest, return bytes. Native
435
+ * vsock RPC, ~100 µs round-trip. 4 MiB default cap; stream
436
+ * larger files via `exec` + redirect to a host path.
437
+ */
438
+ readFile(path: string): Promise<Buffer>
439
+ /**
440
+ * Spawn a process inside the guest and return a streaming
441
+ * [`ExecChild`] handle. Unlike `exec()` which collects
442
+ * stdout/stderr into Buffers, `spawn()` lets you write to
443
+ * stdin / read from stdout/stderr incrementally — useful for
444
+ * LLM-style streaming, long-running daemons, interactive REPLs.
445
+ *
446
+ * Important: ExecOptions.timeoutMs is IGNORED in spawn mode —
447
+ * the caller controls cancellation via `child.signal(9)`. The
448
+ * timeout watchdog only applies to the collect-mode `exec()`.
449
+ */
450
+ spawn(options: ExecOptions): Promise<ExecChild>
451
+ /**
452
+ * Capture a snapshot of this VM's current state and return a
453
+ * new `Image` pointing at it. Equivalent to `Vm::snapshot` in
454
+ * the Rust crate. The guest is paused for the capture
455
+ * (typically 10s of ms; bounded by disk write time for large
456
+ * RAM). The Vm remains usable after — handy for the
457
+ * "warm up + snapshot + keep working" pattern.
458
+ *
459
+ * Returns a fresh Image; build a pool from it via `image.pool()`
460
+ * to spawn workers that restore from the captured state.
461
+ */
462
+ snapshot(destDir: string): Promise<Image>
463
+ /**
464
+ * Send `signum` to the guest's workload PID-1 (the process
465
+ * the image's CMD/ENTRYPOINT launched at boot). Mirrors
466
+ * `supermachine::Vm::workload_signal`.
467
+ *
468
+ * Distinct from `ExecChild.signal`, which targets a process
469
+ * spawned via `vm.spawn()`. Use this for graceful service
470
+ * shutdown of baked service images (e.g. SIGTERM to nginx
471
+ * before tearing down the VM).
472
+ */
473
+ workloadSignal(signum: number): Promise<void>
474
+ /**
475
+ * On-disk path of this Vm's per-acquire vsock mux socket.
476
+ * Stable for the lifetime of the Vm; goes away on `release()`.
477
+ * Use this as an escape hatch when you want to bring your own
478
+ * client (e.g. open a raw UnixStream from `node:net` and speak
479
+ * a custom protocol to a workload listening inside the guest).
480
+ *
481
+ * Throws if called on the warmup vm — the bake driver owns
482
+ * the warmup vm's sockets.
483
+ */
484
+ get vsockPath(): string
485
+ /**
486
+ * On-disk path of this Vm's per-acquire exec control socket.
487
+ * Same lifetime as `vsockPath`. Mostly an escape hatch for
488
+ * users wiring up a non-libuv RPC client; the napi binding's
489
+ * own `exec`/`spawn`/`writeFile`/`readFile` go through this
490
+ * internally.
491
+ */
492
+ get execPath(): string
493
+ /**
494
+ * Bind `127.0.0.1:hostPort` and proxy connections into the
495
+ * guest's vsock mux. Returns a [`TcpForwarder`] handle; drop
496
+ * it (or call `forwarder.stop()`) to stop accepting new
497
+ * connections. In-flight connections survive `stop()` and
498
+ * close naturally.
499
+ *
500
+ * Pass `hostPort = 0` to let the OS pick a free port; read
501
+ * the actual bound port back via `forwarder.localAddr`.
502
+ *
503
+ * Note: `guestPort` is currently advisory. The Rust crate's
504
+ * `expose_tcp` ignores it and routes all forwarded
505
+ * connections into whatever the in-guest TSI mux accepts;
506
+ * per-guest-port routing is on the roadmap. Pass the port
507
+ * you semantically want — it's plumbed through so the
508
+ * signature stays stable when the routing fix lands.
509
+ */
510
+ exposeTcp(hostPort: number, guestPort: number): Promise<TcpForwarder>
511
+ }
512
+
513
+ /**
514
+ * Active TCP→vsock forwarder. Returned by [`Vm.exposeTcp`]; owns
515
+ * the host-side TcpListener accept-loop thread. Drop it (or call
516
+ * `stop()`) to stop accepting new connections. In-flight
517
+ * connections continue independently until they close naturally.
518
+ */
519
+ export declare class TcpForwarder {
520
+ /**
521
+ * The address the forwarder is bound to, e.g. `"127.0.0.1:54321"`.
522
+ * Useful when you asked for `hostPort = 0` and want the
523
+ * OS-assigned port back.
524
+ */
525
+ get localAddr(): string
526
+ /**
527
+ * Stop accepting new connections. Idempotent. Equivalent to
528
+ * dropping the forwarder, but returns when the accept thread
529
+ * has actually exited (vs Drop, which detaches the join).
530
+ */
531
+ stop(): Promise<void>
532
+ }