@molecule/api-code-sandbox-flyio 1.3.2 → 1.3.4

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/README.md CHANGED
@@ -3,7 +3,7 @@ AUTO-GENERATED — DO NOT EDIT THIS FILE.
3
3
  Generated by `mlcl sync-docs` from the package's src/index.ts JSDoc + mlcl/registry.json.
4
4
  Edits here are overwritten on the next commit (molecule's pre-commit hook regenerates).
5
5
  To change this document, edit the module-level JSDoc in src/index.ts.
6
- Generated: 2026-10-17T03:41:21.100Z
6
+ Generated: 2026-10-25T20:03:27.883Z
7
7
  -->
8
8
 
9
9
  # @molecule/api-code-sandbox-flyio
@@ -389,7 +389,7 @@ interface FlyioConfig {
389
389
  * `SandboxProvider.defaultIdleAction`. A caller can override it for one sandbox
390
390
  * with `SandboxConfig.idleAction` and restore this value afterwards with
391
391
  * `Sandbox.setIdleAction` — which is what a production deploy does so its
392
- * destination cannot suspend mid-copy (m103, 2026-10-17).
392
+ * destination cannot suspend mid-copy.
393
393
  */
394
394
  autostop?: 'off' | 'stop' | 'suspend'
395
395
  /**
@@ -1 +1 @@
1
- {"version":3,"file":"exec.d.ts","sourceRoot":"","sources":["../src/exec.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;GAsBG;AAGH,OAAO,KAAK,EAAE,WAAW,EAAE,UAAU,EAAE,MAAM,4BAA4B,CAAA;AAGzE,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,YAAY,CAAA;AAKjD;;;;GAIG;AACH,eAAO,MAAM,4BAA4B,KAAK,CAAA;AAE9C;;;;GAIG;AACH,eAAO,MAAM,0BAA0B,KAAK,CAAA;AAW5C;;;;GAIG;AACH,eAAO,MAAM,yBAAyB,QAAkB,CAAA;AA6BxD;;;;;;;;GAQG;AACH,eAAO,MAAM,sBAAsB,QAAS,CAAA;AAY5C;;;;;GAKG;AACH,eAAO,MAAM,uBAAuB,KAAK,CAAA;AAEzC,0FAA0F;AAC1F,MAAM,MAAM,OAAO,GAAG,CAAC,OAAO,EAAE,MAAM,EAAE,EAAE,cAAc,EAAE,MAAM,KAAK,OAAO,CAAC,eAAe,CAAC,CAAA;AAE7F;;;;;;;;GAQG;AACH,wBAAgB,YAAY,CAAC,QAAQ,EAAE,eAAe,GAAG,UAAU,CAiBlE;AAED;;;;;;;GAOG;AACH,wBAAgB,WAAW,CACzB,OAAO,EAAE,MAAM,EACf,IAAI,EAAE,WAAW,GAAG,SAAS,EAC7B,UAAU,EAAE,MAAM,GACjB,MAAM,CAGR;AAmDD;;;;;;;;;;;;;GAaG;AACH,wBAAsB,WAAW,CAC/B,OAAO,EAAE,OAAO,EAChB,OAAO,EAAE,MAAM,EACf,IAAI,EAAE,WAAW,GAAG,SAAS,EAC7B,UAAU,EAAE,MAAM,GACjB,OAAO,CAAC,UAAU,CAAC,CAqBrB"}
1
+ {"version":3,"file":"exec.d.ts","sourceRoot":"","sources":["../src/exec.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;GAsBG;AAGH,OAAO,KAAK,EAAE,WAAW,EAAE,UAAU,EAAE,MAAM,4BAA4B,CAAA;AAGzE,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,YAAY,CAAA;AAKjD;;;;GAIG;AACH,eAAO,MAAM,4BAA4B,KAAK,CAAA;AAE9C;;;;GAIG;AACH,eAAO,MAAM,0BAA0B,KAAK,CAAA;AAW5C;;;;GAIG;AACH,eAAO,MAAM,yBAAyB,QAAkB,CAAA;AA4BxD;;;;;;;;GAQG;AACH,eAAO,MAAM,sBAAsB,QAAS,CAAA;AAY5C;;;;;GAKG;AACH,eAAO,MAAM,uBAAuB,KAAK,CAAA;AAEzC,0FAA0F;AAC1F,MAAM,MAAM,OAAO,GAAG,CAAC,OAAO,EAAE,MAAM,EAAE,EAAE,cAAc,EAAE,MAAM,KAAK,OAAO,CAAC,eAAe,CAAC,CAAA;AAE7F;;;;;;;;GAQG;AACH,wBAAgB,YAAY,CAAC,QAAQ,EAAE,eAAe,GAAG,UAAU,CAiBlE;AAED;;;;;;;GAOG;AACH,wBAAgB,WAAW,CACzB,OAAO,EAAE,MAAM,EACf,IAAI,EAAE,WAAW,GAAG,SAAS,EAC7B,UAAU,EAAE,MAAM,GACjB,MAAM,CAGR;AAmDD;;;;;;;;;;;;;GAaG;AACH,wBAAsB,WAAW,CAC/B,OAAO,EAAE,OAAO,EAChB,OAAO,EAAE,MAAM,EACf,IAAI,EAAE,WAAW,GAAG,SAAS,EAC7B,UAAU,EAAE,MAAM,GACjB,OAAO,CAAC,UAAU,CAAC,CAqBrB"}
package/dist/exec.js CHANGED
@@ -55,10 +55,9 @@ export const MAX_CAPTURED_OUTPUT_BYTES = 5 * 1024 * 1024;
55
55
  * Fly documents NO output ceiling for the Machines API: the exec response's
56
56
  * `flydv1.ExecResponse` schema types `stdout` and `stderr` as plain,
57
57
  * unconstrained strings (https://docs.machines.dev/openapi.json). The live API
58
- * still returns SHORT output with `exit_code: 0` once a response is large —
59
- * measured 2026-10-18 in production (X1 flash-m175): one read of a
60
- * 1,421,432-byte database file came back 897,144 bytes long, exactly one
61
- * 512 KiB slice missing, with no error at all. So the collector asks for no
58
+ * still returns SHORT output with `exit_code: 0` once a response is large: one
59
+ * read of a 1,421,432-byte database file came back 897,144 bytes long, exactly
60
+ * one 512 KiB slice missing, with no error at all. So the collector asks for no
62
61
  * more than this per response and checks every response's decoded length
63
62
  * against what it asked for, shrinking the request when the transport cuts it.
64
63
  */
@@ -1 +1 @@
1
- {"version":3,"file":"provider.d.ts","sourceRoot":"","sources":["../src/provider.ts"],"names":[],"mappings":"AAAA;;;;;;;GAOG;AAMH,OAAO,KAAK,EAYV,eAAe,EAGhB,MAAM,4BAA4B,CAAA;AAGnC,OAAO,EAAE,YAAY,EAAgC,MAAM,UAAU,CAAA;AAwBrE,OAAO,EAAmD,KAAK,WAAW,EAAE,MAAM,cAAc,CAAA;AAEhG,OAAO,KAAK,EAIV,WAAW,EAUZ,MAAM,YAAY,CAAA;AAkBnB;;;;;;;;;;;;;;;;;;;;;;;;;;GA0BG;AACH,wBAAgB,2BAA2B,CAAC,KAAK,EAAE,OAAO,EAAE,YAAY,CAAC,EAAE,MAAM,GAAG,IAAI,GAAG,OAAO,CAIjG;AAED;;;;;;;;;;;;;;GAcG;AACH,wBAAgB,kBAAkB,CAAC,KAAK,EAAE,MAAM,GAAG,IAAI,GAAG,SAAS,GAAG,OAAO,CAE5E;AAkyFD;;;;;;;;;GASG;AACH,wBAAgB,cAAc,CAC5B,MAAM,CAAC,EAAE,WAAW,EACpB,MAAM,CAAC,EAAE,YAAY,EACrB,KAAK,CAAC,EAAE,WAAW,GAAG,IAAI,GACzB,eAAe,CAEjB"}
1
+ {"version":3,"file":"provider.d.ts","sourceRoot":"","sources":["../src/provider.ts"],"names":[],"mappings":"AAAA;;;;;;;GAOG;AAOH,OAAO,KAAK,EAYV,eAAe,EAGhB,MAAM,4BAA4B,CAAA;AAGnC,OAAO,EAAE,YAAY,EAAgC,MAAM,UAAU,CAAA;AAwBrE,OAAO,EAAmD,KAAK,WAAW,EAAE,MAAM,cAAc,CAAA;AAEhG,OAAO,KAAK,EAIV,WAAW,EAUZ,MAAM,YAAY,CAAA;AAkBnB;;;;;;;;;;;;;;;;;;;;;;;;;;GA0BG;AACH,wBAAgB,2BAA2B,CAAC,KAAK,EAAE,OAAO,EAAE,YAAY,CAAC,EAAE,MAAM,GAAG,IAAI,GAAG,OAAO,CAIjG;AAED;;;;;;;;;;;;;;GAcG;AACH,wBAAgB,kBAAkB,CAAC,KAAK,EAAE,MAAM,GAAG,IAAI,GAAG,SAAS,GAAG,OAAO,CAE5E;AA6yFD;;;;;;;;;GASG;AACH,wBAAgB,cAAc,CAC5B,MAAM,CAAC,EAAE,WAAW,EACpB,MAAM,CAAC,EAAE,YAAY,EACrB,KAAK,CAAC,EAAE,WAAW,GAAG,IAAI,GACzB,eAAe,CAEjB"}
package/dist/provider.js CHANGED
@@ -7,7 +7,8 @@
7
7
  * @module
8
8
  */
9
9
  import { createHash } from 'node:crypto';
10
- import { gzipSync } from 'node:zlib';
10
+ import { promisify } from 'node:util';
11
+ import { gzip } from 'node:zlib';
11
12
  import { getLogger } from '@molecule/api-bond';
12
13
  import { t } from '@molecule/api-i18n';
13
14
  import { FlyApiClient, FlyApiError, normalizeApiUrl } from './api.js';
@@ -230,10 +231,9 @@ const EXEC_BODY_MACHINE_NOT_RUNNING = /machine not running/i;
230
231
  * Attempts for one exec when Fly answers a transient 412 — either body of
231
232
  * {@link isTransientExecPrecondition}. Four attempts over the three backoffs
232
233
  * below is under 12 s of waiting, against the ~75 s each fresh production
233
- * deploy costs when this is left to a caller: X1 run flash-m85 (2026-10-16)
234
- * lost three consecutive deploys, and the run, to the dropped connection;
235
- * flash-m94 (2026-10-16) lost 65 s and a whole redeploy to the same budget not
236
- * covering `machine not running` on a Machine Fly reported `started`.
234
+ * deploy costs when this is left to a caller: a dropped connection has cost
235
+ * three consecutive deploys, and a budget that did not cover `machine not
236
+ * running` on a Machine Fly reported `started` has cost a whole redeploy.
237
237
  */
238
238
  const EXEC_PRECONDITION_ATTEMPTS = 4;
239
239
  /**
@@ -272,6 +272,13 @@ const IMPORT_WRITE_CHUNK_BASE64 = 12_000;
272
272
  * the single download happen back-to-back.
273
273
  */
274
274
  const IMPORT_PRESIGN_EXPIRY_SECONDS = 3600;
275
+ /**
276
+ * zlib's gzip on the libuv thread pool. {@link Sandbox.importFiles} compresses
277
+ * a whole deploy archive (hundreds of MB), and the synchronous form ran on the
278
+ * caller's event loop for its full duration — seconds in which a server process
279
+ * hosting this provider answered no request at all.
280
+ */
281
+ const gzipAsync = promisify(gzip);
275
282
  /** Extra seconds allowed for the probe exec beyond its connection budget. */
276
283
  const PROBE_EXEC_HEADROOM_SECONDS = 10;
277
284
  /**
@@ -2336,7 +2343,8 @@ class FlyioSandboxProvider {
2336
2343
  *
2337
2344
  * The Fly Machines exec endpoint is a single request/response with no
2338
2345
  * stdin, so the archive cannot be piped to `tar` directly. It is buffered,
2339
- * gzipped (fewer bytes = fewer exec round trips over the base64 channel),
2346
+ * gzipped on the thread pool, never on the caller's event loop (fewer
2347
+ * bytes = fewer exec round trips over the base64 channel),
2340
2348
  * written to a temp file in `WRITE_CHUNK_BASE64`-sized pieces the same way
2341
2349
  * `writeFile` does, then extracted.
2342
2350
  *
@@ -2351,7 +2359,10 @@ class FlyioSandboxProvider {
2351
2359
  const parts = [];
2352
2360
  for await (const chunk of archive)
2353
2361
  parts.push(Buffer.from(chunk));
2354
- const gz = gzipSync(Buffer.concat(parts));
2362
+ // Off the event loop: the archive is a whole deploy artifact, and
2363
+ // compressing it synchronously stalled every other request this process
2364
+ // was serving for as long as the compression took.
2365
+ const gz = await gzipAsync(Buffer.concat(parts));
2355
2366
  const quotedPath = shellQuote(path);
2356
2367
  const failIfError = (result, step) => {
2357
2368
  if (result.exitCode !== 0) {
package/dist/types.d.ts CHANGED
@@ -116,7 +116,7 @@ export interface FlyioConfig {
116
116
  * `SandboxProvider.defaultIdleAction`. A caller can override it for one sandbox
117
117
  * with `SandboxConfig.idleAction` and restore this value afterwards with
118
118
  * `Sandbox.setIdleAction` — which is what a production deploy does so its
119
- * destination cannot suspend mid-copy (m103, 2026-10-17).
119
+ * destination cannot suspend mid-copy.
120
120
  */
121
121
  autostop?: 'off' | 'stop' | 'suspend';
122
122
  /**
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@molecule/api-code-sandbox-flyio",
3
- "version": "1.3.2",
3
+ "version": "1.3.4",
4
4
  "description": "Fly.io Machines (Firecracker microVM) code sandbox provider",
5
5
  "type": "module",
6
6
  "main": "dist/index.js",