@claxedo/sandbox-manager 0.7.0 → 0.10.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 (70) hide show
  1. package/README.md +245 -42
  2. package/dist/checkpoint-manager.d.ts +29 -4
  3. package/dist/checkpoint-manager.mjs +133 -24
  4. package/dist/command.d.ts +9 -2
  5. package/dist/command.mjs +8 -8
  6. package/dist/contract.d.ts +687 -0
  7. package/dist/driver-billing.d.ts +29 -0
  8. package/dist/driver-catalog.d.ts +43 -58
  9. package/dist/driver-catalog.mjs +192 -229
  10. package/dist/drivers/boat-client.d.ts +95 -0
  11. package/dist/drivers/boat-named-snapshots.d.ts +31 -0
  12. package/dist/drivers/boat-template.d.ts +49 -0
  13. package/dist/drivers/boat-template.mjs +1196 -0
  14. package/dist/drivers/boat.d.ts +64 -0
  15. package/dist/drivers/boat.mjs +990 -0
  16. package/dist/drivers/cloudflare.d.ts +5 -8
  17. package/dist/drivers/cloudflare.mjs +364 -213
  18. package/dist/drivers/docker.d.ts +4 -3
  19. package/dist/drivers/docker.mjs +244 -165
  20. package/dist/drivers/local-brokering.d.ts +14 -0
  21. package/dist/drivers/local-brokering.mjs +1029 -0
  22. package/dist/drivers/modal.d.ts +4 -7
  23. package/dist/drivers/modal.mjs +220 -155
  24. package/dist/drivers/transient-error.d.ts +13 -0
  25. package/dist/drivers/vercel.d.ts +21 -23
  26. package/dist/drivers/vercel.mjs +279 -169
  27. package/dist/egress-policy.d.ts +134 -0
  28. package/dist/egress-warnings.d.ts +22 -0
  29. package/dist/garbage-collect.d.ts +14 -0
  30. package/dist/hosted-network-policy.d.ts +11 -4
  31. package/dist/hosted-network-policy.mjs +221 -4
  32. package/dist/image-name.d.ts +12 -2
  33. package/dist/image-name.mjs +43 -0
  34. package/dist/image.d.ts +1 -20
  35. package/dist/image.mjs +11 -66
  36. package/dist/index.d.ts +8 -533
  37. package/dist/index.mjs +1420 -315
  38. package/dist/json.d.ts +13 -0
  39. package/dist/lease-failure.d.ts +173 -0
  40. package/dist/lease-lifecycle.d.ts +65 -0
  41. package/dist/lease-retry-wait.d.ts +8 -0
  42. package/dist/lease-start.d.ts +21 -0
  43. package/dist/lease-types.d.ts +15 -5
  44. package/dist/manager.d.ts +2 -0
  45. package/dist/runtime-env.d.ts +15 -2
  46. package/dist/runtime-env.mjs +50 -1
  47. package/dist/runtime-snapshot.d.ts +49 -0
  48. package/dist/runtime-version.d.ts +9 -0
  49. package/dist/runtime-version.mjs +2 -0
  50. package/dist/service-url-exposure.d.ts +1 -3
  51. package/dist/service-url-exposure.mjs +1 -26
  52. package/dist/start-fresh.d.ts +17 -0
  53. package/dist/start-telemetry.d.ts +37 -0
  54. package/dist/stores/memory.d.ts +1 -1
  55. package/dist/stores/memory.mjs +65 -54
  56. package/package.json +67 -81
  57. package/dist/daytona-allow-list.d.ts +0 -16
  58. package/dist/daytona-allow-list.mjs +0 -11
  59. package/dist/drivers/box.d.ts +0 -52
  60. package/dist/drivers/box.mjs +0 -499
  61. package/dist/drivers/cloudflare-egress.d.ts +0 -40
  62. package/dist/drivers/cloudflare-egress.mjs +0 -113
  63. package/dist/drivers/daytona.d.ts +0 -127
  64. package/dist/drivers/daytona.mjs +0 -541
  65. package/dist/drivers/exe.d.ts +0 -26
  66. package/dist/drivers/exe.mjs +0 -469
  67. package/dist/drivers/fetch-bridge.d.ts +0 -10
  68. package/dist/drivers/fetch-bridge.mjs +0 -111
  69. package/dist/lease-policy.d.ts +0 -48
  70. package/dist/lease-policy.mjs +0 -280
@@ -0,0 +1,29 @@
1
+ import type { SandboxMachineClass } from "@claxedo/sandbox-contract";
2
+ /** One size a provider sells, as its own catalog names and prices it. */
3
+ export type SandboxMachineRate = {
4
+ /** The provider's own name for the size. */
5
+ size: string;
6
+ vcpu: number;
7
+ memoryGb: number;
8
+ usdPerHour: number;
9
+ };
10
+ /**
11
+ * How a provider bills the machine a sandbox runs on, read from its published
12
+ * pricing. `rates.default` is also the one size of a driver that offers no
13
+ * choice. `excludes` names a component the hourly rate leaves out because the
14
+ * provider meters it on use rather than on time.
15
+ */
16
+ export type SandboxDriverBilling = {
17
+ source: {
18
+ url: string;
19
+ readOn: string;
20
+ };
21
+ meter: string;
22
+ rates: Partial<Record<SandboxMachineClass, SandboxMachineRate>>;
23
+ excludes?: string;
24
+ };
25
+ export declare const boatBilling: SandboxDriverBilling;
26
+ export declare const cloudflareBilling: SandboxDriverBilling;
27
+ /** The rate a sandbox of this class runs at; a driver with one size answers it for the class it was not asked for. */
28
+ export declare function sandboxMachineRate(billing: SandboxDriverBilling | undefined, machineClass: SandboxMachineClass | null): SandboxMachineRate | undefined;
29
+ export declare function sandboxMachineCostUsd(rate: SandboxMachineRate, activeMs: number): number;
@@ -1,68 +1,53 @@
1
- import { validateSandboxPersistenceCapabilities, type SandboxDriverMetadata } from "./index";
2
- export declare const sandboxDriverIds: readonly ["exe", "daytona", "modal", "vercel", "cloudflare", "box", "docker"];
3
- export type SandboxDriverID = (typeof sandboxDriverIds)[number];
4
- export type SandboxDriverAuth = {
5
- exe?: {
6
- api_token?: string;
7
- };
8
- daytona?: {
9
- api_key?: string;
10
- };
11
- modal?: {
12
- token_id?: string;
13
- token_secret?: string;
14
- };
15
- vercel?: {
16
- access_token?: string;
17
- team_id?: string;
18
- project_id?: string;
19
- };
20
- cloudflare?: {
21
- api_token?: string;
22
- worker_url?: string;
23
- };
24
- box?: {
25
- api_key?: string;
26
- };
27
- docker?: {
28
- image?: string;
29
- };
30
- };
31
- export type SandboxDriverConfig = {
32
- default_driver?: SandboxDriverID;
33
- auth?: SandboxDriverAuth;
34
- };
35
- export type SandboxDriverCatalogEntry = {
36
- id: SandboxDriverID;
1
+ import { validateSandboxPersistenceCapabilities, type SandboxDriverMetadata } from "./contract";
2
+ import { type SandboxDriverBilling } from "./driver-billing";
3
+ import { sandboxDriverId, type SandboxDriverEnv, type SandboxDriverID } from "@claxedo/sandbox-contract";
4
+ export { sandboxDriverId };
5
+ export { sandboxMachineCostUsd, sandboxMachineRate, type SandboxDriverBilling, type SandboxMachineRate } from "./driver-billing";
6
+ export type SandboxDriverCatalogEntry<ID extends string = SandboxDriverID> = {
7
+ id: ID;
37
8
  label: string;
38
9
  metadata: SandboxDriverMetadata;
39
- credentialFields: Array<{
10
+ credentialFields: ReadonlyArray<{
40
11
  key: string;
41
12
  label: string;
42
13
  secret?: boolean;
43
14
  }>;
15
+ runtimeNetwork: {
16
+ controlPlane: "docker-host" | "direct";
17
+ relay: "configured" | "local";
18
+ };
19
+ runtimeEnv: "ensure" | "callback";
20
+ preparedImage: boolean;
21
+ /** Absent where no published rate for the machines this driver places on has been established. */
22
+ billing?: SandboxDriverBilling;
44
23
  };
45
24
  export { validateSandboxPersistenceCapabilities };
25
+ export declare const localBrokeringTestDriverCatalogEntry: {
26
+ readonly id: "local-brokering-test";
27
+ readonly label: "Local brokering test driver";
28
+ readonly credentialFields: readonly [];
29
+ readonly runtimeNetwork: {
30
+ readonly controlPlane: "direct";
31
+ readonly relay: "local";
32
+ };
33
+ readonly runtimeEnv: "ensure";
34
+ readonly preparedImage: false;
35
+ readonly metadata: {
36
+ readonly driverRunsIn: ["local"];
37
+ readonly hostStopBehavior: "terminates-host";
38
+ readonly hostResumeBehavior: "same-host";
39
+ readonly targetAccess: "loopback";
40
+ readonly secretBrokering: "native";
41
+ readonly egressControl: "hosts";
42
+ readonly persistence: {
43
+ readonly resume: "same-sandbox";
44
+ readonly capture: "none";
45
+ readonly clone: false;
46
+ readonly captureSource: "not-applicable";
47
+ readonly retention: "provider-managed";
48
+ readonly restoreMount: "same-resource";
49
+ };
50
+ };
51
+ };
46
52
  export declare const sandboxDriverCatalog: Record<SandboxDriverID, SandboxDriverCatalogEntry>;
47
- export declare function isSandboxDriverID(input: string | undefined): input is SandboxDriverID;
48
- export declare function sandboxDriverId(input: string | undefined, cfg?: SandboxDriverConfig, env?: SandboxDriverEnv): "box" | "cloudflare" | "daytona" | "docker" | "exe" | "modal" | "vercel" | undefined;
49
- export declare function defaultSandboxDriverID(cfg?: SandboxDriverConfig, env?: SandboxDriverEnv): SandboxDriverID;
50
- export declare function sandboxDriverAuth<T extends SandboxDriverID>(cfg: SandboxDriverConfig | undefined, id: T, env?: SandboxDriverEnv): SandboxDriverAuth[T] | undefined;
51
- export declare function hasSandboxDriverAuth(cfg: SandboxDriverConfig | undefined, id: SandboxDriverID, env?: SandboxDriverEnv): boolean;
52
53
  export declare function dockerSandboxDriverEnabled(env?: SandboxDriverEnv): boolean;
53
- export declare function listSandboxDrivers(cfg?: SandboxDriverConfig, env?: SandboxDriverEnv, managedDriverIds?: ReadonlySet<string>): {
54
- default_driver: "box" | "cloudflare" | "daytona" | "docker" | "exe" | "modal" | "vercel";
55
- drivers: {
56
- id: "box" | "cloudflare" | "daytona" | "docker" | "exe" | "modal" | "vercel";
57
- label: string;
58
- fields: {
59
- key: string;
60
- label: string;
61
- secret?: boolean;
62
- }[];
63
- configured: boolean;
64
- source: "config" | "managed" | "none";
65
- default: boolean;
66
- }[];
67
- };
68
- type SandboxDriverEnv = Record<string, string | undefined>;
@@ -1,30 +1,4 @@
1
- // src/hosted-network-policy.ts
2
- var SANDBOX_MODEL_PROVIDER_HOSTS = [
3
- "api.anthropic.com",
4
- "api.openai.com",
5
- "generativelanguage.googleapis.com",
6
- "openrouter.ai",
7
- // Model catalog + engine config, fetched on runner startup.
8
- "models.dev",
9
- "opencode.ai"
10
- ];
11
- var SANDBOX_PACKAGE_REGISTRY_HOSTS = [
12
- "registry.npmjs.org",
13
- "nodejs.org",
14
- "pypi.org",
15
- "files.pythonhosted.org",
16
- "crates.io",
17
- "static.crates.io",
18
- "index.crates.io",
19
- "proxy.golang.org",
20
- "sum.golang.org"
21
- ];
22
- var SANDBOX_BASELINE_EGRESS_HOSTS = [
23
- ...SANDBOX_MODEL_PROVIDER_HOSTS,
24
- ...SANDBOX_PACKAGE_REGISTRY_HOSTS
25
- ];
26
-
27
- // src/index.ts
1
+ // src/contract.ts
28
2
  function validateSandboxPersistenceCapabilities(input) {
29
3
  if (input.resume === "replacement-restore" && input.capture === "none") {
30
4
  return { valid: false, reason: "replacement restore requires a capture source" };
@@ -38,100 +12,176 @@ function validateSandboxPersistenceCapabilities(input) {
38
12
  if (input.capture === "same-resource" && input.restoreMount !== "same-resource") {
39
13
  return { valid: false, reason: "same-resource capture requires same-resource restore" };
40
14
  }
41
- if (input.restoreMount === "copy-on-write" && input.capture !== "directories") {
42
- return { valid: false, reason: "copy-on-write restore requires directory capture" };
43
- }
44
15
  return { valid: true };
45
16
  }
46
17
 
47
- // src/runtime-version.ts
48
- var DEFAULT_WORKSPACE_RUNTIME_VERSION = "0.5.2";
49
- function workspaceRuntimeVersion() {
50
- return process.env.WORKSPACE_RUNTIME_VERSION || DEFAULT_WORKSPACE_RUNTIME_VERSION;
18
+ // src/driver-billing.ts
19
+ var HOUR_SECONDS = 3600;
20
+ var boatBilling = {
21
+ source: { url: "https://docs.boat.dev/pricing", readOn: "2026-10-12" },
22
+ meter: "Boat bills machine time per second while a sandbox runs, at an hourly rate per size; a stopped sandbox costs nothing.",
23
+ rates: {
24
+ small: { size: "small", vcpu: 2, memoryGb: 4, usdPerHour: 0.018 },
25
+ default: { size: "default", vcpu: 4, memoryGb: 8, usdPerHour: 0.036 },
26
+ large: { size: "large", vcpu: 8, memoryGb: 16, usdPerHour: 0.072 }
27
+ }
28
+ };
29
+ var CLOUDFLARE_USD_PER_GIB_SECOND_MEMORY = 25e-7;
30
+ var CLOUDFLARE_USD_PER_GB_SECOND_DISK = 7e-8;
31
+ var CLOUDFLARE_USD_PER_VCPU_SECOND_ACTIVE = 2e-5;
32
+ var CLOUDFLARE_STANDARD_1 = { size: "standard-1", vcpu: 0.5, memoryGb: 4, diskGb: 8 };
33
+ var cloudflareBilling = {
34
+ source: { url: "https://developers.cloudflare.com/containers/pricing/", readOn: "2026-10-12" },
35
+ meter: "Cloudflare bills a container for every 10 ms it runs: memory at $0.0000025 per GiB-second and disk at $0.00000007 per GB-second for the whole run, plus CPU at $0.00002 per vCPU-second of active use.",
36
+ rates: {
37
+ default: {
38
+ size: CLOUDFLARE_STANDARD_1.size,
39
+ vcpu: CLOUDFLARE_STANDARD_1.vcpu,
40
+ memoryGb: CLOUDFLARE_STANDARD_1.memoryGb,
41
+ usdPerHour: (CLOUDFLARE_STANDARD_1.memoryGb * CLOUDFLARE_USD_PER_GIB_SECOND_MEMORY + CLOUDFLARE_STANDARD_1.diskGb * CLOUDFLARE_USD_PER_GB_SECOND_DISK) * HOUR_SECONDS
42
+ }
43
+ },
44
+ excludes: `active CPU, billed at $${CLOUDFLARE_USD_PER_VCPU_SECOND_ACTIVE} per vCPU-second and not measured by Claxedo, and the monthly allowance a Workers Paid plan includes`
45
+ };
46
+ function sandboxMachineRate(billing, machineClass) {
47
+ if (!billing) return void 0;
48
+ return billing.rates[machineClass ?? "default"] ?? (Object.keys(billing.rates).length === 1 ? billing.rates.default : void 0);
49
+ }
50
+ function sandboxMachineCostUsd(rate, activeMs) {
51
+ return rate.usdPerHour * activeMs / (HOUR_SECONDS * 1e3);
51
52
  }
52
53
 
53
- // src/image-name.ts
54
- var SNAPSHOT_SCHEMA_VERSION = 8;
55
- var DEFAULT_SANDBOX_IMAGE_REPOSITORY = "ghcr.io/kyashrathore/claxedo-sandbox";
56
- function snapshotVersion(value) {
57
- return value.toLowerCase().replace(/[^a-z0-9]+/g, "-").replace(/^-|-$/g, "");
54
+ // ../sandbox-contract/dist/index.mjs
55
+ function isString(value) {
56
+ return typeof value === "string";
57
+ }
58
+ function trimToUndefined(value) {
59
+ if (!isString(value))
60
+ return;
61
+ const trimmed = value.trim();
62
+ return trimmed.length > 0 ? trimmed : void 0;
63
+ }
64
+ var sandboxDriverIds = ["modal", "vercel", "cloudflare", "boat", "docker"];
65
+ var sandboxDriverCredentialFields = {
66
+ modal: [
67
+ { key: "token_id", label: "Token ID", secret: true },
68
+ { key: "token_secret", label: "Token Secret", secret: true }
69
+ ],
70
+ vercel: [
71
+ { key: "access_token", label: "Access Token", secret: true },
72
+ { key: "team_id", label: "Team ID" },
73
+ { key: "project_id", label: "Project ID" }
74
+ ],
75
+ cloudflare: [
76
+ { key: "api_token", label: "API Token", secret: true },
77
+ { key: "worker_url", label: "Worker URL" }
78
+ ],
79
+ boat: [{ key: "api_key", label: "API Key", secret: true }],
80
+ docker: [{ key: "image", label: "Image" }]
81
+ };
82
+ var sandboxDriverLabels = {
83
+ modal: "Modal",
84
+ vercel: "Vercel",
85
+ cloudflare: "Cloudflare",
86
+ boat: "Boat",
87
+ docker: "Docker"
88
+ };
89
+ function isSandboxDriverID(input) {
90
+ return !!input && sandboxDriverIds.includes(input);
58
91
  }
59
- function sandboxImageRepository(env = process.env) {
60
- const repository = env.CLAXEDO_SANDBOX_IMAGE_REPOSITORY?.trim();
61
- return repository ? repository : DEFAULT_SANDBOX_IMAGE_REPOSITORY;
92
+ function enabled(input) {
93
+ return ["1", "true", "yes", "on"].includes(input?.trim().toLowerCase() ?? "");
62
94
  }
63
- function buildIdSuffix(buildId, env) {
64
- const id = (buildId ?? env.CLAXEDO_SANDBOX_BUILD_ID)?.trim();
65
- return id ? `-${snapshotVersion(id)}` : "";
95
+ function dockerSandboxDriverEnabled(env = process.env) {
96
+ return enabled(env.CLAXEDO_ENABLE_DOCKER_SANDBOX) || enabled(env.CLAXEDO_DEV_DOCKER_SANDBOX);
66
97
  }
67
- function defaultSandboxImage(version = workspaceRuntimeVersion(), buildId, env = process.env) {
68
- return `${sandboxImageRepository(env)}:workspace-runtime-${snapshotVersion(version)}${buildIdSuffix(buildId, env)}-v${SNAPSHOT_SCHEMA_VERSION}`;
98
+ function sandboxDriverAuthValues(cfg, id, env = process.env) {
99
+ if (id === "modal") {
100
+ const token_id = trimToUndefined(cfg?.auth?.modal?.token_id) ?? trimToUndefined(env.MODAL_TOKEN_ID);
101
+ const token_secret = trimToUndefined(cfg?.auth?.modal?.token_secret) ?? trimToUndefined(env.MODAL_TOKEN_SECRET);
102
+ return token_id && token_secret ? { token_id, token_secret } : void 0;
103
+ }
104
+ if (id === "vercel") {
105
+ const access_token = trimToUndefined(cfg?.auth?.vercel?.access_token) ?? trimToUndefined(env.VERCEL_TOKEN);
106
+ const team_id = trimToUndefined(cfg?.auth?.vercel?.team_id) ?? trimToUndefined(env.VERCEL_TEAM_ID);
107
+ const project_id = trimToUndefined(cfg?.auth?.vercel?.project_id) ?? trimToUndefined(env.VERCEL_PROJECT_ID);
108
+ return access_token && team_id && project_id ? { access_token, team_id, project_id } : void 0;
109
+ }
110
+ if (id === "cloudflare") {
111
+ const api_token = trimToUndefined(cfg?.auth?.cloudflare?.api_token) ?? trimToUndefined(env.CLOUDFLARE_API_TOKEN);
112
+ const configuredUrl = trimToUndefined(cfg?.auth?.cloudflare?.worker_url) ?? trimToUndefined(env.CLOUDFLARE_SANDBOX_WORKER_URL);
113
+ const worker_url = configuredUrl ? cloudflareWorkerBaseUrl(configuredUrl) : void 0;
114
+ return api_token && worker_url ? { api_token, worker_url } : void 0;
115
+ }
116
+ if (id === "boat") {
117
+ const api_key = trimToUndefined(cfg?.auth?.boat?.api_key) ?? trimToUndefined(env.BOAT_API_KEY);
118
+ return api_key ? { api_key } : void 0;
119
+ }
120
+ if (!dockerSandboxDriverEnabled(env))
121
+ return;
122
+ const image = trimToUndefined(cfg?.auth?.docker?.image) ?? trimToUndefined(env.CLAXEDO_DOCKER_SANDBOX_IMAGE) ?? trimToUndefined(env.CLAXEDO_SANDBOX_IMAGE);
123
+ return image ? { image } : {};
124
+ }
125
+ function cloudflareWorkerBaseUrl(input) {
126
+ let url;
127
+ try {
128
+ url = new URL(input.trim());
129
+ } catch {
130
+ throw new Error("Cloudflare Worker URL must be a valid HTTPS endpoint");
131
+ }
132
+ if (url.protocol !== "https:" || url.username || url.password || input.includes("?") || input.includes("#")) {
133
+ throw new Error("Cloudflare Worker URL requires HTTPS without credentials, query or fragment");
134
+ }
135
+ return url.origin + url.pathname.replace(/\/+$/, "");
136
+ }
137
+ function sandboxDriverId(input, cfg, env = process.env) {
138
+ if (!isSandboxDriverID(input))
139
+ return;
140
+ if (input === "docker" && !sandboxDriverAuthValues(cfg, input, env))
141
+ return;
142
+ return input;
69
143
  }
70
144
 
71
145
  // src/driver-catalog.ts
72
- var sandboxDriverIds = ["exe", "daytona", "modal", "vercel", "cloudflare", "box", "docker"];
73
- var sandboxDriverCatalog = {
74
- exe: {
75
- id: "exe",
76
- label: "exe.dev",
77
- credentialFields: [{ key: "api_token", label: "API Token", secret: true }],
78
- metadata: {
79
- driverRunsIn: ["worker", "node"],
80
- hostStopBehavior: "not-supported",
81
- hostResumeBehavior: "same-host",
82
- targetAccess: "relay",
83
- secretBrokering: "none",
84
- egressControl: "none",
85
- persistence: {
86
- resume: "same-sandbox",
87
- capture: "none",
88
- clone: true,
89
- captureSource: "not-applicable",
90
- retention: "provider-managed",
91
- restoreMount: "same-resource"
92
- }
93
- }
94
- },
95
- daytona: {
96
- id: "daytona",
97
- label: "Daytona",
98
- credentialFields: [{ key: "api_key", label: "API Key", secret: true }],
99
- metadata: {
100
- driverRunsIn: ["worker", "node"],
101
- hostStopBehavior: "suspends-host",
102
- hostResumeBehavior: "same-host",
103
- targetAccess: "relay",
104
- secretBrokering: "native",
105
- // Daytona is the only driver that can filter egress by NAME as well as
106
- // by address: `domainAllowList` (names) alongside `networkAllowList`
107
- // (CIDRs), with `networkBlockAll` as the deny-all floor.
108
- egressControl: "hosts-and-cidrs",
109
- persistence: {
110
- resume: "same-sandbox",
111
- capture: "filesystem",
112
- clone: false,
113
- captureSource: "preserved",
114
- retention: "provider-managed",
115
- restoreMount: "new-resource"
116
- }
146
+ var localBrokeringTestDriverCatalogEntry = {
147
+ id: "local-brokering-test",
148
+ label: "Local brokering test driver",
149
+ credentialFields: [],
150
+ runtimeNetwork: { controlPlane: "direct", relay: "local" },
151
+ runtimeEnv: "ensure",
152
+ preparedImage: false,
153
+ metadata: {
154
+ driverRunsIn: ["local"],
155
+ hostStopBehavior: "terminates-host",
156
+ hostResumeBehavior: "same-host",
157
+ targetAccess: "loopback",
158
+ secretBrokering: "native",
159
+ egressControl: "hosts",
160
+ persistence: {
161
+ resume: "same-sandbox",
162
+ capture: "none",
163
+ clone: false,
164
+ captureSource: "not-applicable",
165
+ retention: "provider-managed",
166
+ restoreMount: "same-resource"
117
167
  }
118
- },
168
+ }
169
+ };
170
+ var sandboxDriverCatalog = {
119
171
  modal: {
120
172
  id: "modal",
121
- label: "Modal",
122
- credentialFields: [
123
- { key: "token_id", label: "Token ID", secret: true },
124
- { key: "token_secret", label: "Token Secret", secret: true }
125
- ],
173
+ label: sandboxDriverLabels.modal,
174
+ credentialFields: sandboxDriverCredentialFields.modal,
175
+ runtimeNetwork: { controlPlane: "direct", relay: "configured" },
176
+ runtimeEnv: "callback",
177
+ preparedImage: true,
126
178
  metadata: {
127
179
  driverRunsIn: ["node"],
128
180
  hostStopBehavior: "terminates-host",
129
181
  hostResumeBehavior: "replacement-host",
130
182
  targetAccess: "relay",
131
183
  secretBrokering: "none",
132
- // Modal can cut the network entirely (`blockNetwork`) but cannot express
133
- // an allowlist, and its driver throws on a host policy. A blackout is
134
- // not containment for a workspace that has to clone and reach a model.
184
+ // The driver does not install Modal's domain allowlist or alpha sidecar.
135
185
  egressControl: "none",
136
186
  persistence: {
137
187
  resume: "replacement-restore",
@@ -145,20 +195,18 @@ var sandboxDriverCatalog = {
145
195
  },
146
196
  vercel: {
147
197
  id: "vercel",
148
- label: "Vercel",
149
- credentialFields: [
150
- { key: "access_token", label: "Access Token", secret: true },
151
- { key: "team_id", label: "Team ID" },
152
- { key: "project_id", label: "Project ID" }
153
- ],
198
+ label: sandboxDriverLabels.vercel,
199
+ credentialFields: sandboxDriverCredentialFields.vercel,
200
+ runtimeNetwork: { controlPlane: "direct", relay: "configured" },
201
+ runtimeEnv: "callback",
202
+ preparedImage: false,
154
203
  metadata: {
155
204
  driverRunsIn: ["node"],
156
205
  hostStopBehavior: "terminates-host",
157
206
  hostResumeBehavior: "replacement-host",
158
207
  targetAccess: "relay",
159
208
  secretBrokering: "native",
160
- // Vercel's sandbox firewall takes a hostname allow list (or "deny-all"),
161
- // never CIDRs.
209
+ // The driver translates hosts only; the SDK's subnet rules are not wired to net.cidrs.
162
210
  egressControl: "hosts",
163
211
  persistence: {
164
212
  resume: "replacement-restore",
@@ -172,40 +220,42 @@ var sandboxDriverCatalog = {
172
220
  },
173
221
  cloudflare: {
174
222
  id: "cloudflare",
175
- label: "Cloudflare",
176
- credentialFields: [
177
- { key: "api_token", label: "API Token", secret: true },
178
- { key: "worker_url", label: "Worker URL" }
179
- ],
223
+ label: sandboxDriverLabels.cloudflare,
224
+ credentialFields: sandboxDriverCredentialFields.cloudflare,
225
+ runtimeNetwork: { controlPlane: "direct", relay: "configured" },
226
+ runtimeEnv: "callback",
227
+ preparedImage: false,
228
+ billing: cloudflareBilling,
180
229
  metadata: {
181
230
  driverRunsIn: ["worker"],
182
- hostStopBehavior: "not-supported",
231
+ hostStopBehavior: "terminates-host",
183
232
  hostResumeBehavior: "same-host",
233
+ hostWatchesIdle: true,
184
234
  targetAccess: "relay",
185
- secretBrokering: "proxy",
186
- // The Cloudflare Sandbox Worker exposes no egress filter: its broker
187
- // (drivers/cloudflare-egress.ts) is an OPT-IN proxy the sandbox chooses
188
- // to route brokered-credential requests through, not a boundary. The
189
- // driver therefore drops `net` entirely — which is exactly why this
190
- // must be declared, so the manager refuses instead of provisioning a
191
- // sandbox the caller believes is contained.
235
+ secretBrokering: "native",
236
+ // Credential handlers do not restrict unrelated destinations.
192
237
  egressControl: "none",
238
+ // A container snapshot holds the whole root filesystem; the platform keeps it 30 days past its last restore and offers no deletion.
193
239
  persistence: {
194
240
  resume: "replacement-restore",
195
- capture: "directories",
241
+ capture: "filesystem",
196
242
  clone: false,
197
243
  captureSource: "preserved",
198
244
  retention: "provider-managed",
199
- restoreMount: "copy-on-write"
245
+ restoreMount: "new-resource"
200
246
  }
201
247
  }
202
248
  },
203
- box: {
204
- id: "box",
205
- label: "Box",
206
- credentialFields: [{ key: "api_key", label: "API Key", secret: true }],
249
+ boat: {
250
+ id: "boat",
251
+ label: sandboxDriverLabels.boat,
252
+ credentialFields: sandboxDriverCredentialFields.boat,
253
+ runtimeNetwork: { controlPlane: "direct", relay: "configured" },
254
+ runtimeEnv: "callback",
255
+ preparedImage: true,
256
+ billing: boatBilling,
207
257
  metadata: {
208
- driverRunsIn: ["node"],
258
+ driverRunsIn: ["worker", "node"],
209
259
  hostStopBehavior: "suspends-host",
210
260
  hostResumeBehavior: "same-host",
211
261
  targetAccess: "relay",
@@ -218,13 +268,17 @@ var sandboxDriverCatalog = {
218
268
  captureSource: "not-applicable",
219
269
  retention: "provider-managed",
220
270
  restoreMount: "same-resource"
221
- }
271
+ },
272
+ machineClasses: ["small", "default", "large"]
222
273
  }
223
274
  },
224
275
  docker: {
225
276
  id: "docker",
226
- label: "Docker",
227
- credentialFields: [{ key: "image", label: "Image" }],
277
+ label: sandboxDriverLabels.docker,
278
+ credentialFields: sandboxDriverCredentialFields.docker,
279
+ runtimeNetwork: { controlPlane: "docker-host", relay: "configured" },
280
+ runtimeEnv: "callback",
281
+ preparedImage: true,
228
282
  metadata: {
229
283
  driverRunsIn: ["local"],
230
284
  hostStopBehavior: "terminates-host",
@@ -243,106 +297,15 @@ var sandboxDriverCatalog = {
243
297
  }
244
298
  }
245
299
  };
246
- function isSandboxDriverID(input) {
247
- return !!input && sandboxDriverIds.includes(input);
248
- }
249
- function sandboxDriverId(input, cfg, env = process.env) {
250
- if (!isSandboxDriverID(input)) return;
251
- if (input === "docker" && !sandboxDriverAuth(cfg, input, env)) return;
252
- return input;
253
- }
254
- function defaultSandboxDriverID(cfg, env = process.env) {
255
- return sandboxDriverId(cfg?.default_driver, cfg, env) ?? (dockerSandboxDefault(env) && sandboxDriverAuth(cfg, "docker", env) ? "docker" : "daytona");
256
- }
257
- function sandboxDriverAuth(cfg, id, env = process.env) {
258
- if (id === "daytona") return authDaytona(cfg);
259
- if (id === "exe") return authExe(cfg, env);
260
- if (id === "modal") return authModal(cfg, env);
261
- if (id === "vercel") return authVercel(cfg, env);
262
- if (id === "cloudflare") return authCloudflare(cfg, env);
263
- if (id === "box") return authBox(cfg, env);
264
- return authDocker(cfg, env);
265
- }
266
- function hasSandboxDriverAuth(cfg, id, env = process.env) {
267
- return !!sandboxDriverAuth(cfg, id, env);
268
- }
269
- function dockerSandboxDriverEnabled(env = process.env) {
270
- return dockerSandboxEnabled(env);
271
- }
272
- function listSandboxDrivers(cfg, env = process.env, managedDriverIds = /* @__PURE__ */ new Set()) {
273
- const def = defaultSandboxDriverID(cfg, env);
274
- return {
275
- default_driver: def,
276
- drivers: sandboxDriverIds.filter((id) => id !== "docker" || !!sandboxDriverAuth(cfg, "docker", env)).map((id) => {
277
- const configuredFromConfigOrEnv = !!sandboxDriverAuth(cfg, id, env);
278
- const configured = id === "docker" ? configuredFromConfigOrEnv : configuredFromConfigOrEnv || managedDriverIds.has(id);
279
- return {
280
- id,
281
- label: sandboxDriverCatalog[id].label,
282
- fields: sandboxDriverCatalog[id].credentialFields,
283
- configured,
284
- source: configuredFromConfigOrEnv ? "config" : configured ? "managed" : "none",
285
- default: id === def
286
- };
287
- })
288
- };
289
- }
290
- function clean(input) {
291
- const txt = input?.trim();
292
- return txt ? txt : void 0;
293
- }
294
- function enabled(input) {
295
- return ["1", "true", "yes", "on"].includes(input?.trim().toLowerCase() ?? "");
296
- }
297
- function dockerSandboxEnabled(env) {
298
- return enabled(env.CLAXEDO_ENABLE_DOCKER_SANDBOX) || enabled(env.CLAXEDO_DEV_DOCKER_SANDBOX);
299
- }
300
- function dockerSandboxDefault(env) {
301
- return enabled(env.CLAXEDO_DOCKER_SANDBOX_DEFAULT);
302
- }
303
- function authDaytona(cfg) {
304
- const api_key = clean(cfg?.auth?.daytona?.api_key);
305
- return api_key ? { api_key } : void 0;
306
- }
307
- function authExe(cfg, env) {
308
- const api_token = clean(cfg?.auth?.exe?.api_token) ?? clean(env.EXE_DEV_API_TOKEN);
309
- return api_token ? { api_token } : void 0;
310
- }
311
- function authModal(cfg, env) {
312
- const token_id = clean(cfg?.auth?.modal?.token_id) ?? clean(env.MODAL_TOKEN_ID);
313
- const token_secret = clean(cfg?.auth?.modal?.token_secret) ?? clean(env.MODAL_TOKEN_SECRET);
314
- return token_id && token_secret ? { token_id, token_secret } : void 0;
315
- }
316
- function authVercel(cfg, env) {
317
- const access_token = clean(cfg?.auth?.vercel?.access_token) ?? clean(env.VERCEL_TOKEN);
318
- const team_id = clean(cfg?.auth?.vercel?.team_id) ?? clean(env.VERCEL_TEAM_ID);
319
- const project_id = clean(cfg?.auth?.vercel?.project_id) ?? clean(env.VERCEL_PROJECT_ID);
320
- return access_token && team_id && project_id ? { access_token, team_id, project_id } : void 0;
321
- }
322
- function authCloudflare(cfg, env) {
323
- const api_token = clean(cfg?.auth?.cloudflare?.api_token) ?? clean(env.CLOUDFLARE_API_TOKEN);
324
- const worker_url = clean(cfg?.auth?.cloudflare?.worker_url) ?? clean(env.CLOUDFLARE_SANDBOX_WORKER_URL);
325
- return api_token && worker_url ? { api_token, worker_url } : void 0;
326
- }
327
- function authBox(cfg, env) {
328
- const api_key = clean(cfg?.auth?.box?.api_key) ?? clean(env.BOX_API_KEY);
329
- return api_key ? { api_key } : void 0;
330
- }
331
- function authDocker(cfg, env) {
332
- if (!dockerSandboxEnabled(env)) return;
333
- return {
334
- image: clean(cfg?.auth?.docker?.image) ?? clean(env.CLAXEDO_DOCKER_SANDBOX_IMAGE) ?? clean(env.CLAXEDO_SANDBOX_IMAGE) ?? defaultSandboxImage(workspaceRuntimeVersion(), void 0, env)
335
- };
300
+ function dockerSandboxDriverEnabled2(env = process.env) {
301
+ return dockerSandboxDriverEnabled(env);
336
302
  }
337
303
  export {
338
- defaultSandboxDriverID,
339
- dockerSandboxDriverEnabled,
340
- hasSandboxDriverAuth,
341
- isSandboxDriverID,
342
- listSandboxDrivers,
343
- sandboxDriverAuth,
304
+ dockerSandboxDriverEnabled2 as dockerSandboxDriverEnabled,
305
+ localBrokeringTestDriverCatalogEntry,
344
306
  sandboxDriverCatalog,
345
307
  sandboxDriverId,
346
- sandboxDriverIds,
308
+ sandboxMachineCostUsd,
309
+ sandboxMachineRate,
347
310
  validateSandboxPersistenceCapabilities
348
311
  };