@molecule/api-code-sandbox-e2b 1.0.4 → 1.1.0
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 +75 -10
- package/dist/index.d.ts +26 -6
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +26 -6
- package/dist/provider.d.ts +27 -1
- package/dist/provider.d.ts.map +1 -1
- package/dist/provider.js +158 -11
- package/dist/types.d.ts +42 -0
- package/dist/types.d.ts.map +1 -1
- package/package.json +2 -2
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-
|
|
6
|
+
Generated: 2026-08-15T18:25:48.482Z
|
|
7
7
|
-->
|
|
8
8
|
|
|
9
9
|
# @molecule/api-code-sandbox-e2b
|
|
@@ -45,12 +45,9 @@ import { createProvider } from '@molecule/api-code-sandbox-e2b'
|
|
|
45
45
|
const provider = createProvider({
|
|
46
46
|
templateId: 'molecule-superset',
|
|
47
47
|
defaultPreviewPort: 5173,
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
{ domain: 'github.com', action: 'allow' },
|
|
52
|
-
{ domain: '*', action: 'deny' },
|
|
53
|
-
],
|
|
48
|
+
// Deny-by-default egress: everything not listed here is blocked, raw IPs
|
|
49
|
+
// included. An empty/omitted list applies NO policy at all.
|
|
50
|
+
defaultAllowOut: ['registry.npmjs.org', '*.npmjs.org', 'github.com'],
|
|
54
51
|
})
|
|
55
52
|
```
|
|
56
53
|
|
|
@@ -61,7 +58,7 @@ const provider = createProvider({
|
|
|
61
58
|
## Installation
|
|
62
59
|
|
|
63
60
|
```bash
|
|
64
|
-
npm install @molecule/api-code-sandbox-e2b
|
|
61
|
+
npm install @molecule/api-code-sandbox-e2b @bufbuild/protobuf @molecule/api-bond @molecule/api-code-sandbox @molecule/api-i18n e2b
|
|
65
62
|
```
|
|
66
63
|
|
|
67
64
|
## API
|
|
@@ -125,6 +122,10 @@ interface E2BConfig {
|
|
|
125
122
|
/**
|
|
126
123
|
* Default sandbox lifetime before E2B auto-pauses it, in milliseconds. The
|
|
127
124
|
* control plane extends this per-heartbeat; this is only the initial ceiling.
|
|
125
|
+
*
|
|
126
|
+
* E2B caps this per account: 1 hour on Hobby, 24 hours on Pro. A value above
|
|
127
|
+
* the account's cap is rejected at create time, so raising it is a decision
|
|
128
|
+
* about the account, not just the config.
|
|
128
129
|
*/
|
|
129
130
|
defaultTimeoutMs?: number
|
|
130
131
|
/**
|
|
@@ -168,8 +169,48 @@ interface E2BSandboxClientLike {
|
|
|
168
169
|
connect(sandboxId: string, opts?: Record<string, unknown>): Promise<E2BSandboxLike>
|
|
169
170
|
list(
|
|
170
171
|
opts?: Record<string, unknown>,
|
|
171
|
-
): Promise<
|
|
172
|
+
): Promise<
|
|
173
|
+
| Array<{ sandboxId: string; state?: string }>
|
|
174
|
+
| { sandboxes?: Array<{ sandboxId: string; state?: string }> }
|
|
175
|
+
>
|
|
172
176
|
kill?(sandboxId: string, opts?: Record<string, unknown>): Promise<boolean>
|
|
177
|
+
/**
|
|
178
|
+
* Read a sandbox's record WITHOUT connecting to it — the only lookup that does
|
|
179
|
+
* not resume a paused sandbox. Throws `SandboxNotFoundError` on a 404.
|
|
180
|
+
*/
|
|
181
|
+
getInfo?(sandboxId: string, opts?: Record<string, unknown>): Promise<E2BSandboxInfoLike>
|
|
182
|
+
/**
|
|
183
|
+
* Whether an error means "this sandbox does not exist", as opposed to "the
|
|
184
|
+
* lookup failed". The distinction cannot be recovered from the error's shape by
|
|
185
|
+
* a consumer, and getting it wrong is what makes a control plane treat a
|
|
186
|
+
* provider outage as a destroyed sandbox.
|
|
187
|
+
*/
|
|
188
|
+
isNotFound?(error: unknown): boolean
|
|
189
|
+
}
|
|
190
|
+
```
|
|
191
|
+
|
|
192
|
+
#### `E2BSandboxInfoLike`
|
|
193
|
+
|
|
194
|
+
Subset of the SDK's `SandboxInfo` the bond reads.
|
|
195
|
+
|
|
196
|
+
This is what a sandbox looks like when you only LOOK at it. `connect` — which
|
|
197
|
+
is how a handle is obtained — RESUMES a paused sandbox and extends its
|
|
198
|
+
deadline, so it can never be used to answer "is this thing asleep?".
|
|
199
|
+
|
|
200
|
+
```typescript
|
|
201
|
+
interface E2BSandboxInfoLike {
|
|
202
|
+
sandboxId: string
|
|
203
|
+
templateId?: string
|
|
204
|
+
/** `'running'` or `'paused'`; anything else is treated as running. */
|
|
205
|
+
state?: string
|
|
206
|
+
/** Caller metadata supplied at create (the bond puts `projectId` here). */
|
|
207
|
+
metadata?: Record<string, string>
|
|
208
|
+
/** When the sandbox last started running. */
|
|
209
|
+
startedAt?: Date | string
|
|
210
|
+
/** When the sandbox's current deadline expires. */
|
|
211
|
+
endAt?: Date | string
|
|
212
|
+
/** Volumes mounted into the sandbox, when the account uses them. */
|
|
213
|
+
volumeMounts?: Array<{ name: string; path: string }>
|
|
173
214
|
}
|
|
174
215
|
```
|
|
175
216
|
|
|
@@ -272,10 +313,11 @@ Peer dependencies:
|
|
|
272
313
|
|
|
273
314
|
### Runtime Dependencies
|
|
274
315
|
|
|
275
|
-
- `
|
|
316
|
+
- `@bufbuild/protobuf`
|
|
276
317
|
- `@molecule/api-bond`
|
|
277
318
|
- `@molecule/api-code-sandbox`
|
|
278
319
|
- `@molecule/api-i18n`
|
|
320
|
+
- `e2b`
|
|
279
321
|
|
|
280
322
|
**`verifyEgress` is intentionally not implemented yet.** The control plane
|
|
281
323
|
treats an absent `verifyEgress` as an `inconclusive` verdict and refuses to
|
|
@@ -288,3 +330,26 @@ trade cost for security). Do not stub it with a fabricated `filtered`.
|
|
|
288
330
|
`resume()` report `processesPreserved: true` because the memory snapshot
|
|
289
331
|
restores the process tree — unlike a Docker stop, a resumed E2B sandbox's
|
|
290
332
|
dev servers are still running.
|
|
333
|
+
|
|
334
|
+
**`get()` RESUMES a paused sandbox — use `describe()` to look at one.**
|
|
335
|
+
Obtaining a handle is `POST /sandboxes/{id}/connect`, which resumes a paused
|
|
336
|
+
sandbox and extends its deadline. That is right for a caller about to USE the
|
|
337
|
+
sandbox and wrong for every status check: polling `get()` every few seconds
|
|
338
|
+
silently un-hibernates every sleeping project and bills for the compute while
|
|
339
|
+
the UI still says "asleep". `describe(id)` reads the record instead, reports
|
|
340
|
+
`sleeping` for a paused sandbox, and changes nothing.
|
|
341
|
+
|
|
342
|
+
**`get()` returns `null` ONLY for a sandbox that does not exist.** Every other
|
|
343
|
+
failure throws. A control plane reads `null` as "gone", detaches the project
|
|
344
|
+
and rebuilds it from a template — and since an E2B microVM is the only copy of
|
|
345
|
+
a project's files, answering a transient 5xx with `null` destroys the user's
|
|
346
|
+
code. "I could not look" must never be delivered as "I looked, and it is not
|
|
347
|
+
there". The same rule governs `describe()`.
|
|
348
|
+
|
|
349
|
+
**Sandboxes are created to PAUSE at their timeout, not to be killed.** E2B's
|
|
350
|
+
default is `onTimeout: 'kill'`, so a sandbox nothing touched for its lifetime
|
|
351
|
+
would be destroyed with its files. This bond creates every sandbox with
|
|
352
|
+
`lifecycle: { onTimeout: { action: 'pause', keepMemory: true } }`; the memory
|
|
353
|
+
snapshot is what lets `resume()` truthfully report `processesPreserved: true`.
|
|
354
|
+
Extending the deadline is `keepAlive(ms)` — call it from a real activity
|
|
355
|
+
signal (an open editor's heartbeat), never as a side effect of polling.
|
package/dist/index.d.ts
CHANGED
|
@@ -32,12 +32,9 @@
|
|
|
32
32
|
* const provider = createProvider({
|
|
33
33
|
* templateId: 'molecule-superset',
|
|
34
34
|
* defaultPreviewPort: 5173,
|
|
35
|
-
*
|
|
36
|
-
*
|
|
37
|
-
*
|
|
38
|
-
* { domain: 'github.com', action: 'allow' },
|
|
39
|
-
* { domain: '*', action: 'deny' },
|
|
40
|
-
* ],
|
|
35
|
+
* // Deny-by-default egress: everything not listed here is blocked, raw IPs
|
|
36
|
+
* // included. An empty/omitted list applies NO policy at all.
|
|
37
|
+
* defaultAllowOut: ['registry.npmjs.org', '*.npmjs.org', 'github.com'],
|
|
41
38
|
* })
|
|
42
39
|
* ```
|
|
43
40
|
*
|
|
@@ -54,6 +51,29 @@
|
|
|
54
51
|
* restores the process tree — unlike a Docker stop, a resumed E2B sandbox's
|
|
55
52
|
* dev servers are still running.
|
|
56
53
|
*
|
|
54
|
+
* **`get()` RESUMES a paused sandbox — use `describe()` to look at one.**
|
|
55
|
+
* Obtaining a handle is `POST /sandboxes/{id}/connect`, which resumes a paused
|
|
56
|
+
* sandbox and extends its deadline. That is right for a caller about to USE the
|
|
57
|
+
* sandbox and wrong for every status check: polling `get()` every few seconds
|
|
58
|
+
* silently un-hibernates every sleeping project and bills for the compute while
|
|
59
|
+
* the UI still says "asleep". `describe(id)` reads the record instead, reports
|
|
60
|
+
* `sleeping` for a paused sandbox, and changes nothing.
|
|
61
|
+
*
|
|
62
|
+
* **`get()` returns `null` ONLY for a sandbox that does not exist.** Every other
|
|
63
|
+
* failure throws. A control plane reads `null` as "gone", detaches the project
|
|
64
|
+
* and rebuilds it from a template — and since an E2B microVM is the only copy of
|
|
65
|
+
* a project's files, answering a transient 5xx with `null` destroys the user's
|
|
66
|
+
* code. "I could not look" must never be delivered as "I looked, and it is not
|
|
67
|
+
* there". The same rule governs `describe()`.
|
|
68
|
+
*
|
|
69
|
+
* **Sandboxes are created to PAUSE at their timeout, not to be killed.** E2B's
|
|
70
|
+
* default is `onTimeout: 'kill'`, so a sandbox nothing touched for its lifetime
|
|
71
|
+
* would be destroyed with its files. This bond creates every sandbox with
|
|
72
|
+
* `lifecycle: { onTimeout: { action: 'pause', keepMemory: true } }`; the memory
|
|
73
|
+
* snapshot is what lets `resume()` truthfully report `processesPreserved: true`.
|
|
74
|
+
* Extending the deadline is `keepAlive(ms)` — call it from a real activity
|
|
75
|
+
* signal (an open editor's heartbeat), never as a side effect of polling.
|
|
76
|
+
*
|
|
57
77
|
* @module
|
|
58
78
|
*/
|
|
59
79
|
export * from './provider.js';
|
package/dist/index.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA6EG;AAEH,cAAc,eAAe,CAAA;AAC7B,cAAc,YAAY,CAAA"}
|
package/dist/index.js
CHANGED
|
@@ -32,12 +32,9 @@
|
|
|
32
32
|
* const provider = createProvider({
|
|
33
33
|
* templateId: 'molecule-superset',
|
|
34
34
|
* defaultPreviewPort: 5173,
|
|
35
|
-
*
|
|
36
|
-
*
|
|
37
|
-
*
|
|
38
|
-
* { domain: 'github.com', action: 'allow' },
|
|
39
|
-
* { domain: '*', action: 'deny' },
|
|
40
|
-
* ],
|
|
35
|
+
* // Deny-by-default egress: everything not listed here is blocked, raw IPs
|
|
36
|
+
* // included. An empty/omitted list applies NO policy at all.
|
|
37
|
+
* defaultAllowOut: ['registry.npmjs.org', '*.npmjs.org', 'github.com'],
|
|
41
38
|
* })
|
|
42
39
|
* ```
|
|
43
40
|
*
|
|
@@ -54,6 +51,29 @@
|
|
|
54
51
|
* restores the process tree — unlike a Docker stop, a resumed E2B sandbox's
|
|
55
52
|
* dev servers are still running.
|
|
56
53
|
*
|
|
54
|
+
* **`get()` RESUMES a paused sandbox — use `describe()` to look at one.**
|
|
55
|
+
* Obtaining a handle is `POST /sandboxes/{id}/connect`, which resumes a paused
|
|
56
|
+
* sandbox and extends its deadline. That is right for a caller about to USE the
|
|
57
|
+
* sandbox and wrong for every status check: polling `get()` every few seconds
|
|
58
|
+
* silently un-hibernates every sleeping project and bills for the compute while
|
|
59
|
+
* the UI still says "asleep". `describe(id)` reads the record instead, reports
|
|
60
|
+
* `sleeping` for a paused sandbox, and changes nothing.
|
|
61
|
+
*
|
|
62
|
+
* **`get()` returns `null` ONLY for a sandbox that does not exist.** Every other
|
|
63
|
+
* failure throws. A control plane reads `null` as "gone", detaches the project
|
|
64
|
+
* and rebuilds it from a template — and since an E2B microVM is the only copy of
|
|
65
|
+
* a project's files, answering a transient 5xx with `null` destroys the user's
|
|
66
|
+
* code. "I could not look" must never be delivered as "I looked, and it is not
|
|
67
|
+
* there". The same rule governs `describe()`.
|
|
68
|
+
*
|
|
69
|
+
* **Sandboxes are created to PAUSE at their timeout, not to be killed.** E2B's
|
|
70
|
+
* default is `onTimeout: 'kill'`, so a sandbox nothing touched for its lifetime
|
|
71
|
+
* would be destroyed with its files. This bond creates every sandbox with
|
|
72
|
+
* `lifecycle: { onTimeout: { action: 'pause', keepMemory: true } }`; the memory
|
|
73
|
+
* snapshot is what lets `resume()` truthfully report `processesPreserved: true`.
|
|
74
|
+
* Extending the deadline is `keepAlive(ms)` — call it from a real activity
|
|
75
|
+
* signal (an open editor's heartbeat), never as a side effect of polling.
|
|
76
|
+
*
|
|
57
77
|
* @module
|
|
58
78
|
*/
|
|
59
79
|
export * from './provider.js';
|
package/dist/provider.d.ts
CHANGED
|
@@ -8,7 +8,7 @@
|
|
|
8
8
|
*
|
|
9
9
|
* @module
|
|
10
10
|
*/
|
|
11
|
-
import type { EgressVerdict, Sandbox, SandboxConfig, SandboxProvider } from '@molecule/api-code-sandbox';
|
|
11
|
+
import type { EgressVerdict, Sandbox, SandboxConfig, SandboxDescriptor, SandboxProvider } from '@molecule/api-code-sandbox';
|
|
12
12
|
import type { E2BConfig, E2BSandboxClientLike } from './types.js';
|
|
13
13
|
/**
|
|
14
14
|
* E2B implementation of {@link SandboxProvider}.
|
|
@@ -41,6 +41,15 @@ export declare class E2BSandboxProvider implements SandboxProvider {
|
|
|
41
41
|
/**
|
|
42
42
|
* Create a new sandbox from the golden template and apply the egress policy.
|
|
43
43
|
*
|
|
44
|
+
* The sandbox is created to PAUSE at its timeout, not to be killed. E2B's
|
|
45
|
+
* default is `onTimeout: 'kill'`, which means a sandbox nothing has touched for
|
|
46
|
+
* its lifetime is destroyed — and on this platform the sandbox is the only copy
|
|
47
|
+
* of the project, so the default turns "the tab was closed over lunch" into
|
|
48
|
+
* permanent data loss. `keepMemory` stays on: the pause snapshot restores the
|
|
49
|
+
* process tree, which is what makes `resume()` honest when it reports
|
|
50
|
+
* `processesPreserved: true`. A filesystem-only snapshot would cold-boot
|
|
51
|
+
* instead, leaving a sandbox that is running with every dev server dead.
|
|
52
|
+
*
|
|
44
53
|
* @param config - Project id, env, optional per-boot templateId + labels.
|
|
45
54
|
* @returns A live sandbox handle.
|
|
46
55
|
*/
|
|
@@ -52,6 +61,23 @@ export declare class E2BSandboxProvider implements SandboxProvider {
|
|
|
52
61
|
* @returns A live handle, or `null` if no sandbox has that id.
|
|
53
62
|
*/
|
|
54
63
|
get(id: string): Promise<Sandbox | null>;
|
|
64
|
+
/**
|
|
65
|
+
* Read a sandbox's record WITHOUT connecting to it.
|
|
66
|
+
*
|
|
67
|
+
* The lookup a control plane polls with. `get()` cannot serve that purpose on
|
|
68
|
+
* E2B: obtaining a handle is `POST /sandboxes/{id}/connect`, which RESUMES a
|
|
69
|
+
* paused sandbox and extends its deadline — so a status poll every few seconds
|
|
70
|
+
* silently un-hibernates every sleeping project, bills for the compute, and
|
|
71
|
+
* leaves the UI showing "asleep". This reads the record instead, so `paused`
|
|
72
|
+
* stays paused and is reported as `sleeping`.
|
|
73
|
+
*
|
|
74
|
+
* `null` means the sandbox positively does not exist. A failed lookup throws,
|
|
75
|
+
* for the same reason `get()` does.
|
|
76
|
+
*
|
|
77
|
+
* @param id - The sandbox id.
|
|
78
|
+
* @returns The descriptor, or `null` when no sandbox has that id.
|
|
79
|
+
*/
|
|
80
|
+
describe(id: string): Promise<SandboxDescriptor | null>;
|
|
55
81
|
/**
|
|
56
82
|
* List the caller's live sandboxes.
|
|
57
83
|
*
|
package/dist/provider.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"provider.d.ts","sourceRoot":"","sources":["../src/provider.ts"],"names":[],"mappings":"AAAA;;;;;;;;;GASG;AAEH,OAAO,KAAK,EAEV,aAAa,EAKb,OAAO,EACP,aAAa,EACb,eAAe,EAChB,MAAM,4BAA4B,CAAA;AAEnC,OAAO,KAAK,
|
|
1
|
+
{"version":3,"file":"provider.d.ts","sourceRoot":"","sources":["../src/provider.ts"],"names":[],"mappings":"AAAA;;;;;;;;;GASG;AAEH,OAAO,KAAK,EAEV,aAAa,EAKb,OAAO,EACP,aAAa,EACb,iBAAiB,EACjB,eAAe,EAChB,MAAM,4BAA4B,CAAA;AAEnC,OAAO,KAAK,EACV,SAAS,EACT,oBAAoB,EAGrB,MAAM,YAAY,CAAA;AAwdnB;;;;;;;;;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;;;;;;;;;;;;;;OAcG;IACG,MAAM,CAAC,MAAM,EAAE,aAAa,GAAG,OAAO,CAAC,OAAO,CAAC;IAoBrD;;;;;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;;;;;;;;;;;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"}
|
package/dist/provider.js
CHANGED
|
@@ -28,12 +28,18 @@ const EGRESS_PROBE_DENY = 'example.com';
|
|
|
28
28
|
* Imported lazily so the SDK is only required when the bond is actually used.
|
|
29
29
|
*/
|
|
30
30
|
async function defaultClient(apiKey) {
|
|
31
|
-
const { Sandbox } = await import('e2b');
|
|
31
|
+
const { Sandbox, SandboxNotFoundError } = await import('e2b');
|
|
32
32
|
const S = Sandbox;
|
|
33
33
|
return {
|
|
34
34
|
create: (templateId, opts) => S.create(templateId, { apiKey, ...opts }),
|
|
35
35
|
connect: (id, opts) => S.connect(id, { apiKey, ...opts }),
|
|
36
36
|
kill: (id, opts) => S.kill(id, { apiKey, ...opts }),
|
|
37
|
+
getInfo: (id, opts) => S.getInfo(id, { apiKey, ...opts }),
|
|
38
|
+
// The SDK raises `SandboxNotFoundError` from `getInfo`/`connect` for exactly
|
|
39
|
+
// one condition — the API answered 404 — and routes every other failure to a
|
|
40
|
+
// different class. That makes it a POSITIVE not-found, which is the whole
|
|
41
|
+
// basis for `get()` returning null.
|
|
42
|
+
isNotFound: (error) => error instanceof SandboxNotFoundError,
|
|
37
43
|
async list(opts) {
|
|
38
44
|
// Sandbox.list returns a paginator; normalize to a flat array of running
|
|
39
45
|
// sandboxes. Support the async-iterator, nextItems(), and array shapes so
|
|
@@ -41,9 +47,11 @@ async function defaultClient(apiKey) {
|
|
|
41
47
|
const result = S.list({ apiKey, ...opts });
|
|
42
48
|
const out = [];
|
|
43
49
|
const push = (items) => {
|
|
50
|
+
// Carry the listed state through: it is the only way a caller can skip a
|
|
51
|
+
// PAUSED sandbox, and building a handle for one would resume it.
|
|
44
52
|
for (const it of items)
|
|
45
53
|
if (it?.sandboxId)
|
|
46
|
-
out.push({ sandboxId: it.sandboxId });
|
|
54
|
+
out.push({ sandboxId: it.sandboxId, state: it.state });
|
|
47
55
|
};
|
|
48
56
|
const r = await Promise.resolve(result).catch(() => result);
|
|
49
57
|
if (Array.isArray(r)) {
|
|
@@ -67,6 +75,15 @@ async function defaultClient(apiKey) {
|
|
|
67
75
|
},
|
|
68
76
|
};
|
|
69
77
|
}
|
|
78
|
+
/**
|
|
79
|
+
* Single-quote a value for POSIX `sh` so an arbitrary path is one argument.
|
|
80
|
+
*
|
|
81
|
+
* @param value - The raw string.
|
|
82
|
+
* @returns The quoted string.
|
|
83
|
+
*/
|
|
84
|
+
function shellQuote(value) {
|
|
85
|
+
return `'${value.replace(/'/g, "'\\''")}'`;
|
|
86
|
+
}
|
|
70
87
|
/**
|
|
71
88
|
* Build a deny-by-default network update from an allow-list.
|
|
72
89
|
*
|
|
@@ -76,6 +93,49 @@ async function defaultClient(apiKey) {
|
|
|
76
93
|
function denyByDefault(allowOut) {
|
|
77
94
|
return { allowOut, denyOut: [ALL_TRAFFIC] };
|
|
78
95
|
}
|
|
96
|
+
/**
|
|
97
|
+
* Whether an error means the sandbox POSITIVELY does not exist.
|
|
98
|
+
*
|
|
99
|
+
* Asks the client (the real one compares against the SDK's own
|
|
100
|
+
* `SandboxNotFoundError` class), and falls back to the error's `name` so an
|
|
101
|
+
* injected/duck-typed client — or an SDK loaded twice under different module
|
|
102
|
+
* instances, where `instanceof` silently fails — is still classified correctly.
|
|
103
|
+
* Everything else is a failure to LOOK and must propagate.
|
|
104
|
+
*
|
|
105
|
+
* @param client - The client the error came from.
|
|
106
|
+
* @param error - The thrown value.
|
|
107
|
+
* @returns True only for a not-found.
|
|
108
|
+
*/
|
|
109
|
+
function isNotFound(client, error) {
|
|
110
|
+
if (client.isNotFound?.(error))
|
|
111
|
+
return true;
|
|
112
|
+
return error?.name === 'SandboxNotFoundError';
|
|
113
|
+
}
|
|
114
|
+
/**
|
|
115
|
+
* Map an E2B sandbox record onto the core's coarse lifecycle status.
|
|
116
|
+
*
|
|
117
|
+
* E2B has exactly two states. `paused` is a filesystem + memory snapshot, which
|
|
118
|
+
* is what the core calls `sleeping` — NOT `stopped`, because a resume brings the
|
|
119
|
+
* process tree back with it and callers branch on that.
|
|
120
|
+
*
|
|
121
|
+
* @param state - The SDK's `state` field.
|
|
122
|
+
* @returns The core status.
|
|
123
|
+
*/
|
|
124
|
+
function toCoreStatus(state) {
|
|
125
|
+
return state === 'paused' ? 'sleeping' : 'running';
|
|
126
|
+
}
|
|
127
|
+
/**
|
|
128
|
+
* Normalize an SDK date field (a `Date`, an ISO string, or absent) to ISO.
|
|
129
|
+
*
|
|
130
|
+
* @param value - The SDK value.
|
|
131
|
+
* @returns An ISO 8601 string, or `null`.
|
|
132
|
+
*/
|
|
133
|
+
function toIso(value) {
|
|
134
|
+
if (!value)
|
|
135
|
+
return null;
|
|
136
|
+
const date = value instanceof Date ? value : new Date(value);
|
|
137
|
+
return Number.isNaN(date.getTime()) ? null : date.toISOString();
|
|
138
|
+
}
|
|
79
139
|
/**
|
|
80
140
|
* A live E2B sandbox mapped onto the core `Sandbox` handle.
|
|
81
141
|
*
|
|
@@ -316,7 +376,7 @@ class E2BSandbox {
|
|
|
316
376
|
chunks.push(chunk);
|
|
317
377
|
const tarPath = `/tmp/mol-import-${Date.now().toString(36)}.tar`;
|
|
318
378
|
await this.sbx.files.write(tarPath, new Blob([Buffer.concat(chunks)]));
|
|
319
|
-
const r = await this.sbx.commands.run(`mkdir -p ${path} && tar xf ${tarPath} -C ${path} --no-same-owner --no-same-permissions && rm -f ${tarPath}`, { timeoutMs: 300_000 });
|
|
379
|
+
const r = await this.sbx.commands.run(`mkdir -p ${shellQuote(path)} && tar xf ${tarPath} -C ${shellQuote(path)} --no-same-owner --no-same-permissions && rm -f ${tarPath}`, { timeoutMs: 300_000 });
|
|
320
380
|
if (r.exitCode !== 0) {
|
|
321
381
|
throw new Error(`importFiles: tar extract failed (${r.exitCode}): ${r.stderr.slice(0, 300)}`);
|
|
322
382
|
}
|
|
@@ -326,14 +386,30 @@ class E2BSandbox {
|
|
|
326
386
|
*
|
|
327
387
|
* Tars the tree in-sandbox, reads it back as bytes, and yields it as a single
|
|
328
388
|
* chunk. Sufficient for archive/migrate (whole-workspace capture); not a
|
|
329
|
-
* chunked pipe
|
|
389
|
+
* chunked pipe — the whole archive is held in this process's memory once, so
|
|
390
|
+
* callers moving large trees must bound what they export.
|
|
391
|
+
*
|
|
392
|
+
* Entries are rooted at the LAST SEGMENT of `path` (`tar -C <parent>
|
|
393
|
+
* <name>`), so `exportFiles('/workspace/my-app')` yields `my-app/…` — the
|
|
394
|
+
* shape Docker's archive endpoint produces and the shape every consumer
|
|
395
|
+
* (`importFiles(<parent>)`, host-side unpackers with `strip: 1`) expects.
|
|
396
|
+
* The previous `tar -C <path> .` rooting yielded `./…`, which
|
|
397
|
+
* `importFiles('/')` extracted at the filesystem root instead of the
|
|
398
|
+
* directory it was taken from.
|
|
330
399
|
*
|
|
331
|
-
* @param path - Absolute path inside the sandbox to archive.
|
|
400
|
+
* @param path - Absolute path inside the sandbox to archive (not `/`).
|
|
332
401
|
* @returns A POSIX tar byte stream of that path's contents.
|
|
333
402
|
*/
|
|
334
403
|
async exportFiles(path) {
|
|
404
|
+
const trimmed = path.replace(/\/+$/, '');
|
|
405
|
+
const slash = trimmed.lastIndexOf('/');
|
|
406
|
+
const parent = slash <= 0 ? '/' : trimmed.slice(0, slash);
|
|
407
|
+
const name = trimmed.slice(slash + 1);
|
|
408
|
+
if (!trimmed.startsWith('/') || !name) {
|
|
409
|
+
throw new Error(`exportFiles: path must be an absolute directory below "/" (got "${path}")`);
|
|
410
|
+
}
|
|
335
411
|
const tarPath = `/tmp/mol-export-${Date.now().toString(36)}.tar`;
|
|
336
|
-
const r = await this.sbx.commands.run(`tar cf ${tarPath} -C ${
|
|
412
|
+
const r = await this.sbx.commands.run(`tar cf ${tarPath} -C ${shellQuote(parent)} ${shellQuote(name)}`, { timeoutMs: 300_000 });
|
|
337
413
|
if (r.exitCode !== 0) {
|
|
338
414
|
throw new Error(`exportFiles: tar create failed (${r.exitCode}): ${r.stderr.slice(0, 300)}`);
|
|
339
415
|
}
|
|
@@ -415,6 +491,15 @@ export class E2BSandboxProvider {
|
|
|
415
491
|
/**
|
|
416
492
|
* Create a new sandbox from the golden template and apply the egress policy.
|
|
417
493
|
*
|
|
494
|
+
* The sandbox is created to PAUSE at its timeout, not to be killed. E2B's
|
|
495
|
+
* default is `onTimeout: 'kill'`, which means a sandbox nothing has touched for
|
|
496
|
+
* its lifetime is destroyed — and on this platform the sandbox is the only copy
|
|
497
|
+
* of the project, so the default turns "the tab was closed over lunch" into
|
|
498
|
+
* permanent data loss. `keepMemory` stays on: the pause snapshot restores the
|
|
499
|
+
* process tree, which is what makes `resume()` honest when it reports
|
|
500
|
+
* `processesPreserved: true`. A filesystem-only snapshot would cold-boot
|
|
501
|
+
* instead, leaving a sandbox that is running with every dev server dead.
|
|
502
|
+
*
|
|
418
503
|
* @param config - Project id, env, optional per-boot templateId + labels.
|
|
419
504
|
* @returns A live sandbox handle.
|
|
420
505
|
*/
|
|
@@ -425,6 +510,7 @@ export class E2BSandboxProvider {
|
|
|
425
510
|
timeoutMs: this.config.defaultTimeoutMs,
|
|
426
511
|
envs: config.env ?? {},
|
|
427
512
|
metadata: { projectId: config.projectId, ...(config.labels ?? {}) },
|
|
513
|
+
lifecycle: { onTimeout: { action: 'pause', keepMemory: true } },
|
|
428
514
|
});
|
|
429
515
|
const handle = new E2BSandbox(sbx, client, {
|
|
430
516
|
previewPort: this.config.defaultPreviewPort,
|
|
@@ -451,12 +537,68 @@ export class E2BSandboxProvider {
|
|
|
451
537
|
timeoutMs: this.config.defaultTimeoutMs,
|
|
452
538
|
});
|
|
453
539
|
}
|
|
454
|
-
catch (
|
|
455
|
-
//
|
|
456
|
-
//
|
|
457
|
-
//
|
|
458
|
-
|
|
540
|
+
catch (error) {
|
|
541
|
+
// `null` means the sandbox is GONE, and nothing else. Every other failure
|
|
542
|
+
// THROWS. This used to swallow all of them, and the cost of that is not
|
|
543
|
+
// hypothetical: a control plane reads `null` as "the container is gone",
|
|
544
|
+
// detaches the project, and rebuilds it from a template — so one 5xx from
|
|
545
|
+
// this API destroyed a user's only copy of their code. "I could not look"
|
|
546
|
+
// must never be delivered as "I looked, and it is not there".
|
|
547
|
+
if (isNotFound(client, error))
|
|
548
|
+
return null;
|
|
549
|
+
throw error;
|
|
550
|
+
}
|
|
551
|
+
}
|
|
552
|
+
/**
|
|
553
|
+
* Read a sandbox's record WITHOUT connecting to it.
|
|
554
|
+
*
|
|
555
|
+
* The lookup a control plane polls with. `get()` cannot serve that purpose on
|
|
556
|
+
* E2B: obtaining a handle is `POST /sandboxes/{id}/connect`, which RESUMES a
|
|
557
|
+
* paused sandbox and extends its deadline — so a status poll every few seconds
|
|
558
|
+
* silently un-hibernates every sleeping project, bills for the compute, and
|
|
559
|
+
* leaves the UI showing "asleep". This reads the record instead, so `paused`
|
|
560
|
+
* stays paused and is reported as `sleeping`.
|
|
561
|
+
*
|
|
562
|
+
* `null` means the sandbox positively does not exist. A failed lookup throws,
|
|
563
|
+
* for the same reason `get()` does.
|
|
564
|
+
*
|
|
565
|
+
* @param id - The sandbox id.
|
|
566
|
+
* @returns The descriptor, or `null` when no sandbox has that id.
|
|
567
|
+
*/
|
|
568
|
+
async describe(id) {
|
|
569
|
+
const client = await this.client();
|
|
570
|
+
if (!client.getInfo) {
|
|
571
|
+
// Refusing is the point: answering `null` here would report "no such
|
|
572
|
+
// sandbox" for a client that simply cannot look.
|
|
573
|
+
throw new Error('E2B client does not expose getInfo(); cannot describe a sandbox');
|
|
574
|
+
}
|
|
575
|
+
let info;
|
|
576
|
+
try {
|
|
577
|
+
info = await client.getInfo(id);
|
|
459
578
|
}
|
|
579
|
+
catch (error) {
|
|
580
|
+
if (isNotFound(client, error))
|
|
581
|
+
return null;
|
|
582
|
+
throw error;
|
|
583
|
+
}
|
|
584
|
+
const startedAt = toIso(info.startedAt);
|
|
585
|
+
return {
|
|
586
|
+
id: info.sandboxId ?? id,
|
|
587
|
+
projectId: info.metadata?.projectId ?? null,
|
|
588
|
+
status: toCoreStatus(info.state),
|
|
589
|
+
labels: info.metadata ?? {},
|
|
590
|
+
// E2B has no created-but-never-started state — a sandbox exists only once
|
|
591
|
+
// it has run — so both timestamps are the same fact, and neither is ever
|
|
592
|
+
// the `null` that marks wreckage on a provider that does have one.
|
|
593
|
+
createdAt: startedAt,
|
|
594
|
+
startedAt,
|
|
595
|
+
templateRef: info.templateId ?? null,
|
|
596
|
+
volumeName: info.volumeMounts?.[0]?.name ?? null,
|
|
597
|
+
// E2B publishes every internal port at `<port>-<id>.e2b.app` rather than
|
|
598
|
+
// mapping it to a host port, so there are no mappings to report. The
|
|
599
|
+
// reachable URL comes from `getPreviewUrl(port)`.
|
|
600
|
+
ports: [],
|
|
601
|
+
};
|
|
460
602
|
}
|
|
461
603
|
/**
|
|
462
604
|
* List the caller's live sandboxes.
|
|
@@ -470,6 +612,11 @@ export class E2BSandboxProvider {
|
|
|
470
612
|
const items = Array.isArray(running) ? running : (running.sandboxes ?? []);
|
|
471
613
|
const handles = [];
|
|
472
614
|
for (const it of items) {
|
|
615
|
+
// A PAUSED sandbox is deliberately skipped: building its handle means
|
|
616
|
+
// connecting, and connecting resumes it. Enumerating an account would
|
|
617
|
+
// otherwise wake — and start billing — every hibernated project on it.
|
|
618
|
+
if (it.state === 'paused')
|
|
619
|
+
continue;
|
|
473
620
|
const h = await this.get(it.sandboxId);
|
|
474
621
|
if (h)
|
|
475
622
|
handles.push(h);
|
package/dist/types.d.ts
CHANGED
|
@@ -31,6 +31,10 @@ export interface E2BConfig {
|
|
|
31
31
|
/**
|
|
32
32
|
* Default sandbox lifetime before E2B auto-pauses it, in milliseconds. The
|
|
33
33
|
* control plane extends this per-heartbeat; this is only the initial ceiling.
|
|
34
|
+
*
|
|
35
|
+
* E2B caps this per account: 1 hour on Hobby, 24 hours on Pro. A value above
|
|
36
|
+
* the account's cap is rejected at create time, so raising it is a decision
|
|
37
|
+
* about the account, not just the config.
|
|
34
38
|
*/
|
|
35
39
|
defaultTimeoutMs?: number;
|
|
36
40
|
/**
|
|
@@ -94,17 +98,55 @@ export interface E2BSandboxLike {
|
|
|
94
98
|
denyOut?: string[];
|
|
95
99
|
}): Promise<void>;
|
|
96
100
|
}
|
|
101
|
+
/**
|
|
102
|
+
* Subset of the SDK's `SandboxInfo` the bond reads.
|
|
103
|
+
*
|
|
104
|
+
* This is what a sandbox looks like when you only LOOK at it. `connect` — which
|
|
105
|
+
* is how a handle is obtained — RESUMES a paused sandbox and extends its
|
|
106
|
+
* deadline, so it can never be used to answer "is this thing asleep?".
|
|
107
|
+
*/
|
|
108
|
+
export interface E2BSandboxInfoLike {
|
|
109
|
+
sandboxId: string;
|
|
110
|
+
templateId?: string;
|
|
111
|
+
/** `'running'` or `'paused'`; anything else is treated as running. */
|
|
112
|
+
state?: string;
|
|
113
|
+
/** Caller metadata supplied at create (the bond puts `projectId` here). */
|
|
114
|
+
metadata?: Record<string, string>;
|
|
115
|
+
/** When the sandbox last started running. */
|
|
116
|
+
startedAt?: Date | string;
|
|
117
|
+
/** When the sandbox's current deadline expires. */
|
|
118
|
+
endAt?: Date | string;
|
|
119
|
+
/** Volumes mounted into the sandbox, when the account uses them. */
|
|
120
|
+
volumeMounts?: Array<{
|
|
121
|
+
name: string;
|
|
122
|
+
path: string;
|
|
123
|
+
}>;
|
|
124
|
+
}
|
|
97
125
|
/** Subset of the SDK's `Sandbox` static surface the bond uses. */
|
|
98
126
|
export interface E2BSandboxClientLike {
|
|
99
127
|
create(templateId: string, opts?: Record<string, unknown>): Promise<E2BSandboxLike>;
|
|
100
128
|
connect(sandboxId: string, opts?: Record<string, unknown>): Promise<E2BSandboxLike>;
|
|
101
129
|
list(opts?: Record<string, unknown>): Promise<Array<{
|
|
102
130
|
sandboxId: string;
|
|
131
|
+
state?: string;
|
|
103
132
|
}> | {
|
|
104
133
|
sandboxes?: Array<{
|
|
105
134
|
sandboxId: string;
|
|
135
|
+
state?: string;
|
|
106
136
|
}>;
|
|
107
137
|
}>;
|
|
108
138
|
kill?(sandboxId: string, opts?: Record<string, unknown>): Promise<boolean>;
|
|
139
|
+
/**
|
|
140
|
+
* Read a sandbox's record WITHOUT connecting to it — the only lookup that does
|
|
141
|
+
* not resume a paused sandbox. Throws `SandboxNotFoundError` on a 404.
|
|
142
|
+
*/
|
|
143
|
+
getInfo?(sandboxId: string, opts?: Record<string, unknown>): Promise<E2BSandboxInfoLike>;
|
|
144
|
+
/**
|
|
145
|
+
* Whether an error means "this sandbox does not exist", as opposed to "the
|
|
146
|
+
* lookup failed". The distinction cannot be recovered from the error's shape by
|
|
147
|
+
* a consumer, and getting it wrong is what makes a control plane treat a
|
|
148
|
+
* provider outage as a destroyed sandbox.
|
|
149
|
+
*/
|
|
150
|
+
isNotFound?(error: unknown): boolean;
|
|
109
151
|
}
|
|
110
152
|
//# sourceMappingURL=types.d.ts.map
|
package/dist/types.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../src/types.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;GAUG;AAEH,qFAAqF;AACrF,MAAM,WAAW,SAAS;IACxB;;;OAGG;IACH,MAAM,CAAC,EAAE,MAAM,CAAA;IACf;;;;;OAKG;IACH,UAAU,CAAC,EAAE,MAAM,CAAA;IACnB;;;OAGG;IACH,kBAAkB,CAAC,EAAE,MAAM,CAAA;IAC3B
|
|
1
|
+
{"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../src/types.ts"],"names":[],"mappings":"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"}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@molecule/api-code-sandbox-e2b",
|
|
3
|
-
"version": "1.0
|
|
3
|
+
"version": "1.1.0",
|
|
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",
|
|
@@ -30,7 +30,7 @@
|
|
|
30
30
|
"license": "Apache-2.0",
|
|
31
31
|
"devDependencies": {
|
|
32
32
|
"@molecule/api-bond": "1.0.1",
|
|
33
|
-
"@molecule/api-code-sandbox": "1.
|
|
33
|
+
"@molecule/api-code-sandbox": "1.1.1",
|
|
34
34
|
"@types/node": "26.1.2",
|
|
35
35
|
"typescript": "6.0.3",
|
|
36
36
|
"vitest": "4.1.10"
|