@sandboxrouter/sdk 0.2.0 → 0.3.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 (91) hide show
  1. package/README.md +224 -48
  2. package/dist/bench.js +4 -4
  3. package/dist/catalog.d.ts +159 -0
  4. package/dist/catalog.js +448 -15
  5. package/dist/check.d.ts +28 -0
  6. package/dist/check.js +185 -0
  7. package/dist/cli.js +148 -11
  8. package/dist/computers.d.ts +55 -13
  9. package/dist/computers.js +132 -6
  10. package/dist/conformance.d.ts +46 -0
  11. package/dist/conformance.js +65 -0
  12. package/dist/cost.d.ts +67 -0
  13. package/dist/cost.js +153 -0
  14. package/dist/gc.d.ts +29 -0
  15. package/dist/gc.js +54 -0
  16. package/dist/index.d.ts +28 -2
  17. package/dist/index.js +28 -2
  18. package/dist/leaderboard.d.ts +6 -0
  19. package/dist/leaderboard.js +5 -4
  20. package/dist/ledger.d.ts +38 -0
  21. package/dist/ledger.js +89 -0
  22. package/dist/providers/agent37.d.ts +40 -0
  23. package/dist/providers/agent37.js +224 -0
  24. package/dist/providers/agentcore.d.ts +71 -0
  25. package/dist/providers/agentcore.js +446 -0
  26. package/dist/providers/alibaba.d.ts +18 -0
  27. package/dist/providers/alibaba.js +106 -0
  28. package/dist/providers/azure.d.ts +43 -0
  29. package/dist/providers/azure.js +330 -0
  30. package/dist/providers/beam.d.ts +11 -0
  31. package/dist/providers/beam.js +179 -0
  32. package/dist/providers/blaxel.d.ts +3 -1
  33. package/dist/providers/blaxel.js +32 -22
  34. package/dist/providers/boat.js +8 -3
  35. package/dist/providers/cloudflare.js +8 -3
  36. package/dist/providers/codesandbox.d.ts +59 -0
  37. package/dist/providers/codesandbox.js +287 -0
  38. package/dist/providers/daytona.d.ts +25 -4
  39. package/dist/providers/daytona.js +449 -28
  40. package/dist/providers/dedalus.d.ts +12 -0
  41. package/dist/providers/dedalus.js +244 -0
  42. package/dist/providers/deno.d.ts +50 -0
  43. package/dist/providers/deno.js +170 -0
  44. package/dist/providers/docker.js +11 -5
  45. package/dist/providers/e2b.d.ts +70 -3
  46. package/dist/providers/e2b.js +376 -8
  47. package/dist/providers/exedev.js +17 -5
  48. package/dist/providers/freestyle.d.ts +49 -0
  49. package/dist/providers/freestyle.js +261 -0
  50. package/dist/providers/hopx.js +27 -18
  51. package/dist/providers/instabox.d.ts +76 -0
  52. package/dist/providers/instabox.js +360 -0
  53. package/dist/providers/koyeb.d.ts +71 -0
  54. package/dist/providers/koyeb.js +379 -0
  55. package/dist/providers/lambda.d.ts +51 -0
  56. package/dist/providers/lambda.js +467 -0
  57. package/dist/providers/langsmith.d.ts +16 -0
  58. package/dist/providers/langsmith.js +149 -0
  59. package/dist/providers/limrun.d.ts +77 -0
  60. package/dist/providers/limrun.js +626 -0
  61. package/dist/providers/maritime.d.ts +5 -1
  62. package/dist/providers/maritime.js +39 -8
  63. package/dist/providers/mobilerun.d.ts +44 -0
  64. package/dist/providers/mobilerun.js +417 -0
  65. package/dist/providers/modal.js +12 -4
  66. package/dist/providers/morph.js +12 -4
  67. package/dist/providers/northflank.js +11 -13
  68. package/dist/providers/novita.d.ts +12 -0
  69. package/dist/providers/novita.js +81 -0
  70. package/dist/providers/openscale.d.ts +17 -0
  71. package/dist/providers/openscale.js +87 -0
  72. package/dist/providers/orgo.d.ts +45 -0
  73. package/dist/providers/orgo.js +414 -0
  74. package/dist/providers/sail.d.ts +32 -0
  75. package/dist/providers/sail.js +372 -0
  76. package/dist/providers/superserve.d.ts +25 -0
  77. package/dist/providers/superserve.js +337 -0
  78. package/dist/providers/tensorlake.js +17 -14
  79. package/dist/providers/upstash.d.ts +30 -0
  80. package/dist/providers/upstash.js +258 -0
  81. package/dist/providers/vercel.js +14 -3
  82. package/dist/providers/workspaces.d.ts +60 -0
  83. package/dist/providers/workspaces.js +662 -0
  84. package/dist/router.d.ts +36 -5
  85. package/dist/router.js +149 -19
  86. package/dist/server.d.ts +1 -1
  87. package/dist/server.js +22 -3
  88. package/dist/types.d.ts +13 -5
  89. package/dist/util.d.ts +28 -1
  90. package/dist/util.js +56 -7
  91. package/package.json +80 -5
@@ -0,0 +1,261 @@
1
+ import { createHash } from "node:crypto";
2
+ import { ProviderError } from "../types.js";
3
+ import { dirname, toBytes, wrapCommand } from "../util.js";
4
+ /**
5
+ * Freestyle VMs over the public REST API (no SDK needed). Auth: Authorization: Bearer
6
+ * <FREESTYLE_API_KEY>, base https://api.freestyle.sh. Errors are {code, message}.
7
+ * POST /v5/vms {snapshotId, firewall:{rules}, ttlSeconds, metadata} -> Vm (201, booting)
8
+ * GET /v5/vms/:id -> Vm {id, state: starting|running|pausing|paused|stopped, resources}
9
+ * POST /v5/vms/:id/exec-await {command, env, timeoutMs} -> {statusCode|null, stdout, stderr}
10
+ * PUT /v5/vms/:id/fs/write?path=P&sha256=H raw bytes, atomic (204)
11
+ * GET /v5/vms/:id/fs/read?path=P raw bytes (404 when missing; works while paused)
12
+ * POST /v5/vms/:id/fs/mkdir {path} (creates parents)
13
+ * POST /v5/vms/:id/pause, POST /v5/vms/:id/start, POST /v5/vms/:id/resize {cpu, memory(MiB)}
14
+ * DELETE /v5/vms/:id
15
+ * Long calls: with `x-freestyle-background-after-secs: N` a request still running after N s
16
+ * answers 202 {requestId} and GET /v5/background-requests/:id replays its response once done (202
17
+ * while pending). That is what lets exec run past the 5-minute inline cap (up to 24 h).
18
+ * Sizes come from the base snapshot (FREESTYLE_SIZES): the adapter boots the smallest
19
+ * freestyle/ubuntu-* that fits. A custom image.freestyle (snapshot id/slug) boots at its own size
20
+ * and is grown with resize when the spec asks for more. A VM gets no network unless allowed, so the
21
+ * adapter opens outbound Internet, like other providers' defaults. exec has no streaming (output
22
+ * streams only over PTY WebSockets), so onStdout/onStderr get the whole output once it finishes.
23
+ * pause() keeps memory and disk; connect() and a paused exec start the VM again.
24
+ * Docs: https://www.freestyle.sh/docs/vms, https://www.freestyle.sh/docs/vms/lifecycle,
25
+ * https://www.freestyle.sh/docs/vms/files, https://www.freestyle.sh/docs/vms/base-snapshots,
26
+ * https://www.freestyle.sh/docs/vms/pricing-and-limits, https://www.freestyle.sh/openapi.json
27
+ */
28
+ const ID = "freestyle";
29
+ const BACKGROUND_AFTER_SECS = "5";
30
+ const READY_TIMEOUT_MS = 3 * 60_000;
31
+ const MAX_EXEC_MS = 86_400_000;
32
+ const OUTBOUND_INTERNET = { rules: [{ action: "allow", source: {}, destination: { public: true } }] };
33
+ /**
34
+ * Freestyle's Ubuntu base snapshots (hardware is baked into each), from
35
+ * https://www.freestyle.sh/docs/vms/base-snapshots, priced at the list rates on
36
+ * https://www.freestyle.sh/docs/vms/pricing-and-limits ($0.04032/vCPU-h, $0.0129/GiB-h memory,
37
+ * $0.000086/GiB-h disk), checked 2026-11-04. Free tops out at `ubuntu`, Hobby at `ubuntu-lg`,
38
+ * Pro at `ubuntu-2xl`.
39
+ */
40
+ export const FREESTYLE_SIZES = [
41
+ { snapshot: "freestyle/ubuntu-sm", vcpu: 2, memoryGb: 4, diskGb: 16 },
42
+ { snapshot: "freestyle/ubuntu", vcpu: 4, memoryGb: 8, diskGb: 32 },
43
+ { snapshot: "freestyle/ubuntu-lg", vcpu: 8, memoryGb: 16, diskGb: 64 },
44
+ { snapshot: "freestyle/ubuntu-xl", vcpu: 16, memoryGb: 32, diskGb: 128 },
45
+ { snapshot: "freestyle/ubuntu-2xl", vcpu: 32, memoryGb: 64, diskGb: 128 },
46
+ ].map((s) => ({ ...s, usdHour: round(s.vcpu * 0.04032 + s.memoryGb * 0.0129 + s.diskGb * 0.000086) }));
47
+ /** Smallest Ubuntu base snapshot with at least the requested vCPU and memory, or undefined. */
48
+ export function freestyleSize(vcpu, memoryGb) {
49
+ return FREESTYLE_SIZES.find((s) => s.vcpu >= vcpu && s.memoryGb >= memoryGb);
50
+ }
51
+ export class FreestyleProvider {
52
+ apiKey;
53
+ baseUrl;
54
+ pollMs;
55
+ id = ID;
56
+ constructor(apiKey = process.env.FREESTYLE_API_KEY, baseUrl = process.env.FREESTYLE_API_URL ?? "https://api.freestyle.sh",
57
+ /** How often to poll a backgrounded request or a booting VM. */
58
+ pollMs = 2000) {
59
+ this.apiKey = apiKey;
60
+ this.baseUrl = baseUrl;
61
+ this.pollMs = pollMs;
62
+ }
63
+ configured() {
64
+ return !!this.apiKey;
65
+ }
66
+ /**
67
+ * @internal One API call. With `background`, a call still running after 5 s comes back as 202
68
+ * and is polled at /v5/background-requests/:id until its own response is ready.
69
+ */
70
+ async request(method, path, init = {}) {
71
+ if (!this.apiKey)
72
+ throw new ProviderError(ID, "FREESTYLE_API_KEY is not set");
73
+ const headers = { Authorization: `Bearer ${this.apiKey}` };
74
+ if (init.background)
75
+ headers["x-freestyle-background-after-secs"] = BACKGROUND_AFTER_SECS;
76
+ let body;
77
+ if (init.json !== undefined) {
78
+ headers["Content-Type"] = "application/json";
79
+ body = JSON.stringify(init.json);
80
+ }
81
+ else if (init.bytes) {
82
+ headers["Content-Type"] = "application/octet-stream";
83
+ body = init.bytes;
84
+ }
85
+ let res = await fetch(`${this.baseUrl}${path}`, { method, headers, body, signal: init.signal });
86
+ if (init.background && res.status === 202) {
87
+ const accepted = (await res.json().catch(() => ({})));
88
+ const requestId = res.headers.get("x-freestyle-background-request-id") ?? accepted.requestId;
89
+ const resultPath = accepted.resultUrl ?? (requestId ? `/v5/background-requests/${encodeURIComponent(requestId)}` : undefined);
90
+ if (!resultPath)
91
+ throw new ProviderError(ID, `${method} ${path.split("?")[0]} -> 202 without a background request id`, 202);
92
+ for (;;) {
93
+ await sleep(this.pollMs, init.signal);
94
+ res = await fetch(resultPath.startsWith("http") ? resultPath : `${this.baseUrl}${resultPath}`, {
95
+ headers: { Authorization: `Bearer ${this.apiKey}` },
96
+ signal: init.signal,
97
+ });
98
+ if (res.status !== 202)
99
+ break;
100
+ await res.body?.cancel().catch(() => { });
101
+ }
102
+ }
103
+ if (!res.ok) {
104
+ const text = await res.text();
105
+ let detail = text.slice(0, 300);
106
+ try {
107
+ const j = JSON.parse(text);
108
+ if (j?.message)
109
+ detail = `${j.code ? `${j.code}: ` : ""}${j.message}`;
110
+ }
111
+ catch {
112
+ /* plain-text body */
113
+ }
114
+ throw new ProviderError(ID, `${method} ${path.split("?")[0]} -> ${res.status} ${detail}`, res.status);
115
+ }
116
+ return res;
117
+ }
118
+ /** @internal JSON call. */
119
+ async json(method, path, init = {}) {
120
+ const text = await (await this.request(method, path, init)).text();
121
+ return (text ? JSON.parse(text) : {});
122
+ }
123
+ async create(spec) {
124
+ const vcpu = spec.vcpu ?? 2;
125
+ const memoryGb = spec.memoryGb ?? 4;
126
+ const custom = spec.image?.freestyle;
127
+ const size = freestyleSize(vcpu, memoryGb);
128
+ if (!custom && !size)
129
+ throw new ProviderError(ID, `no Freestyle size has ${vcpu} vCPU / ${memoryGb} GB (max ubuntu-2xl: 32 vCPU / 64 GiB)`);
130
+ const body = {
131
+ snapshotId: custom ?? size.snapshot,
132
+ firewall: OUTBOUND_INTERNET,
133
+ ttlSeconds: Math.max(60, Math.round((spec.timeoutMinutes ?? 30) * 60)),
134
+ };
135
+ if (spec.metadata)
136
+ body.metadata = spec.metadata;
137
+ const vm = await this.json("POST", "/v5/vms", { json: body, background: true });
138
+ const box = new FreestyleBox(this, vm.id, spec.env);
139
+ try {
140
+ const ready = await box.waitRunning();
141
+ // A custom snapshot boots at its own size; grow it (resize is grow-only) when the spec wants more.
142
+ const res = ready.resources;
143
+ if (custom && res && (res.cpu < Math.ceil(vcpu) || res.memory < Math.ceil(memoryGb * 1024))) {
144
+ await this.json("POST", `/v5/vms/${encodeURIComponent(vm.id)}/resize`, {
145
+ json: { cpu: Math.max(res.cpu, Math.ceil(vcpu)), memory: Math.max(res.memory, Math.ceil(memoryGb * 1024)) },
146
+ background: true,
147
+ });
148
+ }
149
+ }
150
+ catch (err) {
151
+ await box.kill().catch(() => { });
152
+ throw err;
153
+ }
154
+ return box;
155
+ }
156
+ /** Reattach by VM id (or slug); a paused or stopped VM is started again. */
157
+ async connect(nativeId) {
158
+ const box = new FreestyleBox(this, nativeId);
159
+ await box.waitRunning();
160
+ return box;
161
+ }
162
+ /** @internal */
163
+ get poll() {
164
+ return this.pollMs;
165
+ }
166
+ }
167
+ class FreestyleBox {
168
+ p;
169
+ nativeId;
170
+ env;
171
+ constructor(p, nativeId, env) {
172
+ this.p = p;
173
+ this.nativeId = nativeId;
174
+ this.env = env;
175
+ }
176
+ get path() {
177
+ return `/v5/vms/${encodeURIComponent(this.nativeId)}`;
178
+ }
179
+ /** Wait until the VM runs, starting it when it is paused or stopped. */
180
+ async waitRunning() {
181
+ const deadline = Date.now() + READY_TIMEOUT_MS;
182
+ let started = false;
183
+ for (;;) {
184
+ const vm = await this.p.json("GET", this.path);
185
+ if (vm.state === "running")
186
+ return vm;
187
+ if ((vm.state === "paused" || vm.state === "stopped") && !started) {
188
+ await this.p.json("POST", `${this.path}/start`, { background: true });
189
+ started = true;
190
+ continue;
191
+ }
192
+ if (Date.now() > deadline)
193
+ throw new ProviderError(ID, `VM ${this.nativeId} still ${vm.state} after ${READY_TIMEOUT_MS / 1000}s`);
194
+ await sleep(Math.min(this.p.poll, 500));
195
+ }
196
+ }
197
+ async exec(cmd, opts = {}) {
198
+ const t0 = Date.now();
199
+ const secs = opts.timeoutSeconds ?? 60;
200
+ const body = {
201
+ command: wrapCommand(cmd, { cwd: opts.cwd }),
202
+ timeoutMs: Math.min(MAX_EXEC_MS, Math.max(1, Math.round(secs * 1000))),
203
+ };
204
+ const env = { ...this.env, ...opts.env };
205
+ if (Object.keys(env).length)
206
+ body.env = env;
207
+ let r;
208
+ try {
209
+ r = await this.p.json("POST", `${this.path}/exec-await`, { json: body, background: true });
210
+ }
211
+ catch (err) {
212
+ // 409 also means "stopped responding mid-command" (VM_NON_RESPONSIVE): never re-run that one.
213
+ if (!(err instanceof ProviderError) || err.status !== 409 || /VM_NON_RESPONSIVE/.test(err.message))
214
+ throw err;
215
+ const vm = await this.p.json("GET", this.path);
216
+ if (vm.state === "running")
217
+ throw err;
218
+ await this.waitRunning();
219
+ r = await this.p.json("POST", `${this.path}/exec-await`, { json: body, background: true });
220
+ }
221
+ if (r.statusCode === null || r.statusCode === undefined)
222
+ throw new ProviderError(ID, `command timed out after ${secs}s`);
223
+ const stdout = r.stdout ?? "";
224
+ const stderr = r.stderr ?? "";
225
+ if (stdout)
226
+ opts.onStdout?.(stdout);
227
+ if (stderr)
228
+ opts.onStderr?.(stderr);
229
+ return { exitCode: r.statusCode, stdout, stderr, durationMs: Date.now() - t0 };
230
+ }
231
+ async writeFile(path, content) {
232
+ const bytes = toBytes(content);
233
+ // Best effort (whether mkdir of an existing directory errors is not documented); the write
234
+ // itself reports any real problem.
235
+ const dir = dirname(path);
236
+ if (dir !== "/")
237
+ await this.p.request("POST", `${this.path}/fs/mkdir`, { json: { path: dir }, background: true }).catch(() => { });
238
+ const q = new URLSearchParams({ path, sha256: createHash("sha256").update(bytes).digest("hex") });
239
+ await this.p.request("PUT", `${this.path}/fs/write?${q}`, { bytes, background: true });
240
+ }
241
+ async readFile(path) {
242
+ const res = await this.p.request("GET", `${this.path}/fs/read?${new URLSearchParams({ path })}`);
243
+ return new Uint8Array(await res.arrayBuffer());
244
+ }
245
+ async pause() {
246
+ await this.p.request("POST", `${this.path}/pause`, { background: true });
247
+ }
248
+ async kill() {
249
+ await this.p.request("DELETE", this.path);
250
+ }
251
+ }
252
+ function round(n) {
253
+ return Math.round(n * 1e5) / 1e5;
254
+ }
255
+ function sleep(ms, signal) {
256
+ return new Promise((resolve, reject) => {
257
+ // Not unref'd: between polls nothing else may keep the process alive.
258
+ const t = setTimeout(resolve, ms);
259
+ signal?.addEventListener("abort", () => (clearTimeout(t), reject(signal.reason)), { once: true });
260
+ });
261
+ }
@@ -1,5 +1,5 @@
1
1
  import { ProviderError } from "../types.js";
2
- import { optionalImport, toBytes } from "../util.js";
2
+ import { DEFAULT_EXEC_TIMEOUT_S, optionalImport, timeoutError, toBytes } from "../util.js";
3
3
  /** Public template used when spec.image.hopx is not set. */
4
4
  const DEFAULT_TEMPLATE = "code-interpreter";
5
5
  /**
@@ -54,9 +54,11 @@ class HopxBox {
54
54
  if (opts.onStdout || opts.onStderr)
55
55
  return this.execStreaming(cmd, opts);
56
56
  const t0 = Date.now();
57
+ const seconds = opts.timeoutSeconds ?? DEFAULT_EXEC_TIMEOUT_S;
57
58
  try {
59
+ // The agent kills the command at `timeout` and reports it as an EXECUTION_TIMEOUT error.
58
60
  const r = await this.sbx.commands.run(cmd, {
59
- timeout: opts.timeoutSeconds ?? 60,
61
+ timeout: seconds,
60
62
  workingDir: opts.cwd,
61
63
  env: opts.env,
62
64
  });
@@ -64,23 +66,23 @@ class HopxBox {
64
66
  return { exitCode: r.exit_code ?? -1, stdout: r.stdout ?? "", stderr: r.stderr ?? "", durationMs: Date.now() - t0 };
65
67
  }
66
68
  catch (err) {
67
- throw fail(err);
69
+ throw fail(err, seconds);
68
70
  }
69
71
  }
70
72
  /** Streams over the agent's WebSocket (/execute/stream) with the code run as bash. */
71
73
  async execStreaming(cmd, opts) {
72
74
  const t0 = Date.now();
73
- const seconds = opts.timeoutSeconds ?? 60;
75
+ const seconds = opts.timeoutSeconds ?? DEFAULT_EXEC_TIMEOUT_S;
74
76
  let stdout = "";
75
77
  let stderr = "";
76
78
  let exitCode;
79
+ const stream = this.sbx.runCodeStream(cmd, {
80
+ language: "bash",
81
+ timeout: seconds,
82
+ workingDir: opts.cwd,
83
+ env: opts.env,
84
+ });
77
85
  const run = async () => {
78
- const stream = this.sbx.runCodeStream(cmd, {
79
- language: "bash",
80
- timeout: seconds,
81
- workingDir: opts.cwd,
82
- env: opts.env,
83
- });
84
86
  for await (const m of stream) {
85
87
  if (m.type === "stdout") {
86
88
  stdout += m.data;
@@ -94,23 +96,27 @@ class HopxBox {
94
96
  exitCode = m.exit_code;
95
97
  }
96
98
  else if (m.type === "error") {
97
- const msg = m.code === "EXECUTION_TIMEOUT" ? `command timed out after ${seconds}s` : m.error;
98
- throw new ProviderError("hopx", msg);
99
+ throw m.code === "EXECUTION_TIMEOUT" ? timeoutError("hopx", seconds) : new ProviderError("hopx", m.error);
99
100
  }
100
101
  }
101
102
  };
102
103
  try {
103
104
  // The agent enforces the timeout; the extra grace covers a stream that never closes.
104
- const graceMs = (seconds + 30) * 1000;
105
- const timedOut = await Promise.race([run().then(() => false), sleep(graceMs).then(() => true)]);
106
- if (timedOut)
107
- throw new ProviderError("hopx", `command timed out after ${seconds}s`);
105
+ const graceMs = (seconds + 15) * 1000;
106
+ const finished = run();
107
+ const timedOut = await Promise.race([finished.then(() => false), sleep(graceMs).then(() => true)]);
108
+ if (timedOut) {
109
+ // Close the stream (and its WebSocket) now that nobody will read it.
110
+ finished.catch(() => { });
111
+ await stream.return?.().catch(() => { });
112
+ throw timeoutError("hopx", seconds);
113
+ }
108
114
  if (exitCode === undefined)
109
115
  throw new ProviderError("hopx", "stream closed before the command finished");
110
116
  return { exitCode, stdout, stderr, durationMs: Date.now() - t0 };
111
117
  }
112
118
  catch (err) {
113
- throw fail(err);
119
+ throw fail(err, seconds);
114
120
  }
115
121
  }
116
122
  async writeFile(path, content) {
@@ -157,9 +163,12 @@ const STATUS_BY_NAME = {
157
163
  FileNotFoundError: 404,
158
164
  SandboxExpiredError: 410,
159
165
  };
160
- function fail(err) {
166
+ /** Map an SDK error; with `timeoutSeconds`, the agent's execution-timeout errors become the contract's timeout error. */
167
+ function fail(err, timeoutSeconds) {
161
168
  if (err instanceof ProviderError)
162
169
  return err;
170
+ if (timeoutSeconds !== undefined && (err?.code === "EXECUTION_TIMEOUT" || err?.name === "TimeoutError"))
171
+ return timeoutError("hopx", timeoutSeconds);
163
172
  const status = err?.statusCode ?? err?.response?.status ?? STATUS_BY_NAME[err?.name];
164
173
  return new ProviderError("hopx", err?.message ?? String(err), status);
165
174
  }
@@ -0,0 +1,76 @@
1
+ import { type Provider, type ProviderSandbox, type SandboxSpec } from "../types.js";
2
+ /** Sizes on api.instabox.sh (vCPUs / GiB); which ones an org may use depends on its plan. */
3
+ export declare const INSTABOX_SIZES: readonly [{
4
+ readonly vcpu: 2;
5
+ readonly memoryGb: 4;
6
+ }, {
7
+ readonly vcpu: 4;
8
+ readonly memoryGb: 8;
9
+ }, {
10
+ readonly vcpu: 8;
11
+ readonly memoryGb: 16;
12
+ }, {
13
+ readonly vcpu: 16;
14
+ readonly memoryGb: 32;
15
+ }, {
16
+ readonly vcpu: 32;
17
+ readonly memoryGb: 64;
18
+ }];
19
+ /** The smallest size with at least the requested vCPUs and memory, or undefined if none fits. */
20
+ export declare function instaboxSize(vcpu: number, memoryGb: number): {
21
+ readonly vcpu: 2;
22
+ readonly memoryGb: 4;
23
+ } | {
24
+ readonly vcpu: 4;
25
+ readonly memoryGb: 8;
26
+ } | {
27
+ readonly vcpu: 8;
28
+ readonly memoryGb: 16;
29
+ } | {
30
+ readonly vcpu: 16;
31
+ readonly memoryGb: 32;
32
+ } | {
33
+ readonly vcpu: 32;
34
+ readonly memoryGb: 64;
35
+ } | undefined;
36
+ interface Operation {
37
+ id?: string;
38
+ machineId?: string;
39
+ type?: string;
40
+ state?: string;
41
+ phase?: string;
42
+ error?: {
43
+ code?: string;
44
+ message?: string;
45
+ retryable?: boolean;
46
+ retryAfterSeconds?: number;
47
+ } | null;
48
+ }
49
+ export declare class InstaboxProvider implements Provider {
50
+ private apiKey;
51
+ private baseUrl;
52
+ readonly id: "instabox";
53
+ constructor(apiKey?: string | undefined, baseUrl?: string);
54
+ configured(): boolean;
55
+ /** @internal Send a request; non-2xx answers throw InstaboxError. */
56
+ request(method: string, path: string, init?: {
57
+ json?: unknown;
58
+ body?: Uint8Array;
59
+ headers?: Record<string, string>;
60
+ idempotent?: boolean;
61
+ timeoutMs?: number;
62
+ }): Promise<Response>;
63
+ /** @internal */
64
+ json<T>(method: string, path: string, json?: unknown, opts?: {
65
+ idempotent?: boolean;
66
+ headers?: Record<string, string>;
67
+ }): Promise<T>;
68
+ /** @internal Follow an operation until it succeeds; a failed one throws. */
69
+ waitOperation(op: Operation, what: string): Promise<Operation>;
70
+ /** @internal Wait until the machine runs and takes commands, starting or resuming it when it is stopped or paused. */
71
+ ensureRunning(id: string): Promise<void>;
72
+ private createMachine;
73
+ create(spec: SandboxSpec): Promise<ProviderSandbox>;
74
+ connect(nativeId: string): Promise<ProviderSandbox>;
75
+ }
76
+ export {};