@molecule/api-code-sandbox-flyio 1.0.13 → 1.0.14

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/dist/api.d.ts CHANGED
@@ -113,13 +113,8 @@ export interface FlyApiClientOptions {
113
113
  /** Injectable sleep, for tests. Defaults to `setTimeout`. */
114
114
  sleep?: (ms: number) => Promise<void>;
115
115
  }
116
- /**
117
- * Thin, retrying JSON client for the Fly Machines API.
118
- *
119
- * Deliberately not a generated SDK: this provider touches ~12 endpoints, and a
120
- * generated client would drag in the whole Machines + Postgres + tokens surface
121
- * for no benefit.
122
- */
116
+ /** Test-only: reset the shared pacer so timing tests start from a clean slate. */
117
+ export declare function resetFlyPacerForTests(): void;
123
118
  export declare class FlyApiClient {
124
119
  private readonly token;
125
120
  private readonly baseUrl;
package/dist/api.d.ts.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"file":"api.d.ts","sourceRoot":"","sources":["../src/api.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;GAiBG;AAgBH;;;;GAIG;AACH,qBAAa,WAAY,SAAQ,KAAK;IACpC,kFAAkF;IAClF,QAAQ,CAAC,MAAM,EAAE,MAAM,CAAA;IACvB,sEAAsE;IACtE,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAA;IACrB,yCAAyC;IACzC,QAAQ,CAAC,MAAM,EAAE,MAAM,CAAA;IACvB,oDAAoD;IACpD,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAA;IAErB;;;;;;;OAOG;gBAED,MAAM,EAAE,MAAM,EACd,IAAI,EAAE,MAAM,EACZ,MAAM,EAAE,MAAM,EACd,IAAI,EAAE,MAAM,EACZ,OAAO,CAAC,EAAE;QAAE,KAAK,CAAC,EAAE,OAAO,CAAA;KAAE;CAgBhC;AAED,4CAA4C;AAC5C,MAAM,WAAW,iBAAiB;IAChC,sCAAsC;IACtC,MAAM,CAAC,EAAE,MAAM,CAAA;IACf,0DAA0D;IAC1D,IAAI,CAAC,EAAE,OAAO,CAAA;IACd,8EAA8E;IAC9E,SAAS,CAAC,EAAE,MAAM,CAAA;IAClB,sFAAsF;IACtF,QAAQ,CAAC,EAAE,MAAM,CAAA;IACjB;;;OAGG;IACH,MAAM,CAAC,EAAE,MAAM,EAAE,CAAA;IACjB;;;;;OAKG;IACH,aAAa,CAAC,EAAE,MAAM,EAAE,CAAA;CACzB;AAED;;;;;;;;;;GAUG;AACH,wBAAgB,iBAAiB,CAAC,MAAM,EAAE,MAAM,GAAG,OAAO,CAEzD;AAED;;;;;;;;;;GAUG;AACH,wBAAgB,YAAY,CAAC,OAAO,EAAE,MAAM,EAAE,UAAU,CAAC,EAAE,MAAM,GAAG,IAAI,GAAG,MAAM,CAQhF;AAED;;;;;;;;;GASG;AACH,wBAAgB,eAAe,CAAC,KAAK,EAAE,MAAM,GAAG,SAAS,GAAG,MAAM,CAoBjE;AAED,oDAAoD;AACpD,MAAM,WAAW,mBAAmB;IAClC,gFAAgF;IAChF,KAAK,EAAE,MAAM,MAAM,GAAG,SAAS,CAAA;IAC/B,gCAAgC;IAChC,OAAO,EAAE,MAAM,CAAA;IACf,wCAAwC;IACxC,SAAS,CAAC,EAAE,MAAM,CAAA;IAClB,mEAAmE;IACnE,SAAS,CAAC,EAAE,OAAO,KAAK,CAAA;IACxB,6DAA6D;IAC7D,KAAK,CAAC,EAAE,CAAC,EAAE,EAAE,MAAM,KAAK,OAAO,CAAC,IAAI,CAAC,CAAA;CACtC;AAED;;;;;;GAMG;AACH,qBAAa,YAAY;IACvB,OAAO,CAAC,QAAQ,CAAC,KAAK,CAA0B;IAChD,OAAO,CAAC,QAAQ,CAAC,OAAO,CAAQ;IAChC,OAAO,CAAC,QAAQ,CAAC,SAAS,CAAQ;IAClC,OAAO,CAAC,QAAQ,CAAC,SAAS,CAAc;IACxC,OAAO,CAAC,QAAQ,CAAC,KAAK,CAA+B;IAErD;;;OAGG;gBACS,OAAO,EAAE,mBAAmB;IASxC;;;;;;;;;;OAUG;IACG,OAAO,CAAC,CAAC,EAAE,IAAI,EAAE,MAAM,EAAE,OAAO,GAAE,iBAAsB,GAAG,OAAO,CAAC,CAAC,GAAG,IAAI,CAAC;CA8EnF"}
1
+ {"version":3,"file":"api.d.ts","sourceRoot":"","sources":["../src/api.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;GAiBG;AAgBH;;;;GAIG;AACH,qBAAa,WAAY,SAAQ,KAAK;IACpC,kFAAkF;IAClF,QAAQ,CAAC,MAAM,EAAE,MAAM,CAAA;IACvB,sEAAsE;IACtE,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAA;IACrB,yCAAyC;IACzC,QAAQ,CAAC,MAAM,EAAE,MAAM,CAAA;IACvB,oDAAoD;IACpD,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAA;IAErB;;;;;;;OAOG;gBAED,MAAM,EAAE,MAAM,EACd,IAAI,EAAE,MAAM,EACZ,MAAM,EAAE,MAAM,EACd,IAAI,EAAE,MAAM,EACZ,OAAO,CAAC,EAAE;QAAE,KAAK,CAAC,EAAE,OAAO,CAAA;KAAE;CAgBhC;AAED,4CAA4C;AAC5C,MAAM,WAAW,iBAAiB;IAChC,sCAAsC;IACtC,MAAM,CAAC,EAAE,MAAM,CAAA;IACf,0DAA0D;IAC1D,IAAI,CAAC,EAAE,OAAO,CAAA;IACd,8EAA8E;IAC9E,SAAS,CAAC,EAAE,MAAM,CAAA;IAClB,sFAAsF;IACtF,QAAQ,CAAC,EAAE,MAAM,CAAA;IACjB;;;OAGG;IACH,MAAM,CAAC,EAAE,MAAM,EAAE,CAAA;IACjB;;;;;OAKG;IACH,aAAa,CAAC,EAAE,MAAM,EAAE,CAAA;CACzB;AAED;;;;;;;;;;GAUG;AACH,wBAAgB,iBAAiB,CAAC,MAAM,EAAE,MAAM,GAAG,OAAO,CAEzD;AAED;;;;;;;;;;GAUG;AACH,wBAAgB,YAAY,CAAC,OAAO,EAAE,MAAM,EAAE,UAAU,CAAC,EAAE,MAAM,GAAG,IAAI,GAAG,MAAM,CAQhF;AAED;;;;;;;;;GASG;AACH,wBAAgB,eAAe,CAAC,KAAK,EAAE,MAAM,GAAG,SAAS,GAAG,MAAM,CAoBjE;AAED,oDAAoD;AACpD,MAAM,WAAW,mBAAmB;IAClC,gFAAgF;IAChF,KAAK,EAAE,MAAM,MAAM,GAAG,SAAS,CAAA;IAC/B,gCAAgC;IAChC,OAAO,EAAE,MAAM,CAAA;IACf,wCAAwC;IACxC,SAAS,CAAC,EAAE,MAAM,CAAA;IAClB,mEAAmE;IACnE,SAAS,CAAC,EAAE,OAAO,KAAK,CAAA;IACxB,6DAA6D;IAC7D,KAAK,CAAC,EAAE,CAAC,EAAE,EAAE,MAAM,KAAK,OAAO,CAAC,IAAI,CAAC,CAAA;CACtC;AAyCD,kFAAkF;AAClF,wBAAgB,qBAAqB,IAAI,IAAI,CAG5C;AAED,qBAAa,YAAY;IACvB,OAAO,CAAC,QAAQ,CAAC,KAAK,CAA0B;IAChD,OAAO,CAAC,QAAQ,CAAC,OAAO,CAAQ;IAChC,OAAO,CAAC,QAAQ,CAAC,SAAS,CAAQ;IAClC,OAAO,CAAC,QAAQ,CAAC,SAAS,CAAc;IACxC,OAAO,CAAC,QAAQ,CAAC,KAAK,CAA+B;IAErD;;;OAGG;gBACS,OAAO,EAAE,mBAAmB;IASxC;;;;;;;;;;OAUG;IACG,OAAO,CAAC,CAAC,EAAE,IAAI,EAAE,MAAM,EAAE,OAAO,GAAE,iBAAsB,GAAG,OAAO,CAAC,CAAC,GAAG,IAAI,CAAC;CAiFnF"}
package/dist/api.js CHANGED
@@ -124,6 +124,42 @@ export function normalizeApiUrl(value) {
124
124
  * generated client would drag in the whole Machines + Postgres + tokens surface
125
125
  * for no benefit.
126
126
  */
127
+ /**
128
+ * Minimum gap between Fly Machines API requests, PROCESS-WIDE. Fly rate-limits
129
+ * per account (most tightly the exec endpoint, ~a few req/s), and one molecule
130
+ * process makes every call with one token — so without pacing, a sandbox boot's
131
+ * burst of exec calls trips `429`, and retrying under the cap sustains a storm
132
+ * that LIVELOCKS the boot (observed live 2026-08-09: a workspace stuck
133
+ * "creating" with continuous per-second 429s that never drained). ~220 ms ≈
134
+ * 4.5 req/s keeps us under the cap. Tunable via `FLY_API_MIN_REQUEST_GAP_MS`.
135
+ */
136
+ function minRequestGapMs() {
137
+ const v = Number(process.env.FLY_API_MIN_REQUEST_GAP_MS);
138
+ return Number.isFinite(v) && v >= 0 ? v : 220;
139
+ }
140
+ /**
141
+ * Serializes every request through a shared chain so no two fire closer than
142
+ * {@link MIN_REQUEST_GAP_MS}. Module-level (not per-client) so concurrent
143
+ * sandbox boots share ONE pacer and cannot collectively exceed the account cap.
144
+ * Errors in the chain are swallowed so one failed wait never wedges the queue.
145
+ */
146
+ let flyPacerTail = Promise.resolve();
147
+ let flyLastRequestAt = 0;
148
+ function paceFlyRequest(sleep) {
149
+ const mine = flyPacerTail.then(async () => {
150
+ const wait = Math.max(0, flyLastRequestAt + minRequestGapMs() - Date.now());
151
+ if (wait > 0)
152
+ await sleep(wait);
153
+ flyLastRequestAt = Date.now();
154
+ });
155
+ flyPacerTail = mine.catch(() => { });
156
+ return mine;
157
+ }
158
+ /** Test-only: reset the shared pacer so timing tests start from a clean slate. */
159
+ export function resetFlyPacerForTests() {
160
+ flyPacerTail = Promise.resolve();
161
+ flyLastRequestAt = 0;
162
+ }
127
163
  export class FlyApiClient {
128
164
  token;
129
165
  baseUrl;
@@ -164,6 +200,9 @@ export class FlyApiClient {
164
200
  }
165
201
  let lastError;
166
202
  for (let attempt = 1; attempt <= attempts; attempt++) {
203
+ // Pace EVERY network call (including retries) through the process-wide
204
+ // limiter so a boot's burst of exec calls never trips Fly's account 429.
205
+ await paceFlyRequest(this.sleep);
167
206
  const controller = new AbortController();
168
207
  const timer = setTimeout(() => controller.abort(), options.timeoutMs ?? this.timeoutMs);
169
208
  // Initialized to 0 ("no answer received"), which is the value that
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@molecule/api-code-sandbox-flyio",
3
- "version": "1.0.13",
3
+ "version": "1.0.14",
4
4
  "description": "Fly.io Machines (Firecracker microVM) code sandbox provider",
5
5
  "type": "module",
6
6
  "main": "dist/index.js",