@opencoredev/sandbox-sdk 0.2.0 → 1.0.0-beta.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (166) hide show
  1. package/CHANGELOG.md +32 -11
  2. package/README.md +350 -25
  3. package/dist/ai.d.ts +5 -0
  4. package/dist/ai.js +1 -0
  5. package/dist/chunk-59t3rqja.js +2 -0
  6. package/dist/chunk-cwx6cc31.js +2 -0
  7. package/dist/chunk-exv1kf89.js +60 -0
  8. package/dist/chunk-gc8zdxyb.js +2 -0
  9. package/dist/chunk-hjzhc3qg.js +40 -0
  10. package/dist/chunk-md6fmprc.js +1 -0
  11. package/dist/chunk-t5vr9nd8.js +8 -0
  12. package/dist/chunk-v6y7eqxw.js +27 -0
  13. package/dist/chunk-yed8mvs7.js +2 -0
  14. package/dist/chunk-yrsb6hws.js +5 -0
  15. package/dist/chunk-z9rjzn28.js +2 -0
  16. package/dist/errors.d.ts +60 -0
  17. package/dist/files.d.ts +57 -0
  18. package/dist/git.d.ts +28 -0
  19. package/dist/handle.d.ts +4 -0
  20. package/dist/index.d.ts +17 -0
  21. package/dist/index.js +1 -0
  22. package/dist/keys.d.ts +5 -0
  23. package/dist/logs.d.ts +8 -0
  24. package/dist/mastra.d.ts +43 -0
  25. package/dist/mastra.js +1 -0
  26. package/dist/memory.d.ts +34 -0
  27. package/dist/memory.js +11 -0
  28. package/dist/openai.d.ts +39 -0
  29. package/dist/openai.js +1 -0
  30. package/dist/peer.d.ts +5 -0
  31. package/dist/processes.d.ts +71 -0
  32. package/dist/provider.d.ts +138 -0
  33. package/dist/provider.js +0 -0
  34. package/dist/providers/agentos/errors.d.ts +4 -0
  35. package/dist/providers/agentos/index.d.ts +11 -0
  36. package/dist/providers/agentos/index.js +2 -0
  37. package/dist/providers/boat/index.d.ts +23 -0
  38. package/dist/providers/boat/index.js +1 -0
  39. package/dist/providers/boat-api/errors.d.ts +6 -0
  40. package/dist/providers/boat-api/exec.d.ts +11 -0
  41. package/dist/providers/boat-api/index.d.ts +22 -0
  42. package/dist/providers/boxd/errors.d.ts +3 -0
  43. package/dist/providers/boxd/execute.d.ts +3 -0
  44. package/dist/providers/boxd/guest.d.ts +14 -0
  45. package/dist/providers/boxd/index.d.ts +23 -0
  46. package/dist/providers/boxd/index.js +85 -0
  47. package/dist/providers/boxd/transfers.d.ts +19 -0
  48. package/dist/providers/daytona/buffered.d.ts +3 -0
  49. package/dist/providers/daytona/errors.d.ts +3 -0
  50. package/dist/providers/daytona/exec.d.ts +14 -0
  51. package/dist/providers/daytona/index.d.ts +24 -0
  52. package/dist/providers/daytona/index.js +88 -0
  53. package/dist/providers/e2b/errors.d.ts +3 -0
  54. package/dist/providers/e2b/index.d.ts +15 -0
  55. package/dist/providers/e2b/index.js +1 -0
  56. package/dist/providers/freestyle/deadline.d.ts +4 -0
  57. package/dist/providers/freestyle/errors.d.ts +16 -0
  58. package/dist/providers/freestyle/execute.d.ts +12 -0
  59. package/dist/providers/freestyle/index.d.ts +14 -0
  60. package/dist/providers/freestyle/index.js +133 -0
  61. package/dist/providers/freestyle/wire.d.ts +10 -0
  62. package/dist/providers/local/docker.d.ts +32 -0
  63. package/dist/providers/local/index.d.ts +17 -0
  64. package/dist/providers/local/index.js +2 -0
  65. package/dist/providers/railway/errors.d.ts +4 -0
  66. package/dist/providers/railway/index.d.ts +24 -0
  67. package/dist/providers/railway/index.js +1 -0
  68. package/dist/providers/sandboxer/index.d.ts +33 -0
  69. package/dist/providers/sandboxer/index.js +1 -0
  70. package/dist/providers/superserve/bootstrap.d.ts +11 -0
  71. package/dist/providers/superserve/errors.d.ts +3 -0
  72. package/dist/providers/superserve/execute.d.ts +13 -0
  73. package/dist/providers/superserve/index.d.ts +23 -0
  74. package/dist/providers/superserve/index.js +126 -0
  75. package/dist/providers/tenki/deadline.d.ts +2 -0
  76. package/dist/providers/tenki/errors.d.ts +10 -0
  77. package/dist/providers/tenki/exec.d.ts +4 -0
  78. package/dist/providers/tenki/files.d.ts +3 -0
  79. package/dist/providers/tenki/index.d.ts +28 -0
  80. package/dist/providers/tenki/index.js +172 -0
  81. package/dist/providers/tenki/ready.d.ts +7 -0
  82. package/dist/providers/tenki/stream.d.ts +3 -0
  83. package/dist/providers/upstash/buffered.d.ts +3 -0
  84. package/dist/providers/upstash/errors.d.ts +3 -0
  85. package/dist/providers/upstash/exec.d.ts +18 -0
  86. package/dist/providers/upstash/files.d.ts +15 -0
  87. package/dist/providers/upstash/index.d.ts +38 -0
  88. package/dist/providers/upstash/index.js +111 -0
  89. package/dist/providers/vercel/errors.d.ts +3 -0
  90. package/dist/providers/vercel/index.d.ts +14 -0
  91. package/dist/providers/vercel/index.js +1 -0
  92. package/dist/providers/vercel/provider.d.ts +10 -0
  93. package/dist/providers/vercel/transport.d.ts +40 -0
  94. package/dist/run.d.ts +41 -0
  95. package/dist/testing.d.ts +17 -0
  96. package/dist/testing.js +6 -0
  97. package/dist/tool-security.d.ts +9 -0
  98. package/dist/tools.d.ts +117 -0
  99. package/dist/tools.js +1 -0
  100. package/dist/types.d.ts +189 -0
  101. package/package.json +164 -106
  102. package/dist/agentos-CbrZW7R0.mjs +0 -390
  103. package/dist/agentos-CbrZW7R0.mjs.map +0 -1
  104. package/dist/ai/harness.d.mts +0 -16
  105. package/dist/ai/harness.mjs +0 -69
  106. package/dist/ai/harness.mjs.map +0 -1
  107. package/dist/ai/index.d.mts +0 -54
  108. package/dist/ai/index.mjs +0 -4
  109. package/dist/ai-DeFa8yPk.mjs +0 -243
  110. package/dist/ai-DeFa8yPk.mjs.map +0 -1
  111. package/dist/capabilities-BWvOVFbH.d.mts +0 -15
  112. package/dist/capabilities-CaSNd6J1.mjs +0 -125
  113. package/dist/capabilities-CaSNd6J1.mjs.map +0 -1
  114. package/dist/capabilities-xs9kaHrK.mjs +0 -28
  115. package/dist/capabilities-xs9kaHrK.mjs.map +0 -1
  116. package/dist/errors-BuF9bYOQ.mjs +0 -68
  117. package/dist/errors-BuF9bYOQ.mjs.map +0 -1
  118. package/dist/eve/index.d.mts +0 -19
  119. package/dist/eve/index.mjs +0 -155
  120. package/dist/eve/index.mjs.map +0 -1
  121. package/dist/index-CkTwqD0X.d.mts +0 -25
  122. package/dist/index-Dh9xob2s.d.mts +0 -31
  123. package/dist/index.d.mts +0 -5
  124. package/dist/index.mjs +0 -40
  125. package/dist/index.mjs.map +0 -1
  126. package/dist/managed-provider-BsZGVQ4I.mjs +0 -148
  127. package/dist/managed-provider-BsZGVQ4I.mjs.map +0 -1
  128. package/dist/mastra/index.d.mts +0 -118
  129. package/dist/mastra/index.mjs +0 -662
  130. package/dist/mastra/index.mjs.map +0 -1
  131. package/dist/metadata.d.mts +0 -34
  132. package/dist/metadata.mjs +0 -135
  133. package/dist/metadata.mjs.map +0 -1
  134. package/dist/provider-DOBErkBO.d.mts +0 -91
  135. package/dist/provider-utils-CfB9nvJx.mjs +0 -57
  136. package/dist/provider-utils-CfB9nvJx.mjs.map +0 -1
  137. package/dist/providers/agentos/index.d.mts +0 -7
  138. package/dist/providers/agentos/index.mjs +0 -9
  139. package/dist/providers/box/index.d.mts +0 -34
  140. package/dist/providers/box/index.mjs +0 -348
  141. package/dist/providers/box/index.mjs.map +0 -1
  142. package/dist/providers/daytona/index.d.mts +0 -21
  143. package/dist/providers/daytona/index.mjs +0 -206
  144. package/dist/providers/daytona/index.mjs.map +0 -1
  145. package/dist/providers/e2b/index.d.mts +0 -17
  146. package/dist/providers/e2b/index.mjs +0 -169
  147. package/dist/providers/e2b/index.mjs.map +0 -1
  148. package/dist/providers/local/index.d.mts +0 -22
  149. package/dist/providers/local/index.mjs +0 -22
  150. package/dist/providers/local/index.mjs.map +0 -1
  151. package/dist/providers/railway/index.d.mts +0 -29
  152. package/dist/providers/railway/index.mjs +0 -211
  153. package/dist/providers/railway/index.mjs.map +0 -1
  154. package/dist/providers/upstash/index.d.mts +0 -17
  155. package/dist/providers/upstash/index.mjs +0 -211
  156. package/dist/providers/upstash/index.mjs.map +0 -1
  157. package/dist/providers/vercel/index.d.mts +0 -28
  158. package/dist/providers/vercel/index.mjs +0 -186
  159. package/dist/providers/vercel/index.mjs.map +0 -1
  160. package/dist/sandbox-DdEqoXJF.d.mts +0 -26
  161. package/dist/sandbox-DgtY5hvt.mjs +0 -112
  162. package/dist/sandbox-DgtY5hvt.mjs.map +0 -1
  163. package/dist/testing/index.d.mts +0 -27
  164. package/dist/testing/index.mjs +0 -173
  165. package/dist/testing/index.mjs.map +0 -1
  166. package/dist/types-Bv6I2U1c.d.mts +0 -103
@@ -0,0 +1,88 @@
1
+ import{o}from"../../chunk-yed8mvs7.js";import{e}from"../../chunk-gc8zdxyb.js";import{posix as de}from"node:path";var se=new Set(["FILE_NOT_FOUND","QUOTA_EXCEEDED"]),ne=/^(?:[a-f0-9]{16,64}|[a-f0-9]{8}-[a-f0-9]{4}-[a-f0-9]{4}-[a-f0-9]{4}-[a-f0-9]{12})$/i;function T(s,a,y=!1,S=y?"files":"request",m=process.env.DAYTONA_API_KEY,l=[]){if(s instanceof e)return s;let u=s&&typeof s==="object"&&"statusCode"in s?s.statusCode:void 0,f=s&&typeof s==="object"&&"code"in s?s.code:void 0,b=s instanceof Error?s.name:"",C=y&&u===400&&s instanceof Error&&/(?:\bENOENT\b|no such file or directory|\bnot found\b|\bdoes not exist\b)/i.test(s.message),h="provider";if(u===401||u===403)h="auth";else if(f==="FILE_NOT_FOUND"||y&&u===404||C)h="file_not_found";else if(u===404||u===410)h="not_found";else if(u===429||u===402||f==="QUOTA_EXCEEDED")h="quota";else if(u===408||u===504||b.includes("Timeout"))h="timeout";else if(typeof u==="number"&&u>=500||b.includes("Connection"))h="unavailable";else if(u===400||u===422||b.includes("InvalidArgument"))h="invalid_argument";let p={operation:/^(request|create|restore|list|connect|destroy|exec|process|preview|snapshot|files)$/.test(S)?S:"request"},x=[...l,m,process.env.DAYTONA_API_KEY].filter((t)=>typeof t==="string"&&t.length>0),k=(t,n)=>typeof t==="string"&&n.test(t)&&!x.some((r)=>t.includes(r));if(typeof u==="number"&&Number.isInteger(u)&&u>=100&&u<=599)p.status=u;if(k(f,/^[A-Z_]{1,64}$/)&&se.has(f))p.providerCode=f;if(s&&typeof s==="object"){if("source"in s&&k(s.source,/^DAYTONA_(API|DAEMON|PROXY)$/))p.source=s.source;if("headers"in s&&s.headers&&typeof s.headers==="object")for(let t of["x-request-id","x-daytona-request-id"]){let n=Reflect.get(s.headers,t);if(k(n,ne)){p.requestId=n;break}}}let A=Object.assign(Error(JSON.stringify(p)),p);return new e(`Daytona request failed (${h}). The provider could not complete the operation. Check the sandbox and provider configuration.`,{code:h,provider:"daytona",sandboxId:a,cause:A,retryable:["quota","unavailable","timeout"].includes(h),hint:"Check Daytona credentials, quotas, sandbox state, and request options before retrying."})}function L(s){throw new e(`${s}. Daytona cannot enforce this request. Choose supported settings.`,{code:"unsupported",provider:"daytona"})}var re=`import base64,os,selectors,signal,subprocess,sys,time,shutil,fcntl
2
+ command,directory,cwd,limit,activity=sys.argv[1:]
3
+ if activity:
4
+ os.makedirs(os.path.dirname(activity),exist_ok=True)
5
+ os.mkdir(activity,mode=0o700)
6
+ os.makedirs(directory,mode=0o700,exist_ok=True)
7
+ cancel=directory+"/cancel"
8
+ with open(directory+"/lock","w") as lock:
9
+ fcntl.flock(lock,fcntl.LOCK_EX)
10
+ if os.path.exists(cancel):
11
+ print("R:0:1:1")
12
+ sys.exit(0)
13
+ p=subprocess.Popen(["sh","-c",'cd "$1" || exit; exec sh -c "$2"',"sh",cwd,command],stdin=subprocess.DEVNULL,stdout=subprocess.PIPE,stderr=subprocess.PIPE,start_new_session=True)
14
+ with open(directory+"/pid","w") as f: f.write(str(p.pid))
15
+ s=selectors.DefaultSelector()
16
+ s.register(p.stdout,selectors.EVENT_READ,"O")
17
+ s.register(p.stderr,selectors.EVENT_READ,"E")
18
+ deadline=time.monotonic()+float(limit)
19
+ timedout=False
20
+ size=0
21
+ spill=None
22
+ try:
23
+ while s.get_map() or p.poll() is None:
24
+ if not timedout and (time.monotonic()>=deadline or os.path.exists(cancel)):
25
+ timedout=True
26
+ try: os.killpg(p.pid,signal.SIGKILL)
27
+ except ProcessLookupError: pass
28
+ for key,_ in s.select(0.02):
29
+ data=os.read(key.fileobj.fileno(),4096)
30
+ if not data: s.unregister(key.fileobj); continue
31
+ frame=key.data+":"+base64.b64encode(data).decode()+"\\n"
32
+ size+=len(frame)
33
+ if size>65536:
34
+ if spill is None: spill=open(directory+"/output","w")
35
+ spill.write(frame)
36
+ else: sys.stdout.write(frame)
37
+ code=p.wait()
38
+ print("R:%d:%d:%d"%(code if code>=0 else 128-code,timedout,spill is not None))
39
+ except BaseException:
40
+ try: os.killpg(p.pid,signal.SIGKILL)
41
+ except ProcessLookupError: pass
42
+ p.wait()
43
+ raise
44
+ finally:
45
+ if activity: shutil.rmtree(activity,ignore_errors=True)
46
+ if spill is not None: spill.close()
47
+ else: shutil.rmtree(directory)
48
+ `,ae=`import os,signal,sys,fcntl
49
+ p=sys.argv[1]
50
+ for attempt in range(3):
51
+ try:
52
+ os.makedirs(p,mode=0o700,exist_ok=True)
53
+ with open(p+"/lock","w") as lock:
54
+ fcntl.flock(lock,fcntl.LOCK_EX)
55
+ open(p+"/cancel","w").close()
56
+ try:
57
+ with open(p+"/pid") as f: pid=int(f.read())
58
+ os.killpg(pid,signal.SIGKILL)
59
+ except (FileNotFoundError,ProcessLookupError): pass
60
+ break
61
+ except FileNotFoundError:
62
+ if attempt==2: raise
63
+ `;async function W(s,a,y=F,S){if(a.signal?.aborted)return{exitCode:null,timedOut:!0};let m=Date.now()+a.timeoutMs,l=new AbortController,u,f=!1,b=()=>{},C=new Promise((g)=>{b=g}),h=`/tmp/.sandbox-sdk/exec/sdk-${crypto.randomUUID()}`,p=!0,x=!1,k,A,t=()=>{if(f=!0,b(),l.abort(),u?.destroy(),x)return;k??=s.process.executeCommand(`python3 -c ${v(ae)} ${v(h)}`,"/",void 0,10).then((g)=>{if(g.exitCode!==0)throw Error("Cancellation failed")}).catch((g)=>{A=g})},n={stdout:new TextDecoder("utf-8",{ignoreBOM:!0}),stderr:new TextDecoder("utf-8",{ignoreBOM:!0})},r=()=>new e("Buffered output is incomplete or malformed. Daytona did not confirm exact output and exit. Inspect or destroy the sandbox before retrying.",{code:"outcome_unknown",provider:"daytona",sandboxId:s.id}),i=(g)=>{let I=/^(O|E):([A-Za-z0-9+/]*={0,2})$/.exec(g);if(!I||g.length>5466||Buffer.from(I[2]??"","base64").toString("base64")!==I[2])throw r();let c=I[1]==="O"?"stdout":"stderr",E=n[c].decode(Buffer.from(I[2]??"","base64"),{stream:!0});if(E)a.onChunk({stream:c,text:E})};a.signal?.addEventListener("abort",t,{once:!0});let d=setTimeout(t,Math.max(0,m-Date.now()));try{let g=await s.process.executeCommand(`${y?`${y} && `:""}python3 -u -c ${v(re)} ${v(a.command)} ${v(h)} ${v(a.cwd)} ${v(String(a.timeoutMs/1000))} ${v(a.activityPath??"")}`,"/",a.env,Math.ceil(a.timeoutMs/1000)+15),I=g.result.trimEnd().split(`
64
+ `),c=/^R:(\d+):([01]):([01])$/.exec(I.pop()??"");if(g.exitCode!==0||!c)throw r();x=!0,S?.(),p=c[3]==="1";for(let _ of I)if(_)i(_);if(c[3]==="1"){let _=m-Date.now();if(_<=0)t();if(!f){let N=async()=>{let R=await s.fs.downloadFileStream(`${h}/output`,{signal:l.signal,timeout:Math.max(1,Math.ceil(_/1000))});if(u=R,f){R.destroy();return}let P="";for await(let q of R){if(f)return;if(!(q instanceof Uint8Array))throw r();P+=Buffer.from(q).toString("ascii");let M;while((M=P.indexOf(`
65
+ `))>=0)i(P.slice(0,M)),P=P.slice(M+1);if(P.length>5466)throw r()}if(P)throw r()};await Promise.race([N(),C])}if(f)return{exitCode:null,timedOut:!0}}for(let _ of["stdout","stderr"]){let N=n[_].decode();if(N)a.onChunk({stream:_,text:N})}if(await k,A!==void 0)throw r();let E=c[2]==="1"||f;return{exitCode:E?null:Number(c[1]),timedOut:E}}catch(g){if(x&&f)return{exitCode:null,timedOut:!0};if(!x)t(),await k,await s.stop();if(await k,A!==void 0)throw r();throw g}finally{if(clearTimeout(d),a.signal?.removeEventListener("abort",t),await k,k||p)await s.fs.deleteFile(h,!0).catch(()=>{});if(a.activityPath&&k)await s.fs.deleteFile(a.activityPath,!0).catch(()=>{})}}var v=(s)=>`'${s.replace(/'/g,"'\\''")}'`,ie=`import base64,os,selectors,subprocess,sys,shutil
66
+ a=sys.argv[3]
67
+ if a:
68
+ os.makedirs(os.path.dirname(a),exist_ok=True)
69
+ os.mkdir(a,mode=0o700)
70
+ p=subprocess.Popen(["sh","-c",sys.argv[1]],stdin=open(sys.argv[2],"rb"),stdout=subprocess.PIPE,stderr=subprocess.PIPE)
71
+ s=selectors.DefaultSelector()
72
+ s.register(p.stdout,selectors.EVENT_READ,"O")
73
+ s.register(p.stderr,selectors.EVENT_READ,"E")
74
+ while s.get_map():
75
+ for key,_ in s.select():
76
+ data=os.read(key.fileobj.fileno(),4096)
77
+ if data: print(key.data+":"+base64.b64encode(data).decode(),flush=True)
78
+ else: s.unregister(key.fileobj)
79
+ code=p.wait()
80
+ if a: shutil.rmtree(a,ignore_errors=True)
81
+ print("X:",flush=True)
82
+ sys.exit(code if code>=0 else 128-code)
83
+ `,U=(s)=>new Promise((a)=>setTimeout(a,s)),F='if [ ! -w /workspace ]; then sudo -n install -d -o "$(id -u)" -g "$(id -g)" -m 755 /workspace; fi; test -w /workspace';async function G(s,a,y,S=F){let m=`sdk-${crypto.randomUUID()}`,l=`/tmp/.sandbox-sdk/exec/${m}`,u=`${l}/pid`,f=a.signal?.aborted??!1,b,C,h=!1,p=!1,x=!1,k=!1,A=y===void 0,t=()=>{f=!0},n=y===void 0?void 0:setTimeout(t,y);a.signal?.addEventListener("abort",t,{once:!0});async function r(d){if(b===void 0)return;if((await s.process.executeCommand(`/bin/kill -${d} -- -${b} 2>/dev/null || ! /bin/kill -0 -- -${b} 2>/dev/null`,"/",void 0,10)).exitCode!==0)throw new e("Remote process group could not be killed. Cancellation is unconfirmed. Destroy the sandbox before retrying.",{code:"outcome_unknown",provider:"daytona",sandboxId:s.id})}async function i(){if(clearTimeout(n),a.signal?.removeEventListener("abort",t),a.activityPath&&!k)await s.fs.deleteFile(a.activityPath,!0).catch(()=>{});if(h)try{await s.process.deleteSession(m)}catch(d){if(T(d).code!=="not_found")throw d}try{await s.fs.deleteFile(l,!0)}catch(d){if(T(d,s.id,!0).code!=="file_not_found")throw d}}try{if(a.stdin!==void 0)await s.fs.createFolder(l,"700"),await s.fs.uploadFile(Buffer.from(a.stdin),`${l}/stdin`);if(f)return await i(),{pid:0,wait:async()=>({exitCode:null,signal:"SIGKILL"}),stop:async()=>{},detach(){}};await s.process.createSession(m),h=!0;let d=Object.entries(a.env).map(([w,D])=>v(`${w}=${D}`)).join(" "),g=`umask 077; mkdir -p ${v(l)} || exit 1; echo $$ > ${v(`${u}.tmp`)}; mv ${v(`${u}.tmp`)} ${v(u)}; cd ${v(a.cwd)} || exit 1; exec env ${d} python3 -u -c ${v(ie)} ${v(a.command)} ${v(a.stdin===void 0?"/dev/null":`${l}/stdin`)} ${v(a.activityPath??"")}`;if(C=(await s.process.executeSessionCommand(m,{command:`${S?`${S} && `:""}setsid --wait sh -c ${v(g)}`,runAsync:!0,suppressInputEcho:!0})).cmdId,!C)throw new e("Session command has no ID. Daytona did not confirm launch. Inspect or destroy the sandbox.",{code:"outcome_unknown",provider:"daytona",sandboxId:s.id});let c="",E,_=!1,N={stdout:new TextDecoder("utf-8",{ignoreBOM:!0}),stderr:new TextDecoder("utf-8",{ignoreBOM:!0})},R=(w)=>{c+=w;let D;while((D=c.indexOf(`
84
+ `))>=0){let O=c.slice(0,D).replace(/\r$/,"");if(c=c.slice(D+1),!O)continue;if(_)throw new e("Session output continued after completion. Exact output could not be recovered. Retry the command.",{code:"provider",provider:"daytona",sandboxId:s.id});if(O==="X:"){_=!0,k=!0;for(let V of["stdout","stderr"]){let J=N[V].decode();if(!p&&J)a.onChunk({stream:V,text:J})}continue}let K=/^(O|E):([A-Za-z0-9+/]*={0,2})$/.exec(O);if(!K||O.length>5466||Buffer.from(K[2]??"","base64").toString("base64")!==K[2])throw new e("Session output is malformed. Exact output could not be recovered. Retry the command.",{code:"provider",provider:"daytona",sandboxId:s.id});let Z=K[1]==="O"?"stdout":"stderr",X=N[Z].decode(Buffer.from(K[2]??"","base64"),{stream:!0});if(!p&&X)a.onChunk({stream:Z,text:X})}if(_&&c.length)throw new e("Session output continued after completion. Exact output could not be recovered. Retry the command.",{code:"provider",provider:"daytona",sandboxId:s.id});if(c.length>5466)throw new e("Session output frame is too large. Exact output could not be recovered. Retry the command.",{code:"provider",provider:"daytona",sandboxId:s.id})},P=(w)=>{try{if(E===void 0)R(w)}catch(D){E=D}},q=A?Promise.resolve():s.process.getSessionCommandLogs(m,C,P,(w)=>{if(!p)a.onChunk({stream:"stderr",text:w})}).then(()=>{if(c.trim())throw new e("Session output is incomplete. Exact output could not be recovered. Retry the command.",{code:"provider",provider:"daytona",sandboxId:s.id});for(let w of["stdout","stderr"]){let D=N[w].decode();if(!p&&D)a.onChunk({stream:w,text:D})}}),M=!1;q.then(()=>{M=!0},(w)=>{E=w,M=!0});let te=Date.now();while(b===void 0)try{let w=Number((await s.fs.downloadFile(u)).toString());if(!Number.isSafeInteger(w)||w<=1)throw new e("Invalid process group ID. Remote launch was not confirmed. Destroy the sandbox.",{code:"outcome_unknown",provider:"daytona",sandboxId:s.id});b=w}catch(w){if(w instanceof e)throw w;if((await s.process.getSessionCommand(m,C)).exitCode!==void 0){b=0;break}if(Date.now()-te>1e4)throw new e("Process launch was not confirmed. No PID arrived in ten seconds. Destroy the sandbox.",{code:"outcome_unknown",provider:"daytona",sandboxId:s.id});await U(10)}let oe=C,z=(async()=>{try{let w;while(!0){if(x)await new Promise(()=>{});if(E!==void 0&&!f)throw E;if(f&&b)await r("KILL");let D;try{D=await s.process.getSessionCommand(m,oe)}catch(O){if(!A||f)throw O;if(T(O).code==="not_found")return{exitCode:137,signal:"SIGKILL"};await U(1000);continue}if(E!==void 0&&!f)throw E;if(D.exitCode!==void 0){if(f)w??=Date.now();if(M||_||w!==void 0&&Date.now()-w>=1000)return{exitCode:f?null:D.exitCode,signal:f?"SIGKILL":null}}await U(20)}}catch(w){if(b&&!A)await r("KILL");throw w}finally{p=!0,await i().catch(()=>{})}})();z.catch(()=>{});let Y=!1;return{pid:b,wait:()=>z,detach(){x=!0},async stop({graceMs:w}){if(Y)return;if(b)await r("TERM");if(await U(w),b)await r("KILL");await z,Y=!0}}}catch(d){try{if(b)await r("KILL");else if(h)await s.stop()}finally{await i()}throw d}}async function Q(s,a,y=F,S){if(a.streaming!==!0&&a.stdin===void 0)return W(s,a,y,S);let m=await G(s,a,a.timeoutMs,y);if(m.pid>0)S?.();let l=await m.wait();return{exitCode:l.exitCode,timedOut:l.signal==="SIGKILL"}}var H={"sandbox-sdk":"1"},B="sandbox-sdk-key",ce={small:{cpu:1,memoryMb:1024,diskGb:10},medium:{cpu:2,memoryMb:4096,diskGb:10},large:{cpu:4,memoryMb:8192,diskGb:10}};function le(s){let a=typeof s==="string"?ce[s]:s,y=a?.diskGb??10;if(!a||!Number.isInteger(a.cpu)||a.cpu<=0||!Number.isInteger(a.memoryMb)||a.memoryMb<=0||a.memoryMb%1024||!Number.isInteger(y)||y<=0)L("Size requires positive integer CPUs, whole GiB memory (memoryMb divisible by 1024), and integer diskGb");return{cpu:a.cpu,memory:a.memoryMb/1024,disk:y}}function ue(s){if(!Number.isFinite(s)||s<=0)throw new e("Timeout must be positive. Invalid milliseconds supplied. Use a positive finite duration.",{code:"invalid_argument",provider:"daytona"});return Math.ceil(s/60000)}function fe(s){if(typeof s!=="object")return{networkBlockAll:s==="none"};if(!s.allow.length)return{networkBlockAll:!0};if(s.allow.some((a)=>!/^(?:[a-zA-Z0-9](?:[a-zA-Z0-9-]*[a-zA-Z0-9])?\.)*[a-zA-Z0-9](?:[a-zA-Z0-9-]*[a-zA-Z0-9])?$/.test(a)||a.length>253))L("Network allow entries must be DNS hostnames without schemes, ports, commas, or wildcards");return{networkBlockAll:!1,domainAllowList:s.allow.join(",")}}function j(s,a){let y=Date.parse(s.createdAt??"")||a;if(y===void 0||!Number.isFinite(y))throw new e("Sandbox creation time is missing. Daytona returned incomplete metadata. Refresh the sandbox metadata.",{code:"provider",provider:"daytona",sandboxId:s.id});return{id:s.id,key:s.labels[B],labels:{...s.labels},createdAt:y,state:s.state==="started"?"running":s.state==="paused"?"paused":"stopped"}}function ee(s,a){return{path:s,type:a.isDir?"directory":a.mode?.startsWith("L")||a.mode?.startsWith("l")?"symlink":"file",size:a.size??0,modifiedAt:Date.parse(a.modifiedAt||a.modTime||"")||0}}function Ce(s={}){let a,y=new Set,S=(t={})=>{for(let n of Object.values(t))if(n)y.add(n)},m=new Map,l=new Set,u=F,f=new Map,b=new Map,C=new Map;async function h(){return a??=(async()=>{if(!Number.isSafeInteger(s.snapshotTimeoutMs??600000)||(s.snapshotTimeoutMs??600000)<=0||(s.snapshotTimeoutMs??600000)>900000)throw new e("snapshotTimeoutMs must be an integer from 1 to 900000.",{code:"invalid_argument",provider:"daytona"});let t={apiKey:s.apiKey??process.env.DAYTONA_API_KEY,apiUrl:s.baseUrl??s.apiUrl??process.env.DAYTONA_API_URL,target:s.target??process.env.DAYTONA_TARGET??"us",requestTimeoutMs:s.requestTimeoutMs??30000};if(!t.apiKey)throw new e("Daytona API key is missing. Authentication is required. Set DAYTONA_API_KEY or pass apiKey.",{code:"auth",provider:"daytona"});let{Daytona:n}=await o("@daytonaio/sdk","daytona",()=>import("@daytonaio/sdk"));return new n(t)})()}async function p(t,n,r=!1,i=r?"files":"request"){try{return await t()}catch(d){throw T(d,n,r,i,s.apiKey??process.env.DAYTONA_API_KEY,y)}}async function x(t){let n=m.get(t);if(n)return n;let r=await(await h()).get(t);return m.set(t,r),l.add(t),r}let k=(t,n)=>p(async()=>n(await x(t)),t,!0),A={name:"daytona",inlineActivity:!0,keyMode:"best-effort",capabilities:new Set(["snapshot","size","network-policy"]),async create(t){return S(t.env),p(async()=>{if(s.image&&s.snapshot)L("Choose either image or snapshot");let n=t.from===void 0?s.image:void 0,r=t.size===void 0?void 0:le(t.size);if(t.timeoutMs!==void 0&&(t.timeoutMs<60000||!Number.isFinite(t.timeoutMs)))L("Daytona hard lifetime must be at least one minute");let i={...t.labels,...H};if(delete i[B],t.key!==void 0)i[B]=t.key;let d={labels:i,envVars:t.env,public:!1,...fe(t.network),autoStopInterval:t.idleTimeoutMs===void 0?void 0:ue(t.idleTimeoutMs),autoPauseInterval:0,ttlMinutes:t.timeoutMs===void 0?void 0:Math.floor(t.timeoutMs/60000)},g=n?{...d,image:n,resources:r}:{...d,snapshot:t.from??s.snapshot??(r?.cpu===4&&r.memory===8&&r.disk===10?"daytona-large":void 0)},I=Date.now(),c=await(await h()).create(g,{timeout:60});m.set(c.id,c);try{if(t.signal?.aborted)throw new e("Creation aborted. The caller cancelled. Retry when ready.",{code:"aborted",provider:"daytona"});if(r&&!n&&(r.cpu!==c.cpu||r.memory!==c.memory||r.disk!==c.disk)){if(r.disk<c.disk)L("Snapshot disk cannot shrink; choose diskGb at least as large as the snapshot");await c.stop(),await c.resize(r),await c.start()}return l.add(c.id),f.set(c.id,{expiresAt:Date.now()+30000}),j(c,I)}catch(E){throw await c.delete(60,!0),m.delete(c.id),f.delete(c.id),E}},void 0,!1,t.from?"restore":"create")},async list(t){return p(async()=>{let n={...t,...H},r=(d)=>Object.entries(n).every(([g,I])=>d.labels[g]===I),i=new Map;for await(let d of(await h()).list({labels:n}))if(r(d)){if(!m.has(d.id))l.add(d.id);m.set(d.id,d),i.set(d.id,j(d)),f.delete(d.id)}for(let[d,g]of f){if(Date.now()>=g.expiresAt){f.delete(d);continue}let I=m.get(d);if(!I||!r(I))continue;try{let c=await(await h()).get(d);if(f.get(d)!==g||b.has(d)||Date.now()>=g.expiresAt)continue;if(r(c))m.set(d,c),i.set(d,j(c))}catch(c){if(T(c).code!=="not_found")throw c;f.delete(d),m.delete(d)}}return[...i.values()]},void 0,!1,"list")},async find(t){return(await A.list({[B]:t}))[0]},async connect(t){return p(async()=>{let n=await(await h()).get(t);return m.set(t,n),l.add(t),j(n)},t,!1,"connect")},async destroy(t){let n=b.get(t);if(n)return n;let r=p(async()=>{try{await(await x(t)).delete(60,!0)}catch(i){if(T(i).code!=="not_found")throw i}finally{m.delete(t),f.delete(t),l.delete(t)}},t,!1,"destroy");b.set(t,r);try{await r}finally{b.delete(t)}},exec:(t,n)=>(S(n.env),p(async()=>Q(await x(t),n,l.has(t)?u:"",()=>l.delete(t)),t,!1,"exec")),startProcess:(t,n)=>(S(n.env),p(async()=>{let r=await G(await x(t),n,void 0,l.has(t)?u:"");if(r.pid>0)l.delete(t);let i=C.get(t);if(!i)i=new Set,C.set(t,i);return i.add(r.detach),r.wait().finally(()=>i.delete(r.detach)).catch(()=>{}),{pid:r.pid,wait:()=>p(r.wait,t,!1,"process"),stop:(d)=>p(()=>r.stop(d),t,!1,"process")}},t,!1,"process")),async close(t){for(let n of C.get(t)??[])n();C.delete(t)},files:{writeCreatesParents:!0,read:(t,n)=>k(t,async(r)=>new Uint8Array(await r.fs.downloadFile(n))),write:(t,n,r)=>k(t,async(i)=>{if(!l.has(t))return i.fs.uploadFile(Buffer.from(r),n);if((await i.process.codeRun(`import os,base64,subprocess
85
+ subprocess.run(["sh","-c",${JSON.stringify(u)}],check=True)
86
+ p=${JSON.stringify(n)}
87
+ os.makedirs(os.path.dirname(p),exist_ok=True)
88
+ with open(p,"wb") as f: f.write(base64.b64decode(${JSON.stringify(Buffer.from(r).toString("base64"))}))`,void 0,120)).exitCode!==0)throw new e("File write failed. Workspace setup or the native code operation failed. Check guest permissions.",{code:"provider",provider:"daytona",sandboxId:t});l.delete(t)}),list:(t,n)=>k(t,async(r)=>{try{return(await r.fs.listFiles(n)).map((i)=>ee(de.join(n,i.name),i))}catch(i){if(n!=="/workspace"||!l.has(t)||T(i,t,!0).code!=="file_not_found")throw i;return[]}}),stat:(t,n)=>k(t,async(r)=>{try{return ee(n,await r.fs.getFileDetails(n))}catch(i){if(n!=="/workspace"||!l.has(t)||T(i,t,!0).code!=="file_not_found")throw i;return{path:n,type:"directory",size:0,modifiedAt:Date.parse(r.createdAt??"")||Date.now()}}}),remove:(t,n,r)=>k(t,async(i)=>{try{await i.fs.deleteFile(n,r.recursive)}catch(d){if(n!=="/workspace"||!l.has(t)||T(d,t,!0).code!=="file_not_found")throw d}if(n==="/workspace")l.delete(t)}),mkdir:(t,n)=>k(t,async(r)=>{if(!l.has(t))return r.fs.createFolder(n,"755");if((await r.process.executeCommand(`${u} && mkdir -p ${v(n)}`,"/",void 0,10)).exitCode!==0)throw new e("Directory creation failed. Check guest permissions.",{code:"provider",provider:"daytona",sandboxId:t});l.delete(t)})},previewUrl:(t,n)=>p(async()=>{let r=await x(t),i=await r.getPreviewLink(n);return{url:i.url,...r.public?{}:{headers:{"X-Daytona-Preview-Token":i.token}}}},t,!1,"preview"),snapshot:(t)=>p(async()=>{let n=`sdk-${crypto.randomUUID()}`;try{await(await x(t)).createSnapshot(n,(s.snapshotTimeoutMs??600000)/1000)}catch(r){let i=T(r,t,!1,"snapshot",s.apiKey??process.env.DAYTONA_API_KEY,y);throw new e(`Snapshot ${n} did not complete. It may still be creating. Inspect or delete this name with the native snapshot API before retrying.`,{code:i.code,cause:i.cause,provider:"daytona",sandboxId:t,retryable:!1,hint:`Recover snapshot ${n} from source sandbox ${t}.`})}return{id:n}},t,!1,"snapshot"),native(t){let n=m.get(t);if(!n)throw new e("Sandbox is not connected. No local native object exists. Connect the sandbox first.",{code:"not_found",provider:"daytona",sandboxId:t});return n}};return A}export{Ce as daytona};
@@ -0,0 +1,3 @@
1
+ import { SandboxError } from "../../errors.js";
2
+ /** Native messages/causes can contain API keys and command output. Keep them private. */
3
+ export declare function e2bError(cause: unknown, sandboxId?: string, file?: boolean): SandboxError;
@@ -0,0 +1,15 @@
1
+ import type { Sandbox as E2BSandbox } from "e2b";
2
+ import type { Provider } from "../../provider.js";
3
+ export interface E2BOptions {
4
+ /** Defaults to E2B_API_KEY; required on first use. */
5
+ apiKey?: string;
6
+ /** Template name or ID, including custom hardware templates. Defaults to base. */
7
+ template?: string;
8
+ /** Self-hosted domain. Defaults to E2B_DOMAIN, then e2b.app. */
9
+ domain?: string;
10
+ }
11
+ export type E2BProvider = Provider<E2BSandbox, "pause" | "snapshot" | "network-policy">;
12
+ /** E2B's template fixes CPU, RAM and disk; explicit size requests fail closed.
13
+ * Cloud modules are loaded only on first provider I/O, never by importing core.
14
+ */
15
+ export declare function e2b(options?: E2BOptions): E2BProvider;
@@ -0,0 +1 @@
1
+ import{o}from"../../chunk-yed8mvs7.js";import{e}from"../../chunk-gc8zdxyb.js";import{posix as C}from"node:path";function j(r,E,p=!1){if(r instanceof e)return r;let f=r instanceof Error?r.constructor.name:"",w=typeof r==="object"&&r!==null&&"status"in r?r.status:void 0,d="provider";if(f==="AuthenticationError"||w===401||w===403)d="auth";else if(f==="FileNotFoundError")d="file_not_found";else if(["NotFoundError","SandboxNotFoundError"].includes(f)||w===404)d=p?"file_not_found":"not_found";else if(["RateLimitError","NotEnoughSpaceError"].includes(f)||w===429||w===507)d="quota";else if(["ServiceBusyError","SandboxUnreachableError","SandboxNotRunningError"].includes(f)||typeof w==="number"&&w>=500)d="unavailable";else if(f==="TimeoutError"||f==="TimeoutException")d="timeout";else if(f==="AbortError"||typeof r==="object"&&r!==null&&"name"in r&&r.name==="AbortError")d="aborted";else if(f==="InvalidArgumentError"||w===400)d="invalid_argument";let c=d==="auth"?"Check E2B_API_KEY and the E2B domain.":"Check the sandbox, template and E2B service, then retry.";return new e(`E2B request failed. The provider reported ${d}. ${c}`,{code:d,provider:"e2b",sandboxId:E,hint:c,retryable:["quota","unavailable","timeout"].includes(d)})}var A="sandbox-sdk-key",v="/tmp/.sandbox-sdk-workspace-ready",_="sandbox-sdk-deadline",S=(r)=>`'${r.replace(/'/g,`'"'"'`)}'`,T=`flock -x ${v}.lock sh -c ${S(`if [ ! -e ${v} ]; then mkdir -p /workspace && touch ${v} || exit 125; fi`)} || exit 125`,P=(r)=>j(r,void 0,!0).code==="file_not_found"||typeof r==="object"&&r!==null&&("code"in r)&&r.code==="ENOENT",U=(r)=>new Promise((E)=>setTimeout(E,r)),z=(r)=>new e(`${r}. E2B cannot enforce this option. Choose a compatible template or omit the option.`,{code:"unsupported",provider:"e2b"}),q=(r)=>({id:r.sandboxId,key:r.metadata[A],labels:Object.fromEntries(Object.entries(r.metadata).filter(([E])=>![A,_].includes(E))),state:r.state,createdAt:r.startedAt.getTime()}),F=(r)=>({path:r.path,type:r.type==="dir"?"directory":r.type==="symlink"?"symlink":"file",size:r.size,modifiedAt:r.modifiedTime?.getTime()??0});function X(r={}){let E,p=()=>E??=o("e2b","e2b",()=>import("e2b")),f=()=>{let t=r.apiKey??process.env.E2B_API_KEY;if(!t?.trim())throw new e("E2B API key is missing. Authentication is required. Set E2B_API_KEY or pass apiKey.",{code:"auth",provider:"e2b"});return{apiKey:t,domain:r.domain}},w=new Map,d=new Map,c=new Map,B=new Map;function D(t){if(B.has(t))return;let n=()=>{},a=new Promise((s)=>{n=s});B.set(t,{wait:a,release:n})}function O(t){B.get(t)?.release(),B.delete(t)}let x=new Map;async function l(t,n,a=!1){try{return await n()}catch(s){throw j(s,t,a)}}async function N(t){let{Sandbox:n}=await p(),a=await n.getInfo(t,f()),s=Number(a.metadata[_]);if(Number.isFinite(s)&&s>0){if(d.set(t,s),s<=Date.now())throw await n.kill(t,f()),new e("Sandbox lifetime expired. Its hard deadline passed. Create another sandbox.",{code:"not_found",provider:"e2b",sandboxId:t})}let i=await n.connect(t,{...f(),timeoutMs:d.has(t)?Math.max(1,(d.get(t)??0)-Date.now()):void 0});w.set(t,i);try{await i.files.getInfo("/workspace",{user:"root"}),await i.files.write(v,"ready",{user:"root"}),c.delete(t)}catch(u){if(!P(u))throw u;try{await i.files.getInfo(v,{user:"root"}),c.delete(t)}catch(m){if(!P(m))throw m;c.set(t,a.startedAt.getTime())}}if(d.has(t))await i.setTimeout(Math.max(1,(d.get(t)??0)-Date.now()));return O(t),{...a,state:"running"}}async function y(t){if(!w.has(t))await N(t);let n=w.get(t);if(!n)throw new e("Sandbox is detached. No local client exists. Connect first.",{code:"not_found",provider:"e2b",sandboxId:t});return n}async function I(t,n){if(!c.has(t))return;try{await n.files.getInfo(v,{user:"root"}),c.delete(t)}catch(a){if(!P(a))throw a}}async function L(t){let{Sandbox:n}=await p(),a=n.list({...f(),query:{metadata:{...t,"sandbox-sdk":"1"},state:["running","paused"]}}),s=[];while(a.hasNext)s.push(...(await a.nextItems()).map(q));return s}async function K(t,n,a){await t.commands.run(`kill -${a} -- -${n} 2>/dev/null || true`,{user:"root",timeoutMs:1e4,stdin:!1})}async function R(t,n){let a=await y(t),s=c.has(t),i=s?`${T}; cd ${S(n.cwd)} && exec sh -c ${S(n.command)}`:n.command,u=`set -- "$(</proc/$$/stat)" || exit 125; set -- \${1##*) }; [[ "$3" =~ ^[0-9]+$ ]] || exit 125; if [[ "$3" = "$$" ]]; then exec sh -c ${S(i)}; else exec setsid -w sh -c ${S(i)}; fi`,m=await a.commands.run(u,{background:!0,cwd:s?"/":n.cwd,envs:n.env,user:"root",stdin:n.stdin!==void 0,timeoutMs:0,onStdout:(b)=>n.onChunk({stream:"stdout",text:b}),onStderr:(b)=>n.onChunk({stream:"stderr",text:b})}),h=x.get(t)??new Set;x.set(t,h),h.add(m);let g=m.wait().then((b)=>({exitCode:b.exitCode,signal:null}),async(b)=>{let{CommandExitError:k}=await p();if(b instanceof k)return{exitCode:b.exitCode,signal:null};throw b});g.catch(()=>{});try{if(n.stdin!==void 0)try{await m.sendStdin(n.stdin),await m.closeStdin()}catch(k){if(m.exitCode===void 0)throw k}let b=g.then(async(k)=>{if(s)if(k.exitCode>=0&&k.exitCode<128&&k.exitCode!==125)c.delete(t);else await I(t,a);return k}).finally(()=>h.delete(m));return b.catch(()=>{}),{box:a,handle:m,pid:m.pid,result:b}}catch(b){throw await M.destroy(t),b}}let M={name:"e2b",keyMode:"best-effort",capabilities:new Set(["pause","snapshot","network-policy"]),create:(t)=>l(void 0,async()=>{H(t);let{Sandbox:n}=await p(),a=Date.now(),s=t.timeoutMs===void 0?void 0:a+t.timeoutMs,i=await n.create(t.from??r.template??"base",{...f(),envs:t.env,metadata:{...t.labels,"sandbox-sdk":"1",...t.key===void 0?{}:{[A]:t.key},...s===void 0?{}:{[_]:String(s)}},timeoutMs:t.timeoutMs,lifecycle:{onTimeout:"kill",autoResume:!1},...t.network==="none"?{allowInternetAccess:!1}:typeof t.network==="object"?{network:{denyOut:["0.0.0.0/0"],allowOut:t.network.allow}}:{allowInternetAccess:!0}});if(w.set(i.sandboxId,i),s!==void 0)d.set(i.sandboxId,s);try{if(t.signal?.aborted)throw new e("Creation aborted. Cancellation arrived during E2B creation. Retry with a fresh signal.",{code:"aborted",provider:"e2b"});let u=t.network==="none"||typeof t.network==="object"?await i.getInfo():void 0;if(t.network==="none"&&u?.allowInternetAccess!==!1&&!(u?.network?.denyOut?.includes("0.0.0.0/0")&&!u?.network.allowOut?.length))throw z("E2B did not confirm that internet access is disabled");if(typeof t.network==="object"){let m=t.network.allow,h=u?.network?.allowOut??[];if(!u?.network?.denyOut?.includes("0.0.0.0/0")||m.some((g)=>!h.includes(g))||h.some((g)=>!m.includes(g)))throw z("E2B did not confirm the requested outbound allow list")}if(c.set(i.sandboxId,a),t.from!==void 0)await I(i.sandboxId,i);if(t.signal?.aborted)throw new e("Creation aborted during E2B policy confirmation",{code:"aborted",provider:"e2b"});return{id:i.sandboxId,key:t.key,labels:{...t.labels,"sandbox-sdk":"1"},state:"running",createdAt:a}}catch(u){throw await M.destroy(i.sandboxId),u}}),find:(t)=>l(void 0,async()=>{let n=(await L({[A]:t}))[0];return n?M.connect(n.id):void 0}),connect:(t)=>l(t,async()=>q(await N(t))),list:(t)=>l(void 0,()=>L(t)),destroy:(t)=>l(t,async()=>{let{Sandbox:n}=await p();await n.kill(t,f()),w.delete(t),c.delete(t),d.delete(t),O(t);for(let a of x.get(t)??[])await a.disconnect();x.delete(t)}),close:(t)=>l(t,async()=>{D(t);for(let n of x.get(t)??[])await n.disconnect();x.delete(t),w.delete(t)}),native(t){let n=w.get(t);if(!n)throw new e("Sandbox client is detached. There is no cached native object. Connect the sandbox first.",{code:"not_found",provider:"e2b",sandboxId:t});return n},exec:(t,n)=>l(t,async()=>{if(n.signal?.aborted)return{exitCode:null,timedOut:!0};let a=Date.now(),s=!1,i=()=>{},u=new Promise((h)=>{i=()=>{s=!0,h("cancelled")}});n.signal?.addEventListener("abort",i,{once:!0});let m=setTimeout(i,n.timeoutMs);try{let h=await R(t,n);if(n.signal?.aborted||Date.now()-a>=n.timeoutMs)i();let g=s?"cancelled":await Promise.race([h.result,u]);if(g!=="cancelled")return{exitCode:g.exitCode,timedOut:!1};try{await h.handle.kill(),await K(h.box,h.pid,"KILL")}catch(b){throw await M.destroy(t),b}return await h.result.catch(()=>{}),await h.handle.disconnect(),{exitCode:null,timedOut:!0}}finally{clearTimeout(m),n.signal?.removeEventListener("abort",i)}}),files:{writeCreatesParents:!0,read:(t,n)=>l(t,async()=>new Uint8Array(await(await y(t)).files.read(n,{format:"bytes",user:"root"})),!0),write:(t,n,a)=>l(t,async()=>{let s=await y(t);if(x.get(t)?.size)await I(t,s);if(C.normalize(n)==="/workspace"&&c.has(t))throw new e("Cannot write a file over the workspace directory",{code:"invalid_argument",provider:"e2b",sandboxId:t});if(c.has(t)&&C.normalize(n).startsWith("/workspace/"))await s.files.write([{path:n,data:new Uint8Array(a).buffer},{path:v,data:"ready"}],{user:"root"}),c.delete(t);else await s.files.write(n,new Uint8Array(a).buffer,{user:"root"})},!0),list:(t,n)=>l(t,async()=>{try{let a=(await(await y(t)).files.list(n,{user:"root",depth:1})).map(F);if(x.get(t)?.size)await I(t,await y(t));let s=c.get(t);if(C.normalize(n)==="/"&&s!==void 0&&!a.some((i)=>i.path==="/workspace"))a.push({path:"/workspace",type:"directory",size:0,modifiedAt:s});return a}catch(a){if(x.get(t)?.size)await I(t,await y(t));if(C.normalize(n)==="/workspace"&&c.has(t)&&P(a))return[];throw a}},!0),stat:(t,n)=>l(t,async()=>{try{return F(await(await y(t)).files.getInfo(n,{user:"root"}))}catch(a){if(x.get(t)?.size)await I(t,await y(t));let s=c.get(t);if(C.normalize(n)==="/workspace"&&s!==void 0&&P(a))return{path:n,type:"directory",size:0,modifiedAt:s};throw a}},!0),mkdir:(t,n)=>l(t,async()=>{let a=await y(t);if(c.has(t))await a.commands.run(`${T}; mkdir -p ${S(n)}`,{user:"root",cwd:"/",stdin:!1}),c.delete(t);else await a.files.makeDir(n,{user:"root"})},!0),remove:(t,n,a)=>l(t,async()=>{let s=await y(t);if(C.normalize(n)==="/workspace"&&c.has(t))try{await s.commands.run(`${T}; if [ -L /workspace ]; then rm /workspace; else ${a.recursive?"rm -rf":"rmdir"} /workspace; fi`,{user:"root",cwd:"/",stdin:!1}),c.delete(t);return}catch(i){let{CommandExitError:u}=await p();if(!a.recursive&&i instanceof u)throw new e("Directory is not empty. Pass recursive: true.",{code:"invalid_argument",provider:"e2b",sandboxId:t});throw i}if(!a.recursive&&(await s.files.getInfo(n,{user:"root"})).type==="dir"&&(await s.files.list(n,{user:"root",depth:1})).length)throw new e("Directory is not empty. Recursive removal was not requested. Pass recursive: true.",{code:"invalid_argument",provider:"e2b",sandboxId:t});await s.files.remove(n,{user:"root"})},!0)},previewUrl:(t,n)=>l(t,async()=>({url:`https://${(await y(t)).getHost(n)}`})),pause:(t)=>l(t,async()=>{D(t);try{let{Sandbox:n}=await p();await n.pause(t,f()),w.delete(t);for(let a of x.get(t)??[])await a.disconnect()}catch(n){throw O(t),n}}),resume:(t)=>l(t,async()=>{await N(t)}),snapshot:(t)=>l(t,async()=>{let n=await y(t);if(c.has(t))await n.commands.run(T,{user:"root",cwd:"/",stdin:!1}),c.delete(t);return{id:(await n.createSnapshot()).snapshotId}}),startProcess:(t,n)=>l(t,async()=>{let a=await R(t,n);return{pid:a.pid,wait:()=>l(t,async()=>{try{return await a.result}catch{}await B.get(t)?.wait;let s=await(await y(t)).commands.connect(a.handle.pid,{timeoutMs:0});try{return{exitCode:(await s.wait()).exitCode,signal:null}}catch(i){let{CommandExitError:u}=await p();if(i instanceof u)return{exitCode:i.exitCode,signal:null};throw i}}),stop:(s)=>l(t,async()=>{await K(a.box,a.pid,"TERM"),await U(s.graceMs),await a.handle.kill(),await K(a.box,a.pid,"KILL")})}})};return M}function H(r){if(r.size!==void 0)throw z("Machine size is fixed by the E2B template; small, medium, large and custom sizes are unavailable at creation");if(r.idleTimeoutMs!==void 0)throw z("E2B timeouts measure elapsed time, not idle time; idleTimeoutMs is unavailable");if(r.labels[A]!==void 0||r.labels[_]!==void 0)throw new e("Reserved E2B metadata key. SDK lifecycle metadata must not be overwritten. Rename the label.",{code:"invalid_argument",provider:"e2b"})}export{X as e2b};
@@ -0,0 +1,4 @@
1
+ import { AsyncLocalStorage } from "node:async_hooks";
2
+ /** One signal/deadline follows every HTTP 202 poll in an SDK operation. */
3
+ export declare const operationSignal: AsyncLocalStorage<AbortSignal>;
4
+ export declare function deadline<T>(action: () => Promise<T>, ms: number, signal?: AbortSignal): Promise<T>;
@@ -0,0 +1,16 @@
1
+ import { AsyncLocalStorage } from "node:async_hooks";
2
+ import { SandboxError, type ErrorCode } from "../../errors.js";
3
+ type RequestEvidence = {
4
+ status?: number;
5
+ requestId?: string;
6
+ operation?: string;
7
+ };
8
+ export declare const requestEvidence: AsyncLocalStorage<RequestEvidence & {
9
+ deniedValues?: string[];
10
+ backgroundRequestId?: string;
11
+ }>;
12
+ export declare function recordRequest(url: string | URL | Request, method?: string, apiKey?: string): void;
13
+ export declare function recordResponse(response: Response, apiKey: string): void;
14
+ export declare function failure(message: string, code?: ErrorCode, sandboxId?: string, cause?: unknown): SandboxError;
15
+ export declare function freestyleError(error: unknown, sandboxId?: string): SandboxError;
16
+ export {};
@@ -0,0 +1,12 @@
1
+ import type { ExecInput, ExecResult } from "../../provider.js";
2
+ export declare const supervisorPath = "/var/lib/sandbox-sdk-exec-v2.py";
3
+ export declare const supervisor = "import os,sys,marshal,_signal as signal,select,time,fcntl\ndef stdin_file():\n try: return os.fdopen(os.memfd_create('sandbox-sdk-stdin'),'w+b')\n except (AttributeError,OSError):\n import tempfile\n return tempfile.TemporaryFile()\nclass Process:\n def __init__(self,v,env,stdin,session=False):\n if not all(hasattr(os,name) for name in ['posix_spawn','waitstatus_to_exitcode']):\n self.legacy(v,env,stdin,session); return\n directory=os.open('.',os.O_RDONLY)\n r,w=os.pipe(); e,x=os.pipe()\n try:\n os.chdir(v['cwd'])\n error=FileNotFoundError(2,os.strerror(2),'sh')\n signals=[getattr(signal,s) for s in ['SIGPIPE','SIGXFZ','SIGXFSZ'] if hasattr(signal,s)]\n for path in os.get_exec_path(env):\n try:\n self.pid=os.posix_spawn(os.path.join(path,'sh'),['sh','-c',v['command']],env,file_actions=[(os.POSIX_SPAWN_DUP2,stdin.fileno(),0),(os.POSIX_SPAWN_DUP2,w,1),(os.POSIX_SPAWN_DUP2,x,2)],setsid=session,setsigdef=signals)\n break\n except (FileNotFoundError,NotADirectoryError): pass\n except OSError as failure:\n if failure.errno==38: raise NotImplementedError()\n error=failure\n else: raise error\n except NotImplementedError:\n os.close(r); os.close(e)\n self.legacy(v,env,stdin,session); return\n except BaseException:\n os.close(r); os.close(e); raise\n finally:\n os.fchdir(directory); os.close(directory); os.close(w); os.close(x)\n self.stdout=os.fdopen(r,'rb',buffering=0); self.stderr=os.fdopen(e,'rb',buffering=0)\n self.code=None\n def legacy(self,v,env,stdin,session):\n import subprocess\n self.child=subprocess.Popen(['sh','-c',v['command']],cwd=v['cwd'],env=env,stdin=stdin,stdout=subprocess.PIPE,stderr=subprocess.PIPE,start_new_session=session)\n self.pid=self.child.pid; self.stdout=self.child.stdout; self.stderr=self.child.stderr\n def poll(self):\n if hasattr(self,'child'): return self.child.poll()\n if self.code is None:\n pid,status=os.waitpid(self.pid,os.WNOHANG)\n if pid: self.code=os.waitstatus_to_exitcode(status)\n return self.code\n def wait(self):\n if hasattr(self,'child'): return self.child.wait()\n if self.code is None: self.code=os.waitstatus_to_exitcode(os.waitpid(self.pid,0)[1])\n return self.code\n\nroot=sys.argv[1]\nv=marshal.loads(bytes.fromhex(sys.stdin.read()))\nif v.get('files') is not None:\n previous_umask=os.umask(0o077)\n os.makedirs('/workspace',exist_ok=True)\n os.makedirs('/tmp/.sandbox-sdk',exist_ok=True)\n for path,content in v['files']:\n os.makedirs(os.path.dirname(path),exist_ok=True)\n tmp=path+'.'+str(os.getpid())\n try:\n with open(tmp,'w') as f: f.write(content)\n os.replace(tmp,path)\n finally:\n if os.path.exists(tmp): os.unlink(tmp)\n os.umask(previous_umask)\nos.makedirs(root,mode=0o700,exist_ok=True)\n# Keep small completed responses until their request deadline has passed.\n# Sweep expired responses inline, so no ack RPC or background daemon is needed.\nwith open(os.path.dirname(root)+'/.sweep','a') as sweep:\n try: fcntl.flock(sweep,fcntl.LOCK_EX|fcntl.LOCK_NB)\n except BlockingIOError: pass\n else:\n if time.time()-os.fstat(sweep.fileno()).st_mtime>30:\n os.utime(sweep.fileno(),None)\n for entry in os.scandir(os.path.dirname(root)):\n if not entry.name.startswith('run-') or entry.path==root: continue\n try:\n with open(entry.path+'/expires') as f: expired=time.time()>float(f.read())\n if expired:\n import shutil\n shutil.rmtree(entry.path,ignore_errors=True)\n except (FileNotFoundError,NotADirectoryError): pass\na=v.get('activityPath')\ntimed=False\ncode=127\ntry:\n if a:\n os.makedirs(os.path.dirname(a),exist_ok=True)\n with open(a,'w') as f: f.write('1')\n try:\n with open('/var/lib/sandbox-sdk-env.json') as f:\n import json\n saved=json.load(f)\n except FileNotFoundError: saved={}\n env={**os.environ,**saved,**v['env']}\n with stdin_file() as f, open(root+'/out','wb',buffering=0) as out:\n f.write(v.get('stdin','').encode()); f.seek(0)\n with open(root+'/lock','w') as lock:\n fcntl.flock(lock,fcntl.LOCK_EX)\n if os.path.exists(root+'/cancelled'): timed=True; p=None\n else:\n try: p=Process(v,env,f,True)\n except OSError as e:\n out.write(('[\"stderr\",\"'+str(e).encode().hex()+'\"]\\n').encode()); p=None\n if p:\n with open(root+'/pid','w') as m: m.write(str(p.pid))\n if p:\n stdout=p.stdout.fileno(); streams={stdout:'stdout',p.stderr.fileno():'stderr'}\n end=time.monotonic()+v['timeoutMs']/1000\n while streams or p.poll() is None:\n if not timed and time.monotonic()>=end:\n timed=True\n try: os.killpg(p.pid,signal.SIGKILL)\n except ProcessLookupError: pass\n for fd in select.select(list(streams),[],[],.01 if streams else .001)[0]:\n data=os.read(fd,8192)\n if data: out.write(('[\"'+streams[fd]+'\",\"'+data.hex()+'\"]\\n').encode())\n else: del streams[fd]; (p.stdout if fd==stdout else p.stderr).close()\n code=p.wait()\n timed=timed or os.path.exists(root+'/cancelled')\n result='{\"exitCode\":%s,\"timedOut\":%s}'%('null' if timed else str(code if code>=0 else 128-code),str(timed).lower())\n with open(root+'/exit','w') as f: f.write(result)\n size=os.path.getsize(root+'/out')\n with open(root+'/out','rb') as f:\n chunks=[line.decode().strip() for _,line in zip(range(3),f)]\n offset=f.tell()\n if offset==size and not timed:\n with open(root+'/expires','w') as f: f.write(str(time.time()+v['timeoutMs']/1000+5))\n if timed and not p:\n import shutil\n shutil.rmtree(root)\n print('{\"result\":%s,\"chunks\":[%s],\"offset\":%d,\"size\":%d}'%(result,','.join(chunks),offset,size))\nfinally:\n if a:\n try: os.unlink(a)\n except FileNotFoundError: pass\n";
4
+ export interface ExecutionGuest {
5
+ exec(command: string, stdin: string, timeoutMs: number, signal?: AbortSignal): Promise<string>;
6
+ raw(command: string): Promise<string>;
7
+ read(path: string, range: {
8
+ offset: number;
9
+ length: number;
10
+ }, signal?: AbortSignal): Promise<Uint8Array>;
11
+ }
12
+ export declare function execute(g: ExecutionGuest, input: ExecInput, files?: [string, string][]): Promise<ExecResult>;
@@ -0,0 +1,14 @@
1
+ import type { Vm } from "freestyle";
2
+ import type { Provider } from "../../provider.js";
3
+ export interface FreestyleOptions {
4
+ /** Defaults to FREESTYLE_API_KEY; required on first use. */
5
+ apiKey?: string;
6
+ /** API endpoint. Default: https://api.freestyle.sh. */
7
+ baseUrl?: string;
8
+ /** Base snapshot ID or slug. Defaults to freestyle/ubuntu. */
9
+ snapshotId?: string;
10
+ /** Overall deadline for control/file operations, including background polls. Default 30 s. Commands use their run timeout. */
11
+ requestTimeoutMs?: number;
12
+ }
13
+ export type FreestyleProvider = Provider<Vm, "pause" | "snapshot" | "network-policy">;
14
+ export declare function freestyle(options?: FreestyleOptions): FreestyleProvider;
@@ -0,0 +1,133 @@
1
+ import{m}from"../../chunk-z9rjzn28.js";import{a,n,d,h}from"../../chunk-exv1kf89.js";import{o}from"../../chunk-yed8mvs7.js";import{e}from"../../chunk-gc8zdxyb.js";import{createHash as re}from"node:crypto";import{AsyncLocalStorage as ee}from"node:async_hooks";var j=new ee,te=new Set(["v5","vms","fs","read","write","uploads","commit","dir","mkdir","remove","exists","stat","exec-await","firewall","rules","tls","pause","start","snapshot","snapshots","background-requests"]);function G(r){return(r.split("?")[0]??"").split("/").map((p)=>te.has(p)?p:p?":id":"").join("/")}function H(r,p="GET",f){let c=j.getStore();if(!c)return;if(f&&!c.deniedValues?.includes(f))c.deniedValues=[...c.deniedValues??[],f];let g=new URL(r instanceof Request?r.url:r).pathname;if(!g.startsWith("/v5/background-requests/")||!c.operation)c.operation=`${/^(GET|POST|PUT|DELETE|PATCH|HEAD)$/.test(p)?p:"REQUEST"} ${G(g)}`,delete c.backgroundRequestId;delete c.status,delete c.requestId}function B(r,p){let f=j.getStore();if(!f)return;f.status=r.status;let c=r.headers.get("x-freestyle-background-request-id"),g=(v)=>v&&/^[A-Za-z0-9_-]{1,128}$/.test(v)&&!v.includes(p)&&!f.deniedValues?.some((x)=>v.includes(x))?v:void 0;if(g(c))f.backgroundRequestId=g(c);f.requestId=g(r.headers.get("x-request-id"))??g(r.headers.get("x-freestyle-request-id"))??f.backgroundRequestId}function w(r,p="provider",f,c){return new e(p==="auth"?r:`${r}. Check Freestyle configuration and retry.`,{code:p,provider:"freestyle",sandboxId:f,cause:c})}function F(r,p){if(r instanceof e)return r;let f=typeof r==="object"&&r!==null&&"status"in r?r.status:void 0,c={400:"invalid_argument",401:"auth",403:"auth",404:"not_found",402:"quota",408:"timeout",429:"quota",500:"unavailable",502:"unavailable",503:"unavailable",504:"timeout"},g=j.getStore(),v={};if(typeof f==="number"&&Number.isInteger(f)&&f>=100&&f<=599)v.status=f;if(typeof r==="object"&&r!==null){if("code"in r&&typeof r.code==="string"&&/^[A-Z][A-Z0-9_]{0,63}$/.test(r.code)){let k=r.code;if(!g?.deniedValues?.some((I)=>k.includes(I)))v.providerCode=k}if("path"in r&&typeof r.path==="string")v.operation=G(r.path)}if(g?.operation)v.operation=g.operation;if(g?.status===f&&g?.requestId)v.requestId=g.requestId;let x=Object.keys(v).length?Object.assign(Error(JSON.stringify(v)),v):void 0;return w("Freestyle request failed",typeof f==="number"?c[f]??"provider":r instanceof Error&&(r.name==="TimeoutError"||r.name==="AbortError")?r.name==="TimeoutError"?"timeout":"aborted":r instanceof Error&&r.name==="FreestyleTransportError"?"unavailable":"provider",p,x)}var K=`import os,sys,marshal,_signal as signal,select,time,fcntl
2
+ ${d}
3
+ root=sys.argv[1]
4
+ v=marshal.loads(bytes.fromhex(sys.stdin.read()))
5
+ if v.get('files') is not None:
6
+ previous_umask=os.umask(0o077)
7
+ os.makedirs('/workspace',exist_ok=True)
8
+ os.makedirs('/tmp/.sandbox-sdk',exist_ok=True)
9
+ for path,content in v['files']:
10
+ os.makedirs(os.path.dirname(path),exist_ok=True)
11
+ tmp=path+'.'+str(os.getpid())
12
+ try:
13
+ with open(tmp,'w') as f: f.write(content)
14
+ os.replace(tmp,path)
15
+ finally:
16
+ if os.path.exists(tmp): os.unlink(tmp)
17
+ os.umask(previous_umask)
18
+ os.makedirs(root,mode=0o700,exist_ok=True)
19
+ # Keep small completed responses until their request deadline has passed.
20
+ # Sweep expired responses inline, so no ack RPC or background daemon is needed.
21
+ with open(os.path.dirname(root)+'/.sweep','a') as sweep:
22
+ try: fcntl.flock(sweep,fcntl.LOCK_EX|fcntl.LOCK_NB)
23
+ except BlockingIOError: pass
24
+ else:
25
+ if time.time()-os.fstat(sweep.fileno()).st_mtime>30:
26
+ os.utime(sweep.fileno(),None)
27
+ for entry in os.scandir(os.path.dirname(root)):
28
+ if not entry.name.startswith('run-') or entry.path==root: continue
29
+ try:
30
+ with open(entry.path+'/expires') as f: expired=time.time()>float(f.read())
31
+ if expired:
32
+ import shutil
33
+ shutil.rmtree(entry.path,ignore_errors=True)
34
+ except (FileNotFoundError,NotADirectoryError): pass
35
+ a=v.get('activityPath')
36
+ timed=False
37
+ code=127
38
+ try:
39
+ if a:
40
+ os.makedirs(os.path.dirname(a),exist_ok=True)
41
+ with open(a,'w') as f: f.write('1')
42
+ try:
43
+ with open('/var/lib/sandbox-sdk-env.json') as f:
44
+ import json
45
+ saved=json.load(f)
46
+ except FileNotFoundError: saved={}
47
+ env={**os.environ,**saved,**v['env']}
48
+ with stdin_file() as f, open(root+'/out','wb',buffering=0) as out:
49
+ f.write(v.get('stdin','').encode()); f.seek(0)
50
+ with open(root+'/lock','w') as lock:
51
+ fcntl.flock(lock,fcntl.LOCK_EX)
52
+ if os.path.exists(root+'/cancelled'): timed=True; p=None
53
+ else:
54
+ try: p=Process(v,env,f,True)
55
+ except OSError as e:
56
+ out.write(('["stderr","'+str(e).encode().hex()+'"]\\n').encode()); p=None
57
+ if p:
58
+ with open(root+'/pid','w') as m: m.write(str(p.pid))
59
+ if p:
60
+ stdout=p.stdout.fileno(); streams={stdout:'stdout',p.stderr.fileno():'stderr'}
61
+ end=time.monotonic()+v['timeoutMs']/1000
62
+ while streams or p.poll() is None:
63
+ if not timed and time.monotonic()>=end:
64
+ timed=True
65
+ try: os.killpg(p.pid,signal.SIGKILL)
66
+ except ProcessLookupError: pass
67
+ for fd in select.select(list(streams),[],[],.01 if streams else .001)[0]:
68
+ data=os.read(fd,8192)
69
+ if data: out.write(('["'+streams[fd]+'","'+data.hex()+'"]\\n').encode())
70
+ else: del streams[fd]; (p.stdout if fd==stdout else p.stderr).close()
71
+ code=p.wait()
72
+ timed=timed or os.path.exists(root+'/cancelled')
73
+ result='{"exitCode":%s,"timedOut":%s}'%('null' if timed else str(code if code>=0 else 128-code),str(timed).lower())
74
+ with open(root+'/exit','w') as f: f.write(result)
75
+ size=os.path.getsize(root+'/out')
76
+ with open(root+'/out','rb') as f:
77
+ chunks=[line.decode().strip() for _,line in zip(range(3),f)]
78
+ offset=f.tell()
79
+ if offset==size and not timed:
80
+ with open(root+'/expires','w') as f: f.write(str(time.time()+v['timeoutMs']/1000+5))
81
+ if timed and not p:
82
+ import shutil
83
+ shutil.rmtree(root)
84
+ print('{"result":%s,"chunks":[%s],"offset":%d,"size":%d}'%(result,','.join(chunks),offset,size))
85
+ finally:
86
+ if a:
87
+ try: os.unlink(a)
88
+ except FileNotFoundError: pass
89
+ `;async function W(r,p,f){if(p.signal?.aborted)return{exitCode:null,timedOut:!0};let c=`/tmp/.sandbox-sdk/run-${crypto.randomUUID()}`,g=new AbortController,v=setTimeout(()=>g.abort(),p.timeoutMs),x=p.signal?AbortSignal.any([p.signal,g.signal]):g.signal,k=0,I={stdout:new TextDecoder,stderr:new TextDecoder};async function C(){let q=await r.raw(n(`import os,sys,fcntl,signal,shutil,time,json
90
+ root=sys.argv[1]
91
+ os.makedirs(root,mode=0o700,exist_ok=True)
92
+ with open(root+'/lock','w') as lock:
93
+ fcntl.flock(lock,fcntl.LOCK_EX)
94
+ with open(root+'/cancelled','w') as f: f.write('1')
95
+ try:
96
+ with open(root+'/pid') as f: pid=int(f.read())
97
+ except FileNotFoundError: pid=None
98
+ if pid and not os.path.exists(root+'/exit'):
99
+ try: os.killpg(pid,signal.SIGKILL)
100
+ except ProcessLookupError: pass
101
+ # Wait for reaping and pipe drainage before recovering the bounded output tail.
102
+ end=time.monotonic()+2
103
+ while pid and not os.path.exists(root+'/exit') and time.monotonic()<end: time.sleep(.01)
104
+ if pid and not os.path.exists(root+'/exit'): sys.exit(1)
105
+ chunks=[]
106
+ start=int(sys.argv[2])
107
+ try:
108
+ with open(root+'/out','rb') as f:
109
+ size=os.fstat(f.fileno()).st_size
110
+ delivered=int(sys.argv[2])
111
+ start=max(delivered,size-65536); f.seek(start)
112
+ if start>delivered: f.readline(); start=f.tell()
113
+ chunks=[json.loads(line) for line in f]
114
+ except FileNotFoundError: pass
115
+ print(json.dumps(dict(chunks=chunks,offset=start)))
116
+ # Retain a tombstone if a delayed supervisor can still arrive.
117
+ if pid: shutil.rmtree(root,ignore_errors=True)`,c,String(k))),u=JSON.parse(q);if(!u||typeof u!=="object"||!("chunks"in u)||!Array.isArray(u.chunks)||u.chunks.length>65536||!("offset"in u)||typeof u.offset!=="number"||!Number.isSafeInteger(u.offset)||u.offset<k)throw w("Invalid cancellation output");if(u.offset!==k)V(I,p);for(let t of u.chunks)J(t,I,p);V(I,p)}let D=!1;async function R(){try{await C()}catch{throw w("Process cancellation could not be confirmed","outcome_unknown")}return D=!1,{exitCode:null,timedOut:!0}}try{let q;try{q=await r.exec(`python3 -S -c ${a(K)} ${a(c)}`,m({files:f,command:p.command,env:p.env,cwd:p.cwd,stdin:p.stdin??"",timeoutMs:p.timeoutMs,activityPath:p.activityPath}).toString("hex"),p.timeoutMs+5000,x)}catch(s){try{await C()}catch{throw w("Process cancellation could not be confirmed","outcome_unknown")}if(x.aborted)return{exitCode:null,timedOut:!0};throw s}let u=JSON.parse(q);if(!u||typeof u!=="object"||!("result"in u)||!u.result||typeof u.result!=="object"||!("exitCode"in u.result)||u.result.exitCode!==null&&typeof u.result.exitCode!=="number"||!("timedOut"in u.result)||typeof u.result.timedOut!=="boolean"||!("chunks"in u)||!Array.isArray(u.chunks)||u.chunks.length>3||!("offset"in u)||typeof u.offset!=="number"||!Number.isSafeInteger(u.offset)||u.offset<0||!("size"in u)||typeof u.size!=="number"||!Number.isSafeInteger(u.size)||u.size<u.offset)throw w("Invalid command response");let t=(s)=>J(s,I,p);if(D=u.offset<u.size||u.result.timedOut,x.aborted)return await R();u.chunks.forEach(t),k=u.offset;let i=u.offset,l="";while(i<u.size){if(x.aborted)return await R();let s;try{s=await r.read(c+"/out",{offset:i,length:Math.min(65536,u.size-i)},x)}catch(y){if(x.aborted)return await R();throw y}if(x.aborted)return await R();if(!s.length)throw w("Incomplete output read");i+=s.length,l+=new TextDecoder().decode(s);let b=l.split(`
118
+ `);l=b.pop()??"",b.forEach((y)=>{t(JSON.parse(y)),k+=Buffer.byteLength(y)+1})}if(l)throw w("Incomplete output record");return V(I,p),{exitCode:u.result.exitCode,timedOut:u.result.timedOut}}finally{if(clearTimeout(v),D)await r.raw(`rm -rf -- ${a(c)}`).catch(()=>{})}}function J(r,p,f){if(!Array.isArray(r)||r[0]!=="stdout"&&r[0]!=="stderr"||typeof r[1]!=="string"||r[1].length>21848)throw w("Invalid output record");let c=r[0]==="stdout"?"stdout":"stderr",g=p[c].decode(Buffer.from(r[1],"hex"),{stream:!0});if(g)f.onChunk({stream:c,text:g})}function V(r,p){for(let f of["stdout","stderr"]){let c=r[f].decode();if(c)p.onChunk({stream:f,text:c})}}import{AsyncLocalStorage as oe}from"node:async_hooks";var P=new oe;async function Y(r,p,f){if(f?.aborted)throw w("Operation aborted","aborted");let c=new AbortController,g=()=>c.abort(w("Operation aborted","aborted"));f?.addEventListener("abort",g,{once:!0});let v=setTimeout(()=>c.abort(w("Native operation timed out","timeout")),p),x=()=>{},k=new Promise((I,C)=>{if(x=()=>C(c.signal.reason),c.signal.addEventListener("abort",x,{once:!0}),c.signal.aborted)x()});try{if(c.signal.aborted)throw c.signal.reason;return await Promise.race([P.run(c.signal,r),k])}finally{clearTimeout(v),f?.removeEventListener("abort",g),c.signal.removeEventListener("abort",x)}}var z="/var/lib/sandbox-sdk.json",Z=re("sha256").update(K).digest("hex"),L="sandbox-sdk-info";function se(r){let f=Buffer.from(JSON.stringify({key:r.key??null,labels:r.labels})).toString("base64url").match(/.{1,63}/g)??[];if(f.length>62)throw w("Key and labels exceed Freestyle's native metadata budget","unsupported");return{"sandbox-sdk":"1",[L]:String(f.length),...Object.fromEntries(f.map((c,g)=>[`${L}-${g}`,c]))}}var ne="/var/lib/sandbox-sdk-env.json";function X(r,p){if(r===void 0)return;if(!Number.isSafeInteger(r)||r<=0)throw w("Timeout must be a positive integer","invalid_argument");if(p&&r<1000)throw w("Hard lifetime requires at least one second","unsupported");return p?Math.floor(r/1000):Math.ceil(r/1000)}function ie(r){if(r.network==="none"||typeof r.network==="object"&&r.network.allow.length===0)return[];if(typeof r.network==="object")throw w("Host allow lists are not implemented; use all or none","unsupported");return[{action:"allow",source:{},destination:{public:!0}}]}function Se(r={}){let p,f=new Map,c=new Map,g=new Map,v=r.requestTimeoutMs??30000;async function x(){return p??=(async()=>{if(!Number.isSafeInteger(v)||v<=0)throw w("requestTimeoutMs must be a positive integer","invalid_argument");let t=r.apiKey??process.env.FREESTYLE_API_KEY;if(!t?.trim())throw w("Freestyle API key is missing. Authentication is required. Set FREESTYLE_API_KEY or pass apiKey.","auth");let{Freestyle:i,FreestyleApiError:l,FreestyleClient:s}=await o("freestyle","freestyle",()=>import("freestyle")),b=new s({apiKey:t,baseUrl:r.baseUrl});return new i({apiKey:t,baseUrl:r.baseUrl,fetch:async(y,S)=>{let E=P.getStore()??AbortSignal.timeout(v),T=()=>new l(408,{code:"SDK_DEADLINE",message:"Native operation stopped"});if(E.aborted)throw T();H(y,S?.method,t);try{let _=await b.fetch(y instanceof Request?y.url:String(y),{...S,signal:S?.signal?AbortSignal.any([E,S.signal]):E});return B(_,t),_}catch(_){if(E.aborted)throw T();throw _}}})})()}async function k(t,i,l,s=v){return j.run({deniedValues:j.getStore()?.deniedValues},async()=>{try{return await Y(i,s,l??P.getStore())}catch(b){throw F(b,t)}})}async function I(t){let i=f.get(t);if(!i)i=(await x()).vms.ref(t),f.set(t,i);return i}async function C(t,i,l,s){let b=c.get(t.id);if(!b)return t.exec({command:i,stdin:l,linuxUser:"root",timeoutMs:s});let y=await t.exec({command:n(`import os,sys,json,tempfile,base64
119
+ v=json.load(sys.stdin)
120
+ for path in ['/workspace','/tmp/.sandbox-sdk']:
121
+ os.makedirs(path,exist_ok=True)
122
+ for path,content in v['files']:
123
+ os.makedirs(os.path.dirname(path),exist_ok=True)
124
+ fd,tmp=tempfile.mkstemp(dir=os.path.dirname(path))
125
+ try:
126
+ with os.fdopen(fd,'w') as f: f.write(content)
127
+ os.replace(tmp,path)
128
+ finally:
129
+ if os.path.exists(tmp): os.unlink(tmp)
130
+ with tempfile.TemporaryFile() as f:
131
+ f.write(base64.b64decode(v.get('stdin') or '')); f.seek(0); os.dup2(f.fileno(),0)
132
+ print('SDK_PREPARED:',end='',flush=True)
133
+ os.execvp('sh',['sh','-c',v['command']])`),stdin:Buffer.from(JSON.stringify({files:b,command:i,stdin:l})).toString("base64"),linuxUser:"root",timeoutMs:s});if(y.stdout?.startsWith("SDK_PREPARED:"))return c.delete(t.id),{...y,stdout:y.stdout.slice(13)};return y}async function D(t){let i=await I(t);return{name:"freestyle",raw:async(l)=>{let s=await k(t,()=>C(i,l,void 0,v));if(s.statusCode!==0)throw w("Guest operation failed",s.statusCode===null?"timeout":"provider",t);return s.stdout??""},upload:(l,s)=>k(t,async()=>{if(c.has(t)){if((await C(i,n("import os,sys; os.makedirs(os.path.dirname(sys.argv[1]),exist_ok=True); f=open(sys.argv[1],'wb'); f.write(sys.stdin.buffer.read()); f.close(); os.chmod(sys.argv[1],0o600)",l),Buffer.from(s).toString("base64"),v)).statusCode!==0)throw w("File upload failed","provider",t)}else await i.fs.writeFile(l,s,{mode:384,signal:P.getStore()})}),read:(l,s)=>k(t,()=>i.fs.readFile(l,{...s,signal:P.getStore()}))}}async function R(t,i=!1){if(t.metadata["sandbox-sdk"]!=="1")throw w("Not an SDK VM","not_found",t.id);let l;if(i&&t.metadata[L]!==void 0){let S=Number(t.metadata[L]);if(!Number.isInteger(S)||S<1||S>62)throw w("Invalid SDK metadata","not_found",t.id);let E="";for(let T=0;T<S;T++){let _=t.metadata[`${L}-${T}`];if(!_||!/^[A-Za-z0-9_-]{1,63}$/.test(_))throw w("Invalid SDK metadata","not_found",t.id);E+=_}l=Buffer.from(E,"base64url").toString()}else l=await(await I(t.id)).fs.readTextFile(z);let s;try{s=JSON.parse(l)}catch{throw w("Invalid SDK metadata","not_found",t.id)}if(!s||typeof s!=="object"||!("key"in s)||s.key!==null&&typeof s.key!=="string"||!("labels"in s)||!s.labels||(typeof s.labels!=="object"||Array.isArray(s.labels)))throw w("Invalid SDK metadata","not_found",t.id);let b={};for(let[S,E]of Object.entries(s.labels)){if(typeof E!=="string")throw w("Invalid SDK label","not_found",t.id);Object.defineProperty(b,S,{value:E,enumerable:!0})}let y=Date.parse(t.createdAt);if(!Number.isFinite(y))throw w("Invalid VM creation time","provider",t.id);return{supervisorHash:"supervisorHash"in s&&typeof s.supervisorHash==="string"?s.supervisorHash:void 0,info:{id:t.id,key:s.key??void 0,labels:b,createdAt:y,state:t.state==="running"?"running":t.state==="paused"||t.state==="pausing"?"paused":"stopped"}}}async function q(t,i=!1){return(await R(t,i)).info}let u={name:"freestyle",keyMode:"best-effort",inlineActivity:!0,capabilities:new Set(["pause","snapshot","network-policy"]),create:(t)=>k(void 0,async()=>{let i=j.getStore();if(i)i.deniedValues=Object.values(t.env??{}).filter(Boolean);if(t.size!==void 0)throw w("Explicit sizes are not implemented; select a base snapshot instead","unsupported");let l=ie(t),s=X(t.idleTimeoutMs,!1),b=X(t.timeoutMs,!0);if(t.signal?.aborted||P.getStore()?.aborted)throw w("Creation aborted","aborted");let y={snapshotId:t.from??r.snapshotId??"freestyle/ubuntu",metadata:se(t),firewall:{rules:l},tls:{rules:[]},vpcs:[],idleTimeoutSeconds:s??-1,ttlSeconds:b},S,E=Date.now(),T=await x();try{S=await T.vms.create(y)}catch(N){let O=F(N);if(O.code==="unavailable"||O.code==="timeout")throw w("VM creation outcome is unknown; inspect the account before retrying","outcome_unknown",void 0,O.cause);throw N}let{vm:_,vmId:A,data:M,firewallRules:U,tlsRules:Q}=S;f.set(A,_);try{if(t.signal?.aborted||P.getStore()?.aborted)throw w("Creation aborted","aborted");if(s!==void 0&&M.idleTimeoutSeconds!==s||b!==void 0&&M.ttlSeconds!==b)throw w("Freestyle did not confirm requested limits","unsupported",A);if(M.vpcs.length||U.length!==l.length||U.some((O)=>O.action!=="allow"||Object.keys(O.source).length!==1||O.source.vmId!==A||Object.keys(O.destination).length!==1||O.destination.public!==!0))throw w("Freestyle did not confirm the requested firewall","unsupported",A);if(Q.length)throw w("Unexpected TLS egress grants","unsupported",A);let N=[[z,JSON.stringify({key:t.key??null,labels:t.labels,supervisorHash:Z})]];if(Object.keys(t.env??{}).length||t.from!==void 0||r.snapshotId!==void 0)N.push([ne,JSON.stringify(t.env??{})]);if(c.set(A,N),Object.keys(t.env??{}).length||t.from!==void 0||r.snapshotId!==void 0){if((await C(_,"true",void 0,v)).statusCode!==0)throw w("Guest setup failed","provider",A)}return await q({...M,createdAt:M.createdAt||new Date(E).toISOString(),state:"running"},!0)}catch(N){throw await P.exit(()=>u.destroy(A)),N}},t.signal).catch((i)=>{let l=F(i);if(l.code==="timeout")throw w("VM creation outcome is unknown; inspect the account before retrying","outcome_unknown",void 0,l.cause);throw l}),list:(t)=>k(void 0,async()=>{let i=[],l=0;while(!0){let s=await(await x()).vms.list({limit:100,offset:l});for(let b of s.vms){if(b.metadata["sandbox-sdk"]!=="1")continue;try{let y=await q(b,!0);if(Object.entries(t).every(([S,E])=>y.labels[S]===E))i.push(y)}catch(y){if(F(y,b.id).code!=="not_found")throw y}}if(l+=s.vms.length,l>=s.totalCount)break;if(!s.vms.length)throw w("VM list ended before all pages were returned")}return i}),async find(t){let i=(await u.list({})).find((l)=>l.key===t);if(!i)return;try{return await u.connect(i.id)}catch(l){if(F(l,i.id).code!=="not_found")throw l;return}},connect:(t)=>k(t,async()=>{let i=await x(),l=await i.vms.get(t);f.set(t,i.vms.ref(t));let s;try{s=await R(l)}catch(b){if(!["file_not_found","not_found"].includes(F(b,t).code))throw b;s=await R(l,!0),c.set(t,[[z,JSON.stringify({key:s.info.key??null,labels:s.info.labels,supervisorHash:Z})]])}return s.info}),destroy:(t)=>k(t,async()=>{try{await(await x()).vms.delete(t)}catch(i){if(F(i).code!=="not_found")throw i}f.delete(t),c.delete(t);for(let i of g.keys())if(i.startsWith(t+":"))g.delete(i)}),async close(t){f.delete(t)},exec:async(t,i)=>{try{if(!f.has(t))await u.connect(t);let l=await I(t),s=await D(t),b=c.get(t),y=await W({raw:s.raw,read:(S,E,T)=>k(t,()=>l.fs.readFile(S,{...E,signal:P.getStore()}),T),exec:(S,E,T,_)=>k(t,async()=>{let A=await l.exec({command:S,stdin:Buffer.from(E).toString("base64"),linuxUser:"root",timeoutMs:T});if(A.statusCode!==0||!A.stdout)throw w("Guest execution failed","provider",t);return A.stdout},_,T)},i,b);if(!y.timedOut&&c.get(t)===b)c.delete(t);return y}catch(l){throw F(l,t)}},files:h(D,k),previewUrl:(t,i)=>k(t,async()=>{let l=`${t}:${i}`,s=g.get(l);if(s)return{url:s};let b=`sdk-${crypto.randomUUID()}.style.dev`,y=await(await x()).tls.rules.create({action:"allow",domain:b,source:{public:!0},destination:{vmId:t,port:i}});if(y.domain!==b)throw w("Freestyle returned a different preview domain","provider",t);let S=`https://${y.domain}`;return g.set(l,S),{url:S}}),pause:(t)=>k(t,async()=>{await(await I(t)).pause()}),resume:(t)=>k(t,async()=>{await(await I(t)).start()}),snapshot:(t)=>k(t,async()=>({id:(await(await I(t)).snapshot()).snapshotId})),native(t){let i=f.get(t);if(!i)throw w("Connect the VM first","not_found",t);return i}};return u}export{Se as freestyle};
@@ -0,0 +1,10 @@
1
+ import type { ExecInput } from "../../provider.js";
2
+ type Spec = Pick<ExecInput, "command" | "cwd" | "env" | "stdin" | "timeoutMs" | "activityPath"> & {
3
+ marker?: string;
4
+ workspace?: string;
5
+ files?: [string, string][];
6
+ };
7
+ export declare function guestSpec(spec: Spec | (Omit<Spec, "env" | "stdin"> & {
8
+ envKeys: string[];
9
+ })): Buffer;
10
+ export {};
@@ -0,0 +1,32 @@
1
+ import { SandboxError, type ErrorCode } from "../../errors.js";
2
+ import type { OutputChunk } from "../../provider.js";
3
+ export declare const failure: (message: string, code?: ErrorCode) => SandboxError;
4
+ export declare function object(value: unknown): Record<string, unknown>;
5
+ export declare function string(value: unknown): string;
6
+ export declare function number(value: unknown): number;
7
+ export declare function array(value: unknown): unknown[];
8
+ export declare const encode: typeof encodeURIComponent;
9
+ export declare function parse(text: string): unknown;
10
+ /** Docker's eight-byte framing can span arbitrary HTTP/TCP chunks. */
11
+ export declare class Demux {
12
+ private readonly emit;
13
+ private pending;
14
+ private readonly stdout;
15
+ private readonly stderr;
16
+ constructor(emit: (chunk: OutputChunk) => void);
17
+ push(data: Buffer): void;
18
+ end(): void;
19
+ }
20
+ export declare class Docker {
21
+ readonly socketPath: string;
22
+ private connectionPool;
23
+ private pool;
24
+ constructor(host?: string);
25
+ call(method: string, path: string, body?: unknown): Promise<unknown>;
26
+ exec(id: string, command: string[], options: {
27
+ cwd?: string;
28
+ env?: Record<string, string>;
29
+ stdin?: string;
30
+ onChunk(chunk: OutputChunk): void;
31
+ }): Promise<number>;
32
+ }
@@ -0,0 +1,17 @@
1
+ import type { Provider } from "../../provider.js";
2
+ import { Docker } from "./docker.js";
3
+ export interface LocalOptions {
4
+ /** Default: node:22-bookworm; requires git, tar, setsid, nohup, mkfifo and GNU sed. */
5
+ image?: string;
6
+ /** Defaults to DOCKER_HOST, then unix:///var/run/docker.sock; absolute unix:// sockets only. */
7
+ dockerHost?: string;
8
+ }
9
+ export interface LocalNative {
10
+ readonly id: string;
11
+ readonly client: Docker;
12
+ }
13
+ type LocalCapability = "pause" | "snapshot" | "size" | "network-policy";
14
+ export type LocalProvider = Provider<LocalNative, LocalCapability>;
15
+ /** Local Docker Engine transport. No Docker CLI or daemon inside the container. */
16
+ export declare function local(options?: LocalOptions): LocalProvider;
17
+ export {};
@@ -0,0 +1,2 @@
1
+ import{e}from"../../chunk-gc8zdxyb.js";import{createHash as W,randomUUID as R}from"node:crypto";import{Agent as G,request as j}from"node:http";import{StringDecoder as q}from"node:string_decoder";var a=(r,o="provider")=>new e(`${r}. Docker request failed. Check Docker access and the supplied options.`,{code:o,provider:"local"});function p(r){if(!r||typeof r!=="object"||Array.isArray(r))throw a("Invalid Docker response");return Object.fromEntries(Object.entries(r))}function C(r){if(typeof r!=="string")throw a("Expected a Docker string");return r}function M(r){if(typeof r!=="number"||!Number.isFinite(r))throw a("Expected a Docker number");return r}function N(r){if(!Array.isArray(r))throw a("Expected a Docker array");return r}var w=encodeURIComponent;function D(r){try{return JSON.parse(r)}catch{throw a("Malformed Docker JSON response")}}class B{emit;pending=Buffer.alloc(0);stdout=new q("utf8");stderr=new q("utf8");constructor(r){this.emit=r}push(r){this.pending=Buffer.concat([this.pending,r]);while(this.pending.length>=8){let o=this.pending.readUInt32BE(4);if(o>67108864||![1,2].includes(this.pending[0]??0))throw a("Invalid Docker exec frame");if(this.pending.length<o+8)return;let g=this.pending[0]===1?"stdout":"stderr",k=this[g].write(this.pending.subarray(8,o+8));if(k)this.emit({stream:g,text:k});this.pending=this.pending.subarray(o+8)}}end(){if(this.pending.length)throw a("Truncated Docker exec frame");for(let r of["stdout","stderr"]){let o=this[r].end();if(o)this.emit({stream:r,text:o})}}}class A{socketPath;connectionPool;pool(){return this.connectionPool??=new G({keepAlive:!0,timeout:5000})}constructor(r=process.env.DOCKER_HOST??"unix:///var/run/docker.sock"){if(!r.startsWith("unix://")||!r.slice(7).startsWith("/"))throw a("DOCKER_HOST must be an absolute unix:// socket URL; remote Docker hosts cannot provide localhost previews","unsupported");this.socketPath=r.slice(7)}async call(r,o,g){let k=g===void 0?void 0:JSON.stringify(g),h=await new Promise((x,f)=>{let m=j({agent:this.pool(),socketPath:this.socketPath,path:`/v1.44${o}`,method:r,headers:{"Content-Type":"application/json"}},(d)=>{let v=[];d.on("data",(S)=>v.push(S)),d.on("error",(S)=>f(a(S.message,"unavailable"))),d.on("end",()=>{let S=Buffer.concat(v);if((d.statusCode??500)>=400){f(a(S.toString(),d.statusCode===404?"not_found":d.statusCode===401||d.statusCode===403?"auth":"provider"));return}x(S)})});m.setTimeout(600000,()=>m.destroy(a("Docker API timed out","timeout"))),m.on("error",(d)=>f(d instanceof e?d:a(d.message,"unavailable"))),m.end(k)});if(!h.length)return;if(o.startsWith("/images/create")){for(let x of h.toString().trim().split(`
2
+ `)){let f=p(D(x));if(f.error)throw a(`Image pull: ${C(f.error)}`)}return}return D(h.toString())}async exec(r,o,g){let k=p(await this.call("POST",`/containers/${w(r)}/exec`,{Cmd:o,WorkingDir:g.cwd??"/",Env:Object.entries(g.env??{}).map(([f,m])=>`${f}=${m}`),AttachStdout:!0,AttachStderr:!0,AttachStdin:g.stdin!==void 0,Tty:!1})),h=C(k.Id);await new Promise((f,m)=>{let d=new B(g.onChunk),v=j({agent:this.pool(),socketPath:this.socketPath,path:`/v1.44/exec/${w(h)}/start`,method:"POST",headers:{"Content-Type":"application/json",Connection:"Upgrade",Upgrade:"tcp"}}),S=(l)=>{l.on("data",(t)=>{try{d.push(t)}catch(n){l.destroy(),m(n)}}),l.on("error",(t)=>m(a(t.message,"unavailable"))),l.on("end",()=>{try{d.end(),f()}catch(t){m(t)}})};v.on("upgrade",(l,t,n)=>{if(t.setTimeout(0),S(t),n.length)try{d.push(n)}catch(s){t.destroy(),m(s);return}t.end(g.stdin??"")}),v.on("response",(l)=>{if((l.statusCode??500)>=400){l.resume(),m(a(`Exec attach HTTP ${l.statusCode}`));return}S(l)}),v.on("error",(l)=>m(a(l.message,"unavailable"))),v.setTimeout(30000,()=>v.destroy(a("Exec attach timed out","timeout"))),v.end(JSON.stringify({Detach:!1,Tty:!1}))});let x=p(await this.call("GET",`/exec/${w(h)}/json`));if(x.Running)throw a("Exec attachment ended before the process exited","outcome_unknown");return M(x.ExitCode)}}var H="sandbox-sdk.local.deadline",F="sandbox-sdk.local.idle-ms",T="/tmp/.sandbox-sdk-activity",z="sandbox-sdk.local.key",U=(r)=>`sandbox-sdk-${W("sha256").update(r).digest("hex")}`,L=(r)=>`'${r.replace(/'/g,"'\\''")}'`,K={small:{cpu:1,memoryMb:1024},medium:{cpu:2,memoryMb:4096},large:{cpu:4,memoryMb:8192}};function X(r){if(!r)return{};if(typeof r!=="string")throw a("Custom sizes include diskGb, which Docker cannot enforce portably; use small, medium, or large","unsupported");let o=K[r];if(!o)throw a("Unknown size preset","unsupported");return{NanoCpus:o.cpu*1e9,Memory:o.memoryMb*1024*1024,MemorySwap:o.memoryMb*1024*1024}}function _(r){let o=p(r),g=p(o.Config),k=p(o.State),h=Object.fromEntries(Object.entries(p(g.Labels??{})).map(([x,f])=>[x,C(f)]));if(h["sandbox-sdk"]!=="1")throw a("Container was not created by Sandbox SDK","not_found");return{id:C(o.Id),key:h[z]||void 0,labels:h,state:k.Paused?"paused":k.Running?"running":"stopped",createdAt:Date.parse(C(o.Created))}}function re(r={}){let o=new A(r.dockerHost),g=r.image??"node:22-bookworm",k=new Map,h=new Set,x=new Map,f=(t)=>o.call("GET",`/containers/${w(t)}/json`);async function m(t,n,s){let i="",c="",u=h.has(t)?["sh","-c",`touch ${T}; "$@"; code=$?; touch ${T}; exit "$code"`,"sh",...n]:n,O=await o.exec(t,u,{stdin:s,onChunk(P){if(P.stream==="stdout")i+=P.text;else c+=P.text}});if(O!==0)throw a(`Container operation exited ${O}: ${c}`,c.includes("ENOENT")||c.includes("No such file")?"file_not_found":"provider");return i}let d=(t,n,s=[],i)=>m(t,["node","-e",n,...s],i),v="const fs=require('fs'); const p=require('path'); const stat=x=>{const s=fs.lstatSync(x);return {path:x,type:s.isSymbolicLink()?'symlink':s.isDirectory()?'directory':'file',size:s.size,modifiedAt:s.mtimeMs}};";function S(t){let n=p(t),s=n.type;if(s!=="file"&&s!=="directory"&&s!=="symlink")throw a("Invalid file type");return{path:C(n.path),type:s,size:M(n.size),modifiedAt:M(n.modifiedAt)}}let l={name:"local",keyMode:"exact",capabilities:new Set(["pause","snapshot","size","network-policy"]),async create(t){if(typeof t.network==="object")throw a("Network allow-lists cannot be enforced by this Docker adapter","unsupported");for(let y of[t.idleTimeoutMs,t.timeoutMs])if(y!==void 0&&(!Number.isFinite(y)||y<=0))throw a("Timeouts must be positive milliseconds","invalid_argument");let n=X(t.size);if(t.signal?.aborted)throw a("Creation aborted","aborted");let s={},i=performance.now(),c=t.from??g;try{await o.call("GET",`/images/${w(c)}/json`)}catch(y){if(!(y instanceof e)||y.code!=="not_found")throw y;if(t.from)throw a("Snapshot image not found","not_found");await o.call("POST",`/images/create?fromImage=${w(c)}`)}if(s.createInspectMs=performance.now()-i,t.signal?.aborted)throw a("Creation aborted after image pull","aborted");let u=[...new Set(t.ports??[3000])],O=Object.fromEntries(u.map((y)=>[`${y}/tcp`,[{HostIp:"127.0.0.1",HostPort:""}]]));i=performance.now();let P=Date.now(),I={...t.labels,"sandbox-sdk":"1",[z]:t.key??"",...t.timeoutMs===void 0?{}:{[H]:String(P+t.timeoutMs)},...t.idleTimeoutMs===void 0?{}:{[F]:String(t.idleTimeoutMs)}},E=p(await o.call("POST",`/containers/create?name=${w(t.key?U(t.key):`sandbox-sdk-${R()}`)}`,{Image:c,WorkingDir:"/workspace",Cmd:["sh","-c","exec sleep infinity"],Env:Object.entries(t.env??{}).map(([y,J])=>`${y}=${J}`),Labels:I,ExposedPorts:Object.fromEntries(u.map((y)=>[`${y}/tcp`,{}])),HostConfig:{...n,NetworkMode:t.network==="none"?"none":"bridge",PortBindings:t.network==="none"?{}:O,Init:!0}}));s.createContainerMs=performance.now()-i;let b=C(E.Id);if(x.set(b,s),t.timeoutMs!==void 0||t.idleTimeoutMs!==void 0)h.add(b);try{if(i=performance.now(),await o.call("POST",`/containers/${w(b)}/start`),s.createStartMs=performance.now()-i,s.createPrerequisiteMs=0,t.signal?.aborted)throw a("Creation aborted","aborted");if(t.timeoutMs!==void 0||t.idleTimeoutMs!==void 0)return await l.connect(b);return{id:b,key:t.key,labels:I,state:"running",createdAt:P}}catch(y){throw await l.destroy(b),y}},async find(t){try{let n=await l.connect(U(t));return n.key===t?n:void 0}catch(n){if(n instanceof e&&n.code==="not_found")return;throw n}},async connect(t){let n=_(await f(t)),s=Number(n.labels[H]??1/0),i=Number(n.labels[F]??1/0);if(Number.isFinite(s)||Number.isFinite(i))h.add(n.id);let c=Date.now()>=s;if(!c&&Number.isFinite(i)&&n.state==="running"){let u="";if(await o.exec(n.id,["node","-e",`const f=require('fs'), p='/tmp/.sandbox-sdk';const busy=(f.existsSync(p+'/runs')&&f.readdirSync(p+'/runs').length)||(f.existsSync(p+'/procs')&&f.readdirSync(p+'/procs').some(n=>!f.existsSync(p+'/procs/'+n+'/exit')));process.stdout.write(String(busy?Date.now():f.existsSync('${T}')?f.statSync('${T}').mtimeMs:${n.createdAt}))`],{onChunk(P){if(P.stream==="stdout")u+=P.text}})!==0||!Number.isFinite(Number(u)))throw a("Could not check local idle deadline","provider");c=Date.now()-Number(u)>=i}if(c)throw await l.destroy(n.id),a("Local sandbox deadline expired; create another sandbox","not_found");return n},async list(t){let n=w(JSON.stringify({label:Object.entries({...t,"sandbox-sdk":"1"}).map(([c,u])=>`${c}=${u}`)})),s=N(await o.call("GET",`/containers/json?all=1&filters=${n}`)),i=[];for(let c of s)try{i.push(_(await f(C(p(c).Id))))}catch(u){if(!(u instanceof e)||u.code!=="not_found")throw u}return i},async destroy(t){let n=k.get(t);if(n)return n;let s=(async()=>{try{let i=_(await f(t));if(i.state==="paused")await o.call("POST",`/containers/${w(t)}/unpause`);if(i.state!=="stopped")await o.call("POST",`/containers/${w(t)}/stop?t=1`);await o.call("DELETE",`/containers/${w(t)}?force=1&v=1`)}catch(i){if(!(i instanceof e)||i.code!=="not_found")throw i}})();k.set(t,s);try{await s}finally{k.delete(t),h.delete(t),x.delete(t)}},async exec(t,n){let s=performance.now();if(n.signal?.aborted)return{exitCode:null,timedOut:!0};let i=`/tmp/.sandbox-sdk-exec-${R()}`,c=!1,u=()=>{},O=new Promise((b)=>{u=()=>{c=!0,b("cancelled")}});n.signal?.addEventListener("abort",u,{once:!0});let P=setTimeout(u,n.timeoutMs),I=["setsid","--wait","sh","-c",`echo $$ > ${L(i)}; ${h.has(t)?`touch ${T}; trap 'touch ${T}' EXIT;`:""} sh -c ${L(n.command)}`],E=o.exec(t,I,{cwd:n.cwd,env:n.env,stdin:n.stdin,onChunk:n.onChunk});E.catch(()=>{});try{if(await Promise.race([E,O]),c)await m(t,["sh","-c",`i=0; while [ ! -s ${L(i)} ]; do i=$((i+1)); [ "$i" -lt 3000 ] || exit 1; sleep .01; done; p=$(cat ${L(i)}); node -e 'try {process.kill(-Number(process.argv[1]), "SIGKILL")} catch(e) {if(e.code!=="ESRCH") throw e}' "$p"`]);let b=await E;return{exitCode:c?null:b,timedOut:c}}finally{clearTimeout(P),n.signal?.removeEventListener("abort",u),await m(t,["rm","-f",i]).catch(()=>{});let b=x.get(t);if(b&&b.firstCommandMs===void 0)b.firstCommandMs=performance.now()-s}},files:{writeCreatesParents:!0,async read(t,n){return new Uint8Array(Buffer.from(await d(t,"process.stdout.write(require('fs').readFileSync(process.argv[1]).toString('base64'))",[n]),"base64"))},async write(t,n,s){await d(t,"const f=require('fs');f.mkdirSync(require('path').dirname(process.argv[1]),{recursive:true});f.writeFileSync(process.argv[1],Buffer.from(f.readFileSync(0,'utf8'),'base64'))",[n],Buffer.from(s).toString("base64"))},async stat(t,n){return S(D(await d(t,v+"process.stdout.write(JSON.stringify(stat(process.argv[1])))",[n])))},async list(t,n){return N(D(await d(t,v+"process.stdout.write(JSON.stringify(fs.readdirSync(process.argv[1]).map(x=>stat(p.join(process.argv[1],x)))))",[n]))).map(S)},async mkdir(t,n){await d(t,"require('fs').mkdirSync(process.argv[1],{recursive:true})",[n])},async remove(t,n,s){await d(t,"require('fs').rmSync(process.argv[1],{recursive:process.argv[2]==='true'})",[n,String(s.recursive)])}},async previewUrl(t,n){let s=p(await f(t)),i=p(s.NetworkSettings),c=p(i.Ports??{}),u=N(c[`${n}/tcp`]??[])[0];if(!u)throw a(`Port ${n} has no localhost mapping; declare it in ports when creating the sandbox`,"unsupported");let O=p(u);if(O.HostIp!=="127.0.0.1")throw a("Preview binding is not loopback","unsupported");return{url:`http://127.0.0.1:${C(O.HostPort)}/`}},native(t){return{id:t,client:o}},async usage(t){let n=p(await f(t)),s=p(n.State);return{...x.get(t),runningMs:s.Running&&!s.Paused?Math.max(0,Date.now()-Date.parse(C(s.StartedAt))):0}},async pause(t){await l.connect(t),await o.call("POST",`/containers/${w(t)}/pause`)},async resume(t){await l.connect(t),await o.call("POST",`/containers/${w(t)}/unpause`)},async snapshot(t){await l.connect(t);let n=p(await o.call("POST",`/commit?container=${w(t)}&pause=true`,{Labels:{"sandbox-sdk":"1","sandbox-sdk.local.snapshot":"1"}}));return{id:C(n.Id)}}};return l}export{re as local};
@@ -0,0 +1,4 @@
1
+ import { SandboxError } from "../../errors.js";
2
+ /** Never retain native messages or causes: Railway can include tokens and output. */
3
+ export declare function railwayError(cause: unknown, sandboxId?: string): SandboxError;
4
+ export declare function unsupported(message: string): never;
@@ -0,0 +1,24 @@
1
+ import type { Sandbox, SandboxTemplate, CreateOptions } from "railway";
2
+ import type { Provider } from "../../provider.js";
3
+ export type RailwayOptions = {
4
+ /** Defaults to RAILWAY_API_TOKEN; required for authentication. */
5
+ token?: CreateOptions["token"];
6
+ /** Defaults to RAILWAY_ENVIRONMENT_ID; required for authentication. */
7
+ environmentId?: CreateOptions["environmentId"];
8
+ /** Deployment region; default: the Railway service default. */
9
+ region?: CreateOptions["region"];
10
+ /** Network isolation; default: the native Railway SDK setting. */
11
+ networkIsolation?: CreateOptions["networkIsolation"];
12
+ /** Token kind; default: the native Railway SDK authentication mode. */
13
+ authType?: CreateOptions["authType"];
14
+ } & ({
15
+ /** Base template; default: the Railway service default; mutually exclusive with checkpoint. */
16
+ template?: SandboxTemplate;
17
+ checkpoint?: never;
18
+ } | {
19
+ template?: never;
20
+ /** Checkpoint to restore; default: none; mutually exclusive with template. */
21
+ checkpoint?: string;
22
+ });
23
+ export type RailwayProvider = Provider<Sandbox, "snapshot">;
24
+ export declare function railway(options?: RailwayOptions): RailwayProvider;
@@ -0,0 +1 @@
1
+ import{o}from"../../chunk-yed8mvs7.js";import{e}from"../../chunk-gc8zdxyb.js";import{posix as N}from"node:path";function x(s,l){if(s instanceof e)return s;let u=s instanceof Error?s.constructor.name:"",m=typeof s==="object"&&s!==null&&"status"in s?s.status:void 0,d="provider";if(u==="RailwayAuthError"||m===401||m===403)d="auth";else if(u==="SandboxFileNotFoundError")d="file_not_found";else if(u==="SandboxNotFoundError"||m===404)d="not_found";else if(u==="ExecControlUnsupportedError")d="unsupported";else if(u==="ExecInterruptedError"||u==="RailwayConnectionError")d="outcome_unknown";else if(m===429||m===507)d="quota";else if(u==="ExecNotStartedError"||typeof m==="number"&&m>=500)d="unavailable";else if(u==="SandboxTimeoutError")d="timeout";else if(u==="AbortError")d="aborted";else if(s instanceof TypeError||m===400)d="invalid_argument";let y=d==="auth"?"Check RAILWAY_API_TOKEN and RAILWAY_ENVIRONMENT_ID.":"Check the sandbox and Railway service before retrying.";return new e(`Railway request failed. The provider reported ${d}. ${y}`,{code:d,provider:"railway",sandboxId:l,hint:y,retryable:["quota","unavailable"].includes(d)})}function h(s){throw new e(`${s}. Railway cannot enforce this request. Omit the option or use another provider.`,{code:"unsupported",provider:"railway"})}var I="/tmp/.sandbox-sdk/railway.json",k=(s)=>`'${s.replace(/'/g,`'"'"'`)}'`;function T(s){let l;try{l=JSON.parse(s)}catch{throw new e("Invalid Railway SDK metadata",{code:"not_found",provider:"railway"})}if(typeof l!=="object"||l===null||!("version"in l)||l.version!==1||!("labels"in l)||typeof l.labels!=="object"||l.labels===null||Array.isArray(l.labels)||"key"in l&&l.key!==void 0&&typeof l.key!=="string")throw new e("Invalid Railway SDK metadata",{code:"not_found",provider:"railway"});let u={};for(let[m,d]of Object.entries(l.labels)){if(typeof d!=="string")throw new e("Invalid Railway SDK label",{code:"not_found",provider:"railway"});Object.defineProperty(u,m,{value:d,enumerable:!0})}return{version:1,key:"key"in l&&typeof l.key==="string"?l.key:void 0,labels:u}}function E(s,l){let u=Date.parse(s.createdAt);if(!Number.isFinite(u))throw Error("Invalid Railway creation time");return{id:s.id,key:l.key,labels:l.labels,state:s.status==="RUNNING"?"running":"stopped",createdAt:u}}function D(s={}){let l,u=()=>l??=o("railway","railway",()=>import("railway")),m=()=>({token:s.token??process.env.RAILWAY_API_TOKEN,environmentId:s.environmentId??process.env.RAILWAY_ENVIRONMENT_ID,authType:s.authType}),d=new Map;async function y(t,n){try{return await n()}catch(r){throw x(r,t)}}async function b(t){let n=d.get(t);if(n)return n;let{Sandbox:r}=await u(),a=await r.connect(t,m());return d.set(t,a),a}async function A(){let t=m();if(!t.token||!t.environmentId)throw new e("Railway credentials are missing. Authentication requires a token and environment ID. Set RAILWAY_API_TOKEN and RAILWAY_ENVIRONMENT_ID or pass token and environmentId.",{code:"auth",provider:"railway"});let n=[],r=null;do{let a=await fetch((await u()).DEFAULT_RAILWAY_GRAPHQL_ENDPOINT,{method:"POST",headers:{"Content-Type":"application/json",...t.authType==="project-token"?{"Project-Access-Token":t.token}:{Authorization:`Bearer ${t.token}`}},signal:AbortSignal.timeout(30000),body:JSON.stringify({query:"query SandboxSdkRailwayList($environmentId: String!, $after: String) { sandboxes(environmentId: $environmentId, first: 100, after: $after) { edges { node { id } } pageInfo { hasNextPage endCursor } } }",variables:{environmentId:t.environmentId,after:r}})});if(!a.ok)throw Object.assign(Error("Railway list failed"),{status:a.status});let i=await a.json();if(typeof i!=="object"||i===null||"errors"in i&&i.errors||!("data"in i)||typeof i.data!=="object"||i.data===null||!("sandboxes"in i.data))throw Error("Invalid Railway list response");let c=i.data.sandboxes;if(typeof c!=="object"||c===null||!("edges"in c)||!Array.isArray(c.edges)||!("pageInfo"in c))throw Error("Invalid Railway connection");for(let f of c.edges){if(typeof f!=="object"||f===null||!("node"in f)||typeof f.node!=="object"||f.node===null||!("id"in f.node)||typeof f.node.id!=="string")throw Error("Invalid Railway sandbox ID");n.push(f.node.id)}let w=c.pageInfo;if(typeof w!=="object"||w===null||!("hasNextPage"in w)||typeof w.hasNextPage!=="boolean")throw Error("Invalid Railway pagination");if(!w.hasNextPage)break;if(!("endCursor"in w)||typeof w.endCursor!=="string"||!w.endCursor||w.endCursor===r)throw Error("Missing Railway cursor");r=w.endCursor}while(r!==null);return n}async function g(t,n){if(n.signal?.aborted)return{exitCode:null,timedOut:!0};let r=await b(t),a=new AbortController,i=()=>a.abort(),c=setTimeout(i,n.timeoutMs);if(n.signal?.addEventListener("abort",i,{once:!0}),n.signal?.aborted)i();try{let w=r.exec(n.command,{cwd:n.cwd,env:n.env,stdin:n.stdin!==void 0,ephemeral:!0,captureOutput:!1,signal:a.signal,onStdout:(p)=>n.onChunk({stream:"stdout",text:p}),onStderr:(p)=>n.onChunk({stream:"stderr",text:p})}),f=Promise.resolve(w);f.catch(()=>{});try{if(n.stdin!==void 0)try{await w.stdin.write(n.stdin),await w.stdin.end()}catch{await f}let p=await f;if(p.timedOut&&p.exitCode===null)await v.destroy(t);return{exitCode:p.timedOut?null:p.exitCode,timedOut:p.timedOut}}catch(p){if(a.signal.aborted){if(p!==a.signal.reason)await v.destroy(t);return await f.catch(()=>{}),{exitCode:null,timedOut:!0}}if(x(p,t).code==="outcome_unknown")await v.destroy(t);throw p}}finally{clearTimeout(c),n.signal?.removeEventListener("abort",i)}}async function R(t,n){let r="";if((await g(t,{command:`stat -c '%f %s %Y' -- ${k(n)}`,cwd:"/",env:{},timeoutMs:30000,onChunk:(S)=>{if(S.stream==="stdout")r+=S.text}})).exitCode!==0)throw await(await b(t)).files.stat(n),Error("Railway stat command failed");let[i,c,w]=r.trim().split(/\s+/),f=Number.parseInt(i??"",16),p=Number(c),C=Number(w)*1000;if(![f,p,C].every(Number.isFinite))throw Error("Invalid Railway stat output");return{path:n,type:(f&61440)===40960?"symlink":(f&61440)===16384?"directory":"file",size:p,modifiedAt:C}}let v={name:"railway",commandShell:"bash",keyMode:"best-effort",capabilities:new Set(["snapshot"]),create:(t)=>y(void 0,async()=>{if(t.size!==void 0)h("Railway resources set CPU and memory but cannot set diskGb; size presets and exact sizes are unavailable");if(t.network!==void 0&&t.network!=="all")h("Railway isolation modes retain outbound internet access");if(t.timeoutMs!==void 0)h("Railway has no hard sandbox lifetime; idle destruction is not a lifetime limit");if(t.signal?.aborted)throw new e("Creation aborted. The signal was cancelled. Retry with a fresh signal.",{code:"aborted",provider:"railway"});if(t.ports&&(t.ports.length>10||new Set(t.ports).size!==t.ports.length))h("Railway accepts at most 10 unique preview ports");if(t.ports?.length&&s.networkIsolation==="ISOLATED")h("Public domains require PRIVATE networking");if(t.idleTimeoutMs!==void 0&&(!Number.isFinite(t.idleTimeoutMs)||t.idleTimeoutMs<=0))throw new e("Invalid idle timeout. A positive duration is required. Set idleTimeoutMs above zero.",{code:"invalid_argument",provider:"railway"});let{Sandbox:n}=await u(),r={...m(),region:s.region,env:t.env,idleTimeoutMinutes:t.idleTimeoutMs===void 0?void 0:Math.ceil(t.idleTimeoutMs/60000),networkIsolation:t.ports?.length?"PRIVATE":s.networkIsolation,domains:t.ports?.map((c)=>({port:c}))},a=t.from??s.checkpoint??s.template,i=a===void 0?await n.create(r):typeof a==="string"?await n.create(a,r):await n.create(a,r);d.set(i.id,i);try{if(t.signal?.aborted)throw new e("Creation aborted. Cancellation arrived while provisioning. Retry with a fresh signal.",{code:"aborted",provider:"railway"});let c={version:1,key:t.key,labels:{...t.labels,"sandbox-sdk":"1"}},w=a===void 0?"":'for d in /tmp/.sandbox-sdk/procs/*; do [ -f "$d/spec.json" ] && [ ! -f "$d/exit" ] && printf 137 > "$d/exit"; done; rm -rf /tmp/.sandbox-sdk/runs; ',f=await g(i.id,{command:`mkdir -p /workspace /tmp/.sandbox-sdk && { ${w}printf %s ${k(JSON.stringify(c))} > ${k(I)}; }`,cwd:"/",env:{},timeoutMs:30000,onChunk(){}});if(f.timedOut||f.exitCode!==0)throw Error("Railway workspace and ownership initialization failed");if(t.signal?.aborted)throw new e("Creation aborted. Cancellation arrived during initialization. Retry with a fresh signal.",{code:"aborted",provider:"railway"});return E(i,c)}catch(c){throw await v.destroy(i.id),c}}),connect:(t)=>y(t,async()=>{let{Sandbox:n}=await u(),r=await n.connect(t,m());return d.set(t,r),E(r,T(await r.files.read(I)))}),find:(t)=>y(void 0,async()=>(await v.list({})).find((n)=>n.key===t)),list:(t)=>y(void 0,async()=>{let n=[];for(let r of await A())try{let{Sandbox:a}=await u(),i=await a.connect(r,m());if(i.status!=="RUNNING")continue;let c=T(await i.files.read(I));if(c.labels["sandbox-sdk"]==="1"&&Object.entries(t).every(([w,f])=>c.labels[w]===f))n.push(E(i,c))}catch(a){if(!["not_found","file_not_found"].includes(x(a,r).code))throw a}return n}),destroy:(t)=>y(t,async()=>{try{await(await b(t)).destroy()}catch(n){if(x(n,t).code!=="not_found")throw n}d.delete(t)}),close:async(t)=>{d.delete(t)},native(t){let n=d.get(t);if(!n)throw new e("Sandbox client is detached. No cached Railway object exists. Connect first.",{code:"not_found",provider:"railway",sandboxId:t});return n},exec:(t,n)=>y(t,()=>g(t,n)),files:{writeCreatesParents:!0,read:(t,n)=>y(t,async()=>(await b(t)).files.read(n,{format:"bytes"})),readRange:(t,n,r)=>y(t,async()=>r.length===0?new Uint8Array:(await b(t)).files.read(n,{format:"bytes",...r})),write:(t,n,r)=>y(t,async()=>{await(await b(t)).files.write(n,r)}),mkdir:(t,n)=>y(t,async()=>{await(await b(t)).files.mkdir(n)}),stat:(t,n)=>y(t,()=>R(t,n)),list:(t,n)=>y(t,async()=>{let r=await(await b(t)).files.list(n),a=[];for(let i of r)a.push(await R(t,N.join(n,i.name)));return a}),remove:(t,n,r)=>y(t,async()=>{let a=await b(t);if(!r.recursive){await a.files.remove(n);return}if((await g(t,{command:`rm -rf -- ${k(n)}`,cwd:"/",env:{},timeoutMs:30000,onChunk(){}})).exitCode!==0)throw Error("Railway recursive removal failed")})},previewUrl:(t,n)=>y(t,async()=>{let a=(await b(t)).domains.find((i)=>i.port===n);if(!a)h("The preview port was not declared at creation; pass ports to createSandbox");return{url:`https://${a.domain}`}}),snapshot:(t)=>y(t,async()=>({id:(await(await b(t)).checkpoint(`sandbox-sdk-${crypto.randomUUID()}`)).key}))};return v}export{D as railway};
@@ -0,0 +1,33 @@
1
+ /** Sandboxer API v1 derives from Boat API v1. https://sandboxer.com/api/v1/openapi.yaml */
2
+ import type { CreateSandboxRequest } from "@boatdev/sdk";
3
+ import type { Provider } from "../../provider.js";
4
+ import type { BoatNative } from "../boat/index.js";
5
+ /** `GET /regions` lists them: us-east (Ashburn, Virginia), eu-central (Helsinki). */
6
+ export type SandboxerRegion = "us-east" | "eu-central" | (string & {});
7
+ export interface SandboxerOptions {
8
+ /** Defaults to SANDBOXER_API_KEY; required on first use. */
9
+ apiKey?: string;
10
+ /** Default: https://sandboxer.com/api/v1. */
11
+ baseUrl?: string;
12
+ /** Native machine size; default: Sandboxer default (4 CPU/8 GB). Per-create size wins. */
13
+ machine?: CreateSandboxRequest["type"];
14
+ /** Deadline for each control-plane request and lifecycle poll. Default: 90 seconds. */
15
+ requestTimeoutMs?: number;
16
+ /** Region for new sandboxes. Default: SANDBOXER_REGION, else the region
17
+ * nearest the caller. Snapshot restores must match the snapshot's region. */
18
+ region?: SandboxerRegion;
19
+ }
20
+ declare const regionSources: readonly ["requested", "nearest", "default", "source"];
21
+ export type SandboxerRegionSource = (typeof regionSources)[number];
22
+ export interface SandboxerNative extends BoatNative {
23
+ /** Null for sandboxes from before regions. */
24
+ readonly region: string | null;
25
+ readonly regionSource: SandboxerRegionSource | null;
26
+ createSnapshot(name: string): Promise<{
27
+ id: string;
28
+ }>;
29
+ }
30
+ export type SandboxerProvider = Provider<SandboxerNative, "size" | "pause" | "snapshot">;
31
+ /** Sandboxer through its Boat-compatible API; loads @boatdev/sdk on first use. */
32
+ export declare function sandboxer(options?: SandboxerOptions): SandboxerProvider;
33
+ export {};