sbox-sdk 0.0.2

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 (132) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +137 -0
  3. package/dist/adapter/index.d.ts +22 -0
  4. package/dist/adapter/index.d.ts.map +1 -0
  5. package/dist/adapter/index.js +16 -0
  6. package/dist/agent-tools/index.d.ts +13 -0
  7. package/dist/agent-tools/index.d.ts.map +1 -0
  8. package/dist/agent-tools/index.js +9 -0
  9. package/dist/agent-tools/policy.d.ts +48 -0
  10. package/dist/agent-tools/policy.d.ts.map +1 -0
  11. package/dist/agent-tools/policy.js +51 -0
  12. package/dist/agent-tools/registry.d.ts +9 -0
  13. package/dist/agent-tools/registry.d.ts.map +1 -0
  14. package/dist/agent-tools/registry.js +412 -0
  15. package/dist/agent-tools/result.d.ts +32 -0
  16. package/dist/agent-tools/result.d.ts.map +1 -0
  17. package/dist/agent-tools/result.js +14 -0
  18. package/dist/agent-tools/types.d.ts +76 -0
  19. package/dist/agent-tools/types.d.ts.map +1 -0
  20. package/dist/agent-tools/types.js +1 -0
  21. package/dist/ai/index.d.ts +36 -0
  22. package/dist/ai/index.d.ts.map +1 -0
  23. package/dist/ai/index.js +40 -0
  24. package/dist/ai-sdk/index.d.ts +31 -0
  25. package/dist/ai-sdk/index.d.ts.map +1 -0
  26. package/dist/ai-sdk/index.js +80 -0
  27. package/dist/anthropic/index.d.ts +42 -0
  28. package/dist/anthropic/index.d.ts.map +1 -0
  29. package/dist/anthropic/index.js +64 -0
  30. package/dist/aws-lambda/index.d.ts +87 -0
  31. package/dist/aws-lambda/index.d.ts.map +1 -0
  32. package/dist/aws-lambda/index.js +290 -0
  33. package/dist/beam/index.d.ts +92 -0
  34. package/dist/beam/index.d.ts.map +1 -0
  35. package/dist/beam/index.js +222 -0
  36. package/dist/blaxel/index.d.ts +125 -0
  37. package/dist/blaxel/index.d.ts.map +1 -0
  38. package/dist/blaxel/index.js +220 -0
  39. package/dist/cli.d.ts +3 -0
  40. package/dist/cli.d.ts.map +1 -0
  41. package/dist/cli.js +249 -0
  42. package/dist/cloudflare/index.d.ts +64 -0
  43. package/dist/cloudflare/index.d.ts.map +1 -0
  44. package/dist/cloudflare/index.js +259 -0
  45. package/dist/codesandbox/index.d.ts +100 -0
  46. package/dist/codesandbox/index.d.ts.map +1 -0
  47. package/dist/codesandbox/index.js +227 -0
  48. package/dist/conformance/index.d.ts +20 -0
  49. package/dist/conformance/index.d.ts.map +1 -0
  50. package/dist/conformance/index.js +189 -0
  51. package/dist/daytona/index.d.ts +64 -0
  52. package/dist/daytona/index.d.ts.map +1 -0
  53. package/dist/daytona/index.js +258 -0
  54. package/dist/e2b/index.d.ts +63 -0
  55. package/dist/e2b/index.d.ts.map +1 -0
  56. package/dist/e2b/index.js +411 -0
  57. package/dist/fly/index.d.ts +75 -0
  58. package/dist/fly/index.d.ts.map +1 -0
  59. package/dist/fly/index.js +222 -0
  60. package/dist/index.d.ts +21 -0
  61. package/dist/index.d.ts.map +1 -0
  62. package/dist/index.js +16 -0
  63. package/dist/internal/capabilities.d.ts +57 -0
  64. package/dist/internal/capabilities.d.ts.map +1 -0
  65. package/dist/internal/capabilities.js +68 -0
  66. package/dist/internal/client.d.ts +9 -0
  67. package/dist/internal/client.d.ts.map +1 -0
  68. package/dist/internal/client.js +126 -0
  69. package/dist/internal/encoding.d.ts +8 -0
  70. package/dist/internal/encoding.d.ts.map +1 -0
  71. package/dist/internal/encoding.js +20 -0
  72. package/dist/internal/errors.d.ts +45 -0
  73. package/dist/internal/errors.d.ts.map +1 -0
  74. package/dist/internal/errors.js +79 -0
  75. package/dist/internal/exec.d.ts +19 -0
  76. package/dist/internal/exec.d.ts.map +1 -0
  77. package/dist/internal/exec.js +208 -0
  78. package/dist/internal/plugin.d.ts +38 -0
  79. package/dist/internal/plugin.d.ts.map +1 -0
  80. package/dist/internal/plugin.js +1 -0
  81. package/dist/internal/runtime.d.ts +8 -0
  82. package/dist/internal/runtime.d.ts.map +1 -0
  83. package/dist/internal/runtime.js +21 -0
  84. package/dist/internal/sandbox.d.ts +12 -0
  85. package/dist/internal/sandbox.d.ts.map +1 -0
  86. package/dist/internal/sandbox.js +438 -0
  87. package/dist/internal/shell.d.ts +36 -0
  88. package/dist/internal/shell.d.ts.map +1 -0
  89. package/dist/internal/shell.js +88 -0
  90. package/dist/internal/stream.d.ts +15 -0
  91. package/dist/internal/stream.d.ts.map +1 -0
  92. package/dist/internal/stream.js +58 -0
  93. package/dist/internal/types.d.ts +381 -0
  94. package/dist/internal/types.d.ts.map +1 -0
  95. package/dist/internal/types.js +1 -0
  96. package/dist/langchain/index.d.ts +25 -0
  97. package/dist/langchain/index.d.ts.map +1 -0
  98. package/dist/langchain/index.js +61 -0
  99. package/dist/mastra/index.d.ts +43 -0
  100. package/dist/mastra/index.d.ts.map +1 -0
  101. package/dist/mastra/index.js +69 -0
  102. package/dist/memory/index.d.ts +57 -0
  103. package/dist/memory/index.d.ts.map +1 -0
  104. package/dist/memory/index.js +573 -0
  105. package/dist/modal/index.d.ts +67 -0
  106. package/dist/modal/index.d.ts.map +1 -0
  107. package/dist/modal/index.js +223 -0
  108. package/dist/morph/index.d.ts +91 -0
  109. package/dist/morph/index.d.ts.map +1 -0
  110. package/dist/morph/index.js +221 -0
  111. package/dist/northflank/index.d.ts +74 -0
  112. package/dist/northflank/index.d.ts.map +1 -0
  113. package/dist/northflank/index.js +265 -0
  114. package/dist/openai/index.d.ts +25 -0
  115. package/dist/openai/index.d.ts.map +1 -0
  116. package/dist/openai/index.js +71 -0
  117. package/dist/railway/index.d.ts +109 -0
  118. package/dist/railway/index.d.ts.map +1 -0
  119. package/dist/railway/index.js +219 -0
  120. package/dist/runloop/index.d.ts +69 -0
  121. package/dist/runloop/index.d.ts.map +1 -0
  122. package/dist/runloop/index.js +226 -0
  123. package/dist/testing/index.d.ts +44 -0
  124. package/dist/testing/index.d.ts.map +1 -0
  125. package/dist/testing/index.js +61 -0
  126. package/dist/vercel/index.d.ts +63 -0
  127. package/dist/vercel/index.d.ts.map +1 -0
  128. package/dist/vercel/index.js +241 -0
  129. package/package.json +252 -0
  130. package/src/aws-lambda/runner/Dockerfile +15 -0
  131. package/src/aws-lambda/runner/README.md +59 -0
  132. package/src/aws-lambda/runner/server.mjs +91 -0
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/vercel/index.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,OAAO,IAAI,aAAa,EAAE,MAAM,iBAAiB,CAAC;AAchE,OAAO,KAAK,EAYV,eAAe,EAGhB,MAAM,qBAAqB,CAAC;AAE7B,MAAM,WAAW,aAAa;IAC5B,KAAK,EAAE,MAAM,CAAC;IACd,MAAM,EAAE,MAAM,CAAC;IACf,SAAS,EAAE,MAAM,CAAC;CACnB;AAED,eAAO,MAAM,WAAW;;;;;;;;;;;;;;;;;;;;;;;;;;CA0BU,CAAC;AAEnC,MAAM,MAAM,UAAU,GAAG,OAAO,WAAW,CAAC;AAgE5C,eAAO,MAAM,MAAM;;;;;;;;;;;;;;;;;;;;;;;;;;iBA6MlB,CAAC"}
@@ -0,0 +1,241 @@
1
+ /**
2
+ * `sbox-sdk/vercel` — adapter for `@vercel/sandbox` (ephemeral microVMs).
3
+ * Exercises the exec-emulation surface: no PTY, no fs watch, no code interpreter.
4
+ * Node-only (uses Buffer for binary fs). Requires the optional peer dependency
5
+ * `@vercel/sandbox`; auth via a Vercel token + team/project ids (OIDC or PAT).
6
+ */
7
+ import { AsyncQueue, defineProvider, numExit, SandboxError, } from "../adapter/index.js";
8
+ export const VERCEL_CAPS = {
9
+ background: "native",
10
+ codeInterpreter: "unsupported",
11
+ egressControl: "unsupported",
12
+ exposePort: "native",
13
+ filesUpload: "native",
14
+ filesWatch: "unsupported",
15
+ fork: "unsupported",
16
+ gpu: "unsupported",
17
+ killProcess: "unsupported",
18
+ list: "unsupported",
19
+ metrics: "unsupported",
20
+ pause: "unsupported",
21
+ privatePreview: "unsupported",
22
+ proxiedFetch: "unsupported",
23
+ pty: "unsupported",
24
+ region: "unsupported",
25
+ secretsVault: "unsupported",
26
+ setTimeout: "unsupported",
27
+ snapshot: "unsupported",
28
+ ssh: "unsupported",
29
+ statefulKernel: "unsupported",
30
+ stdin: "unsupported",
31
+ stop: "unsupported",
32
+ streaming: "native",
33
+ volumes: "unsupported",
34
+ };
35
+ const VERCEL_FLAGS = {
36
+ exitCodeNative: true,
37
+ perCommandEnvCwd: true,
38
+ preservesDiskOnStop: true, // stop() auto-snapshots the filesystem
39
+ preservesMemoryOnPause: false,
40
+ previewModel: "declaredPorts",
41
+ };
42
+ let cached = null;
43
+ async function loadVercel() {
44
+ if (!cached) {
45
+ cached = (await import("@vercel/sandbox"));
46
+ }
47
+ return cached;
48
+ }
49
+ function mapState(status) {
50
+ switch (status) {
51
+ case "running": {
52
+ return "running";
53
+ }
54
+ case "stopped":
55
+ case "stopping": {
56
+ return "stopped";
57
+ }
58
+ case "pending":
59
+ case "initializing": {
60
+ return "creating";
61
+ }
62
+ case "failed": {
63
+ return "error";
64
+ }
65
+ default: {
66
+ return "unknown";
67
+ }
68
+ }
69
+ }
70
+ function mapVercelError(e) {
71
+ const msg = e instanceof Error ? e.message : String(e);
72
+ if (/not ?found/i.test(msg)) {
73
+ return new SandboxError("NotFound", msg, { cause: e, provider: "vercel" });
74
+ }
75
+ if (/unauthor|forbidden|token/i.test(msg)) {
76
+ return new SandboxError("Unauthorized", msg, {
77
+ cause: e,
78
+ provider: "vercel",
79
+ });
80
+ }
81
+ if (/timeout|timed out/i.test(msg)) {
82
+ return new SandboxError("Timeout", msg, { cause: e, provider: "vercel" });
83
+ }
84
+ return undefined;
85
+ }
86
+ export const vercel = defineProvider((opts) => {
87
+ const creds = {
88
+ projectId: opts.projectId,
89
+ teamId: opts.teamId,
90
+ token: opts.token,
91
+ };
92
+ const makeHandle = (sb) => {
93
+ const v = sb;
94
+ const drive = (queue, cmdP) => {
95
+ void (async () => {
96
+ let cmd;
97
+ try {
98
+ cmd = await cmdP;
99
+ }
100
+ catch (error) {
101
+ queue.fail(mapVercelError(error) ?? SandboxError.wrap(error, "vercel"));
102
+ return;
103
+ }
104
+ try {
105
+ for await (const log of cmd.logs()) {
106
+ queue.push({
107
+ data: log.data,
108
+ type: log.stream === "stderr" ? "stderr" : "stdout",
109
+ });
110
+ }
111
+ const fin = await cmd.wait();
112
+ queue.push({ exitCode: fin.exitCode, type: "exit" });
113
+ }
114
+ catch (error) {
115
+ queue.push({ exitCode: numExit(error), type: "exit" });
116
+ }
117
+ queue.close();
118
+ })();
119
+ };
120
+ return {
121
+ id: v.sandboxId,
122
+ raw: sb,
123
+ getInfo() {
124
+ return {
125
+ id: v.sandboxId,
126
+ metadata: {},
127
+ provider: "vercel",
128
+ raw: sb,
129
+ state: mapState(v.status),
130
+ };
131
+ },
132
+ async destroy() {
133
+ await v.stop();
134
+ },
135
+ exec(cmd, options) {
136
+ const queue = new AsyncQueue();
137
+ const cmdP = v.runCommand({
138
+ args: ["-c", cmd],
139
+ cmd: "sh",
140
+ cwd: options.cwd,
141
+ detached: true,
142
+ env: options.env,
143
+ });
144
+ drive(queue, cmdP);
145
+ return {
146
+ pid: cmdP.then((c) => c.cmdId).catch(() => ""),
147
+ async kill() {
148
+ /* no kill handle exposed by the SDK */
149
+ },
150
+ [Symbol.asyncIterator]: () => queue.iterator(),
151
+ };
152
+ },
153
+ async spawn(cmd, options) {
154
+ const c = await v.runCommand({
155
+ args: ["-c", cmd],
156
+ cmd: "sh",
157
+ cwd: options.cwd,
158
+ detached: true,
159
+ env: options.env,
160
+ });
161
+ const queue = new AsyncQueue();
162
+ drive(queue, Promise.resolve(c));
163
+ return {
164
+ id: c.cmdId,
165
+ pid: Promise.resolve(c.cmdId),
166
+ async kill() {
167
+ /* no kill handle exposed by the SDK */
168
+ },
169
+ [Symbol.asyncIterator]: () => queue.iterator(),
170
+ };
171
+ },
172
+ async readFile(path) {
173
+ const buf = await v.fs.readFileToBuffer({ path });
174
+ if (!buf) {
175
+ throw new SandboxError("NotFound", `no such file: '${path}'`, {
176
+ provider: "vercel",
177
+ });
178
+ }
179
+ return new Uint8Array(buf);
180
+ },
181
+ async writeFile(path, data) {
182
+ await v.fs.writeFiles([{ content: data, path }]);
183
+ },
184
+ async listDir(path) {
185
+ const entries = await v.fs.readdir(path, { withFileTypes: true });
186
+ return entries.map((d) => ({
187
+ name: d.name,
188
+ path: `${path.replace(/\/$/, "")}/${d.name}`,
189
+ type: d.isDirectory() ? "dir" : "file",
190
+ }));
191
+ },
192
+ async mkdir(path, recursive) {
193
+ await v.fs.mkdir(path, { recursive });
194
+ },
195
+ async remove(path, recursive) {
196
+ await v.fs.rm(path, { force: true, recursive });
197
+ },
198
+ async stat(path) {
199
+ const s = await v.fs.stat(path);
200
+ return {
201
+ mtime: s.mtime,
202
+ path,
203
+ size: s.size,
204
+ type: s.isDirectory() ? "dir" : "file",
205
+ };
206
+ },
207
+ exposePort(port) {
208
+ return { port, url: v.domain(port) };
209
+ },
210
+ // NOTE: rename is omitted -> the core polyfills it via exec(`mv`).
211
+ };
212
+ };
213
+ const provider = {
214
+ capabilities: VERCEL_CAPS,
215
+ async connect(id) {
216
+ const { Sandbox } = await loadVercel();
217
+ const sb = await Sandbox.get({ ...creds, sandboxId: id });
218
+ return makeHandle(sb);
219
+ },
220
+ async create(spec) {
221
+ const { Sandbox } = await loadVercel();
222
+ const sb = await Sandbox.create({
223
+ ...creds,
224
+ env: spec.env,
225
+ name: spec.name,
226
+ ports: spec.ports,
227
+ resources: spec.resources?.vcpus
228
+ ? { vcpus: spec.resources.vcpus }
229
+ : undefined,
230
+ runtime: spec.template,
231
+ signal: spec.signal,
232
+ timeout: spec.ttlMs,
233
+ });
234
+ return makeHandle(sb);
235
+ },
236
+ flags: VERCEL_FLAGS,
237
+ mapError: mapVercelError,
238
+ name: "vercel",
239
+ };
240
+ return provider;
241
+ });
package/package.json ADDED
@@ -0,0 +1,252 @@
1
+ {
2
+ "name": "sbox-sdk",
3
+ "version": "0.0.2",
4
+ "description": "One unified SDK for agent sandbox providers (E2B, Vercel, Cloudflare, Daytona, Modal, and more) — swap the adapter import, keep your code.",
5
+ "keywords": [
6
+ "agent",
7
+ "ai",
8
+ "cloudflare-sandbox",
9
+ "code-interpreter",
10
+ "daytona",
11
+ "e2b",
12
+ "sandbox",
13
+ "vercel-sandbox"
14
+ ],
15
+ "license": "MIT",
16
+ "bin": {
17
+ "sbox": "dist/cli.js"
18
+ },
19
+ "files": [
20
+ "dist",
21
+ "src/aws-lambda/runner",
22
+ "README.md",
23
+ "LICENSE"
24
+ ],
25
+ "type": "module",
26
+ "sideEffects": false,
27
+ "exports": {
28
+ ".": {
29
+ "types": "./dist/index.d.ts",
30
+ "import": "./dist/index.js"
31
+ },
32
+ "./adapter": {
33
+ "types": "./dist/adapter/index.d.ts",
34
+ "import": "./dist/adapter/index.js"
35
+ },
36
+ "./testing": {
37
+ "types": "./dist/testing/index.d.ts",
38
+ "import": "./dist/testing/index.js"
39
+ },
40
+ "./conformance": {
41
+ "types": "./dist/conformance/index.d.ts",
42
+ "import": "./dist/conformance/index.js"
43
+ },
44
+ "./memory": {
45
+ "types": "./dist/memory/index.d.ts",
46
+ "import": "./dist/memory/index.js"
47
+ },
48
+ "./agent-tools": {
49
+ "types": "./dist/agent-tools/index.d.ts",
50
+ "import": "./dist/agent-tools/index.js"
51
+ },
52
+ "./ai": {
53
+ "types": "./dist/ai/index.d.ts",
54
+ "import": "./dist/ai/index.js"
55
+ },
56
+ "./ai-sdk": {
57
+ "types": "./dist/ai-sdk/index.d.ts",
58
+ "import": "./dist/ai-sdk/index.js"
59
+ },
60
+ "./mastra": {
61
+ "types": "./dist/mastra/index.d.ts",
62
+ "import": "./dist/mastra/index.js"
63
+ },
64
+ "./openai": {
65
+ "types": "./dist/openai/index.d.ts",
66
+ "import": "./dist/openai/index.js"
67
+ },
68
+ "./anthropic": {
69
+ "types": "./dist/anthropic/index.d.ts",
70
+ "import": "./dist/anthropic/index.js"
71
+ },
72
+ "./langchain": {
73
+ "types": "./dist/langchain/index.d.ts",
74
+ "import": "./dist/langchain/index.js"
75
+ },
76
+ "./e2b": {
77
+ "types": "./dist/e2b/index.d.ts",
78
+ "import": "./dist/e2b/index.js"
79
+ },
80
+ "./cloudflare": {
81
+ "types": "./dist/cloudflare/index.d.ts",
82
+ "import": "./dist/cloudflare/index.js"
83
+ },
84
+ "./vercel": {
85
+ "types": "./dist/vercel/index.d.ts",
86
+ "import": "./dist/vercel/index.js"
87
+ },
88
+ "./daytona": {
89
+ "types": "./dist/daytona/index.d.ts",
90
+ "import": "./dist/daytona/index.js"
91
+ },
92
+ "./modal": {
93
+ "types": "./dist/modal/index.d.ts",
94
+ "import": "./dist/modal/index.js"
95
+ },
96
+ "./fly": {
97
+ "types": "./dist/fly/index.d.ts",
98
+ "import": "./dist/fly/index.js"
99
+ },
100
+ "./aws-lambda": {
101
+ "types": "./dist/aws-lambda/index.d.ts",
102
+ "import": "./dist/aws-lambda/index.js"
103
+ },
104
+ "./northflank": {
105
+ "types": "./dist/northflank/index.d.ts",
106
+ "import": "./dist/northflank/index.js"
107
+ },
108
+ "./runloop": {
109
+ "types": "./dist/runloop/index.d.ts",
110
+ "import": "./dist/runloop/index.js"
111
+ },
112
+ "./codesandbox": {
113
+ "types": "./dist/codesandbox/index.d.ts",
114
+ "import": "./dist/codesandbox/index.js"
115
+ },
116
+ "./morph": {
117
+ "types": "./dist/morph/index.d.ts",
118
+ "import": "./dist/morph/index.js"
119
+ },
120
+ "./blaxel": {
121
+ "types": "./dist/blaxel/index.d.ts",
122
+ "import": "./dist/blaxel/index.js"
123
+ },
124
+ "./beam": {
125
+ "types": "./dist/beam/index.d.ts",
126
+ "import": "./dist/beam/index.js"
127
+ },
128
+ "./railway": {
129
+ "types": "./dist/railway/index.d.ts",
130
+ "import": "./dist/railway/index.js"
131
+ }
132
+ },
133
+ "scripts": {
134
+ "build": "rm -rf dist && tsc -p tsconfig.json && chmod +x dist/cli.js",
135
+ "check-types": "tsgo -p tsconfig.json --noEmit",
136
+ "types": "tsgo -p tsconfig.json --noEmit",
137
+ "test": "vitest run",
138
+ "test:watch": "vitest",
139
+ "prepack": "pnpm run build"
140
+ },
141
+ "devDependencies": {
142
+ "@anthropic-ai/sdk": "^0.69.0",
143
+ "@aws-sdk/client-lambda": "^3.1075.0",
144
+ "@aws-sdk/client-lambda-microvms": "^3.1075.0",
145
+ "@aws-sdk/client-s3": "^3.1075.0",
146
+ "@beamcloud/beam-js": "*",
147
+ "@blaxel/core": "*",
148
+ "@cloudflare/sandbox": "^0.12.1",
149
+ "@codesandbox/sdk": "*",
150
+ "@daytonaio/sdk": "^0.191.0",
151
+ "@e2b/code-interpreter": "^2.6.1",
152
+ "@langchain/core": "^0.3.0",
153
+ "@mastra/core": "^1.46.0",
154
+ "@northflank/js-client": "*",
155
+ "@openai/agents": "^0.12.0",
156
+ "@runloop/api-client": "*",
157
+ "@sbox-sdk/config": "workspace:*",
158
+ "@types/node": "^25.9.1",
159
+ "@typescript/native-preview": "7.0.0-dev.20260624.1",
160
+ "@vercel/sandbox": "^2.2.1",
161
+ "ai": "^5.0.0",
162
+ "modal": "^0.8.1",
163
+ "morphcloud": "*",
164
+ "railway": "*",
165
+ "typescript": "5.9.2",
166
+ "vitest": "^3.2.4",
167
+ "zod": "^4.0.0"
168
+ },
169
+ "peerDependencies": {
170
+ "@anthropic-ai/sdk": ">=0.40.0",
171
+ "@aws-sdk/client-lambda-microvms": "*",
172
+ "@beamcloud/beam-js": "*",
173
+ "@blaxel/core": "*",
174
+ "@cloudflare/sandbox": "*",
175
+ "@codesandbox/sdk": "*",
176
+ "@daytonaio/sdk": "*",
177
+ "@e2b/code-interpreter": "*",
178
+ "@langchain/core": ">=0.3.0",
179
+ "@mastra/core": "^1.0.0",
180
+ "@northflank/js-client": "*",
181
+ "@openai/agents": ">=0.12.0",
182
+ "@runloop/api-client": "*",
183
+ "@vercel/sandbox": "*",
184
+ "ai": "^5.0.0 || ^6.0.0",
185
+ "modal": "*",
186
+ "morphcloud": "*",
187
+ "railway": "*",
188
+ "zod": "^3.25.0 || ^4.0.0"
189
+ },
190
+ "peerDependenciesMeta": {
191
+ "@aws-sdk/client-lambda-microvms": {
192
+ "optional": true
193
+ },
194
+ "@beamcloud/beam-js": {
195
+ "optional": true
196
+ },
197
+ "@blaxel/core": {
198
+ "optional": true
199
+ },
200
+ "@cloudflare/sandbox": {
201
+ "optional": true
202
+ },
203
+ "@codesandbox/sdk": {
204
+ "optional": true
205
+ },
206
+ "@northflank/js-client": {
207
+ "optional": true
208
+ },
209
+ "@runloop/api-client": {
210
+ "optional": true
211
+ },
212
+ "morphcloud": {
213
+ "optional": true
214
+ },
215
+ "railway": {
216
+ "optional": true
217
+ },
218
+ "@daytonaio/sdk": {
219
+ "optional": true
220
+ },
221
+ "@e2b/code-interpreter": {
222
+ "optional": true
223
+ },
224
+ "modal": {
225
+ "optional": true
226
+ },
227
+ "@vercel/sandbox": {
228
+ "optional": true
229
+ },
230
+ "zod": {
231
+ "optional": true
232
+ },
233
+ "ai": {
234
+ "optional": true
235
+ },
236
+ "@mastra/core": {
237
+ "optional": true
238
+ },
239
+ "@openai/agents": {
240
+ "optional": true
241
+ },
242
+ "@anthropic-ai/sdk": {
243
+ "optional": true
244
+ },
245
+ "@langchain/core": {
246
+ "optional": true
247
+ }
248
+ },
249
+ "engines": {
250
+ "node": ">=20.0.0"
251
+ }
252
+ }
@@ -0,0 +1,15 @@
1
+ # Reference MicroVM image for the sbox-sdk AWS Lambda MicroVMs adapter.
2
+ # Build -> zip with this Dockerfile + server.mjs -> upload to S3 ->
3
+ # CreateMicrovmImage (see ./README.md). The runner runs INSIDE the isolated
4
+ # MicroVM; executing arbitrary commands is its purpose (that is what the sandbox
5
+ # is for), and it is never exposed on the host.
6
+ FROM public.ecr.aws/docker/library/node:22-slim
7
+
8
+ WORKDIR /opt/sbox
9
+ COPY server.mjs .
10
+
11
+ # The MicroVM endpoint routes to port 8080 by default.
12
+ ENV PORT=8080
13
+ EXPOSE 8080
14
+
15
+ CMD ["node", "/opt/sbox/server.mjs"]
@@ -0,0 +1,59 @@
1
+ # sbox-sdk runner for AWS Lambda MicroVMs
2
+
3
+ AWS Lambda MicroVMs give you isolation + lifecycle + a dedicated HTTPS endpoint,
4
+ but **the exec/filesystem protocol is defined by your image** — AWS only defines
5
+ lifecycle hooks. This folder is a reference "runner" the `sbox-sdk/aws-lambda`
6
+ adapter talks to. Bake it into your MicroVM image once.
7
+
8
+ ## Protocol the adapter expects
9
+
10
+ Served on port `8080` (override with the adapter's `port` option):
11
+
12
+ | Method & path | Body | Response |
13
+ | --------------------------------------------------------------------- | --------------------------------- | ------------------------------------ |
14
+ | `POST /sbox/exec` | `{ cmd, cwd?, env?, timeoutMs? }` | `{ stdout, stderr, exitCode }` |
15
+ | `POST /sbox/fs/read` | `{ path }` | `{ contentBase64 }` (404 if missing) |
16
+ | `POST /sbox/fs/write` | `{ path, contentBase64 }` | `{ ok: true }` |
17
+ | `GET /sbox/health` | — | `200` |
18
+ | `POST /aws/lambda-microvms/runtime/v1/{run,resume,suspend,terminate}` | — | `200` |
19
+
20
+ The `/run` hook must return `200` before traffic flows — the reference
21
+ `server.mjs` does this. Directory ops (`ls`, `mkdir`, `mv`, `stat`) are not
22
+ separate routes: the core polyfills them through `/sbox/exec`.
23
+
24
+ > Security: the runner runs **inside the isolated MicroVM** and executes
25
+ > arbitrary commands on purpose — that is the sandbox. Never run it on a host.
26
+
27
+ ## Build & register the image
28
+
29
+ ```bash
30
+ zip -j runner.zip Dockerfile server.mjs
31
+ aws s3 cp runner.zip s3://YOUR_BUCKET/runner.zip
32
+
33
+ aws lambda-microvms create-microvm-image \
34
+ --image-name sbox-runner \
35
+ --source '{"s3":{"bucket":"YOUR_BUCKET","key":"runner.zip"}}'
36
+ # -> note the returned image ARN
37
+ ```
38
+
39
+ ## Use it
40
+
41
+ ```ts
42
+ import { createSandboxClient } from "sbox-sdk";
43
+ import { awsLambda } from "sbox-sdk/aws-lambda";
44
+
45
+ const client = createSandboxClient({
46
+ provider: awsLambda({
47
+ imageIdentifier:
48
+ "arn:aws:lambda:us-east-1:123456789012:microvm-image:sbox-runner",
49
+ region: "us-east-1",
50
+ }),
51
+ });
52
+
53
+ const sandbox = await client.create();
54
+ const res = await sandbox.commands.run("echo hello"); // res.stdout === "hello\n"
55
+ await sandbox.files.write("/tmp/data.txt", "hi");
56
+ await sandbox.pause(); // SuspendMicrovm (memory + disk preserved up to 8h)
57
+ await sandbox.resume(); // ResumeMicrovm
58
+ await sandbox.destroy(); // TerminateMicrovm
59
+ ```
@@ -0,0 +1,91 @@
1
+ // Reference "runner" for sbox-sdk's AWS Lambda MicroVMs adapter.
2
+ // Bake this into your MicroVM image (see Dockerfile). It exposes the small HTTP
3
+ // protocol the adapter calls over the microVM's dedicated endpoint, plus the
4
+ // required AWS lifecycle hooks. No external deps — Node stdlib only.
5
+ //
6
+ // Protocol (POST JSON unless noted), served on PORT (default 8080):
7
+ // POST /sbox/exec { cmd, cwd?, env?, timeoutMs? } -> { stdout, stderr, exitCode }
8
+ // POST /sbox/fs/read { path } -> { contentBase64 } (404 if missing)
9
+ // POST /sbox/fs/write { path, contentBase64 } -> { ok: true }
10
+ // GET /sbox/health -> 200
11
+ // POST /aws/lambda-microvms/runtime/v1/{run,resume,suspend,terminate} -> 200
12
+
13
+ import { exec } from "node:child_process";
14
+ import { readFile, writeFile, mkdir } from "node:fs/promises";
15
+ import { createServer } from "node:http";
16
+ import { dirname } from "node:path";
17
+
18
+ const PORT = Number(process.env.PORT ?? 8080);
19
+
20
+ const readJson = (req) =>
21
+ new Promise((resolve, reject) => {
22
+ let body = "";
23
+ req.on("data", (c) => (body += c));
24
+ req.on("end", () => {
25
+ try {
26
+ resolve(body ? JSON.parse(body) : {});
27
+ } catch (error) {
28
+ reject(error);
29
+ }
30
+ });
31
+ req.on("error", reject);
32
+ });
33
+
34
+ const send = (res, status, obj) => {
35
+ res.writeHead(status, { "content-type": "application/json" });
36
+ res.end(obj === undefined ? "" : JSON.stringify(obj));
37
+ };
38
+
39
+ const runCmd = (cmd, cwd, env, timeoutMs) =>
40
+ new Promise((resolve) => {
41
+ exec(
42
+ cmd,
43
+ {
44
+ cwd,
45
+ env: { ...process.env, ...env },
46
+ maxBuffer: 64 * 1024 * 1024,
47
+ timeout: timeoutMs ?? 0,
48
+ },
49
+ (err, stdout, stderr) => {
50
+ const exitCode =
51
+ err && typeof err.code === "number" ? err.code : err ? 1 : 0;
52
+ resolve({ exitCode, stderr: String(stderr), stdout: String(stdout) });
53
+ }
54
+ );
55
+ });
56
+
57
+ createServer(async (req, res) => {
58
+ try {
59
+ const url = req.url ?? "/";
60
+ if (req.method === "GET" && url === "/sbox/health") {
61
+ return send(res, 200, { ok: true });
62
+ }
63
+
64
+ if (url.startsWith("/aws/lambda-microvms/runtime/v1/")) {
65
+ return send(res, 200, { ok: true });
66
+ }
67
+
68
+ if (req.method === "POST" && url === "/sbox/exec") {
69
+ const { cmd, cwd, env, timeoutMs } = await readJson(req);
70
+ return send(res, 200, await runCmd(cmd, cwd, env, timeoutMs));
71
+ }
72
+ if (req.method === "POST" && url === "/sbox/fs/read") {
73
+ const { path } = await readJson(req);
74
+ try {
75
+ const buf = await readFile(path);
76
+ return send(res, 200, { contentBase64: buf.toString("base64") });
77
+ } catch {
78
+ return send(res, 404, { error: "not found" });
79
+ }
80
+ }
81
+ if (req.method === "POST" && url === "/sbox/fs/write") {
82
+ const { path, contentBase64 } = await readJson(req);
83
+ await mkdir(dirname(path), { recursive: true });
84
+ await writeFile(path, Buffer.from(contentBase64, "base64"));
85
+ return send(res, 200, { ok: true });
86
+ }
87
+ return send(res, 404, { error: "unknown route" });
88
+ } catch (error) {
89
+ return send(res, 500, { error: String(error?.message ?? error) });
90
+ }
91
+ }).listen(PORT, () => console.log(`[sbox-runner] listening on :${PORT}`));