@claxedo/sandbox-manager 0.5.1

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 (44) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +78 -0
  3. package/dist/command.d.ts +3 -0
  4. package/dist/command.mjs +18 -0
  5. package/dist/constants.d.ts +1 -0
  6. package/dist/constants.mjs +7 -0
  7. package/dist/daytona-allow-list.d.ts +5 -0
  8. package/dist/daytona-allow-list.mjs +9 -0
  9. package/dist/defaults.d.ts +3 -0
  10. package/dist/defaults.mjs +14 -0
  11. package/dist/driver-catalog.d.ts +62 -0
  12. package/dist/driver-catalog.mjs +206 -0
  13. package/dist/drivers/cloudflare-egress.d.ts +40 -0
  14. package/dist/drivers/cloudflare-egress.mjs +115 -0
  15. package/dist/drivers/cloudflare.d.ts +37 -0
  16. package/dist/drivers/cloudflare.mjs +151 -0
  17. package/dist/drivers/daytona.d.ts +94 -0
  18. package/dist/drivers/daytona.mjs +235 -0
  19. package/dist/drivers/docker.d.ts +36 -0
  20. package/dist/drivers/docker.mjs +329 -0
  21. package/dist/drivers/fetch-bridge.d.ts +10 -0
  22. package/dist/drivers/fetch-bridge.mjs +104 -0
  23. package/dist/drivers/modal.d.ts +68 -0
  24. package/dist/drivers/modal.mjs +227 -0
  25. package/dist/drivers/vercel.d.ts +109 -0
  26. package/dist/drivers/vercel.mjs +297 -0
  27. package/dist/image-name.d.ts +7 -0
  28. package/dist/image.d.ts +8 -0
  29. package/dist/image.mjs +124 -0
  30. package/dist/index.d.ts +316 -0
  31. package/dist/index.mjs +330 -0
  32. package/dist/lease-policy.d.ts +49 -0
  33. package/dist/lease-policy.mjs +126 -0
  34. package/dist/lease-types.d.ts +89 -0
  35. package/dist/lease-types.mjs +1 -0
  36. package/dist/runtime-env.d.ts +24 -0
  37. package/dist/runtime-env.mjs +35 -0
  38. package/dist/runtime-version.d.ts +1 -0
  39. package/dist/runtime-version.mjs +24 -0
  40. package/dist/service-url-exposure.d.ts +10 -0
  41. package/dist/service-url-exposure.mjs +46 -0
  42. package/dist/stores/memory.d.ts +6 -0
  43. package/dist/stores/memory.mjs +117 -0
  44. package/package.json +178 -0
@@ -0,0 +1,329 @@
1
+ import { createRequire as __createRequire } from 'module';var require = __createRequire(import.meta.url);
2
+
3
+ // src/drivers/docker.ts
4
+ import { execFile } from "node:child_process";
5
+ import fs from "node:fs/promises";
6
+ import os from "node:os";
7
+ import path from "node:path";
8
+ import { promisify } from "node:util";
9
+
10
+ // src/runtime-env.ts
11
+ function workspaceRuntimeTargetEnv(input) {
12
+ return {
13
+ WORKSPACE_RUNTIME_WORKSPACE_ID: input.workspaceId,
14
+ ...input.hostId ? { WORKSPACE_RUNTIME_HOST_ID: input.hostId } : {},
15
+ WORKSPACE_RUNTIME_DIRECTORY: input.directory,
16
+ WORKSPACE_RUNTIME_PORT: String(input.port),
17
+ ...input.host ? { WORKSPACE_RUNTIME_HOST: input.host } : {}
18
+ };
19
+ }
20
+ function workspaceRuntimeSourceEnv(input) {
21
+ if (!input.source || input.source.kind === "empty") return { WORKSPACE_RUNTIME_SOURCE_KIND: "empty" };
22
+ return {
23
+ WORKSPACE_RUNTIME_SOURCE_KIND: "git",
24
+ WORKSPACE_RUNTIME_GIT_REPO_URL: input.source.repoUrl,
25
+ ...input.source.branch ? { WORKSPACE_RUNTIME_GIT_BRANCH: input.source.branch } : {}
26
+ };
27
+ }
28
+
29
+ // src/command.ts
30
+ function shell(input) {
31
+ return `'${input.replace(/'/g, `'"'"'`)}'`;
32
+ }
33
+
34
+ // src/constants.ts
35
+ var DEFAULT_WORKSPACE_RUNTIME_PORT = 2593;
36
+
37
+ // src/image.ts
38
+ import { Image, DaytonaNotFoundError } from "@daytona/sdk";
39
+
40
+ // src/runtime-version.ts
41
+ import { createRequire } from "module";
42
+ var require2 = createRequire(import.meta.url);
43
+ var versionCache;
44
+ function workspaceRuntimeVersion() {
45
+ if (versionCache) return versionCache;
46
+ const envVersion = process.env.WORKSPACE_RUNTIME_VERSION;
47
+ if (envVersion) {
48
+ versionCache = envVersion;
49
+ return versionCache;
50
+ }
51
+ try {
52
+ versionCache = require2("@claxedo/workspace-runtime/package.json").version;
53
+ return versionCache;
54
+ } catch {
55
+ }
56
+ versionCache = "0.0.0";
57
+ return versionCache;
58
+ }
59
+
60
+ // src/image-name.ts
61
+ var SNAPSHOT_SCHEMA_VERSION = 8;
62
+ var DEFAULT_SANDBOX_IMAGE_REPOSITORY = "ghcr.io/kyashrathore/claxedo-sandbox";
63
+ function snapshotVersion(value) {
64
+ return value.toLowerCase().replace(/[^a-z0-9]+/g, "-").replace(/^-|-$/g, "");
65
+ }
66
+ function sandboxImageRepository(env = process.env) {
67
+ const repository = env.CLAXEDO_SANDBOX_IMAGE_REPOSITORY?.trim();
68
+ return repository ? repository : DEFAULT_SANDBOX_IMAGE_REPOSITORY;
69
+ }
70
+ function buildIdSuffix(buildId, env) {
71
+ const id = (buildId ?? env.CLAXEDO_SANDBOX_BUILD_ID)?.trim();
72
+ return id ? `-${snapshotVersion(id)}` : "";
73
+ }
74
+ function defaultSandboxImage(version = workspaceRuntimeVersion(), buildId, env = process.env) {
75
+ return `${sandboxImageRepository(env)}:workspace-runtime-${snapshotVersion(version)}${buildIdSuffix(buildId, env)}-v${SNAPSHOT_SCHEMA_VERSION}`;
76
+ }
77
+ function defaultSnapshotName(version = workspaceRuntimeVersion(), buildId, env = process.env) {
78
+ return `claxedo-workspace-runtime-${snapshotVersion(version)}${buildIdSuffix(buildId, env)}-v${SNAPSHOT_SCHEMA_VERSION}`;
79
+ }
80
+
81
+ // src/image.ts
82
+ var SANDBOX_IMAGE_REPOSITORY = sandboxImageRepository();
83
+ var SANDBOX_IMAGE = process.env.CLAXEDO_SANDBOX_IMAGE || defaultSandboxImage();
84
+ var SNAPSHOT_NAME = process.env.CLAXEDO_SNAPSHOT_NAME || defaultSnapshotName();
85
+
86
+ // src/drivers/docker.ts
87
+ var execFileAsync = promisify(execFile);
88
+ var DEFAULT_OPERATION_TIMEOUT_MS = 6e4;
89
+ var DEFAULT_RUNTIME_COMMAND = "/usr/local/bin/workspace-runtime";
90
+ var DEFAULT_WORKSPACE_DIR = "/workspace";
91
+ var DOCKER_LABEL = "claxedo";
92
+ var AUTH_STAGE_DIR = "/tmp/claxedo-auth";
93
+ function dockerSandboxSyncLocalAuth(env = process.env) {
94
+ return !disabled(env.CLAXEDO_DOCKER_SANDBOX_SYNC_LOCAL_AUTH);
95
+ }
96
+ function dockerSandboxAuthHome(env = process.env) {
97
+ return clean(env.CLAXEDO_DOCKER_SANDBOX_AUTH_HOME) ?? clean(env.HOME) ?? os.homedir();
98
+ }
99
+ function dockerSandboxImageFromEnv(env = process.env) {
100
+ return clean(env.CLAXEDO_DOCKER_SANDBOX_IMAGE) ?? clean(env.CLAXEDO_SANDBOX_IMAGE) ?? SANDBOX_IMAGE;
101
+ }
102
+ function parseDockerPort(input) {
103
+ const line = input.trim().split(/\r?\n/)[0]?.trim();
104
+ const match = line?.match(/(?:(?:\[.*\]|[^:]+):)?(\d+)$/);
105
+ return match?.[1] ? `http://127.0.0.1:${match[1]}` : void 0;
106
+ }
107
+ function dockerLocalAuthCandidates(home) {
108
+ return [
109
+ {
110
+ kind: "file",
111
+ source: path.join(home, ".codex", "auth.json"),
112
+ target: "/root/.codex/auth.json"
113
+ },
114
+ {
115
+ kind: "dir",
116
+ source: path.join(home, ".codex", "accounts"),
117
+ target: "/root/.codex/accounts"
118
+ },
119
+ {
120
+ kind: "file",
121
+ source: path.join(home, ".local", "share", "opencode", "auth.json"),
122
+ target: "/root/.local/share/opencode/auth.json"
123
+ },
124
+ {
125
+ kind: "file",
126
+ source: path.join(home, ".claude.json"),
127
+ target: "/root/.claude.json"
128
+ }
129
+ ];
130
+ }
131
+ function clean(input) {
132
+ const txt = input?.trim();
133
+ return txt ? txt : void 0;
134
+ }
135
+ function disabled(input) {
136
+ return ["0", "false", "no", "off"].includes(input?.trim().toLowerCase() ?? "");
137
+ }
138
+ function nameFor(workspaceId) {
139
+ const cleanId = workspaceId.toLowerCase().replace(/[^a-z0-9_.-]+/g, "-").replace(/^-+|-+$/g, "");
140
+ return `claxedo-${cleanId || "workspace"}-${Date.now().toString(36)}`.slice(0, 63);
141
+ }
142
+ async function docker(args, timeoutMs = DEFAULT_OPERATION_TIMEOUT_MS) {
143
+ return execFileAsync("docker", args, {
144
+ maxBuffer: 20 * 1024 * 1024,
145
+ timeout: timeoutMs
146
+ });
147
+ }
148
+ async function stageLocalAgentAuth(containerId, input) {
149
+ if (!input.syncLocalAuth) return;
150
+ const tmp = await fs.mkdtemp(path.join(os.tmpdir(), "claxedo-docker-auth-"));
151
+ try {
152
+ const stagedRoot = path.join(tmp, "root");
153
+ const copied = await Promise.all(dockerLocalAuthCandidates(input.authHome).map(async (item) => {
154
+ const stat = await fs.stat(item.source).catch(() => void 0);
155
+ if (!stat) return false;
156
+ if (item.kind === "file" && !stat.isFile()) return false;
157
+ if (item.kind === "dir" && !stat.isDirectory()) return false;
158
+ const target = path.join(stagedRoot, item.target.replace(/^\/root\/?/, ""));
159
+ await fs.mkdir(path.dirname(target), { recursive: true });
160
+ if (item.kind === "dir") await fs.cp(item.source, target, { recursive: true });
161
+ else await fs.copyFile(item.source, target);
162
+ return true;
163
+ }));
164
+ if (!copied.some(Boolean)) return;
165
+ await input.docker(["cp", stagedRoot, `${containerId}:${AUTH_STAGE_DIR}`], input.timeoutMs);
166
+ } finally {
167
+ await fs.rm(tmp, { recursive: true, force: true }).catch(() => {
168
+ });
169
+ }
170
+ }
171
+ function authHydrationScript() {
172
+ return [
173
+ "rm -f /root/.codex/auth.json /root/.local/share/opencode/auth.json /root/.claude.json || true",
174
+ "rm -rf /root/.codex/accounts || true",
175
+ "mkdir -p /root/.codex /root/.local/share/opencode /root/.claude",
176
+ `if [ -f ${AUTH_STAGE_DIR}/.codex/auth.json ]; then cp -a ${AUTH_STAGE_DIR}/.codex/auth.json /root/.codex/auth.json && chmod 600 /root/.codex/auth.json || true; fi`,
177
+ `if [ -d ${AUTH_STAGE_DIR}/.codex/accounts ]; then mkdir -p /root/.codex/accounts && cp -a ${AUTH_STAGE_DIR}/.codex/accounts/. /root/.codex/accounts/ && chmod -R go-rwx /root/.codex/accounts || true; fi`,
178
+ `if [ -f ${AUTH_STAGE_DIR}/.local/share/opencode/auth.json ]; then cp -a ${AUTH_STAGE_DIR}/.local/share/opencode/auth.json /root/.local/share/opencode/auth.json && chmod 600 /root/.local/share/opencode/auth.json || true; fi`,
179
+ `if [ -f ${AUTH_STAGE_DIR}/.claude.json ]; then cp -a ${AUTH_STAGE_DIR}/.claude.json /root/.claude.json && chmod 600 /root/.claude.json || true; fi`
180
+ ].join(" && ");
181
+ }
182
+ function bootScript(directory, runtimeCommand) {
183
+ return [
184
+ authHydrationScript(),
185
+ `mkdir -p ${shell(directory)}`,
186
+ `cd ${shell(directory)}`,
187
+ `exec ${runtimeCommand}`
188
+ ].join(" && ");
189
+ }
190
+ function envArgs(input) {
191
+ return Object.entries(input).flatMap(([key, value]) => ["--env", `${key}=${value}`]);
192
+ }
193
+ function labelArgs(input) {
194
+ return Object.entries(input).flatMap(([key, value]) => ["--label", `${key}=${value}`]);
195
+ }
196
+ function transientDriverError(err) {
197
+ const shaped = err;
198
+ const text = `${shaped.code ?? ""} ${shaped.message ?? ""}`.toLowerCase();
199
+ return text.includes("timeout") || text.includes("temporarily unavailable") || text.includes("connection refused");
200
+ }
201
+ function createDockerSandboxDriver(options) {
202
+ const dockerCommand = options.docker ?? docker;
203
+ const runtimeCommand = options.runtimeCommand ?? DEFAULT_RUNTIME_COMMAND;
204
+ const workspaceDir = options.workspaceDir ?? DEFAULT_WORKSPACE_DIR;
205
+ const timeoutMs = options.operationTimeoutMs ?? DEFAULT_OPERATION_TIMEOUT_MS;
206
+ const syncLocalAuth = options.syncLocalAuth ?? dockerSandboxSyncLocalAuth();
207
+ const authHome = options.authHome ?? dockerSandboxAuthHome();
208
+ function runtimePort(input) {
209
+ return input.workspaceRuntimePort ?? options.runtimePort ?? DEFAULT_WORKSPACE_RUNTIME_PORT;
210
+ }
211
+ function workspaceDirectory(input) {
212
+ return input.workspaceRoot ?? workspaceDir;
213
+ }
214
+ function image(input) {
215
+ if (input.bootSource?.kind === "driver-snapshot") {
216
+ throw new Error("Docker SandboxDriver does not support driver snapshots; use image boot");
217
+ }
218
+ return input.bootSource?.kind === "image" ? input.bootSource.image : input.snapshot ?? options.image;
219
+ }
220
+ function bootEnv(input, hostId) {
221
+ const env = {
222
+ ...workspaceRuntimeTargetEnv({
223
+ workspaceId: input.workspaceId,
224
+ hostId,
225
+ directory: workspaceDirectory(input),
226
+ port: runtimePort(input),
227
+ host: "0.0.0.0"
228
+ }),
229
+ ...workspaceRuntimeSourceEnv({ source: input.source }),
230
+ ...input.env
231
+ };
232
+ if (options.runner) env.WORKSPACE_RUNTIME_RUNNER = options.runner;
233
+ return env;
234
+ }
235
+ async function readyTarget(input, sandboxId, hostId) {
236
+ const out = await dockerCommand(["port", sandboxId, `${runtimePort(input)}/tcp`], timeoutMs);
237
+ const url = parseDockerPort(String(out.stdout ?? ""));
238
+ if (!url) throw new Error(`Docker container ${sandboxId} does not expose workspace runtime port ${runtimePort(input)}`);
239
+ return {
240
+ workspaceId: input.workspaceId,
241
+ sandboxId,
242
+ url,
243
+ hostId,
244
+ driverResourceId: sandboxId,
245
+ driver: {
246
+ id: "docker",
247
+ resourceId: sandboxId
248
+ },
249
+ labels: input.labels
250
+ };
251
+ }
252
+ async function ensureHost(input) {
253
+ if (input.net && input.net.mode !== "allow-all") {
254
+ throw new Error("Docker SandboxDriver cannot enforce restricted network policies");
255
+ }
256
+ const hostId = input.hostId ?? nameFor(input.workspaceId);
257
+ const env = {
258
+ ...bootEnv(input, hostId),
259
+ ...await options.env?.(input, { id: hostId })
260
+ };
261
+ const created = await dockerCommand([
262
+ "create",
263
+ "--name",
264
+ hostId,
265
+ "--label",
266
+ `app=${DOCKER_LABEL}`,
267
+ "--label",
268
+ `claxedo.workspaceId=${input.workspaceId}`,
269
+ ...labelArgs(input.labels),
270
+ "-p",
271
+ `127.0.0.1::${runtimePort(input)}`,
272
+ ...envArgs(env),
273
+ "--entrypoint",
274
+ "sh",
275
+ image(input),
276
+ "-lc",
277
+ bootScript(workspaceDirectory(input), runtimeCommand)
278
+ ], 12e4).catch((err) => {
279
+ if (transientDriverError(err)) return void 0;
280
+ throw err;
281
+ });
282
+ if (!created) return { provisioning: true, retryAfterMs: 2e3 };
283
+ const sandboxId = String(created.stdout ?? "").trim() || hostId;
284
+ await stageLocalAgentAuth(sandboxId, { authHome, syncLocalAuth, docker: dockerCommand, timeoutMs });
285
+ await dockerCommand(["start", sandboxId], timeoutMs);
286
+ return readyTarget(input, sandboxId, hostId);
287
+ }
288
+ async function resumeHost(input) {
289
+ const sandboxId = input.lease.sandboxId ?? input.lease.sandbox_id;
290
+ if (!sandboxId) return ensureHost(input.ensure);
291
+ await dockerCommand(["inspect", "-f", "{{.Id}}", sandboxId], timeoutMs).catch(() => void 0);
292
+ await dockerCommand(["start", sandboxId], timeoutMs).catch((err) => {
293
+ if (transientDriverError(err)) return void 0;
294
+ throw err;
295
+ });
296
+ return readyTarget(input.ensure, sandboxId, input.ensure.hostId ?? sandboxId);
297
+ }
298
+ async function stop(target) {
299
+ await dockerCommand(["stop", target.sandboxId], 3e4);
300
+ }
301
+ async function destroy(target) {
302
+ await dockerCommand(["rm", "-f", target.sandboxId], 3e4);
303
+ }
304
+ return {
305
+ id: "docker",
306
+ metadata: {
307
+ driverRunsIn: ["local"],
308
+ hostStopBehavior: "terminates-host",
309
+ hostResumeBehavior: "same-host",
310
+ targetAccess: "loopback",
311
+ secretBrokering: "none"
312
+ },
313
+ ensureHost,
314
+ resumeHost,
315
+ async touch() {
316
+ },
317
+ suspend: stop,
318
+ stop,
319
+ destroy
320
+ };
321
+ }
322
+ export {
323
+ createDockerSandboxDriver,
324
+ dockerLocalAuthCandidates,
325
+ dockerSandboxAuthHome,
326
+ dockerSandboxImageFromEnv,
327
+ dockerSandboxSyncLocalAuth,
328
+ parseDockerPort
329
+ };
@@ -0,0 +1,10 @@
1
+ import type { SandboxDriver } from "..";
2
+ export type FetchBridgeSandboxDriverOptions = {
3
+ id: string;
4
+ baseUrl: string;
5
+ token?: string;
6
+ fetch?: typeof fetch;
7
+ autoStopMs: number;
8
+ autoDeleteMs: number;
9
+ };
10
+ export declare function createFetchBridgeSandboxDriver(options: FetchBridgeSandboxDriverOptions): SandboxDriver;
@@ -0,0 +1,104 @@
1
+ import { createRequire as __createRequire } from 'module';var require = __createRequire(import.meta.url);
2
+
3
+ // src/drivers/fetch-bridge.ts
4
+ function cleanUrl(input) {
5
+ return input.replace(/\/+$/, "");
6
+ }
7
+ function assertLifecycleSettings(options) {
8
+ if (!Number.isFinite(options.autoStopMs) || options.autoStopMs <= 0) {
9
+ throw new Error("Fetch bridge sandbox driver requires a finite auto-stop/sleep policy");
10
+ }
11
+ if (!Number.isFinite(options.autoDeleteMs) || options.autoDeleteMs <= 0) {
12
+ throw new Error("Fetch bridge sandbox driver requires a finite auto-delete policy");
13
+ }
14
+ }
15
+ function headers(token) {
16
+ return {
17
+ "content-type": "application/json",
18
+ ...token ? { authorization: `Bearer ${token}` } : {}
19
+ };
20
+ }
21
+ function target(input) {
22
+ if (!input || typeof input !== "object" || Array.isArray(input)) throw new Error("Fetch bridge sandbox driver returned an invalid response");
23
+ const row = input;
24
+ if (row.status === "provisioning") {
25
+ return {
26
+ provisioning: true,
27
+ retryAfterMs: typeof row.retryAfterMs === "number" ? row.retryAfterMs : 2e3
28
+ };
29
+ }
30
+ if (typeof row.sandboxId !== "string" || typeof row.url !== "string" || typeof row.hostId !== "string") {
31
+ throw new Error("Fetch bridge sandbox driver returned an incomplete target");
32
+ }
33
+ return {
34
+ workspaceId: typeof row.workspaceId === "string" ? row.workspaceId : void 0,
35
+ sandboxId: row.sandboxId,
36
+ url: row.url,
37
+ hostId: row.hostId,
38
+ driverResourceId: typeof row.driverResourceId === "string" ? row.driverResourceId : void 0,
39
+ labels: row.labels && typeof row.labels === "object" && !Array.isArray(row.labels) ? row.labels : void 0
40
+ };
41
+ }
42
+ function bridgeTarget(input) {
43
+ const result = target(input);
44
+ if ("provisioning" in result) throw new Error("Fetch bridge sandbox driver returned provisioning status in a target list");
45
+ return result;
46
+ }
47
+ function targetList(input) {
48
+ const rows = Array.isArray(input) ? input : input && typeof input === "object" && !Array.isArray(input) && Array.isArray(input.targets) ? input.targets : void 0;
49
+ if (!rows) throw new Error("Fetch bridge sandbox driver returned an invalid target list");
50
+ return rows.map(bridgeTarget);
51
+ }
52
+ async function post(options, path, body) {
53
+ const res = await (options.fetch ?? fetch)(`${cleanUrl(options.baseUrl)}${path}`, {
54
+ method: "POST",
55
+ headers: headers(options.token),
56
+ body: JSON.stringify(body)
57
+ });
58
+ if (!res.ok) throw new Error(`Fetch bridge sandbox driver ${path} failed with ${res.status}`);
59
+ return res.json();
60
+ }
61
+ function createFetchBridgeSandboxDriver(options) {
62
+ assertLifecycleSettings(options);
63
+ async function ensureHost(input) {
64
+ return target(await post(options, "/runtime/ensure", {
65
+ workspaceId: input.workspaceId,
66
+ homeRegion: input.homeRegion,
67
+ epoch: input.epoch,
68
+ labels: input.labels,
69
+ hostControl: {
70
+ autoStopMs: options.autoStopMs,
71
+ autoDeleteMs: options.autoDeleteMs
72
+ }
73
+ }));
74
+ }
75
+ return {
76
+ id: options.id,
77
+ metadata: {
78
+ driverRunsIn: ["worker", "node"],
79
+ hostStopBehavior: "suspends-host",
80
+ hostResumeBehavior: "same-host",
81
+ targetAccess: "relay",
82
+ secretBrokering: "none"
83
+ },
84
+ ensureHost,
85
+ async list() {
86
+ return targetList(await post(options, "/runtime/list", {}));
87
+ },
88
+ async touch(input) {
89
+ await post(options, "/runtime/touch", input);
90
+ },
91
+ async stop(input) {
92
+ await post(options, "/runtime/stop", input);
93
+ },
94
+ async suspend(input) {
95
+ await post(options, "/runtime/stop", input);
96
+ },
97
+ async destroy(input) {
98
+ await post(options, "/runtime/destroy", input);
99
+ }
100
+ };
101
+ }
102
+ export {
103
+ createFetchBridgeSandboxDriver
104
+ };
@@ -0,0 +1,68 @@
1
+ import type { SandboxDriver, SandboxDriverEnsureInput } from "..";
2
+ type ModalAppLike = unknown;
3
+ type ModalImageLike = {
4
+ imageId?: string;
5
+ };
6
+ type ModalTunnelLike = {
7
+ url: string;
8
+ };
9
+ export type ModalSandboxLike = {
10
+ sandboxId: string;
11
+ tunnels: (timeoutMs?: number) => Promise<Record<number, ModalTunnelLike>>;
12
+ terminate: () => Promise<void>;
13
+ setTags: (tags: Record<string, string>) => Promise<void>;
14
+ snapshotFilesystem: (timeoutMs?: number) => Promise<ModalImageLike>;
15
+ };
16
+ export type ModalClientLike = {
17
+ apps: {
18
+ fromName: (name: string, params?: {
19
+ createIfMissing?: boolean;
20
+ }) => Promise<ModalAppLike>;
21
+ };
22
+ images: {
23
+ fromRegistry: (tag: string) => ModalImageLike;
24
+ fromId: (imageId: string) => Promise<ModalImageLike>;
25
+ };
26
+ sandboxes: {
27
+ create: (app: ModalAppLike, image: ModalImageLike, params?: {
28
+ name?: string;
29
+ command?: string[];
30
+ workdir?: string;
31
+ env?: Record<string, string>;
32
+ encryptedPorts?: number[];
33
+ timeoutMs?: number;
34
+ idleTimeoutMs?: number;
35
+ tags?: Record<string, string>;
36
+ blockNetwork?: boolean;
37
+ outboundCidrAllowlist?: string[];
38
+ readinessProbe?: unknown;
39
+ }) => Promise<ModalSandboxLike>;
40
+ fromId: (sandboxId: string) => Promise<ModalSandboxLike>;
41
+ };
42
+ };
43
+ export type ModalSandboxDriverOptions = {
44
+ tokenId: string;
45
+ tokenSecret: string;
46
+ appName?: string;
47
+ baseImage?: string;
48
+ runtimePort?: number;
49
+ runtimeCommand?: string;
50
+ workspaceDir?: string;
51
+ runner?: string;
52
+ controlEnv?: {
53
+ relayJwksUrl?: string;
54
+ relayVerifyPem?: string;
55
+ managementJwksUrl?: string;
56
+ };
57
+ env?: (input: SandboxDriverEnsureInput, host: {
58
+ id: string;
59
+ }) => Record<string, string> | Promise<Record<string, string>>;
60
+ timeoutMs?: number;
61
+ idleTimeoutMs?: number;
62
+ tunnelTimeoutMs?: number;
63
+ operationTimeoutMs?: number;
64
+ client?: ModalClientLike;
65
+ readinessProbe?: (port: number) => unknown;
66
+ };
67
+ export declare function createModalSandboxDriver(options: ModalSandboxDriverOptions): SandboxDriver;
68
+ export {};