@sandboxrouter/sdk 0.3.4 → 0.3.5
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.
- package/README.md +16 -16
- package/dist/providers/agentcore.d.ts +9 -0
- package/dist/providers/agentcore.js +44 -3
- package/dist/providers/freestyle.js +11 -4
- package/dist/providers/modal.js +5 -1
- package/dist/providers/sprites.js +4 -3
- package/dist/providers/vercel.js +5 -1
- package/dist/server.d.ts +1 -1
- package/dist/verified.js +16 -5
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -41,39 +41,39 @@ List price while running, 2 vCPU / 4 GB, cheapest first; waitlisted sign-ups fol
|
|
|
41
41
|
|
|
42
42
|
| Provider | $/hr | Plan needed | Real-account check | Source |
|
|
43
43
|
|---|---|---|---|---|
|
|
44
|
-
| [Agent37](https://sandboxrouter.vercel.app/providers/agent37) | $0.007 | none |
|
|
44
|
+
| [Agent37](https://sandboxrouter.vercel.app/providers/agent37) | $0.007 | none | passed (2026-11-11) | [pricing](https://www.agent37.com/docs/agents-api/billing) |
|
|
45
45
|
| [Boat](https://sandboxrouter.vercel.app/providers/boat) | $0.018 | $20/mo (credited) | not run yet | [pricing](https://docs.boat.dev/pricing.md) |
|
|
46
|
-
| [Maritime](https://sandboxrouter.vercel.app/providers/maritime) | $0.022 | $20/mo (credited) | passed (2026-11-
|
|
47
|
-
| [Sailboxes (Sail Research)](https://sandboxrouter.vercel.app/providers/sail) | up to $0.062 | none | passed (2026-11-
|
|
46
|
+
| [Maritime](https://sandboxrouter.vercel.app/providers/maritime) | $0.022 | $20/mo (credited) | passed (2026-11-11) | [pricing](https://maritime.sh/pricing) |
|
|
47
|
+
| [Sailboxes (Sail Research)](https://sandboxrouter.vercel.app/providers/sail) | up to $0.062 | none | passed (2026-11-11) | [pricing](https://docs.sailresearch.com/sailboxes-pricing.md) |
|
|
48
48
|
| [Northflank](https://sandboxrouter.vercel.app/providers/northflank) | $0.067 | none | not run yet | [pricing](https://northflank.com/pricing) |
|
|
49
49
|
| [Morph Cloud](https://sandboxrouter.vercel.app/providers/morph) | $0.100 | none | not run yet | [pricing](https://cloud.morph.so/web/pricing) |
|
|
50
50
|
| [exe.dev](https://sandboxrouter.vercel.app/providers/exedev) | $0.105 | $15/mo | not run yet | [pricing](https://exe.dev/docs/standalone-vms.md) |
|
|
51
|
-
| [Novita AI Agent Sandbox](https://sandboxrouter.vercel.app/providers/novita) | $0.117 | none |
|
|
52
|
-
| [Freestyle](https://sandboxrouter.vercel.app/providers/freestyle) | $0.134 | none |
|
|
51
|
+
| [Novita AI Agent Sandbox](https://sandboxrouter.vercel.app/providers/novita) | $0.117 | none | passed (2026-11-11) | [pricing](https://docs.novita.ai/guides/sandbox-pricing) |
|
|
52
|
+
| [Freestyle](https://sandboxrouter.vercel.app/providers/freestyle) | $0.134 | none | passed (2026-11-11) | [pricing](https://www.freestyle.sh/docs/vms/pricing-and-limits) |
|
|
53
53
|
| [Beam](https://sandboxrouter.vercel.app/providers/beam) | $0.140 | $20/mo (credited) | not run yet | [pricing](https://www.beam.cloud/pricing) |
|
|
54
54
|
| [CodeSandbox SDK (Together)](https://sandboxrouter.vercel.app/providers/codesandbox) | $0.149 | none | not run yet | [pricing](https://docs.together.ai/docs/together-code-sandbox-legacy) |
|
|
55
|
-
| [Fly.io Sprites](https://sandboxrouter.vercel.app/providers/sprites) | up to $0.164 | none |
|
|
56
|
-
| [Blaxel](https://sandboxrouter.vercel.app/providers/blaxel) | $0.166 | none | passed (2026-11-
|
|
55
|
+
| [Fly.io Sprites](https://sandboxrouter.vercel.app/providers/sprites) | up to $0.164 | none | passed (2026-11-11) | [pricing](https://fly.io/sprites) |
|
|
56
|
+
| [Blaxel](https://sandboxrouter.vercel.app/providers/blaxel) | $0.166 | none | passed (2026-11-11) | [pricing](https://blaxel.ai/pricing) |
|
|
57
57
|
| [HOPX](https://sandboxrouter.vercel.app/providers/hopx) | $0.166 | none | not run yet | [pricing](https://hopx.ai/pricing) |
|
|
58
|
-
| [Superserve](https://sandboxrouter.vercel.app/providers/superserve) | $0.166 | maybe $20/mo (credited) |
|
|
58
|
+
| [Superserve](https://sandboxrouter.vercel.app/providers/superserve) | $0.166 | maybe $20/mo (credited) | passed (2026-11-11) | [pricing](https://superserve.ai/pricing) |
|
|
59
59
|
| [Tensorlake](https://sandboxrouter.vercel.app/providers/tensorlake) | up to $0.200 | none | not run yet | [pricing](https://www.tensorlake.ai/pricing) |
|
|
60
60
|
| [Upstash Box](https://sandboxrouter.vercel.app/providers/upstash) | up to $0.200 | none | not run yet | [pricing](https://upstash.com/pricing/box) |
|
|
61
|
-
| [Cloudflare Sandbox](https://sandboxrouter.vercel.app/providers/cloudflare) | up to $0.216 | $5/mo |
|
|
62
|
-
| [Amazon Bedrock AgentCore Code Interpreter](https://sandboxrouter.vercel.app/providers/agentcore) | up to $0.217 | none |
|
|
63
|
-
| [Modal](https://sandboxrouter.vercel.app/providers/modal) | up to $0.238 | none |
|
|
64
|
-
| [AWS Lambda MicroVMs](https://sandboxrouter.vercel.app/providers/lambda) | $0.252 | none |
|
|
61
|
+
| [Cloudflare Sandbox](https://sandboxrouter.vercel.app/providers/cloudflare) | up to $0.216 | $5/mo | passed (2026-11-11) | [pricing](https://developers.cloudflare.com/containers/platform/pricing/) |
|
|
62
|
+
| [Amazon Bedrock AgentCore Code Interpreter](https://sandboxrouter.vercel.app/providers/agentcore) | up to $0.217 | none | passed (2026-11-11) | [pricing](https://aws.amazon.com/bedrock/agentcore/pricing/) |
|
|
63
|
+
| [Modal](https://sandboxrouter.vercel.app/providers/modal) | up to $0.238 | none | passed (2026-11-11) | [pricing](https://modal.com/pricing) |
|
|
64
|
+
| [AWS Lambda MicroVMs](https://sandboxrouter.vercel.app/providers/lambda) | $0.252 | none | passed (2026-11-11) | [pricing](https://aws.amazon.com/lambda/pricing/) |
|
|
65
65
|
| [Deno Sandbox](https://sandboxrouter.vercel.app/providers/deno) | up to $0.300 | $20/mo | not run yet | [pricing](https://deno.com/sandbox) |
|
|
66
66
|
| [Runloop](https://sandboxrouter.vercel.app/providers/runloop) | $0.317 | none | not run yet | [pricing](https://www.runloop.ai/pricing) |
|
|
67
|
-
| [Vercel Sandbox](https://sandboxrouter.vercel.app/providers/vercel) | up to $0.341 | none |
|
|
67
|
+
| [Vercel Sandbox](https://sandboxrouter.vercel.app/providers/vercel) | up to $0.341 | none | passed (2026-11-11) | [pricing](https://vercel.com/docs/vercel-sandbox/pricing) |
|
|
68
68
|
| [InstaBox (sign-up waitlisted)](https://sandboxrouter.vercel.app/providers/instabox) | $0.017 | none | not run yet | [pricing](https://instabox.sh/docs/pricing.md) |
|
|
69
69
|
| [Koyeb Sandboxes (not taking new accounts)](https://sandboxrouter.vercel.app/providers/koyeb) | $0.058 | $29/mo | not run yet | [pricing](https://www.koyeb.com/docs/reference/instances) |
|
|
70
70
|
| [Dedalus Machines (sign-up waitlisted)](https://sandboxrouter.vercel.app/providers/dedalus) | $0.149 | none | not run yet | [pricing](https://docs.dedaluslabs.ai/dcs/dm/pricing) |
|
|
71
71
|
| [LangSmith Sandboxes (sign-up waitlisted)](https://sandboxrouter.vercel.app/providers/langsmith) | $0.189 | none | not run yet | [pricing](https://www.langchain.com/pricing) |
|
|
72
|
-
| [OpenScale Sandboxes](https://sandboxrouter.vercel.app/providers/openscale) | skipped (default image is 2 vCPU / 1 GB; a bigger size needs image.openscale) | none |
|
|
72
|
+
| [OpenScale Sandboxes](https://sandboxrouter.vercel.app/providers/openscale) | skipped (default image is 2 vCPU / 1 GB; a bigger size needs image.openscale) | none | passed (2026-11-11) | [pricing](https://openscale.so/sandboxes) |
|
|
73
73
|
| [Azure Container Apps dynamic sessions](https://sandboxrouter.vercel.app/providers/azure) | skipped (max 1 vCPU) | none | not run yet | [pricing](https://learn.microsoft.com/en-us/azure/container-apps/billing#dynamic-sessions) |
|
|
74
|
-
| [Daytona](https://sandboxrouter.vercel.app/providers/daytona) | skipped (default image is 1 vCPU / 1 GB; a bigger size needs image.daytona) | none | passed (2026-11-
|
|
74
|
+
| [Daytona](https://sandboxrouter.vercel.app/providers/daytona) | skipped (default image is 1 vCPU / 1 GB; a bigger size needs image.daytona) | none | passed (2026-11-11) | [pricing](https://www.daytona.io/pricing) |
|
|
75
75
|
| [Alibaba Cloud Agent Sandbox](https://sandboxrouter.vercel.app/providers/alibaba) | skipped (max 2 GB memory) | none | not run yet | [pricing](https://www.alibabacloud.com/help/en/agent-sandbox/product-overview/billing-overview) |
|
|
76
|
-
| [E2B](https://sandboxrouter.vercel.app/providers/e2b) | skipped (default image is 2 vCPU / 0.5 GB; a bigger size needs image.e2b) | none | passed (2026-11-
|
|
76
|
+
| [E2B](https://sandboxrouter.vercel.app/providers/e2b) | skipped (default image is 2 vCPU / 0.5 GB; a bigger size needs image.e2b) | none | passed (2026-11-11) | [pricing](https://e2b.dev/pricing) |
|
|
77
77
|
| [Docker (local)](https://sandboxrouter.vercel.app/providers/docker) | free | none | passed (2026-11-09) | [pricing](https://docs.docker.com/engine/) |
|
|
78
78
|
|
|
79
79
|
Checked 2026-11-04 to 2026-11-06.
|
|
@@ -69,3 +69,12 @@ export declare class AgentCoreProvider implements Provider {
|
|
|
69
69
|
create(spec: SandboxSpec): Promise<ProviderSandbox>;
|
|
70
70
|
connect(nativeId: string): Promise<ProviderSandbox>;
|
|
71
71
|
}
|
|
72
|
+
/**
|
|
73
|
+
* Splits exec's combined terminal output at the stderr marker: the command's stdout comes before
|
|
74
|
+
* it, its stderr (base64) after. If the terminal still translated newlines (stty unavailable), the
|
|
75
|
+
* marker is preceded by \r\n and stdout's \r\n are turned back into \n.
|
|
76
|
+
*/
|
|
77
|
+
export declare function splitOutput(combined: string, marker: string): {
|
|
78
|
+
stdout: string;
|
|
79
|
+
stderr: string;
|
|
80
|
+
};
|
|
@@ -386,14 +386,39 @@ class AgentCoreSandbox {
|
|
|
386
386
|
const timeout = Math.max(1, Math.round(opts.timeoutSeconds ?? 60));
|
|
387
387
|
const full = wrapCommand(cmd, { cwd: opts.cwd, env: { ...this.env, ...opts.env } });
|
|
388
388
|
const b64 = Buffer.from(full).toString("base64");
|
|
389
|
+
// The service runs commands in a terminal: stdout and stderr come back as one stream (labelled
|
|
390
|
+
// "stdout" on exit 0 and "stderr" otherwise), with \n turned into \r\n. So stderr goes to a file
|
|
391
|
+
// and is printed base64-encoded after a marker, and `stty -onlcr` keeps newlines as they are.
|
|
392
|
+
const nonce = randomBytes(6).toString("hex");
|
|
393
|
+
const errFile = `/tmp/.sbr-stderr-${nonce}`;
|
|
394
|
+
const marker = `__SBR_STDERR_${nonce}__`;
|
|
389
395
|
// base64 keeps the user's command intact through whatever quoting the service applies.
|
|
390
|
-
const command = `timeout -k 5 ${timeout} bash -c "$(echo ${b64} | base64 -d)"
|
|
391
|
-
|
|
396
|
+
const command = `stty -onlcr 2>/dev/null; timeout -k 5 ${timeout} bash -c "$(echo ${b64} | base64 -d)" 2>${errFile}; c=$?; ` +
|
|
397
|
+
`printf '\\n${marker}\\n'; base64 < ${errFile} | tr -d '\\r\\n'; rm -f ${errFile}; exit $c`;
|
|
398
|
+
// Stream stdout as it arrives, holding back only what could be the start of the marker.
|
|
399
|
+
let combined = "";
|
|
400
|
+
let sent = 0;
|
|
401
|
+
const feed = (chunk) => {
|
|
402
|
+
combined += chunk;
|
|
403
|
+
if (!opts.onStdout)
|
|
404
|
+
return;
|
|
405
|
+
const at = combined.indexOf(`\n${marker}`);
|
|
406
|
+
const safe = at >= 0 ? at : Math.max(sent, combined.length - marker.length - 2);
|
|
407
|
+
if (safe > sent)
|
|
408
|
+
opts.onStdout(combined.slice(sent, safe));
|
|
409
|
+
sent = Math.max(sent, safe);
|
|
410
|
+
};
|
|
411
|
+
const r = await this.command(command, { onStdout: feed, onStderr: feed, timeoutMs: (timeout + 60) * 1000 });
|
|
392
412
|
const durationMs = Date.now() - t0;
|
|
413
|
+
const { stdout, stderr } = splitOutput(combined || r.stdout + r.stderr, marker);
|
|
414
|
+
if (opts.onStdout && stdout.length > sent)
|
|
415
|
+
opts.onStdout(stdout.slice(sent));
|
|
416
|
+
if (stderr)
|
|
417
|
+
opts.onStderr?.(stderr);
|
|
393
418
|
// `timeout` leaves exit 124 (or 137 after SIGKILL) when it had to stop the command.
|
|
394
419
|
if (killedByTimeout(r.exitCode, durationMs, timeout))
|
|
395
420
|
throw timeoutError(ID, timeout);
|
|
396
|
-
return {
|
|
421
|
+
return { stdout, stderr, exitCode: r.exitCode, durationMs };
|
|
397
422
|
}
|
|
398
423
|
async writeFile(path, content) {
|
|
399
424
|
const bytes = toBytes(content);
|
|
@@ -426,6 +451,22 @@ class AgentCoreSandbox {
|
|
|
426
451
|
}
|
|
427
452
|
}
|
|
428
453
|
}
|
|
454
|
+
/**
|
|
455
|
+
* Splits exec's combined terminal output at the stderr marker: the command's stdout comes before
|
|
456
|
+
* it, its stderr (base64) after. If the terminal still translated newlines (stty unavailable), the
|
|
457
|
+
* marker is preceded by \r\n and stdout's \r\n are turned back into \n.
|
|
458
|
+
*/
|
|
459
|
+
export function splitOutput(combined, marker) {
|
|
460
|
+
const at = combined.lastIndexOf(`\n${marker}`);
|
|
461
|
+
if (at < 0)
|
|
462
|
+
return { stdout: combined, stderr: "" };
|
|
463
|
+
const translated = combined[at - 1] === "\r";
|
|
464
|
+
let stdout = combined.slice(0, translated ? at - 1 : at);
|
|
465
|
+
if (translated)
|
|
466
|
+
stdout = stdout.replace(/\r\n/g, "\n");
|
|
467
|
+
const b64 = combined.slice(at + marker.length + 1).replace(/\s/g, "");
|
|
468
|
+
return { stdout, stderr: Buffer.from(b64, "base64").toString("utf8") };
|
|
469
|
+
}
|
|
429
470
|
function exceptionStatus(name) {
|
|
430
471
|
const n = name.toLowerCase();
|
|
431
472
|
if (n.startsWith("accessdenied"))
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { createHash } from "node:crypto";
|
|
2
2
|
import { ProviderError } from "../types.js";
|
|
3
|
-
import { dirname, toBytes, wrapCommand } from "../util.js";
|
|
3
|
+
import { dirname, shq, toBytes, wrapCommand } from "../util.js";
|
|
4
4
|
/**
|
|
5
5
|
* Freestyle VMs over the public REST API (no SDK needed). Auth: Authorization: Bearer
|
|
6
6
|
* <FREESTYLE_API_KEY>, base https://api.freestyle.sh. Errors are {code, message}.
|
|
@@ -230,11 +230,18 @@ class FreestyleBox {
|
|
|
230
230
|
}
|
|
231
231
|
async writeFile(path, content) {
|
|
232
232
|
const bytes = toBytes(content);
|
|
233
|
-
//
|
|
233
|
+
// The file API runs as root, so a folder it creates belongs to root and commands (which run as
|
|
234
|
+
// the image's user) can't write in it. Make the folder with a command instead, as that user;
|
|
235
|
+
// fall back to the file API where the user can't (e.g. under /root). Best effort: the write
|
|
234
236
|
// itself reports any real problem.
|
|
235
237
|
const dir = dirname(path);
|
|
236
|
-
if (dir !== "/")
|
|
237
|
-
await this.p
|
|
238
|
+
if (dir !== "/") {
|
|
239
|
+
const r = await this.p
|
|
240
|
+
.json("POST", `${this.path}/exec-await`, { json: { command: `mkdir -p ${shq(dir)}`, timeoutMs: 30_000 }, background: true })
|
|
241
|
+
.catch(() => undefined);
|
|
242
|
+
if (r?.statusCode !== 0)
|
|
243
|
+
await this.p.request("POST", `${this.path}/fs/mkdir`, { json: { path: dir }, background: true }).catch(() => { });
|
|
244
|
+
}
|
|
238
245
|
const q = new URLSearchParams({ path, sha256: createHash("sha256").update(bytes).digest("hex") });
|
|
239
246
|
await this.p.request("PUT", `${this.path}/fs/write?${q}`, { bytes, background: true });
|
|
240
247
|
}
|
package/dist/providers/modal.js
CHANGED
|
@@ -75,7 +75,11 @@ class ModalBox {
|
|
|
75
75
|
catch (err) {
|
|
76
76
|
if (err instanceof ProviderError)
|
|
77
77
|
throw err;
|
|
78
|
-
|
|
78
|
+
const message = err?.message ?? String(err);
|
|
79
|
+
// Newer SDKs end the output streams with "Deadline exceeded" at timeoutMs instead of a signal exit.
|
|
80
|
+
if (/deadline exceeded/i.test(message) && killedByTimeout(-1, Date.now() - t0, seconds))
|
|
81
|
+
throw timeoutError("modal", seconds);
|
|
82
|
+
throw new ProviderError("modal", message);
|
|
79
83
|
}
|
|
80
84
|
}
|
|
81
85
|
async writeFile(path, content) {
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import { randomUUID } from "node:crypto";
|
|
2
2
|
import { StringDecoder } from "node:string_decoder";
|
|
3
3
|
import { ProviderError } from "../types.js";
|
|
4
|
-
import { optionalImport, toBytes } from "../util.js";
|
|
4
|
+
import { optionalImport, timeoutError, toBytes } from "../util.js";
|
|
5
5
|
/**
|
|
6
6
|
* Fly.io Sprites via `@fly/sprites`. A sprite is a persistent machine named by the caller, so the
|
|
7
7
|
* name is the native id. Sprites idle on their own and have no lifetime knob: kill() deletes it.
|
|
@@ -78,9 +78,10 @@ class SpritesBox {
|
|
|
78
78
|
try {
|
|
79
79
|
const exitCode = await new Promise((resolve, reject) => {
|
|
80
80
|
const timer = setTimeout(() => {
|
|
81
|
+
// Reject first: killing can report an exit (-1) right away, and that must not count as the result.
|
|
82
|
+
reject(timeoutError("sprites", limit / 1000));
|
|
81
83
|
proc.kill("SIGKILL");
|
|
82
84
|
proc.close();
|
|
83
|
-
reject(new ProviderError("sprites", `command timed out after ${limit / 1000}s`));
|
|
84
85
|
}, limit);
|
|
85
86
|
timer.unref();
|
|
86
87
|
proc.on("exit", (code) => {
|
|
@@ -89,8 +90,8 @@ class SpritesBox {
|
|
|
89
90
|
});
|
|
90
91
|
proc.on("error", (e) => {
|
|
91
92
|
clearTimeout(timer);
|
|
92
|
-
proc.close();
|
|
93
93
|
reject(e);
|
|
94
|
+
proc.close();
|
|
94
95
|
});
|
|
95
96
|
});
|
|
96
97
|
const so = out.end();
|
package/dist/providers/vercel.js
CHANGED
|
@@ -27,6 +27,9 @@ export class VercelProvider {
|
|
|
27
27
|
resources: { vcpus },
|
|
28
28
|
env: spec.env,
|
|
29
29
|
tags: spec.metadata,
|
|
30
|
+
// v3 keeps sandboxes by default and restarts a stopped one on the next command; a router
|
|
31
|
+
// sandbox is single-use, so nothing should outlive kill().
|
|
32
|
+
persistent: false,
|
|
30
33
|
});
|
|
31
34
|
return new VercelBox(sbx);
|
|
32
35
|
}
|
|
@@ -93,6 +96,7 @@ class VercelBox {
|
|
|
93
96
|
return new Uint8Array(buf);
|
|
94
97
|
}
|
|
95
98
|
async kill() {
|
|
96
|
-
|
|
99
|
+
// stop() only ends the session: the next SDK call would start it again. delete() makes it inert.
|
|
100
|
+
await this.sbx.delete({ deleteOrphanSnapshots: true });
|
|
97
101
|
}
|
|
98
102
|
}
|
package/dist/server.d.ts
CHANGED
|
@@ -2,7 +2,7 @@ import { type IncomingMessage, type ServerResponse } from "node:http";
|
|
|
2
2
|
import { Router, type RoutedSandbox } from "./router.js";
|
|
3
3
|
import { type RouteOptions, type SandboxSpec } from "./types.js";
|
|
4
4
|
/**
|
|
5
|
-
* Hooks for running this API for many users,
|
|
5
|
+
* Hooks for running this API for many users (accounts, billing, per-user sandboxes). With none set,
|
|
6
6
|
* the server is single-user: one SANDBOXROUTER_TOKEN, every sandbox reachable by anyone holding it.
|
|
7
7
|
*/
|
|
8
8
|
export interface ServerHooks {
|
package/dist/verified.js
CHANGED
|
@@ -1,7 +1,18 @@
|
|
|
1
1
|
export const VERIFIED = {
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
2
|
+
agent37: "2026-11-11",
|
|
3
|
+
agentcore: "2026-11-11",
|
|
4
|
+
lambda: "2026-11-11",
|
|
5
|
+
blaxel: "2026-11-11",
|
|
6
|
+
cloudflare: "2026-11-11",
|
|
7
|
+
daytona: "2026-11-11",
|
|
8
|
+
e2b: "2026-11-11",
|
|
9
|
+
sprites: "2026-11-11",
|
|
10
|
+
freestyle: "2026-11-11",
|
|
11
|
+
maritime: "2026-11-11",
|
|
12
|
+
modal: "2026-11-11",
|
|
13
|
+
novita: "2026-11-11",
|
|
14
|
+
openscale: "2026-11-11",
|
|
15
|
+
sail: "2026-11-11",
|
|
16
|
+
superserve: "2026-11-11",
|
|
17
|
+
vercel: "2026-11-11",
|
|
7
18
|
};
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@sandboxrouter/sdk",
|
|
3
|
-
"version": "0.3.
|
|
3
|
+
"version": "0.3.5",
|
|
4
4
|
"description": "One API for every sandbox provider: route AI agents' code by price, speed or capability, with automatic fallback. Free and open source.",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"main": "dist/index.js",
|