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,57 @@
1
+ import type { Preview, SandboxProvider, SandboxState } from "../adapter/index.js";
2
+ export interface MemoryOptions {
3
+ /** Hide native fs methods to force the core's exec-based polyfills. */
4
+ bareFs?: boolean;
5
+ idPrefix?: string;
6
+ }
7
+ declare const MEMORY_CAPS: {
8
+ readonly background: "native";
9
+ readonly codeInterpreter: "unsupported";
10
+ readonly egressControl: "unsupported";
11
+ readonly exposePort: "emulated";
12
+ readonly filesUpload: "native";
13
+ readonly filesWatch: "unsupported";
14
+ readonly fork: "native";
15
+ readonly gpu: "unsupported";
16
+ readonly killProcess: "native";
17
+ readonly list: "native";
18
+ readonly metrics: "unsupported";
19
+ readonly pause: "native";
20
+ readonly privatePreview: "unsupported";
21
+ readonly proxiedFetch: "unsupported";
22
+ readonly pty: "unsupported";
23
+ readonly region: "unsupported";
24
+ readonly secretsVault: "unsupported";
25
+ readonly setTimeout: "native";
26
+ readonly snapshot: "native";
27
+ readonly ssh: "unsupported";
28
+ readonly statefulKernel: "unsupported";
29
+ readonly stdin: "unsupported";
30
+ readonly stop: "native";
31
+ readonly streaming: "native";
32
+ readonly volumes: "unsupported";
33
+ };
34
+ export type MemoryCaps = typeof MEMORY_CAPS;
35
+ interface MemSandbox {
36
+ id: string;
37
+ files: Map<string, Uint8Array>;
38
+ dirs: Set<string>;
39
+ env: Record<string, string>;
40
+ metadata: Record<string, string>;
41
+ state: SandboxState;
42
+ createdAt: Date;
43
+ ports: Map<number, Preview>;
44
+ procCounter: number;
45
+ processes: Map<string, {
46
+ cmd: string;
47
+ }>;
48
+ snapshots: Map<string, {
49
+ files: Map<string, Uint8Array>;
50
+ dirs: Set<string>;
51
+ }>;
52
+ snapCounter: number;
53
+ }
54
+ export type MemoryRaw = MemSandbox;
55
+ export declare function memory(opts?: MemoryOptions): SandboxProvider<MemoryCaps, MemoryRaw>;
56
+ export {};
57
+ //# sourceMappingURL=index.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/memory/index.ts"],"names":[],"mappings":"AAOA,OAAO,KAAK,EAUV,OAAO,EAEP,eAAe,EAEf,YAAY,EAEb,MAAM,qBAAqB,CAAC;AAE7B,MAAM,WAAW,aAAa;IAC5B,uEAAuE;IACvE,MAAM,CAAC,EAAE,OAAO,CAAC;IACjB,QAAQ,CAAC,EAAE,MAAM,CAAC;CACnB;AAED,QAAA,MAAM,WAAW;;;;;;;;;;;;;;;;;;;;;;;;;;CA0BiB,CAAC;AAEnC,MAAM,MAAM,UAAU,GAAG,OAAO,WAAW,CAAC;AAU5C,UAAU,UAAU;IAClB,EAAE,EAAE,MAAM,CAAC;IACX,KAAK,EAAE,GAAG,CAAC,MAAM,EAAE,UAAU,CAAC,CAAC;IAC/B,IAAI,EAAE,GAAG,CAAC,MAAM,CAAC,CAAC;IAClB,GAAG,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;IAC5B,QAAQ,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;IACjC,KAAK,EAAE,YAAY,CAAC;IACpB,SAAS,EAAE,IAAI,CAAC;IAChB,KAAK,EAAE,GAAG,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;IAC5B,WAAW,EAAE,MAAM,CAAC;IACpB,SAAS,EAAE,GAAG,CAAC,MAAM,EAAE;QAAE,GAAG,EAAE,MAAM,CAAA;KAAE,CAAC,CAAC;IACxC,SAAS,EAAE,GAAG,CAAC,MAAM,EAAE;QAAE,KAAK,EAAE,GAAG,CAAC,MAAM,EAAE,UAAU,CAAC,CAAC;QAAC,IAAI,EAAE,GAAG,CAAC,MAAM,CAAC,CAAA;KAAE,CAAC,CAAC;IAC9E,WAAW,EAAE,MAAM,CAAC;CACrB;AAED,MAAM,MAAM,SAAS,GAAG,UAAU,CAAC;AA0XnC,wBAAgB,MAAM,CACpB,IAAI,GAAE,aAAkB,GACvB,eAAe,CAAC,UAAU,EAAE,SAAS,CAAC,CA4NxC"}
@@ -0,0 +1,573 @@
1
+ /**
2
+ * `sbox-sdk/memory` — an in-memory sandbox provider. It is the zero-config
3
+ * default for `createSandboxClient()` and the fixture the conformance suite runs
4
+ * against. With `{ bareFs: true }` it hides the native filesystem methods so the
5
+ * core's exec-based polyfills (ls/mkdir/rm/mv/stat) are exercised instead.
6
+ */
7
+ import { SandboxError } from "../adapter/index.js";
8
+ const MEMORY_CAPS = {
9
+ background: "native",
10
+ codeInterpreter: "unsupported",
11
+ egressControl: "unsupported",
12
+ exposePort: "emulated",
13
+ filesUpload: "native",
14
+ filesWatch: "unsupported",
15
+ fork: "native",
16
+ gpu: "unsupported",
17
+ killProcess: "native",
18
+ list: "native",
19
+ metrics: "unsupported",
20
+ pause: "native",
21
+ privatePreview: "unsupported",
22
+ proxiedFetch: "unsupported",
23
+ pty: "unsupported",
24
+ region: "unsupported",
25
+ secretsVault: "unsupported",
26
+ setTimeout: "native",
27
+ snapshot: "native",
28
+ ssh: "unsupported",
29
+ statefulKernel: "unsupported",
30
+ stdin: "unsupported",
31
+ stop: "native",
32
+ streaming: "native",
33
+ volumes: "unsupported",
34
+ };
35
+ const MEMORY_FLAGS = {
36
+ exitCodeNative: true,
37
+ perCommandEnvCwd: true,
38
+ preservesDiskOnStop: true,
39
+ preservesMemoryOnPause: true,
40
+ previewModel: "ip",
41
+ };
42
+ // --------------------------------------------------------------------------
43
+ // path helpers
44
+ // --------------------------------------------------------------------------
45
+ function normalizePath(p) {
46
+ const abs = p.startsWith("/") ? p : `/${p}`;
47
+ const parts = [];
48
+ for (const seg of abs.split("/")) {
49
+ if (seg === "" || seg === ".") {
50
+ continue;
51
+ }
52
+ if (seg === "..") {
53
+ parts.pop();
54
+ }
55
+ else {
56
+ parts.push(seg);
57
+ }
58
+ }
59
+ return `/${parts.join("/")}`;
60
+ }
61
+ function parentOf(p) {
62
+ const n = normalizePath(p);
63
+ const i = n.lastIndexOf("/");
64
+ return i <= 0 ? "/" : n.slice(0, i);
65
+ }
66
+ function baseName(p) {
67
+ const n = normalizePath(p);
68
+ return n.slice(n.lastIndexOf("/") + 1);
69
+ }
70
+ function resolvePath(cwd, p) {
71
+ return p.startsWith("/") ? normalizePath(p) : normalizePath(`${cwd}/${p}`);
72
+ }
73
+ function ancestors(dir) {
74
+ const out = [];
75
+ let cur = normalizePath(dir);
76
+ while (cur !== "/") {
77
+ out.unshift(cur);
78
+ cur = parentOf(cur);
79
+ }
80
+ return out;
81
+ }
82
+ // --------------------------------------------------------------------------
83
+ // pure fs ops shared by native methods + exec interpreter
84
+ // --------------------------------------------------------------------------
85
+ function fsWrite(sb, path, data) {
86
+ const p = normalizePath(path);
87
+ for (const a of ancestors(parentOf(p))) {
88
+ sb.dirs.add(a);
89
+ }
90
+ sb.files.set(p, data);
91
+ }
92
+ function fsRead(sb, path) {
93
+ return sb.files.get(normalizePath(path)) ?? null;
94
+ }
95
+ function fsList(sb, dir) {
96
+ const d = normalizePath(dir);
97
+ if (!sb.dirs.has(d)) {
98
+ return null;
99
+ }
100
+ const seen = new Map();
101
+ for (const sub of sb.dirs) {
102
+ if (sub !== d && parentOf(sub) === d) {
103
+ const name = baseName(sub);
104
+ seen.set(name, { name, path: sub, type: "dir" });
105
+ }
106
+ }
107
+ for (const f of sb.files.keys()) {
108
+ if (parentOf(f) === d) {
109
+ const name = baseName(f);
110
+ seen.set(name, { name, path: f, type: "file" });
111
+ }
112
+ }
113
+ return [...seen.values()].toSorted((a, b) => a.name.localeCompare(b.name));
114
+ }
115
+ function fsMkdir(sb, path, recursive) {
116
+ const p = normalizePath(path);
117
+ if (sb.dirs.has(p)) {
118
+ return recursive ? null : `mkdir: cannot create '${path}': File exists`;
119
+ }
120
+ if (sb.files.has(p)) {
121
+ return `mkdir: cannot create '${path}': File exists`;
122
+ }
123
+ if (!recursive && !sb.dirs.has(parentOf(p))) {
124
+ return `mkdir: cannot create '${path}': No such file or directory`;
125
+ }
126
+ for (const a of ancestors(p)) {
127
+ sb.dirs.add(a);
128
+ }
129
+ return null;
130
+ }
131
+ function fsRemove(sb, path, recursive, force) {
132
+ const p = normalizePath(path);
133
+ if (sb.files.has(p)) {
134
+ sb.files.delete(p);
135
+ return null;
136
+ }
137
+ if (sb.dirs.has(p)) {
138
+ if (!recursive) {
139
+ return `rm: cannot remove '${path}': Is a directory`;
140
+ }
141
+ sb.dirs.delete(p);
142
+ for (const d of [...sb.dirs]) {
143
+ if (d.startsWith(`${p}/`)) {
144
+ sb.dirs.delete(d);
145
+ }
146
+ }
147
+ for (const f of [...sb.files.keys()]) {
148
+ if (f.startsWith(`${p}/`)) {
149
+ sb.files.delete(f);
150
+ }
151
+ }
152
+ return null;
153
+ }
154
+ return force
155
+ ? null
156
+ : `rm: cannot remove '${path}': No such file or directory`;
157
+ }
158
+ function fsRename(sb, from, to) {
159
+ const a = normalizePath(from);
160
+ const b = normalizePath(to);
161
+ if (sb.files.has(a)) {
162
+ fsWrite(sb, b, sb.files.get(a));
163
+ sb.files.delete(a);
164
+ return null;
165
+ }
166
+ if (sb.dirs.has(a)) {
167
+ for (const a2 of ancestors(b)) {
168
+ sb.dirs.add(a2);
169
+ }
170
+ sb.dirs.add(b);
171
+ for (const f of [...sb.files.keys()]) {
172
+ if (f === a || f.startsWith(`${a}/`)) {
173
+ fsWrite(sb, b + f.slice(a.length), sb.files.get(f));
174
+ sb.files.delete(f);
175
+ }
176
+ }
177
+ sb.dirs.delete(a);
178
+ return null;
179
+ }
180
+ return `mv: cannot stat '${from}': No such file or directory`;
181
+ }
182
+ function fsStat(sb, path) {
183
+ const p = normalizePath(path);
184
+ if (sb.dirs.has(p)) {
185
+ return { path: p, size: 0, type: "dir" };
186
+ }
187
+ const f = sb.files.get(p);
188
+ if (f) {
189
+ return { path: p, size: f.length, type: "file" };
190
+ }
191
+ return null;
192
+ }
193
+ function tokenize(input) {
194
+ const tokens = [];
195
+ let cur = "";
196
+ let quote = null;
197
+ let has = false;
198
+ for (const ch of input) {
199
+ if (quote) {
200
+ if (ch === quote) {
201
+ quote = null;
202
+ }
203
+ else {
204
+ cur += ch;
205
+ }
206
+ has = true;
207
+ }
208
+ else if (ch === "'" || ch === '"') {
209
+ quote = ch;
210
+ has = true;
211
+ }
212
+ else if (ch === " " || ch === "\t") {
213
+ if (has) {
214
+ tokens.push(cur);
215
+ cur = "";
216
+ has = false;
217
+ }
218
+ }
219
+ else {
220
+ cur += ch;
221
+ has = true;
222
+ }
223
+ }
224
+ if (has) {
225
+ tokens.push(cur);
226
+ }
227
+ return tokens;
228
+ }
229
+ function expandVars(s, env) {
230
+ return s.replaceAll(/\$\{(\w+)\}|\$(\w+)/g, (_m, a, b) => env[a ?? b] ?? "");
231
+ }
232
+ function runMemCommand(sb, command, opts) {
233
+ const cwd = opts.cwd ?? "/";
234
+ const env = { ...sb.env, ...opts.env };
235
+ const argv = tokenize(expandVars(command, env));
236
+ const [cmd] = argv;
237
+ const ok = (stdout = "") => ({ exit: 0, stderr: "", stdout });
238
+ const operands = argv.slice(1).filter((a) => !a.startsWith("-"));
239
+ switch (cmd) {
240
+ case undefined: {
241
+ return ok();
242
+ }
243
+ case "true": {
244
+ return ok();
245
+ }
246
+ case "false": {
247
+ return { exit: 1, stderr: "", stdout: "" };
248
+ }
249
+ case "exit": {
250
+ return { exit: Number(argv[1] ?? 0) || 0, stderr: "", stdout: "" };
251
+ }
252
+ case "pwd": {
253
+ return ok(`${cwd}\n`);
254
+ }
255
+ case "echo": {
256
+ let args = argv.slice(1);
257
+ let nl = true;
258
+ if (args[0] === "-n") {
259
+ nl = false;
260
+ args = args.slice(1);
261
+ }
262
+ return ok(args.join(" ") + (nl ? "\n" : ""));
263
+ }
264
+ case "printf": {
265
+ return ok((operands[0] ?? "").replaceAll(/\\n/g, "\n").replaceAll(/\\t/g, "\t"));
266
+ }
267
+ case "env": {
268
+ return ok(`${Object.entries(env)
269
+ .map(([k, v]) => `${k}=${v}`)
270
+ .join("\n")}\n`);
271
+ }
272
+ case "cat": {
273
+ let out = "";
274
+ for (const f of operands) {
275
+ const data = fsRead(sb, resolvePath(cwd, f));
276
+ if (!data) {
277
+ return {
278
+ exit: 1,
279
+ stderr: `cat: ${f}: No such file or directory\n`,
280
+ stdout: "",
281
+ };
282
+ }
283
+ out += new TextDecoder().decode(data);
284
+ }
285
+ return ok(out);
286
+ }
287
+ case "touch": {
288
+ for (const f of operands) {
289
+ fsWrite(sb, resolvePath(cwd, f), new Uint8Array());
290
+ }
291
+ return ok();
292
+ }
293
+ case "ls": {
294
+ const entries = fsList(sb, resolvePath(cwd, operands[0] ?? "."));
295
+ if (!entries) {
296
+ return {
297
+ exit: 2,
298
+ stderr: `ls: cannot access '${operands[0] ?? "."}': No such file or directory\n`,
299
+ stdout: "",
300
+ };
301
+ }
302
+ const names = entries.map((e) => e.type === "dir" ? `${e.name}/` : e.name);
303
+ return ok(names.length ? `${names.join("\n")}\n` : "");
304
+ }
305
+ case "mkdir": {
306
+ const recursive = argv.includes("-p");
307
+ const err = fsMkdir(sb, resolvePath(cwd, operands[0] ?? ""), recursive);
308
+ return err ? { exit: 1, stderr: `${err}\n`, stdout: "" } : ok();
309
+ }
310
+ case "rm": {
311
+ const flags = argv.filter((a) => a.startsWith("-")).join("");
312
+ const recursive = flags.includes("r") || flags.includes("R");
313
+ const force = flags.includes("f");
314
+ for (const f of operands) {
315
+ const err = fsRemove(sb, resolvePath(cwd, f), recursive, force);
316
+ if (err) {
317
+ return { exit: 1, stderr: `${err}\n`, stdout: "" };
318
+ }
319
+ }
320
+ return ok();
321
+ }
322
+ case "mv": {
323
+ if (operands.length < 2) {
324
+ return { exit: 1, stderr: "mv: missing operand\n", stdout: "" };
325
+ }
326
+ const err = fsRename(sb, resolvePath(cwd, operands[0]), resolvePath(cwd, operands[1]));
327
+ return err ? { exit: 1, stderr: `${err}\n`, stdout: "" } : ok();
328
+ }
329
+ case "stat": {
330
+ const target = argv.at(-1) ?? "";
331
+ const info = fsStat(sb, resolvePath(cwd, target));
332
+ if (!info) {
333
+ return {
334
+ exit: 1,
335
+ stderr: `stat: cannot statx '${target}': No such file or directory\n`,
336
+ stdout: "",
337
+ };
338
+ }
339
+ const kind = info.type === "dir" ? "directory" : "regular file";
340
+ return ok(`${kind}|${info.size}|0\n`);
341
+ }
342
+ default: {
343
+ return { exit: 127, stderr: `sh: ${cmd}: not found\n`, stdout: "" };
344
+ }
345
+ }
346
+ }
347
+ function toDriverExec(pid, r) {
348
+ return {
349
+ pid: Promise.resolve(pid),
350
+ async kill() {
351
+ /* nothing to kill in memory */
352
+ },
353
+ async *[Symbol.asyncIterator]() {
354
+ if (r.stdout) {
355
+ yield { data: r.stdout, type: "stdout" };
356
+ }
357
+ if (r.stderr) {
358
+ yield { data: r.stderr, type: "stderr" };
359
+ }
360
+ yield { exitCode: r.exit, type: "exit" };
361
+ },
362
+ };
363
+ }
364
+ // --------------------------------------------------------------------------
365
+ // provider
366
+ // --------------------------------------------------------------------------
367
+ export function memory(opts = {}) {
368
+ {
369
+ const o = opts;
370
+ const bareFs = o.bareFs ?? false;
371
+ const sandboxes = new Map();
372
+ let counter = 0;
373
+ const spawnSandbox = (spec) => {
374
+ const id = `${o.idPrefix ?? "mem"}_${++counter}`;
375
+ const sb = {
376
+ createdAt: new Date(),
377
+ dirs: new Set(["/", "/tmp", "/home", "/app"]),
378
+ env: { ...spec.env },
379
+ files: new Map(),
380
+ id,
381
+ metadata: { ...spec.metadata },
382
+ ports: new Map(),
383
+ procCounter: 0,
384
+ processes: new Map(),
385
+ snapCounter: 0,
386
+ snapshots: new Map(),
387
+ state: "running",
388
+ };
389
+ sandboxes.set(id, sb);
390
+ return sb;
391
+ };
392
+ const info = (sb) => ({
393
+ createdAt: sb.createdAt,
394
+ id: sb.id,
395
+ metadata: sb.metadata,
396
+ provider: "memory",
397
+ raw: sb,
398
+ state: sb.state,
399
+ });
400
+ const makeHandle = (sb) => {
401
+ const required = {
402
+ connectProcess: (processId) => ({
403
+ ...toDriverExec(processId, { exit: 0, stderr: "", stdout: "" }),
404
+ id: processId,
405
+ }),
406
+ deleteSnapshot: (ref) => {
407
+ sb.snapshots.delete(ref);
408
+ },
409
+ destroy: () => {
410
+ sb.state = "destroyed";
411
+ sandboxes.delete(sb.id);
412
+ },
413
+ exec: (cmd, execOpts) => toDriverExec(`p${++sb.procCounter}`, runMemCommand(sb, cmd, execOpts)),
414
+ exposePort: (port) => {
415
+ const preview = { port, url: `http://127.0.0.1:${port}` };
416
+ sb.ports.set(port, preview);
417
+ return preview;
418
+ },
419
+ fork: (count) => {
420
+ const out = [];
421
+ for (let i = 0; i < count; i++) {
422
+ const clone = spawnSandbox({ env: sb.env, metadata: sb.metadata });
423
+ clone.files = new Map(sb.files);
424
+ clone.dirs = new Set(sb.dirs);
425
+ out.push(makeHandle(clone));
426
+ }
427
+ return out;
428
+ },
429
+ getInfo: () => info(sb),
430
+ id: sb.id,
431
+ killProcess: (processId) => {
432
+ sb.processes.delete(processId);
433
+ },
434
+ listPorts: () => [...sb.ports.values()],
435
+ listProcesses: () => [...sb.processes.entries()].map(([id, p]) => ({ cmd: p.cmd, id })),
436
+ listSnapshots: () => [...sb.snapshots.keys()].map((id) => ({
437
+ id,
438
+ provider: "memory",
439
+ raw: sb,
440
+ })),
441
+ pause: () => {
442
+ sb.state = "paused";
443
+ },
444
+ raw: sb,
445
+ readFile: (path) => {
446
+ const data = fsRead(sb, path);
447
+ if (!data) {
448
+ throw new SandboxError("NotFound", `no such file: '${path}'`, {
449
+ provider: "memory",
450
+ });
451
+ }
452
+ return data;
453
+ },
454
+ restoreSnapshot: (ref) => {
455
+ const snap = sb.snapshots.get(ref);
456
+ if (!snap) {
457
+ throw new SandboxError("NotFound", `no snapshot ${ref}`, {
458
+ provider: "memory",
459
+ });
460
+ }
461
+ sb.files = new Map(snap.files);
462
+ sb.dirs = new Set(snap.dirs);
463
+ },
464
+ resume: () => {
465
+ sb.state = "running";
466
+ },
467
+ setTimeout: () => {
468
+ /* memory sandboxes never expire */
469
+ },
470
+ snapshot: ({ name }) => {
471
+ const id = `snap_${++sb.snapCounter}`;
472
+ sb.snapshots.set(id, {
473
+ dirs: new Set(sb.dirs),
474
+ files: new Map(sb.files),
475
+ });
476
+ return {
477
+ createdAt: new Date(),
478
+ id,
479
+ name,
480
+ provider: "memory",
481
+ raw: sb,
482
+ };
483
+ },
484
+ spawn: (cmd, execOpts) => {
485
+ const id = `p${++sb.procCounter}`;
486
+ sb.processes.set(id, { cmd });
487
+ return { ...toDriverExec(id, runMemCommand(sb, cmd, execOpts)), id };
488
+ },
489
+ stop: () => {
490
+ sb.state = "stopped";
491
+ },
492
+ unexposePort: (port) => {
493
+ sb.ports.delete(port);
494
+ },
495
+ writeFile: (path, data) => fsWrite(sb, path, data),
496
+ };
497
+ if (bareFs) {
498
+ return required;
499
+ }
500
+ return {
501
+ ...required,
502
+ listDir: (path) => {
503
+ const entries = fsList(sb, path);
504
+ if (!entries) {
505
+ throw new SandboxError("NotFound", `not a directory: '${path}'`, {
506
+ provider: "memory",
507
+ });
508
+ }
509
+ return entries;
510
+ },
511
+ mkdir: (path, recursive) => {
512
+ const err = fsMkdir(sb, path, recursive);
513
+ if (err) {
514
+ throw new SandboxError("Provider", err, { provider: "memory" });
515
+ }
516
+ },
517
+ remove: (path, recursive) => {
518
+ const err = fsRemove(sb, path, recursive, true);
519
+ if (err) {
520
+ throw new SandboxError("Provider", err, { provider: "memory" });
521
+ }
522
+ },
523
+ rename: (from, to) => {
524
+ const err = fsRename(sb, from, to);
525
+ if (err) {
526
+ throw new SandboxError("NotFound", err, { provider: "memory" });
527
+ }
528
+ },
529
+ stat: (path) => {
530
+ const i = fsStat(sb, path);
531
+ if (!i) {
532
+ throw new SandboxError("NotFound", `not found: '${path}'`, {
533
+ provider: "memory",
534
+ });
535
+ }
536
+ return i;
537
+ },
538
+ upload: (path, data) => {
539
+ if (typeof data === "string") {
540
+ fsWrite(sb, path, new TextEncoder().encode(data));
541
+ }
542
+ else if (data instanceof Uint8Array) {
543
+ fsWrite(sb, path, data);
544
+ }
545
+ else {
546
+ throw new SandboxError("Validation", "stream upload unsupported in memory");
547
+ }
548
+ },
549
+ };
550
+ };
551
+ const provider = {
552
+ capabilities: MEMORY_CAPS,
553
+ connect: (id) => {
554
+ const sb = sandboxes.get(id);
555
+ if (!sb) {
556
+ throw new SandboxError("NotFound", `no sandbox ${id}`, {
557
+ provider: "memory",
558
+ });
559
+ }
560
+ return makeHandle(sb);
561
+ },
562
+ create: (spec) => makeHandle(spawnSandbox(spec)),
563
+ flags: MEMORY_FLAGS,
564
+ async *list() {
565
+ for (const sb of sandboxes.values()) {
566
+ yield info(sb);
567
+ }
568
+ },
569
+ name: "memory",
570
+ };
571
+ return provider;
572
+ }
573
+ }
@@ -0,0 +1,67 @@
1
+ import type { Sandbox as ModalSandbox } from "modal";
2
+ import type { SandboxProvider } from "../adapter/index.js";
3
+ export interface ModalOptions {
4
+ tokenId?: string;
5
+ tokenSecret?: string;
6
+ environment?: string;
7
+ /** Modal App name to attach sandboxes to (created if missing). */
8
+ appName?: string;
9
+ /** Default container image when a sandbox spec doesn't set `template`. */
10
+ image?: string;
11
+ }
12
+ export declare const MODAL_CAPS: {
13
+ readonly background: "unsupported";
14
+ readonly codeInterpreter: "unsupported";
15
+ readonly egressControl: "unsupported";
16
+ readonly exposePort: "native";
17
+ readonly filesUpload: "native";
18
+ readonly filesWatch: "unsupported";
19
+ readonly fork: "unsupported";
20
+ readonly gpu: "native";
21
+ readonly killProcess: "unsupported";
22
+ readonly list: "native";
23
+ readonly metrics: "unsupported";
24
+ readonly pause: "unsupported";
25
+ readonly privatePreview: "unsupported";
26
+ readonly proxiedFetch: "unsupported";
27
+ readonly pty: "unsupported";
28
+ readonly region: "unsupported";
29
+ readonly secretsVault: "unsupported";
30
+ readonly setTimeout: "unsupported";
31
+ readonly snapshot: "unsupported";
32
+ readonly ssh: "unsupported";
33
+ readonly statefulKernel: "unsupported";
34
+ readonly stdin: "unsupported";
35
+ readonly stop: "unsupported";
36
+ readonly streaming: "native";
37
+ readonly volumes: "unsupported";
38
+ };
39
+ export type ModalCaps = typeof MODAL_CAPS;
40
+ export declare const modal: (opts: ModalOptions) => SandboxProvider<{
41
+ readonly background: "unsupported";
42
+ readonly codeInterpreter: "unsupported";
43
+ readonly egressControl: "unsupported";
44
+ readonly exposePort: "native";
45
+ readonly filesUpload: "native";
46
+ readonly filesWatch: "unsupported";
47
+ readonly fork: "unsupported";
48
+ readonly gpu: "native";
49
+ readonly killProcess: "unsupported";
50
+ readonly list: "native";
51
+ readonly metrics: "unsupported";
52
+ readonly pause: "unsupported";
53
+ readonly privatePreview: "unsupported";
54
+ readonly proxiedFetch: "unsupported";
55
+ readonly pty: "unsupported";
56
+ readonly region: "unsupported";
57
+ readonly secretsVault: "unsupported";
58
+ readonly setTimeout: "unsupported";
59
+ readonly snapshot: "unsupported";
60
+ readonly ssh: "unsupported";
61
+ readonly statefulKernel: "unsupported";
62
+ readonly stdin: "unsupported";
63
+ readonly stop: "unsupported";
64
+ readonly streaming: "native";
65
+ readonly volumes: "unsupported";
66
+ }, ModalSandbox>;
67
+ //# sourceMappingURL=index.d.ts.map