@evolvingmachines/modal 0.0.11 → 0.0.13
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 +4 -3
- package/dist/index.d.cts +18 -4
- package/dist/index.d.ts +18 -4
- package/dist/index.js +4 -3
- package/package.json +1 -1
package/dist/index.cjs
CHANGED
|
@@ -1,3 +1,4 @@
|
|
|
1
|
-
'use strict';var modal=require('modal'),tarStream=require('tar-stream');var b={"evolve-all":"evolvingmachines/evolve-all:latest"},h=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"]);function y(c){let t=c.substring(c.lastIndexOf(".")).toLowerCase();return h.has(t)}var l=class{constructor(t){this.sandbox=t;}wrapAsUser(t,e,n){let r="";n&&Object.keys(n).length>0&&(r=Object.entries(n).filter(([,
|
|
2
|
-
`).slice(1).map(r=>{let s=r.trim().split(/\s+/);return {processId:s[0],cmd:s[1]||"",args:s.slice(2),envs:{}}})}async connect(t,e){throw new Error("Modal does not support connecting to existing processes")}async sendStdin(t,e){throw new Error("Modal does not support sendStdin by process ID")}async kill(t){return await(await this.sandbox.exec(["kill","-9",t],{timeoutMs:1e4})).wait()===0}async accumulateStreams(t,e,n){let r="",s="",i=[];return i.push((async()=>{try{for await(let
|
|
3
|
-
`)){if(!i)continue;let
|
|
1
|
+
'use strict';var modal=require('modal'),tarStream=require('tar-stream');var b={"evolve-all":"evolvingmachines/evolve-all:latest"},h=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"]);function y(c){let t=c.substring(c.lastIndexOf(".")).toLowerCase();return h.has(t)}var l=class{constructor(t){this.sandbox=t;}wrapAsUser(t,e,n){let r="";n&&Object.keys(n).length>0&&(r=Object.entries(n).filter(([,a])=>a!=null).map(([a,o])=>`export ${a}='${String(o).replace(/'/g,"'\\''")}'`).join("; ")+"; ");let s=e?`cd '${e.replace(/'/g,"'\\''")}' && ${r}${t}`:`${r}${t}`;return ["su","user","-c",`echo ${Buffer.from(s).toString("base64")} | base64 -d | bash`]}async run(t,e){let n=this.wrapAsUser(t,e?.cwd,e?.envs),r=await this.sandbox.exec(n,{timeoutMs:e?.timeoutMs}),{stdout:s,stderr:i}=await this.accumulateStreams(r,e?.onStdout,e?.onStderr);return {exitCode:await r.wait(),stdout:s,stderr:i}}async spawn(t,e){let n=this.wrapAsUser(t,e?.cwd,e?.envs),r=await this.sandbox.exec(n,{timeoutMs:e?.timeoutMs}),s="",i="",a=this.accumulateStreams(r,e?.onStdout?d=>{e.onStdout(d);}:void 0,e?.onStderr?d=>{e.onStderr(d);}:void 0).then(({stdout:d,stderr:m})=>{s=d,i=m;}).catch(()=>{});return {processId:`modal-${Date.now()}-${Math.random().toString(36).slice(2)}`,wait:async()=>(await a,{exitCode:await r.wait(),stdout:s,stderr:i}),kill:async()=>false}}async list(){let t=await this.sandbox.exec(["ps","-eo","pid,comm,args"],{timeoutMs:1e4});return await t.wait(),(await t.stdout.readText()).trim().split(`
|
|
2
|
+
`).slice(1).map(r=>{let s=r.trim().split(/\s+/);return {processId:s[0],cmd:s[1]||"",args:s.slice(2),envs:{}}})}async connect(t,e){throw new Error("Modal does not support connecting to existing processes")}async sendStdin(t,e){throw new Error("Modal does not support sendStdin by process ID")}async kill(t){return await(await this.sandbox.exec(["kill","-9",t],{timeoutMs:1e4})).wait()===0}async accumulateStreams(t,e,n){let r="",s="",i=[];return i.push((async()=>{try{for await(let a of t.stdout){let o=typeof a=="string"?a:new TextDecoder().decode(a);r+=o,e?.(o);}}catch{}})()),i.push((async()=>{try{for await(let a of t.stderr){let o=typeof a=="string"?a:new TextDecoder().decode(a);s+=o,n?.(o);}}catch{}})()),await Promise.all(i),{stdout:r,stderr:s}}},f=class{constructor(t){this.sandbox=t;}async read(t){if(y(t)){let r=await this.sandbox.exec(["cat",t],{timeoutMs:3e5,mode:"binary"}),s=await r.wait();if(s!==0){let i=await r.stderr.readText();throw new Error(`Failed to read file ${t}: ${i||`exit code ${s}`}`)}return await r.stdout.readBytes()}let e=await this.sandbox.exec(["cat",t],{timeoutMs:3e5}),n=await e.wait();if(n!==0){let r=await e.stderr.readText();throw new Error(`Failed to read file ${t}: ${r||`exit code ${n}`}`)}return await e.stdout.readText()}async write(t,e){let n=this.toBuffer(e),r=t.substring(0,t.lastIndexOf("/"));r&&await this.makeDir(r);let s=t.replace(/'/g,"'\\''"),i=await this.sandbox.exec(["bash","-c",`cat > '${s}'`],{mode:"binary"});await i.stdin.writeBytes(new Uint8Array(n)),await i.stdin.getWriter().close(),await i.wait(),await(await this.sandbox.exec(["chown","user:user",t],{timeoutMs:1e4})).wait();}async writeBatch(t){let e=tarStream.pack(),n=[],r=new Set;for(let o of t){let d=this.toBuffer(o.data),m=o.path.startsWith("/")?o.path.slice(1):o.path;e.entry({name:m},d);let u=o.path.substring(0,o.path.lastIndexOf("/"));u&&r.add(u);}e.finalize();for await(let o of e)n.push(Buffer.from(o));let s=Buffer.concat(n),i=await this.sandbox.exec(["tar","-xf","-","-C","/"],{mode:"binary"});if(await i.stdin.writeBytes(new Uint8Array(s)),await i.stdin.getWriter().close(),await i.wait(),r.size>0){let o=Array.from(r),d=new Set(o.map(m=>m.split("/").slice(0,4).join("/")));for(let m of d)await(await this.sandbox.exec(["chown","-R","user:user",m],{timeoutMs:3e4})).wait();}}async makeDir(t){await(await this.sandbox.exec(["mkdir","-p",t],{timeoutMs:1e4})).wait(),await(await this.sandbox.exec(["chown","-R","user:user",t],{timeoutMs:1e4})).wait();}async exists(t){return await(await this.sandbox.exec(["test","-e",t],{timeoutMs:1e4})).wait()===0}async list(t){let e=t.replace(/'/g,"'\\''"),n=await this.sandbox.exec(["bash","-c",`ls -la '${e}' | tail -n +2`],{timeoutMs:3e4});await n.wait();let r=await n.stdout.readText(),s=[];for(let i of r.trim().split(`
|
|
3
|
+
`)){if(!i)continue;let a=i.split(/\s+/);if(a.length<9)continue;let o=a[0],d=a.slice(8).join(" ");d==="."||d===".."||s.push({name:d,path:t.endsWith("/")?`${t}${d}`:`${t}/${d}`,type:o.startsWith("d")?"dir":"file"});}return s}async remove(t){await(await this.sandbox.exec(["rm","-rf",t],{timeoutMs:3e4})).wait();}async rename(t,e){await(await this.sandbox.exec(["mv",t,e],{timeoutMs:3e4})).wait();}async readStream(t){return (await this.sandbox.exec(["cat",t],{timeoutMs:3e5,mode:"binary"})).stdout}async writeStream(t,e){let n=t.substring(0,t.lastIndexOf("/"));n&&await this.makeDir(n);let r=t.replace(/'/g,"'\\''"),s=await this.sandbox.exec(["bash","-c",`cat > '${r}'`],{mode:"binary"}),i=e.getReader();try{for(;;){let{done:o,value:d}=await i.read();if(o)break;await s.stdin.writeBytes(d);}}finally{i.releaseLock();}await s.stdin.getWriter().close(),await s.wait();}async uploadUrl(t,e){throw new Error("Modal does not support pre-signed upload URLs")}async downloadUrl(t,e){throw new Error("Modal does not support pre-signed download URLs")}async watchDir(t,e,n){throw new Error("Modal does not support watchDir")}toBuffer(t){if(typeof t=="string")return Buffer.from(t,"utf-8");if(t instanceof Buffer)return t;if(t instanceof ArrayBuffer||t instanceof Uint8Array)return Buffer.from(t);throw new Error(`Unsupported data type: ${typeof t}`)}},p=class{constructor(t,e){this.sandbox=t;this.commands=new l(t),this.files=new f(t),this.image=e,this.startTime=new Date;}commands;files;image;startTime;get sandboxId(){return this.sandbox.sandboxId}async getHost(t){let n=(await this.sandbox.tunnels())[t];if(!n)throw new Error(`No tunnel found for port ${t}`);return n.url}async isRunning(){try{return await(await this.sandbox.exec(["echo","ping"],{timeoutMs:5e3})).wait(),!0}catch{return false}}async getInfo(){return {sandboxId:this.sandbox.sandboxId,image:this.image,metadata:{},startedAt:this.startTime.toISOString()}}async kill(){try{await this.sandbox.terminate();}catch{await new Promise(t=>setTimeout(t,500)),await this.sandbox.terminate();}}async pause(){throw new Error("Modal does not support pause. Use kill() instead.")}},w=class{providerType="modal";client;appName;defaultTimeoutMs;_app;constructor(t){!t.endpoint&&process.env.MODAL_SERVER_URL?.startsWith("unix:")?process.env.MODAL_SERVER_URL="https://api.modal.com:443":t.endpoint&&(process.env.MODAL_SERVER_URL=t.endpoint),this.client=new modal.ModalClient({tokenId:t.tokenId,tokenSecret:t.tokenSecret}),this.appName=t.appName??"evolve-sandbox",this.defaultTimeoutMs=t.defaultTimeoutMs??36e5;}async getApp(){return this._app||(this._app=await this.client.apps.fromName(this.appName,{createIfMissing:true})),this._app}async create(t){let e=await this.getApp(),n=t.timeoutMs??this.defaultTimeoutMs,r=b[t.image]??t.image,s=this.client.images.fromRegistry(r),i=t.envs?Object.fromEntries(Object.entries(t.envs).filter(([,d])=>d!=null)):void 0,a=i&&Object.keys(i).length>0?i:void 0,o=await this.client.sandboxes.create(e,s,{cpu:4,memoryMiB:4096,timeoutMs:n,workdir:t.workingDirectory,env:a});return t.workingDirectory&&await(await o.exec(["chown","-R","user:user",t.workingDirectory],{timeoutMs:3e4})).wait(),new p(o,r)}async connect(t,e){let n=await this.client.sandboxes.fromId(t);return new p(n,"unknown")}async list(t){let e=[],n=t?.limit??100;try{for await(let r of this.client.sandboxes.list())if(e.push({sandboxId:r.sandboxId,image:"unknown",metadata:{},startedAt:new Date().toISOString()}),e.length>=n)break}catch{}return e}};function k(c={}){let t=c.tokenId??process.env.MODAL_TOKEN_ID,e=c.tokenSecret??process.env.MODAL_TOKEN_SECRET;if(!t||!e)throw new Error("Modal credentials required. Set MODAL_TOKEN_ID and MODAL_TOKEN_SECRET environment variables, or pass tokenId/tokenSecret in config. Get your token at https://modal.com/settings/tokens");return new w({...c,tokenId:t,tokenSecret:e})}
|
|
4
|
+
exports.ModalProvider=w;exports.createModalProvider=k;
|
package/dist/index.d.cts
CHANGED
|
@@ -181,6 +181,20 @@ interface ModalConfig {
|
|
|
181
181
|
appName?: string;
|
|
182
182
|
/** Default timeout in ms. Default: 3600000 (1 hour) */
|
|
183
183
|
defaultTimeoutMs?: number;
|
|
184
|
+
/** Modal token ID. Falls back to MODAL_TOKEN_ID env var */
|
|
185
|
+
tokenId?: string;
|
|
186
|
+
/** Modal token secret. Falls back to MODAL_TOKEN_SECRET env var */
|
|
187
|
+
tokenSecret?: string;
|
|
188
|
+
/** Modal API endpoint. Default: https://api.modal.com:443 */
|
|
189
|
+
endpoint?: string;
|
|
190
|
+
}
|
|
191
|
+
/** Internal resolved config with required credentials */
|
|
192
|
+
interface ResolvedModalConfig {
|
|
193
|
+
tokenId: string;
|
|
194
|
+
tokenSecret: string;
|
|
195
|
+
appName?: string;
|
|
196
|
+
defaultTimeoutMs?: number;
|
|
197
|
+
endpoint?: string;
|
|
184
198
|
}
|
|
185
199
|
declare class ModalProvider implements SandboxProvider {
|
|
186
200
|
readonly providerType: "modal";
|
|
@@ -188,7 +202,7 @@ declare class ModalProvider implements SandboxProvider {
|
|
|
188
202
|
private readonly appName;
|
|
189
203
|
private readonly defaultTimeoutMs;
|
|
190
204
|
private _app;
|
|
191
|
-
constructor(config
|
|
205
|
+
constructor(config: ResolvedModalConfig);
|
|
192
206
|
private getApp;
|
|
193
207
|
create(options: SandboxCreateOptions): Promise<SandboxInstance>;
|
|
194
208
|
connect(sandboxId: string, _timeoutMs?: number): Promise<SandboxInstance>;
|
|
@@ -197,10 +211,10 @@ declare class ModalProvider implements SandboxProvider {
|
|
|
197
211
|
/**
|
|
198
212
|
* Create Modal sandbox provider.
|
|
199
213
|
*
|
|
200
|
-
*
|
|
201
|
-
*
|
|
214
|
+
* @param config - Optional configuration. If credentials not provided, reads from env vars.
|
|
215
|
+
* @throws Error if credentials cannot be resolved
|
|
202
216
|
*
|
|
203
|
-
* @
|
|
217
|
+
* @see https://github.com/evolving-machines-lab/evolve/issues/8
|
|
204
218
|
*/
|
|
205
219
|
declare function createModalProvider(config?: ModalConfig): SandboxProvider;
|
|
206
220
|
|
package/dist/index.d.ts
CHANGED
|
@@ -181,6 +181,20 @@ interface ModalConfig {
|
|
|
181
181
|
appName?: string;
|
|
182
182
|
/** Default timeout in ms. Default: 3600000 (1 hour) */
|
|
183
183
|
defaultTimeoutMs?: number;
|
|
184
|
+
/** Modal token ID. Falls back to MODAL_TOKEN_ID env var */
|
|
185
|
+
tokenId?: string;
|
|
186
|
+
/** Modal token secret. Falls back to MODAL_TOKEN_SECRET env var */
|
|
187
|
+
tokenSecret?: string;
|
|
188
|
+
/** Modal API endpoint. Default: https://api.modal.com:443 */
|
|
189
|
+
endpoint?: string;
|
|
190
|
+
}
|
|
191
|
+
/** Internal resolved config with required credentials */
|
|
192
|
+
interface ResolvedModalConfig {
|
|
193
|
+
tokenId: string;
|
|
194
|
+
tokenSecret: string;
|
|
195
|
+
appName?: string;
|
|
196
|
+
defaultTimeoutMs?: number;
|
|
197
|
+
endpoint?: string;
|
|
184
198
|
}
|
|
185
199
|
declare class ModalProvider implements SandboxProvider {
|
|
186
200
|
readonly providerType: "modal";
|
|
@@ -188,7 +202,7 @@ declare class ModalProvider implements SandboxProvider {
|
|
|
188
202
|
private readonly appName;
|
|
189
203
|
private readonly defaultTimeoutMs;
|
|
190
204
|
private _app;
|
|
191
|
-
constructor(config
|
|
205
|
+
constructor(config: ResolvedModalConfig);
|
|
192
206
|
private getApp;
|
|
193
207
|
create(options: SandboxCreateOptions): Promise<SandboxInstance>;
|
|
194
208
|
connect(sandboxId: string, _timeoutMs?: number): Promise<SandboxInstance>;
|
|
@@ -197,10 +211,10 @@ declare class ModalProvider implements SandboxProvider {
|
|
|
197
211
|
/**
|
|
198
212
|
* Create Modal sandbox provider.
|
|
199
213
|
*
|
|
200
|
-
*
|
|
201
|
-
*
|
|
214
|
+
* @param config - Optional configuration. If credentials not provided, reads from env vars.
|
|
215
|
+
* @throws Error if credentials cannot be resolved
|
|
202
216
|
*
|
|
203
|
-
* @
|
|
217
|
+
* @see https://github.com/evolving-machines-lab/evolve/issues/8
|
|
204
218
|
*/
|
|
205
219
|
declare function createModalProvider(config?: ModalConfig): SandboxProvider;
|
|
206
220
|
|
package/dist/index.js
CHANGED
|
@@ -1,3 +1,4 @@
|
|
|
1
|
-
import {ModalClient}from'modal';import {pack}from'tar-stream';var b={"evolve-all":"evolvingmachines/evolve-all:latest"},h=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"]);function y(c){let t=c.substring(c.lastIndexOf(".")).toLowerCase();return h.has(t)}var l=class{constructor(t){this.sandbox=t;}wrapAsUser(t,e,n){let r="";n&&Object.keys(n).length>0&&(r=Object.entries(n).filter(([,
|
|
2
|
-
`).slice(1).map(r=>{let s=r.trim().split(/\s+/);return {processId:s[0],cmd:s[1]||"",args:s.slice(2),envs:{}}})}async connect(t,e){throw new Error("Modal does not support connecting to existing processes")}async sendStdin(t,e){throw new Error("Modal does not support sendStdin by process ID")}async kill(t){return await(await this.sandbox.exec(["kill","-9",t],{timeoutMs:1e4})).wait()===0}async accumulateStreams(t,e,n){let r="",s="",i=[];return i.push((async()=>{try{for await(let
|
|
3
|
-
`)){if(!i)continue;let
|
|
1
|
+
import {ModalClient}from'modal';import {pack}from'tar-stream';var b={"evolve-all":"evolvingmachines/evolve-all:latest"},h=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"]);function y(c){let t=c.substring(c.lastIndexOf(".")).toLowerCase();return h.has(t)}var l=class{constructor(t){this.sandbox=t;}wrapAsUser(t,e,n){let r="";n&&Object.keys(n).length>0&&(r=Object.entries(n).filter(([,a])=>a!=null).map(([a,o])=>`export ${a}='${String(o).replace(/'/g,"'\\''")}'`).join("; ")+"; ");let s=e?`cd '${e.replace(/'/g,"'\\''")}' && ${r}${t}`:`${r}${t}`;return ["su","user","-c",`echo ${Buffer.from(s).toString("base64")} | base64 -d | bash`]}async run(t,e){let n=this.wrapAsUser(t,e?.cwd,e?.envs),r=await this.sandbox.exec(n,{timeoutMs:e?.timeoutMs}),{stdout:s,stderr:i}=await this.accumulateStreams(r,e?.onStdout,e?.onStderr);return {exitCode:await r.wait(),stdout:s,stderr:i}}async spawn(t,e){let n=this.wrapAsUser(t,e?.cwd,e?.envs),r=await this.sandbox.exec(n,{timeoutMs:e?.timeoutMs}),s="",i="",a=this.accumulateStreams(r,e?.onStdout?d=>{e.onStdout(d);}:void 0,e?.onStderr?d=>{e.onStderr(d);}:void 0).then(({stdout:d,stderr:m})=>{s=d,i=m;}).catch(()=>{});return {processId:`modal-${Date.now()}-${Math.random().toString(36).slice(2)}`,wait:async()=>(await a,{exitCode:await r.wait(),stdout:s,stderr:i}),kill:async()=>false}}async list(){let t=await this.sandbox.exec(["ps","-eo","pid,comm,args"],{timeoutMs:1e4});return await t.wait(),(await t.stdout.readText()).trim().split(`
|
|
2
|
+
`).slice(1).map(r=>{let s=r.trim().split(/\s+/);return {processId:s[0],cmd:s[1]||"",args:s.slice(2),envs:{}}})}async connect(t,e){throw new Error("Modal does not support connecting to existing processes")}async sendStdin(t,e){throw new Error("Modal does not support sendStdin by process ID")}async kill(t){return await(await this.sandbox.exec(["kill","-9",t],{timeoutMs:1e4})).wait()===0}async accumulateStreams(t,e,n){let r="",s="",i=[];return i.push((async()=>{try{for await(let a of t.stdout){let o=typeof a=="string"?a:new TextDecoder().decode(a);r+=o,e?.(o);}}catch{}})()),i.push((async()=>{try{for await(let a of t.stderr){let o=typeof a=="string"?a:new TextDecoder().decode(a);s+=o,n?.(o);}}catch{}})()),await Promise.all(i),{stdout:r,stderr:s}}},f=class{constructor(t){this.sandbox=t;}async read(t){if(y(t)){let r=await this.sandbox.exec(["cat",t],{timeoutMs:3e5,mode:"binary"}),s=await r.wait();if(s!==0){let i=await r.stderr.readText();throw new Error(`Failed to read file ${t}: ${i||`exit code ${s}`}`)}return await r.stdout.readBytes()}let e=await this.sandbox.exec(["cat",t],{timeoutMs:3e5}),n=await e.wait();if(n!==0){let r=await e.stderr.readText();throw new Error(`Failed to read file ${t}: ${r||`exit code ${n}`}`)}return await e.stdout.readText()}async write(t,e){let n=this.toBuffer(e),r=t.substring(0,t.lastIndexOf("/"));r&&await this.makeDir(r);let s=t.replace(/'/g,"'\\''"),i=await this.sandbox.exec(["bash","-c",`cat > '${s}'`],{mode:"binary"});await i.stdin.writeBytes(new Uint8Array(n)),await i.stdin.getWriter().close(),await i.wait(),await(await this.sandbox.exec(["chown","user:user",t],{timeoutMs:1e4})).wait();}async writeBatch(t){let e=pack(),n=[],r=new Set;for(let o of t){let d=this.toBuffer(o.data),m=o.path.startsWith("/")?o.path.slice(1):o.path;e.entry({name:m},d);let u=o.path.substring(0,o.path.lastIndexOf("/"));u&&r.add(u);}e.finalize();for await(let o of e)n.push(Buffer.from(o));let s=Buffer.concat(n),i=await this.sandbox.exec(["tar","-xf","-","-C","/"],{mode:"binary"});if(await i.stdin.writeBytes(new Uint8Array(s)),await i.stdin.getWriter().close(),await i.wait(),r.size>0){let o=Array.from(r),d=new Set(o.map(m=>m.split("/").slice(0,4).join("/")));for(let m of d)await(await this.sandbox.exec(["chown","-R","user:user",m],{timeoutMs:3e4})).wait();}}async makeDir(t){await(await this.sandbox.exec(["mkdir","-p",t],{timeoutMs:1e4})).wait(),await(await this.sandbox.exec(["chown","-R","user:user",t],{timeoutMs:1e4})).wait();}async exists(t){return await(await this.sandbox.exec(["test","-e",t],{timeoutMs:1e4})).wait()===0}async list(t){let e=t.replace(/'/g,"'\\''"),n=await this.sandbox.exec(["bash","-c",`ls -la '${e}' | tail -n +2`],{timeoutMs:3e4});await n.wait();let r=await n.stdout.readText(),s=[];for(let i of r.trim().split(`
|
|
3
|
+
`)){if(!i)continue;let a=i.split(/\s+/);if(a.length<9)continue;let o=a[0],d=a.slice(8).join(" ");d==="."||d===".."||s.push({name:d,path:t.endsWith("/")?`${t}${d}`:`${t}/${d}`,type:o.startsWith("d")?"dir":"file"});}return s}async remove(t){await(await this.sandbox.exec(["rm","-rf",t],{timeoutMs:3e4})).wait();}async rename(t,e){await(await this.sandbox.exec(["mv",t,e],{timeoutMs:3e4})).wait();}async readStream(t){return (await this.sandbox.exec(["cat",t],{timeoutMs:3e5,mode:"binary"})).stdout}async writeStream(t,e){let n=t.substring(0,t.lastIndexOf("/"));n&&await this.makeDir(n);let r=t.replace(/'/g,"'\\''"),s=await this.sandbox.exec(["bash","-c",`cat > '${r}'`],{mode:"binary"}),i=e.getReader();try{for(;;){let{done:o,value:d}=await i.read();if(o)break;await s.stdin.writeBytes(d);}}finally{i.releaseLock();}await s.stdin.getWriter().close(),await s.wait();}async uploadUrl(t,e){throw new Error("Modal does not support pre-signed upload URLs")}async downloadUrl(t,e){throw new Error("Modal does not support pre-signed download URLs")}async watchDir(t,e,n){throw new Error("Modal does not support watchDir")}toBuffer(t){if(typeof t=="string")return Buffer.from(t,"utf-8");if(t instanceof Buffer)return t;if(t instanceof ArrayBuffer||t instanceof Uint8Array)return Buffer.from(t);throw new Error(`Unsupported data type: ${typeof t}`)}},p=class{constructor(t,e){this.sandbox=t;this.commands=new l(t),this.files=new f(t),this.image=e,this.startTime=new Date;}commands;files;image;startTime;get sandboxId(){return this.sandbox.sandboxId}async getHost(t){let n=(await this.sandbox.tunnels())[t];if(!n)throw new Error(`No tunnel found for port ${t}`);return n.url}async isRunning(){try{return await(await this.sandbox.exec(["echo","ping"],{timeoutMs:5e3})).wait(),!0}catch{return false}}async getInfo(){return {sandboxId:this.sandbox.sandboxId,image:this.image,metadata:{},startedAt:this.startTime.toISOString()}}async kill(){try{await this.sandbox.terminate();}catch{await new Promise(t=>setTimeout(t,500)),await this.sandbox.terminate();}}async pause(){throw new Error("Modal does not support pause. Use kill() instead.")}},w=class{providerType="modal";client;appName;defaultTimeoutMs;_app;constructor(t){!t.endpoint&&process.env.MODAL_SERVER_URL?.startsWith("unix:")?process.env.MODAL_SERVER_URL="https://api.modal.com:443":t.endpoint&&(process.env.MODAL_SERVER_URL=t.endpoint),this.client=new ModalClient({tokenId:t.tokenId,tokenSecret:t.tokenSecret}),this.appName=t.appName??"evolve-sandbox",this.defaultTimeoutMs=t.defaultTimeoutMs??36e5;}async getApp(){return this._app||(this._app=await this.client.apps.fromName(this.appName,{createIfMissing:true})),this._app}async create(t){let e=await this.getApp(),n=t.timeoutMs??this.defaultTimeoutMs,r=b[t.image]??t.image,s=this.client.images.fromRegistry(r),i=t.envs?Object.fromEntries(Object.entries(t.envs).filter(([,d])=>d!=null)):void 0,a=i&&Object.keys(i).length>0?i:void 0,o=await this.client.sandboxes.create(e,s,{cpu:4,memoryMiB:4096,timeoutMs:n,workdir:t.workingDirectory,env:a});return t.workingDirectory&&await(await o.exec(["chown","-R","user:user",t.workingDirectory],{timeoutMs:3e4})).wait(),new p(o,r)}async connect(t,e){let n=await this.client.sandboxes.fromId(t);return new p(n,"unknown")}async list(t){let e=[],n=t?.limit??100;try{for await(let r of this.client.sandboxes.list())if(e.push({sandboxId:r.sandboxId,image:"unknown",metadata:{},startedAt:new Date().toISOString()}),e.length>=n)break}catch{}return e}};function k(c={}){let t=c.tokenId??process.env.MODAL_TOKEN_ID,e=c.tokenSecret??process.env.MODAL_TOKEN_SECRET;if(!t||!e)throw new Error("Modal credentials required. Set MODAL_TOKEN_ID and MODAL_TOKEN_SECRET environment variables, or pass tokenId/tokenSecret in config. Get your token at https://modal.com/settings/tokens");return new w({...c,tokenId:t,tokenSecret:e})}
|
|
4
|
+
export{w as ModalProvider,k as createModalProvider};
|