@evolvingmachines/e2b 0.0.60 → 0.0.61

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 CHANGED
@@ -1,8 +1,8 @@
1
- 'use strict';var codeInterpreter=require('@e2b/code-interpreter');function b(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=100,I=100;function u(s){return s instanceof Date?s.toISOString():String(s)}function U(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.`)}var l=class extends Error{constructor(e){super(e),this.name="E2BResourcesError";}},B="2.25.0",g=class extends Error{constructor(e){super(e),this.name="E2BNetworkUpdateUnsupportedError";}};function x(s){if(s?.outbound==="open"&&s.allowedDestinations?.length)throw new Error("network.allowedDestinations is only valid when outbound is blocked");let e=s?.allowedDestinations??[],t=s?.outbound==="blocked"&&e.length>0;return {allowInternetAccess:s?.outbound!=="blocked"||t,network:t?{denyOut:["0.0.0.0/0"],allowOut:e}:void 0}}var h=class extends Error{constructor(){super("E2B takes no create-time boot command: the sandbox boots its template's own init, and a start command is a template-BUILD field (Template startCmd) this provider never sets. The boot is already inert \u2014 run the process by exec after create, or bake it into the template the `image` names."),this.name="E2BBootCommandError";}},y=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";}},w=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(b(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(b(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(b(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))}},S=class{constructor(e,t){this.sandbox=e;this.defaultUser=t;}async read(e){let t=await this.sandbox.files.read(e,{format:"bytes",requestTimeoutMs:3e5,user:this.defaultUser});if(!t.includes(0))try{return new TextDecoder("utf-8",{fatal:!0,ignoreBOM:!0}).decode(t)}catch{}return t}async write(e,t){await this.sandbox.files.write(e,U(t),{requestTimeoutMs:3e5,user:this.defaultUser});}async writeBatch(e){let t=e.map(r=>({path:r.path,data:U(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:d}=await import('crypto'),a=n(t).size,p=`----evolve${d(16).toString("hex")}`,v=Buffer.from(`--${p}\r
1
+ 'use strict';var codeInterpreter=require('@e2b/code-interpreter'),compareVersions=require('compare-versions');require('fs');var x=class extends Error{feature;provider;reason;constructor(e,t,n){super(`${t} does not support ${e}${n?`: ${n}`:""}`),this.name="SandboxFeatureUnsupportedError",this.feature=e,this.provider=t,this.reason=n;}},m=class extends Error{path;provider;constructor(e,t){super(`${t}: no such file or directory: ${e}`),this.name="SandboxPathNotFoundError",this.path=e,this.provider=t;}},g=class extends Error{sandboxId;provider;state;constructor(e,t,n){super(`${t} sandbox ${e} is not running (${n}); inspect never starts or resumes a sandbox`),this.name="SandboxNotRunningError",this.sandboxId=e,this.provider=t,this.state=n;}};function P(r,e){return !!r&&typeof r=="object"&&r.name===e}function q(r){return P(r,"SandboxFeatureUnsupportedError")}function W(r){return P(r,"SandboxPathNotFoundError")}function j(r){return P(r,"SandboxNotRunningError")}function E(r){if(!Number.isInteger(r.offset)||r.offset<0)throw new RangeError(`offset must be a non-negative integer, got ${r.offset}`);if(!Number.isInteger(r.length)||r.length<0)throw new RangeError(`length must be a non-negative integer, got ${r.length}`)}function z(r){return r.padStart(4,"0")}var X=/^(-|[dalTLDpSugct?]+)([-r][-w][-x]){3}$/;function N(r){if(!X.test(r))throw new RangeError(`not a Go file mode string: ${r}`);let e=r.slice(0,-9),t=r.slice(-9),n=e.includes("d")?"dir":e.includes("L")?"symlink":/[DpSc?]/.test(e)?"other":"file",s=(e.includes("u")?2048:0)|(e.includes("g")?1024:0)|(e.includes("t")?512:0);for(let o=0;o<9;o++)t[o]!=="-"&&(s|=1<<8-o);return {type:n,mode:z(s.toString(8))}}function v(r){let e=r instanceof Date?r:typeof r=="number"?new Date(r*1e3):new Date(r);if(Number.isNaN(e.getTime()))throw new RangeError(`not a timestamp: ${String(r)}`);return e.toISOString()}function D(r,e){return r.endsWith("/")?`${r}${e}`:`${r}/${e}`}async function $(r,e,t){if(E(e),e.length===0)return new Uint8Array(0);let n=e.offset+e.length-1,s=await fetch(r,{headers:{Range:`bytes=${e.offset}-${n}`},signal:AbortSignal.timeout(t.timeoutMs)});if(s.status===206){let o=new Uint8Array(await s.arrayBuffer());return o.length>e.length?o.subarray(0,e.length):o}if(s.status===200)return Y(s,e);if(s.status===416)return await s.body?.cancel().catch(()=>{}),new Uint8Array(0);throw await s.body?.cancel().catch(()=>{}),s.status===404?new m(t.path,t.provider):new Error(`${t.provider}: range read of ${t.path} failed (HTTP ${s.status})`)}async function Y(r,e){if(!r.body)return new Uint8Array(0);let t=r.body.getReader(),n=[],s=0,o=0,a=e.offset+e.length;try{for(;;){let{done:c,value:p}=await t.read();if(c)break;let h=s;if(s+=p.length,s>e.offset){let d=Math.max(0,e.offset-h),u=Math.min(p.length,a-h);u>d&&(n.push(p.subarray(d,u)),o+=u-d);}if(s>=a)break}}finally{await t.cancel().catch(()=>{});}let i=new Uint8Array(o),l=0;for(let c of n)i.set(c,l),l+=c.length;return i}var b=3e5,_="0.2.5",ee=new Date(0);function I(r){if(!r||typeof r!="object")return false;if(r.name==="TimeoutError")return true;let e=r.message;return typeof e=="string"&&/timed?\s*out/i.test(e)}var L=100,K=100;function w(r){return r instanceof Date?r.toISOString():String(r)}function G(r){if(typeof r=="string"||r instanceof ArrayBuffer)return r;if(r instanceof Buffer)return new Uint8Array(r).buffer;if(r instanceof Uint8Array)return new Uint8Array(r).buffer;throw new Error(`Unsupported data type for file upload: ${typeof r}. Expected string, Buffer, ArrayBuffer, or Uint8Array.`)}var S=class extends Error{constructor(e){super(e),this.name="E2BResourcesError";}},te="2.25.0",A=class extends Error{constructor(e){super(e),this.name="E2BNetworkUpdateUnsupportedError";}};function T(r){if(r?.outbound==="open"&&r.allowedDestinations?.length)throw new Error("network.allowedDestinations is only valid when outbound is blocked");let e=r?.allowedDestinations??[],t=r?.outbound==="blocked"&&e.length>0;return {allowInternetAccess:r?.outbound!=="blocked"||t,network:t?{denyOut:["0.0.0.0/0"],allowOut:e}:void 0}}var B=class extends Error{constructor(){super("E2B takes no create-time boot command: the sandbox boots its template's own init, and a start command is a template-BUILD field (Template startCmd) this provider never sets. The boot is already inert \u2014 run the process by exec after create, or bake it into the template the `image` names."),this.name="E2BBootCommandError";}},M=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";}},R=class{constructor(e,t){this.sandbox=e;this.defaultUser=t;}async run(e,t){try{let n=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:n.exitCode,stdout:n.stdout,stderr:n.stderr}}catch(n){if(n&&typeof n=="object"&&"exitCode"in n){let s=n;return {exitCode:s.exitCode,stdout:s.stdout??"",stderr:s.stderr??""}}if(I(n))return {exitCode:124,stdout:"",stderr:n instanceof Error?n.message:"command timed out"};throw n}}async spawn(e,t){let n=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(n.pid),wait:async()=>{try{let s=await n.wait();return {exitCode:s.exitCode,stdout:s.stdout,stderr:s.stderr}}catch(s){if(s&&typeof s=="object"&&"exitCode"in s){let o=s;return {exitCode:o.exitCode,stdout:o.stdout??"",stderr:o.stderr??""}}if(I(s))return {exitCode:124,stdout:"",stderr:s instanceof Error?s.message:"command timed out"};throw s}},kill:()=>this.sandbox.commands.kill(n.pid)}}async list(){return (await this.sandbox.commands.list()).map(t=>({...t,processId:String(t.pid)}))}async connect(e,t){let n=await this.sandbox.commands.connect(Number(e),{onStdout:t?.onStdout,onStderr:t?.onStderr,timeoutMs:t?.timeoutMs});return {processId:String(n.pid),wait:async()=>{try{let s=await n.wait();return {exitCode:s.exitCode,stdout:s.stdout,stderr:s.stderr}}catch(s){if(s&&typeof s=="object"&&"exitCode"in s){let o=s;return {exitCode:o.exitCode,stdout:o.stdout??"",stderr:o.stderr??""}}if(I(s))return {exitCode:124,stdout:"",stderr:s instanceof Error?s.message:"command timed out"};throw s}},kill:()=>this.sandbox.commands.kill(n.pid)}}async sendStdin(e,t){await this.sandbox.commands.sendStdin(Number(e),t);}async kill(e){return this.sandbox.commands.kill(Number(e))}},C=class{constructor(e,t,n){this.sandbox=e;this.defaultUser=t;this.envdVersion=n;}async assertEntryInfo(e){if(this.envdVersion??=(await this.sandbox.getInfo()).envdVersion,compareVersions.compareVersions(this.envdVersion,_)<0)throw new x(e,"e2b",`the sandbox runs envd ${this.envdVersion}; entry permissions, owner, group and mtime need envd ${_} or later (rebuild the template)`)}async read(e){let t=await this.sandbox.files.read(e,{format:"bytes",requestTimeoutMs:b,user:this.defaultUser});if(!t.includes(0))try{return new TextDecoder("utf-8",{fatal:!0,ignoreBOM:!0}).decode(t)}catch{}return t}async write(e,t){await this.sandbox.files.write(e,G(t),{requestTimeoutMs:b,user:this.defaultUser});}async writeBatch(e){let t=e.map(n=>({path:n.path,data:G(n.data)}));await this.sandbox.files.write(t,{requestTimeoutMs:b,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){await this.assertEntryInfo("files.list");try{return (await this.sandbox.files.list(e,{user:this.defaultUser})).map(n=>H(n))}catch(t){throw U(t)?new m(e,"e2b"):t}}async stat(e){await this.assertEntryInfo("files.stat");try{return H(await this.sandbox.files.getInfo(e,{user:this.defaultUser}))}catch(t){throw U(t)?new m(e,"e2b"):t}}async readRange(e,t){if(E(t),t.length===0)return new Uint8Array(0);let n=await this.sandbox.downloadUrl(e,{user:this.defaultUser,useSignatureExpiration:Math.ceil(b/1e3)});return $(n,t,{provider:"e2b",path:e,timeoutMs:b})}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:n,statSync:s}=await import('fs'),{Readable:o}=await import('stream'),{randomBytes:a}=await import('crypto'),i=s(t).size,l=`----evolve${a(16).toString("hex")}`,c=Buffer.from(`--${l}\r
2
2
  Content-Disposition: form-data; name="file"; filename="blob"\r
3
3
  Content-Type: application/octet-stream\r
4
4
  \r
5
- `),A=Buffer.from(`\r
6
- --${p}--\r
7
- `);async function*C(){yield v;for await(let o of r(t))yield o;yield A;}try{let o=await this.uploadUrl(e),m=await fetch(o,{method:"POST",body:i.toWeb(i.from(C())),headers:{"Content-Type":`multipart/form-data; boundary=${p}`,"Content-Length":String(v.length+a+A.length)},duplex:"half"});if(!m.ok)throw new Error(`streamed upload to ${e} failed (HTTP ${m.status})`)}catch(o){console.warn(`[e2b] streamed upload of ${t} failed, falling back to a buffered write:`,o instanceof Error?o.message:o);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()}}},c=class{constructor(e,t,r,n){this.sandbox=e;this.apiKey=t;this.apiUrl=r;this.commands=new w(e,n),this.files=new S(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 updateNetwork(e){let t=x(e),r=this.sandbox;if(typeof r.updateNetwork!="function")throw new g(`The installed e2b client cannot change a running sandbox's network policy: Sandbox.updateNetwork requires e2b >= ${B}. Upgrade the e2b dependency (it is pulled in by @e2b/code-interpreter), or create the sandbox with the policy it needs for its whole lifetime.`);await r.updateNetwork({allowInternetAccess:t.allowInternetAccess,...t.network??{}});}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});}},P=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.bootCommand!==void 0)throw new h;if(e.idleTimeoutMs!==void 0)throw new y;if(e.resources?.gpu!==void 0||e.resources?.gpuTypes!==void 0)throw new l("E2B offers no GPU allocation at any tier \u2014 a `resources.gpu` request cannot be enforced. Run GPU workloads on a provider that reserves GPUs (modal).");if(e.resources&&(e.resources.cpu!==void 0||e.resources.memory!==void 0||e.resources.disk!==void 0))throw new l("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";for(let d of e.phaseNetworkPolicies??[])x(d);let n=x(e.network),i=await codeInterpreter.Sandbox.create(r,{apiKey:this.apiKey,apiUrl:this.apiUrl,envs:e.envs,metadata:e.metadata,timeoutMs:t,...n});return e.workingDirectory&&await i.files.makeDir(e.workingDirectory,{user:e.user}),e.user&&this.sandboxUsers.set(i.sandboxId,e.user),new c(i,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 c(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 E(codeInterpreter.Sandbox.list({apiKey:this.apiKey,apiUrl:this.apiUrl,query:{state:e?.state,metadata:e?.metadata},limit:t===void 0?k:Math.min(t,k)}),t)}};async function E(s,e){let t=[],r=0,n=new Set;for(;s.hasNext;){if(r>=I)return {sandboxes:t,complete:false,pagesFetched:r,stoppedAtLimit:false,error:`sandbox list exceeded ${I} 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 d;try{d=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 d){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 T=E;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 P({...s,apiKey:e})}
8
- exports.E2BBootCommandError=h;exports.E2BCommands=w;exports.E2BFiles=S;exports.E2BIdleTimeoutError=y;exports.E2BNetworkUpdateUnsupportedError=g;exports.E2BProvider=P;exports.E2BResourcesError=l;exports.E2B_MAX_LIST_PAGES=I;exports.E2B_MAX_PAGE_SIZE=k;exports.E2B_MIN_UPDATE_NETWORK_VERSION=B;exports._testCollectSandboxPages=T;exports.createE2BProvider=M;
5
+ `),p=Buffer.from(`\r
6
+ --${l}--\r
7
+ `);async function*h(){yield c;for await(let d of n(t))yield d;yield p;}try{let d=await this.uploadUrl(e),u=await fetch(d,{method:"POST",body:o.toWeb(o.from(h())),headers:{"Content-Type":`multipart/form-data; boundary=${l}`,"Content-Length":String(c.length+i+p.length)},duplex:"half"});if(!u.ok)throw new Error(`streamed upload to ${e} failed (HTTP ${u.status})`)}catch(d){console.warn(`[e2b] streamed upload of ${t} failed, falling back to a buffered write:`,d instanceof Error?d.message:d);let u=o.toWeb(n(t));await this.writeStream(e,u);}}async watchDir(e,t,n){let s;try{s=await this.sandbox.files.watchDir(e,o=>{let a=o.type==="chmod"?"write":o.type;return t({path:D(e,o.name),type:a})},{recursive:n?.recursive??!1,timeoutMs:0,user:this.defaultUser});}catch(o){throw U(o)?new m(e,"e2b"):o}return {stop:()=>s.stop()}}};function U(r){let e=r&&typeof r=="object"?r.name:void 0;return e==="FileNotFoundError"||e==="NotFoundError"}function H(r){let{type:e,mode:t}=N(r.permissions),n={name:r.name,path:r.path,type:e,size:r.size,mtime:v(r.modifiedTime??ee),mode:t,owner:r.owner,group:r.group};return e==="symlink"&&r.symlinkTarget!==void 0&&r.symlinkTarget!==r.path&&(n.target=r.symlinkTarget),n}var f=class{constructor(e,t,n,s,o){this.sandbox=e;this.apiKey=t;this.apiUrl=n;this.commands=new R(e,s),this.files=new C(e,s,o);}commands;files;lastMetricsAt;get sandboxId(){return this.sandbox.sandboxId}async metrics(){let e=await this.sandbox.getMetrics(this.lastMetricsAt?{start:this.lastMetricsAt}:{}),t;for(let n of e)(!t||n.timestamp.getTime()>t.timestamp.getTime())&&(t=n);return t?(this.lastMetricsAt=t.timestamp,{cpuPct:t.cpuUsedPct,memUsedMb:t.memUsed/k,memTotalMb:t.memTotal/k,diskUsedMb:t.diskUsed/k,sampledAt:v(t.timestamp),source:"e2b:getMetrics"}):null}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:w(e.startedAt),endAt:e.endAt?w(e.endAt):void 0}}async updateNetwork(e){let t=T(e),n=this.sandbox;if(typeof n.updateNetwork!="function")throw new A(`The installed e2b client cannot change a running sandbox's network policy: Sandbox.updateNetwork requires e2b >= ${te}. Upgrade the e2b dependency (it is pulled in by @e2b/code-interpreter), or create the sandbox with the policy it needs for its whole lifetime.`);await n.updateNetwork({allowInternetAccess:t.allowInternetAccess,...t.network??{}});}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});}},O=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.bootCommand!==void 0)throw new B;if(e.idleTimeoutMs!==void 0)throw new M;if(e.resources?.gpu!==void 0||e.resources?.gpuTypes!==void 0)throw new S("E2B offers no GPU allocation at any tier \u2014 a `resources.gpu` request cannot be enforced. Run GPU workloads on a provider that reserves GPUs (modal).");if(e.resources&&(e.resources.cpu!==void 0||e.resources.memory!==void 0||e.resources.disk!==void 0))throw new S("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,n=e.image??this.templateId??"evolve-all";for(let a of e.phaseNetworkPolicies??[])T(a);let s=T(e.network),o=await codeInterpreter.Sandbox.create(n,{apiKey:this.apiKey,apiUrl:this.apiUrl,envs:e.envs,metadata:e.metadata,timeoutMs:t,...s});return e.workingDirectory&&await o.files.makeDir(e.workingDirectory,{user:e.user}),e.user&&this.sandboxUsers.set(o.sandboxId,e.user),new f(o,this.apiKey,this.apiUrl,e.user)}async connect(e,t){let n=await codeInterpreter.Sandbox.connect(e,{apiKey:this.apiKey,apiUrl:this.apiUrl,timeoutMs:t??this.defaultTimeoutMs});return new f(n,this.apiKey,this.apiUrl,this.sandboxUsers.get(e))}async inspect(e,t){let n=await this.fetchSandboxDetail(e);if(n.state!=="running")throw new g(e,"e2b",n.state);let s=F.attach({sandboxId:n.sandboxID,sandboxDomain:n.domain??void 0,envdVersion:n.envdVersion,envdAccessToken:n.envdAccessToken,trafficAccessToken:n.trafficAccessToken??void 0,apiKey:this.apiKey,apiUrl:this.apiUrl});return new f(s,this.apiKey,this.apiUrl,t?.user??this.sandboxUsers.get(e),n.envdVersion)}async fetchSandboxDetail(e){let t=new codeInterpreter.ConnectionConfig({apiKey:this.apiKey,apiUrl:this.apiUrl}),n=await new codeInterpreter.ApiClient(t).api.GET("/sandboxes/{sandboxID}",{params:{path:{sandboxID:e}}});if(n.error?.code===404||!n.data&&!n.error)throw new g(e,"e2b","not found");if(n.error)throw new Error(`E2B refused the sandbox record for ${e}: ${n.error.message??n.error.code}`);return n.data}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,...n}=await this.paginate(e);return n}async paginate(e){let t=e?.limit;return V(codeInterpreter.Sandbox.list({apiKey:this.apiKey,apiUrl:this.apiUrl,query:{state:e?.state,metadata:e?.metadata},limit:t===void 0?L:Math.min(t,L)}),t)}};async function V(r,e){let t=[],n=0,s=new Set;for(;r.hasNext;){if(n>=K)return {sandboxes:t,complete:false,pagesFetched:n,stoppedAtLimit:false,error:`sandbox list exceeded ${K} pages`};let o=r.nextToken;if(o!==void 0){if(s.has(o))return {sandboxes:t,complete:false,pagesFetched:n,stoppedAtLimit:false,error:"pagination token repeated"};s.add(o);}let a;try{a=await r.nextItems();}catch(i){return {sandboxes:t,complete:false,pagesFetched:n,stoppedAtLimit:false,error:`sandbox list failed: ${i instanceof Error?i.message:String(i)}`}}n+=1;for(let i of a){if(e!==void 0&&t.length>=e)return {sandboxes:t,complete:false,pagesFetched:n,stoppedAtLimit:true,error:`stopped at the requested limit of ${e} with more sandboxes available`};t.push({sandboxId:i.sandboxId,image:i.templateId,name:i.name,metadata:i.metadata??{},startedAt:w(i.startedAt),endAt:i.endAt?w(i.endAt):void 0});}if(e!==void 0&&t.length>=e&&r.hasNext)return {sandboxes:t,complete:false,pagesFetched:n,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:n,stoppedAtLimit:false}}var ce=V,k=1024*1024,F=class r extends codeInterpreter.Sandbox{static attach(e){return new r(e)}};function le(r={}){let e=r.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 O({...r,apiKey:e})}var pe=f;
8
+ exports.E2BBootCommandError=B;exports.E2BCommands=R;exports.E2BFiles=C;exports.E2BIdleTimeoutError=M;exports.E2BNetworkUpdateUnsupportedError=A;exports.E2BProvider=O;exports.E2BResourcesError=S;exports.E2B_MAX_LIST_PAGES=K;exports.E2B_MAX_PAGE_SIZE=L;exports.E2B_MIN_UPDATE_NETWORK_VERSION=te;exports.SandboxFeatureUnsupportedError=x;exports.SandboxNotRunningError=g;exports.SandboxPathNotFoundError=m;exports._testCollectSandboxPages=ce;exports._testE2BSandboxImplCtor=pe;exports.createE2BProvider=le;exports.isSandboxFeatureUnsupportedError=q;exports.isSandboxNotRunningError=j;exports.isSandboxPathNotFoundError=W;
package/dist/index.d.cts CHANGED
@@ -1,9 +1,37 @@
1
1
  import { Sandbox } from '@e2b/code-interpreter';
2
2
 
3
+ /** A capability this provider lacks: `feature` in dotted form (`files.watchDir`), `provider` type, optional `reason`. */
4
+ declare class SandboxFeatureUnsupportedError extends Error {
5
+ readonly feature: string;
6
+ readonly provider: string;
7
+ readonly reason?: string;
8
+ constructor(feature: string, provider: string, reason?: string);
9
+ }
10
+ /** A path the sandbox does not have — never an empty success. */
11
+ declare class SandboxPathNotFoundError extends Error {
12
+ readonly path: string;
13
+ readonly provider: string;
14
+ constructor(path: string, provider: string);
15
+ }
16
+ /** An inspect refused because the sandbox is not running; `state` is the provider's own word (`paused`, `exited with code 137`). */
17
+ declare class SandboxNotRunningError extends Error {
18
+ readonly sandboxId: string;
19
+ readonly provider: string;
20
+ readonly state: string;
21
+ constructor(sandboxId: string, provider: string, state: string);
22
+ }
23
+ /** True for a SandboxFeatureUnsupportedError from ANY package's copy. */
24
+ declare function isSandboxFeatureUnsupportedError(err: unknown): err is SandboxFeatureUnsupportedError;
25
+ /** True for a SandboxPathNotFoundError from ANY package's copy. */
26
+ declare function isSandboxPathNotFoundError(err: unknown): err is SandboxPathNotFoundError;
27
+ /** True for a SandboxNotRunningError from ANY package's copy. */
28
+ declare function isSandboxNotRunningError(err: unknown): err is SandboxNotRunningError;
29
+
3
30
  /**
4
31
  * E2B Sandbox Provider - Clean Architecture
5
32
  *
6
- * @requires @e2b/code-interpreter >= 1.0.0 or e2b >= 1.0.0
33
+ * @requires @e2b/code-interpreter >= 2.7.1 (pins e2b 2.39.0); every field and call this adapter uses is already
34
+ * in e2b 2.10.3, the version the dashboard resolves (typings 2.10.3…2.39.0 unpacked and checked 2026-09-16)
7
35
  * @requires Node.js >= 18 (for ReadableStream support)
8
36
  *
9
37
  * Design principles:
@@ -110,18 +138,27 @@ interface SandboxInfo {
110
138
  /** End time (undefined for running sandboxes) */
111
139
  endAt?: string;
112
140
  }
113
- /** File or directory entry info */
141
+ /** The SDK contract's FileInfo (sdk-ts types.ts), the same entry on every provider. */
114
142
  interface FileInfo {
115
143
  name: string;
116
144
  path: string;
117
- type: "file" | "dir";
145
+ type: "file" | "dir" | "symlink" | "other";
146
+ size: number;
147
+ mtime: string;
148
+ mode: string;
149
+ owner: string;
150
+ group: string;
151
+ target?: string;
152
+ }
153
+ /** A byte range of a file (the SDK contract's FileRange). */
154
+ interface FileRange {
155
+ offset: number;
156
+ length: number;
118
157
  }
119
- /** Filesystem event from watchDir */
158
+ /** One filesystem change from watchDir: an absolute path, four kinds. */
120
159
  interface FilesystemEvent {
121
- /** Relative path to the changed file/directory */
122
- name: string;
123
- /** Type of filesystem operation */
124
- type: "create" | "remove" | "rename" | "chmod" | "write";
160
+ path: string;
161
+ type: "create" | "write" | "remove" | "rename";
125
162
  }
126
163
  /** Handle to stop watching a directory */
127
164
  interface WatchHandle {
@@ -129,9 +166,21 @@ interface WatchHandle {
129
166
  }
130
167
  /** Options for watching a directory */
131
168
  interface WatchOptions {
169
+ /** Also report changes in every subdirectory. Default false. */
132
170
  recursive?: boolean;
133
- timeoutMs?: number;
134
- onExit?: (err?: Error) => void | Promise<void>;
171
+ }
172
+ /** One resource-usage sample (the SDK contract's SandboxMetrics). */
173
+ interface SandboxMetrics {
174
+ cpuPct: number;
175
+ memUsedMb: number;
176
+ memTotalMb: number;
177
+ diskUsedMb?: number;
178
+ sampledAt: string;
179
+ source: string;
180
+ }
181
+ /** Options for an inspect-only attach (the SDK contract's SandboxInspectOptions). */
182
+ interface SandboxInspectOptions {
183
+ user?: string;
135
184
  }
136
185
  /** Options for blocking sandbox command execution */
137
186
  interface SandboxRunOptions {
@@ -285,6 +334,10 @@ interface SandboxFiles {
285
334
  remove(path: string): Promise<void>;
286
335
  /** Rename or move file/directory */
287
336
  rename(oldPath: string, newPath: string): Promise<void>;
337
+ /** The entry at `path` itself; a symlink is never followed */
338
+ stat(path: string): Promise<FileInfo>;
339
+ /** Exactly the requested bytes, without moving the whole file when the range is small */
340
+ readRange(path: string, range: FileRange): Promise<Uint8Array>;
288
341
  /** Watch directory for changes */
289
342
  watchDir(path: string, onEvent: (event: FilesystemEvent) => void | Promise<void>, options?: WatchOptions): Promise<WatchHandle>;
290
343
  }
@@ -299,6 +352,8 @@ interface SandboxInstance {
299
352
  isRunning(): Promise<boolean>;
300
353
  /** Get sandbox metadata and timing */
301
354
  getInfo(): Promise<SandboxInfo>;
355
+ /** The newest resource-usage sample, or null while there is none yet */
356
+ metrics(): Promise<SandboxMetrics | null>;
302
357
  /** Terminate sandbox */
303
358
  kill(): Promise<void>;
304
359
  /** Pause sandbox (preserves state) */
@@ -316,6 +371,8 @@ interface SandboxProvider {
316
371
  create(options: SandboxCreateOptions): Promise<SandboxInstance>;
317
372
  /** Connect to existing sandbox */
318
373
  connect(sandboxId: string, timeoutMs?: number): Promise<SandboxInstance>;
374
+ /** Attach to a RUNNING sandbox for reads; never resumes it, never touches its lifetime */
375
+ inspect(sandboxId: string, options?: SandboxInspectOptions): Promise<SandboxInstance>;
319
376
  /** List sandboxes, paginating to exhaustion. `limit` bounds items returned. */
320
377
  list(options?: SandboxListOptions): Promise<SandboxInfo[]>;
321
378
  /** The same enumeration for fleet bookkeeping: never throws, reports completeness. */
@@ -351,7 +408,10 @@ declare class E2BCommands implements SandboxCommands {
351
408
  declare class E2BFiles implements SandboxFiles {
352
409
  private sandbox;
353
410
  private defaultUser?;
354
- constructor(sandbox: Sandbox, defaultUser?: string | undefined);
411
+ private envdVersion?;
412
+ /** inspect() passes the record's envd version; a created or connected sandbox reads its record once. */
413
+ constructor(sandbox: Sandbox, defaultUser?: string | undefined, envdVersion?: string | undefined);
414
+ private assertEntryInfo;
355
415
  read(path: string): Promise<string | Uint8Array>;
356
416
  write(path: string, content: string | Buffer | ArrayBuffer | Uint8Array): Promise<void>;
357
417
  writeBatch(files: Array<{
@@ -363,6 +423,8 @@ declare class E2BFiles implements SandboxFiles {
363
423
  downloadUrl(path: string, expiresInSeconds?: number): Promise<string>;
364
424
  exists(path: string): Promise<boolean>;
365
425
  list(path: string): Promise<FileInfo[]>;
426
+ stat(path: string): Promise<FileInfo>;
427
+ readRange(path: string, range: FileRange): Promise<Uint8Array>;
366
428
  remove(path: string): Promise<void>;
367
429
  rename(oldPath: string, newPath: string): Promise<void>;
368
430
  readStream(path: string): Promise<ReadableStream<Uint8Array>>;
@@ -398,8 +460,11 @@ declare class E2BSandboxImpl implements SandboxInstance {
398
460
  private apiUrl?;
399
461
  readonly commands: SandboxCommands;
400
462
  readonly files: SandboxFiles;
401
- constructor(sandbox: Sandbox, apiKey: string, apiUrl?: string | undefined, defaultUser?: string);
463
+ /** Timestamp of the newest metrics sample seen, so later reads ask only for what is new. */
464
+ private lastMetricsAt?;
465
+ constructor(sandbox: Sandbox, apiKey: string, apiUrl?: string | undefined, defaultUser?: string, envdVersion?: string);
402
466
  get sandboxId(): string;
467
+ metrics(): Promise<SandboxMetrics | null>;
403
468
  getHost(port: number): Promise<string>;
404
469
  isRunning(): Promise<boolean>;
405
470
  getInfo(): Promise<SandboxInfo>;
@@ -444,6 +509,8 @@ declare class E2BProvider implements SandboxProvider {
444
509
  constructor(config: ResolvedE2BConfig);
445
510
  create(options: SandboxCreateOptions): Promise<SandboxInstance>;
446
511
  connect(sandboxId: string, timeoutMs?: number): Promise<SandboxInstance>;
512
+ inspect(sandboxId: string, options?: SandboxInspectOptions): Promise<SandboxInstance>;
513
+ protected fetchSandboxDetail(sandboxId: string): Promise<E2BSandboxDetail>;
447
514
  /**
448
515
  * List sandboxes, walking every page.
449
516
  *
@@ -500,6 +567,15 @@ declare function collectSandboxPages(paginator: E2BSandboxPaginator, wanted?: nu
500
567
  stoppedAtLimit: boolean;
501
568
  }>;
502
569
  declare const _testCollectSandboxPages: typeof collectSandboxPages;
570
+ /** The fields of E2B's SandboxDetail record that inspect() reads. */
571
+ interface E2BSandboxDetail {
572
+ sandboxID: string;
573
+ state: string;
574
+ envdVersion: string;
575
+ domain?: string | null;
576
+ envdAccessToken?: string;
577
+ trafficAccessToken?: string | null;
578
+ }
503
579
  /**
504
580
  * Create E2B sandbox provider.
505
581
  *
@@ -515,5 +591,7 @@ declare function createE2BProvider(config?: E2BConfig): SandboxProvider;
515
591
  * the type (never the constructor) gives the seam the real methods to pin.
516
592
  */
517
593
  type _testE2BSandboxImpl = E2BSandboxImpl;
594
+ /** The constructor, for the metrics unit test (a vendor sandbox double goes in). */
595
+ declare const _testE2BSandboxImplCtor: typeof E2BSandboxImpl;
518
596
 
519
- export { E2BBootCommandError, E2BCommands, type E2BConfig, E2BFiles, E2BIdleTimeoutError, E2BNetworkUpdateUnsupportedError, E2BProvider, E2BResourcesError, type E2BSandboxPaginator, E2B_MAX_LIST_PAGES, E2B_MAX_PAGE_SIZE, E2B_MIN_UPDATE_NETWORK_VERSION, 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, type _testE2BSandboxImpl, createE2BProvider };
597
+ export { E2BBootCommandError, E2BCommands, type E2BConfig, E2BFiles, E2BIdleTimeoutError, E2BNetworkUpdateUnsupportedError, E2BProvider, E2BResourcesError, type E2BSandboxPaginator, E2B_MAX_LIST_PAGES, E2B_MAX_PAGE_SIZE, E2B_MIN_UPDATE_NETWORK_VERSION, type FileInfo, type FileRange, type FilesystemEvent, type ProcessInfo, type SandboxCommandHandle, type SandboxCommandResult, type SandboxCommands, type SandboxConnectOptions, type SandboxCreateOptions, SandboxFeatureUnsupportedError, type SandboxFiles, type SandboxInfo, type SandboxInspectOptions, type SandboxInstance, type SandboxListOptions, type SandboxListPage, type SandboxMetrics, SandboxNotRunningError, SandboxPathNotFoundError, type SandboxProvider, type SandboxRunOptions, type SandboxSpawnOptions, type WatchHandle, type WatchOptions, _testCollectSandboxPages, type _testE2BSandboxImpl, _testE2BSandboxImplCtor, createE2BProvider, isSandboxFeatureUnsupportedError, isSandboxNotRunningError, isSandboxPathNotFoundError };
package/dist/index.d.ts CHANGED
@@ -1,9 +1,37 @@
1
1
  import { Sandbox } from '@e2b/code-interpreter';
2
2
 
3
+ /** A capability this provider lacks: `feature` in dotted form (`files.watchDir`), `provider` type, optional `reason`. */
4
+ declare class SandboxFeatureUnsupportedError extends Error {
5
+ readonly feature: string;
6
+ readonly provider: string;
7
+ readonly reason?: string;
8
+ constructor(feature: string, provider: string, reason?: string);
9
+ }
10
+ /** A path the sandbox does not have — never an empty success. */
11
+ declare class SandboxPathNotFoundError extends Error {
12
+ readonly path: string;
13
+ readonly provider: string;
14
+ constructor(path: string, provider: string);
15
+ }
16
+ /** An inspect refused because the sandbox is not running; `state` is the provider's own word (`paused`, `exited with code 137`). */
17
+ declare class SandboxNotRunningError extends Error {
18
+ readonly sandboxId: string;
19
+ readonly provider: string;
20
+ readonly state: string;
21
+ constructor(sandboxId: string, provider: string, state: string);
22
+ }
23
+ /** True for a SandboxFeatureUnsupportedError from ANY package's copy. */
24
+ declare function isSandboxFeatureUnsupportedError(err: unknown): err is SandboxFeatureUnsupportedError;
25
+ /** True for a SandboxPathNotFoundError from ANY package's copy. */
26
+ declare function isSandboxPathNotFoundError(err: unknown): err is SandboxPathNotFoundError;
27
+ /** True for a SandboxNotRunningError from ANY package's copy. */
28
+ declare function isSandboxNotRunningError(err: unknown): err is SandboxNotRunningError;
29
+
3
30
  /**
4
31
  * E2B Sandbox Provider - Clean Architecture
5
32
  *
6
- * @requires @e2b/code-interpreter >= 1.0.0 or e2b >= 1.0.0
33
+ * @requires @e2b/code-interpreter >= 2.7.1 (pins e2b 2.39.0); every field and call this adapter uses is already
34
+ * in e2b 2.10.3, the version the dashboard resolves (typings 2.10.3…2.39.0 unpacked and checked 2026-09-16)
7
35
  * @requires Node.js >= 18 (for ReadableStream support)
8
36
  *
9
37
  * Design principles:
@@ -110,18 +138,27 @@ interface SandboxInfo {
110
138
  /** End time (undefined for running sandboxes) */
111
139
  endAt?: string;
112
140
  }
113
- /** File or directory entry info */
141
+ /** The SDK contract's FileInfo (sdk-ts types.ts), the same entry on every provider. */
114
142
  interface FileInfo {
115
143
  name: string;
116
144
  path: string;
117
- type: "file" | "dir";
145
+ type: "file" | "dir" | "symlink" | "other";
146
+ size: number;
147
+ mtime: string;
148
+ mode: string;
149
+ owner: string;
150
+ group: string;
151
+ target?: string;
152
+ }
153
+ /** A byte range of a file (the SDK contract's FileRange). */
154
+ interface FileRange {
155
+ offset: number;
156
+ length: number;
118
157
  }
119
- /** Filesystem event from watchDir */
158
+ /** One filesystem change from watchDir: an absolute path, four kinds. */
120
159
  interface FilesystemEvent {
121
- /** Relative path to the changed file/directory */
122
- name: string;
123
- /** Type of filesystem operation */
124
- type: "create" | "remove" | "rename" | "chmod" | "write";
160
+ path: string;
161
+ type: "create" | "write" | "remove" | "rename";
125
162
  }
126
163
  /** Handle to stop watching a directory */
127
164
  interface WatchHandle {
@@ -129,9 +166,21 @@ interface WatchHandle {
129
166
  }
130
167
  /** Options for watching a directory */
131
168
  interface WatchOptions {
169
+ /** Also report changes in every subdirectory. Default false. */
132
170
  recursive?: boolean;
133
- timeoutMs?: number;
134
- onExit?: (err?: Error) => void | Promise<void>;
171
+ }
172
+ /** One resource-usage sample (the SDK contract's SandboxMetrics). */
173
+ interface SandboxMetrics {
174
+ cpuPct: number;
175
+ memUsedMb: number;
176
+ memTotalMb: number;
177
+ diskUsedMb?: number;
178
+ sampledAt: string;
179
+ source: string;
180
+ }
181
+ /** Options for an inspect-only attach (the SDK contract's SandboxInspectOptions). */
182
+ interface SandboxInspectOptions {
183
+ user?: string;
135
184
  }
136
185
  /** Options for blocking sandbox command execution */
137
186
  interface SandboxRunOptions {
@@ -285,6 +334,10 @@ interface SandboxFiles {
285
334
  remove(path: string): Promise<void>;
286
335
  /** Rename or move file/directory */
287
336
  rename(oldPath: string, newPath: string): Promise<void>;
337
+ /** The entry at `path` itself; a symlink is never followed */
338
+ stat(path: string): Promise<FileInfo>;
339
+ /** Exactly the requested bytes, without moving the whole file when the range is small */
340
+ readRange(path: string, range: FileRange): Promise<Uint8Array>;
288
341
  /** Watch directory for changes */
289
342
  watchDir(path: string, onEvent: (event: FilesystemEvent) => void | Promise<void>, options?: WatchOptions): Promise<WatchHandle>;
290
343
  }
@@ -299,6 +352,8 @@ interface SandboxInstance {
299
352
  isRunning(): Promise<boolean>;
300
353
  /** Get sandbox metadata and timing */
301
354
  getInfo(): Promise<SandboxInfo>;
355
+ /** The newest resource-usage sample, or null while there is none yet */
356
+ metrics(): Promise<SandboxMetrics | null>;
302
357
  /** Terminate sandbox */
303
358
  kill(): Promise<void>;
304
359
  /** Pause sandbox (preserves state) */
@@ -316,6 +371,8 @@ interface SandboxProvider {
316
371
  create(options: SandboxCreateOptions): Promise<SandboxInstance>;
317
372
  /** Connect to existing sandbox */
318
373
  connect(sandboxId: string, timeoutMs?: number): Promise<SandboxInstance>;
374
+ /** Attach to a RUNNING sandbox for reads; never resumes it, never touches its lifetime */
375
+ inspect(sandboxId: string, options?: SandboxInspectOptions): Promise<SandboxInstance>;
319
376
  /** List sandboxes, paginating to exhaustion. `limit` bounds items returned. */
320
377
  list(options?: SandboxListOptions): Promise<SandboxInfo[]>;
321
378
  /** The same enumeration for fleet bookkeeping: never throws, reports completeness. */
@@ -351,7 +408,10 @@ declare class E2BCommands implements SandboxCommands {
351
408
  declare class E2BFiles implements SandboxFiles {
352
409
  private sandbox;
353
410
  private defaultUser?;
354
- constructor(sandbox: Sandbox, defaultUser?: string | undefined);
411
+ private envdVersion?;
412
+ /** inspect() passes the record's envd version; a created or connected sandbox reads its record once. */
413
+ constructor(sandbox: Sandbox, defaultUser?: string | undefined, envdVersion?: string | undefined);
414
+ private assertEntryInfo;
355
415
  read(path: string): Promise<string | Uint8Array>;
356
416
  write(path: string, content: string | Buffer | ArrayBuffer | Uint8Array): Promise<void>;
357
417
  writeBatch(files: Array<{
@@ -363,6 +423,8 @@ declare class E2BFiles implements SandboxFiles {
363
423
  downloadUrl(path: string, expiresInSeconds?: number): Promise<string>;
364
424
  exists(path: string): Promise<boolean>;
365
425
  list(path: string): Promise<FileInfo[]>;
426
+ stat(path: string): Promise<FileInfo>;
427
+ readRange(path: string, range: FileRange): Promise<Uint8Array>;
366
428
  remove(path: string): Promise<void>;
367
429
  rename(oldPath: string, newPath: string): Promise<void>;
368
430
  readStream(path: string): Promise<ReadableStream<Uint8Array>>;
@@ -398,8 +460,11 @@ declare class E2BSandboxImpl implements SandboxInstance {
398
460
  private apiUrl?;
399
461
  readonly commands: SandboxCommands;
400
462
  readonly files: SandboxFiles;
401
- constructor(sandbox: Sandbox, apiKey: string, apiUrl?: string | undefined, defaultUser?: string);
463
+ /** Timestamp of the newest metrics sample seen, so later reads ask only for what is new. */
464
+ private lastMetricsAt?;
465
+ constructor(sandbox: Sandbox, apiKey: string, apiUrl?: string | undefined, defaultUser?: string, envdVersion?: string);
402
466
  get sandboxId(): string;
467
+ metrics(): Promise<SandboxMetrics | null>;
403
468
  getHost(port: number): Promise<string>;
404
469
  isRunning(): Promise<boolean>;
405
470
  getInfo(): Promise<SandboxInfo>;
@@ -444,6 +509,8 @@ declare class E2BProvider implements SandboxProvider {
444
509
  constructor(config: ResolvedE2BConfig);
445
510
  create(options: SandboxCreateOptions): Promise<SandboxInstance>;
446
511
  connect(sandboxId: string, timeoutMs?: number): Promise<SandboxInstance>;
512
+ inspect(sandboxId: string, options?: SandboxInspectOptions): Promise<SandboxInstance>;
513
+ protected fetchSandboxDetail(sandboxId: string): Promise<E2BSandboxDetail>;
447
514
  /**
448
515
  * List sandboxes, walking every page.
449
516
  *
@@ -500,6 +567,15 @@ declare function collectSandboxPages(paginator: E2BSandboxPaginator, wanted?: nu
500
567
  stoppedAtLimit: boolean;
501
568
  }>;
502
569
  declare const _testCollectSandboxPages: typeof collectSandboxPages;
570
+ /** The fields of E2B's SandboxDetail record that inspect() reads. */
571
+ interface E2BSandboxDetail {
572
+ sandboxID: string;
573
+ state: string;
574
+ envdVersion: string;
575
+ domain?: string | null;
576
+ envdAccessToken?: string;
577
+ trafficAccessToken?: string | null;
578
+ }
503
579
  /**
504
580
  * Create E2B sandbox provider.
505
581
  *
@@ -515,5 +591,7 @@ declare function createE2BProvider(config?: E2BConfig): SandboxProvider;
515
591
  * the type (never the constructor) gives the seam the real methods to pin.
516
592
  */
517
593
  type _testE2BSandboxImpl = E2BSandboxImpl;
594
+ /** The constructor, for the metrics unit test (a vendor sandbox double goes in). */
595
+ declare const _testE2BSandboxImplCtor: typeof E2BSandboxImpl;
518
596
 
519
- export { E2BBootCommandError, E2BCommands, type E2BConfig, E2BFiles, E2BIdleTimeoutError, E2BNetworkUpdateUnsupportedError, E2BProvider, E2BResourcesError, type E2BSandboxPaginator, E2B_MAX_LIST_PAGES, E2B_MAX_PAGE_SIZE, E2B_MIN_UPDATE_NETWORK_VERSION, 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, type _testE2BSandboxImpl, createE2BProvider };
597
+ export { E2BBootCommandError, E2BCommands, type E2BConfig, E2BFiles, E2BIdleTimeoutError, E2BNetworkUpdateUnsupportedError, E2BProvider, E2BResourcesError, type E2BSandboxPaginator, E2B_MAX_LIST_PAGES, E2B_MAX_PAGE_SIZE, E2B_MIN_UPDATE_NETWORK_VERSION, type FileInfo, type FileRange, type FilesystemEvent, type ProcessInfo, type SandboxCommandHandle, type SandboxCommandResult, type SandboxCommands, type SandboxConnectOptions, type SandboxCreateOptions, SandboxFeatureUnsupportedError, type SandboxFiles, type SandboxInfo, type SandboxInspectOptions, type SandboxInstance, type SandboxListOptions, type SandboxListPage, type SandboxMetrics, SandboxNotRunningError, SandboxPathNotFoundError, type SandboxProvider, type SandboxRunOptions, type SandboxSpawnOptions, type WatchHandle, type WatchOptions, _testCollectSandboxPages, type _testE2BSandboxImpl, _testE2BSandboxImplCtor, createE2BProvider, isSandboxFeatureUnsupportedError, isSandboxNotRunningError, isSandboxPathNotFoundError };
package/dist/index.js CHANGED
@@ -1,8 +1,8 @@
1
- import {Sandbox}from'@e2b/code-interpreter';function b(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=100,I=100;function u(s){return s instanceof Date?s.toISOString():String(s)}function U(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.`)}var l=class extends Error{constructor(e){super(e),this.name="E2BResourcesError";}},B="2.25.0",g=class extends Error{constructor(e){super(e),this.name="E2BNetworkUpdateUnsupportedError";}};function x(s){if(s?.outbound==="open"&&s.allowedDestinations?.length)throw new Error("network.allowedDestinations is only valid when outbound is blocked");let e=s?.allowedDestinations??[],t=s?.outbound==="blocked"&&e.length>0;return {allowInternetAccess:s?.outbound!=="blocked"||t,network:t?{denyOut:["0.0.0.0/0"],allowOut:e}:void 0}}var h=class extends Error{constructor(){super("E2B takes no create-time boot command: the sandbox boots its template's own init, and a start command is a template-BUILD field (Template startCmd) this provider never sets. The boot is already inert \u2014 run the process by exec after create, or bake it into the template the `image` names."),this.name="E2BBootCommandError";}},y=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";}},w=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(b(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(b(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(b(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))}},S=class{constructor(e,t){this.sandbox=e;this.defaultUser=t;}async read(e){let t=await this.sandbox.files.read(e,{format:"bytes",requestTimeoutMs:3e5,user:this.defaultUser});if(!t.includes(0))try{return new TextDecoder("utf-8",{fatal:!0,ignoreBOM:!0}).decode(t)}catch{}return t}async write(e,t){await this.sandbox.files.write(e,U(t),{requestTimeoutMs:3e5,user:this.defaultUser});}async writeBatch(e){let t=e.map(r=>({path:r.path,data:U(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:d}=await import('crypto'),a=n(t).size,p=`----evolve${d(16).toString("hex")}`,v=Buffer.from(`--${p}\r
1
+ import {Sandbox,ConnectionConfig,ApiClient}from'@e2b/code-interpreter';import {compareVersions}from'compare-versions';import'fs';var x=class extends Error{feature;provider;reason;constructor(e,t,n){super(`${t} does not support ${e}${n?`: ${n}`:""}`),this.name="SandboxFeatureUnsupportedError",this.feature=e,this.provider=t,this.reason=n;}},m=class extends Error{path;provider;constructor(e,t){super(`${t}: no such file or directory: ${e}`),this.name="SandboxPathNotFoundError",this.path=e,this.provider=t;}},g=class extends Error{sandboxId;provider;state;constructor(e,t,n){super(`${t} sandbox ${e} is not running (${n}); inspect never starts or resumes a sandbox`),this.name="SandboxNotRunningError",this.sandboxId=e,this.provider=t,this.state=n;}};function P(r,e){return !!r&&typeof r=="object"&&r.name===e}function q(r){return P(r,"SandboxFeatureUnsupportedError")}function W(r){return P(r,"SandboxPathNotFoundError")}function j(r){return P(r,"SandboxNotRunningError")}function E(r){if(!Number.isInteger(r.offset)||r.offset<0)throw new RangeError(`offset must be a non-negative integer, got ${r.offset}`);if(!Number.isInteger(r.length)||r.length<0)throw new RangeError(`length must be a non-negative integer, got ${r.length}`)}function z(r){return r.padStart(4,"0")}var X=/^(-|[dalTLDpSugct?]+)([-r][-w][-x]){3}$/;function N(r){if(!X.test(r))throw new RangeError(`not a Go file mode string: ${r}`);let e=r.slice(0,-9),t=r.slice(-9),n=e.includes("d")?"dir":e.includes("L")?"symlink":/[DpSc?]/.test(e)?"other":"file",s=(e.includes("u")?2048:0)|(e.includes("g")?1024:0)|(e.includes("t")?512:0);for(let o=0;o<9;o++)t[o]!=="-"&&(s|=1<<8-o);return {type:n,mode:z(s.toString(8))}}function v(r){let e=r instanceof Date?r:typeof r=="number"?new Date(r*1e3):new Date(r);if(Number.isNaN(e.getTime()))throw new RangeError(`not a timestamp: ${String(r)}`);return e.toISOString()}function D(r,e){return r.endsWith("/")?`${r}${e}`:`${r}/${e}`}async function $(r,e,t){if(E(e),e.length===0)return new Uint8Array(0);let n=e.offset+e.length-1,s=await fetch(r,{headers:{Range:`bytes=${e.offset}-${n}`},signal:AbortSignal.timeout(t.timeoutMs)});if(s.status===206){let o=new Uint8Array(await s.arrayBuffer());return o.length>e.length?o.subarray(0,e.length):o}if(s.status===200)return Y(s,e);if(s.status===416)return await s.body?.cancel().catch(()=>{}),new Uint8Array(0);throw await s.body?.cancel().catch(()=>{}),s.status===404?new m(t.path,t.provider):new Error(`${t.provider}: range read of ${t.path} failed (HTTP ${s.status})`)}async function Y(r,e){if(!r.body)return new Uint8Array(0);let t=r.body.getReader(),n=[],s=0,o=0,a=e.offset+e.length;try{for(;;){let{done:c,value:p}=await t.read();if(c)break;let h=s;if(s+=p.length,s>e.offset){let d=Math.max(0,e.offset-h),u=Math.min(p.length,a-h);u>d&&(n.push(p.subarray(d,u)),o+=u-d);}if(s>=a)break}}finally{await t.cancel().catch(()=>{});}let i=new Uint8Array(o),l=0;for(let c of n)i.set(c,l),l+=c.length;return i}var b=3e5,_="0.2.5",ee=new Date(0);function I(r){if(!r||typeof r!="object")return false;if(r.name==="TimeoutError")return true;let e=r.message;return typeof e=="string"&&/timed?\s*out/i.test(e)}var L=100,K=100;function w(r){return r instanceof Date?r.toISOString():String(r)}function G(r){if(typeof r=="string"||r instanceof ArrayBuffer)return r;if(r instanceof Buffer)return new Uint8Array(r).buffer;if(r instanceof Uint8Array)return new Uint8Array(r).buffer;throw new Error(`Unsupported data type for file upload: ${typeof r}. Expected string, Buffer, ArrayBuffer, or Uint8Array.`)}var S=class extends Error{constructor(e){super(e),this.name="E2BResourcesError";}},te="2.25.0",A=class extends Error{constructor(e){super(e),this.name="E2BNetworkUpdateUnsupportedError";}};function T(r){if(r?.outbound==="open"&&r.allowedDestinations?.length)throw new Error("network.allowedDestinations is only valid when outbound is blocked");let e=r?.allowedDestinations??[],t=r?.outbound==="blocked"&&e.length>0;return {allowInternetAccess:r?.outbound!=="blocked"||t,network:t?{denyOut:["0.0.0.0/0"],allowOut:e}:void 0}}var B=class extends Error{constructor(){super("E2B takes no create-time boot command: the sandbox boots its template's own init, and a start command is a template-BUILD field (Template startCmd) this provider never sets. The boot is already inert \u2014 run the process by exec after create, or bake it into the template the `image` names."),this.name="E2BBootCommandError";}},M=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";}},R=class{constructor(e,t){this.sandbox=e;this.defaultUser=t;}async run(e,t){try{let n=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:n.exitCode,stdout:n.stdout,stderr:n.stderr}}catch(n){if(n&&typeof n=="object"&&"exitCode"in n){let s=n;return {exitCode:s.exitCode,stdout:s.stdout??"",stderr:s.stderr??""}}if(I(n))return {exitCode:124,stdout:"",stderr:n instanceof Error?n.message:"command timed out"};throw n}}async spawn(e,t){let n=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(n.pid),wait:async()=>{try{let s=await n.wait();return {exitCode:s.exitCode,stdout:s.stdout,stderr:s.stderr}}catch(s){if(s&&typeof s=="object"&&"exitCode"in s){let o=s;return {exitCode:o.exitCode,stdout:o.stdout??"",stderr:o.stderr??""}}if(I(s))return {exitCode:124,stdout:"",stderr:s instanceof Error?s.message:"command timed out"};throw s}},kill:()=>this.sandbox.commands.kill(n.pid)}}async list(){return (await this.sandbox.commands.list()).map(t=>({...t,processId:String(t.pid)}))}async connect(e,t){let n=await this.sandbox.commands.connect(Number(e),{onStdout:t?.onStdout,onStderr:t?.onStderr,timeoutMs:t?.timeoutMs});return {processId:String(n.pid),wait:async()=>{try{let s=await n.wait();return {exitCode:s.exitCode,stdout:s.stdout,stderr:s.stderr}}catch(s){if(s&&typeof s=="object"&&"exitCode"in s){let o=s;return {exitCode:o.exitCode,stdout:o.stdout??"",stderr:o.stderr??""}}if(I(s))return {exitCode:124,stdout:"",stderr:s instanceof Error?s.message:"command timed out"};throw s}},kill:()=>this.sandbox.commands.kill(n.pid)}}async sendStdin(e,t){await this.sandbox.commands.sendStdin(Number(e),t);}async kill(e){return this.sandbox.commands.kill(Number(e))}},C=class{constructor(e,t,n){this.sandbox=e;this.defaultUser=t;this.envdVersion=n;}async assertEntryInfo(e){if(this.envdVersion??=(await this.sandbox.getInfo()).envdVersion,compareVersions(this.envdVersion,_)<0)throw new x(e,"e2b",`the sandbox runs envd ${this.envdVersion}; entry permissions, owner, group and mtime need envd ${_} or later (rebuild the template)`)}async read(e){let t=await this.sandbox.files.read(e,{format:"bytes",requestTimeoutMs:b,user:this.defaultUser});if(!t.includes(0))try{return new TextDecoder("utf-8",{fatal:!0,ignoreBOM:!0}).decode(t)}catch{}return t}async write(e,t){await this.sandbox.files.write(e,G(t),{requestTimeoutMs:b,user:this.defaultUser});}async writeBatch(e){let t=e.map(n=>({path:n.path,data:G(n.data)}));await this.sandbox.files.write(t,{requestTimeoutMs:b,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){await this.assertEntryInfo("files.list");try{return (await this.sandbox.files.list(e,{user:this.defaultUser})).map(n=>H(n))}catch(t){throw U(t)?new m(e,"e2b"):t}}async stat(e){await this.assertEntryInfo("files.stat");try{return H(await this.sandbox.files.getInfo(e,{user:this.defaultUser}))}catch(t){throw U(t)?new m(e,"e2b"):t}}async readRange(e,t){if(E(t),t.length===0)return new Uint8Array(0);let n=await this.sandbox.downloadUrl(e,{user:this.defaultUser,useSignatureExpiration:Math.ceil(b/1e3)});return $(n,t,{provider:"e2b",path:e,timeoutMs:b})}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:n,statSync:s}=await import('fs'),{Readable:o}=await import('stream'),{randomBytes:a}=await import('crypto'),i=s(t).size,l=`----evolve${a(16).toString("hex")}`,c=Buffer.from(`--${l}\r
2
2
  Content-Disposition: form-data; name="file"; filename="blob"\r
3
3
  Content-Type: application/octet-stream\r
4
4
  \r
5
- `),A=Buffer.from(`\r
6
- --${p}--\r
7
- `);async function*C(){yield v;for await(let o of r(t))yield o;yield A;}try{let o=await this.uploadUrl(e),m=await fetch(o,{method:"POST",body:i.toWeb(i.from(C())),headers:{"Content-Type":`multipart/form-data; boundary=${p}`,"Content-Length":String(v.length+a+A.length)},duplex:"half"});if(!m.ok)throw new Error(`streamed upload to ${e} failed (HTTP ${m.status})`)}catch(o){console.warn(`[e2b] streamed upload of ${t} failed, falling back to a buffered write:`,o instanceof Error?o.message:o);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()}}},c=class{constructor(e,t,r,n){this.sandbox=e;this.apiKey=t;this.apiUrl=r;this.commands=new w(e,n),this.files=new S(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 updateNetwork(e){let t=x(e),r=this.sandbox;if(typeof r.updateNetwork!="function")throw new g(`The installed e2b client cannot change a running sandbox's network policy: Sandbox.updateNetwork requires e2b >= ${B}. Upgrade the e2b dependency (it is pulled in by @e2b/code-interpreter), or create the sandbox with the policy it needs for its whole lifetime.`);await r.updateNetwork({allowInternetAccess:t.allowInternetAccess,...t.network??{}});}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});}},P=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.bootCommand!==void 0)throw new h;if(e.idleTimeoutMs!==void 0)throw new y;if(e.resources?.gpu!==void 0||e.resources?.gpuTypes!==void 0)throw new l("E2B offers no GPU allocation at any tier \u2014 a `resources.gpu` request cannot be enforced. Run GPU workloads on a provider that reserves GPUs (modal).");if(e.resources&&(e.resources.cpu!==void 0||e.resources.memory!==void 0||e.resources.disk!==void 0))throw new l("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";for(let d of e.phaseNetworkPolicies??[])x(d);let n=x(e.network),i=await Sandbox.create(r,{apiKey:this.apiKey,apiUrl:this.apiUrl,envs:e.envs,metadata:e.metadata,timeoutMs:t,...n});return e.workingDirectory&&await i.files.makeDir(e.workingDirectory,{user:e.user}),e.user&&this.sandboxUsers.set(i.sandboxId,e.user),new c(i,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 c(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 E(Sandbox.list({apiKey:this.apiKey,apiUrl:this.apiUrl,query:{state:e?.state,metadata:e?.metadata},limit:t===void 0?k:Math.min(t,k)}),t)}};async function E(s,e){let t=[],r=0,n=new Set;for(;s.hasNext;){if(r>=I)return {sandboxes:t,complete:false,pagesFetched:r,stoppedAtLimit:false,error:`sandbox list exceeded ${I} 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 d;try{d=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 d){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 T=E;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 P({...s,apiKey:e})}
8
- export{h as E2BBootCommandError,w as E2BCommands,S as E2BFiles,y as E2BIdleTimeoutError,g as E2BNetworkUpdateUnsupportedError,P as E2BProvider,l as E2BResourcesError,I as E2B_MAX_LIST_PAGES,k as E2B_MAX_PAGE_SIZE,B as E2B_MIN_UPDATE_NETWORK_VERSION,T as _testCollectSandboxPages,M as createE2BProvider};
5
+ `),p=Buffer.from(`\r
6
+ --${l}--\r
7
+ `);async function*h(){yield c;for await(let d of n(t))yield d;yield p;}try{let d=await this.uploadUrl(e),u=await fetch(d,{method:"POST",body:o.toWeb(o.from(h())),headers:{"Content-Type":`multipart/form-data; boundary=${l}`,"Content-Length":String(c.length+i+p.length)},duplex:"half"});if(!u.ok)throw new Error(`streamed upload to ${e} failed (HTTP ${u.status})`)}catch(d){console.warn(`[e2b] streamed upload of ${t} failed, falling back to a buffered write:`,d instanceof Error?d.message:d);let u=o.toWeb(n(t));await this.writeStream(e,u);}}async watchDir(e,t,n){let s;try{s=await this.sandbox.files.watchDir(e,o=>{let a=o.type==="chmod"?"write":o.type;return t({path:D(e,o.name),type:a})},{recursive:n?.recursive??!1,timeoutMs:0,user:this.defaultUser});}catch(o){throw U(o)?new m(e,"e2b"):o}return {stop:()=>s.stop()}}};function U(r){let e=r&&typeof r=="object"?r.name:void 0;return e==="FileNotFoundError"||e==="NotFoundError"}function H(r){let{type:e,mode:t}=N(r.permissions),n={name:r.name,path:r.path,type:e,size:r.size,mtime:v(r.modifiedTime??ee),mode:t,owner:r.owner,group:r.group};return e==="symlink"&&r.symlinkTarget!==void 0&&r.symlinkTarget!==r.path&&(n.target=r.symlinkTarget),n}var f=class{constructor(e,t,n,s,o){this.sandbox=e;this.apiKey=t;this.apiUrl=n;this.commands=new R(e,s),this.files=new C(e,s,o);}commands;files;lastMetricsAt;get sandboxId(){return this.sandbox.sandboxId}async metrics(){let e=await this.sandbox.getMetrics(this.lastMetricsAt?{start:this.lastMetricsAt}:{}),t;for(let n of e)(!t||n.timestamp.getTime()>t.timestamp.getTime())&&(t=n);return t?(this.lastMetricsAt=t.timestamp,{cpuPct:t.cpuUsedPct,memUsedMb:t.memUsed/k,memTotalMb:t.memTotal/k,diskUsedMb:t.diskUsed/k,sampledAt:v(t.timestamp),source:"e2b:getMetrics"}):null}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:w(e.startedAt),endAt:e.endAt?w(e.endAt):void 0}}async updateNetwork(e){let t=T(e),n=this.sandbox;if(typeof n.updateNetwork!="function")throw new A(`The installed e2b client cannot change a running sandbox's network policy: Sandbox.updateNetwork requires e2b >= ${te}. Upgrade the e2b dependency (it is pulled in by @e2b/code-interpreter), or create the sandbox with the policy it needs for its whole lifetime.`);await n.updateNetwork({allowInternetAccess:t.allowInternetAccess,...t.network??{}});}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});}},O=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.bootCommand!==void 0)throw new B;if(e.idleTimeoutMs!==void 0)throw new M;if(e.resources?.gpu!==void 0||e.resources?.gpuTypes!==void 0)throw new S("E2B offers no GPU allocation at any tier \u2014 a `resources.gpu` request cannot be enforced. Run GPU workloads on a provider that reserves GPUs (modal).");if(e.resources&&(e.resources.cpu!==void 0||e.resources.memory!==void 0||e.resources.disk!==void 0))throw new S("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,n=e.image??this.templateId??"evolve-all";for(let a of e.phaseNetworkPolicies??[])T(a);let s=T(e.network),o=await Sandbox.create(n,{apiKey:this.apiKey,apiUrl:this.apiUrl,envs:e.envs,metadata:e.metadata,timeoutMs:t,...s});return e.workingDirectory&&await o.files.makeDir(e.workingDirectory,{user:e.user}),e.user&&this.sandboxUsers.set(o.sandboxId,e.user),new f(o,this.apiKey,this.apiUrl,e.user)}async connect(e,t){let n=await Sandbox.connect(e,{apiKey:this.apiKey,apiUrl:this.apiUrl,timeoutMs:t??this.defaultTimeoutMs});return new f(n,this.apiKey,this.apiUrl,this.sandboxUsers.get(e))}async inspect(e,t){let n=await this.fetchSandboxDetail(e);if(n.state!=="running")throw new g(e,"e2b",n.state);let s=F.attach({sandboxId:n.sandboxID,sandboxDomain:n.domain??void 0,envdVersion:n.envdVersion,envdAccessToken:n.envdAccessToken,trafficAccessToken:n.trafficAccessToken??void 0,apiKey:this.apiKey,apiUrl:this.apiUrl});return new f(s,this.apiKey,this.apiUrl,t?.user??this.sandboxUsers.get(e),n.envdVersion)}async fetchSandboxDetail(e){let t=new ConnectionConfig({apiKey:this.apiKey,apiUrl:this.apiUrl}),n=await new ApiClient(t).api.GET("/sandboxes/{sandboxID}",{params:{path:{sandboxID:e}}});if(n.error?.code===404||!n.data&&!n.error)throw new g(e,"e2b","not found");if(n.error)throw new Error(`E2B refused the sandbox record for ${e}: ${n.error.message??n.error.code}`);return n.data}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,...n}=await this.paginate(e);return n}async paginate(e){let t=e?.limit;return V(Sandbox.list({apiKey:this.apiKey,apiUrl:this.apiUrl,query:{state:e?.state,metadata:e?.metadata},limit:t===void 0?L:Math.min(t,L)}),t)}};async function V(r,e){let t=[],n=0,s=new Set;for(;r.hasNext;){if(n>=K)return {sandboxes:t,complete:false,pagesFetched:n,stoppedAtLimit:false,error:`sandbox list exceeded ${K} pages`};let o=r.nextToken;if(o!==void 0){if(s.has(o))return {sandboxes:t,complete:false,pagesFetched:n,stoppedAtLimit:false,error:"pagination token repeated"};s.add(o);}let a;try{a=await r.nextItems();}catch(i){return {sandboxes:t,complete:false,pagesFetched:n,stoppedAtLimit:false,error:`sandbox list failed: ${i instanceof Error?i.message:String(i)}`}}n+=1;for(let i of a){if(e!==void 0&&t.length>=e)return {sandboxes:t,complete:false,pagesFetched:n,stoppedAtLimit:true,error:`stopped at the requested limit of ${e} with more sandboxes available`};t.push({sandboxId:i.sandboxId,image:i.templateId,name:i.name,metadata:i.metadata??{},startedAt:w(i.startedAt),endAt:i.endAt?w(i.endAt):void 0});}if(e!==void 0&&t.length>=e&&r.hasNext)return {sandboxes:t,complete:false,pagesFetched:n,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:n,stoppedAtLimit:false}}var ce=V,k=1024*1024,F=class r extends Sandbox{static attach(e){return new r(e)}};function le(r={}){let e=r.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 O({...r,apiKey:e})}var pe=f;
8
+ export{B as E2BBootCommandError,R as E2BCommands,C as E2BFiles,M as E2BIdleTimeoutError,A as E2BNetworkUpdateUnsupportedError,O as E2BProvider,S as E2BResourcesError,K as E2B_MAX_LIST_PAGES,L as E2B_MAX_PAGE_SIZE,te as E2B_MIN_UPDATE_NETWORK_VERSION,x as SandboxFeatureUnsupportedError,g as SandboxNotRunningError,m as SandboxPathNotFoundError,ce as _testCollectSandboxPages,pe as _testE2BSandboxImplCtor,le as createE2BProvider,q as isSandboxFeatureUnsupportedError,j as isSandboxNotRunningError,W as isSandboxPathNotFoundError};
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@evolvingmachines/e2b",
3
- "version": "0.0.60",
3
+ "version": "0.0.61",
4
4
  "keywords": [
5
5
  "ai",
6
6
  "agents",
@@ -33,10 +33,11 @@
33
33
  "build": "tsup --minify",
34
34
  "dev": "tsup --watch",
35
35
  "type-check": "tsc --noEmit",
36
- "test:unit": "tsx tests/unit/e2b-list-pagination.test.ts && tsx tests/unit/e2b-files-read.test.ts && tsx tests/unit/e2b-gpu-rejection.test.ts && tsx tests/unit/e2b-boot-command-rejection.test.ts && tsx tests/unit/e2b-template-refresh.test.ts"
36
+ "test:unit": "tsx tests/unit/e2b-list-pagination.test.ts && tsx tests/unit/e2b-files-read.test.ts && tsx tests/unit/e2b-gpu-rejection.test.ts && tsx tests/unit/e2b-boot-command-rejection.test.ts && tsx tests/unit/e2b-template-refresh.test.ts && tsx tests/unit/e2b-files-observe.test.ts"
37
37
  },
38
38
  "dependencies": {
39
- "@e2b/code-interpreter": "^2.7.1"
39
+ "@e2b/code-interpreter": "^2.7.1",
40
+ "compare-versions": "^6.1.0"
40
41
  },
41
42
  "devDependencies": {
42
43
  "@types/node": "^22.15.18",