@evolvingmachines/e2b 0.0.52-project-sable.20260726.6e95f36 → 0.0.52-project-sable.20260729.96caaab
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/index.cjs +5 -5
- package/dist/index.d.cts +101 -2
- package/dist/index.d.ts +101 -2
- package/dist/index.js +5 -5
- package/package.json +3 -2
package/dist/index.cjs
CHANGED
|
@@ -1,8 +1,8 @@
|
|
|
1
|
-
'use strict';var codeInterpreter=require('@e2b/code-interpreter');function
|
|
1
|
+
'use strict';var codeInterpreter=require('@e2b/code-interpreter');function p(s){if(!s||typeof s!="object")return false;if(s.name==="TimeoutError")return true;let e=s.message;return typeof e=="string"&&/timed?\s*out/i.test(e)}var k=new Set([".xlsx",".xls",".docx",".doc",".pptx",".ppt",".pdf",".zip",".tar",".gz",".7z",".rar",".png",".jpg",".jpeg",".gif",".webp",".ico",".bmp",".mp3",".wav",".ogg",".flac",".aac",".mp4",".avi",".mov",".mkv",".webm",".woff",".woff2",".ttf",".otf",".eot",".exe",".dll",".so",".dylib",".sqlite",".db",".pickle",".pkl",".parquet"]),P=100,v=100;function u(s){return s instanceof Date?s.toISOString():String(s)}function A(s){if(typeof s=="string"||s instanceof ArrayBuffer)return s;if(s instanceof Buffer)return new Uint8Array(s).buffer;if(s instanceof Uint8Array)return new Uint8Array(s).buffer;throw new Error(`Unsupported data type for file upload: ${typeof s}. Expected string, Buffer, ArrayBuffer, or Uint8Array.`)}function E(s){let e=s.substring(s.lastIndexOf(".")).toLowerCase();return k.has(e)}var b=class extends Error{constructor(e){super(e),this.name="E2BResourcesError";}},g=class extends Error{constructor(){super("E2B has no idle timeout: its sandbox timeout is an ABSOLUTE lifetime that in-sandbox activity never extends. Use `timeoutMs` for the lifetime, and call setTimeout() to extend a sandbox you know is still working."),this.name="E2BIdleTimeoutError";}},x=class{constructor(e,t){this.sandbox=e;this.defaultUser=t;}async run(e,t){try{let r=await this.sandbox.commands.run(e,{timeoutMs:t?.timeoutMs,envs:t?.envs,cwd:t?.cwd,user:this.defaultUser,onStdout:t?.onStdout,onStderr:t?.onStderr});return {exitCode:r.exitCode,stdout:r.stdout,stderr:r.stderr}}catch(r){if(r&&typeof r=="object"&&"exitCode"in r){let n=r;return {exitCode:n.exitCode,stdout:n.stdout??"",stderr:n.stderr??""}}if(p(r))return {exitCode:124,stdout:"",stderr:r instanceof Error?r.message:"command timed out"};throw r}}async spawn(e,t){let r=await this.sandbox.commands.run(e,{background:true,stdin:t?.stdin??true,timeoutMs:t?.timeoutMs,envs:t?.envs,cwd:t?.cwd,user:this.defaultUser,onStdout:t?.onStdout,onStderr:t?.onStderr});return {processId:String(r.pid),wait:async()=>{try{let n=await r.wait();return {exitCode:n.exitCode,stdout:n.stdout,stderr:n.stderr}}catch(n){if(n&&typeof n=="object"&&"exitCode"in n){let i=n;return {exitCode:i.exitCode,stdout:i.stdout??"",stderr:i.stderr??""}}if(p(n))return {exitCode:124,stdout:"",stderr:n instanceof Error?n.message:"command timed out"};throw n}},kill:()=>this.sandbox.commands.kill(r.pid)}}async list(){return (await this.sandbox.commands.list()).map(t=>({...t,processId:String(t.pid)}))}async connect(e,t){let r=await this.sandbox.commands.connect(Number(e),{onStdout:t?.onStdout,onStderr:t?.onStderr,timeoutMs:t?.timeoutMs});return {processId:String(r.pid),wait:async()=>{try{let n=await r.wait();return {exitCode:n.exitCode,stdout:n.stdout,stderr:n.stderr}}catch(n){if(n&&typeof n=="object"&&"exitCode"in n){let i=n;return {exitCode:i.exitCode,stdout:i.stdout??"",stderr:i.stderr??""}}if(p(n))return {exitCode:124,stdout:"",stderr:n instanceof Error?n.message:"command timed out"};throw n}},kill:()=>this.sandbox.commands.kill(r.pid)}}async sendStdin(e,t){await this.sandbox.commands.sendStdin(Number(e),t);}async kill(e){return this.sandbox.commands.kill(Number(e))}},h=class{constructor(e,t){this.sandbox=e;this.defaultUser=t;}async read(e){return E(e)?this.sandbox.files.read(e,{format:"bytes",requestTimeoutMs:3e5,user:this.defaultUser}):this.sandbox.files.read(e,{format:"text",requestTimeoutMs:3e5,user:this.defaultUser})}async write(e,t){await this.sandbox.files.write(e,A(t),{requestTimeoutMs:3e5,user:this.defaultUser});}async writeBatch(e){let t=e.map(r=>({path:r.path,data:A(r.data)}));await this.sandbox.files.write(t,{requestTimeoutMs:3e5,user:this.defaultUser});}async makeDir(e){await this.sandbox.files.makeDir(e,{user:this.defaultUser});}async uploadUrl(e,t){return this.sandbox.uploadUrl(e,{user:this.defaultUser,...t?{useSignatureExpiration:t}:{}})}async downloadUrl(e,t){return this.sandbox.downloadUrl(e,{user:this.defaultUser,...t?{useSignatureExpiration:t}:{}})}async exists(e){return this.sandbox.files.exists(e,{user:this.defaultUser})}async list(e){return (await this.sandbox.files.list(e,{user:this.defaultUser})).map(r=>({name:r.name,path:r.path,type:r.type==="dir"?"dir":"file"}))}async remove(e){await this.sandbox.files.remove(e,{user:this.defaultUser});}async rename(e,t){await this.sandbox.files.rename(e,t,{user:this.defaultUser});}async readStream(e){return this.sandbox.files.read(e,{format:"stream",user:this.defaultUser})}async writeStream(e,t){await this.sandbox.files.write(e,t,{user:this.defaultUser});}async writeFromPath(e,t){let{createReadStream:r,statSync:n}=await import('fs'),{Readable:i}=await import('stream'),{randomBytes:o}=await import('crypto'),a=n(t).size,c=`----evolve${o(16).toString("hex")}`,w=Buffer.from(`--${c}\r
|
|
2
2
|
Content-Disposition: form-data; name="file"; filename="blob"\r
|
|
3
3
|
Content-Type: application/octet-stream\r
|
|
4
4
|
\r
|
|
5
|
-
`),
|
|
6
|
-
--${
|
|
7
|
-
`);async function*
|
|
8
|
-
exports.E2BCommands=
|
|
5
|
+
`),S=Buffer.from(`\r
|
|
6
|
+
--${c}--\r
|
|
7
|
+
`);async function*U(){yield w;for await(let d of r(t))yield d;yield S;}try{let d=await this.uploadUrl(e),m=await fetch(d,{method:"POST",body:i.toWeb(i.from(U())),headers:{"Content-Type":`multipart/form-data; boundary=${c}`,"Content-Length":String(w.length+a+S.length)},duplex:"half"});if(!m.ok)throw new Error(`streamed upload to ${e} failed (HTTP ${m.status})`)}catch(d){console.warn(`[e2b] streamed upload of ${t} failed, falling back to a buffered write:`,d instanceof Error?d.message:d);let m=i.toWeb(r(t));await this.writeStream(e,m);}}async watchDir(e,t,r){let n=await this.sandbox.files.watchDir(e,t,{recursive:r?.recursive,timeoutMs:r?.timeoutMs,user:this.defaultUser,onExit:r?.onExit});return {stop:()=>n.stop()}}},l=class{constructor(e,t,r,n){this.sandbox=e;this.apiKey=t;this.apiUrl=r;this.commands=new x(e,n),this.files=new h(e,n);}commands;files;get sandboxId(){return this.sandbox.sandboxId}getHost(e){return Promise.resolve(this.sandbox.getHost(e))}async isRunning(){return this.sandbox.isRunning()}async getInfo(){let e=await this.sandbox.getInfo();return {sandboxId:e.sandboxId,image:e.templateId,name:e.name,metadata:e.metadata??{},startedAt:u(e.startedAt),endAt:e.endAt?u(e.endAt):void 0}}async kill(){try{await this.sandbox.kill();}catch{await new Promise(e=>setTimeout(e,500)),await this.sandbox.kill();}}async pause(){await this.sandbox.betaPause({apiKey:this.apiKey,apiUrl:this.apiUrl});}},y=class{providerType="e2b";name="E2B";apiKey;apiUrl;defaultTimeoutMs;templateId;sandboxUsers=new Map;constructor(e){this.apiKey=e.apiKey,this.apiUrl=e.apiUrl,this.defaultTimeoutMs=e.defaultTimeoutMs??36e5,this.templateId=e.templateId;}async create(e){if(e.idleTimeoutMs!==void 0)throw new g;if(e.resources&&(e.resources.cpu!==void 0||e.resources.memory!==void 0||e.resources.disk!==void 0))throw new b("E2B cannot size a sandbox at create time: sizing is fixed by the template (Template.build cpuCount/memoryMB; disk is plan-fixed). Build a template with the desired resources and pass it as `image` instead of `resources`.");let t=e.timeoutMs??this.defaultTimeoutMs,r=e.image??this.templateId??"evolve-all";if(e.network?.outbound==="open"&&e.network.allowedDestinations?.length)throw new Error("network.allowedDestinations is only valid when outbound is blocked");let n=e.network?.allowedDestinations??[],i=e.network?.outbound==="blocked"&&n.length>0,o=await codeInterpreter.Sandbox.create(r,{apiKey:this.apiKey,apiUrl:this.apiUrl,envs:e.envs,metadata:e.metadata,timeoutMs:t,allowInternetAccess:e.network?.outbound!=="blocked"||i,network:i?{denyOut:["0.0.0.0/0"],allowOut:n}:void 0});return e.workingDirectory&&await o.files.makeDir(e.workingDirectory,{user:e.user}),e.user&&this.sandboxUsers.set(o.sandboxId,e.user),new l(o,this.apiKey,this.apiUrl,e.user)}async connect(e,t){let r=await codeInterpreter.Sandbox.connect(e,{apiKey:this.apiKey,apiUrl:this.apiUrl,timeoutMs:t??this.defaultTimeoutMs});return new l(r,this.apiKey,this.apiUrl,this.sandboxUsers.get(e))}async list(e){let t=await this.paginate(e);if(t.error&&!t.stoppedAtLimit)throw new Error(t.error);return t.sandboxes}async listAll(e){let{stoppedAtLimit:t,...r}=await this.paginate(e);return r}async paginate(e){let t=e?.limit;return I(codeInterpreter.Sandbox.list({apiKey:this.apiKey,apiUrl:this.apiUrl,query:{state:e?.state,metadata:e?.metadata},limit:t===void 0?P:Math.min(t,P)}),t)}};async function I(s,e){let t=[],r=0,n=new Set;for(;s.hasNext;){if(r>=v)return {sandboxes:t,complete:false,pagesFetched:r,stoppedAtLimit:false,error:`sandbox list exceeded ${v} pages`};let i=s.nextToken;if(i!==void 0){if(n.has(i))return {sandboxes:t,complete:false,pagesFetched:r,stoppedAtLimit:false,error:"pagination token repeated"};n.add(i);}let o;try{o=await s.nextItems();}catch(a){return {sandboxes:t,complete:false,pagesFetched:r,stoppedAtLimit:false,error:`sandbox list failed: ${a instanceof Error?a.message:String(a)}`}}r+=1;for(let a of o){if(e!==void 0&&t.length>=e)return {sandboxes:t,complete:false,pagesFetched:r,stoppedAtLimit:true,error:`stopped at the requested limit of ${e} with more sandboxes available`};t.push({sandboxId:a.sandboxId,image:a.templateId,name:a.name,metadata:a.metadata??{},startedAt:u(a.startedAt),endAt:a.endAt?u(a.endAt):void 0});}if(e!==void 0&&t.length>=e&&s.hasNext)return {sandboxes:t,complete:false,pagesFetched:r,stoppedAtLimit:true,error:`stopped at the requested limit of ${e} with more sandboxes available`};if(e!==void 0&&t.length>=e)break}return {sandboxes:t,complete:true,pagesFetched:r,stoppedAtLimit:false}}var B=I;function M(s={}){let e=s.apiKey??process.env.E2B_API_KEY;if(!e)throw new Error("E2B API key required. Set E2B_API_KEY environment variable or pass apiKey in config. Get your key at https://e2b.dev/sign-in");return new y({...s,apiKey:e})}
|
|
8
|
+
exports.E2BCommands=x;exports.E2BFiles=h;exports.E2BIdleTimeoutError=g;exports.E2BProvider=y;exports.E2BResourcesError=b;exports.E2B_MAX_LIST_PAGES=v;exports.E2B_MAX_PAGE_SIZE=P;exports._testCollectSandboxPages=B;exports.createE2BProvider=M;
|
package/dist/index.d.cts
CHANGED
|
@@ -14,6 +14,19 @@ import { Sandbox } from '@e2b/code-interpreter';
|
|
|
14
14
|
* - Clear naming (run = blocking, spawn = background)
|
|
15
15
|
*/
|
|
16
16
|
|
|
17
|
+
/**
|
|
18
|
+
* Largest page E2B will serve. Not a taste choice — a larger `limit` is refused
|
|
19
|
+
* outright: `400 validation error: parameter "limit" in query has an error:
|
|
20
|
+
* number must be at most 100`.
|
|
21
|
+
*/
|
|
22
|
+
declare const E2B_MAX_PAGE_SIZE = 100;
|
|
23
|
+
/**
|
|
24
|
+
* Page ceiling for one enumeration — 10,000 sandboxes at the maximum page size.
|
|
25
|
+
* A walk that reaches it stops and reports itself INCOMPLETE, because the one
|
|
26
|
+
* thing a fleet enumeration may never do is return a short list that reads like
|
|
27
|
+
* a whole one.
|
|
28
|
+
*/
|
|
29
|
+
declare const E2B_MAX_LIST_PAGES = 100;
|
|
17
30
|
/**
|
|
18
31
|
* Typed error for create-time sizing requests E2B cannot enforce.
|
|
19
32
|
* E2B sandboxes inherit cpu/memory from their TEMPLATE (Template.build
|
|
@@ -24,6 +37,16 @@ import { Sandbox } from '@e2b/code-interpreter';
|
|
|
24
37
|
declare class E2BResourcesError extends Error {
|
|
25
38
|
constructor(message: string);
|
|
26
39
|
}
|
|
40
|
+
/**
|
|
41
|
+
* Typed error for an idle timeout E2B cannot enforce. E2B has exactly one
|
|
42
|
+
* clock and it is absolute: the sandbox is killed when its timeout expires,
|
|
43
|
+
* and only explicit client calls (create, connect, setTimeout) move that
|
|
44
|
+
* deadline — never what the sandbox is or is not doing. An `idleTimeoutMs`
|
|
45
|
+
* would therefore be silently ignored, so it is refused instead.
|
|
46
|
+
*/
|
|
47
|
+
declare class E2BIdleTimeoutError extends Error {
|
|
48
|
+
constructor();
|
|
49
|
+
}
|
|
27
50
|
/** Result of a completed sandbox command */
|
|
28
51
|
interface SandboxCommandResult {
|
|
29
52
|
exitCode: number;
|
|
@@ -109,6 +132,12 @@ interface SandboxCreateOptions {
|
|
|
109
132
|
envs?: Record<string, string>;
|
|
110
133
|
metadata?: Record<string, string>;
|
|
111
134
|
timeoutMs?: number;
|
|
135
|
+
/**
|
|
136
|
+
* REJECTED with E2BIdleTimeoutError. E2B's timeout is an ABSOLUTE lifetime
|
|
137
|
+
* that in-sandbox activity never extends, so there is no inactivity clock to
|
|
138
|
+
* map this onto and honouring it would be a lie.
|
|
139
|
+
*/
|
|
140
|
+
idleTimeoutMs?: number;
|
|
112
141
|
workingDirectory?: string;
|
|
113
142
|
/**
|
|
114
143
|
* Per-sandbox compute sizing (cpu cores, memory GiB, disk GiB). E2B sizes
|
|
@@ -137,6 +166,20 @@ interface SandboxListOptions {
|
|
|
137
166
|
metadata?: Record<string, string>;
|
|
138
167
|
limit?: number;
|
|
139
168
|
}
|
|
169
|
+
/**
|
|
170
|
+
* A COMPLETE (or admittedly incomplete) enumeration of the project's fleet.
|
|
171
|
+
*
|
|
172
|
+
* `complete` is the load-bearing field. Callers that need a whole fleet —
|
|
173
|
+
* orphan sweeps, lifecycle reconciliation — read a sandbox's ABSENCE from the
|
|
174
|
+
* list as evidence it is gone, so a truncated page and a small fleet must never
|
|
175
|
+
* be the same answer. `complete: false` means leave every row alone.
|
|
176
|
+
*/
|
|
177
|
+
interface SandboxListPage {
|
|
178
|
+
sandboxes: SandboxInfo[];
|
|
179
|
+
complete: boolean;
|
|
180
|
+
pagesFetched: number;
|
|
181
|
+
error?: string;
|
|
182
|
+
}
|
|
140
183
|
/** Command execution capabilities */
|
|
141
184
|
interface SandboxCommands {
|
|
142
185
|
/** Run command and wait for completion */
|
|
@@ -212,8 +255,10 @@ interface SandboxProvider {
|
|
|
212
255
|
create(options: SandboxCreateOptions): Promise<SandboxInstance>;
|
|
213
256
|
/** Connect to existing sandbox */
|
|
214
257
|
connect(sandboxId: string, timeoutMs?: number): Promise<SandboxInstance>;
|
|
215
|
-
/** List sandboxes
|
|
258
|
+
/** List sandboxes, paginating to exhaustion. `limit` bounds items returned. */
|
|
216
259
|
list(options?: SandboxListOptions): Promise<SandboxInfo[]>;
|
|
260
|
+
/** The same enumeration for fleet bookkeeping: never throws, reports completeness. */
|
|
261
|
+
listAll(options?: SandboxListOptions): Promise<SandboxListPage>;
|
|
217
262
|
}
|
|
218
263
|
interface E2BConfig {
|
|
219
264
|
/** E2B API key. Default: reads from E2B_API_KEY env var */
|
|
@@ -303,8 +348,62 @@ declare class E2BProvider implements SandboxProvider {
|
|
|
303
348
|
constructor(config: ResolvedE2BConfig);
|
|
304
349
|
create(options: SandboxCreateOptions): Promise<SandboxInstance>;
|
|
305
350
|
connect(sandboxId: string, timeoutMs?: number): Promise<SandboxInstance>;
|
|
351
|
+
/**
|
|
352
|
+
* List sandboxes, walking every page.
|
|
353
|
+
*
|
|
354
|
+
* This used to call `nextItems()` exactly once and return whatever the first
|
|
355
|
+
* page held — an account with more than E2B_MAX_PAGE_SIZE sandboxes was
|
|
356
|
+
* silently truncated, and nothing in the return value said so. That is a
|
|
357
|
+
* correctness bug rather than a performance one for any caller that reads
|
|
358
|
+
* absence from the list as "this sandbox is gone".
|
|
359
|
+
*
|
|
360
|
+
* `limit` still means what a caller expects: stop after this many ITEMS, so
|
|
361
|
+
* an explicit limit remains a cost bound. The per-request page size is capped
|
|
362
|
+
* separately at E2B_MAX_PAGE_SIZE because E2B rejects anything larger
|
|
363
|
+
* outright (`400 validation error: parameter "limit" ... must be at most
|
|
364
|
+
* 100`), so a caller asking for 500 gets five requests, not one refusal.
|
|
365
|
+
*/
|
|
306
366
|
list(options?: SandboxListOptions): Promise<SandboxInfo[]>;
|
|
367
|
+
/**
|
|
368
|
+
* The fleet-bookkeeping enumeration: same walk, never throws.
|
|
369
|
+
*
|
|
370
|
+
* The distinction from `list()` is what a failure MEANS to the caller. An
|
|
371
|
+
* orphan sweep treats a missing sandbox as a terminated one, so it must be
|
|
372
|
+
* able to tell "the project has no sandboxes" from "the enumeration stopped
|
|
373
|
+
* early" — and an exception it catches and turns into an empty array erases
|
|
374
|
+
* exactly that difference.
|
|
375
|
+
*/
|
|
376
|
+
listAll(options?: SandboxListOptions): Promise<SandboxListPage>;
|
|
377
|
+
private paginate;
|
|
378
|
+
}
|
|
379
|
+
/** The paginator surface this walk needs — E2B's SandboxPaginator satisfies it. */
|
|
380
|
+
interface E2BSandboxPaginator {
|
|
381
|
+
readonly hasNext: boolean;
|
|
382
|
+
readonly nextToken?: string;
|
|
383
|
+
nextItems(): Promise<Array<{
|
|
384
|
+
sandboxId: string;
|
|
385
|
+
templateId: string;
|
|
386
|
+
name?: string;
|
|
387
|
+
metadata?: Record<string, string>;
|
|
388
|
+
startedAt: unknown;
|
|
389
|
+
endAt?: unknown;
|
|
390
|
+
}>>;
|
|
307
391
|
}
|
|
392
|
+
/**
|
|
393
|
+
* Drain a paginator into one answer, with an honest completeness verdict.
|
|
394
|
+
*
|
|
395
|
+
* Separate from the provider because everything worth getting wrong lives here
|
|
396
|
+
* and none of it needs a network: the two ways a walk can fail to terminate,
|
|
397
|
+
* the difference between "the caller asked for ten" and "the provider ran out",
|
|
398
|
+
* and the rule that a failure mid-walk yields the sandboxes seen so far marked
|
|
399
|
+
* INCOMPLETE rather than either an exception or a short complete list.
|
|
400
|
+
*
|
|
401
|
+
* Exported for its test (`_testCollectSandboxPages`).
|
|
402
|
+
*/
|
|
403
|
+
declare function collectSandboxPages(paginator: E2BSandboxPaginator, wanted?: number): Promise<SandboxListPage & {
|
|
404
|
+
stoppedAtLimit: boolean;
|
|
405
|
+
}>;
|
|
406
|
+
declare const _testCollectSandboxPages: typeof collectSandboxPages;
|
|
308
407
|
/**
|
|
309
408
|
* Create E2B sandbox provider.
|
|
310
409
|
*
|
|
@@ -313,4 +412,4 @@ declare class E2BProvider implements SandboxProvider {
|
|
|
313
412
|
*/
|
|
314
413
|
declare function createE2BProvider(config?: E2BConfig): SandboxProvider;
|
|
315
414
|
|
|
316
|
-
export { E2BCommands, type E2BConfig, E2BFiles, E2BProvider, E2BResourcesError, type FileInfo, type FilesystemEvent, type ProcessInfo, type SandboxCommandHandle, type SandboxCommandResult, type SandboxCommands, type SandboxConnectOptions, type SandboxCreateOptions, type SandboxFiles, type SandboxInfo, type SandboxInstance, type SandboxListOptions, type SandboxProvider, type SandboxRunOptions, type SandboxSpawnOptions, type WatchHandle, type WatchOptions, createE2BProvider };
|
|
415
|
+
export { E2BCommands, type E2BConfig, E2BFiles, E2BIdleTimeoutError, E2BProvider, E2BResourcesError, type E2BSandboxPaginator, E2B_MAX_LIST_PAGES, E2B_MAX_PAGE_SIZE, type FileInfo, type FilesystemEvent, type ProcessInfo, type SandboxCommandHandle, type SandboxCommandResult, type SandboxCommands, type SandboxConnectOptions, type SandboxCreateOptions, type SandboxFiles, type SandboxInfo, type SandboxInstance, type SandboxListOptions, type SandboxListPage, type SandboxProvider, type SandboxRunOptions, type SandboxSpawnOptions, type WatchHandle, type WatchOptions, _testCollectSandboxPages, createE2BProvider };
|
package/dist/index.d.ts
CHANGED
|
@@ -14,6 +14,19 @@ import { Sandbox } from '@e2b/code-interpreter';
|
|
|
14
14
|
* - Clear naming (run = blocking, spawn = background)
|
|
15
15
|
*/
|
|
16
16
|
|
|
17
|
+
/**
|
|
18
|
+
* Largest page E2B will serve. Not a taste choice — a larger `limit` is refused
|
|
19
|
+
* outright: `400 validation error: parameter "limit" in query has an error:
|
|
20
|
+
* number must be at most 100`.
|
|
21
|
+
*/
|
|
22
|
+
declare const E2B_MAX_PAGE_SIZE = 100;
|
|
23
|
+
/**
|
|
24
|
+
* Page ceiling for one enumeration — 10,000 sandboxes at the maximum page size.
|
|
25
|
+
* A walk that reaches it stops and reports itself INCOMPLETE, because the one
|
|
26
|
+
* thing a fleet enumeration may never do is return a short list that reads like
|
|
27
|
+
* a whole one.
|
|
28
|
+
*/
|
|
29
|
+
declare const E2B_MAX_LIST_PAGES = 100;
|
|
17
30
|
/**
|
|
18
31
|
* Typed error for create-time sizing requests E2B cannot enforce.
|
|
19
32
|
* E2B sandboxes inherit cpu/memory from their TEMPLATE (Template.build
|
|
@@ -24,6 +37,16 @@ import { Sandbox } from '@e2b/code-interpreter';
|
|
|
24
37
|
declare class E2BResourcesError extends Error {
|
|
25
38
|
constructor(message: string);
|
|
26
39
|
}
|
|
40
|
+
/**
|
|
41
|
+
* Typed error for an idle timeout E2B cannot enforce. E2B has exactly one
|
|
42
|
+
* clock and it is absolute: the sandbox is killed when its timeout expires,
|
|
43
|
+
* and only explicit client calls (create, connect, setTimeout) move that
|
|
44
|
+
* deadline — never what the sandbox is or is not doing. An `idleTimeoutMs`
|
|
45
|
+
* would therefore be silently ignored, so it is refused instead.
|
|
46
|
+
*/
|
|
47
|
+
declare class E2BIdleTimeoutError extends Error {
|
|
48
|
+
constructor();
|
|
49
|
+
}
|
|
27
50
|
/** Result of a completed sandbox command */
|
|
28
51
|
interface SandboxCommandResult {
|
|
29
52
|
exitCode: number;
|
|
@@ -109,6 +132,12 @@ interface SandboxCreateOptions {
|
|
|
109
132
|
envs?: Record<string, string>;
|
|
110
133
|
metadata?: Record<string, string>;
|
|
111
134
|
timeoutMs?: number;
|
|
135
|
+
/**
|
|
136
|
+
* REJECTED with E2BIdleTimeoutError. E2B's timeout is an ABSOLUTE lifetime
|
|
137
|
+
* that in-sandbox activity never extends, so there is no inactivity clock to
|
|
138
|
+
* map this onto and honouring it would be a lie.
|
|
139
|
+
*/
|
|
140
|
+
idleTimeoutMs?: number;
|
|
112
141
|
workingDirectory?: string;
|
|
113
142
|
/**
|
|
114
143
|
* Per-sandbox compute sizing (cpu cores, memory GiB, disk GiB). E2B sizes
|
|
@@ -137,6 +166,20 @@ interface SandboxListOptions {
|
|
|
137
166
|
metadata?: Record<string, string>;
|
|
138
167
|
limit?: number;
|
|
139
168
|
}
|
|
169
|
+
/**
|
|
170
|
+
* A COMPLETE (or admittedly incomplete) enumeration of the project's fleet.
|
|
171
|
+
*
|
|
172
|
+
* `complete` is the load-bearing field. Callers that need a whole fleet —
|
|
173
|
+
* orphan sweeps, lifecycle reconciliation — read a sandbox's ABSENCE from the
|
|
174
|
+
* list as evidence it is gone, so a truncated page and a small fleet must never
|
|
175
|
+
* be the same answer. `complete: false` means leave every row alone.
|
|
176
|
+
*/
|
|
177
|
+
interface SandboxListPage {
|
|
178
|
+
sandboxes: SandboxInfo[];
|
|
179
|
+
complete: boolean;
|
|
180
|
+
pagesFetched: number;
|
|
181
|
+
error?: string;
|
|
182
|
+
}
|
|
140
183
|
/** Command execution capabilities */
|
|
141
184
|
interface SandboxCommands {
|
|
142
185
|
/** Run command and wait for completion */
|
|
@@ -212,8 +255,10 @@ interface SandboxProvider {
|
|
|
212
255
|
create(options: SandboxCreateOptions): Promise<SandboxInstance>;
|
|
213
256
|
/** Connect to existing sandbox */
|
|
214
257
|
connect(sandboxId: string, timeoutMs?: number): Promise<SandboxInstance>;
|
|
215
|
-
/** List sandboxes
|
|
258
|
+
/** List sandboxes, paginating to exhaustion. `limit` bounds items returned. */
|
|
216
259
|
list(options?: SandboxListOptions): Promise<SandboxInfo[]>;
|
|
260
|
+
/** The same enumeration for fleet bookkeeping: never throws, reports completeness. */
|
|
261
|
+
listAll(options?: SandboxListOptions): Promise<SandboxListPage>;
|
|
217
262
|
}
|
|
218
263
|
interface E2BConfig {
|
|
219
264
|
/** E2B API key. Default: reads from E2B_API_KEY env var */
|
|
@@ -303,8 +348,62 @@ declare class E2BProvider implements SandboxProvider {
|
|
|
303
348
|
constructor(config: ResolvedE2BConfig);
|
|
304
349
|
create(options: SandboxCreateOptions): Promise<SandboxInstance>;
|
|
305
350
|
connect(sandboxId: string, timeoutMs?: number): Promise<SandboxInstance>;
|
|
351
|
+
/**
|
|
352
|
+
* List sandboxes, walking every page.
|
|
353
|
+
*
|
|
354
|
+
* This used to call `nextItems()` exactly once and return whatever the first
|
|
355
|
+
* page held — an account with more than E2B_MAX_PAGE_SIZE sandboxes was
|
|
356
|
+
* silently truncated, and nothing in the return value said so. That is a
|
|
357
|
+
* correctness bug rather than a performance one for any caller that reads
|
|
358
|
+
* absence from the list as "this sandbox is gone".
|
|
359
|
+
*
|
|
360
|
+
* `limit` still means what a caller expects: stop after this many ITEMS, so
|
|
361
|
+
* an explicit limit remains a cost bound. The per-request page size is capped
|
|
362
|
+
* separately at E2B_MAX_PAGE_SIZE because E2B rejects anything larger
|
|
363
|
+
* outright (`400 validation error: parameter "limit" ... must be at most
|
|
364
|
+
* 100`), so a caller asking for 500 gets five requests, not one refusal.
|
|
365
|
+
*/
|
|
306
366
|
list(options?: SandboxListOptions): Promise<SandboxInfo[]>;
|
|
367
|
+
/**
|
|
368
|
+
* The fleet-bookkeeping enumeration: same walk, never throws.
|
|
369
|
+
*
|
|
370
|
+
* The distinction from `list()` is what a failure MEANS to the caller. An
|
|
371
|
+
* orphan sweep treats a missing sandbox as a terminated one, so it must be
|
|
372
|
+
* able to tell "the project has no sandboxes" from "the enumeration stopped
|
|
373
|
+
* early" — and an exception it catches and turns into an empty array erases
|
|
374
|
+
* exactly that difference.
|
|
375
|
+
*/
|
|
376
|
+
listAll(options?: SandboxListOptions): Promise<SandboxListPage>;
|
|
377
|
+
private paginate;
|
|
378
|
+
}
|
|
379
|
+
/** The paginator surface this walk needs — E2B's SandboxPaginator satisfies it. */
|
|
380
|
+
interface E2BSandboxPaginator {
|
|
381
|
+
readonly hasNext: boolean;
|
|
382
|
+
readonly nextToken?: string;
|
|
383
|
+
nextItems(): Promise<Array<{
|
|
384
|
+
sandboxId: string;
|
|
385
|
+
templateId: string;
|
|
386
|
+
name?: string;
|
|
387
|
+
metadata?: Record<string, string>;
|
|
388
|
+
startedAt: unknown;
|
|
389
|
+
endAt?: unknown;
|
|
390
|
+
}>>;
|
|
307
391
|
}
|
|
392
|
+
/**
|
|
393
|
+
* Drain a paginator into one answer, with an honest completeness verdict.
|
|
394
|
+
*
|
|
395
|
+
* Separate from the provider because everything worth getting wrong lives here
|
|
396
|
+
* and none of it needs a network: the two ways a walk can fail to terminate,
|
|
397
|
+
* the difference between "the caller asked for ten" and "the provider ran out",
|
|
398
|
+
* and the rule that a failure mid-walk yields the sandboxes seen so far marked
|
|
399
|
+
* INCOMPLETE rather than either an exception or a short complete list.
|
|
400
|
+
*
|
|
401
|
+
* Exported for its test (`_testCollectSandboxPages`).
|
|
402
|
+
*/
|
|
403
|
+
declare function collectSandboxPages(paginator: E2BSandboxPaginator, wanted?: number): Promise<SandboxListPage & {
|
|
404
|
+
stoppedAtLimit: boolean;
|
|
405
|
+
}>;
|
|
406
|
+
declare const _testCollectSandboxPages: typeof collectSandboxPages;
|
|
308
407
|
/**
|
|
309
408
|
* Create E2B sandbox provider.
|
|
310
409
|
*
|
|
@@ -313,4 +412,4 @@ declare class E2BProvider implements SandboxProvider {
|
|
|
313
412
|
*/
|
|
314
413
|
declare function createE2BProvider(config?: E2BConfig): SandboxProvider;
|
|
315
414
|
|
|
316
|
-
export { E2BCommands, type E2BConfig, E2BFiles, E2BProvider, E2BResourcesError, type FileInfo, type FilesystemEvent, type ProcessInfo, type SandboxCommandHandle, type SandboxCommandResult, type SandboxCommands, type SandboxConnectOptions, type SandboxCreateOptions, type SandboxFiles, type SandboxInfo, type SandboxInstance, type SandboxListOptions, type SandboxProvider, type SandboxRunOptions, type SandboxSpawnOptions, type WatchHandle, type WatchOptions, createE2BProvider };
|
|
415
|
+
export { E2BCommands, type E2BConfig, E2BFiles, E2BIdleTimeoutError, E2BProvider, E2BResourcesError, type E2BSandboxPaginator, E2B_MAX_LIST_PAGES, E2B_MAX_PAGE_SIZE, type FileInfo, type FilesystemEvent, type ProcessInfo, type SandboxCommandHandle, type SandboxCommandResult, type SandboxCommands, type SandboxConnectOptions, type SandboxCreateOptions, type SandboxFiles, type SandboxInfo, type SandboxInstance, type SandboxListOptions, type SandboxListPage, type SandboxProvider, type SandboxRunOptions, type SandboxSpawnOptions, type WatchHandle, type WatchOptions, _testCollectSandboxPages, createE2BProvider };
|
package/dist/index.js
CHANGED
|
@@ -1,8 +1,8 @@
|
|
|
1
|
-
import {Sandbox}from'@e2b/code-interpreter';function
|
|
1
|
+
import {Sandbox}from'@e2b/code-interpreter';function p(s){if(!s||typeof s!="object")return false;if(s.name==="TimeoutError")return true;let e=s.message;return typeof e=="string"&&/timed?\s*out/i.test(e)}var k=new Set([".xlsx",".xls",".docx",".doc",".pptx",".ppt",".pdf",".zip",".tar",".gz",".7z",".rar",".png",".jpg",".jpeg",".gif",".webp",".ico",".bmp",".mp3",".wav",".ogg",".flac",".aac",".mp4",".avi",".mov",".mkv",".webm",".woff",".woff2",".ttf",".otf",".eot",".exe",".dll",".so",".dylib",".sqlite",".db",".pickle",".pkl",".parquet"]),P=100,v=100;function u(s){return s instanceof Date?s.toISOString():String(s)}function A(s){if(typeof s=="string"||s instanceof ArrayBuffer)return s;if(s instanceof Buffer)return new Uint8Array(s).buffer;if(s instanceof Uint8Array)return new Uint8Array(s).buffer;throw new Error(`Unsupported data type for file upload: ${typeof s}. Expected string, Buffer, ArrayBuffer, or Uint8Array.`)}function E(s){let e=s.substring(s.lastIndexOf(".")).toLowerCase();return k.has(e)}var b=class extends Error{constructor(e){super(e),this.name="E2BResourcesError";}},g=class extends Error{constructor(){super("E2B has no idle timeout: its sandbox timeout is an ABSOLUTE lifetime that in-sandbox activity never extends. Use `timeoutMs` for the lifetime, and call setTimeout() to extend a sandbox you know is still working."),this.name="E2BIdleTimeoutError";}},x=class{constructor(e,t){this.sandbox=e;this.defaultUser=t;}async run(e,t){try{let r=await this.sandbox.commands.run(e,{timeoutMs:t?.timeoutMs,envs:t?.envs,cwd:t?.cwd,user:this.defaultUser,onStdout:t?.onStdout,onStderr:t?.onStderr});return {exitCode:r.exitCode,stdout:r.stdout,stderr:r.stderr}}catch(r){if(r&&typeof r=="object"&&"exitCode"in r){let n=r;return {exitCode:n.exitCode,stdout:n.stdout??"",stderr:n.stderr??""}}if(p(r))return {exitCode:124,stdout:"",stderr:r instanceof Error?r.message:"command timed out"};throw r}}async spawn(e,t){let r=await this.sandbox.commands.run(e,{background:true,stdin:t?.stdin??true,timeoutMs:t?.timeoutMs,envs:t?.envs,cwd:t?.cwd,user:this.defaultUser,onStdout:t?.onStdout,onStderr:t?.onStderr});return {processId:String(r.pid),wait:async()=>{try{let n=await r.wait();return {exitCode:n.exitCode,stdout:n.stdout,stderr:n.stderr}}catch(n){if(n&&typeof n=="object"&&"exitCode"in n){let i=n;return {exitCode:i.exitCode,stdout:i.stdout??"",stderr:i.stderr??""}}if(p(n))return {exitCode:124,stdout:"",stderr:n instanceof Error?n.message:"command timed out"};throw n}},kill:()=>this.sandbox.commands.kill(r.pid)}}async list(){return (await this.sandbox.commands.list()).map(t=>({...t,processId:String(t.pid)}))}async connect(e,t){let r=await this.sandbox.commands.connect(Number(e),{onStdout:t?.onStdout,onStderr:t?.onStderr,timeoutMs:t?.timeoutMs});return {processId:String(r.pid),wait:async()=>{try{let n=await r.wait();return {exitCode:n.exitCode,stdout:n.stdout,stderr:n.stderr}}catch(n){if(n&&typeof n=="object"&&"exitCode"in n){let i=n;return {exitCode:i.exitCode,stdout:i.stdout??"",stderr:i.stderr??""}}if(p(n))return {exitCode:124,stdout:"",stderr:n instanceof Error?n.message:"command timed out"};throw n}},kill:()=>this.sandbox.commands.kill(r.pid)}}async sendStdin(e,t){await this.sandbox.commands.sendStdin(Number(e),t);}async kill(e){return this.sandbox.commands.kill(Number(e))}},h=class{constructor(e,t){this.sandbox=e;this.defaultUser=t;}async read(e){return E(e)?this.sandbox.files.read(e,{format:"bytes",requestTimeoutMs:3e5,user:this.defaultUser}):this.sandbox.files.read(e,{format:"text",requestTimeoutMs:3e5,user:this.defaultUser})}async write(e,t){await this.sandbox.files.write(e,A(t),{requestTimeoutMs:3e5,user:this.defaultUser});}async writeBatch(e){let t=e.map(r=>({path:r.path,data:A(r.data)}));await this.sandbox.files.write(t,{requestTimeoutMs:3e5,user:this.defaultUser});}async makeDir(e){await this.sandbox.files.makeDir(e,{user:this.defaultUser});}async uploadUrl(e,t){return this.sandbox.uploadUrl(e,{user:this.defaultUser,...t?{useSignatureExpiration:t}:{}})}async downloadUrl(e,t){return this.sandbox.downloadUrl(e,{user:this.defaultUser,...t?{useSignatureExpiration:t}:{}})}async exists(e){return this.sandbox.files.exists(e,{user:this.defaultUser})}async list(e){return (await this.sandbox.files.list(e,{user:this.defaultUser})).map(r=>({name:r.name,path:r.path,type:r.type==="dir"?"dir":"file"}))}async remove(e){await this.sandbox.files.remove(e,{user:this.defaultUser});}async rename(e,t){await this.sandbox.files.rename(e,t,{user:this.defaultUser});}async readStream(e){return this.sandbox.files.read(e,{format:"stream",user:this.defaultUser})}async writeStream(e,t){await this.sandbox.files.write(e,t,{user:this.defaultUser});}async writeFromPath(e,t){let{createReadStream:r,statSync:n}=await import('fs'),{Readable:i}=await import('stream'),{randomBytes:o}=await import('crypto'),a=n(t).size,c=`----evolve${o(16).toString("hex")}`,w=Buffer.from(`--${c}\r
|
|
2
2
|
Content-Disposition: form-data; name="file"; filename="blob"\r
|
|
3
3
|
Content-Type: application/octet-stream\r
|
|
4
4
|
\r
|
|
5
|
-
`),
|
|
6
|
-
--${
|
|
7
|
-
`);async function*
|
|
8
|
-
export{
|
|
5
|
+
`),S=Buffer.from(`\r
|
|
6
|
+
--${c}--\r
|
|
7
|
+
`);async function*U(){yield w;for await(let d of r(t))yield d;yield S;}try{let d=await this.uploadUrl(e),m=await fetch(d,{method:"POST",body:i.toWeb(i.from(U())),headers:{"Content-Type":`multipart/form-data; boundary=${c}`,"Content-Length":String(w.length+a+S.length)},duplex:"half"});if(!m.ok)throw new Error(`streamed upload to ${e} failed (HTTP ${m.status})`)}catch(d){console.warn(`[e2b] streamed upload of ${t} failed, falling back to a buffered write:`,d instanceof Error?d.message:d);let m=i.toWeb(r(t));await this.writeStream(e,m);}}async watchDir(e,t,r){let n=await this.sandbox.files.watchDir(e,t,{recursive:r?.recursive,timeoutMs:r?.timeoutMs,user:this.defaultUser,onExit:r?.onExit});return {stop:()=>n.stop()}}},l=class{constructor(e,t,r,n){this.sandbox=e;this.apiKey=t;this.apiUrl=r;this.commands=new x(e,n),this.files=new h(e,n);}commands;files;get sandboxId(){return this.sandbox.sandboxId}getHost(e){return Promise.resolve(this.sandbox.getHost(e))}async isRunning(){return this.sandbox.isRunning()}async getInfo(){let e=await this.sandbox.getInfo();return {sandboxId:e.sandboxId,image:e.templateId,name:e.name,metadata:e.metadata??{},startedAt:u(e.startedAt),endAt:e.endAt?u(e.endAt):void 0}}async kill(){try{await this.sandbox.kill();}catch{await new Promise(e=>setTimeout(e,500)),await this.sandbox.kill();}}async pause(){await this.sandbox.betaPause({apiKey:this.apiKey,apiUrl:this.apiUrl});}},y=class{providerType="e2b";name="E2B";apiKey;apiUrl;defaultTimeoutMs;templateId;sandboxUsers=new Map;constructor(e){this.apiKey=e.apiKey,this.apiUrl=e.apiUrl,this.defaultTimeoutMs=e.defaultTimeoutMs??36e5,this.templateId=e.templateId;}async create(e){if(e.idleTimeoutMs!==void 0)throw new g;if(e.resources&&(e.resources.cpu!==void 0||e.resources.memory!==void 0||e.resources.disk!==void 0))throw new b("E2B cannot size a sandbox at create time: sizing is fixed by the template (Template.build cpuCount/memoryMB; disk is plan-fixed). Build a template with the desired resources and pass it as `image` instead of `resources`.");let t=e.timeoutMs??this.defaultTimeoutMs,r=e.image??this.templateId??"evolve-all";if(e.network?.outbound==="open"&&e.network.allowedDestinations?.length)throw new Error("network.allowedDestinations is only valid when outbound is blocked");let n=e.network?.allowedDestinations??[],i=e.network?.outbound==="blocked"&&n.length>0,o=await Sandbox.create(r,{apiKey:this.apiKey,apiUrl:this.apiUrl,envs:e.envs,metadata:e.metadata,timeoutMs:t,allowInternetAccess:e.network?.outbound!=="blocked"||i,network:i?{denyOut:["0.0.0.0/0"],allowOut:n}:void 0});return e.workingDirectory&&await o.files.makeDir(e.workingDirectory,{user:e.user}),e.user&&this.sandboxUsers.set(o.sandboxId,e.user),new l(o,this.apiKey,this.apiUrl,e.user)}async connect(e,t){let r=await Sandbox.connect(e,{apiKey:this.apiKey,apiUrl:this.apiUrl,timeoutMs:t??this.defaultTimeoutMs});return new l(r,this.apiKey,this.apiUrl,this.sandboxUsers.get(e))}async list(e){let t=await this.paginate(e);if(t.error&&!t.stoppedAtLimit)throw new Error(t.error);return t.sandboxes}async listAll(e){let{stoppedAtLimit:t,...r}=await this.paginate(e);return r}async paginate(e){let t=e?.limit;return I(Sandbox.list({apiKey:this.apiKey,apiUrl:this.apiUrl,query:{state:e?.state,metadata:e?.metadata},limit:t===void 0?P:Math.min(t,P)}),t)}};async function I(s,e){let t=[],r=0,n=new Set;for(;s.hasNext;){if(r>=v)return {sandboxes:t,complete:false,pagesFetched:r,stoppedAtLimit:false,error:`sandbox list exceeded ${v} pages`};let i=s.nextToken;if(i!==void 0){if(n.has(i))return {sandboxes:t,complete:false,pagesFetched:r,stoppedAtLimit:false,error:"pagination token repeated"};n.add(i);}let o;try{o=await s.nextItems();}catch(a){return {sandboxes:t,complete:false,pagesFetched:r,stoppedAtLimit:false,error:`sandbox list failed: ${a instanceof Error?a.message:String(a)}`}}r+=1;for(let a of o){if(e!==void 0&&t.length>=e)return {sandboxes:t,complete:false,pagesFetched:r,stoppedAtLimit:true,error:`stopped at the requested limit of ${e} with more sandboxes available`};t.push({sandboxId:a.sandboxId,image:a.templateId,name:a.name,metadata:a.metadata??{},startedAt:u(a.startedAt),endAt:a.endAt?u(a.endAt):void 0});}if(e!==void 0&&t.length>=e&&s.hasNext)return {sandboxes:t,complete:false,pagesFetched:r,stoppedAtLimit:true,error:`stopped at the requested limit of ${e} with more sandboxes available`};if(e!==void 0&&t.length>=e)break}return {sandboxes:t,complete:true,pagesFetched:r,stoppedAtLimit:false}}var B=I;function M(s={}){let e=s.apiKey??process.env.E2B_API_KEY;if(!e)throw new Error("E2B API key required. Set E2B_API_KEY environment variable or pass apiKey in config. Get your key at https://e2b.dev/sign-in");return new y({...s,apiKey:e})}
|
|
8
|
+
export{x as E2BCommands,h as E2BFiles,g as E2BIdleTimeoutError,y as E2BProvider,b as E2BResourcesError,v as E2B_MAX_LIST_PAGES,P as E2B_MAX_PAGE_SIZE,B as _testCollectSandboxPages,M as createE2BProvider};
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@evolvingmachines/e2b",
|
|
3
|
-
"version": "0.0.52-project-sable.
|
|
3
|
+
"version": "0.0.52-project-sable.20260729.96caaab",
|
|
4
4
|
"keywords": [
|
|
5
5
|
"ai",
|
|
6
6
|
"agents",
|
|
@@ -32,7 +32,8 @@
|
|
|
32
32
|
"scripts": {
|
|
33
33
|
"build": "tsup --minify",
|
|
34
34
|
"dev": "tsup --watch",
|
|
35
|
-
"type-check": "tsc --noEmit"
|
|
35
|
+
"type-check": "tsc --noEmit",
|
|
36
|
+
"test:unit": "tsx tests/unit/e2b-list-pagination.test.ts"
|
|
36
37
|
},
|
|
37
38
|
"dependencies": {
|
|
38
39
|
"@e2b/code-interpreter": "^2.0.1"
|