withruntime 0.8.3 → 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 (92) hide show
  1. package/COMPATIBILITY.md +145 -0
  2. package/E2B.md +23 -13
  3. package/README.md +8 -5
  4. package/README.src.md +8 -5
  5. package/compatibility-lock.json +281 -0
  6. package/dist/ai-harness/index.js +2 -2
  7. package/dist/api-defaults.d.ts +17 -0
  8. package/dist/api-defaults.js +22 -0
  9. package/dist/blaxel/preview.d.ts +1 -1
  10. package/dist/blaxel/preview.js +1 -1
  11. package/dist/blaxel/process.d.ts +1 -1
  12. package/dist/blaxel/process.js +11 -2
  13. package/dist/cli-words.d.ts +27 -0
  14. package/dist/cli-words.js +135 -0
  15. package/dist/cli.js +162 -31
  16. package/dist/client.d.ts +4 -1
  17. package/dist/client.js +8 -2
  18. package/dist/cloudflare/index.d.ts +294 -0
  19. package/dist/cloudflare/index.js +554 -0
  20. package/dist/cloudflare/worker.d.ts +415 -0
  21. package/dist/cloudflare/worker.js +297 -0
  22. package/dist/codesandbox/guest-service.d.ts +31 -0
  23. package/dist/codesandbox/guest-service.js +453 -0
  24. package/dist/codesandbox/index.d.ts +386 -0
  25. package/dist/codesandbox/index.js +1313 -0
  26. package/dist/compat/core.d.ts +39 -0
  27. package/dist/compat/core.js +199 -0
  28. package/dist/compat/files.d.ts +26 -0
  29. package/dist/compat/files.js +115 -0
  30. package/dist/compat/shell.d.ts +4 -0
  31. package/dist/compat/shell.js +165 -0
  32. package/dist/daytona/context.js +2 -1
  33. package/dist/daytona/process.d.ts +1 -1
  34. package/dist/daytona/process.js +27 -4
  35. package/dist/e2b/code-interpreter.d.ts +4 -5
  36. package/dist/e2b/code-interpreter.js +54 -56
  37. package/dist/e2b/commands.d.ts +5 -4
  38. package/dist/e2b/commands.js +37 -29
  39. package/dist/e2b/errors.js +1 -1
  40. package/dist/e2b/filesystem.d.ts +8 -6
  41. package/dist/e2b/filesystem.js +127 -28
  42. package/dist/e2b/sandbox.d.ts +4 -3
  43. package/dist/e2b/sandbox.js +10 -10
  44. package/dist/errors.d.ts +8 -0
  45. package/dist/errors.js +15 -2
  46. package/dist/freestyle/index.d.ts +301 -0
  47. package/dist/freestyle/index.js +310 -0
  48. package/dist/index.d.ts +1 -0
  49. package/dist/mcp.js +2 -2
  50. package/dist/modal/index.d.ts +205 -0
  51. package/dist/modal/index.js +485 -0
  52. package/dist/network-cli.js +1 -1
  53. package/dist/openai-agents/index.js +9 -26
  54. package/dist/products/audit.d.ts +3 -0
  55. package/dist/products/index.d.ts +2 -0
  56. package/dist/products/index.js +2 -0
  57. package/dist/products/interpreter.d.ts +11 -4
  58. package/dist/products/interpreter.js +33 -9
  59. package/dist/products/jobs.d.ts +1 -1
  60. package/dist/products/jobs.js +5 -4
  61. package/dist/products/limits.d.ts +10 -0
  62. package/dist/products/previews.d.ts +10 -2
  63. package/dist/products/previews.js +3 -2
  64. package/dist/products/tailscale.d.ts +57 -0
  65. package/dist/products/tailscale.js +17 -0
  66. package/dist/products/watch.d.ts +25 -4
  67. package/dist/products/watch.js +75 -14
  68. package/dist/runloop/index.d.ts +340 -0
  69. package/dist/runloop/index.js +438 -0
  70. package/dist/runloop/pagination.d.ts +46 -0
  71. package/dist/runloop/pagination.js +82 -0
  72. package/dist/runloop/snapshots.d.ts +52 -0
  73. package/dist/runloop/snapshots.js +244 -0
  74. package/dist/sandbox.d.ts +40 -9
  75. package/dist/sandbox.js +273 -76
  76. package/dist/snapshots.d.ts +11 -1
  77. package/dist/snapshots.js +11 -1
  78. package/dist/sprites/index.d.ts +251 -0
  79. package/dist/sprites/index.js +552 -0
  80. package/dist/tar.d.ts +8 -1
  81. package/dist/tar.js +185 -35
  82. package/dist/tools/index.js +2 -1
  83. package/dist/transport.d.ts +20 -2
  84. package/dist/transport.js +48 -11
  85. package/dist/types.d.ts +52 -3
  86. package/dist/vercel/command.js +12 -1
  87. package/dist/vercel/errors.d.ts +2 -2
  88. package/dist/vercel/errors.js +12 -1
  89. package/dist/vercel/filesystem.d.ts +21 -18
  90. package/dist/vercel/filesystem.js +95 -48
  91. package/dist/vercel/sandbox.js +5 -5
  92. package/package.json +45 -3
@@ -0,0 +1,297 @@
1
+ /** Workers conditional entry. The Durable Object coordinates requests and stores
2
+ * configuration; Runtime owns compute. Existing Container/Wrangler declarations
3
+ * still need removal during infrastructure migration. */
4
+ import { DurableObject } from "cloudflare:workers";
5
+ import { only, CompatibilityError } from "../compat/core.js";
6
+ import { Runtime } from "../client.js";
7
+ import { Sandbox as RuntimeSandbox, sanitizeSandboxId, } from "./index.js";
8
+ export * from "./index.js";
9
+ /** The official Worker SDK returns plain records with callable RPC properties,
10
+ * so ids/status are values rather than remote-property promises. */
11
+ function sessionTarget(session) {
12
+ function readFile(path, options) {
13
+ return options?.encoding === "none"
14
+ ? session.readFile(path, { encoding: "none" })
15
+ : session.readFile(path, options);
16
+ }
17
+ return {
18
+ id: session.id,
19
+ exec: (command, options) => session.exec(command, options),
20
+ execStream: (command, options) => session.execStream(command, options),
21
+ startProcess: async (command, options) => processTarget(await session.startProcess(command, options)),
22
+ writeFile: (...args) => session.writeFile(...args),
23
+ readFile,
24
+ mkdir: (...args) => session.mkdir(...args),
25
+ deleteFile: (path) => session.deleteFile(path),
26
+ renameFile: (path, to) => session.renameFile(path, to),
27
+ moveFile: (path, to) => session.renameFile(path, to),
28
+ exists: (path) => session.exists(path),
29
+ listFiles: (...args) => session.listFiles(...args),
30
+ setEnvVars: (...args) => session.setEnvVars(...args),
31
+ };
32
+ }
33
+ function processTarget(process) {
34
+ return {
35
+ id: process.id,
36
+ command: process.command,
37
+ status: process.status,
38
+ startTime: process.startTime,
39
+ endTime: process.endTime,
40
+ exitCode: process.exitCode,
41
+ sessionId: process.sessionId,
42
+ kill: (signal) => process.kill(signal),
43
+ getStatus: () => process.getStatus(),
44
+ getLogs: () => process.getLogs(),
45
+ waitForExit: (timeout) => process.waitForExit(timeout),
46
+ waitForLog: (pattern, timeout) => process.waitForLog(pattern, timeout),
47
+ };
48
+ }
49
+ export class Sandbox extends DurableObject {
50
+ configuration = {};
51
+ facade;
52
+ previewTail = Promise.resolve();
53
+ previewOperation(operation) {
54
+ const result = this.previewTail.catch(() => undefined).then(operation);
55
+ this.previewTail = result;
56
+ return result;
57
+ }
58
+ initialized;
59
+ constructor(ctx, env) {
60
+ super(ctx, env);
61
+ this.initialized = ctx.blockConcurrencyWhile(async () => {
62
+ this.configuration = (await ctx.storage.get("runtime.configuration")) ?? {};
63
+ });
64
+ }
65
+ async sandbox() {
66
+ await this.initialized;
67
+ if (!this.configuration.sandboxName)
68
+ throw new Error("Call getSandbox(namespace, id) before using the Durable Object");
69
+ if (!this.env.RUNTIME_API_KEY?.startsWith("rtcloud_"))
70
+ throw new Error("Set the RUNTIME_API_KEY Worker secret to a Runtime API key");
71
+ this.facade ??= new RuntimeSandbox(new Runtime({ apiKey: this.env.RUNTIME_API_KEY, baseUrl: this.env.RUNTIME_API_URL }), this.configuration.sandboxName.name, this.configuration);
72
+ return this.facade;
73
+ }
74
+ async configure(configuration) {
75
+ only("Cloudflare Worker configure", configuration, ["sandboxName", "sleepAfter", "keepAlive"]);
76
+ await this.initialized;
77
+ if (this.configuration.sandboxName &&
78
+ configuration.sandboxName &&
79
+ this.configuration.sandboxName.name !== configuration.sandboxName.name)
80
+ throw new Error("A Durable Object cannot change sandbox identity");
81
+ this.configuration = { ...this.configuration, ...configuration };
82
+ await this.ctx.storage.put("runtime.configuration", this.configuration);
83
+ if (this.facade)
84
+ await this.facade.configure(configuration);
85
+ }
86
+ setSandboxName(name, normalizeId = false) {
87
+ return this.configure({
88
+ sandboxName: { name: normalizeId ? name.toLowerCase() : name, normalizeId },
89
+ });
90
+ }
91
+ setSleepAfter(sleepAfter) {
92
+ return this.configure({ sleepAfter });
93
+ }
94
+ setKeepAlive(keepAlive) {
95
+ return this.configure({ keepAlive });
96
+ }
97
+ async exec(command, options) {
98
+ return (await this.sandbox()).exec(command, options);
99
+ }
100
+ async execStream(command, options) {
101
+ return (await this.sandbox()).execStream(command, options);
102
+ }
103
+ async startProcess(command, options) {
104
+ return processTarget(await (await this.sandbox()).startProcess(command, options));
105
+ }
106
+ async listProcesses() {
107
+ return (await (await this.sandbox()).listProcesses()).map((p) => processTarget(p));
108
+ }
109
+ async getProcess(id) {
110
+ const p = await (await this.sandbox()).getProcess(id);
111
+ return p ? processTarget(p) : null;
112
+ }
113
+ async getProcessLogs(id) {
114
+ return (await this.sandbox()).getProcessLogs(id);
115
+ }
116
+ async killProcess(id, signal) {
117
+ return (await this.sandbox()).killProcess(id, signal);
118
+ }
119
+ async killAllProcesses() {
120
+ return (await this.sandbox()).killAllProcesses();
121
+ }
122
+ async createSession(options) {
123
+ return sessionTarget(await (await this.sandbox()).createSession(options));
124
+ }
125
+ async getSession(id) {
126
+ return sessionTarget(await (await this.sandbox()).getSession(id));
127
+ }
128
+ async deleteSession(id) {
129
+ return (await this.sandbox()).deleteSession(id);
130
+ }
131
+ async writeFile(...args) {
132
+ return (await this.sandbox()).writeFile(...args);
133
+ }
134
+ async readFile(path, options) {
135
+ const s = await this.sandbox();
136
+ return options?.encoding === "none"
137
+ ? s.readFile(path, { encoding: "none" })
138
+ : s.readFile(path, options);
139
+ }
140
+ async mkdir(...args) {
141
+ return (await this.sandbox()).mkdir(...args);
142
+ }
143
+ async deleteFile(path) {
144
+ return (await this.sandbox()).deleteFile(path);
145
+ }
146
+ async renameFile(path, to) {
147
+ return (await this.sandbox()).renameFile(path, to);
148
+ }
149
+ async moveFile(path, to) {
150
+ return (await this.sandbox()).moveFile(path, to);
151
+ }
152
+ async listFiles(...args) {
153
+ return (await this.sandbox()).listFiles(...args);
154
+ }
155
+ async exists(path) {
156
+ return (await this.sandbox()).exists(path);
157
+ }
158
+ async setEnvVars(...args) {
159
+ return (await this.sandbox()).setEnvVars(...args);
160
+ }
161
+ exposePort(port, options) {
162
+ return this.previewOperation(() => this.expose(port, options));
163
+ }
164
+ async expose(port, options) {
165
+ only("Cloudflare Worker exposePort", options, ["name", "hostname", "token"]);
166
+ if (!Number.isInteger(port) || port < 1024 || port > 65535 || port === 3000)
167
+ throw new TypeError("Preview port must be 1024-65535, excluding 3000");
168
+ if (!/^[a-z0-9.-]+$/i.test(options.hostname) ||
169
+ options.hostname.startsWith(".") ||
170
+ options.hostname.endsWith("."))
171
+ throw new TypeError("Preview hostname must be a DNS hostname");
172
+ if (options.hostname.endsWith(".workers.dev"))
173
+ throw new Error("Port exposure requires a custom domain; .workers.dev does not support wildcard preview subdomains");
174
+ const existing = await this.ctx.storage.get(`runtime.preview.${port}`);
175
+ const token = options.token ?? existing?.token ?? crypto.randomUUID().replaceAll("-", "");
176
+ const ports = await this.ctx.storage.list({
177
+ prefix: "runtime.preview.",
178
+ });
179
+ if ([...ports.values()].some((p) => p.port !== port && p.token === token))
180
+ throw new Error(`Token '${token}' is already in use by another port`);
181
+ if (!/^[a-z0-9_]{1,63}$/.test(token))
182
+ throw new TypeError("Preview token must contain 1-63 lowercase letters, digits or underscores");
183
+ const sandbox = await this.sandbox();
184
+ const name = this.configuration.sandboxName.name;
185
+ if (name !== name.toLowerCase())
186
+ throw new CompatibilityError("Cloudflare", "uppercase sandbox IDs in preview hostnames; use normalizeId:true");
187
+ const native = await (await sandbox.native()).previews.create(port, { visibility: "private" });
188
+ const url = `https://${port}-${name}-${token}.${options.hostname}`;
189
+ await this.ctx.storage.put(`runtime.preview.${port}`, {
190
+ token,
191
+ url,
192
+ target: native.url,
193
+ authToken: native.token,
194
+ authExpiresAt: native.tokenExpiresAt,
195
+ port,
196
+ name: options.name,
197
+ });
198
+ return { url, port, name: options.name };
199
+ }
200
+ unexposePort(port) {
201
+ return this.previewOperation(async () => {
202
+ await (await this.sandbox()).unexposePort(port);
203
+ await this.ctx.storage.delete(`runtime.preview.${port}`);
204
+ });
205
+ }
206
+ async isPortExposed(port) {
207
+ return !!(await this.ctx.storage.get(`runtime.preview.${port}`));
208
+ }
209
+ async validatePortToken(port, token) {
210
+ const record = await this.ctx.storage.get(`runtime.preview.${port}`);
211
+ return record?.token === token;
212
+ }
213
+ async getExposedPorts(hostname) {
214
+ return [
215
+ ...(await this.ctx.storage.list({
216
+ prefix: "runtime.preview.",
217
+ })).values(),
218
+ ].map((p) => ({
219
+ url: `https://${p.port}-${this.configuration.sandboxName.name}-${p.token}.${hostname}`,
220
+ port: p.port,
221
+ status: "active",
222
+ }));
223
+ }
224
+ async fetch(request) {
225
+ return this.forwardPreview(request);
226
+ }
227
+ async forwardPreview(request) {
228
+ await this.initialized;
229
+ const route = previewRoute(new URL(request.url));
230
+ if (!route || route.id !== this.configuration.sandboxName?.name)
231
+ return new Response("Not found", { status: 404 });
232
+ const record = await this.ctx.storage.get(`runtime.preview.${route.port}`);
233
+ if (!record || record.token !== route.token)
234
+ return new Response("Not found", { status: 404 });
235
+ if (!record.authExpiresAt || Date.parse(record.authExpiresAt) <= Date.now() + 60000) {
236
+ const preview = await (await (await this.sandbox()).native()).previews.get(route.port);
237
+ record.target = preview.url;
238
+ record.authToken = preview.token;
239
+ record.authExpiresAt = preview.tokenExpiresAt;
240
+ await this.ctx.storage.put(`runtime.preview.${route.port}`, record);
241
+ }
242
+ if (!record.authToken)
243
+ throw new Error("Private preview did not return an authorization token");
244
+ const incoming = new URL(request.url), target = new URL(record.target);
245
+ target.pathname = incoming.pathname;
246
+ const authorization = [...target.searchParams];
247
+ target.search = incoming.search;
248
+ for (const [key, value] of authorization)
249
+ target.searchParams.set(key, value);
250
+ const headers = new Headers(request.headers);
251
+ headers.set("x-runtime-preview-token", record.authToken);
252
+ headers.delete("host");
253
+ return fetch(new Request(new Request(target, request), { headers, redirect: "manual" }));
254
+ }
255
+ async destroy() {
256
+ await (await this.sandbox()).destroy();
257
+ this.facade = undefined;
258
+ const ports = await this.ctx.storage.list({ prefix: "runtime.preview." });
259
+ await this.ctx.storage.delete([...ports.keys()]);
260
+ }
261
+ }
262
+ export function getSandbox(namespace, id, options = {}) {
263
+ only("Cloudflare Worker getSandbox", options, ["normalizeId", "sleepAfter", "keepAlive"]);
264
+ sanitizeSandboxId(id);
265
+ const name = options.normalizeId ? id.toLowerCase() : id;
266
+ const stub = namespace.get(namespace.idFromName(name));
267
+ const configured = stub.configure({
268
+ sandboxName: { name, normalizeId: options.normalizeId },
269
+ ...(options.sleepAfter !== undefined ? { sleepAfter: options.sleepAfter } : {}),
270
+ ...(options.keepAlive !== undefined ? { keepAlive: options.keepAlive } : {}),
271
+ });
272
+ // Await configuration for every operation so no request can race name setup.
273
+ return new Proxy(stub, {
274
+ get(target, key) {
275
+ const value = Reflect.get(target, key);
276
+ if (typeof value !== "function" || key === "then")
277
+ return value;
278
+ return (...args) => Promise.resolve(configured).then(() => Reflect.apply(value, target, args));
279
+ },
280
+ });
281
+ }
282
+ function previewRoute(url) {
283
+ const label = url.hostname.split(".")[0] ?? "";
284
+ const match = /^(\d{4,5})-([a-z0-9_-]+)-([a-z0-9_]{1,63})$/.exec(label);
285
+ if (!match)
286
+ return null;
287
+ const port = Number(match[1]);
288
+ if (port < 1024 || port > 65535 || port === 3000)
289
+ return null;
290
+ return { port, id: match[2], token: match[3] };
291
+ }
292
+ export async function proxyToSandbox(request, env) {
293
+ const route = previewRoute(new URL(request.url));
294
+ if (!route)
295
+ return null;
296
+ return getSandbox(env.Sandbox, route.id, { normalizeId: true }).fetch(request);
297
+ }
@@ -0,0 +1,31 @@
1
+ import type { Sandbox, Process } from "../sandbox.js";
2
+ export declare const taskServiceSource: string;
3
+ export declare class ManagedTasks {
4
+ private readonly native;
5
+ constructor(native: Sandbox);
6
+ install(tasks: Record<string, {
7
+ command: string;
8
+ runAtStart?: boolean;
9
+ }>, env: Record<string, string>, setup: {
10
+ steps: {
11
+ name: string;
12
+ command: string;
13
+ }[];
14
+ source: string;
15
+ }): Promise<void>;
16
+ call<T>(request: Record<string, unknown>, signal?: AbortSignal): Promise<T>;
17
+ get(taskId: string): Promise<Process | undefined>;
18
+ boot(signal?: AbortSignal): Promise<{
19
+ state: "starting" | "ready" | "failed";
20
+ config?: string;
21
+ error?: string;
22
+ } | undefined>;
23
+ start(taskId: string): Promise<Process>;
24
+ stop(taskId: string): Promise<Process | undefined>;
25
+ list(signal?: AbortSignal): Promise<{
26
+ taskId: string;
27
+ process: Process;
28
+ }[]>;
29
+ output(id: string): Promise<string>;
30
+ private process;
31
+ }