sbox-sdk 0.0.2
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/LICENSE +21 -0
- package/README.md +137 -0
- package/dist/adapter/index.d.ts +22 -0
- package/dist/adapter/index.d.ts.map +1 -0
- package/dist/adapter/index.js +16 -0
- package/dist/agent-tools/index.d.ts +13 -0
- package/dist/agent-tools/index.d.ts.map +1 -0
- package/dist/agent-tools/index.js +9 -0
- package/dist/agent-tools/policy.d.ts +48 -0
- package/dist/agent-tools/policy.d.ts.map +1 -0
- package/dist/agent-tools/policy.js +51 -0
- package/dist/agent-tools/registry.d.ts +9 -0
- package/dist/agent-tools/registry.d.ts.map +1 -0
- package/dist/agent-tools/registry.js +412 -0
- package/dist/agent-tools/result.d.ts +32 -0
- package/dist/agent-tools/result.d.ts.map +1 -0
- package/dist/agent-tools/result.js +14 -0
- package/dist/agent-tools/types.d.ts +76 -0
- package/dist/agent-tools/types.d.ts.map +1 -0
- package/dist/agent-tools/types.js +1 -0
- package/dist/ai/index.d.ts +36 -0
- package/dist/ai/index.d.ts.map +1 -0
- package/dist/ai/index.js +40 -0
- package/dist/ai-sdk/index.d.ts +31 -0
- package/dist/ai-sdk/index.d.ts.map +1 -0
- package/dist/ai-sdk/index.js +80 -0
- package/dist/anthropic/index.d.ts +42 -0
- package/dist/anthropic/index.d.ts.map +1 -0
- package/dist/anthropic/index.js +64 -0
- package/dist/aws-lambda/index.d.ts +87 -0
- package/dist/aws-lambda/index.d.ts.map +1 -0
- package/dist/aws-lambda/index.js +290 -0
- package/dist/beam/index.d.ts +92 -0
- package/dist/beam/index.d.ts.map +1 -0
- package/dist/beam/index.js +222 -0
- package/dist/blaxel/index.d.ts +125 -0
- package/dist/blaxel/index.d.ts.map +1 -0
- package/dist/blaxel/index.js +220 -0
- package/dist/cli.d.ts +3 -0
- package/dist/cli.d.ts.map +1 -0
- package/dist/cli.js +249 -0
- package/dist/cloudflare/index.d.ts +64 -0
- package/dist/cloudflare/index.d.ts.map +1 -0
- package/dist/cloudflare/index.js +259 -0
- package/dist/codesandbox/index.d.ts +100 -0
- package/dist/codesandbox/index.d.ts.map +1 -0
- package/dist/codesandbox/index.js +227 -0
- package/dist/conformance/index.d.ts +20 -0
- package/dist/conformance/index.d.ts.map +1 -0
- package/dist/conformance/index.js +189 -0
- package/dist/daytona/index.d.ts +64 -0
- package/dist/daytona/index.d.ts.map +1 -0
- package/dist/daytona/index.js +258 -0
- package/dist/e2b/index.d.ts +63 -0
- package/dist/e2b/index.d.ts.map +1 -0
- package/dist/e2b/index.js +411 -0
- package/dist/fly/index.d.ts +75 -0
- package/dist/fly/index.d.ts.map +1 -0
- package/dist/fly/index.js +222 -0
- package/dist/index.d.ts +21 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +16 -0
- package/dist/internal/capabilities.d.ts +57 -0
- package/dist/internal/capabilities.d.ts.map +1 -0
- package/dist/internal/capabilities.js +68 -0
- package/dist/internal/client.d.ts +9 -0
- package/dist/internal/client.d.ts.map +1 -0
- package/dist/internal/client.js +126 -0
- package/dist/internal/encoding.d.ts +8 -0
- package/dist/internal/encoding.d.ts.map +1 -0
- package/dist/internal/encoding.js +20 -0
- package/dist/internal/errors.d.ts +45 -0
- package/dist/internal/errors.d.ts.map +1 -0
- package/dist/internal/errors.js +79 -0
- package/dist/internal/exec.d.ts +19 -0
- package/dist/internal/exec.d.ts.map +1 -0
- package/dist/internal/exec.js +208 -0
- package/dist/internal/plugin.d.ts +38 -0
- package/dist/internal/plugin.d.ts.map +1 -0
- package/dist/internal/plugin.js +1 -0
- package/dist/internal/runtime.d.ts +8 -0
- package/dist/internal/runtime.d.ts.map +1 -0
- package/dist/internal/runtime.js +21 -0
- package/dist/internal/sandbox.d.ts +12 -0
- package/dist/internal/sandbox.d.ts.map +1 -0
- package/dist/internal/sandbox.js +438 -0
- package/dist/internal/shell.d.ts +36 -0
- package/dist/internal/shell.d.ts.map +1 -0
- package/dist/internal/shell.js +88 -0
- package/dist/internal/stream.d.ts +15 -0
- package/dist/internal/stream.d.ts.map +1 -0
- package/dist/internal/stream.js +58 -0
- package/dist/internal/types.d.ts +381 -0
- package/dist/internal/types.d.ts.map +1 -0
- package/dist/internal/types.js +1 -0
- package/dist/langchain/index.d.ts +25 -0
- package/dist/langchain/index.d.ts.map +1 -0
- package/dist/langchain/index.js +61 -0
- package/dist/mastra/index.d.ts +43 -0
- package/dist/mastra/index.d.ts.map +1 -0
- package/dist/mastra/index.js +69 -0
- package/dist/memory/index.d.ts +57 -0
- package/dist/memory/index.d.ts.map +1 -0
- package/dist/memory/index.js +573 -0
- package/dist/modal/index.d.ts +67 -0
- package/dist/modal/index.d.ts.map +1 -0
- package/dist/modal/index.js +223 -0
- package/dist/morph/index.d.ts +91 -0
- package/dist/morph/index.d.ts.map +1 -0
- package/dist/morph/index.js +221 -0
- package/dist/northflank/index.d.ts +74 -0
- package/dist/northflank/index.d.ts.map +1 -0
- package/dist/northflank/index.js +265 -0
- package/dist/openai/index.d.ts +25 -0
- package/dist/openai/index.d.ts.map +1 -0
- package/dist/openai/index.js +71 -0
- package/dist/railway/index.d.ts +109 -0
- package/dist/railway/index.d.ts.map +1 -0
- package/dist/railway/index.js +219 -0
- package/dist/runloop/index.d.ts +69 -0
- package/dist/runloop/index.d.ts.map +1 -0
- package/dist/runloop/index.js +226 -0
- package/dist/testing/index.d.ts +44 -0
- package/dist/testing/index.d.ts.map +1 -0
- package/dist/testing/index.js +61 -0
- package/dist/vercel/index.d.ts +63 -0
- package/dist/vercel/index.d.ts.map +1 -0
- package/dist/vercel/index.js +241 -0
- package/package.json +252 -0
- package/src/aws-lambda/runner/Dockerfile +15 -0
- package/src/aws-lambda/runner/README.md +59 -0
- package/src/aws-lambda/runner/server.mjs +91 -0
|
@@ -0,0 +1,227 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* `sbox-sdk/codesandbox` — adapter for the CodeSandbox SDK (`@codesandbox/sdk`).
|
|
3
|
+
* A "sandbox" is a CodeSandbox microVM. The SDK has two halves: a control object
|
|
4
|
+
* (`sdk.sandboxes.*` — create/resume/hibernate/shutdown/list) and a per-sandbox
|
|
5
|
+
* `client` you get from `sandbox.connect()` for commands/fs/ports. This adapter
|
|
6
|
+
* holds both.
|
|
7
|
+
*
|
|
8
|
+
* exec is the buffered `client.commands.run` (native cwd/env), which THROWS a
|
|
9
|
+
* `CommandError` on non-zero exit — the adapter catches it and emits a normal
|
|
10
|
+
* `exit` event so the core never sees a throw. Filesystem is native
|
|
11
|
+
* (`client.fs.*`). Ports are public hosts (`client.hosts.getUrl`). `pause()` =
|
|
12
|
+
* hibernate (memory snapshotted), `resume()` wakes it, `shutdown()` destroys.
|
|
13
|
+
* `setTimeout()` maps to the hibernation timeout. Requires the optional peer
|
|
14
|
+
* dependency `@codesandbox/sdk`.
|
|
15
|
+
*/
|
|
16
|
+
import { AsyncQueue, defineProvider, SandboxError } from "../adapter/index.js";
|
|
17
|
+
export const CODESANDBOX_CAPS = {
|
|
18
|
+
background: "unsupported",
|
|
19
|
+
codeInterpreter: "unsupported",
|
|
20
|
+
egressControl: "unsupported",
|
|
21
|
+
exposePort: "native",
|
|
22
|
+
filesUpload: "native",
|
|
23
|
+
filesWatch: "unsupported",
|
|
24
|
+
fork: "unsupported",
|
|
25
|
+
gpu: "unsupported",
|
|
26
|
+
killProcess: "unsupported",
|
|
27
|
+
list: "native",
|
|
28
|
+
metrics: "unsupported",
|
|
29
|
+
pause: "native",
|
|
30
|
+
privatePreview: "native",
|
|
31
|
+
proxiedFetch: "unsupported",
|
|
32
|
+
pty: "unsupported",
|
|
33
|
+
region: "unsupported",
|
|
34
|
+
secretsVault: "unsupported",
|
|
35
|
+
setTimeout: "native",
|
|
36
|
+
snapshot: "unsupported",
|
|
37
|
+
ssh: "unsupported",
|
|
38
|
+
statefulKernel: "unsupported",
|
|
39
|
+
stdin: "unsupported",
|
|
40
|
+
stop: "unsupported",
|
|
41
|
+
streaming: "emulated",
|
|
42
|
+
volumes: "unsupported",
|
|
43
|
+
};
|
|
44
|
+
const CODESANDBOX_FLAGS = {
|
|
45
|
+
exitCodeNative: true, // exit code recovered from CommandError
|
|
46
|
+
perCommandEnvCwd: true, // commands.run accepts { cwd, env }
|
|
47
|
+
preservesDiskOnStop: false,
|
|
48
|
+
preservesMemoryOnPause: true, // hibernate snapshots memory
|
|
49
|
+
previewModel: "subdomain",
|
|
50
|
+
};
|
|
51
|
+
let cached = null;
|
|
52
|
+
async function loadCsb() {
|
|
53
|
+
if (!cached) {
|
|
54
|
+
cached = (await import("@codesandbox/sdk"));
|
|
55
|
+
}
|
|
56
|
+
return cached;
|
|
57
|
+
}
|
|
58
|
+
function mapState(state) {
|
|
59
|
+
switch ((state ?? "").toLowerCase()) {
|
|
60
|
+
case "running":
|
|
61
|
+
case "connected": {
|
|
62
|
+
return "running";
|
|
63
|
+
}
|
|
64
|
+
case "hibernated": {
|
|
65
|
+
return "paused";
|
|
66
|
+
}
|
|
67
|
+
case "shutdown": {
|
|
68
|
+
return "stopped";
|
|
69
|
+
}
|
|
70
|
+
default: {
|
|
71
|
+
return "unknown";
|
|
72
|
+
}
|
|
73
|
+
}
|
|
74
|
+
}
|
|
75
|
+
function mapFileType(type) {
|
|
76
|
+
if (type === "directory" || type === "dir") {
|
|
77
|
+
return "dir";
|
|
78
|
+
}
|
|
79
|
+
if (type === "symlink") {
|
|
80
|
+
return "symlink";
|
|
81
|
+
}
|
|
82
|
+
return "file";
|
|
83
|
+
}
|
|
84
|
+
export const codesandbox = defineProvider((opts) => {
|
|
85
|
+
let sdkP = null;
|
|
86
|
+
const getSdk = () => {
|
|
87
|
+
if (!sdkP) {
|
|
88
|
+
sdkP = loadCsb().then((mod) => new mod.CodeSandbox(opts.apiKey));
|
|
89
|
+
}
|
|
90
|
+
return sdkP;
|
|
91
|
+
};
|
|
92
|
+
const makeHandle = (sb, client) => ({
|
|
93
|
+
id: sb.id,
|
|
94
|
+
raw: sb,
|
|
95
|
+
getInfo() {
|
|
96
|
+
return {
|
|
97
|
+
id: sb.id,
|
|
98
|
+
state: "running",
|
|
99
|
+
provider: "codesandbox",
|
|
100
|
+
metadata: {},
|
|
101
|
+
raw: sb,
|
|
102
|
+
};
|
|
103
|
+
},
|
|
104
|
+
async destroy() {
|
|
105
|
+
const sdk = await getSdk();
|
|
106
|
+
await sdk.sandboxes.shutdown(sb.id);
|
|
107
|
+
},
|
|
108
|
+
async pause() {
|
|
109
|
+
const sdk = await getSdk();
|
|
110
|
+
await sdk.sandboxes.hibernate(sb.id);
|
|
111
|
+
},
|
|
112
|
+
async resume() {
|
|
113
|
+
const sdk = await getSdk();
|
|
114
|
+
await sdk.sandboxes.resume(sb.id);
|
|
115
|
+
},
|
|
116
|
+
async setTimeout(ttlMs) {
|
|
117
|
+
await sb.updateHibernationTimeout(Math.max(1, Math.ceil(ttlMs / 1000)));
|
|
118
|
+
},
|
|
119
|
+
exec(cmd, options) {
|
|
120
|
+
const queue = new AsyncQueue();
|
|
121
|
+
void client.commands
|
|
122
|
+
.run(cmd, { cwd: options.cwd, env: options.env })
|
|
123
|
+
.then((stdout) => {
|
|
124
|
+
if (stdout) {
|
|
125
|
+
queue.push({ type: "stdout", data: stdout });
|
|
126
|
+
}
|
|
127
|
+
queue.push({ type: "exit", exitCode: 0 });
|
|
128
|
+
queue.close();
|
|
129
|
+
})
|
|
130
|
+
.catch((error) => {
|
|
131
|
+
// CommandError carries the non-zero exit code + buffered output; turn
|
|
132
|
+
// it into a normal exit event rather than a thrown error.
|
|
133
|
+
const ce = error;
|
|
134
|
+
if (typeof ce?.exitCode === "number") {
|
|
135
|
+
if (ce.output) {
|
|
136
|
+
queue.push({ type: "stderr", data: ce.output });
|
|
137
|
+
}
|
|
138
|
+
queue.push({ type: "exit", exitCode: ce.exitCode });
|
|
139
|
+
queue.close();
|
|
140
|
+
return;
|
|
141
|
+
}
|
|
142
|
+
queue.fail(error instanceof SandboxError
|
|
143
|
+
? error
|
|
144
|
+
: SandboxError.wrap(error, "codesandbox"));
|
|
145
|
+
});
|
|
146
|
+
return {
|
|
147
|
+
pid: Promise.resolve(""),
|
|
148
|
+
async kill() {
|
|
149
|
+
/* commands.run is buffered; use runBackground for control (not wired) */
|
|
150
|
+
},
|
|
151
|
+
[Symbol.asyncIterator]: () => queue.iterator(),
|
|
152
|
+
};
|
|
153
|
+
},
|
|
154
|
+
async readFile(path) {
|
|
155
|
+
return new Uint8Array(await client.fs.readFile(path));
|
|
156
|
+
},
|
|
157
|
+
async writeFile(path, data) {
|
|
158
|
+
await client.fs.writeFile(path, data, { create: true, overwrite: true });
|
|
159
|
+
},
|
|
160
|
+
async listDir(path) {
|
|
161
|
+
const entries = await client.fs.readdir(path);
|
|
162
|
+
const base = path.replace(/\/$/, "");
|
|
163
|
+
return entries.map((e) => ({
|
|
164
|
+
name: e.name,
|
|
165
|
+
path: `${base}/${e.name}`,
|
|
166
|
+
type: mapFileType(e.type),
|
|
167
|
+
}));
|
|
168
|
+
},
|
|
169
|
+
async remove(path, recursive) {
|
|
170
|
+
await client.fs.remove(path, recursive);
|
|
171
|
+
},
|
|
172
|
+
async rename(from, to) {
|
|
173
|
+
await client.fs.rename(from, to);
|
|
174
|
+
},
|
|
175
|
+
async stat(path) {
|
|
176
|
+
const s = await client.fs.stat(path);
|
|
177
|
+
return {
|
|
178
|
+
path,
|
|
179
|
+
type: mapFileType(s.type),
|
|
180
|
+
size: s.size ?? 0,
|
|
181
|
+
mtime: s.mtime ? new Date(s.mtime) : undefined,
|
|
182
|
+
};
|
|
183
|
+
},
|
|
184
|
+
exposePort(port) {
|
|
185
|
+
return { url: client.hosts.getUrl(port), port };
|
|
186
|
+
},
|
|
187
|
+
});
|
|
188
|
+
const provider = {
|
|
189
|
+
name: "codesandbox",
|
|
190
|
+
capabilities: CODESANDBOX_CAPS,
|
|
191
|
+
flags: CODESANDBOX_FLAGS,
|
|
192
|
+
async create(spec) {
|
|
193
|
+
const sdk = await getSdk();
|
|
194
|
+
const id = spec.template ?? opts.templateId;
|
|
195
|
+
const sb = await sdk.sandboxes.create({
|
|
196
|
+
id,
|
|
197
|
+
title: spec.name,
|
|
198
|
+
tags: spec.metadata ? Object.values(spec.metadata) : undefined,
|
|
199
|
+
hibernationTimeoutSeconds: spec.ttlMs
|
|
200
|
+
? Math.ceil(spec.ttlMs / 1000)
|
|
201
|
+
: undefined,
|
|
202
|
+
});
|
|
203
|
+
const client = await sb.connect();
|
|
204
|
+
return makeHandle(sb, client);
|
|
205
|
+
},
|
|
206
|
+
async connect(id) {
|
|
207
|
+
const sdk = await getSdk();
|
|
208
|
+
const sb = await sdk.sandboxes.resume(id);
|
|
209
|
+
const client = await sb.connect();
|
|
210
|
+
return makeHandle(sb, client);
|
|
211
|
+
},
|
|
212
|
+
async *list() {
|
|
213
|
+
const sdk = await getSdk();
|
|
214
|
+
const res = await sdk.sandboxes.list();
|
|
215
|
+
for (const s of res.sandboxes ?? []) {
|
|
216
|
+
yield {
|
|
217
|
+
id: s.id,
|
|
218
|
+
state: mapState(s.status),
|
|
219
|
+
provider: "codesandbox",
|
|
220
|
+
metadata: {},
|
|
221
|
+
raw: s,
|
|
222
|
+
};
|
|
223
|
+
}
|
|
224
|
+
},
|
|
225
|
+
};
|
|
226
|
+
return provider;
|
|
227
|
+
});
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
import type { CapabilityMap } from "../internal/capabilities.js";
|
|
2
|
+
import type { SandboxProvider } from "../internal/types.js";
|
|
3
|
+
export interface ConformanceCheck {
|
|
4
|
+
name: string;
|
|
5
|
+
ok: boolean;
|
|
6
|
+
error?: string;
|
|
7
|
+
}
|
|
8
|
+
export interface ConformanceReport {
|
|
9
|
+
provider: string;
|
|
10
|
+
checks: ConformanceCheck[];
|
|
11
|
+
passed: boolean;
|
|
12
|
+
}
|
|
13
|
+
export interface ConformanceOptions {
|
|
14
|
+
/** Assert the provider declares these exact capability levels. */
|
|
15
|
+
expectedCaps?: Partial<CapabilityMap>;
|
|
16
|
+
/** Skip checks by name (for genuinely-not-applicable providers). */
|
|
17
|
+
skip?: string[];
|
|
18
|
+
}
|
|
19
|
+
export declare function runConformance(provider: SandboxProvider, options?: ConformanceOptions): Promise<ConformanceReport>;
|
|
20
|
+
//# sourceMappingURL=index.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/conformance/index.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,6BAA6B,CAAC;AAQjE,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,sBAAsB,CAAC;AAE5D,MAAM,WAAW,gBAAgB;IAC/B,IAAI,EAAE,MAAM,CAAC;IACb,EAAE,EAAE,OAAO,CAAC;IACZ,KAAK,CAAC,EAAE,MAAM,CAAC;CAChB;AAED,MAAM,WAAW,iBAAiB;IAChC,QAAQ,EAAE,MAAM,CAAC;IACjB,MAAM,EAAE,gBAAgB,EAAE,CAAC;IAC3B,MAAM,EAAE,OAAO,CAAC;CACjB;AAED,MAAM,WAAW,kBAAkB;IACjC,kEAAkE;IAClE,YAAY,CAAC,EAAE,OAAO,CAAC,aAAa,CAAC,CAAC;IACtC,oEAAoE;IACpE,IAAI,CAAC,EAAE,MAAM,EAAE,CAAC;CACjB;AAQD,wBAAsB,cAAc,CAClC,QAAQ,EAAE,eAAe,EACzB,OAAO,GAAE,kBAAuB,GAC/B,OAAO,CAAC,iBAAiB,CAAC,CA0N5B"}
|
|
@@ -0,0 +1,189 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* `sbox-sdk/conformance` — one identical battery every adapter must pass, so all
|
|
3
|
+
* providers behave the same. Runner-agnostic: returns a report you assert on
|
|
4
|
+
* inside your own test framework (vitest, node:test, ...).
|
|
5
|
+
*/
|
|
6
|
+
import { createSandboxClient } from "../internal/client.js";
|
|
7
|
+
import { NotSupportedError } from "../internal/errors.js";
|
|
8
|
+
function assert(cond, msg) {
|
|
9
|
+
if (!cond) {
|
|
10
|
+
throw new Error(msg);
|
|
11
|
+
}
|
|
12
|
+
}
|
|
13
|
+
export async function runConformance(provider, options = {}) {
|
|
14
|
+
const client = createSandboxClient({ provider });
|
|
15
|
+
const checks = [];
|
|
16
|
+
const skip = new Set(options.skip ?? []);
|
|
17
|
+
const caps = provider.capabilities;
|
|
18
|
+
const check = async (name, fn) => {
|
|
19
|
+
if (skip.has(name)) {
|
|
20
|
+
return;
|
|
21
|
+
}
|
|
22
|
+
try {
|
|
23
|
+
await fn();
|
|
24
|
+
checks.push({ name, ok: true });
|
|
25
|
+
}
|
|
26
|
+
catch (error) {
|
|
27
|
+
checks.push({
|
|
28
|
+
error: error instanceof Error ? error.message : String(error),
|
|
29
|
+
name,
|
|
30
|
+
ok: false,
|
|
31
|
+
});
|
|
32
|
+
}
|
|
33
|
+
};
|
|
34
|
+
if (options.expectedCaps) {
|
|
35
|
+
const expected = options.expectedCaps;
|
|
36
|
+
await check("caps: declared levels match expected", async () => {
|
|
37
|
+
for (const key of Object.keys(expected)) {
|
|
38
|
+
const actual = caps[key];
|
|
39
|
+
assert(actual === expected[key], `cap '${key}' expected '${expected[key]}' got '${actual}'`);
|
|
40
|
+
}
|
|
41
|
+
});
|
|
42
|
+
}
|
|
43
|
+
const sb = await client.create({});
|
|
44
|
+
await check("lifecycle: getInfo", async () => {
|
|
45
|
+
const info = await sb.getInfo();
|
|
46
|
+
assert(!!info.id, "info.id present");
|
|
47
|
+
assert(info.provider === provider.name, "info.provider matches");
|
|
48
|
+
});
|
|
49
|
+
await check("exec: echo buffered", async () => {
|
|
50
|
+
const r = await sb.commands.run("echo hi");
|
|
51
|
+
assert(r.exitCode === 0, `exit 0 (got ${r.exitCode})`);
|
|
52
|
+
assert(r.stdout.trim() === "hi", `stdout 'hi' (got ${JSON.stringify(r.stdout)})`);
|
|
53
|
+
});
|
|
54
|
+
await check("exec: non-zero exit is data, not throw", async () => {
|
|
55
|
+
const r = await sb.commands.run("false");
|
|
56
|
+
assert(r.exitCode !== 0, `non-zero exit (got ${r.exitCode})`);
|
|
57
|
+
});
|
|
58
|
+
if (caps.streaming !== "unsupported") {
|
|
59
|
+
await check("exec: streaming events", async () => {
|
|
60
|
+
let out = "";
|
|
61
|
+
let exited = false;
|
|
62
|
+
for await (const ev of sb.commands.run("echo streamed")) {
|
|
63
|
+
if (ev.type === "stdout") {
|
|
64
|
+
out += ev.data;
|
|
65
|
+
}
|
|
66
|
+
if (ev.type === "exit") {
|
|
67
|
+
exited = true;
|
|
68
|
+
}
|
|
69
|
+
}
|
|
70
|
+
assert(out.trim() === "streamed", `streamed stdout (got ${JSON.stringify(out)})`);
|
|
71
|
+
assert(exited, "saw exit event");
|
|
72
|
+
});
|
|
73
|
+
}
|
|
74
|
+
await check("exec: cwd applied", async () => {
|
|
75
|
+
const r = await sb.commands.run("pwd", { cwd: "/tmp" });
|
|
76
|
+
assert(r.stdout.includes("/tmp"), `pwd in /tmp (got ${JSON.stringify(r.stdout)})`);
|
|
77
|
+
});
|
|
78
|
+
await check("exec: env applied", async () => {
|
|
79
|
+
const r = await sb.commands.run("echo $SBOX_CONF", {
|
|
80
|
+
env: { SBOX_CONF: "xyz" },
|
|
81
|
+
});
|
|
82
|
+
assert(r.stdout.trim() === "xyz", `env expand (got ${JSON.stringify(r.stdout)})`);
|
|
83
|
+
});
|
|
84
|
+
await check("files: write/read text round-trip", async () => {
|
|
85
|
+
await sb.files.write("/tmp/conf.txt", "hello world");
|
|
86
|
+
const f = await sb.files.read("/tmp/conf.txt");
|
|
87
|
+
const text = await f.text();
|
|
88
|
+
assert(text === "hello world", `text round-trip (got ${JSON.stringify(text)})`);
|
|
89
|
+
});
|
|
90
|
+
await check("files: write/read binary round-trip", async () => {
|
|
91
|
+
const bytes = new Uint8Array([0, 1, 2, 250, 255]);
|
|
92
|
+
await sb.files.write("/tmp/conf.bin", bytes);
|
|
93
|
+
const got = await (await sb.files.read("/tmp/conf.bin")).bytes();
|
|
94
|
+
assert(got.length === bytes.length, `binary length (got ${got.length})`);
|
|
95
|
+
assert(got[0] === 0 && got[4] === 255, "binary content preserved");
|
|
96
|
+
});
|
|
97
|
+
await check("files: list shows written file", async () => {
|
|
98
|
+
await sb.files.write("/tmp/listed.txt", "x");
|
|
99
|
+
const entries = await sb.files.list("/tmp");
|
|
100
|
+
assert(entries.some((e) => e.name === "listed.txt"), "file listed");
|
|
101
|
+
});
|
|
102
|
+
await check("files: mkdir/exists/remove", async () => {
|
|
103
|
+
await sb.files.mkdir("/tmp/confdir", { recursive: true });
|
|
104
|
+
assert(await sb.files.exists("/tmp/confdir"), "exists after mkdir");
|
|
105
|
+
await sb.files.remove("/tmp/confdir", { recursive: true });
|
|
106
|
+
assert(!(await sb.files.exists("/tmp/confdir")), "gone after remove");
|
|
107
|
+
});
|
|
108
|
+
await check("files: exists() is false (not throw) on missing", async () => {
|
|
109
|
+
const e = await sb.files.exists("/tmp/definitely-missing-xyz");
|
|
110
|
+
assert(e === false, "missing => false");
|
|
111
|
+
});
|
|
112
|
+
await check("caps: code gating matches declaration", async () => {
|
|
113
|
+
if (caps.codeInterpreter === "unsupported") {
|
|
114
|
+
assert(sb.code === undefined, "code undefined");
|
|
115
|
+
}
|
|
116
|
+
else {
|
|
117
|
+
assert(sb.code !== undefined, "code present");
|
|
118
|
+
}
|
|
119
|
+
});
|
|
120
|
+
await check("caps: snapshots gating matches declaration", async () => {
|
|
121
|
+
if (caps.snapshot === "unsupported") {
|
|
122
|
+
assert(sb.snapshots === undefined, "snapshots undefined");
|
|
123
|
+
}
|
|
124
|
+
else {
|
|
125
|
+
assert(sb.snapshots !== undefined, "snapshots present");
|
|
126
|
+
}
|
|
127
|
+
});
|
|
128
|
+
await check("caps: ports gating matches declaration", async () => {
|
|
129
|
+
if (caps.exposePort === "unsupported") {
|
|
130
|
+
assert(sb.ports === undefined, "ports undefined");
|
|
131
|
+
}
|
|
132
|
+
else {
|
|
133
|
+
assert(sb.ports !== undefined, "ports present");
|
|
134
|
+
}
|
|
135
|
+
});
|
|
136
|
+
await check("caps: network gating matches declaration", async () => {
|
|
137
|
+
if (caps.egressControl === "unsupported") {
|
|
138
|
+
assert(sb.network === undefined, "network undefined");
|
|
139
|
+
}
|
|
140
|
+
else {
|
|
141
|
+
assert(sb.network !== undefined, "network present");
|
|
142
|
+
}
|
|
143
|
+
});
|
|
144
|
+
if (caps.snapshot !== "unsupported") {
|
|
145
|
+
await check("snapshots: create returns a ref", async () => {
|
|
146
|
+
const snap = await sb.snapshots.create({ name: "conf-ck" });
|
|
147
|
+
assert(!!snap.id, "snapshot id");
|
|
148
|
+
});
|
|
149
|
+
}
|
|
150
|
+
if (caps.pause !== "unsupported") {
|
|
151
|
+
await check("lifecycle: pause/resume", async () => {
|
|
152
|
+
await sb.pause();
|
|
153
|
+
await sb.resume();
|
|
154
|
+
});
|
|
155
|
+
}
|
|
156
|
+
await check("client: list honors capability", async () => {
|
|
157
|
+
if (caps.list === "unsupported") {
|
|
158
|
+
let threw = false;
|
|
159
|
+
try {
|
|
160
|
+
for await (const _info of client.list()) {
|
|
161
|
+
break;
|
|
162
|
+
}
|
|
163
|
+
}
|
|
164
|
+
catch (error) {
|
|
165
|
+
threw = error instanceof NotSupportedError;
|
|
166
|
+
}
|
|
167
|
+
assert(threw, "list throws NotSupportedError when unsupported");
|
|
168
|
+
}
|
|
169
|
+
else {
|
|
170
|
+
for await (const _info of client.list()) {
|
|
171
|
+
break;
|
|
172
|
+
}
|
|
173
|
+
}
|
|
174
|
+
});
|
|
175
|
+
await check("lifecycle: destroy", async () => {
|
|
176
|
+
await sb.destroy();
|
|
177
|
+
});
|
|
178
|
+
await check("lifecycle: create + destroy a fresh sandbox", async () => {
|
|
179
|
+
const s2 = await client.create({});
|
|
180
|
+
assert(!!s2.id, "fresh id");
|
|
181
|
+
await s2.destroy();
|
|
182
|
+
});
|
|
183
|
+
await client.dispose();
|
|
184
|
+
return {
|
|
185
|
+
checks,
|
|
186
|
+
passed: checks.every((c) => c.ok),
|
|
187
|
+
provider: provider.name,
|
|
188
|
+
};
|
|
189
|
+
}
|
|
@@ -0,0 +1,64 @@
|
|
|
1
|
+
import type { Sandbox as DaytonaSandbox } from "@daytonaio/sdk";
|
|
2
|
+
import type { SandboxProvider } from "../adapter/index.js";
|
|
3
|
+
export interface DaytonaOptions {
|
|
4
|
+
apiKey: string;
|
|
5
|
+
apiUrl?: string;
|
|
6
|
+
/** Target region, e.g. "us" or "eu". */
|
|
7
|
+
target?: string;
|
|
8
|
+
}
|
|
9
|
+
export declare const DAYTONA_CAPS: {
|
|
10
|
+
readonly background: "unsupported";
|
|
11
|
+
readonly codeInterpreter: "native";
|
|
12
|
+
readonly egressControl: "unsupported";
|
|
13
|
+
readonly exposePort: "native";
|
|
14
|
+
readonly filesUpload: "native";
|
|
15
|
+
readonly filesWatch: "unsupported";
|
|
16
|
+
readonly fork: "unsupported";
|
|
17
|
+
readonly gpu: "unsupported";
|
|
18
|
+
readonly killProcess: "unsupported";
|
|
19
|
+
readonly list: "native";
|
|
20
|
+
readonly metrics: "unsupported";
|
|
21
|
+
readonly pause: "native";
|
|
22
|
+
readonly privatePreview: "native";
|
|
23
|
+
readonly proxiedFetch: "unsupported";
|
|
24
|
+
readonly pty: "unsupported";
|
|
25
|
+
readonly region: "native";
|
|
26
|
+
readonly secretsVault: "unsupported";
|
|
27
|
+
readonly setTimeout: "native";
|
|
28
|
+
readonly snapshot: "unsupported";
|
|
29
|
+
readonly ssh: "unsupported";
|
|
30
|
+
readonly statefulKernel: "unsupported";
|
|
31
|
+
readonly stdin: "unsupported";
|
|
32
|
+
readonly stop: "native";
|
|
33
|
+
readonly streaming: "emulated";
|
|
34
|
+
readonly volumes: "unsupported";
|
|
35
|
+
};
|
|
36
|
+
export type DaytonaCaps = typeof DAYTONA_CAPS;
|
|
37
|
+
export declare const daytona: (opts: DaytonaOptions) => SandboxProvider<{
|
|
38
|
+
readonly background: "unsupported";
|
|
39
|
+
readonly codeInterpreter: "native";
|
|
40
|
+
readonly egressControl: "unsupported";
|
|
41
|
+
readonly exposePort: "native";
|
|
42
|
+
readonly filesUpload: "native";
|
|
43
|
+
readonly filesWatch: "unsupported";
|
|
44
|
+
readonly fork: "unsupported";
|
|
45
|
+
readonly gpu: "unsupported";
|
|
46
|
+
readonly killProcess: "unsupported";
|
|
47
|
+
readonly list: "native";
|
|
48
|
+
readonly metrics: "unsupported";
|
|
49
|
+
readonly pause: "native";
|
|
50
|
+
readonly privatePreview: "native";
|
|
51
|
+
readonly proxiedFetch: "unsupported";
|
|
52
|
+
readonly pty: "unsupported";
|
|
53
|
+
readonly region: "native";
|
|
54
|
+
readonly secretsVault: "unsupported";
|
|
55
|
+
readonly setTimeout: "native";
|
|
56
|
+
readonly snapshot: "unsupported";
|
|
57
|
+
readonly ssh: "unsupported";
|
|
58
|
+
readonly statefulKernel: "unsupported";
|
|
59
|
+
readonly stdin: "unsupported";
|
|
60
|
+
readonly stop: "native";
|
|
61
|
+
readonly streaming: "emulated";
|
|
62
|
+
readonly volumes: "unsupported";
|
|
63
|
+
}, DaytonaSandbox>;
|
|
64
|
+
//# sourceMappingURL=index.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/daytona/index.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAW,OAAO,IAAI,cAAc,EAAE,MAAM,gBAAgB,CAAC;AAWzE,OAAO,KAAK,EAaV,eAAe,EAGhB,MAAM,qBAAqB,CAAC;AAE7B,MAAM,WAAW,cAAc;IAC7B,MAAM,EAAE,MAAM,CAAC;IACf,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,wCAAwC;IACxC,MAAM,CAAC,EAAE,MAAM,CAAC;CACjB;AAED,eAAO,MAAM,YAAY;;;;;;;;;;;;;;;;;;;;;;;;;;CA0BS,CAAC;AAEnC,MAAM,MAAM,WAAW,GAAG,OAAO,YAAY,CAAC;AA4G9C,eAAO,MAAM,OAAO;;;;;;;;;;;;;;;;;;;;;;;;;;kBAgNlB,CAAC"}
|