@molecule/api-code-sandbox-flyio 1.2.3 → 1.2.5

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-08-16T14:04:35.624Z
6
+ Generated: 2026-10-08T03:25:09.946Z
7
7
  -->
8
8
 
9
9
  # @molecule/api-code-sandbox-flyio
@@ -2145,6 +2145,17 @@ refused, a leading `/` stripped, a write through a symlink refused, and
2145
2145
  setuid/setgid dropped by `--no-same-permissions` — were verified by running
2146
2146
  GNU tar 1.35 against crafted archives rather than inferred from its manual.
2147
2147
 
2148
+ **Absence vs failure: `get()` only answers `null` for a REAL absence.**
2149
+ `get()` (and each read shaped like it — `list()`, `find()`, `getTemplate()`)
2150
+ reserves `null`/`[]` for a positive not-found answer — Fly answered 404 for
2151
+ the app or the Machine — and THROWS for every other failure: 5xx, 429 past
2152
+ the client's retries, timeouts, network errors. A caller that reconciles
2153
+ from `null` (clearing sandbox ids, reaping Machines) must never read a
2154
+ transient Fly API blip as "the sandbox does not exist"; treat a rejection
2155
+ from these methods as "unknown", never as "gone". The thrown error carries
2156
+ the underlying `FlyApiError` (HTTP status, or 0 for a transport failure) as
2157
+ its `cause`.
2158
+
2148
2159
  **`sleep()` is suspend, not stop — that is the point of this bond.**
2149
2160
  `sleep()` calls `POST /v1/apps/{app}/machines/{id}/suspend`, which "uses
2150
2161
  Firecracker snapshots to capture the entire VM state: CPU registers, memory
package/dist/index.d.ts CHANGED
@@ -86,6 +86,17 @@
86
86
  * setuid/setgid dropped by `--no-same-permissions` — were verified by running
87
87
  * GNU tar 1.35 against crafted archives rather than inferred from its manual.
88
88
  *
89
+ * **Absence vs failure: `get()` only answers `null` for a REAL absence.**
90
+ * `get()` (and each read shaped like it — `list()`, `find()`, `getTemplate()`)
91
+ * reserves `null`/`[]` for a positive not-found answer — Fly answered 404 for
92
+ * the app or the Machine — and THROWS for every other failure: 5xx, 429 past
93
+ * the client's retries, timeouts, network errors. A caller that reconciles
94
+ * from `null` (clearing sandbox ids, reaping Machines) must never read a
95
+ * transient Fly API blip as "the sandbox does not exist"; treat a rejection
96
+ * from these methods as "unknown", never as "gone". The thrown error carries
97
+ * the underlying `FlyApiError` (HTTP status, or 0 for a transport failure) as
98
+ * its `cause`.
99
+ *
89
100
  * **`sleep()` is suspend, not stop — that is the point of this bond.**
90
101
  * `sleep()` calls `POST /v1/apps/{app}/machines/{id}/suspend`, which "uses
91
102
  * Firecracker snapshots to capture the entire VM state: CPU registers, memory
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA0UG;AAEH,cAAc,UAAU,CAAA;AACxB,cAAc,oBAAoB,CAAA;AAClC,cAAc,aAAa,CAAA;AAC3B,cAAc,WAAW,CAAA;AACzB,cAAc,cAAc,CAAA;AAC5B,cAAc,UAAU,CAAA;AACxB,cAAc,eAAe,CAAA;AAC7B,cAAc,cAAc,CAAA;AAC5B,cAAc,gBAAgB,CAAA;AAC9B,cAAc,YAAY,CAAA;AAC1B,cAAc,gBAAgB,CAAA;AAE9B,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,4BAA4B,CAAA;AAMjE;;GAEG;AACH,eAAO,MAAM,QAAQ,EAAE,eAUrB,CAAA"}
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAqVG;AAEH,cAAc,UAAU,CAAA;AACxB,cAAc,oBAAoB,CAAA;AAClC,cAAc,aAAa,CAAA;AAC3B,cAAc,WAAW,CAAA;AACzB,cAAc,cAAc,CAAA;AAC5B,cAAc,UAAU,CAAA;AACxB,cAAc,eAAe,CAAA;AAC7B,cAAc,cAAc,CAAA;AAC5B,cAAc,gBAAgB,CAAA;AAC9B,cAAc,YAAY,CAAA;AAC1B,cAAc,gBAAgB,CAAA;AAE9B,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,4BAA4B,CAAA;AAMjE;;GAEG;AACH,eAAO,MAAM,QAAQ,EAAE,eAUrB,CAAA"}
package/dist/index.js CHANGED
@@ -86,6 +86,17 @@
86
86
  * setuid/setgid dropped by `--no-same-permissions` — were verified by running
87
87
  * GNU tar 1.35 against crafted archives rather than inferred from its manual.
88
88
  *
89
+ * **Absence vs failure: `get()` only answers `null` for a REAL absence.**
90
+ * `get()` (and each read shaped like it — `list()`, `find()`, `getTemplate()`)
91
+ * reserves `null`/`[]` for a positive not-found answer — Fly answered 404 for
92
+ * the app or the Machine — and THROWS for every other failure: 5xx, 429 past
93
+ * the client's retries, timeouts, network errors. A caller that reconciles
94
+ * from `null` (clearing sandbox ids, reaping Machines) must never read a
95
+ * transient Fly API blip as "the sandbox does not exist"; treat a rejection
96
+ * from these methods as "unknown", never as "gone". The thrown error carries
97
+ * the underlying `FlyApiError` (HTTP status, or 0 for a transport failure) as
98
+ * its `cause`.
99
+ *
89
100
  * **`sleep()` is suspend, not stop — that is the point of this bond.**
90
101
  * `sleep()` calls `POST /v1/apps/{app}/machines/{id}/suspend`, which "uses
91
102
  * Firecracker snapshots to capture the entire VM state: CPU registers, memory
@@ -1 +1 @@
1
- {"version":3,"file":"provider.d.ts","sourceRoot":"","sources":["../src/provider.ts"],"names":[],"mappings":"AAAA;;;;;;;GAOG;AAMH,OAAO,KAAK,EAWV,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;AA8yEnB;;;;;;;;;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;AAMH,OAAO,KAAK,EAWV,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;AA20EnB;;;;;;;;;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
@@ -1043,8 +1043,22 @@ class FlyioSandboxProvider {
1043
1043
  }
1044
1044
  /**
1045
1045
  * Retrieves an existing sandbox by its composite `<app>:<machineId>` id.
1046
+ *
1047
+ * `null` is reserved for a POSITIVE answer that the sandbox is gone: Fly
1048
+ * answered 404 for the app or the Machine (the client's `nullOn: [404]`
1049
+ * resolves that before this method sees an error), or the id is not in
1050
+ * `<app>:<machineId>` form at all. Every OTHER failure — 5xx, 429, a timeout,
1051
+ * a network error, anything the API call can still throw after its retries —
1052
+ * THROWS. That split is the core's absence contract, and it is load-bearing:
1053
+ * a caller that reconciles from `null` (clearing sandbox ids, reaping
1054
+ * Machines) must never read a transient Fly blip as "the sandbox does not
1055
+ * exist" — on 2026-10-07 exactly that orphaned live Machines that kept
1056
+ * billing with no row left to name them.
1046
1057
  * @param id - The sandbox id returned by `create`.
1047
- * @returns The sandbox, or `null` when the id is malformed or the Machine is gone.
1058
+ * @returns The sandbox, or `null` when the id is malformed or Fly positively
1059
+ * answered that the app or Machine does not exist.
1060
+ * @throws {Error} When the lookup itself failed — with `cause` carrying the
1061
+ * `FlyApiError`. The Machine may still exist; this is not an absence answer.
1048
1062
  */
1049
1063
  async get(id) {
1050
1064
  let app;
@@ -1066,8 +1080,15 @@ class FlyioSandboxProvider {
1066
1080
  return this.buildSandbox(app, machine.id, mapMachineState(machine.state ?? 'created'));
1067
1081
  }
1068
1082
  catch (error) {
1069
- logger.debug('Failed to get Fly Machine', { id, error });
1070
- return null;
1083
+ // NOT an absence. Returning null here made molecule.dev's loss-recorder
1084
+ // clear the sandbox ids of projects whose Machines were still running
1085
+ // (2026-10-07, two leaked 2 vCPU / 4 GB Machines). Say the lookup failed
1086
+ // and keep the cause, so the caller retries or surfaces it instead.
1087
+ throw new Error(t('codeSandbox.flyio.error.getFailed', { id }, {
1088
+ defaultValue: `Cannot read Fly sandbox "${id}": the Fly API lookup failed, so whether it exists ` +
1089
+ 'is UNKNOWN — the Machine may still be running. This is not an absence answer; ' +
1090
+ 'retry or surface the error rather than treating the sandbox as gone.',
1091
+ }), { cause: error });
1071
1092
  }
1072
1093
  }
1073
1094
  /**
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@molecule/api-code-sandbox-flyio",
3
- "version": "1.2.3",
3
+ "version": "1.2.5",
4
4
  "description": "Fly.io Machines (Firecracker microVM) code sandbox provider",
5
5
  "type": "module",
6
6
  "main": "dist/index.js",
@@ -31,7 +31,7 @@
31
31
  "license": "Apache-2.0",
32
32
  "devDependencies": {
33
33
  "@molecule/api-bond": "1.0.2",
34
- "@molecule/api-code-sandbox": "1.2.1",
34
+ "@molecule/api-code-sandbox": "1.3.0",
35
35
  "@types/node": "26.1.2",
36
36
  "typescript": "6.0.3",
37
37
  "vitest": "4.1.11"