@supermachine/core 0.7.5 → 0.7.11

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (3) hide show
  1. package/index.d.ts +90 -1
  2. package/index.js +25 -0
  3. package/package.json +2 -2
package/index.d.ts CHANGED
@@ -499,9 +499,60 @@ export declare class ExecChild {
499
499
  resize(cols: number, rows: number): Promise<void>
500
500
  /**
501
501
  * Send a signal to the guest-side process. Common values:
502
- * 1=SIGHUP, 2=SIGINT, 9=SIGKILL, 15=SIGTERM.
502
+ * 1=SIGHUP, 2=SIGINT, 9=SIGKILL, 15=SIGTERM. Routes through
503
+ * the cached signaler so it works even if a concurrent
504
+ * `wait()` has already consumed the child handle (the
505
+ * signaler outlives the child; calls become no-ops on the
506
+ * closed socket).
503
507
  */
504
508
  signal(signum: number): Promise<void>
509
+ /**
510
+ * Return a thread-safe [`ExecSignaler`] handle that can signal
511
+ * or abort this child from ANY caller (including a different
512
+ * async task) without holding the ExecChild itself. The handle
513
+ * can outlive the child — after exit, calls become no-ops on
514
+ * the closed socket.
515
+ *
516
+ * Use this when you want to interrupt a `wait()` from a Ctrl-C
517
+ * handler, a cancel registry, or a pool-shutdown hook. The
518
+ * returned object is the JS-side analogue of Rust's
519
+ * `ExecSignaler` — Send + Sync + Clone, one atomic refcount
520
+ * inc per clone.
521
+ *
522
+ * Idiomatic shape:
523
+ *
524
+ * ```js
525
+ * const child = await vm.spawn({ argv: ["./run.sh"] });
526
+ * const sig = child.signaler();
527
+ * process.on("SIGINT", () => sig.kill());
528
+ * const exit = await child.wait();
529
+ * ```
530
+ */
531
+ signaler(): ExecSignaler
532
+ /**
533
+ * Close the host-side socket WITHOUT waiting for a clean exit.
534
+ * The demux thread observes EOF, a concurrent `wait()` returns
535
+ * an error within milliseconds. Use this when the agent /
536
+ * worker is unresponsive — e.g. you've already decided the
537
+ * process must stop right now and don't care about reaping a
538
+ * clean exit code.
539
+ *
540
+ * Works even AFTER a concurrent `wait()` has consumed the
541
+ * child handle — routes through the cached signaler so the
542
+ * host-side shutdown still fires.
543
+ */
544
+ abort(): void
545
+ /**
546
+ * Non-consuming poll for child exit. Returns `null` if the
547
+ * child is still running, or an `ExecWaitResult` if it has
548
+ * exited. Mirrors `std::process::Child::try_wait`. Useful for
549
+ * loops that want to check status without blocking, and that
550
+ * pair with a signaler stashed in a registry.
551
+ *
552
+ * Returns null also if `wait()` has already consumed the
553
+ * child (subsequent polls don't error).
554
+ */
555
+ tryWait(): ExecWaitResult | null
505
556
  /**
506
557
  * Wait for the guest-side process to exit and return its
507
558
  * status. Consumes the underlying ExecChild — subsequent
@@ -512,6 +563,44 @@ export declare class ExecChild {
512
563
  wait(): Promise<ExecWaitResult>
513
564
  }
514
565
 
566
+ /**
567
+ * Thread-safe control handle for an [`ExecChild`]. Returned by
568
+ * [`ExecChild::signaler`]. Send a signal (SIGINT / SIGTERM /
569
+ * SIGKILL / ...) to the in-guest process from any caller — a
570
+ * cancel registry, a Ctrl-C handler, a pool-shutdown hook —
571
+ * without holding the ExecChild itself.
572
+ *
573
+ * The handle keeps the underlying socket alive via Arc refcount
574
+ * (one atomic inc per JS-side wrapper). Calls after the child
575
+ * has exited or been waited are no-ops on the closed socket;
576
+ * they don't panic or deadlock.
577
+ */
578
+ export declare class ExecSignaler {
579
+ /**
580
+ * Send a signal (numeric) to the in-guest process. Common
581
+ * values: 2 = SIGINT, 9 = SIGKILL, 15 = SIGTERM.
582
+ */
583
+ signal(signum: number): void
584
+ /**
585
+ * Shortcut for `signal(9)` — SIGKILL. Mirrors
586
+ * `child_process.ChildProcess.kill('SIGKILL')` semantics on
587
+ * the JS side.
588
+ */
589
+ kill(): void
590
+ /**
591
+ * Close the host-side socket immediately. Wakes a concurrent
592
+ * `wait()` on the corresponding ExecChild, regardless of
593
+ * whether the in-guest agent is still alive. Use this when
594
+ * the SIGNAL path won't work — e.g. you've already
595
+ * SIGKILL'd the guest agent, or the worker process is dead
596
+ * and you want the host-side `await child.wait()` to
597
+ * return now.
598
+ *
599
+ * Idempotent.
600
+ */
601
+ abort(): void
602
+ }
603
+
515
604
  /**
516
605
  * VM handle. Drop or `release()` to return to the pool. With Node
517
606
  * 20+, use the `using` keyword + `Symbol.asyncDispose`.
package/index.js CHANGED
@@ -239,6 +239,31 @@ function wrapExecChild(native) {
239
239
  async wait() {
240
240
  return native.wait();
241
241
  },
242
+ // 0.7.11 additions — cancellable-from-anywhere control surface.
243
+ // See the napi `ExecSignaler` class for the full shape.
244
+ signaler() {
245
+ return wrapExecSignaler(native.signaler());
246
+ },
247
+ async abort() {
248
+ return native.abort();
249
+ },
250
+ async tryWait() {
251
+ return native.tryWait();
252
+ },
253
+ };
254
+ }
255
+
256
+ function wrapExecSignaler(native) {
257
+ return {
258
+ async signal(signum) {
259
+ return native.signal(signum);
260
+ },
261
+ async kill() {
262
+ return native.kill();
263
+ },
264
+ async abort() {
265
+ return native.abort();
266
+ },
242
267
  };
243
268
  }
244
269
 
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@supermachine/core",
3
- "version": "0.7.5",
3
+ "version": "0.7.11",
4
4
  "description": "Run any OCI/Docker image as a hardware-isolated microVM. Node/Bun/Deno binding for the supermachine Rust crate.",
5
5
  "license": "Apache-2.0",
6
6
  "main": "index.js",
@@ -22,7 +22,7 @@
22
22
  "arm64"
23
23
  ],
24
24
  "optionalDependencies": {
25
- "@supermachine/core-darwin-arm64": "0.7.5"
25
+ "@supermachine/core-darwin-arm64": "0.7.11"
26
26
  },
27
27
  "scripts": {
28
28
  "build:rust": "TYPE_DEF_TMP_PATH=$(pwd)/scripts/.napi_type_defs.tmp cargo build --release -p supermachine-napi && cargo build --release --bin supermachine-worker -p supermachine",