eve 0.8.6 → 0.9.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 (59) hide show
  1. package/CHANGELOG.md +7 -1
  2. package/dist/src/execution/sandbox/bindings/docker-cli.d.ts +1 -1
  3. package/dist/src/execution/sandbox/bindings/docker-cli.js +1 -1
  4. package/dist/src/execution/sandbox/bindings/docker-network.js +1 -1
  5. package/dist/src/execution/sandbox/bindings/docker-options.d.ts +1 -1
  6. package/dist/src/execution/sandbox/bindings/docker-options.js +1 -1
  7. package/dist/src/execution/sandbox/bindings/docker.d.ts +1 -1
  8. package/dist/src/execution/sandbox/bindings/just-bash-runtime.js +1 -1
  9. package/dist/src/execution/sandbox/bindings/just-bash.d.ts +1 -1
  10. package/dist/src/execution/sandbox/bindings/microsandbox-options.d.ts +1 -1
  11. package/dist/src/execution/sandbox/bindings/microsandbox-platform.d.ts +1 -1
  12. package/dist/src/execution/sandbox/bindings/microsandbox-platform.js +1 -1
  13. package/dist/src/execution/sandbox/bindings/microsandbox-runtime.js +1 -1
  14. package/dist/src/execution/sandbox/bindings/microsandbox.d.ts +1 -1
  15. package/dist/src/execution/sandbox/bindings/vercel.d.ts +4 -4
  16. package/dist/src/execution/sandbox/bindings/vercel.js +1 -1
  17. package/dist/src/execution/sandbox/ensure.d.ts +1 -1
  18. package/dist/src/execution/sandbox/lazy-backend.d.ts +2 -2
  19. package/dist/src/internal/application/package.js +1 -1
  20. package/dist/src/internal/authored-definition/sandbox.d.ts +1 -1
  21. package/dist/src/internal/authored-definition/sandbox.js +1 -1
  22. package/dist/src/internal/nitro/host/create-application-nitro.d.ts +1 -1
  23. package/dist/src/public/sandbox/backends/default.d.ts +10 -10
  24. package/dist/src/public/sandbox/backends/default.js +1 -1
  25. package/dist/src/public/sandbox/backends/docker.d.ts +1 -1
  26. package/dist/src/public/sandbox/backends/docker.js +1 -1
  27. package/dist/src/public/sandbox/backends/just-bash.d.ts +1 -1
  28. package/dist/src/public/sandbox/backends/just-bash.js +1 -1
  29. package/dist/src/public/sandbox/backends/microsandbox.d.ts +1 -1
  30. package/dist/src/public/sandbox/backends/microsandbox.js +1 -1
  31. package/dist/src/public/sandbox/backends/vercel.d.ts +1 -1
  32. package/dist/src/public/sandbox/backends/vercel.js +1 -1
  33. package/dist/src/public/sandbox/docker-sandbox.d.ts +2 -2
  34. package/dist/src/public/sandbox/docker.d.ts +2 -0
  35. package/dist/src/public/sandbox/docker.js +1 -0
  36. package/dist/src/public/sandbox/index.d.ts +1 -9
  37. package/dist/src/public/sandbox/index.js +1 -1
  38. package/dist/src/public/sandbox/just-bash-sandbox.d.ts +1 -1
  39. package/dist/src/public/sandbox/just-bash.d.ts +2 -0
  40. package/dist/src/public/sandbox/just-bash.js +1 -0
  41. package/dist/src/public/sandbox/microsandbox-sandbox.d.ts +1 -1
  42. package/dist/src/public/sandbox/microsandbox.d.ts +2 -0
  43. package/dist/src/public/sandbox/microsandbox.js +1 -0
  44. package/dist/src/public/sandbox/vercel-sandbox.d.ts +1 -1
  45. package/dist/src/public/sandbox/vercel.d.ts +2 -0
  46. package/dist/src/public/sandbox/vercel.js +1 -0
  47. package/dist/src/runtime/resolve-sandbox.d.ts +1 -1
  48. package/dist/src/runtime/resolve-sandbox.js +1 -1
  49. package/dist/src/runtime/sandbox/registry.d.ts +2 -2
  50. package/dist/src/runtime/sandbox/registry.js +1 -1
  51. package/dist/src/runtime/types.d.ts +2 -2
  52. package/dist/src/setup/scaffold/create/add-to-project.js +1 -1
  53. package/dist/src/setup/scaffold/create/project.js +2 -2
  54. package/dist/src/setup/scaffold/update/channels.js +1 -1
  55. package/dist/src/shared/sandbox-backend.d.ts +4 -4
  56. package/dist/src/shared/sandbox-definition.d.ts +4 -4
  57. package/docs/guides/deployment.md +4 -3
  58. package/docs/sandbox.mdx +21 -19
  59. package/package.json +21 -1
package/CHANGELOG.md CHANGED
@@ -1,5 +1,11 @@
1
1
  # eve
2
2
 
3
+ ## 0.9.0
4
+
5
+ ### Minor Changes
6
+
7
+ - ccaa1ae: Move concrete sandbox backend factories out of `eve/sandbox` and into nested backend imports: `eve/sandbox/docker`, `eve/sandbox/just-bash`, `eve/sandbox/microsandbox`, and `eve/sandbox/vercel`. Agent sandbox definitions should import `defineSandbox` and `defaultBackend` from `eve/sandbox`, and concrete backend factories from the matching nested entrypoint.
8
+
3
9
  ## 0.8.6
4
10
 
5
11
  ### Patch Changes
@@ -49,7 +55,7 @@
49
55
 
50
56
  ### Minor Changes
51
57
 
52
- - b460a24: Add explicit sandbox backends for Docker, microsandbox, just-bash, and Vercel, with `defaultBackend()` choosing the best available backend for local dev.
58
+ - b460a24: Add explicit sandbox backends for Docker, microsandbox, just-bash, and Vercel, with `defaultSandbox()` choosing the best available backend for local dev.
53
59
 
54
60
  Docker and microsandbox now use Ubuntu 26.04 and show sandbox initialization progress directly in the dev TUI.
55
61
 
@@ -65,7 +65,7 @@ export declare class DockerDaemonUnavailableError extends Error {
65
65
  export declare function assertDockerDaemonAvailable(cli: DockerCli): Promise<void>;
66
66
  /**
67
67
  * Synchronously probes whether a Docker daemon is reachable, for
68
- * `defaultBackend()`'s availability chain. The result is cached for the
68
+ * `defaultSandbox()`'s availability chain. The result is cached for the
69
69
  * process lifetime: backend selection must be stable, and the probe
70
70
  * costs a subprocess round-trip.
71
71
  */
@@ -1,2 +1,2 @@
1
- import{spawn,spawnSync}from"node:child_process";import{Readable}from"node:stream";var DockerUnavailableError=class extends Error{constructor(e){super("The Docker sandbox backend requires Docker, but the `docker` CLI was not found. Install and start Docker Desktop, OrbStack, Colima, or another runtime exposing a Docker-compatible `docker` CLI (or point EVE_DOCKER_PATH at one, e.g. Podman). Alternatively use microsandboxBackend(), the dependency-free justBashBackend(), vercelSandboxBackend(), or defaultBackend() to pick by availability.",{cause:e}),this.name=`DockerUnavailableError`}},DockerDaemonUnavailableError=class extends Error{constructor(e){super(`The Docker sandbox backend requires a running Docker daemon, but it is not reachable. Start Docker Desktop (or your Docker-compatible runtime) and retry. Alternatively use microsandboxBackend(), the dependency-free justBashBackend() (installed automatically by \`eve dev\`, or \`pnpm add -D just-bash\`), vercelSandboxBackend(), or defaultBackend() to pick by availability. Docker reported: ${e}`),this.name=`DockerDaemonUnavailableError`}};async function assertDockerDaemonAvailable(e){let t=await e.run([`version`,`--format`,`{{.Server.Version}}`]);if(t.exitCode!==0)throw new DockerDaemonUnavailableError(firstLine(t.stderr)||`exit ${t.exitCode}`)}function resolveDockerExecutable(){let e=process.env.EVE_DOCKER_PATH?.trim();return e!==void 0&&e.length>0?e:`docker`}let cachedDockerAvailability;function isDockerDaemonAvailableSync(){return cachedDockerAvailability??=probeDockerDaemonSync(),cachedDockerAvailability}function probeDockerDaemonSync(){try{return spawnSync(resolveDockerExecutable(),[`version`,`--format`,`{{.Server.Version}}`],{stdio:`ignore`,timeout:5e3}).status===0}catch{return!1}}function createDockerCli(){return{async run(t,n={}){throwIfAborted(n.signal);let r=spawn(resolveDockerExecutable(),t,{signal:n.signal,stdio:[n.stdin===void 0?`ignore`:`pipe`,`pipe`,`pipe`]}),i=[],a=[];r.stdout?.on(`data`,e=>i.push(e)),r.stderr?.on(`data`,e=>a.push(e)),n.stdin!==void 0&&r.stdin?.end(n.stdin);let o=await new Promise((e,t)=>{r.on(`error`,e=>t(adaptSpawnError(e))),r.on(`close`,t=>e(t??1))}),s=Buffer.concat(i);return{exitCode:o,stderr:Buffer.concat(a).toString(`utf8`),stdout:s.toString(`utf8`),stdoutBytes:s}},stream(t,r={}){throwIfAborted(r.signal);let i=spawn(resolveDockerExecutable(),t,{signal:r.signal,stdio:[`ignore`,`pipe`,`pipe`]}),a=new Promise((e,t)=>{i.on(`error`,e=>t(adaptSpawnError(e))),i.on(`close`,t=>e(t??1))});return a.catch(()=>{}),{stdout:Readable.toWeb(i.stdout),stderr:Readable.toWeb(i.stderr),async wait(){return{exitCode:await a}},async kill(){i.kill(`SIGKILL`),await a.catch(()=>{})}}}}}function adaptSpawnError(e){return e.code===`ENOENT`?new DockerUnavailableError(e):e.code===`ABORT_ERR`?new DOMException(`The operation was aborted.`,`AbortError`):e}function throwIfAborted(e){if(e?.aborted)throw new DOMException(`The operation was aborted.`,`AbortError`)}function firstLine(e){return e.split(`
1
+ import{spawn,spawnSync}from"node:child_process";import{Readable}from"node:stream";var DockerUnavailableError=class extends Error{constructor(e){super("The Docker sandbox backend requires Docker, but the `docker` CLI was not found. Install and start Docker Desktop, OrbStack, Colima, or another runtime exposing a Docker-compatible `docker` CLI (or point EVE_DOCKER_PATH at one, e.g. Podman). Alternatively use microsandbox(), the dependency-free justbash(), vercel(), or defaultSandbox() to pick by availability.",{cause:e}),this.name=`DockerUnavailableError`}},DockerDaemonUnavailableError=class extends Error{constructor(e){super(`The Docker sandbox backend requires a running Docker daemon, but it is not reachable. Start Docker Desktop (or your Docker-compatible runtime) and retry. Alternatively use microsandbox(), the dependency-free justbash() (installed automatically by \`eve dev\`, or \`pnpm add -D just-bash\`), vercel(), or defaultSandbox() to pick by availability. Docker reported: ${e}`),this.name=`DockerDaemonUnavailableError`}};async function assertDockerDaemonAvailable(e){let t=await e.run([`version`,`--format`,`{{.Server.Version}}`]);if(t.exitCode!==0)throw new DockerDaemonUnavailableError(firstLine(t.stderr)||`exit ${t.exitCode}`)}function resolveDockerExecutable(){let e=process.env.EVE_DOCKER_PATH?.trim();return e!==void 0&&e.length>0?e:`docker`}let cachedDockerAvailability;function isDockerDaemonAvailableSync(){return cachedDockerAvailability??=probeDockerDaemonSync(),cachedDockerAvailability}function probeDockerDaemonSync(){try{return spawnSync(resolveDockerExecutable(),[`version`,`--format`,`{{.Server.Version}}`],{stdio:`ignore`,timeout:5e3}).status===0}catch{return!1}}function createDockerCli(){return{async run(t,n={}){throwIfAborted(n.signal);let r=spawn(resolveDockerExecutable(),t,{signal:n.signal,stdio:[n.stdin===void 0?`ignore`:`pipe`,`pipe`,`pipe`]}),i=[],a=[];r.stdout?.on(`data`,e=>i.push(e)),r.stderr?.on(`data`,e=>a.push(e)),n.stdin!==void 0&&r.stdin?.end(n.stdin);let o=await new Promise((e,t)=>{r.on(`error`,e=>t(adaptSpawnError(e))),r.on(`close`,t=>e(t??1))}),s=Buffer.concat(i);return{exitCode:o,stderr:Buffer.concat(a).toString(`utf8`),stdout:s.toString(`utf8`),stdoutBytes:s}},stream(t,r={}){throwIfAborted(r.signal);let i=spawn(resolveDockerExecutable(),t,{signal:r.signal,stdio:[`ignore`,`pipe`,`pipe`]}),a=new Promise((e,t)=>{i.on(`error`,e=>t(adaptSpawnError(e))),i.on(`close`,t=>e(t??1))});return a.catch(()=>{}),{stdout:Readable.toWeb(i.stdout),stderr:Readable.toWeb(i.stderr),async wait(){return{exitCode:await a}},async kill(){i.kill(`SIGKILL`),await a.catch(()=>{})}}}}}function adaptSpawnError(e){return e.code===`ENOENT`?new DockerUnavailableError(e):e.code===`ABORT_ERR`?new DOMException(`The operation was aborted.`,`AbortError`):e}function throwIfAborted(e){if(e?.aborted)throw new DOMException(`The operation was aborted.`,`AbortError`)}function firstLine(e){return e.split(`
2
2
  `,1)[0]?.trim()??``}export{DockerDaemonUnavailableError,DockerUnavailableError,assertDockerDaemonAvailable,createDockerCli,isDockerDaemonAvailableSync};
@@ -1 +1 @@
1
- import{expectDockerSuccess}from"#execution/sandbox/bindings/docker-utils.js";async function setDockerNetworkPolicy(e,t,n){if(n!==`allow-all`&&n!==`deny-all`)throw Error(`The local Docker sandbox backend supports only the "allow-all" and "deny-all" network policies. Domain-level allow-lists and credential brokering require the Vercel backend (vercelSandboxBackend()) or microsandboxBackend().`);let r=await e.run([`container`,`inspect`,`--format`,`{{json .NetworkSettings.Networks}}`,t]);expectDockerSuccess(r,`inspect networks of sandbox container "${t}"`);let i=Object.keys(JSON.parse(r.stdout.trim()===``?`{}`:r.stdout));if(n===`deny-all`){for(let n of i)expectDockerSuccess(await e.run([`network`,`disconnect`,`--force`,n,t]),`disconnect sandbox container "${t}" from network "${n}"`);return}i.includes(`bridge`)||(i.includes(`none`)&&expectDockerSuccess(await e.run([`network`,`disconnect`,`--force`,`none`,t]),`detach sandbox container "${t}" from the none network`),expectDockerSuccess(await e.run([`network`,`connect`,`bridge`,t]),`connect sandbox container "${t}" to the bridge network`))}export{setDockerNetworkPolicy};
1
+ import{expectDockerSuccess}from"#execution/sandbox/bindings/docker-utils.js";async function setDockerNetworkPolicy(e,t,n){if(n!==`allow-all`&&n!==`deny-all`)throw Error(`The local Docker sandbox backend supports only the "allow-all" and "deny-all" network policies. Domain-level allow-lists and credential brokering require the Vercel backend (vercel()) or microsandbox().`);let r=await e.run([`container`,`inspect`,`--format`,`{{json .NetworkSettings.Networks}}`,t]);expectDockerSuccess(r,`inspect networks of sandbox container "${t}"`);let i=Object.keys(JSON.parse(r.stdout.trim()===``?`{}`:r.stdout));if(n===`deny-all`){for(let n of i)expectDockerSuccess(await e.run([`network`,`disconnect`,`--force`,n,t]),`disconnect sandbox container "${t}" from network "${n}"`);return}i.includes(`bridge`)||(i.includes(`none`)&&expectDockerSuccess(await e.run([`network`,`disconnect`,`--force`,`none`,t]),`detach sandbox container "${t}" from the none network`),expectDockerSuccess(await e.run([`network`,`connect`,`bridge`,t]),`connect sandbox container "${t}" to the bridge network`))}export{setDockerNetworkPolicy};
@@ -15,7 +15,7 @@ export interface ResolvedDockerSandboxOptions {
15
15
  readonly pullPolicy: DockerSandboxPullPolicy;
16
16
  }
17
17
  /**
18
- * Applies defaults to `dockerBackend(opts)`.
18
+ * Applies defaults to `docker(opts)`.
19
19
  */
20
20
  export declare function resolveDockerSandboxOptions(options?: DockerSandboxCreateOptions): ResolvedDockerSandboxOptions;
21
21
  export declare function createDockerSandboxOptionsHash(options: ResolvedDockerSandboxOptions): string;
@@ -1 +1 @@
1
- import{createHash}from"node:crypto";const DEFAULT_DOCKER_SANDBOX_IMAGE=`ghcr.io/vercel/eve:latest`;function resolveDockerSandboxOptions(e={}){return{env:e.env??{},image:e.image??`ghcr.io/vercel/eve:latest`,networkPolicy:e.networkPolicy??`allow-all`,pullPolicy:e.pullPolicy??`if-not-present`}}function createDockerSandboxOptionsHash(t){return createHash(`sha256`).update(JSON.stringify(dockerSandboxOptionsForHash(t))).digest(`hex`).slice(0,20)}function dockerSandboxOptionsForHash(e){return{env:sortStringRecord(e.env),image:e.image,networkPolicy:e.networkPolicy,pullPolicy:e.pullPolicy}}function sortStringRecord(e){return Object.fromEntries(Object.entries(e).sort(([e],[t])=>e.localeCompare(t)))}export{DEFAULT_DOCKER_SANDBOX_IMAGE,createDockerSandboxOptionsHash,resolveDockerSandboxOptions};
1
+ import{createHash}from"node:crypto";const DEFAULT_DOCKER_SANDBOX_IMAGE=`ghcr.io/vercel/eve:latest`;function resolveDockerSandboxOptions(e={}){return{env:e.env??{},image:e.image??`ghcr.io/vercel/eve:latest`,networkPolicy:e.networkPolicy??`allow-all`,pullPolicy:e.pullPolicy??`if-not-present`}}function createDockerSandboxOptionsHash(t){return createHash(`sha256`).update(JSON.stringify(dockerOptionsForHash(t))).digest(`hex`).slice(0,20)}function dockerOptionsForHash(e){return{env:sortStringRecord(e.env),image:e.image,networkPolicy:e.networkPolicy,pullPolicy:e.pullPolicy}}function sortStringRecord(e){return Object.fromEntries(Object.entries(e).sort(([e],[t])=>e.localeCompare(t)))}export{DEFAULT_DOCKER_SANDBOX_IMAGE,createDockerSandboxOptionsHash,resolveDockerSandboxOptions};
@@ -9,7 +9,7 @@ export { DOCKER_TEMPLATE_IMAGE_REPOSITORY, pruneDockerSandboxTemplates, } from "
9
9
  export declare const DOCKER_BACKEND_NAME = "docker";
10
10
  /**
11
11
  * Construction input for {@link createDockerSandboxBackend}. Internal —
12
- * the public surface is the `dockerBackend()` factory under
12
+ * the public surface is the `docker()` factory under
13
13
  * `eve/sandbox`.
14
14
  */
15
15
  export interface CreateDockerSandboxBackendInput {
@@ -1 +1 @@
1
- import{dirname}from"node:path";import{mkdir,readFile,writeFile}from"node:fs/promises";import{loadOptionalEnginePackage}from"#internal/application/optional-package-install.js";import{WORKSPACE_ROOT}from"#runtime/workspace/types.js";import{createFileBackedInternalSandboxSession,pathExists}from"#execution/sandbox/bindings/local-backend-utils.js";import{shellQuote}from"#execution/sandbox/shell-quote.js";import{buildSandboxSession}from"#execution/sandbox/session.js";let justBashModulePromise;async function loadJustBashModule(e){return justBashModulePromise??=loadOptionalEnginePackage({appRoot:e.appRoot,autoInstall:e.autoInstall,importModule:async()=>await import(`just-bash`),missingMessage:"The just-bash sandbox backend requires the `just-bash` package, which is not bundled with Eve. Install it in your application (for example `pnpm add -D just-bash`), or use dockerBackend() / defaultBackend() instead.",packageName:`just-bash`}).catch(e=>{throw justBashModulePromise=void 0,e}),await justBashModulePromise}async function createBashSandbox(n){let{ReadWriteFs:r,Sandbox:i}=await loadJustBashModule({appRoot:n.appRoot,autoInstall:n.autoInstall}),o=resolveLocalSandboxFilesystemRootPath(n.rootPath),s=resolveLocalSandboxMetadataPath(n.rootPath),c=await readLocalMetadata(s);await mkdir(o,{recursive:!0});let l=new r({allowSymlinks:!0,maxFileReadSize:2**53-1,root:o});await ensureLocalSandboxDirectories(l);let u=await i.create({cwd:WORKSPACE_ROOT,env:c?.env,fs:l,network:{dangerouslyAllowFullInternetAccess:!0}});return{async captureState(){return await writeLocalMetadata(s,{env:{...u.bashEnvInstance.getEnv()},version:1}),{rootPath:n.rootPath}},async dispose(){await u.stop()},async readFileBytes(e){let t;try{t=await l.readFileBuffer(e)}catch{return null}return Buffer.from(t)},async removePath(e){await l.rm(e.path,{force:e.force,recursive:e.recursive})},rootPath:n.rootPath,sessionKey:n.sessionKey,async spawn(e){if(e.abortSignal?.aborted)throw new DOMException(`The operation was aborted.`,`AbortError`);let t=e.workingDirectory===void 0?e.command:`( cd ${shellQuote(e.workingDirectory)} && ${e.command} )`;return adaptJustBashCommandToSandboxProcess(await u.runCommand({args:[t],cmd:`eval`,detached:!0,env:e.env,signal:e.abortSignal}))},async writeFiles(t){for(let n of t){let t=dirname(n.path);await l.mkdir(t,{recursive:!0}),await l.writeFile(n.path,n.content)}}}}function adaptJustBashCommandToSandboxProcess(e){let t=new TextEncoder,n,r,i=!1,a,o=new ReadableStream({start(e){n=e}}),s=new ReadableStream({start(e){r=e}});return(async()=>{try{for await(let i of e.logs()){let e=t.encode(i.data);i.type===`stdout`?n?.enqueue(e):r?.enqueue(e)}}catch(e){a=e,n?.error(e),r?.error(e)}finally{i=!0,a===void 0&&(n?.close(),r?.close())}})(),{stdout:o,stderr:s,async wait(){let t=await e.wait();for(;!i;)await new Promise(e=>setTimeout(e,0));if(a!==void 0)throw a;return{exitCode:t.exitCode}},async kill(){await e.kill()}}}async function justBashSetNetworkPolicyUnsupported(){throw Error(`setNetworkPolicy() is not supported on the just-bash sandbox backend. just-bash applies its network policy only at sandbox creation (no run-time update) and does not run git or other binaries. Use dockerBackend() for coarse egress control or vercelSandboxBackend() / microsandboxBackend() for credential brokering.`)}function createJustBashHandle(e,t){let n=buildSandboxSession(createFileBackedInternalSandboxSession({id:e.sessionKey,sandbox:e}),justBashSetNetworkPolicyUnsupported);return{session:n,useSessionFn:async()=>n,async captureState(){return{backendName:t,metadata:await e.captureState()??{},sessionKey:e.sessionKey}},async dispose(){await e.dispose()}}}function resolveLocalSandboxFilesystemRootPath(e){return`${e}/fs`}function resolveLocalSandboxMetadataPath(e){return`${e}/metadata.json`}async function ensureLocalSandboxDirectories(e){await e.mkdir(WORKSPACE_ROOT,{recursive:!0})}async function readLocalMetadata(e){if(!await pathExists(e))return null;let t=JSON.parse(await readFile(e,`utf8`));return t.version!==1||!isStringRecord(t.env)?null:{env:t.env,version:1}}async function writeLocalMetadata(n,i){await mkdir(dirname(n),{recursive:!0}),await writeFile(n,`${JSON.stringify(i,null,2)}\n`)}function isStringRecord(e){return typeof e==`object`&&!!e&&!Array.isArray(e)&&Object.values(e).every(e=>typeof e==`string`)}export{createBashSandbox,createJustBashHandle,justBashSetNetworkPolicyUnsupported};
1
+ import{dirname}from"node:path";import{mkdir,readFile,writeFile}from"node:fs/promises";import{loadOptionalEnginePackage}from"#internal/application/optional-package-install.js";import{WORKSPACE_ROOT}from"#runtime/workspace/types.js";import{createFileBackedInternalSandboxSession,pathExists}from"#execution/sandbox/bindings/local-backend-utils.js";import{shellQuote}from"#execution/sandbox/shell-quote.js";import{buildSandboxSession}from"#execution/sandbox/session.js";let justBashModulePromise;async function loadJustBashModule(e){return justBashModulePromise??=loadOptionalEnginePackage({appRoot:e.appRoot,autoInstall:e.autoInstall,importModule:async()=>await import(`just-bash`),missingMessage:"The just-bash sandbox backend requires the `just-bash` package, which is not bundled with Eve. Install it in your application (for example `pnpm add -D just-bash`), or use docker() / defaultSandbox() instead.",packageName:`just-bash`}).catch(e=>{throw justBashModulePromise=void 0,e}),await justBashModulePromise}async function createBashSandbox(n){let{ReadWriteFs:r,Sandbox:i}=await loadJustBashModule({appRoot:n.appRoot,autoInstall:n.autoInstall}),o=resolveLocalSandboxFilesystemRootPath(n.rootPath),s=resolveLocalSandboxMetadataPath(n.rootPath),c=await readLocalMetadata(s);await mkdir(o,{recursive:!0});let l=new r({allowSymlinks:!0,maxFileReadSize:2**53-1,root:o});await ensureLocalSandboxDirectories(l);let u=await i.create({cwd:WORKSPACE_ROOT,env:c?.env,fs:l,network:{dangerouslyAllowFullInternetAccess:!0}});return{async captureState(){return await writeLocalMetadata(s,{env:{...u.bashEnvInstance.getEnv()},version:1}),{rootPath:n.rootPath}},async dispose(){await u.stop()},async readFileBytes(e){let t;try{t=await l.readFileBuffer(e)}catch{return null}return Buffer.from(t)},async removePath(e){await l.rm(e.path,{force:e.force,recursive:e.recursive})},rootPath:n.rootPath,sessionKey:n.sessionKey,async spawn(e){if(e.abortSignal?.aborted)throw new DOMException(`The operation was aborted.`,`AbortError`);let t=e.workingDirectory===void 0?e.command:`( cd ${shellQuote(e.workingDirectory)} && ${e.command} )`;return adaptJustBashCommandToSandboxProcess(await u.runCommand({args:[t],cmd:`eval`,detached:!0,env:e.env,signal:e.abortSignal}))},async writeFiles(t){for(let n of t){let t=dirname(n.path);await l.mkdir(t,{recursive:!0}),await l.writeFile(n.path,n.content)}}}}function adaptJustBashCommandToSandboxProcess(e){let t=new TextEncoder,n,r,i=!1,a,o=new ReadableStream({start(e){n=e}}),s=new ReadableStream({start(e){r=e}});return(async()=>{try{for await(let i of e.logs()){let e=t.encode(i.data);i.type===`stdout`?n?.enqueue(e):r?.enqueue(e)}}catch(e){a=e,n?.error(e),r?.error(e)}finally{i=!0,a===void 0&&(n?.close(),r?.close())}})(),{stdout:o,stderr:s,async wait(){let t=await e.wait();for(;!i;)await new Promise(e=>setTimeout(e,0));if(a!==void 0)throw a;return{exitCode:t.exitCode}},async kill(){await e.kill()}}}async function justBashSetNetworkPolicyUnsupported(){throw Error(`setNetworkPolicy() is not supported on the just-bash sandbox backend. just-bash applies its network policy only at sandbox creation (no run-time update) and does not run git or other binaries. Use docker() for coarse egress control or vercel() / microsandbox() for credential brokering.`)}function createJustBashHandle(e,t){let n=buildSandboxSession(createFileBackedInternalSandboxSession({id:e.sessionKey,sandbox:e}),justBashSetNetworkPolicyUnsupported);return{session:n,useSessionFn:async()=>n,async captureState(){return{backendName:t,metadata:await e.captureState()??{},sessionKey:e.sessionKey}},async dispose(){await e.dispose()}}}function resolveLocalSandboxFilesystemRootPath(e){return`${e}/fs`}function resolveLocalSandboxMetadataPath(e){return`${e}/metadata.json`}async function ensureLocalSandboxDirectories(e){await e.mkdir(WORKSPACE_ROOT,{recursive:!0})}async function readLocalMetadata(e){if(!await pathExists(e))return null;let t=JSON.parse(await readFile(e,`utf8`));return t.version!==1||!isStringRecord(t.env)?null:{env:t.env,version:1}}async function writeLocalMetadata(n,i){await mkdir(dirname(n),{recursive:!0}),await writeFile(n,`${JSON.stringify(i,null,2)}\n`)}function isStringRecord(e){return typeof e==`object`&&!!e&&!Array.isArray(e)&&Object.values(e).every(e=>typeof e==`string`)}export{createBashSandbox,createJustBashHandle,justBashSetNetworkPolicyUnsupported};
@@ -7,7 +7,7 @@ import type { JustBashSandboxCreateOptions } from "#public/sandbox/just-bash-san
7
7
  export declare const JUST_BASH_BACKEND_NAME = "just-bash";
8
8
  /**
9
9
  * Construction input for {@link createJustBashSandboxBackend}. Internal —
10
- * the public surface is the `justBashBackend()` factory under
10
+ * the public surface is the `justbash()` factory under
11
11
  * `eve/sandbox`.
12
12
  */
13
13
  export interface CreateJustBashSandboxBackendInput {
@@ -23,7 +23,7 @@ export interface ResolvedMicrosandboxOptions {
23
23
  };
24
24
  }
25
25
  /**
26
- * Applies defaults to `microsandboxBackend(opts)`.
26
+ * Applies defaults to `microsandbox(opts)`.
27
27
  */
28
28
  export declare function resolveMicrosandboxOptions(options: MicrosandboxCreateOptions | undefined): ResolvedMicrosandboxOptions;
29
29
  /**
@@ -2,7 +2,7 @@ import type { Sandbox as MicrosandboxSandbox } from "microsandbox";
2
2
  /**
3
3
  * Synchronously reports whether this host can run microsandbox at all:
4
4
  * macOS on Apple Silicon, or Linux (glibc) with KVM available. Used by
5
- * `defaultBackend()`'s availability chain.
5
+ * `defaultSandbox()`'s availability chain.
6
6
  */
7
7
  export declare function isMicrosandboxPlatformSupported(): boolean;
8
8
  /**
@@ -1,4 +1,4 @@
1
- import{existsSync}from"node:fs";import{access}from"node:fs/promises";import{WORKSPACE_ROOT}from"#runtime/workspace/types.js";import{MICROSANDBOX_USER}from"#execution/sandbox/bindings/microsandbox-options.js";function isMicrosandboxPlatformSupported(){return process.platform===`darwin`&&process.arch===`arm64`?!0:process.platform===`linux`&&(process.arch===`x64`||process.arch===`arm64`)&&isGlibcLinux()?process.env.MSB_PATH!==void 0||existsSync(`/dev/kvm`):!1}function isGlibcLinux(){try{return typeof(process.report?.getReport())?.header?.glibcVersionRuntime==`string`}catch{return!1}}async function assertMicrosandboxPlatformCandidate(){if(!(process.platform===`darwin`&&process.arch===`arm64`)){if(process.platform===`linux`&&(process.arch===`x64`||process.arch===`arm64`)){if(!isGlibcLinux())throw Error(`The microsandbox sandbox backend requires a glibc-based Linux distribution; musl hosts are not supported. Use dockerBackend() or vercelSandboxBackend() instead.`);if(process.env.MSB_PATH!==void 0||await doesPathExist(`/dev/kvm`))return;throw Error("The microsandbox sandbox backend requires Linux with KVM enabled. `/dev/kvm` is not available on this host. Enable KVM, set MSB_PATH for a custom runtime, or use dockerBackend() / vercelSandboxBackend().")}throw Error(`The microsandbox sandbox backend supports Linux with KVM or macOS on Apple Silicon. Current host is ${process.platform}/${process.arch}. Use dockerBackend() or vercelSandboxBackend() on this host.`)}}async function doesPathExist(e){try{return await access(e),!0}catch{return!1}}async function ensureMicrosandboxBaseRuntime(e,t={}){let n=await collectMicrosandboxBaseRuntimeOutput(await e.execStreamWith(`bash`,e=>e.args([`-lc`,MICROSANDBOX_BASE_SETUP_SCRIPT]).cwd(`/`).user(`root`)),t.log);if(n.exitCode!==0)throw Error(`Failed to initialize the microsandbox base runtime. ${n.stderr||n.stdout}`.trim())}async function collectMicrosandboxBaseRuntimeOutput(e,t){let n=new TextDecoder,r=new TextDecoder,i=``,a=``,o=``,s=``,c;for await(let l of e)if(l.kind===`stdout`){let e=n.decode(l.data,{stream:!0});i=appendOutput(i,e),o=emitMicrosandboxBaseRuntimeLogs(o+e,t)}else if(l.kind===`stderr`){let e=r.decode(l.data,{stream:!0});a=appendOutput(a,e),s=emitMicrosandboxBaseRuntimeLogs(s+e,t)}else if(l.kind===`exited`){c=l.code;break}let l=n.decode(),u=r.decode();if(l.length>0&&(i=appendOutput(i,l),o=emitMicrosandboxBaseRuntimeLogs(o+l,t)),u.length>0&&(a=appendOutput(a,u),s=emitMicrosandboxBaseRuntimeLogs(s+u,t)),emitMicrosandboxBaseRuntimeLogLine(o,t),emitMicrosandboxBaseRuntimeLogLine(s,t),c===void 0)throw Error(`Microsandbox base runtime setup ended without an exit event.`);return{exitCode:c,stderr:a,stdout:i}}function emitMicrosandboxBaseRuntimeLogs(e,t){let n=e.split(/\r?\n/u),r=n.pop()??``;for(let e of n)emitMicrosandboxBaseRuntimeLogLine(e,t);return r}function emitMicrosandboxBaseRuntimeLogLine(e,t){let n=e.match(/^eve-base-runtime: ?(.*)$/u)?.[1];n!==void 0&&n.length>0&&t?.(n)}function appendOutput(e,t){let n=e+t;return n.length>2e4?n.slice(-2e4):n}const MICROSANDBOX_BASE_SETUP_SCRIPT=`
1
+ import{existsSync}from"node:fs";import{access}from"node:fs/promises";import{WORKSPACE_ROOT}from"#runtime/workspace/types.js";import{MICROSANDBOX_USER}from"#execution/sandbox/bindings/microsandbox-options.js";function isMicrosandboxPlatformSupported(){return process.platform===`darwin`&&process.arch===`arm64`?!0:process.platform===`linux`&&(process.arch===`x64`||process.arch===`arm64`)&&isGlibcLinux()?process.env.MSB_PATH!==void 0||existsSync(`/dev/kvm`):!1}function isGlibcLinux(){try{return typeof(process.report?.getReport())?.header?.glibcVersionRuntime==`string`}catch{return!1}}async function assertMicrosandboxPlatformCandidate(){if(!(process.platform===`darwin`&&process.arch===`arm64`)){if(process.platform===`linux`&&(process.arch===`x64`||process.arch===`arm64`)){if(!isGlibcLinux())throw Error(`The microsandbox sandbox backend requires a glibc-based Linux distribution; musl hosts are not supported. Use docker() or vercel() instead.`);if(process.env.MSB_PATH!==void 0||await doesPathExist(`/dev/kvm`))return;throw Error("The microsandbox sandbox backend requires Linux with KVM enabled. `/dev/kvm` is not available on this host. Enable KVM, set MSB_PATH for a custom runtime, or use docker() / vercel().")}throw Error(`The microsandbox sandbox backend supports Linux with KVM or macOS on Apple Silicon. Current host is ${process.platform}/${process.arch}. Use docker() or vercel() on this host.`)}}async function doesPathExist(e){try{return await access(e),!0}catch{return!1}}async function ensureMicrosandboxBaseRuntime(e,t={}){let n=await collectMicrosandboxBaseRuntimeOutput(await e.execStreamWith(`bash`,e=>e.args([`-lc`,MICROSANDBOX_BASE_SETUP_SCRIPT]).cwd(`/`).user(`root`)),t.log);if(n.exitCode!==0)throw Error(`Failed to initialize the microsandbox base runtime. ${n.stderr||n.stdout}`.trim())}async function collectMicrosandboxBaseRuntimeOutput(e,t){let n=new TextDecoder,r=new TextDecoder,i=``,a=``,o=``,s=``,c;for await(let l of e)if(l.kind===`stdout`){let e=n.decode(l.data,{stream:!0});i=appendOutput(i,e),o=emitMicrosandboxBaseRuntimeLogs(o+e,t)}else if(l.kind===`stderr`){let e=r.decode(l.data,{stream:!0});a=appendOutput(a,e),s=emitMicrosandboxBaseRuntimeLogs(s+e,t)}else if(l.kind===`exited`){c=l.code;break}let l=n.decode(),u=r.decode();if(l.length>0&&(i=appendOutput(i,l),o=emitMicrosandboxBaseRuntimeLogs(o+l,t)),u.length>0&&(a=appendOutput(a,u),s=emitMicrosandboxBaseRuntimeLogs(s+u,t)),emitMicrosandboxBaseRuntimeLogLine(o,t),emitMicrosandboxBaseRuntimeLogLine(s,t),c===void 0)throw Error(`Microsandbox base runtime setup ended without an exit event.`);return{exitCode:c,stderr:a,stdout:i}}function emitMicrosandboxBaseRuntimeLogs(e,t){let n=e.split(/\r?\n/u),r=n.pop()??``;for(let e of n)emitMicrosandboxBaseRuntimeLogLine(e,t);return r}function emitMicrosandboxBaseRuntimeLogLine(e,t){let n=e.match(/^eve-base-runtime: ?(.*)$/u)?.[1];n!==void 0&&n.length>0&&t?.(n)}function appendOutput(e,t){let n=e+t;return n.length>2e4?n.slice(-2e4):n}const MICROSANDBOX_BASE_SETUP_SCRIPT=`
2
2
  set -euo pipefail
3
3
 
4
4
  log_step() {
@@ -1 +1 @@
1
- import{posix}from"node:path";import{access}from"node:fs/promises";import{createHash,randomUUID}from"node:crypto";import{isEveDevEnvironment,loadOptionalEnginePackage}from"#internal/application/optional-package-install.js";import{WORKSPACE_ROOT}from"#runtime/workspace/types.js";import{withDevelopmentSandboxTags}from"#execution/sandbox/development-run.js";import{shellQuote}from"#execution/sandbox/shell-quote.js";import{assertMicrosandboxPlatformCandidate,ensureMicrosandboxBaseRuntime}from"#execution/sandbox/bindings/microsandbox-platform.js";import{MICROSANDBOX_METADATA_VERSION,writeSessionMetadata}from"#execution/sandbox/bindings/microsandbox-metadata.js";import{MICROSANDBOX_USER}from"#execution/sandbox/bindings/microsandbox-options.js";import{applyMicrosandboxNetwork,createMicrosandboxNetworkPlan,createTransformBrokerEnvironment}from"#execution/sandbox/bindings/microsandbox-network.js";import{adaptMicrosandboxExecToSandboxProcess}from"#execution/sandbox/bindings/microsandbox-process.js";const MICROSANDBOX_STOP_TIMEOUT_MS=1e4;var MicrosandboxVm=class{#e;#t;#n;#r;#i;#a;#o;constructor(e,t,n,r,i,a,o){this.#e=e,this.#i=t,this.#a=n,this.#n=r,this.#t=i,this.#r=a,this.#o=o}get id(){return this.#e.sessionKey}async captureState(e){if(this.#r=e,isEveDevEnvironment())return this.#t!==void 0&&await this.writeMetadata(this.#t,e),{networkPolicy:this.#n,optionsHash:e,sandboxName:this.#a,stateSnapshotName:this.#o,version:MICROSANDBOX_METADATA_VERSION};let t=this.#o,n=createProviderName(`eve-sbx-state`,`${this.#e.sessionKey}:${randomUUID()}`);return await this.stopAndSnapshot(n),this.#o=n,this.#t!==void 0&&await this.writeMetadata(this.#t,e),t!==void 0&&await removeSnapshotIfExists(this.#e.module,t),{networkPolicy:this.#n,optionsHash:e,sandboxName:this.#a,stateSnapshotName:n,version:MICROSANDBOX_METADATA_VERSION}}async detach(){await this.#i.detach().catch(()=>{})}async readFileBytes(e){try{let t=this.#i.fs();return await t.exists(e)?Buffer.from(await t.read(e)):null}catch{return null}}async removePath(e){let t=`${e.force===!0?`f`:``}${e.recursive===!0?`r`:``}`,n=`${t.length>0?`rm -${t}`:`rm`} -- ${shellQuote(e.path)}`;await this.runInternalCommand({abortSignal:e.abortSignal,command:n,user:MICROSANDBOX_USER})}async removePersisted(){await removeSandboxIfExists(this.#e.module,this.#a),this.#o!==void 0&&await removeSnapshotIfExists(this.#e.module,this.#o)}async setNetworkPolicy(e){let t=this.#o,n=createProviderName(`eve-sbx-state`,`${this.#e.sessionKey}:${randomUUID()}`),i=this.#a;await this.stopAndSnapshot(n),await removeSandboxIfExists(this.#e.module,i);let a=createProviderName(`eve-sbx-ses`,`${this.#e.sessionKey}:${randomUUID()}`);this.#i=await createMicrosandbox({fromSnapshot:n,module:this.#e.module,name:a,networkPolicy:e,options:this.#e.options,tags:this.#e.tags,user:MICROSANDBOX_USER,workdir:WORKSPACE_ROOT}),this.#a=a,this.#n=e,this.#o=void 0,this.#t!==void 0&&this.#r!==void 0&&await this.writeMetadata(this.#t,this.#r),await removeSnapshotIfExists(this.#e.module,n),t!==void 0&&await removeSnapshotIfExists(this.#e.module,t)}async spawn(e){if(e.abortSignal?.aborted)throw new DOMException(`The operation was aborted.`,`AbortError`);let t={...this.#e.options.env,...createTransformBrokerEnvironment(createMicrosandboxNetworkPlan(this.#n)),...e.env},n=await this.#i.execStreamWith(`bash`,n=>n.args([`-lc`,e.command]).cwd(e.workingDirectory??WORKSPACE_ROOT).envs(t).user(MICROSANDBOX_USER));return e.abortSignal!==void 0&&e.abortSignal.addEventListener(`abort`,()=>{n.kill().catch(()=>{})},{once:!0}),adaptMicrosandboxExecToSandboxProcess(n)}async stopAndSnapshot(e){await this.#i.stop().catch(()=>{}),await stopAndSnapshotMicrosandboxSandbox(this.#e.module,this.#a,e)}async writeFiles(t){let n=this.#i.fs();for(let r of t){let t=posix.dirname(r.path);await this.runInternalCommand({command:`mkdir -p ${shellQuote(t)}`,user:MICROSANDBOX_USER}),await n.write(r.path,r.content),await this.runInternalCommand({command:`chown ${MICROSANDBOX_USER}:${MICROSANDBOX_USER} ${shellQuote(r.path)}`,user:`root`})}}async writeMetadata(e,t){this.#t=e,this.#r=t,await writeSessionMetadata(e,{networkPolicy:this.#n,optionsHash:t,sandboxName:this.#a,stateSnapshotName:this.#o,version:MICROSANDBOX_METADATA_VERSION})}async runInternalCommand(e){if(e.abortSignal?.aborted)throw new DOMException(`The operation was aborted.`,`AbortError`);let t=await this.#i.execWith(`bash`,t=>t.args([`-lc`,e.command]).cwd(WORKSPACE_ROOT).user(e.user));if(t.code!==0){let n=e.failureMessage??`Microsandbox command failed.`;throw Error(`${n} ${t.stderr()}`.trim())}}};async function createPreparedMicrosandbox(e){let t=e.setupBaseRuntime?`allow-all`:e.networkPolicy,n=await createMicrosandbox({fromSnapshot:e.fromSnapshot,module:e.module,name:e.name,networkPolicy:t,options:e.options,tags:e.tags,user:e.setupBaseRuntime?void 0:MICROSANDBOX_USER,workdir:e.setupBaseRuntime?`/`:WORKSPACE_ROOT}),r=new MicrosandboxVm({module:e.module,options:e.options,sessionKey:e.sessionKey,tags:e.tags},n,e.name,t);return e.setupBaseRuntime&&(await withProgressHeartbeat(`preparing base runtime inside VM`,e.log,async()=>{await ensureMicrosandboxBaseRuntime(n,{log:e.log})}),e.networkPolicy!==void 0&&e.networkPolicy!==`allow-all`&&(e.log?.(`applying network policy`),await r.setNetworkPolicy(e.networkPolicy))),r}async function connectMicrosandbox(e){let t;try{t=await e.module.Sandbox.get(e.metadata.sandboxName)}catch(t){if(!isMicrosandboxNotFoundError(t)||e.metadata.stateSnapshotName===void 0)throw t;return await restoreMicrosandboxSessionSnapshot(e)}if(t.status!==`running`&&t.status!==`draining`&&e.metadata.stateSnapshotName!==void 0)return await restoreMicrosandboxSessionSnapshot(e);let n=t.status===`running`||t.status===`draining`?await t.connectWithTimeout(1e4):await t.startDetached();return new MicrosandboxVm({module:e.module,options:e.options,sessionKey:e.sessionKey,tags:e.tags},n,e.metadata.sandboxName,e.metadata.networkPolicy,e.metadataPath,e.metadata.optionsHash,e.metadata.stateSnapshotName)}async function restoreMicrosandboxSessionSnapshot(e){if(e.metadata.stateSnapshotName===void 0||!await snapshotExists(e.module,e.metadata.stateSnapshotName))throw Error(`Microsandbox session snapshot is missing for sandbox "${e.metadata.sandboxName}".`);let t=createProviderName(`eve-sbx-ses`,`${e.sessionKey}:${randomUUID()}`),n=await createMicrosandbox({fromSnapshot:e.metadata.stateSnapshotName,module:e.module,name:t,networkPolicy:e.metadata.networkPolicy,options:e.options,tags:e.tags,user:MICROSANDBOX_USER,workdir:WORKSPACE_ROOT});await removeSandboxIfExists(e.module,e.metadata.sandboxName);let i=new MicrosandboxVm({module:e.module,options:e.options,sessionKey:e.sessionKey,tags:e.tags},n,t,e.metadata.networkPolicy,e.metadataPath,e.metadata.optionsHash,e.metadata.stateSnapshotName);return await i.writeMetadata(e.metadataPath,e.metadata.optionsHash),i}async function loadMicrosandboxModule(e){e.log?.(`checking microsandbox platform support`),await assertMicrosandboxPlatformCandidate();let t=await withProgressHeartbeat(`loading microsandbox npm package`,e.log,()=>loadOptionalEnginePackage({appRoot:e.appRoot,autoInstall:e.options.setup.autoInstall,importModule:async()=>await import(`microsandbox`),missingMessage:"The microsandbox sandbox backend requires the `microsandbox` package, which is not bundled with Eve. Install it in your application (for example `pnpm add -D microsandbox`), or use dockerBackend() / vercelSandboxBackend() instead.",packageName:`microsandbox`}));if(e.log?.(`checking microsandbox VM runtime`),!t.isInstalled()){if(!e.options.setup.autoInstall||!isEveDevEnvironment())throw Error("The microsandbox VM runtime is not installed. Run `npx microsandbox install`, set MSB_PATH for a custom install, or let `eve dev` install it automatically with microsandboxBackend({ setup: { autoInstall: true } }).");await withProgressHeartbeat(`installing microsandbox VM runtime`,e.log,async()=>{await t.setup().skipVerify(e.options.setup.skipVerify).install()})}return e.log?.(`microsandbox runtime ready`),t}async function withProgressHeartbeat(e,t,n){if(t?.(e),t===void 0)return await n();let r=Date.now(),i=setInterval(()=>{t(`${e} (${Math.round((Date.now()-r)/1e3)}s elapsed)`)},1e4);i.unref?.();try{return await n()}finally{clearInterval(i)}}async function loadMicrosandboxWithoutInstall(){try{let e=await import(`microsandbox`);return e.isInstalled()?e:null}catch{return null}}async function stopAndSnapshotMicrosandboxSandbox(e,t,n){for(let r=0;r<3;r+=1){let i=await e.Sandbox.get(t);await i.stopWithTimeout(r===0?MICROSANDBOX_STOP_TIMEOUT_MS:0).catch(()=>{});try{await i.snapshot(n);return}catch(e){if(!isMicrosandboxSnapshotSourceRunningError(e)||r===2)throw e;await i.kill().catch(()=>{}),await new Promise(e=>setTimeout(e,250))}}}async function snapshotExists(e,t){try{return await e.Snapshot.get(t),!0}catch(e){if(isMicrosandboxNotFoundError(e))return!1;throw e}}async function sandboxExists(e,t){try{return await e.Sandbox.get(t),!0}catch(e){if(isMicrosandboxNotFoundError(e))return!1;throw e}}async function removeSnapshotIfExists(e,t){try{await e.Snapshot.remove(t,{force:!0})}catch(e){if(!isMicrosandboxNotFoundError(e))throw e}}function createProviderName(e,t,n=``){return`${e}-${createStableHash(`${t}:${n}`).slice(0,32)}`}function createStableHash(e){return createHash(`sha256`).update(e).digest(`hex`)}async function doesPathExist(e){try{return await access(e),!0}catch{return!1}}async function createMicrosandbox(e){let t=e.module.Sandbox.builder(e.name).cpus(e.options.cpus).detached(!0).envs(e.options.env).labels(resolveMicrosandboxLabels(e.tags)).memory(e.options.memoryMiB).pullPolicy(e.options.pullPolicy).replace().workdir(e.workdir);return t=e.fromSnapshot===void 0?t.image(e.options.image):t.fromSnapshot(e.fromSnapshot),e.user!==void 0&&(t=t.user(e.user)),await applyMicrosandboxNetwork(t,e.networkPolicy).create()}async function removeSandboxIfExists(e,t){for(let n=0;n<3;n+=1)try{let r=await e.Sandbox.get(t);await r.stopWithTimeout(n===0?MICROSANDBOX_STOP_TIMEOUT_MS:0).catch(()=>{}),await r.remove();return}catch(r){if(isMicrosandboxNotFoundError(r))return;if(isMicrosandboxStillRunningError(r)&&n<2){await(await e.Sandbox.get(t).catch(()=>null))?.kill().catch(()=>{}),await new Promise(e=>setTimeout(e,250));continue}throw r}}function isMicrosandboxNotFoundError(e){return e instanceof Error?/not found|not exist|no such/i.test(e.message):!1}function isMicrosandboxStillRunningError(e){return e instanceof Error?/still running/i.test(e.message):!1}function isMicrosandboxSnapshotSourceRunningError(e){return e instanceof Error?/snapshot source sandbox .*not stopped|SnapshotSandboxRunning/i.test(e.message):!1}function resolveMicrosandboxLabels(e){return{"eve.backend":`microsandbox`,...withDevelopmentSandboxTags(e)}}export{MicrosandboxVm,connectMicrosandbox,createPreparedMicrosandbox,createProviderName,createStableHash,doesPathExist,loadMicrosandboxModule,loadMicrosandboxWithoutInstall,removeSnapshotIfExists,sandboxExists,snapshotExists,stopAndSnapshotMicrosandboxSandbox};
1
+ import{posix}from"node:path";import{access}from"node:fs/promises";import{createHash,randomUUID}from"node:crypto";import{isEveDevEnvironment,loadOptionalEnginePackage}from"#internal/application/optional-package-install.js";import{WORKSPACE_ROOT}from"#runtime/workspace/types.js";import{withDevelopmentSandboxTags}from"#execution/sandbox/development-run.js";import{shellQuote}from"#execution/sandbox/shell-quote.js";import{assertMicrosandboxPlatformCandidate,ensureMicrosandboxBaseRuntime}from"#execution/sandbox/bindings/microsandbox-platform.js";import{MICROSANDBOX_METADATA_VERSION,writeSessionMetadata}from"#execution/sandbox/bindings/microsandbox-metadata.js";import{MICROSANDBOX_USER}from"#execution/sandbox/bindings/microsandbox-options.js";import{applyMicrosandboxNetwork,createMicrosandboxNetworkPlan,createTransformBrokerEnvironment}from"#execution/sandbox/bindings/microsandbox-network.js";import{adaptMicrosandboxExecToSandboxProcess}from"#execution/sandbox/bindings/microsandbox-process.js";const MICROSANDBOX_STOP_TIMEOUT_MS=1e4;var MicrosandboxVm=class{#e;#t;#n;#r;#i;#a;#o;constructor(e,t,n,r,i,a,o){this.#e=e,this.#i=t,this.#a=n,this.#n=r,this.#t=i,this.#r=a,this.#o=o}get id(){return this.#e.sessionKey}async captureState(e){if(this.#r=e,isEveDevEnvironment())return this.#t!==void 0&&await this.writeMetadata(this.#t,e),{networkPolicy:this.#n,optionsHash:e,sandboxName:this.#a,stateSnapshotName:this.#o,version:MICROSANDBOX_METADATA_VERSION};let t=this.#o,n=createProviderName(`eve-sbx-state`,`${this.#e.sessionKey}:${randomUUID()}`);return await this.stopAndSnapshot(n),this.#o=n,this.#t!==void 0&&await this.writeMetadata(this.#t,e),t!==void 0&&await removeSnapshotIfExists(this.#e.module,t),{networkPolicy:this.#n,optionsHash:e,sandboxName:this.#a,stateSnapshotName:n,version:MICROSANDBOX_METADATA_VERSION}}async detach(){await this.#i.detach().catch(()=>{})}async readFileBytes(e){try{let t=this.#i.fs();return await t.exists(e)?Buffer.from(await t.read(e)):null}catch{return null}}async removePath(e){let t=`${e.force===!0?`f`:``}${e.recursive===!0?`r`:``}`,n=`${t.length>0?`rm -${t}`:`rm`} -- ${shellQuote(e.path)}`;await this.runInternalCommand({abortSignal:e.abortSignal,command:n,user:MICROSANDBOX_USER})}async removePersisted(){await removeSandboxIfExists(this.#e.module,this.#a),this.#o!==void 0&&await removeSnapshotIfExists(this.#e.module,this.#o)}async setNetworkPolicy(e){let t=this.#o,n=createProviderName(`eve-sbx-state`,`${this.#e.sessionKey}:${randomUUID()}`),i=this.#a;await this.stopAndSnapshot(n),await removeSandboxIfExists(this.#e.module,i);let a=createProviderName(`eve-sbx-ses`,`${this.#e.sessionKey}:${randomUUID()}`);this.#i=await createMicrosandbox({fromSnapshot:n,module:this.#e.module,name:a,networkPolicy:e,options:this.#e.options,tags:this.#e.tags,user:MICROSANDBOX_USER,workdir:WORKSPACE_ROOT}),this.#a=a,this.#n=e,this.#o=void 0,this.#t!==void 0&&this.#r!==void 0&&await this.writeMetadata(this.#t,this.#r),await removeSnapshotIfExists(this.#e.module,n),t!==void 0&&await removeSnapshotIfExists(this.#e.module,t)}async spawn(e){if(e.abortSignal?.aborted)throw new DOMException(`The operation was aborted.`,`AbortError`);let t={...this.#e.options.env,...createTransformBrokerEnvironment(createMicrosandboxNetworkPlan(this.#n)),...e.env},n=await this.#i.execStreamWith(`bash`,n=>n.args([`-lc`,e.command]).cwd(e.workingDirectory??WORKSPACE_ROOT).envs(t).user(MICROSANDBOX_USER));return e.abortSignal!==void 0&&e.abortSignal.addEventListener(`abort`,()=>{n.kill().catch(()=>{})},{once:!0}),adaptMicrosandboxExecToSandboxProcess(n)}async stopAndSnapshot(e){await this.#i.stop().catch(()=>{}),await stopAndSnapshotMicrosandboxSandbox(this.#e.module,this.#a,e)}async writeFiles(t){let n=this.#i.fs();for(let r of t){let t=posix.dirname(r.path);await this.runInternalCommand({command:`mkdir -p ${shellQuote(t)}`,user:MICROSANDBOX_USER}),await n.write(r.path,r.content),await this.runInternalCommand({command:`chown ${MICROSANDBOX_USER}:${MICROSANDBOX_USER} ${shellQuote(r.path)}`,user:`root`})}}async writeMetadata(e,t){this.#t=e,this.#r=t,await writeSessionMetadata(e,{networkPolicy:this.#n,optionsHash:t,sandboxName:this.#a,stateSnapshotName:this.#o,version:MICROSANDBOX_METADATA_VERSION})}async runInternalCommand(e){if(e.abortSignal?.aborted)throw new DOMException(`The operation was aborted.`,`AbortError`);let t=await this.#i.execWith(`bash`,t=>t.args([`-lc`,e.command]).cwd(WORKSPACE_ROOT).user(e.user));if(t.code!==0){let n=e.failureMessage??`Microsandbox command failed.`;throw Error(`${n} ${t.stderr()}`.trim())}}};async function createPreparedMicrosandbox(e){let t=e.setupBaseRuntime?`allow-all`:e.networkPolicy,n=await createMicrosandbox({fromSnapshot:e.fromSnapshot,module:e.module,name:e.name,networkPolicy:t,options:e.options,tags:e.tags,user:e.setupBaseRuntime?void 0:MICROSANDBOX_USER,workdir:e.setupBaseRuntime?`/`:WORKSPACE_ROOT}),r=new MicrosandboxVm({module:e.module,options:e.options,sessionKey:e.sessionKey,tags:e.tags},n,e.name,t);return e.setupBaseRuntime&&(await withProgressHeartbeat(`preparing base runtime inside VM`,e.log,async()=>{await ensureMicrosandboxBaseRuntime(n,{log:e.log})}),e.networkPolicy!==void 0&&e.networkPolicy!==`allow-all`&&(e.log?.(`applying network policy`),await r.setNetworkPolicy(e.networkPolicy))),r}async function connectMicrosandbox(e){let t;try{t=await e.module.Sandbox.get(e.metadata.sandboxName)}catch(t){if(!isMicrosandboxNotFoundError(t)||e.metadata.stateSnapshotName===void 0)throw t;return await restoreMicrosandboxSessionSnapshot(e)}if(t.status!==`running`&&t.status!==`draining`&&e.metadata.stateSnapshotName!==void 0)return await restoreMicrosandboxSessionSnapshot(e);let n=t.status===`running`||t.status===`draining`?await t.connectWithTimeout(1e4):await t.startDetached();return new MicrosandboxVm({module:e.module,options:e.options,sessionKey:e.sessionKey,tags:e.tags},n,e.metadata.sandboxName,e.metadata.networkPolicy,e.metadataPath,e.metadata.optionsHash,e.metadata.stateSnapshotName)}async function restoreMicrosandboxSessionSnapshot(e){if(e.metadata.stateSnapshotName===void 0||!await snapshotExists(e.module,e.metadata.stateSnapshotName))throw Error(`Microsandbox session snapshot is missing for sandbox "${e.metadata.sandboxName}".`);let t=createProviderName(`eve-sbx-ses`,`${e.sessionKey}:${randomUUID()}`),n=await createMicrosandbox({fromSnapshot:e.metadata.stateSnapshotName,module:e.module,name:t,networkPolicy:e.metadata.networkPolicy,options:e.options,tags:e.tags,user:MICROSANDBOX_USER,workdir:WORKSPACE_ROOT});await removeSandboxIfExists(e.module,e.metadata.sandboxName);let i=new MicrosandboxVm({module:e.module,options:e.options,sessionKey:e.sessionKey,tags:e.tags},n,t,e.metadata.networkPolicy,e.metadataPath,e.metadata.optionsHash,e.metadata.stateSnapshotName);return await i.writeMetadata(e.metadataPath,e.metadata.optionsHash),i}async function loadMicrosandboxModule(e){e.log?.(`checking microsandbox platform support`),await assertMicrosandboxPlatformCandidate();let t=await withProgressHeartbeat(`loading microsandbox npm package`,e.log,()=>loadOptionalEnginePackage({appRoot:e.appRoot,autoInstall:e.options.setup.autoInstall,importModule:async()=>await import(`microsandbox`),missingMessage:"The microsandbox sandbox backend requires the `microsandbox` package, which is not bundled with Eve. Install it in your application (for example `pnpm add -D microsandbox`), or use docker() / vercel() instead.",packageName:`microsandbox`}));if(e.log?.(`checking microsandbox VM runtime`),!t.isInstalled()){if(!e.options.setup.autoInstall||!isEveDevEnvironment())throw Error("The microsandbox VM runtime is not installed. Run `npx microsandbox install`, set MSB_PATH for a custom install, or let `eve dev` install it automatically with microsandbox({ setup: { autoInstall: true } }).");await withProgressHeartbeat(`installing microsandbox VM runtime`,e.log,async()=>{await t.setup().skipVerify(e.options.setup.skipVerify).install()})}return e.log?.(`microsandbox runtime ready`),t}async function withProgressHeartbeat(e,t,n){if(t?.(e),t===void 0)return await n();let r=Date.now(),i=setInterval(()=>{t(`${e} (${Math.round((Date.now()-r)/1e3)}s elapsed)`)},1e4);i.unref?.();try{return await n()}finally{clearInterval(i)}}async function loadMicrosandboxWithoutInstall(){try{let e=await import(`microsandbox`);return e.isInstalled()?e:null}catch{return null}}async function stopAndSnapshotMicrosandboxSandbox(e,t,n){for(let r=0;r<3;r+=1){let i=await e.Sandbox.get(t);await i.stopWithTimeout(r===0?MICROSANDBOX_STOP_TIMEOUT_MS:0).catch(()=>{});try{await i.snapshot(n);return}catch(e){if(!isMicrosandboxSnapshotSourceRunningError(e)||r===2)throw e;await i.kill().catch(()=>{}),await new Promise(e=>setTimeout(e,250))}}}async function snapshotExists(e,t){try{return await e.Snapshot.get(t),!0}catch(e){if(isMicrosandboxNotFoundError(e))return!1;throw e}}async function sandboxExists(e,t){try{return await e.Sandbox.get(t),!0}catch(e){if(isMicrosandboxNotFoundError(e))return!1;throw e}}async function removeSnapshotIfExists(e,t){try{await e.Snapshot.remove(t,{force:!0})}catch(e){if(!isMicrosandboxNotFoundError(e))throw e}}function createProviderName(e,t,n=``){return`${e}-${createStableHash(`${t}:${n}`).slice(0,32)}`}function createStableHash(e){return createHash(`sha256`).update(e).digest(`hex`)}async function doesPathExist(e){try{return await access(e),!0}catch{return!1}}async function createMicrosandbox(e){let t=e.module.Sandbox.builder(e.name).cpus(e.options.cpus).detached(!0).envs(e.options.env).labels(resolveMicrosandboxLabels(e.tags)).memory(e.options.memoryMiB).pullPolicy(e.options.pullPolicy).replace().workdir(e.workdir);return t=e.fromSnapshot===void 0?t.image(e.options.image):t.fromSnapshot(e.fromSnapshot),e.user!==void 0&&(t=t.user(e.user)),await applyMicrosandboxNetwork(t,e.networkPolicy).create()}async function removeSandboxIfExists(e,t){for(let n=0;n<3;n+=1)try{let r=await e.Sandbox.get(t);await r.stopWithTimeout(n===0?MICROSANDBOX_STOP_TIMEOUT_MS:0).catch(()=>{}),await r.remove();return}catch(r){if(isMicrosandboxNotFoundError(r))return;if(isMicrosandboxStillRunningError(r)&&n<2){await(await e.Sandbox.get(t).catch(()=>null))?.kill().catch(()=>{}),await new Promise(e=>setTimeout(e,250));continue}throw r}}function isMicrosandboxNotFoundError(e){return e instanceof Error?/not found|not exist|no such/i.test(e.message):!1}function isMicrosandboxStillRunningError(e){return e instanceof Error?/still running/i.test(e.message):!1}function isMicrosandboxSnapshotSourceRunningError(e){return e instanceof Error?/snapshot source sandbox .*not stopped|SnapshotSandboxRunning/i.test(e.message):!1}function resolveMicrosandboxLabels(e){return{"eve.backend":`microsandbox`,...withDevelopmentSandboxTags(e)}}export{MicrosandboxVm,connectMicrosandbox,createPreparedMicrosandbox,createProviderName,createStableHash,doesPathExist,loadMicrosandboxModule,loadMicrosandboxWithoutInstall,removeSnapshotIfExists,sandboxExists,snapshotExists,stopAndSnapshotMicrosandboxSandbox};
@@ -8,7 +8,7 @@ export { pruneMicrosandboxTemplates } from "#execution/sandbox/bindings/microsan
8
8
  export declare const MICROSANDBOX_BACKEND_NAME = "microsandbox";
9
9
  /**
10
10
  * Construction input for {@link createMicrosandboxSandboxBackend}.
11
- * Internal — the public surface is the `microsandboxBackend()` factory
11
+ * Internal — the public surface is the `microsandbox()` factory
12
12
  * under `eve/sandbox`.
13
13
  */
14
14
  export interface CreateMicrosandboxSandboxBackendInput {
@@ -3,11 +3,11 @@ import type { SandboxBackend } from "#public/definitions/sandbox-backend.js";
3
3
  import type { VercelSandboxBootstrapUseOptions, VercelSandboxSessionUseOptions } from "#public/sandbox/vercel-sandbox.js";
4
4
  import { type CreateVercelSandbox, type VercelSandboxModule } from "#execution/sandbox/bindings/vercel-create-sdk.js";
5
5
  /**
6
- * Construction input for {@link createVercelSandboxBackend}. Internal —
7
- * the public surface is the `vercelSandboxBackend()` factory under
6
+ * Construction input for {@link createVercelSandbox}. Internal —
7
+ * the public surface is the `vercel()` factory under
8
8
  * `eve/sandbox`.
9
9
  */
10
- export interface CreateVercelSandboxBackendInput {
10
+ export interface CreateVercelSandboxInput {
11
11
  readonly createSandbox?: CreateVercelSandbox;
12
12
  readonly createOptions?: SandboxCreateOptions;
13
13
  readonly loadSandboxModule?: () => Promise<VercelSandboxModule>;
@@ -20,4 +20,4 @@ export interface CreateVercelSandboxBackendInput {
20
20
  * prewarm time, session at first-time session-create). On resume
21
21
  * (`Sandbox.get`) no create happens, so they are not re-applied.
22
22
  */
23
- export declare function createVercelSandboxBackend(input?: CreateVercelSandboxBackendInput): SandboxBackend<VercelSandboxBootstrapUseOptions, VercelSandboxSessionUseOptions>;
23
+ export declare function createVercelSandbox(input?: CreateVercelSandboxInput): SandboxBackend<VercelSandboxBootstrapUseOptions, VercelSandboxSessionUseOptions>;
@@ -1 +1 @@
1
- import{WORKSPACE_ROOT}from"#runtime/workspace/types.js";import{streamToBuffer}from"#execution/sandbox/stream-utils.js";import{createLoggingSandboxSession}from"#execution/sandbox/logging-session.js";import{buildSandboxSession}from"#execution/sandbox/session.js";import{SandboxTemplateNotProvisionedError}from"#public/definitions/sandbox-backend.js";import{applyInitialVercelNetworkPolicy,ensureVercelSandboxBaseRuntime}from"#execution/sandbox/bindings/vercel-base-runtime.js";import{createVercelEveImageSandbox}from"#execution/sandbox/bindings/vercel-create-sdk.js";import{isVercelSnapshotUnavailableError}from"#execution/sandbox/bindings/vercel-errors.js";import{getNamedVercelSandbox}from"#execution/sandbox/bindings/vercel-lookup.js";function createVercelSandboxBackend(e={}){let t=e.loadSandboxModule??(async()=>await import(`#compiled/@vercel/sandbox/index.js`)),n={timeout:DEFAULT_SANDBOX_TIMEOUT_MS,...e.createOptions},r=e.createSandbox??createVercelEveImageSandbox,u=new Map;return{name:`vercel`,async create(e){let s=resolveVercelSandboxTags(n.tags,e.tags),l=e.templateKey===null?null:await readTemplateForCreate({createOptions:n,loadSandboxModule:t,prewarmedTemplates:u,templateKey:e.templateKey}),d=await t(),f;try{f=await ensureSession({createOptions:n,createSandbox:r,existingMetadata:e.existingMetadata,sandboxModule:d,sessionKey:e.sessionKey,snapshotId:l?.snapshotId,tags:s})}catch(t){throw l!==null&&isVercelSnapshotUnavailableError(t)?(u.delete(l.templateKey),await(await getNamedVercelSandbox({createOptions:n,sandboxModule:d,sandboxName:l.sandboxName}))?.delete(),new SandboxTemplateNotProvisionedError({backendName:`vercel`,templateKey:l.templateKey})):Error(`Failed to create sandbox session "${e.sessionKey}": ${errorMessage(t)}`,{cause:t})}return l===null&&f.created&&(await ensureVercelSandboxBaseRuntime(f.sandbox),await applyInitialVercelNetworkPolicy(f.sandbox,n.networkPolicy)),createHandle(f.sandbox,e.sessionKey)},async prewarm(e){let i;try{i=await ensureTemplate({bootstrap:e.bootstrap,createOptions:n,createSandbox:r,loadSandboxModule:t,log:e.log,seedFiles:e.seedFiles,templateKey:e.templateKey})}catch(t){throw Error(`Failed to prewarm Vercel sandbox template "${e.templateKey}": ${errorMessage(t)}`,{cause:t})}return u.set(e.templateKey,i.template),{reused:i.reused}}}}async function readTemplate(e){let t=e.prewarmedTemplates.get(e.templateKey);if(t!==void 0)return t;let n=await e.loadSandboxModule(),r=await getNamedVercelSandbox({createOptions:e.createOptions,sandboxModule:n,sandboxName:e.templateKey});if(r===null||typeof r.currentSnapshotId!=`string`)throw new SandboxTemplateNotProvisionedError({backendName:`vercel`,templateKey:e.templateKey});return{sandboxName:r.name,snapshotId:r.currentSnapshotId,templateKey:e.templateKey}}async function readTemplateForCreate(e){try{return await readTemplate(e)}catch(t){throw SandboxTemplateNotProvisionedError.is(t)?t:Error(`Failed to read sandbox template "${e.templateKey}": ${errorMessage(t)}`,{cause:t})}}async function ensureTemplate(e){let t=await e.loadSandboxModule(),i=await getNamedVercelSandbox({createOptions:e.createOptions,sandboxModule:t,sandboxName:e.templateKey}),s=resolveVercelSandboxTags(e.createOptions.tags,e.tags),c=extractAuthorSnapshotId(e.createOptions);if(i!==null&&isUnprovisionedTerminalTemplateSandbox(i,c)&&(await i.delete(),i=null),i===null?i=await e.createSandbox({sandboxModule:t,createOptions:withBaseSetupNetworkPolicy({...e.createOptions,name:e.templateKey,persistent:!1,tags:s})}):await ensureVercelSandboxTags(i,s),typeof i.currentSnapshotId==`string`&&i.currentSnapshotId.length>0&&i.currentSnapshotId!==c)return{reused:!0,template:{sandboxName:i.name,snapshotId:i.currentSnapshotId,templateKey:e.templateKey}};e.log?.(`preparing base runtime inside sandbox`),await ensureVercelSandboxBaseRuntime(i),await applyInitialVercelNetworkPolicy(i,e.createOptions.networkPolicy);let l=buildSandboxSession(createVercelInternalSandboxSession(i,e.templateKey),createVercelNetworkPolicySetter(i));e.bootstrap!==void 0&&(e.log?.(`running sandbox bootstrap`),await e.bootstrap({use:async t=>(t!==void 0&&await i.update(t),createLoggingSandboxSession({log:e.log,session:l}))}));for(let t of e.seedFiles)typeof t.content==`string`?await l.writeTextFile({content:t.content,path:t.path}):await l.writeBinaryFile({content:t.content,path:t.path});let u=await i.snapshot();return{reused:!1,template:{sandboxName:i.name,snapshotId:u.snapshotId,templateKey:e.templateKey}}}async function ensureSession(e){let t=getVercelSandboxName(e.existingMetadata)??e.sessionKey,n=await getNamedVercelSandbox({createOptions:e.createOptions,sandboxModule:e.sandboxModule,sandboxName:t});if(n!==null)return await ensureVercelSandboxTags(n,e.tags),{created:!1,sandbox:n};let r=createSessionCreateParams(e,t);return e.tags!==void 0&&(r.tags=e.tags),{created:!0,sandbox:await e.createSandbox({createOptions:r,sandboxModule:e.sandboxModule})}}function createSessionCreateParams(e,t){if(e.snapshotId===void 0)return withBaseSetupNetworkPolicy({...e.createOptions,name:t,persistent:!0});let{runtime:n,source:r,...i}=e.createOptions;return{...i,name:t,persistent:!0,source:{snapshotId:e.snapshotId,type:`snapshot`}}}function withBaseSetupNetworkPolicy(e){return{...e,networkPolicy:`allow-all`}}function createHandle(e,t){return{session:buildSandboxSession(createVercelInternalSandboxSession(e,t),createVercelNetworkPolicySetter(e)),useSessionFn:async n=>(n!==void 0&&await e.update(n),buildSandboxSession(createVercelInternalSandboxSession(e,t),createVercelNetworkPolicySetter(e))),async captureState(){return{backendName:`vercel`,metadata:{sandboxName:e.name},sessionKey:t}},async dispose(){}}}function createVercelNetworkPolicySetter(e){return async t=>{await e.update({networkPolicy:t})}}function createVercelInternalSandboxSession(n,r){return{id:r,resolvePath:resolveVercelSandboxPath,async spawn(t){return adaptVercelCommandToSandboxProcess(await n.runCommand({args:[`-lc`,t.command],cmd:`bash`,cwd:t.workingDirectory??WORKSPACE_ROOT,detached:!0,env:t.env,signal:t.abortSignal}))},async readFile(e){return await n.readFile({path:e.path})??null},async writeFile(e){let r=await streamToBuffer(e.content);await n.writeFiles([{content:r,path:e.path}])},async removePath(e){await n.fs.rm(e.path,{force:e.force,recursive:e.recursive,signal:e.abortSignal})}}}function adaptVercelCommandToSandboxProcess(e){let t=new TextEncoder,n,r,i=!1,a,o=new ReadableStream({start(e){n=e}}),s=new ReadableStream({start(e){r=e}});return(async()=>{try{for await(let i of e.logs()){let e=t.encode(i.data);i.stream===`stdout`?n?.enqueue(e):r?.enqueue(e)}}catch(e){a=e,n?.error(e),r?.error(e)}finally{i=!0,a===void 0&&(n?.close(),r?.close())}})(),{stdout:o,stderr:s,async wait(){let t=await e.wait();for(;!i;)await new Promise(e=>setTimeout(e,0));if(a!==void 0)throw a;return{exitCode:t.exitCode}},async kill(){await e.kill()}}}function resolveVercelSandboxPath(t){return t.startsWith(`/`)?t:`${WORKSPACE_ROOT}/${t}`}function isUnprovisionedTerminalTemplateSandbox(e,t){let n=e.currentSnapshotId;return typeof n==`string`&&n.length>0&&n!==t?!1:e.status===`aborted`||e.status===`failed`||e.status===`stopped`}function extractAuthorSnapshotId(e){let t=e.source;if(t?.type===`snapshot`&&typeof t.snapshotId==`string`)return t.snapshotId}function getVercelSandboxName(e){let t=e?.sandboxName;return typeof t==`string`?t:void 0}function resolveVercelSandboxTags(e,t){let n={};if(e!==void 0)for(let[t,r]of Object.entries(e))n[t]=r;if(t!==void 0)for(let[e,r]of Object.entries(t))n[e]=r;let r=Object.keys(n).length;if(r!==0){if(r>VERCEL_SANDBOX_TAG_LIMIT)throw Error(`Vercel Sandbox supports at most ${VERCEL_SANDBOX_TAG_LIMIT} tags. Eve reserves "agent", "channel", and "sessionId"; remove or consolidate custom tags passed to vercelSandboxBackend().`);return n}}async function ensureVercelSandboxTags(e,t){t===void 0||areVercelSandboxTagsEqual(e.tags,t)||await e.update({tags:t})}function areVercelSandboxTagsEqual(e,t){let n=e??{},r=Object.entries(n),i=Object.entries(t);return r.length===i.length?i.every(([e,t])=>n[e]===t):!1}function errorMessage(e){if(e instanceof Error){let t=e.json,n=e.text,r=typeof n==`string`&&n.length>0?n:t===void 0?void 0:JSON.stringify(t);return r===void 0?e.message:`${e.message}: ${r}`}return String(e)}const DEFAULT_SANDBOX_TIMEOUT_MS=1800*1e3,VERCEL_SANDBOX_TAG_LIMIT=5;export{createVercelSandboxBackend};
1
+ import{WORKSPACE_ROOT}from"#runtime/workspace/types.js";import{streamToBuffer}from"#execution/sandbox/stream-utils.js";import{createLoggingSandboxSession}from"#execution/sandbox/logging-session.js";import{buildSandboxSession}from"#execution/sandbox/session.js";import{SandboxTemplateNotProvisionedError}from"#public/definitions/sandbox-backend.js";import{applyInitialVercelNetworkPolicy,ensureVercelSandboxBaseRuntime}from"#execution/sandbox/bindings/vercel-base-runtime.js";import{createVercelEveImageSandbox}from"#execution/sandbox/bindings/vercel-create-sdk.js";import{isVercelSnapshotUnavailableError}from"#execution/sandbox/bindings/vercel-errors.js";import{getNamedVercelSandbox}from"#execution/sandbox/bindings/vercel-lookup.js";function createVercelSandbox(e={}){let t=e.loadSandboxModule??(async()=>await import(`#compiled/@vercel/sandbox/index.js`)),n={timeout:DEFAULT_SANDBOX_TIMEOUT_MS,...e.createOptions},r=e.createSandbox??createVercelEveImageSandbox,u=new Map;return{name:`vercel`,async create(e){let s=resolveVercelSandboxTags(n.tags,e.tags),l=e.templateKey===null?null:await readTemplateForCreate({createOptions:n,loadSandboxModule:t,prewarmedTemplates:u,templateKey:e.templateKey}),d=await t(),f;try{f=await ensureSession({createOptions:n,createSandbox:r,existingMetadata:e.existingMetadata,sandboxModule:d,sessionKey:e.sessionKey,snapshotId:l?.snapshotId,tags:s})}catch(t){throw l!==null&&isVercelSnapshotUnavailableError(t)?(u.delete(l.templateKey),await(await getNamedVercelSandbox({createOptions:n,sandboxModule:d,sandboxName:l.sandboxName}))?.delete(),new SandboxTemplateNotProvisionedError({backendName:`vercel`,templateKey:l.templateKey})):Error(`Failed to create sandbox session "${e.sessionKey}": ${errorMessage(t)}`,{cause:t})}return l===null&&f.created&&(await ensureVercelSandboxBaseRuntime(f.sandbox),await applyInitialVercelNetworkPolicy(f.sandbox,n.networkPolicy)),createHandle(f.sandbox,e.sessionKey)},async prewarm(e){let i;try{i=await ensureTemplate({bootstrap:e.bootstrap,createOptions:n,createSandbox:r,loadSandboxModule:t,log:e.log,seedFiles:e.seedFiles,templateKey:e.templateKey})}catch(t){throw Error(`Failed to prewarm Vercel sandbox template "${e.templateKey}": ${errorMessage(t)}`,{cause:t})}return u.set(e.templateKey,i.template),{reused:i.reused}}}}async function readTemplate(e){let t=e.prewarmedTemplates.get(e.templateKey);if(t!==void 0)return t;let n=await e.loadSandboxModule(),r=await getNamedVercelSandbox({createOptions:e.createOptions,sandboxModule:n,sandboxName:e.templateKey});if(r===null||typeof r.currentSnapshotId!=`string`)throw new SandboxTemplateNotProvisionedError({backendName:`vercel`,templateKey:e.templateKey});return{sandboxName:r.name,snapshotId:r.currentSnapshotId,templateKey:e.templateKey}}async function readTemplateForCreate(e){try{return await readTemplate(e)}catch(t){throw SandboxTemplateNotProvisionedError.is(t)?t:Error(`Failed to read sandbox template "${e.templateKey}": ${errorMessage(t)}`,{cause:t})}}async function ensureTemplate(e){let t=await e.loadSandboxModule(),i=await getNamedVercelSandbox({createOptions:e.createOptions,sandboxModule:t,sandboxName:e.templateKey}),s=resolveVercelSandboxTags(e.createOptions.tags,e.tags),c=extractAuthorSnapshotId(e.createOptions);if(i!==null&&isUnprovisionedTerminalTemplateSandbox(i,c)&&(await i.delete(),i=null),i===null?i=await e.createSandbox({sandboxModule:t,createOptions:withBaseSetupNetworkPolicy({...e.createOptions,name:e.templateKey,persistent:!1,tags:s})}):await ensureVercelSandboxTags(i,s),typeof i.currentSnapshotId==`string`&&i.currentSnapshotId.length>0&&i.currentSnapshotId!==c)return{reused:!0,template:{sandboxName:i.name,snapshotId:i.currentSnapshotId,templateKey:e.templateKey}};e.log?.(`preparing base runtime inside sandbox`),await ensureVercelSandboxBaseRuntime(i),await applyInitialVercelNetworkPolicy(i,e.createOptions.networkPolicy);let l=buildSandboxSession(createVercelInternalSandboxSession(i,e.templateKey),createVercelNetworkPolicySetter(i));e.bootstrap!==void 0&&(e.log?.(`running sandbox bootstrap`),await e.bootstrap({use:async t=>(t!==void 0&&await i.update(t),createLoggingSandboxSession({log:e.log,session:l}))}));for(let t of e.seedFiles)typeof t.content==`string`?await l.writeTextFile({content:t.content,path:t.path}):await l.writeBinaryFile({content:t.content,path:t.path});let u=await i.snapshot();return{reused:!1,template:{sandboxName:i.name,snapshotId:u.snapshotId,templateKey:e.templateKey}}}async function ensureSession(e){let t=getVercelSandboxName(e.existingMetadata)??e.sessionKey,n=await getNamedVercelSandbox({createOptions:e.createOptions,sandboxModule:e.sandboxModule,sandboxName:t});if(n!==null)return await ensureVercelSandboxTags(n,e.tags),{created:!1,sandbox:n};let r=createSessionCreateParams(e,t);return e.tags!==void 0&&(r.tags=e.tags),{created:!0,sandbox:await e.createSandbox({createOptions:r,sandboxModule:e.sandboxModule})}}function createSessionCreateParams(e,t){if(e.snapshotId===void 0)return withBaseSetupNetworkPolicy({...e.createOptions,name:t,persistent:!0});let{runtime:n,source:r,...i}=e.createOptions;return{...i,name:t,persistent:!0,source:{snapshotId:e.snapshotId,type:`snapshot`}}}function withBaseSetupNetworkPolicy(e){return{...e,networkPolicy:`allow-all`}}function createHandle(e,t){return{session:buildSandboxSession(createVercelInternalSandboxSession(e,t),createVercelNetworkPolicySetter(e)),useSessionFn:async n=>(n!==void 0&&await e.update(n),buildSandboxSession(createVercelInternalSandboxSession(e,t),createVercelNetworkPolicySetter(e))),async captureState(){return{backendName:`vercel`,metadata:{sandboxName:e.name},sessionKey:t}},async dispose(){}}}function createVercelNetworkPolicySetter(e){return async t=>{await e.update({networkPolicy:t})}}function createVercelInternalSandboxSession(n,r){return{id:r,resolvePath:resolveVercelSandboxPath,async spawn(t){return adaptVercelCommandToSandboxProcess(await n.runCommand({args:[`-lc`,t.command],cmd:`bash`,cwd:t.workingDirectory??WORKSPACE_ROOT,detached:!0,env:t.env,signal:t.abortSignal}))},async readFile(e){return await n.readFile({path:e.path})??null},async writeFile(e){let r=await streamToBuffer(e.content);await n.writeFiles([{content:r,path:e.path}])},async removePath(e){await n.fs.rm(e.path,{force:e.force,recursive:e.recursive,signal:e.abortSignal})}}}function adaptVercelCommandToSandboxProcess(e){let t=new TextEncoder,n,r,i=!1,a,o=new ReadableStream({start(e){n=e}}),s=new ReadableStream({start(e){r=e}});return(async()=>{try{for await(let i of e.logs()){let e=t.encode(i.data);i.stream===`stdout`?n?.enqueue(e):r?.enqueue(e)}}catch(e){a=e,n?.error(e),r?.error(e)}finally{i=!0,a===void 0&&(n?.close(),r?.close())}})(),{stdout:o,stderr:s,async wait(){let t=await e.wait();for(;!i;)await new Promise(e=>setTimeout(e,0));if(a!==void 0)throw a;return{exitCode:t.exitCode}},async kill(){await e.kill()}}}function resolveVercelSandboxPath(t){return t.startsWith(`/`)?t:`${WORKSPACE_ROOT}/${t}`}function isUnprovisionedTerminalTemplateSandbox(e,t){let n=e.currentSnapshotId;return typeof n==`string`&&n.length>0&&n!==t?!1:e.status===`aborted`||e.status===`failed`||e.status===`stopped`}function extractAuthorSnapshotId(e){let t=e.source;if(t?.type===`snapshot`&&typeof t.snapshotId==`string`)return t.snapshotId}function getVercelSandboxName(e){let t=e?.sandboxName;return typeof t==`string`?t:void 0}function resolveVercelSandboxTags(e,t){let n={};if(e!==void 0)for(let[t,r]of Object.entries(e))n[t]=r;if(t!==void 0)for(let[e,r]of Object.entries(t))n[e]=r;let r=Object.keys(n).length;if(r!==0){if(r>VERCEL_SANDBOX_TAG_LIMIT)throw Error(`Vercel Sandbox supports at most ${VERCEL_SANDBOX_TAG_LIMIT} tags. Eve reserves "agent", "channel", and "sessionId"; remove or consolidate custom tags passed to vercel().`);return n}}async function ensureVercelSandboxTags(e,t){t===void 0||areVercelSandboxTagsEqual(e.tags,t)||await e.update({tags:t})}function areVercelSandboxTagsEqual(e,t){let n=e??{},r=Object.entries(n),i=Object.entries(t);return r.length===i.length?i.every(([e,t])=>n[e]===t):!1}function errorMessage(e){if(e instanceof Error){let t=e.json,n=e.text,r=typeof n==`string`&&n.length>0?n:t===void 0?void 0:JSON.stringify(t);return r===void 0?e.message:`${e.message}: ${r}`}return String(e)}const DEFAULT_SANDBOX_TIMEOUT_MS=1800*1e3,VERCEL_SANDBOX_TAG_LIMIT=5;export{createVercelSandbox};
@@ -21,7 +21,7 @@ export interface EnsureSandboxAccessInput {
21
21
  *
22
22
  * Every agent has exactly one sandbox. The sandbox carries its own
23
23
  * `SandboxBackend` value (resolved from the authored module or
24
- * substituted with `defaultBackend()` when omitted), and the runtime
24
+ * substituted with `defaultSandbox()` when omitted), and the runtime
25
25
  * simply calls `backend.create(...)`.
26
26
  */
27
27
  export declare function ensureSandboxAccess(input: EnsureSandboxAccessInput): Promise<SandboxAccess>;
@@ -5,9 +5,9 @@ import type { SandboxBackend } from "#public/definitions/sandbox-backend.js";
5
5
  * `.create`, or `.prewarm`. Subsequent accesses return the same cached
6
6
  * underlying backend.
7
7
  *
8
- * Used by `defaultBackend()` for env-conditional selection, and by the
8
+ * Used by `defaultSandbox()` for env-conditional selection, and by the
9
9
  * authored-definition normalizer when an author passes a callback to
10
- * `SandboxDefinition.backend` (e.g. `backend: () => vercelSandboxBackend({...})`)
10
+ * `SandboxDefinition.backend` (e.g. `backend: () => vercel({...})`)
11
11
  * so the factory runs at first use rather than at module load — while
12
12
  * still preserving backend-internal state (such as the Vercel backend's
13
13
  * prewarmed-templates map) across every framework call.
@@ -1 +1 @@
1
- import{createRequire}from"node:module";import{basename,dirname,join}from"node:path";import{existsSync,readFileSync,realpathSync}from"node:fs";import{EVE_PACKAGE_NAME}from"#internal/package-name.js";import{fileURLToPath}from"node:url";let cachedPackageInfo;const BUNDLED_FALLBACK_PACKAGE_VERSION=`0.8.6`,WORKFLOW_MODULE_ALIASES={"workflow/api":`src/compiled/@workflow/core/runtime.js`,"workflow/errors":`src/compiled/@workflow/errors/index.js`,"workflow/internal/private":`src/compiled/@workflow/core/private.js`,"workflow/runtime":`src/compiled/@workflow/core/runtime.js`};function resolveFallbackPackageVersion(){return BUNDLED_FALLBACK_PACKAGE_VERSION.startsWith(`__`)?`0.0.0`:BUNDLED_FALLBACK_PACKAGE_VERSION}const FALLBACK_PACKAGE_INFO={name:EVE_PACKAGE_NAME,version:resolveFallbackPackageVersion()};function resolveCurrentModulePath(){return typeof __filename==`string`?__filename:resolveCurrentModulePathFromStack()}function resolveCurrentModulePathFromStack(){let e=Error.prepareStackTrace;try{Error.prepareStackTrace=(e,t)=>t;let e=Error().stack?.[0]?.getFileName();if(typeof e!=`string`||e.length===0)throw Error(`Failed to resolve the current module path from the stack trace.`);return e.startsWith(`file:`)?fileURLToPath(e):e}finally{Error.prepareStackTrace=e}}const require=createRequire(resolveCurrentModulePath());function isBuildOutputPackageRoot(e){return basename(e)===`dist`&&existsSync(join(dirname(e),`package.json`))}function resolvePackageBuildRoot(){let e=dirname(realpathSync(resolveCurrentModulePath()));for(;;){if(isBuildOutputPackageRoot(e))return e;let t=dirname(e);if(t===e)return null;e=t}}function findNearestPackageRoot(e){let t=e;for(;;){if(existsSync(join(t,`package.json`))&&!isBuildOutputPackageRoot(t))return t;let r=dirname(t);if(r===t)throw Error(`Failed to resolve package root from "${e}".`);t=r}}function resolvePackageRoot(){return findNearestPackageRoot(dirname(realpathSync(resolveCurrentModulePath())))}function tryResolvePackageRoot(){try{return resolvePackageRoot()}catch{return}}function rewriteSourceFilePathForBuild(e){return e.replace(/\.[cm]?tsx?$/,`.js`)}function resolvePackageSourceFilePath(e){let t=resolvePackageBuildRoot();return t===null?join(resolvePackageRoot(),e):join(t,rewriteSourceFilePathForBuild(e))}function resolvePackageSourceDirectoryPath(e){let t=resolvePackageBuildRoot();return join(t===null?resolvePackageRoot():t,e)}function resolvePackageDependencyPath(e){return require.resolve(e)}function resolvePackageCompiledFilePath(e){let t=resolvePackageBuildRoot();return t===null?join(resolvePackageRoot(),`.generated`,`compiled`,e.replace(/^src\/compiled\//,``)):join(t,e)}function normalizeInstalledPackageInfo(e){let t=e;if(!(typeof t.name!=`string`||typeof t.version!=`string`))return{name:t.name,version:t.version}}function tryReadInstalledPackageInfo(e,t){let n=normalizeInstalledPackageInfo(JSON.parse(readFileSync(e,`utf8`)));if(n?.name===t)return n}function resolveInstalledPackageInfo(){if(cachedPackageInfo)return cachedPackageInfo;let e=tryResolvePackageRoot(),t=e===void 0?void 0:tryReadInstalledPackageInfo(join(e,`package.json`),EVE_PACKAGE_NAME);if(t)return cachedPackageInfo=t,cachedPackageInfo;try{let e=tryReadInstalledPackageInfo(require.resolve(`${EVE_PACKAGE_NAME}/package.json`),EVE_PACKAGE_NAME);if(e)return cachedPackageInfo=e,cachedPackageInfo}catch{}return cachedPackageInfo={...FALLBACK_PACKAGE_INFO},cachedPackageInfo}function resolveWorkflowModulePath(e){if(e===`workflow`)return resolvePackageSourceFilePath(`src/internal/workflow/index.ts`);if(e===`workflow/internal/builtins`)return resolvePackageSourceFilePath(`src/internal/workflow/builtins.ts`);let t=WORKFLOW_MODULE_ALIASES[e];return t===void 0?require.resolve(e):resolvePackageCompiledFilePath(t)}export{resolveInstalledPackageInfo,resolvePackageDependencyPath,resolvePackageRoot,resolvePackageSourceDirectoryPath,resolvePackageSourceFilePath,resolveWorkflowModulePath};
1
+ import{createRequire}from"node:module";import{basename,dirname,join}from"node:path";import{existsSync,readFileSync,realpathSync}from"node:fs";import{EVE_PACKAGE_NAME}from"#internal/package-name.js";import{fileURLToPath}from"node:url";let cachedPackageInfo;const BUNDLED_FALLBACK_PACKAGE_VERSION=`0.9.0`,WORKFLOW_MODULE_ALIASES={"workflow/api":`src/compiled/@workflow/core/runtime.js`,"workflow/errors":`src/compiled/@workflow/errors/index.js`,"workflow/internal/private":`src/compiled/@workflow/core/private.js`,"workflow/runtime":`src/compiled/@workflow/core/runtime.js`};function resolveFallbackPackageVersion(){return BUNDLED_FALLBACK_PACKAGE_VERSION.startsWith(`__`)?`0.0.0`:BUNDLED_FALLBACK_PACKAGE_VERSION}const FALLBACK_PACKAGE_INFO={name:EVE_PACKAGE_NAME,version:resolveFallbackPackageVersion()};function resolveCurrentModulePath(){return typeof __filename==`string`?__filename:resolveCurrentModulePathFromStack()}function resolveCurrentModulePathFromStack(){let e=Error.prepareStackTrace;try{Error.prepareStackTrace=(e,t)=>t;let e=Error().stack?.[0]?.getFileName();if(typeof e!=`string`||e.length===0)throw Error(`Failed to resolve the current module path from the stack trace.`);return e.startsWith(`file:`)?fileURLToPath(e):e}finally{Error.prepareStackTrace=e}}const require=createRequire(resolveCurrentModulePath());function isBuildOutputPackageRoot(e){return basename(e)===`dist`&&existsSync(join(dirname(e),`package.json`))}function resolvePackageBuildRoot(){let e=dirname(realpathSync(resolveCurrentModulePath()));for(;;){if(isBuildOutputPackageRoot(e))return e;let t=dirname(e);if(t===e)return null;e=t}}function findNearestPackageRoot(e){let t=e;for(;;){if(existsSync(join(t,`package.json`))&&!isBuildOutputPackageRoot(t))return t;let r=dirname(t);if(r===t)throw Error(`Failed to resolve package root from "${e}".`);t=r}}function resolvePackageRoot(){return findNearestPackageRoot(dirname(realpathSync(resolveCurrentModulePath())))}function tryResolvePackageRoot(){try{return resolvePackageRoot()}catch{return}}function rewriteSourceFilePathForBuild(e){return e.replace(/\.[cm]?tsx?$/,`.js`)}function resolvePackageSourceFilePath(e){let t=resolvePackageBuildRoot();return t===null?join(resolvePackageRoot(),e):join(t,rewriteSourceFilePathForBuild(e))}function resolvePackageSourceDirectoryPath(e){let t=resolvePackageBuildRoot();return join(t===null?resolvePackageRoot():t,e)}function resolvePackageDependencyPath(e){return require.resolve(e)}function resolvePackageCompiledFilePath(e){let t=resolvePackageBuildRoot();return t===null?join(resolvePackageRoot(),`.generated`,`compiled`,e.replace(/^src\/compiled\//,``)):join(t,e)}function normalizeInstalledPackageInfo(e){let t=e;if(!(typeof t.name!=`string`||typeof t.version!=`string`))return{name:t.name,version:t.version}}function tryReadInstalledPackageInfo(e,t){let n=normalizeInstalledPackageInfo(JSON.parse(readFileSync(e,`utf8`)));if(n?.name===t)return n}function resolveInstalledPackageInfo(){if(cachedPackageInfo)return cachedPackageInfo;let e=tryResolvePackageRoot(),t=e===void 0?void 0:tryReadInstalledPackageInfo(join(e,`package.json`),EVE_PACKAGE_NAME);if(t)return cachedPackageInfo=t,cachedPackageInfo;try{let e=tryReadInstalledPackageInfo(require.resolve(`${EVE_PACKAGE_NAME}/package.json`),EVE_PACKAGE_NAME);if(e)return cachedPackageInfo=e,cachedPackageInfo}catch{}return cachedPackageInfo={...FALLBACK_PACKAGE_INFO},cachedPackageInfo}function resolveWorkflowModulePath(e){if(e===`workflow`)return resolvePackageSourceFilePath(`src/internal/workflow/index.ts`);if(e===`workflow/internal/builtins`)return resolvePackageSourceFilePath(`src/internal/workflow/builtins.ts`);let t=WORKFLOW_MODULE_ALIASES[e];return t===void 0?require.resolve(e):resolvePackageCompiledFilePath(t)}export{resolveInstalledPackageInfo,resolvePackageDependencyPath,resolvePackageRoot,resolvePackageSourceDirectoryPath,resolvePackageSourceFilePath,resolveWorkflowModulePath};
@@ -8,7 +8,7 @@ type NormalizedSandboxDefinition = Readonly<Omit<SandboxDefinition, "backend">>
8
8
  /**
9
9
  * Normalizes one authored sandbox definition into the canonical internal
10
10
  * shape. If the author supplied a `backend` callback (e.g.
11
- * `backend: () => vercelSandboxBackend({...})`), it is wrapped via
11
+ * `backend: () => vercel({...})`), it is wrapped via
12
12
  * {@link lazyBackend} so downstream consumers always see a plain
13
13
  * `SandboxBackend` value — the callback fires exactly once on first
14
14
  * access and the resulting backend is memoized.
@@ -1 +1 @@
1
- import{expectFunction,expectObjectRecord,expectOnlyKnownKeys}from"#internal/authored-module.js";import{lazyBackend}from"#execution/sandbox/lazy-backend.js";function normalizeSandboxDefinition(n,r){let i=expectObjectRecord(n,r);expectOnlyKnownKeys(i,[`backend`,`bootstrap`,`description`,`onSession`,`revalidationKey`],r);let a={};if(i.backend!==void 0&&(a.backend=expectSandboxBackend(i.backend,r)),i.description!==void 0){if(typeof i.description!=`string`)throw Error(`${r} The "description" field must be a string when set.`);a.description=i.description}if(i.bootstrap!==void 0&&(a.bootstrap=expectFunction(i.bootstrap,r)),i.revalidationKey!==void 0&&(a.revalidationKey=expectFunction(i.revalidationKey,r)),a.bootstrap===void 0&&a.revalidationKey!==void 0)throw Error(`${r} The "revalidationKey" field can only be set when "bootstrap" is set.`);return i.onSession!==void 0&&(a.onSession=expectFunction(i.onSession,r)),a}function expectSandboxBackend(e,t){if(typeof e==`function`)return lazyBackend(e);let r=expectObjectRecord(e,`${t} The "backend" field must be a SandboxBackend value (use dockerBackend(), vercelSandboxBackend(), or your own factory) or a zero-arg function returning one.`);if(typeof r.name!=`string`||r.name.length===0)throw Error(`${t} The "backend" value must expose a non-empty string "name" identifier.`);if(typeof r.create!=`function`)throw Error(`${t} The "backend" value must expose a "create" function.`);if(r.prewarm!==void 0&&typeof r.prewarm!=`function`)throw Error(`${t} The "backend.prewarm" property must be a function when set.`);return r}export{normalizeSandboxDefinition};
1
+ import{expectFunction,expectObjectRecord,expectOnlyKnownKeys}from"#internal/authored-module.js";import{lazyBackend}from"#execution/sandbox/lazy-backend.js";function normalizeSandboxDefinition(n,r){let i=expectObjectRecord(n,r);expectOnlyKnownKeys(i,[`backend`,`bootstrap`,`description`,`onSession`,`revalidationKey`],r);let a={};if(i.backend!==void 0&&(a.backend=expectSandboxBackend(i.backend,r)),i.description!==void 0){if(typeof i.description!=`string`)throw Error(`${r} The "description" field must be a string when set.`);a.description=i.description}if(i.bootstrap!==void 0&&(a.bootstrap=expectFunction(i.bootstrap,r)),i.revalidationKey!==void 0&&(a.revalidationKey=expectFunction(i.revalidationKey,r)),a.bootstrap===void 0&&a.revalidationKey!==void 0)throw Error(`${r} The "revalidationKey" field can only be set when "bootstrap" is set.`);return i.onSession!==void 0&&(a.onSession=expectFunction(i.onSession,r)),a}function expectSandboxBackend(e,t){if(typeof e==`function`)return lazyBackend(e);let r=expectObjectRecord(e,`${t} The "backend" field must be a SandboxBackend value (use docker(), vercel(), or your own factory) or a zero-arg function returning one.`);if(typeof r.name!=`string`||r.name.length===0)throw Error(`${t} The "backend" value must expose a non-empty string "name" identifier.`);if(typeof r.create!=`function`)throw Error(`${t} The "backend" value must expose a "create" function.`);if(r.prewarm!==void 0&&typeof r.prewarm!=`function`)throw Error(`${t} The "backend.prewarm" property must be a function when set.`);return r}export{normalizeSandboxDefinition};
@@ -3,7 +3,7 @@ import type { NitroBuildSurface, PreparedApplicationHost } from "#internal/nitro
3
3
  /**
4
4
  * Hosted Vercel builds can prune local sandbox backends only when the
5
5
  * app did not explicitly configure one. Omitted backends resolve through
6
- * `defaultBackend()`, which selects Vercel on hosted Vercel and never
6
+ * `defaultSandbox()`, which selects Vercel on hosted Vercel and never
7
7
  * needs local runtime code there.
8
8
  */
9
9
  export declare function shouldPruneLocalSandboxBackends(input: {
@@ -4,21 +4,21 @@ import type { JustBashSandboxCreateOptions } from "#public/sandbox/just-bash-san
4
4
  import type { MicrosandboxCreateOptions } from "#public/sandbox/microsandbox-sandbox.js";
5
5
  import type { VercelSandboxCreateOptions } from "#public/sandbox/vercel-sandbox.js";
6
6
  /**
7
- * Input to {@link defaultBackend}: a separate options bag per inner
7
+ * Input to {@link defaultSandbox}: a separate options bag per inner
8
8
  * backend. The framework picks one backend at runtime based on
9
9
  * availability and passes it the matching bag; the others are ignored.
10
10
  */
11
- export interface DefaultBackendOptions {
11
+ export interface DefaultSandboxOptions {
12
12
  readonly docker?: DockerSandboxCreateOptions;
13
13
  readonly justBash?: JustBashSandboxCreateOptions;
14
14
  readonly microsandbox?: MicrosandboxCreateOptions;
15
15
  readonly vercel?: VercelSandboxCreateOptions;
16
16
  }
17
17
  /**
18
- * Availability probes behind {@link defaultBackend}'s selection chain.
18
+ * Availability probes behind {@link defaultSandbox}'s selection chain.
19
19
  * Injectable so selection logic is testable without touching the host.
20
20
  */
21
- export interface DefaultBackendProbes {
21
+ export interface DefaultSandboxProbes {
22
22
  readonly isDeployedOnVercel: () => boolean;
23
23
  readonly isDockerAvailable: () => boolean;
24
24
  readonly isMicrosandboxSupported: () => boolean;
@@ -37,13 +37,13 @@ export interface DefaultBackendProbes {
37
37
  * auto-installs the package into the project.
38
38
  *
39
39
  * The selection is cached for the process lifetime. To pin a backend
40
- * unconditionally, configure its factory directly (`dockerBackend()`,
41
- * `microsandboxBackend()`, `justBashBackend()`,
42
- * `vercelSandboxBackend()`).
40
+ * unconditionally, configure its factory directly (`docker()`,
41
+ * `microsandbox()`, `justbash()`,
42
+ * `vercel()`).
43
43
  */
44
- export declare function defaultBackend(opts?: DefaultBackendOptions): SandboxBackend;
44
+ export declare function defaultSandbox(opts?: DefaultSandboxOptions): SandboxBackend;
45
45
  /**
46
- * The selection chain behind {@link defaultBackend}. Internal —
46
+ * The selection chain behind {@link defaultSandbox}. Internal —
47
47
  * exported for tests, which inject probes.
48
48
  */
49
- export declare function selectDefaultSandboxBackend(opts: DefaultBackendOptions | undefined, probes: DefaultBackendProbes): SandboxBackend;
49
+ export declare function selectDefaultSandbox(opts: DefaultSandboxOptions | undefined, probes: DefaultSandboxProbes): SandboxBackend;
@@ -1 +1 @@
1
- import{lazyBackend}from"#execution/sandbox/lazy-backend.js";import{isDockerDaemonAvailableSync,isMicrosandboxPlatformSupported}from"#execution/sandbox/bindings/local.js";import{dockerBackend}from"#public/sandbox/backends/docker.js";import{justBashBackend}from"#public/sandbox/backends/just-bash.js";import{microsandboxBackend}from"#public/sandbox/backends/microsandbox.js";import{vercelSandboxBackend}from"#public/sandbox/backends/vercel.js";const PRODUCTION_PROBES={isDeployedOnVercel:()=>!!process.env.VERCEL,isDockerAvailable:()=>isDockerDaemonAvailableSync(),isMicrosandboxSupported:()=>isMicrosandboxPlatformSupported()};function defaultBackend(t){return lazyBackend(()=>selectDefaultSandboxBackend(t,PRODUCTION_PROBES))}function selectDefaultSandboxBackend(e,t){return t.isDeployedOnVercel()?vercelSandboxBackend(e?.vercel):t.isDockerAvailable()?dockerBackend(e?.docker):t.isMicrosandboxSupported()?microsandboxBackend(e?.microsandbox):justBashBackend(e?.justBash)}export{defaultBackend,selectDefaultSandboxBackend};
1
+ import{lazyBackend}from"#execution/sandbox/lazy-backend.js";import{isDockerDaemonAvailableSync,isMicrosandboxPlatformSupported}from"#execution/sandbox/bindings/local.js";import{docker}from"#public/sandbox/backends/docker.js";import{justbash}from"#public/sandbox/backends/just-bash.js";import{microsandbox}from"#public/sandbox/backends/microsandbox.js";import{vercel}from"#public/sandbox/backends/vercel.js";const PRODUCTION_PROBES={isDeployedOnVercel:()=>!!process.env.VERCEL,isDockerAvailable:()=>isDockerDaemonAvailableSync(),isMicrosandboxSupported:()=>isMicrosandboxPlatformSupported()};function defaultSandbox(t){return lazyBackend(()=>selectDefaultSandbox(t,PRODUCTION_PROBES))}function selectDefaultSandbox(e,t){return t.isDeployedOnVercel()?vercel(e?.vercel):t.isDockerAvailable()?docker(e?.docker):t.isMicrosandboxSupported()?microsandbox(e?.microsandbox):justbash(e?.justBash)}export{defaultSandbox,selectDefaultSandbox};
@@ -11,4 +11,4 @@ import type { DockerSandboxCreateOptions } from "#public/sandbox/docker-sandbox.
11
11
  * Configuring this backend pins it unconditionally — when you want
12
12
  * fallback behavior, use `defaultBackend()` instead.
13
13
  */
14
- export declare function dockerBackend(opts?: DockerSandboxCreateOptions): SandboxBackend;
14
+ export declare function docker(opts?: DockerSandboxCreateOptions): SandboxBackend;
@@ -1 +1 @@
1
- import{createDockerSandboxBackend}from"#execution/sandbox/bindings/local.js";function dockerBackend(e){return createDockerSandboxBackend({createOptions:e})}export{dockerBackend};
1
+ import{createDockerSandboxBackend}from"#execution/sandbox/bindings/local.js";function docker(e){return createDockerSandboxBackend({createOptions:e})}export{docker};
@@ -14,4 +14,4 @@ import type { JustBashSandboxCreateOptions } from "#public/sandbox/just-bash-san
14
14
  * unconditionally — when you want fallback behavior, use
15
15
  * `defaultBackend()` instead.
16
16
  */
17
- export declare function justBashBackend(opts?: JustBashSandboxCreateOptions): SandboxBackend;
17
+ export declare function justbash(opts?: JustBashSandboxCreateOptions): SandboxBackend;
@@ -1 +1 @@
1
- import{createJustBashSandboxBackend}from"#execution/sandbox/bindings/local.js";function justBashBackend(e){return createJustBashSandboxBackend({createOptions:e})}export{justBashBackend};
1
+ import{createJustBashSandboxBackend}from"#execution/sandbox/bindings/local.js";function justbash(e){return createJustBashSandboxBackend({createOptions:e})}export{justbash};
@@ -14,4 +14,4 @@ import type { MicrosandboxBootstrapUseOptions, MicrosandboxCreateOptions, Micros
14
14
  * Configuring this backend pins it unconditionally — when you want
15
15
  * fallback behavior, use `defaultBackend()` instead.
16
16
  */
17
- export declare function microsandboxBackend(opts?: MicrosandboxCreateOptions): SandboxBackend<MicrosandboxBootstrapUseOptions, MicrosandboxSessionUseOptions>;
17
+ export declare function microsandbox(opts?: MicrosandboxCreateOptions): SandboxBackend<MicrosandboxBootstrapUseOptions, MicrosandboxSessionUseOptions>;
@@ -1 +1 @@
1
- import{createMicrosandboxSandboxBackend}from"#execution/sandbox/bindings/local.js";function microsandboxBackend(e){return createMicrosandboxSandboxBackend({createOptions:e})}export{microsandboxBackend};
1
+ import{createMicrosandboxSandboxBackend}from"#execution/sandbox/bindings/local.js";function microsandbox(e){return createMicrosandboxSandboxBackend({createOptions:e})}export{microsandbox};
@@ -26,4 +26,4 @@ import type { VercelSandboxBootstrapUseOptions, VercelSandboxCreateOptions, Verc
26
26
  * SDK's `update` under the hood, overriding any overlapping field
27
27
  * from `opts`.
28
28
  */
29
- export declare function vercelSandboxBackend(opts?: VercelSandboxCreateOptions): SandboxBackend<VercelSandboxBootstrapUseOptions, VercelSandboxSessionUseOptions>;
29
+ export declare function vercel(opts?: VercelSandboxCreateOptions): SandboxBackend<VercelSandboxBootstrapUseOptions, VercelSandboxSessionUseOptions>;
@@ -1 +1 @@
1
- import{createVercelSandboxBackend}from"#execution/sandbox/bindings/vercel.js";function vercelSandboxBackend(e){return createVercelSandboxBackend({createOptions:e})}export{vercelSandboxBackend};
1
+ import{createVercelSandbox}from"#execution/sandbox/bindings/vercel.js";function vercel(e){return createVercelSandbox({createOptions:e})}export{vercel};
@@ -13,11 +13,11 @@ export type DockerSandboxPullPolicy = "if-not-present" | "always" | "never";
13
13
  * Docker supports coarse-grained egress control only: `"allow-all"`
14
14
  * attaches the container to the default bridge network, `"deny-all"`
15
15
  * runs it with networking disabled. Domain-level policies and
16
- * credential brokering require `vercelSandboxBackend()`.
16
+ * credential brokering require `vercel()`.
17
17
  */
18
18
  export type DockerSandboxNetworkPolicy = "allow-all" | "deny-all";
19
19
  /**
20
- * Options accepted by `dockerBackend(opts)`.
20
+ * Options accepted by `docker(opts)`.
21
21
  */
22
22
  export interface DockerSandboxCreateOptions {
23
23
  /**
@@ -0,0 +1,2 @@
1
+ export { docker } from "#public/sandbox/backends/docker.js";
2
+ export type { DockerSandboxCreateOptions, DockerSandboxNetworkPolicy, DockerSandboxPullPolicy, } from "#public/sandbox/docker-sandbox.js";
@@ -0,0 +1 @@
1
+ import{docker}from"#public/sandbox/backends/docker.js";export{docker};
@@ -6,12 +6,4 @@ export { defineSandbox, type SandboxBootstrapContext, type SandboxBootstrapUseFn
6
6
  export type { SandboxBackend, SandboxBackendCreateInput, SandboxBackendHandle, SandboxBackendPrewarmInput, SandboxBackendRuntimeContext, SandboxBackendSessionState, SandboxSeedFile, } from "#public/definitions/sandbox-backend.js";
7
7
  export type { SandboxNetworkPolicy } from "#shared/sandbox-network-policy.js";
8
8
  export { SandboxTemplateNotProvisionedError } from "#public/definitions/sandbox-backend.js";
9
- export { defaultBackend, type DefaultBackendOptions } from "#public/sandbox/backends/default.js";
10
- export { dockerBackend } from "#public/sandbox/backends/docker.js";
11
- export { justBashBackend } from "#public/sandbox/backends/just-bash.js";
12
- export { microsandboxBackend } from "#public/sandbox/backends/microsandbox.js";
13
- export { vercelSandboxBackend } from "#public/sandbox/backends/vercel.js";
14
- export type { DockerSandboxCreateOptions, DockerSandboxNetworkPolicy, DockerSandboxPullPolicy, } from "#public/sandbox/docker-sandbox.js";
15
- export type { JustBashSandboxCreateOptions } from "#public/sandbox/just-bash-sandbox.js";
16
- export type { MicrosandboxBootstrapUseOptions, MicrosandboxCreateOptions, MicrosandboxSessionUseOptions, } from "#public/sandbox/microsandbox-sandbox.js";
17
- export type { VercelSandboxBootstrapUseOptions, VercelSandboxCreateOptions, VercelSandboxSessionUseOptions, } from "#public/sandbox/vercel-sandbox.js";
9
+ export { defaultSandbox as defaultBackend, type DefaultSandboxOptions as DefaultBackendOptions, } from "#public/sandbox/backends/default.js";
@@ -1 +1 @@
1
- import{SandboxTemplateNotProvisionedError}from"#public/definitions/sandbox-backend.js";import{dockerBackend}from"#public/sandbox/backends/docker.js";import{justBashBackend}from"#public/sandbox/backends/just-bash.js";import{microsandboxBackend}from"#public/sandbox/backends/microsandbox.js";import{vercelSandboxBackend}from"#public/sandbox/backends/vercel.js";import{defineSandbox}from"#public/definitions/sandbox.js";import{defaultBackend}from"#public/sandbox/backends/default.js";export{SandboxTemplateNotProvisionedError,defaultBackend,defineSandbox,dockerBackend,justBashBackend,microsandboxBackend,vercelSandboxBackend};
1
+ import{SandboxTemplateNotProvisionedError}from"#public/definitions/sandbox-backend.js";import{defineSandbox}from"#public/definitions/sandbox.js";import{defaultSandbox as defaultBackend}from"#public/sandbox/backends/default.js";export{SandboxTemplateNotProvisionedError,defaultBackend,defineSandbox};
@@ -1,5 +1,5 @@
1
1
  /**
2
- * Options accepted by `justBashBackend(opts)`.
2
+ * Options accepted by `justbash(opts)`.
3
3
  *
4
4
  * The just-bash backend runs the workspace under the pure-JS `just-bash`
5
5
  * interpreter with a virtual filesystem — no daemon or VM required, but
@@ -0,0 +1,2 @@
1
+ export { justbash } from "#public/sandbox/backends/just-bash.js";
2
+ export type { JustBashSandboxCreateOptions } from "#public/sandbox/just-bash-sandbox.js";
@@ -0,0 +1 @@
1
+ import{justbash}from"#public/sandbox/backends/just-bash.js";export{justbash};
@@ -1,6 +1,6 @@
1
1
  import type { SandboxNetworkPolicy } from "#shared/sandbox-network-policy.js";
2
2
  /**
3
- * Options accepted by `microsandboxBackend(opts)`.
3
+ * Options accepted by `microsandbox(opts)`.
4
4
  *
5
5
  * The microsandbox backend runs sandboxes in lightweight local VMs via
6
6
  * [microsandbox](https://www.npmjs.com/package/microsandbox). Options
@@ -0,0 +1,2 @@
1
+ export { microsandbox } from "#public/sandbox/backends/microsandbox.js";
2
+ export type { MicrosandboxBootstrapUseOptions, MicrosandboxCreateOptions, MicrosandboxSessionUseOptions, } from "#public/sandbox/microsandbox-sandbox.js";
@@ -0,0 +1 @@
1
+ import{microsandbox}from"#public/sandbox/backends/microsandbox.js";export{microsandbox};
@@ -1,6 +1,6 @@
1
1
  import type { Sandbox as SdkSandbox, SandboxUpdateParams } from "#compiled/@vercel/sandbox/index.js";
2
2
  /**
3
- * Options accepted by `vercelSandboxBackend(opts)`. Forwarded to Vercel
3
+ * Options accepted by `vercel(opts)`. Forwarded to Vercel
4
4
  * Sandbox creation for every fresh sandbox the framework creates
5
5
  * (template at prewarm time, session at first-time session-create).
6
6
  * Skipped on resume (`Sandbox.get`) since no create happens there.
@@ -0,0 +1,2 @@
1
+ export { vercel } from "#public/sandbox/backends/vercel.js";
2
+ export type { VercelSandboxBootstrapUseOptions, VercelSandboxCreateOptions, VercelSandboxSessionUseOptions, } from "#public/sandbox/vercel-sandbox.js";
@@ -0,0 +1 @@
1
+ import{vercel}from"#public/sandbox/backends/vercel.js";export{vercel};
@@ -7,7 +7,7 @@ import type { ResolvedSandboxDefinition } from "#runtime/types.js";
7
7
  * (when present) attached from the authored module.
8
8
  *
9
9
  * If the authored module omits `backend`, the resolver substitutes
10
- * {@link defaultBackend} so the rest of the runtime can rely on a
10
+ * {@link defaultSandbox} so the rest of the runtime can rely on a
11
11
  * non-null backend value.
12
12
  */
13
13
  export declare function resolveSandboxDefinition(definition: CompiledSandboxDefinition, moduleMap: CompiledModuleMap, nodeId: string | undefined): Promise<ResolvedSandboxDefinition>;
@@ -1 +1 @@
1
- import{expectObjectRecord}from"#internal/authored-module.js";import{toErrorMessage}from"#shared/errors.js";import{lazyBackend}from"#execution/sandbox/lazy-backend.js";import{ResolveAgentError,loadResolvedModuleExport}from"#runtime/resolve-helpers.js";import{defaultBackend}from"#public/sandbox/backends/default.js";async function resolveSandboxDefinition(n,i,a){try{let t=expectObjectRecord(await loadResolvedModuleExport({definition:n,kindLabel:`sandbox`,moduleMap:i,nodeId:a}),`Expected the sandbox export "${n.exportName??`default`}" from "${n.logicalPath}" to return an object.`);return{backend:resolveBackend(t.backend,n.logicalPath),bootstrap:t.bootstrap,description:n.description,exportName:n.exportName,logicalPath:n.logicalPath,onSession:t.onSession,revalidationKey:n.revalidationKey,sourceHash:n.sourceHash,sourceId:n.sourceId,sourceKind:`module`}}catch(e){throw e instanceof ResolveAgentError?e:new ResolveAgentError(`Failed to attach the sandbox lifecycle handlers from "${n.logicalPath}": ${toErrorMessage(e)}`,{logicalPath:n.logicalPath,sourceId:n.sourceId})}}function resolveBackend(e,t){if(e===void 0)return defaultBackend();if(typeof e==`function`)return lazyBackend(e);if(typeof e!=`object`||!e)throw new ResolveAgentError(`Sandbox "${t}" exposed a non-object "backend" field. Use dockerBackend(), vercelSandboxBackend(), another factory that returns a SandboxBackend value, or a zero-arg callback returning one.`,{logicalPath:t});let r=e;if(typeof r.name!=`string`||r.name.length===0)throw new ResolveAgentError(`Sandbox "${t}" backend is missing a non-empty string "name" identifier.`,{logicalPath:t});if(typeof r.create!=`function`)throw new ResolveAgentError(`Sandbox "${t}" backend is missing a "create" function.`,{logicalPath:t});return r}export{resolveSandboxDefinition};
1
+ import{expectObjectRecord}from"#internal/authored-module.js";import{toErrorMessage}from"#shared/errors.js";import{lazyBackend}from"#execution/sandbox/lazy-backend.js";import{ResolveAgentError,loadResolvedModuleExport}from"#runtime/resolve-helpers.js";import{defaultSandbox}from"#public/sandbox/backends/default.js";async function resolveSandboxDefinition(n,i,a){try{let t=expectObjectRecord(await loadResolvedModuleExport({definition:n,kindLabel:`sandbox`,moduleMap:i,nodeId:a}),`Expected the sandbox export "${n.exportName??`default`}" from "${n.logicalPath}" to return an object.`);return{backend:resolveBackend(t.backend,n.logicalPath),bootstrap:t.bootstrap,description:n.description,exportName:n.exportName,logicalPath:n.logicalPath,onSession:t.onSession,revalidationKey:n.revalidationKey,sourceHash:n.sourceHash,sourceId:n.sourceId,sourceKind:`module`}}catch(e){throw e instanceof ResolveAgentError?e:new ResolveAgentError(`Failed to attach the sandbox lifecycle handlers from "${n.logicalPath}": ${toErrorMessage(e)}`,{logicalPath:n.logicalPath,sourceId:n.sourceId})}}function resolveBackend(e,t){if(e===void 0)return defaultSandbox();if(typeof e==`function`)return lazyBackend(e);if(typeof e!=`object`||!e)throw new ResolveAgentError(`Sandbox "${t}" exposed a non-object "backend" field. Use docker(), vercel(), another factory that returns a SandboxBackend value, or a zero-arg callback returning one.`,{logicalPath:t});let r=e;if(typeof r.name!=`string`||r.name.length===0)throw new ResolveAgentError(`Sandbox "${t}" backend is missing a non-empty string "name" identifier.`,{logicalPath:t});if(typeof r.create!=`function`)throw new ResolveAgentError(`Sandbox "${t}" backend is missing a "create" function.`,{logicalPath:t});return r}export{resolveSandboxDefinition};
@@ -51,9 +51,9 @@ export declare function createRuntimeSandboxRegistry(input: {
51
51
  * Builds the framework default sandbox definition used when no agent
52
52
  * authored override is present.
53
53
  *
54
- * The `backend` is resolved through {@link defaultBackend} on each
54
+ * The `backend` is resolved through {@link defaultSandbox} on each
55
55
  * call so the framework default picks up the same environment-aware
56
- * fallback as authored sandboxes that omit `backend` (`vercelSandboxBackend()`
56
+ * fallback as authored sandboxes that omit `backend` (`vercel()`
57
57
  * on hosted Vercel, then Docker, microsandbox, or just-bash by availability). Implemented as
58
58
  * a factory rather than a constant so the environment is read at
59
59
  * graph-resolution time rather than at module-load time.
@@ -1 +1 @@
1
- import{defaultBackend}from"#public/sandbox/backends/default.js";const DEFAULT_SANDBOX_SOURCE_ID=`eve:default-sandbox`;function createRuntimeSandboxRegistry(e){return{sandbox:{definition:e.authoredSandbox??createFrameworkSandboxDefinition(),workspaceResourceRoot:e.workspaceResourceRoot}}}function createFrameworkSandboxDefinition(){return{backend:defaultBackend(),logicalPath:`eve:framework/default-sandbox`,sourceId:DEFAULT_SANDBOX_SOURCE_ID,sourceKind:`module`}}export{DEFAULT_SANDBOX_SOURCE_ID,createFrameworkSandboxDefinition,createRuntimeSandboxRegistry};
1
+ import{defaultSandbox}from"#public/sandbox/backends/default.js";const DEFAULT_SANDBOX_SOURCE_ID=`eve:default-sandbox`;function createRuntimeSandboxRegistry(e){return{sandbox:{definition:e.authoredSandbox??createFrameworkSandboxDefinition(),workspaceResourceRoot:e.workspaceResourceRoot}}}function createFrameworkSandboxDefinition(){return{backend:defaultSandbox(),logicalPath:`eve:framework/default-sandbox`,sourceId:DEFAULT_SANDBOX_SOURCE_ID,sourceKind:`module`}}export{DEFAULT_SANDBOX_SOURCE_ID,createFrameworkSandboxDefinition,createRuntimeSandboxRegistry};
@@ -96,8 +96,8 @@ export interface ResolvedConnectionDefinition extends ResolvedModuleSourceRef {
96
96
  * The resolved `backend` is non-optional: every sandbox in the runtime
97
97
  * graph carries a concrete SandboxBackend value, even when the
98
98
  * authored definition omits `backend`. The unauthored case is filled
99
- * in by `defaultBackend()` (which itself selects between
100
- * `vercelSandboxBackend()`, `dockerBackend()`, `microsandboxBackend()`, and `justBashBackend()` based on the current
99
+ * in by `defaultSandbox()` (which itself selects between
100
+ * `vercel()`, `docker()`, `microsandbox()`, and `justbash()` based on the current
101
101
  * environment).
102
102
  */
103
103
  export type ResolvedSandboxDefinition = ResolvedModuleSourceRef & {
@@ -1 +1 @@
1
- import{getPackageManagerStrategy}from"../../primitives/pm/index.js";import{pathExists,writeTextFile}from"../files.js";import{patchPackageJson}from"../update/package-json.js";import{resolveVersionToken}from"../version-tokens.js";import{agentTemplateFiles,formatEveDependencySpecifier}from"./project.js";import{join}from"node:path";import{readFile}from"node:fs/promises";const DEPENDENCY_FIELDS=[`dependencies`,`devDependencies`,`optionalDependencies`,`peerDependencies`];function isJsonObject(e){return typeof e==`object`&&!!e&&!Array.isArray(e)}function hasDeclaredDependency(e,t){if(!isJsonObject(e))return!1;for(let n of DEPENDENCY_FIELDS){let r=e[n];if(isJsonObject(r)&&typeof r[t]==`string`)return!0}return!1}async function addAgentToProject(i){let a=join(i.projectRoot,`package.json`);if(!await pathExists(a))throw Error(`Cannot add an Eve agent to "${i.projectRoot}" because it has no package.json. Run \`eve init <name>\` to create a new project instead.`);let o=agentTemplateFiles(i.model),s=[];for(let e of Object.keys(o))await pathExists(join(i.projectRoot,e))&&s.push(e);if(s.length===0&&await pathExists(join(i.projectRoot,`agent`))&&s.push(`agent/`),s.length>0)throw Error(`Cannot add an Eve agent to "${i.projectRoot}" because it already has: ${s.join(`, `)}. Move them aside first.`);let c=resolveVersionToken(`evePackageVersion`,i.evePackageVersion??`0.8.6`),l=resolveVersionToken(`aiPackageVersion`,i.aiPackageVersion??`7.0.0-canary.171`),u=resolveVersionToken(`connectPackageVersion`,i.connectPackageVersion??`0.2.2`),d=resolveVersionToken(`zodPackageVersion`,i.zodPackageVersion??`4.4.3`),f=[];for(let[e,t]of Object.entries(o)){let r=join(i.projectRoot,e);await writeTextFile(r,t),f.push(r)}let p=JSON.parse(await readFile(a,`utf8`)),m={"@vercel/connect":u,ai:l,eve:formatEveDependencySpecifier(c),zod:d},h={};for(let[e,t]of Object.entries(m))hasDeclaredDependency(p,e)||(h[e]=t);return Object.keys(h).length>0&&await patchPackageJson(a,{dependencies:h}),await getPackageManagerStrategy(i.packageManager??`pnpm`).applyProjectConfiguration(i.projectRoot),{filesWritten:f,dependenciesAdded:Object.keys(h).sort()}}export{addAgentToProject};
1
+ import{getPackageManagerStrategy}from"../../primitives/pm/index.js";import{pathExists,writeTextFile}from"../files.js";import{patchPackageJson}from"../update/package-json.js";import{resolveVersionToken}from"../version-tokens.js";import{agentTemplateFiles,formatEveDependencySpecifier}from"./project.js";import{join}from"node:path";import{readFile}from"node:fs/promises";const DEPENDENCY_FIELDS=[`dependencies`,`devDependencies`,`optionalDependencies`,`peerDependencies`];function isJsonObject(e){return typeof e==`object`&&!!e&&!Array.isArray(e)}function hasDeclaredDependency(e,t){if(!isJsonObject(e))return!1;for(let n of DEPENDENCY_FIELDS){let r=e[n];if(isJsonObject(r)&&typeof r[t]==`string`)return!0}return!1}async function addAgentToProject(i){let a=join(i.projectRoot,`package.json`);if(!await pathExists(a))throw Error(`Cannot add an Eve agent to "${i.projectRoot}" because it has no package.json. Run \`eve init <name>\` to create a new project instead.`);let o=agentTemplateFiles(i.model),s=[];for(let e of Object.keys(o))await pathExists(join(i.projectRoot,e))&&s.push(e);if(s.length===0&&await pathExists(join(i.projectRoot,`agent`))&&s.push(`agent/`),s.length>0)throw Error(`Cannot add an Eve agent to "${i.projectRoot}" because it already has: ${s.join(`, `)}. Move them aside first.`);let c=resolveVersionToken(`evePackageVersion`,i.evePackageVersion??`0.9.0`),l=resolveVersionToken(`aiPackageVersion`,i.aiPackageVersion??`7.0.0-canary.171`),u=resolveVersionToken(`connectPackageVersion`,i.connectPackageVersion??`0.2.2`),d=resolveVersionToken(`zodPackageVersion`,i.zodPackageVersion??`4.4.3`),f=[];for(let[e,t]of Object.entries(o)){let r=join(i.projectRoot,e);await writeTextFile(r,t),f.push(r)}let p=JSON.parse(await readFile(a,`utf8`)),m={"@vercel/connect":u,ai:l,eve:formatEveDependencySpecifier(c),zod:d},h={};for(let[e,t]of Object.entries(m))hasDeclaredDependency(p,e)||(h[e]=t);return Object.keys(h).length>0&&await patchPackageJson(a,{dependencies:h}),await getPackageManagerStrategy(i.packageManager??`pnpm`).applyProjectConfiguration(i.projectRoot),{filesWritten:f,dependenciesAdded:Object.keys(h).sort()}}export{addAgentToProject};
@@ -1,4 +1,4 @@
1
- import{getPackageManagerStrategy}from"../../primitives/pm/index.js";import{pathExists,writeTextFile}from"../files.js";import{resolveVersionToken}from"../version-tokens.js";import{SUPPORTED_AUTHORED_MODULE_FILE_EXTENSIONS}from"../update/module-files.js";import{WEB_APP_TEMPLATE_FILES}from"./web-template.js";import{basename,join,resolve}from"node:path";import{mkdir,readdir,stat}from"node:fs/promises";const CURRENT_DIRECTORY_PROJECT_NAME=`.`,ALLOWED_CREATE_IN_PLACE_ENTRIES=new Set([`.DS_Store`,`.git`,`.gitkeep`,`.hg`]),DEFAULT_EVE_PACKAGE_VERSION=`0.8.6`,DEFAULT_AI_PACKAGE_VERSION=`7.0.0-canary.171`,DEFAULT_CONNECT_PACKAGE_VERSION=`0.2.2`,DEFAULT_ZOD_PACKAGE_VERSION=`4.4.3`;function modelProviderSlug(e){let t=(e.split(`/`)[0]??``).replaceAll(/[^A-Za-z0-9._-]/gu,``);return t.length>0?t:`anthropic`}function byokProviderEnvVar(e){let t=modelProviderSlug(e).toUpperCase().replaceAll(/[^A-Z0-9]/gu,`_`);return`${/^[0-9]/.test(t)?`_`:``}${t}_API_KEY`}function agentTemplateFiles(e){return{"agent/agent.ts":BASE_AGENT_TEMPLATE.replaceAll(`__EVE_INIT_MODEL__`,e),"agent/channels/eve.ts":WEB_APP_TEMPLATE_FILES[`agent/channels/eve.ts`],"agent/instructions.md":AGENT_INSTRUCTIONS_TEMPLATE}}function renderTemplate(e,t){return e.replaceAll(`__EVE_INIT_APP_NAME__`,t.appName).replaceAll(`__EVE_INIT_MODEL__`,t.model).replaceAll(`__EVE_INIT_BYOK_PROVIDER__`,modelProviderSlug(t.model)).replaceAll(`__EVE_INIT_BYOK_ENV_VAR__`,byokProviderEnvVar(t.model)).replaceAll(`__EVE_INIT_PACKAGE_VERSION__`,formatEveDependencySpecifier(t.evePackageVersion)).replaceAll(`__EVE_INIT_AI_SDK_VERSION__`,t.aiPackageVersion).replaceAll(`__EVE_INIT_CONNECT_VERSION__`,t.connectPackageVersion).replaceAll(`__EVE_INIT_ZOD_VERSION__`,t.zodPackageVersion).replaceAll(`__EVE_INIT_TSGO_VERSION__`,t.tsgoPackageVersion).replaceAll(`__EVE_INIT_TYPES_NODE_VERSION__`,t.typesNodePackageVersion)}function formatEveDependencySpecifier(e){return/^\d+\.\d+\.\d+(?:[-+][0-9A-Za-z-.]+)?$/.test(e)?`^${e}`:e}const BASE_AGENT_TEMPLATE=`import { defineAgent } from "eve";
1
+ import{getPackageManagerStrategy}from"../../primitives/pm/index.js";import{pathExists,writeTextFile}from"../files.js";import{resolveVersionToken}from"../version-tokens.js";import{SUPPORTED_AUTHORED_MODULE_FILE_EXTENSIONS}from"../update/module-files.js";import{WEB_APP_TEMPLATE_FILES}from"./web-template.js";import{basename,join,resolve}from"node:path";import{mkdir,readdir,stat}from"node:fs/promises";const CURRENT_DIRECTORY_PROJECT_NAME=`.`,ALLOWED_CREATE_IN_PLACE_ENTRIES=new Set([`.DS_Store`,`.git`,`.gitkeep`,`.hg`]),DEFAULT_EVE_PACKAGE_VERSION=`0.9.0`,DEFAULT_AI_PACKAGE_VERSION=`7.0.0-canary.171`,DEFAULT_CONNECT_PACKAGE_VERSION=`0.2.2`,DEFAULT_ZOD_PACKAGE_VERSION=`4.4.3`;function modelProviderSlug(e){let t=(e.split(`/`)[0]??``).replaceAll(/[^A-Za-z0-9._-]/gu,``);return t.length>0?t:`anthropic`}function byokProviderEnvVar(e){let t=modelProviderSlug(e).toUpperCase().replaceAll(/[^A-Z0-9]/gu,`_`);return`${/^[0-9]/.test(t)?`_`:``}${t}_API_KEY`}function agentTemplateFiles(e){return{"agent/agent.ts":BASE_AGENT_TEMPLATE.replaceAll(`__EVE_INIT_MODEL__`,e),"agent/channels/eve.ts":WEB_APP_TEMPLATE_FILES[`agent/channels/eve.ts`],"agent/instructions.md":AGENT_INSTRUCTIONS_TEMPLATE}}function renderTemplate(e,t){return e.replaceAll(`__EVE_INIT_APP_NAME__`,t.appName).replaceAll(`__EVE_INIT_MODEL__`,t.model).replaceAll(`__EVE_INIT_BYOK_PROVIDER__`,modelProviderSlug(t.model)).replaceAll(`__EVE_INIT_BYOK_ENV_VAR__`,byokProviderEnvVar(t.model)).replaceAll(`__EVE_INIT_PACKAGE_VERSION__`,formatEveDependencySpecifier(t.evePackageVersion)).replaceAll(`__EVE_INIT_AI_SDK_VERSION__`,t.aiPackageVersion).replaceAll(`__EVE_INIT_CONNECT_VERSION__`,t.connectPackageVersion).replaceAll(`__EVE_INIT_ZOD_VERSION__`,t.zodPackageVersion).replaceAll(`__EVE_INIT_TSGO_VERSION__`,t.tsgoPackageVersion).replaceAll(`__EVE_INIT_TYPES_NODE_VERSION__`,t.typesNodePackageVersion)}function formatEveDependencySpecifier(e){return/^\d+\.\d+\.\d+(?:[-+][0-9A-Za-z-.]+)?$/.test(e)?`^${e}`:e}const BASE_AGENT_TEMPLATE=`import { defineAgent } from "eve";
2
2
 
3
3
  export default defineAgent({
4
4
  model: "__EVE_INIT_MODEL__",
@@ -86,4 +86,4 @@ export default defineAgent({
86
86
  },
87
87
  },
88
88
  });
89
- `:BASE_AGENT_TEMPLATE,...SHARED_TEMPLATE_FILES,"package.json":packageJsonTemplate(t),...getPackageManagerStrategy(n).scaffoldFiles}}async function assertCanCreateInPlace(e,n){if(!await pathExists(e))return;let r=(await readdir(e)).filter(e=>!ALLOWED_CREATE_IN_PLACE_ENTRIES.has(e));if(r.length>0&&!n){let e=r.slice(0,5).join(`, `),t=r.length>5?`, and ${r.length-5} more`:``;throw Error(`Cannot create project in current directory because it is not empty. Found: ${e}${t}. Use an empty directory.`)}}async function scaffoldBaseProject(e){let i=resolve(e.targetDirectory??process.cwd(),e.projectName),a=e.projectName===`.`,s=e.overwriteExisting??!1,u=e.byokProvider??!1,d=e.packageManager??`pnpm`;if(a)await assertCanCreateInPlace(i,s);else if(await pathExists(i))throw Error(`Cannot create project because "${i}" already exists.`);let f=e.typesNodePackageVersion??`25.9.1`,p={appName:basename(i),model:e.model,evePackageVersion:resolveVersionToken(`evePackageVersion`,e.evePackageVersion??`0.8.6`),aiPackageVersion:resolveVersionToken(`aiPackageVersion`,e.aiPackageVersion??`7.0.0-canary.171`),connectPackageVersion:resolveVersionToken(`connectPackageVersion`,e.connectPackageVersion??`0.2.2`),zodPackageVersion:resolveVersionToken(`zodPackageVersion`,e.zodPackageVersion??`4.4.3`),tsgoPackageVersion:resolveVersionToken(`tsgoPackageVersion`,e.tsgoPackageVersion??`7.0.0-dev.20260523.1`),typesNodePackageVersion:u?resolveVersionToken(`typesNodePackageVersion`,f):f};await mkdir(i,{recursive:!0});for(let[r,o]of Object.entries(templateFiles(u,d))){let c=`${i}/${r}`,l=await pathExists(c);await writeTextFile(c,renderTemplate(o,p),{force:a&&s}),l&&await e.onOverwriteFile?.(c)}return i}async function isEveProject(e){for(let t of SUPPORTED_AUTHORED_MODULE_FILE_EXTENSIONS)try{return await stat(join(e,`agent`,`agent${t}`)),!0}catch{}return!1}export{CURRENT_DIRECTORY_PROJECT_NAME,DEFAULT_AI_PACKAGE_VERSION,DEFAULT_CONNECT_PACKAGE_VERSION,DEFAULT_EVE_PACKAGE_VERSION,DEFAULT_ZOD_PACKAGE_VERSION,agentTemplateFiles,byokProviderEnvVar,formatEveDependencySpecifier,isEveProject,modelProviderSlug,scaffoldBaseProject};
89
+ `:BASE_AGENT_TEMPLATE,...SHARED_TEMPLATE_FILES,"package.json":packageJsonTemplate(t),...getPackageManagerStrategy(n).scaffoldFiles}}async function assertCanCreateInPlace(e,n){if(!await pathExists(e))return;let r=(await readdir(e)).filter(e=>!ALLOWED_CREATE_IN_PLACE_ENTRIES.has(e));if(r.length>0&&!n){let e=r.slice(0,5).join(`, `),t=r.length>5?`, and ${r.length-5} more`:``;throw Error(`Cannot create project in current directory because it is not empty. Found: ${e}${t}. Use an empty directory.`)}}async function scaffoldBaseProject(e){let i=resolve(e.targetDirectory??process.cwd(),e.projectName),a=e.projectName===`.`,s=e.overwriteExisting??!1,u=e.byokProvider??!1,d=e.packageManager??`pnpm`;if(a)await assertCanCreateInPlace(i,s);else if(await pathExists(i))throw Error(`Cannot create project because "${i}" already exists.`);let f=e.typesNodePackageVersion??`25.9.1`,p={appName:basename(i),model:e.model,evePackageVersion:resolveVersionToken(`evePackageVersion`,e.evePackageVersion??`0.9.0`),aiPackageVersion:resolveVersionToken(`aiPackageVersion`,e.aiPackageVersion??`7.0.0-canary.171`),connectPackageVersion:resolveVersionToken(`connectPackageVersion`,e.connectPackageVersion??`0.2.2`),zodPackageVersion:resolveVersionToken(`zodPackageVersion`,e.zodPackageVersion??`4.4.3`),tsgoPackageVersion:resolveVersionToken(`tsgoPackageVersion`,e.tsgoPackageVersion??`7.0.0-dev.20260523.1`),typesNodePackageVersion:u?resolveVersionToken(`typesNodePackageVersion`,f):f};await mkdir(i,{recursive:!0});for(let[r,o]of Object.entries(templateFiles(u,d))){let c=`${i}/${r}`,l=await pathExists(c);await writeTextFile(c,renderTemplate(o,p),{force:a&&s}),l&&await e.onOverwriteFile?.(c)}return i}async function isEveProject(e){for(let t of SUPPORTED_AUTHORED_MODULE_FILE_EXTENSIONS)try{return await stat(join(e,`agent`,`agent${t}`)),!0}catch{}return!1}export{CURRENT_DIRECTORY_PROJECT_NAME,DEFAULT_AI_PACKAGE_VERSION,DEFAULT_CONNECT_PACKAGE_VERSION,DEFAULT_EVE_PACKAGE_VERSION,DEFAULT_ZOD_PACKAGE_VERSION,agentTemplateFiles,byokProviderEnvVar,formatEveDependencySpecifier,isEveProject,modelProviderSlug,scaffoldBaseProject};
@@ -1,4 +1,4 @@
1
- import{getPackageManagerStrategy}from"../../primitives/pm/index.js";import{pathExists,writeTextFile}from"../files.js";import{patchPackageJson}from"./package-json.js";import{resolveVersionToken}from"../version-tokens.js";import{getSupportedModuleBaseName,matchesSupportedModuleBaseName}from"./module-files.js";import{WEB_APP_TEMPLATE_FILES,WEB_APP_TEMPLATE_PACKAGE_JSON}from"../create/web-template.js";import"../create/project.js";import{basename,join,resolve}from"node:path";import{readFile,readdir,writeFile}from"node:fs/promises";const SLACK_CHANNEL_DEFAULT_ROUTE=`/eve/v1/slack`,DEFAULT_SLACK_CONNECTOR_SLUG=`my-agent`,PACKAGE_DEPENDENCY_FIELDS=[`dependencies`,`devDependencies`,`peerDependencies`,`optionalDependencies`],WEB_NEXT_CONFIG_PATH=`next.config.ts`,WEB_VERCEL_JSON_PATH=`vercel.json`,WEB_VERCEL_JSON_SCHEMA=`https://openapi.vercel.sh/vercel.json`,WEB_COMPETING_NEXT_CONFIG_PATHS=[`next.config.js`,`next.config.mjs`,WEB_NEXT_CONFIG_PATH,`next.config.mts`].filter(e=>e!==WEB_NEXT_CONFIG_PATH),WEB_DEFAULT_VERCEL_SERVICES={web:{entrypoint:`.`,framework:`nextjs`,routePrefix:`/`},eve:{buildCommand:`eve build`,entrypoint:`.`,framework:`eve`,routePrefix:`/_eve_internal/eve`}};function toSlackConnectorSlug(e){return e}function isJsonObject(e){return typeof e==`object`&&!!e&&!Array.isArray(e)}async function readDependencyVersion(e,t){let n=JSON.parse(await readFile(e,`utf8`));if(!isJsonObject(n)||!isJsonObject(n.dependencies))return;let r=n.dependencies[t];return typeof r==`string`?r:void 0}function packageJsonHasDependency(e,t){for(let n of PACKAGE_DEPENDENCY_FIELDS){let r=e[n];if(isJsonObject(r)&&typeof r[t]==`string`)return!0}return!1}async function hasPackageDependency(e,n){if(!await pathExists(e))return!1;let r=JSON.parse(await readFile(e,`utf8`));return isJsonObject(r)&&packageJsonHasDependency(r,n)}async function isNextJsProject(e){return hasPackageDependency(join(e,`package.json`),`next`)}async function ensurePackageDependency(e,n,i){return!await pathExists(e)||await readDependencyVersion(e,n)===i?[]:(await patchPackageJson(e,{dependencies:{[n]:i}}),[{path:e,dependencies:[n],devDependencies:[],scripts:[]}])}function resolveWebPackageVersions(e){return{evePackageVersion:e?.evePackageVersion??`0.8.6`,aiPackageVersion:e?.aiPackageVersion??`7.0.0-canary.171`,nextPackageVersion:e?.nextPackageVersion??`16.2.6`,reactPackageVersion:e?.reactPackageVersion??`19.2.6`,reactDomPackageVersion:e?.reactDomPackageVersion??`19.2.6`,streamdownPackageVersion:e?.streamdownPackageVersion??`2.5.0`,zodPackageVersion:e?.zodPackageVersion??`4.4.3`,tsgoPackageVersion:e?.tsgoPackageVersion??`7.0.0-dev.20260523.1`,typesNodePackageVersion:e?.typesNodePackageVersion??`25.9.1`,typesReactPackageVersion:e?.typesReactPackageVersion??`19.2.15`,typesReactDomPackageVersion:e?.typesReactDomPackageVersion??`19.2.3`}}function formatEveDependencySpecifier(e){return/^\d+\.\d+\.\d+(?:[-+][0-9A-Za-z-.]+)?$/.test(e)?`^${e}`:e}async function patchWebPackageJson(e,n){if(!await pathExists(e))return[];let a={...WEB_APP_TEMPLATE_PACKAGE_JSON.dependencies,ai:resolveVersionToken(`aiPackageVersion`,n.aiPackageVersion),eve:formatEveDependencySpecifier(resolveVersionToken(`evePackageVersion`,n.evePackageVersion)),next:resolveVersionToken(`nextPackageVersion`,n.nextPackageVersion),react:resolveVersionToken(`reactPackageVersion`,n.reactPackageVersion),"react-dom":resolveVersionToken(`reactDomPackageVersion`,n.reactDomPackageVersion),streamdown:resolveVersionToken(`streamdownPackageVersion`,n.streamdownPackageVersion),zod:resolveVersionToken(`zodPackageVersion`,n.zodPackageVersion)},o={...WEB_APP_TEMPLATE_PACKAGE_JSON.devDependencies,"@types/node":resolveVersionToken(`typesNodePackageVersion`,n.typesNodePackageVersion),"@types/react":resolveVersionToken(`typesReactPackageVersion`,n.typesReactPackageVersion),"@types/react-dom":resolveVersionToken(`typesReactDomPackageVersion`,n.typesReactDomPackageVersion),"@typescript/native-preview":resolveVersionToken(`tsgoPackageVersion`,n.tsgoPackageVersion)},s=WEB_APP_TEMPLATE_PACKAGE_JSON.scripts;return await patchPackageJson(e,{dependencies:a,devDependencies:o,scripts:s}),[{path:e,dependencies:Object.keys(a),devDependencies:Object.keys(o),scripts:Object.keys(s)}]}function normalizeSlackConnectorSlug(e){return toSlackConnectorSlug((e.trim().replace(/^@/,``).split(`/`).at(-1)??``).toLowerCase().replace(/[^a-z0-9_-]+/g,`-`).replace(/^[^a-z0-9]+/,``).replace(/[^a-z0-9]+$/,``).slice(0,100).replace(/[^a-z0-9]+$/,``)||`my-agent`)}async function deriveSlackConnectorSlug(e,t){if(t!==void 0&&t.length>0&&t!==`.`)return normalizeSlackConnectorSlug(t);try{let t=await readFile(join(e,`package.json`),`utf8`),n=JSON.parse(t);if(typeof n.name==`string`&&n.name.length>0)return normalizeSlackConnectorSlug(n.name)}catch{}return normalizeSlackConnectorSlug(basename(resolve(e))||`my-agent`)}function buildSlackTemplate(e){if(!e.startsWith(`slack/`)||e.length===6)throw Error(`Invalid Slack connector UID "${e}".`);return`import { connectSlackCredentials } from "@vercel/connect/eve";
1
+ import{getPackageManagerStrategy}from"../../primitives/pm/index.js";import{pathExists,writeTextFile}from"../files.js";import{patchPackageJson}from"./package-json.js";import{resolveVersionToken}from"../version-tokens.js";import{getSupportedModuleBaseName,matchesSupportedModuleBaseName}from"./module-files.js";import{WEB_APP_TEMPLATE_FILES,WEB_APP_TEMPLATE_PACKAGE_JSON}from"../create/web-template.js";import"../create/project.js";import{basename,join,resolve}from"node:path";import{readFile,readdir,writeFile}from"node:fs/promises";const SLACK_CHANNEL_DEFAULT_ROUTE=`/eve/v1/slack`,DEFAULT_SLACK_CONNECTOR_SLUG=`my-agent`,PACKAGE_DEPENDENCY_FIELDS=[`dependencies`,`devDependencies`,`peerDependencies`,`optionalDependencies`],WEB_NEXT_CONFIG_PATH=`next.config.ts`,WEB_VERCEL_JSON_PATH=`vercel.json`,WEB_VERCEL_JSON_SCHEMA=`https://openapi.vercel.sh/vercel.json`,WEB_COMPETING_NEXT_CONFIG_PATHS=[`next.config.js`,`next.config.mjs`,WEB_NEXT_CONFIG_PATH,`next.config.mts`].filter(e=>e!==WEB_NEXT_CONFIG_PATH),WEB_DEFAULT_VERCEL_SERVICES={web:{entrypoint:`.`,framework:`nextjs`,routePrefix:`/`},eve:{buildCommand:`eve build`,entrypoint:`.`,framework:`eve`,routePrefix:`/_eve_internal/eve`}};function toSlackConnectorSlug(e){return e}function isJsonObject(e){return typeof e==`object`&&!!e&&!Array.isArray(e)}async function readDependencyVersion(e,t){let n=JSON.parse(await readFile(e,`utf8`));if(!isJsonObject(n)||!isJsonObject(n.dependencies))return;let r=n.dependencies[t];return typeof r==`string`?r:void 0}function packageJsonHasDependency(e,t){for(let n of PACKAGE_DEPENDENCY_FIELDS){let r=e[n];if(isJsonObject(r)&&typeof r[t]==`string`)return!0}return!1}async function hasPackageDependency(e,n){if(!await pathExists(e))return!1;let r=JSON.parse(await readFile(e,`utf8`));return isJsonObject(r)&&packageJsonHasDependency(r,n)}async function isNextJsProject(e){return hasPackageDependency(join(e,`package.json`),`next`)}async function ensurePackageDependency(e,n,i){return!await pathExists(e)||await readDependencyVersion(e,n)===i?[]:(await patchPackageJson(e,{dependencies:{[n]:i}}),[{path:e,dependencies:[n],devDependencies:[],scripts:[]}])}function resolveWebPackageVersions(e){return{evePackageVersion:e?.evePackageVersion??`0.9.0`,aiPackageVersion:e?.aiPackageVersion??`7.0.0-canary.171`,nextPackageVersion:e?.nextPackageVersion??`16.2.6`,reactPackageVersion:e?.reactPackageVersion??`19.2.6`,reactDomPackageVersion:e?.reactDomPackageVersion??`19.2.6`,streamdownPackageVersion:e?.streamdownPackageVersion??`2.5.0`,zodPackageVersion:e?.zodPackageVersion??`4.4.3`,tsgoPackageVersion:e?.tsgoPackageVersion??`7.0.0-dev.20260523.1`,typesNodePackageVersion:e?.typesNodePackageVersion??`25.9.1`,typesReactPackageVersion:e?.typesReactPackageVersion??`19.2.15`,typesReactDomPackageVersion:e?.typesReactDomPackageVersion??`19.2.3`}}function formatEveDependencySpecifier(e){return/^\d+\.\d+\.\d+(?:[-+][0-9A-Za-z-.]+)?$/.test(e)?`^${e}`:e}async function patchWebPackageJson(e,n){if(!await pathExists(e))return[];let a={...WEB_APP_TEMPLATE_PACKAGE_JSON.dependencies,ai:resolveVersionToken(`aiPackageVersion`,n.aiPackageVersion),eve:formatEveDependencySpecifier(resolveVersionToken(`evePackageVersion`,n.evePackageVersion)),next:resolveVersionToken(`nextPackageVersion`,n.nextPackageVersion),react:resolveVersionToken(`reactPackageVersion`,n.reactPackageVersion),"react-dom":resolveVersionToken(`reactDomPackageVersion`,n.reactDomPackageVersion),streamdown:resolveVersionToken(`streamdownPackageVersion`,n.streamdownPackageVersion),zod:resolveVersionToken(`zodPackageVersion`,n.zodPackageVersion)},o={...WEB_APP_TEMPLATE_PACKAGE_JSON.devDependencies,"@types/node":resolveVersionToken(`typesNodePackageVersion`,n.typesNodePackageVersion),"@types/react":resolveVersionToken(`typesReactPackageVersion`,n.typesReactPackageVersion),"@types/react-dom":resolveVersionToken(`typesReactDomPackageVersion`,n.typesReactDomPackageVersion),"@typescript/native-preview":resolveVersionToken(`tsgoPackageVersion`,n.tsgoPackageVersion)},s=WEB_APP_TEMPLATE_PACKAGE_JSON.scripts;return await patchPackageJson(e,{dependencies:a,devDependencies:o,scripts:s}),[{path:e,dependencies:Object.keys(a),devDependencies:Object.keys(o),scripts:Object.keys(s)}]}function normalizeSlackConnectorSlug(e){return toSlackConnectorSlug((e.trim().replace(/^@/,``).split(`/`).at(-1)??``).toLowerCase().replace(/[^a-z0-9_-]+/g,`-`).replace(/^[^a-z0-9]+/,``).replace(/[^a-z0-9]+$/,``).slice(0,100).replace(/[^a-z0-9]+$/,``)||`my-agent`)}async function deriveSlackConnectorSlug(e,t){if(t!==void 0&&t.length>0&&t!==`.`)return normalizeSlackConnectorSlug(t);try{let t=await readFile(join(e,`package.json`),`utf8`),n=JSON.parse(t);if(typeof n.name==`string`&&n.name.length>0)return normalizeSlackConnectorSlug(n.name)}catch{}return normalizeSlackConnectorSlug(basename(resolve(e))||`my-agent`)}function buildSlackTemplate(e){if(!e.startsWith(`slack/`)||e.length===6)throw Error(`Invalid Slack connector UID "${e}".`);return`import { connectSlackCredentials } from "@vercel/connect/eve";
2
2
  import { slackChannel } from "eve/channels/slack";
3
3
 
4
4
  export default slackChannel({
@@ -114,10 +114,10 @@ export interface SandboxBackendPrewarmResult {
114
114
  *
115
115
  * A `SandboxBackend` is a value an author attaches to a
116
116
  * {@link SandboxDefinition} to choose which underlying runtime hosts the
117
- * sandbox. Eve ships built-in backends (`dockerBackend()`,
118
- * `justBashBackend()`, `microsandboxBackend()`,
119
- * `vercelSandboxBackend()`, and the availability-aware
120
- * `defaultBackend()`), but the interface is public so authors can write
117
+ * sandbox. Eve ships built-in backends (`docker()`,
118
+ * `justbash()`, `microsandbox()`,
119
+ * `vercel()`, and the availability-aware
120
+ * `defaultSandbox()`), but the interface is public so authors can write
121
121
  * their own.
122
122
  *
123
123
  * A backend implements the full two-phase lifecycle:
@@ -48,7 +48,7 @@ export type SandboxRevalidationKeyFn = () => Promise<string> | string;
48
48
  *
49
49
  * Each agent (and each subagent) owns exactly one sandbox. When the
50
50
  * module file is absent the framework auto-provides a default sandbox
51
- * via `defaultBackend()`. Authors override lifecycle and backend by
51
+ * via `defaultSandbox()`. Authors override lifecycle and backend by
52
52
  * creating `agent/sandbox.ts` (or `agent/sandbox/sandbox.ts` when they
53
53
  * also want a workspace folder); subagents override independently via
54
54
  * `subagents/<name>/sandbox.ts` (or the folder form) and do not inherit
@@ -69,12 +69,12 @@ interface SandboxDefinitionBase<BO = Record<string, never>, SO = Record<string,
69
69
  *
70
70
  * ```ts
71
71
  * defineSandbox({
72
- * backend: () => vercelSandboxBackend({ env: { TOKEN: process.env.TOKEN ?? "" } }),
72
+ * backend: () => vercel({ env: { TOKEN: process.env.TOKEN ?? "" } }),
73
73
  * });
74
74
  * ```
75
75
  *
76
- * When this field is omitted, Eve substitutes `defaultBackend()` at
77
- * runtime, which picks the best available backend: `vercelSandboxBackend()`
76
+ * When this field is omitted, Eve substitutes `defaultSandbox()` at
77
+ * runtime, which picks the best available backend: `vercel()`
78
78
  * on hosted Vercel (where `process.env.VERCEL` is set), then Docker,
79
79
  * microsandbox, or just-bash
80
80
  * everywhere else. Set `backend` explicitly to pin the sandbox to a
@@ -29,10 +29,11 @@ Route-auth secrets never get serialized into the compiled discovery or module-ma
29
29
  On Vercel, the [sandbox](../sandbox) runs on hosted [Vercel Sandbox](https://vercel.com/docs/sandbox) infrastructure. Attach the backend on the sandbox definition:
30
30
 
31
31
  ```ts title="agent/sandbox/sandbox.ts"
32
- import { defineSandbox, vercelSandboxBackend } from "eve/sandbox";
32
+ import { defineSandbox } from "eve/sandbox";
33
+ import { vercel } from "eve/sandbox/vercel";
33
34
 
34
35
  export default defineSandbox({
35
- backend: vercelSandboxBackend(),
36
+ backend: vercel(),
36
37
  });
37
38
  ```
38
39
 
@@ -110,7 +111,7 @@ Agent Runs is separate from the OpenTelemetry exporters configured in [`instrume
110
111
 
111
112
  - [ ] `eve build` succeeds and writes `.vercel/output`.
112
113
  - [ ] Provider keys and route-auth secrets are set in Vercel env vars.
113
- - [ ] The sandbox backend matches the environment (`vercelSandboxBackend()` or `defaultBackend()`).
114
+ - [ ] The sandbox backend matches the environment (`vercel()` or `defaultBackend()`).
114
115
  - [ ] Build-time prewarm reused or built templates without failing.
115
116
  - [ ] `placeholderAuth()` is replaced with your real policy.
116
117
 
package/docs/sandbox.mdx CHANGED
@@ -90,10 +90,11 @@ To add setup, seed files, or pick a backend, author `defineSandbox`. There are t
90
90
  - `agent/sandbox/sandbox.ts`: folder layout. Use it when you also seed `agent/sandbox/workspace/**`. If both exist, the folder layout wins.
91
91
 
92
92
  ```ts title="agent/sandbox/sandbox.ts"
93
- import { defineSandbox, vercelSandboxBackend } from "eve/sandbox";
93
+ import { defineSandbox } from "eve/sandbox";
94
+ import { vercel } from "eve/sandbox/vercel";
94
95
 
95
96
  export default defineSandbox({
96
- backend: vercelSandboxBackend({ runtime: "node24", resources: { vcpus: 2 } }),
97
+ backend: vercel({ runtime: "node24", resources: { vcpus: 2 } }),
97
98
  revalidationKey: () => "repo-bootstrap-v1",
98
99
  async bootstrap({ use }) {
99
100
  const sandbox = await use();
@@ -105,21 +106,21 @@ export default defineSandbox({
105
106
  });
106
107
  ```
107
108
 
108
- `defineSandbox` lives on `eve/sandbox`. Omit `backend` and the runtime falls back to `defaultBackend()` (see [Backends](#backends)).
109
+ `defineSandbox` and `defaultBackend` live on `eve/sandbox`. Omit `backend` and the runtime falls back to `defaultBackend()` (see [Backends](#backends)).
109
110
 
110
111
  ## Backends
111
112
 
112
- The backend decides where the sandbox runs. Eve ships four pinned factories plus an availability-aware default from `eve/sandbox`:
113
+ The backend decides where the sandbox runs. Eve ships four pinned factories from nested `eve/sandbox/*` imports plus an availability-aware default from `eve/sandbox`:
113
114
 
114
- | Backend | Runs the sandbox |
115
- | ------------------------ | ---------------------------------------------------------------------------------------------- |
116
- | `vercelSandboxBackend()` | on [Vercel Sandbox](https://vercel.com/docs/sandbox). |
117
- | `dockerBackend()` | locally in a Docker container, driven through the `docker` CLI. |
118
- | `microsandboxBackend()` | locally in a lightweight [microsandbox](https://www.npmjs.com/package/microsandbox) VM. |
119
- | `justBashBackend()` | locally in the pure-JS `just-bash` interpreter — no daemon or VM, but no real binaries either. |
120
- | `defaultBackend()` | picks the best available: Vercel Sandbox on hosted Vercel → Docker → microsandbox → just-bash. |
115
+ | Backend | Runs the sandbox |
116
+ | ------------------ | ---------------------------------------------------------------------------------------------- |
117
+ | `vercel()` | on [Vercel Sandbox](https://vercel.com/docs/sandbox). |
118
+ | `docker()` | locally in a Docker container, driven through the `docker` CLI. |
119
+ | `microsandbox()` | locally in a lightweight [microsandbox](https://www.npmjs.com/package/microsandbox) VM. |
120
+ | `justbash()` | locally in the pure-JS `just-bash` interpreter — no daemon or VM, but no real binaries either. |
121
+ | `defaultBackend()` | picks the best available: Vercel Sandbox on hosted Vercel → Docker → microsandbox → just-bash. |
121
122
 
122
- Configuring a pinned factory uses that backend unconditionally — `dockerBackend()` always requires a reachable Docker daemon, `vercelSandboxBackend()` always creates hosted sandboxes (including from local dev, with Vercel credentials).
123
+ Configuring a pinned factory uses that backend unconditionally — `docker()` always requires a reachable Docker daemon, `vercel()` always creates hosted sandboxes (including from local dev, with Vercel credentials).
123
124
 
124
125
  With `backend` omitted, Eve uses `defaultBackend()`, which resolves on first use in priority order:
125
126
 
@@ -144,15 +145,15 @@ export default defineSandbox({
144
145
 
145
146
  ### Docker
146
147
 
147
- `dockerBackend()` drives the Docker CLI directly. The default base image is `ghcr.io/vercel/eve:latest`, Eve's published sandbox runtime image; Eve creates `/workspace` and verifies Bash during framework setup before authored bootstrap code runs. Configure it through `dockerBackend({ image, env, pullPolicy, networkPolicy })`; install authored runtime tools in sandbox bootstrap or provide them through a custom image. Templates are committed as local Docker images and reused across sessions when the sandbox source, seed files, `revalidationKey`, and Docker backend options still match; sessions run as long-lived containers whose filesystems persist `/workspace` changes across turns for the same durable session. `eve dev` prunes stale template images in the background.
148
+ `docker()` drives the Docker CLI directly. The default base image is `ghcr.io/vercel/eve:latest`, Eve's published sandbox runtime image; Eve creates `/workspace` and verifies Bash during framework setup before authored bootstrap code runs. Configure it through `docker({ image, env, pullPolicy, networkPolicy })`; install authored runtime tools in sandbox bootstrap or provide them through a custom image. Templates are committed as local Docker images and reused across sessions when the sandbox source, seed files, `revalidationKey`, and Docker backend options still match; sessions run as long-lived containers whose filesystems persist `/workspace` changes across turns for the same durable session. `eve dev` prunes stale template images in the background.
148
149
 
149
150
  ### microsandbox
150
151
 
151
- `microsandboxBackend()` runs each sandbox in a lightweight local VM with snapshot-backed templates, a `vercel-sandbox` user, and a firewall capable of domain-level network policies and credential brokering — the closest local match to hosted Vercel Sandbox. The default base image is `ghcr.io/vercel/eve:latest`, Eve's published sandbox runtime image; Eve verifies Bash, creates `/workspace`, and creates the sandbox user during framework setup before authored bootstrap code runs. Install authored runtime tools in sandbox bootstrap or provide them through a custom image. Supported hosts: macOS on Apple Silicon, or Linux (glibc) with KVM. The `microsandbox` npm package and its VM runtime are not bundled with Eve: `eve dev` installs both automatically when missing (disable with `setup: { autoInstall: false }`); production processes fail with actionable install errors instead.
152
+ `microsandbox()` runs each sandbox in a lightweight local VM with snapshot-backed templates, a `vercel-sandbox` user, and a firewall capable of domain-level network policies and credential brokering — the closest local match to hosted Vercel Sandbox. The default base image is `ghcr.io/vercel/eve:latest`, Eve's published sandbox runtime image; Eve verifies Bash, creates `/workspace`, and creates the sandbox user during framework setup before authored bootstrap code runs. Install authored runtime tools in sandbox bootstrap or provide them through a custom image. Supported hosts: macOS on Apple Silicon, or Linux (glibc) with KVM. The `microsandbox` npm package and its VM runtime are not bundled with Eve: `eve dev` installs both automatically when missing (disable with `setup: { autoInstall: false }`); production processes fail with actionable install errors instead.
152
153
 
153
154
  ### just-bash
154
155
 
155
- `justBashBackend()` needs no daemon or VM, but commands run in a simulated bash with a virtual filesystem under `.eve/sandbox-cache/` — no real binaries (`git`, `node`, package managers) and no network isolation. The `just-bash` package is an optional peer dependency: `eve dev` installs it into your application automatically when missing (disable with `autoInstall: false`); production processes fail with an actionable install error instead.
156
+ `justbash()` needs no daemon or VM, but commands run in a simulated bash with a virtual filesystem under `.eve/sandbox-cache/` — no real binaries (`git`, `node`, package managers) and no network isolation. The `just-bash` package is an optional peer dependency: `eve dev` installs it into your application automatically when missing (disable with `autoInstall: false`); production processes fail with an actionable install error instead.
156
157
 
157
158
  You can write your own backend too: a `SandboxBackend` is just an object with a `name`, a `create`, and an optional `prewarm`. See the `SandboxBackend*` types on `eve/sandbox`.
158
159
 
@@ -164,10 +165,11 @@ There are two hooks, scoped differently:
164
165
  - **`onSession({ use, ctx })`** is durable-session-scoped and runs once per session. This is where per-session setup goes: network policy, resources, timeout, per-user credentials, one-time markers. Because it runs inside the active runtime context, it can read `ctx.session` and derive the current principal without baking credentials into the template. Call `use(opts?)` to get a `SandboxSession`; `opts` flow to the backend's update path after create.
165
166
 
166
167
  ```ts
167
- import { defineSandbox, vercelSandboxBackend } from "eve/sandbox";
168
+ import { defineSandbox } from "eve/sandbox";
169
+ import { vercel } from "eve/sandbox/vercel";
168
170
 
169
171
  export default defineSandbox({
170
- backend: vercelSandboxBackend(),
172
+ backend: vercel(),
171
173
  async onSession({ use, ctx }) {
172
174
  const sandbox = await use({ networkPolicy: "deny-all" });
173
175
  const user = ctx.session.auth.current;
@@ -193,9 +195,9 @@ networkPolicy: {
193
195
  };
194
196
  ```
195
197
 
196
- Set it on the factory (`vercelSandboxBackend({ networkPolicy: "deny-all" })`) and it applies before authored `bootstrap` code runs; framework-owned base setup may briefly keep egress open to install required packages. Set it in `onSession`'s `use()` to override per-session. The common pattern combines both: leave the factory open so `bootstrap` can `git clone`, then lock down in `onSession`. And to change the policy mid-turn, call `sandbox.setNetworkPolicy(...)` on the live handle.
198
+ Set it on the factory (`vercel({ networkPolicy: "deny-all" })`) and it applies before authored `bootstrap` code runs; framework-owned base setup may briefly keep egress open to install required packages. Set it in `onSession`'s `use()` to override per-session. The common pattern combines both: leave the factory open so `bootstrap` can `git clone`, then lock down in `onSession`. And to change the policy mid-turn, call `sandbox.setNetworkPolicy(...)` on the live handle.
197
199
 
198
- Domain-level allow-lists and credential brokering are supported by `vercelSandboxBackend()` and `microsandboxBackend()`. The Docker backend honors only `"allow-all"` and `"deny-all"` (at creation and via `setNetworkPolicy`); the just-bash backend rejects `setNetworkPolicy` entirely.
200
+ Domain-level allow-lists and credential brokering are supported by `vercel()` and `microsandbox()`. The Docker backend honors only `"allow-all"` and `"deny-all"` (at creation and via `setNetworkPolicy`); the just-bash backend rejects `setNetworkPolicy` entirely.
199
201
 
200
202
  ## Credential brokering
201
203
 
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "eve",
3
- "version": "0.8.6",
3
+ "version": "0.9.0",
4
4
  "private": false,
5
5
  "description": "Filesystem-first framework for durable backend AI agents that run anywhere.",
6
6
  "keywords": [
@@ -131,6 +131,26 @@
131
131
  "import": "./dist/src/public/sandbox/index.js",
132
132
  "default": "./dist/src/public/sandbox/index.js"
133
133
  },
134
+ "./sandbox/docker": {
135
+ "types": "./dist/src/public/sandbox/docker.d.ts",
136
+ "import": "./dist/src/public/sandbox/docker.js",
137
+ "default": "./dist/src/public/sandbox/docker.js"
138
+ },
139
+ "./sandbox/just-bash": {
140
+ "types": "./dist/src/public/sandbox/just-bash.d.ts",
141
+ "import": "./dist/src/public/sandbox/just-bash.js",
142
+ "default": "./dist/src/public/sandbox/just-bash.js"
143
+ },
144
+ "./sandbox/microsandbox": {
145
+ "types": "./dist/src/public/sandbox/microsandbox.d.ts",
146
+ "import": "./dist/src/public/sandbox/microsandbox.js",
147
+ "default": "./dist/src/public/sandbox/microsandbox.js"
148
+ },
149
+ "./sandbox/vercel": {
150
+ "types": "./dist/src/public/sandbox/vercel.d.ts",
151
+ "import": "./dist/src/public/sandbox/vercel.js",
152
+ "default": "./dist/src/public/sandbox/vercel.js"
153
+ },
134
154
  "./evals": {
135
155
  "types": "./dist/src/evals/index.d.ts",
136
156
  "import": "./dist/src/evals/index.js",