@molecule/api-code-sandbox-e2b 1.2.0 → 1.2.2

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-16T01:25:40.978Z
6
+ Generated: 2026-08-16T14:04:34.100Z
7
7
  -->
8
8
 
9
9
  # @molecule/api-code-sandbox-e2b
@@ -441,7 +441,7 @@ export function setupCodeSandboxE2b(): void {
441
441
  Peer dependencies:
442
442
 
443
443
  - `@molecule/api-bond` ^1.0.1
444
- - `@molecule/api-code-sandbox` ^1.0.1
444
+ - `@molecule/api-code-sandbox` ^1.2.0
445
445
  - `@molecule/api-i18n` ^1.0.1
446
446
 
447
447
  ### Environment Variables
@@ -237,6 +237,20 @@ export declare class E2BSandboxProvider implements SandboxProvider {
237
237
  * @returns The observed egress verdict.
238
238
  */
239
239
  verifyEgress(): Promise<EgressVerdict>;
240
+ /**
241
+ * Destroy an egress-probe sandbox, retrying once.
242
+ *
243
+ * @param id - The probe sandbox id.
244
+ * @returns Null when it was destroyed, else a sentence naming the leaked sandbox.
245
+ */
246
+ private destroyProbe;
247
+ /**
248
+ * Run the egress checks inside an already-created probe sandbox.
249
+ *
250
+ * @param handle - The probe sandbox.
251
+ * @returns The observed verdict; any failure is `inconclusive`.
252
+ */
253
+ private probeEgress;
240
254
  }
241
255
  /**
242
256
  * Create an E2B provider with the given configuration.
@@ -1 +1 @@
1
- {"version":3,"file":"provider.d.ts","sourceRoot":"","sources":["../src/provider.ts"],"names":[],"mappings":"AAAA;;;;;;;;;GASG;AAEH,OAAO,KAAK,EACV,qBAAqB,EAErB,aAAa,EAKb,oBAAoB,EACpB,kBAAkB,EAClB,OAAO,EACP,aAAa,EACb,iBAAiB,EACjB,eAAe,EACf,eAAe,EAGf,UAAU,EACX,MAAM,4BAA4B,CAAA;AAEnC,OAAO,KAAK,EAGV,SAAS,EACT,oBAAoB,EAMrB,MAAM,YAAY,CAAA;AAkvBnB;;;;;;;;;GASG;AACH,qBAAa,kBAAmB,YAAW,eAAe;IACxD,QAAQ,CAAC,IAAI,SAAQ;IAErB,OAAO,CAAC,QAAQ,CAAC,MAAM,CAA0D;IACjF,OAAO,CAAC,aAAa,CAA6C;IAClE,OAAO,CAAC,QAAQ,CAAC,cAAc,CAAC,CAAsB;IAEtD;;;;;OAKG;gBACS,MAAM,GAAE,SAAc,EAAE,cAAc,CAAC,EAAE,oBAAoB;IAYzE;;;;OAIG;YACW,MAAM;IASpB;;;;;;;;;;;;;;;;;;;;;;;;OAwBG;IACG,MAAM,CAAC,MAAM,EAAE,aAAa,GAAG,OAAO,CAAC,OAAO,CAAC;IA+BrD;;;;;OAKG;IACG,GAAG,CAAC,EAAE,EAAE,MAAM,GAAG,OAAO,CAAC,OAAO,GAAG,IAAI,CAAC;IAoB9C;;;;;;;;;;;;;;;OAeG;IACG,QAAQ,CAAC,EAAE,EAAE,MAAM,GAAG,OAAO,CAAC,iBAAiB,GAAG,IAAI,CAAC;IAkC7D;;;;;OAKG;IACG,IAAI,CAAC,OAAO,EAAE,MAAM,GAAG,OAAO,CAAC,OAAO,EAAE,CAAC;IAgB/C;;;;OAIG;IACG,OAAO,CAAC,EAAE,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC;IAcxC;;;;;;;;;OASG;YACW,aAAa;IAM3B;;;;;OAKG;YACW,UAAU;IASxB;;;;;;;;;;;;;;OAcG;IACG,YAAY,CAAC,IAAI,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC;IAS/C;;;;OAIG;IACG,YAAY,CAAC,IAAI,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC;IAU/C;;;;;;;;;;;OAWG;IACG,YAAY,CAAC,IAAI,EAAE,MAAM,GAAG,OAAO,CAAC,OAAO,CAAC;IAIlD;;;;;;;;;;OAUG;IACG,WAAW,CAAC,OAAO,CAAC,EAAE,kBAAkB,GAAG,OAAO,CAAC,UAAU,EAAE,CAAC;IAmBtE;;;;;;;;;;;;;;;;;;;;;;OAsBG;IACG,cAAc,CAAC,OAAO,EAAE,qBAAqB,GAAG,OAAO,CAAC,eAAe,CAAC;IA6B9E;;;;;;;;;OASG;IACG,WAAW,CAAC,UAAU,EAAE,MAAM,GAAG,OAAO,CAAC,eAAe,GAAG,IAAI,CAAC;IAoBtE;;;;;;;;;OASG;IACG,aAAa,CAAC,OAAO,CAAC,EAAE,oBAAoB,GAAG,OAAO,CAAC,eAAe,EAAE,CAAC;IAmB/E;;;;;;;;;;OAUG;IACG,cAAc,CAAC,UAAU,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC;IAevD;;;;;;;;;;;OAWG;IACG,YAAY,IAAI,OAAO,CAAC,aAAa,CAAC;CAyD7C;AAED;;;;;;GAMG;AACH,wBAAgB,cAAc,CAC5B,MAAM,GAAE,SAAc,EACtB,cAAc,CAAC,EAAE,oBAAoB,GACpC,kBAAkB,CAEpB;AAED,kEAAkE;AAClE,eAAO,MAAM,QAAQ,EAAE,eAAkC,CAAA"}
1
+ {"version":3,"file":"provider.d.ts","sourceRoot":"","sources":["../src/provider.ts"],"names":[],"mappings":"AAAA;;;;;;;;;GASG;AAEH,OAAO,KAAK,EACV,qBAAqB,EAErB,aAAa,EAKb,oBAAoB,EACpB,kBAAkB,EAClB,OAAO,EACP,aAAa,EACb,iBAAiB,EACjB,eAAe,EACf,eAAe,EAGf,UAAU,EACX,MAAM,4BAA4B,CAAA;AAEnC,OAAO,KAAK,EAGV,SAAS,EACT,oBAAoB,EAMrB,MAAM,YAAY,CAAA;AAkvBnB;;;;;;;;;GASG;AACH,qBAAa,kBAAmB,YAAW,eAAe;IACxD,QAAQ,CAAC,IAAI,SAAQ;IAErB,OAAO,CAAC,QAAQ,CAAC,MAAM,CAA0D;IACjF,OAAO,CAAC,aAAa,CAA6C;IAClE,OAAO,CAAC,QAAQ,CAAC,cAAc,CAAC,CAAsB;IAEtD;;;;;OAKG;gBACS,MAAM,GAAE,SAAc,EAAE,cAAc,CAAC,EAAE,oBAAoB;IAYzE;;;;OAIG;YACW,MAAM;IASpB;;;;;;;;;;;;;;;;;;;;;;;;OAwBG;IACG,MAAM,CAAC,MAAM,EAAE,aAAa,GAAG,OAAO,CAAC,OAAO,CAAC;IA4CrD;;;;;OAKG;IACG,GAAG,CAAC,EAAE,EAAE,MAAM,GAAG,OAAO,CAAC,OAAO,GAAG,IAAI,CAAC;IAoB9C;;;;;;;;;;;;;;;OAeG;IACG,QAAQ,CAAC,EAAE,EAAE,MAAM,GAAG,OAAO,CAAC,iBAAiB,GAAG,IAAI,CAAC;IAkC7D;;;;;OAKG;IACG,IAAI,CAAC,OAAO,EAAE,MAAM,GAAG,OAAO,CAAC,OAAO,EAAE,CAAC;IAgB/C;;;;OAIG;IACG,OAAO,CAAC,EAAE,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC;IAcxC;;;;;;;;;OASG;YACW,aAAa;IAM3B;;;;;OAKG;YACW,UAAU;IASxB;;;;;;;;;;;;;;OAcG;IACG,YAAY,CAAC,IAAI,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC;IAS/C;;;;OAIG;IACG,YAAY,CAAC,IAAI,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC;IAU/C;;;;;;;;;;;OAWG;IACG,YAAY,CAAC,IAAI,EAAE,MAAM,GAAG,OAAO,CAAC,OAAO,CAAC;IAIlD;;;;;;;;;;OAUG;IACG,WAAW,CAAC,OAAO,CAAC,EAAE,kBAAkB,GAAG,OAAO,CAAC,UAAU,EAAE,CAAC;IAmBtE;;;;;;;;;;;;;;;;;;;;;;OAsBG;IACG,cAAc,CAAC,OAAO,EAAE,qBAAqB,GAAG,OAAO,CAAC,eAAe,CAAC;IA6B9E;;;;;;;;;OASG;IACG,WAAW,CAAC,UAAU,EAAE,MAAM,GAAG,OAAO,CAAC,eAAe,GAAG,IAAI,CAAC;IAoBtE;;;;;;;;;OASG;IACG,aAAa,CAAC,OAAO,CAAC,EAAE,oBAAoB,GAAG,OAAO,CAAC,eAAe,EAAE,CAAC;IAmB/E;;;;;;;;;;OAUG;IACG,cAAc,CAAC,UAAU,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC;IAevD;;;;;;;;;;;OAWG;IACG,YAAY,IAAI,OAAO,CAAC,aAAa,CAAC;IAoB5C;;;;;OAKG;YACW,YAAY;IAa1B;;;;;OAKG;YACW,WAAW;CAsC1B;AAED;;;;;;GAMG;AACH,wBAAgB,cAAc,CAC5B,MAAM,GAAE,SAAc,EACtB,cAAc,CAAC,EAAE,oBAAoB,GACpC,kBAAkB,CAEpB;AAED,kEAAkE;AAClE,eAAO,MAAM,QAAQ,EAAE,eAAkC,CAAA"}
package/dist/provider.js CHANGED
@@ -800,7 +800,18 @@ export class E2BSandboxProvider {
800
800
  });
801
801
  // Apply the egress allow-list immediately, before any user code runs.
802
802
  if (this.config.defaultAllowOut.length > 0) {
803
- await handle.applyNetwork(this.config.defaultAllowOut);
803
+ try {
804
+ await handle.applyNetwork(this.config.defaultAllowOut);
805
+ }
806
+ catch (error) {
807
+ // The sandbox exists on E2B but the caller never receives its handle, so
808
+ // nothing else can ever destroy it: it would run until its timeout and
809
+ // then sit paused (billed storage) forever. Kill it before rethrowing.
810
+ await this.destroy(sbx.sandboxId).catch((destroyError) => {
811
+ throw new Error(`E2B sandbox ${sbx.sandboxId} was created but its egress policy failed to apply, and destroying it failed too — it is orphaned: ${destroyError instanceof Error ? destroyError.message : String(destroyError)}`, { cause: error });
812
+ });
813
+ throw error;
814
+ }
804
815
  }
805
816
  return handle;
806
817
  }
@@ -1180,7 +1191,7 @@ export class E2BSandboxProvider {
1180
1191
  * @returns The observed egress verdict.
1181
1192
  */
1182
1193
  async verifyEgress() {
1183
- let handle = null;
1194
+ let handle;
1184
1195
  try {
1185
1196
  handle = await this.create({ projectId: `egress-probe-${Date.now()}`, env: {} });
1186
1197
  }
@@ -1191,6 +1202,40 @@ export class E2BSandboxProvider {
1191
1202
  remediation: 'Check E2B_API_KEY and account capacity.',
1192
1203
  };
1193
1204
  }
1205
+ const verdict = await this.probeEgress(handle);
1206
+ // The probe sandbox is destroyed on EVERY path. A failed destroy is retried,
1207
+ // and one that still fails is reported in the verdict's detail: the sandbox
1208
+ // was created to pause at its timeout, so a silently leaked probe is billed
1209
+ // storage forever.
1210
+ const leaked = await this.destroyProbe(handle.id);
1211
+ return leaked ? { ...verdict, detail: `${verdict.detail} ${leaked}` } : verdict;
1212
+ }
1213
+ /**
1214
+ * Destroy an egress-probe sandbox, retrying once.
1215
+ *
1216
+ * @param id - The probe sandbox id.
1217
+ * @returns Null when it was destroyed, else a sentence naming the leaked sandbox.
1218
+ */
1219
+ async destroyProbe(id) {
1220
+ let lastError = null;
1221
+ for (let attempt = 0; attempt < 2; attempt++) {
1222
+ try {
1223
+ await this.destroy(id);
1224
+ return null;
1225
+ }
1226
+ catch (error) {
1227
+ lastError = error;
1228
+ }
1229
+ }
1230
+ return `(The probe sandbox ${id} could not be destroyed and is left behind: ${lastError instanceof Error ? lastError.message : String(lastError)}.)`;
1231
+ }
1232
+ /**
1233
+ * Run the egress checks inside an already-created probe sandbox.
1234
+ *
1235
+ * @param handle - The probe sandbox.
1236
+ * @returns The observed verdict; any failure is `inconclusive`.
1237
+ */
1238
+ async probeEgress(handle) {
1194
1239
  try {
1195
1240
  // Force a KNOWN deny-default policy for the probe regardless of config.
1196
1241
  await handle.applyNetwork([
@@ -1222,16 +1267,6 @@ export class E2BSandboxProvider {
1222
1267
  detail: `Egress probe could not run: ${error instanceof Error ? error.message : String(error)}`,
1223
1268
  };
1224
1269
  }
1225
- finally {
1226
- // Best-effort cleanup of the throwaway probe sandbox; a failed destroy
1227
- // must not mask the verdict (E2B auto-pauses idle sandboxes regardless).
1228
- if (handle) {
1229
- await this.destroy(handle.id).catch((_error) => {
1230
- // intentional noop — probe teardown is best-effort; the sandbox
1231
- // auto-pauses and the verdict is what matters.
1232
- });
1233
- }
1234
- }
1235
1270
  }
1236
1271
  }
1237
1272
  /**
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@molecule/api-code-sandbox-e2b",
3
- "version": "1.2.0",
3
+ "version": "1.2.2",
4
4
  "description": "E2B (e2b.dev) code sandbox provider — Firecracker microVMs with golden templates, fork, and pause/resume",
5
5
  "type": "module",
6
6
  "main": "dist/index.js",
@@ -29,11 +29,11 @@
29
29
  ],
30
30
  "license": "Apache-2.0",
31
31
  "devDependencies": {
32
- "@molecule/api-bond": "1.0.1",
33
- "@molecule/api-code-sandbox": "1.2.0",
32
+ "@molecule/api-bond": "1.0.2",
33
+ "@molecule/api-code-sandbox": "1.2.1",
34
34
  "@types/node": "26.1.2",
35
35
  "typescript": "6.0.3",
36
- "vitest": "4.1.10"
36
+ "vitest": "4.1.11"
37
37
  },
38
38
  "peerDependencies": {
39
39
  "@molecule/api-bond": "^1.0.1",
@@ -50,7 +50,7 @@
50
50
  "url": "https://github.com/molecule-dev/molecule.git",
51
51
  "directory": "packages/api/bonds/code-sandbox/e2b"
52
52
  },
53
- "homepage": "https://github.com/molecule-dev/molecule/tree/main/packages/api/bonds/code-sandbox/e2b",
53
+ "homepage": "https://www.molecule.dev/packages/api-code-sandbox-e2b",
54
54
  "bugs": "https://github.com/molecule-dev/molecule/issues",
55
55
  "publishConfig": {
56
56
  "access": "public"