@anvia/sandbox 0.4.1 → 0.5.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.
- package/dist/chunk-FTNNCT6S.js +151 -0
- package/dist/chunk-FTNNCT6S.js.map +1 -0
- package/dist/cli.d.ts +62 -0
- package/dist/cli.js +836 -0
- package/dist/cli.js.map +1 -0
- package/dist/index.js +22 -145
- package/dist/index.js.map +1 -1
- package/package.json +10 -3
|
@@ -0,0 +1,151 @@
|
|
|
1
|
+
// src/errors.ts
|
|
2
|
+
var SandboxError = class extends Error {
|
|
3
|
+
constructor(message, cause) {
|
|
4
|
+
super(message);
|
|
5
|
+
this.cause = cause;
|
|
6
|
+
this.name = new.target.name;
|
|
7
|
+
}
|
|
8
|
+
cause;
|
|
9
|
+
};
|
|
10
|
+
var SandboxDockerUnavailableError = class extends SandboxError {
|
|
11
|
+
};
|
|
12
|
+
var SandboxDockerCommandError = class extends SandboxError {
|
|
13
|
+
constructor(message, result) {
|
|
14
|
+
super(message);
|
|
15
|
+
this.result = result;
|
|
16
|
+
}
|
|
17
|
+
result;
|
|
18
|
+
};
|
|
19
|
+
var SandboxSessionDestroyedError = class extends SandboxError {
|
|
20
|
+
};
|
|
21
|
+
var SandboxPathError = class extends SandboxError {
|
|
22
|
+
};
|
|
23
|
+
var SandboxTimeoutError = class extends SandboxError {
|
|
24
|
+
};
|
|
25
|
+
var SandboxFileSizeError = class extends SandboxError {
|
|
26
|
+
};
|
|
27
|
+
var SandboxToolPolicyError = class extends SandboxError {
|
|
28
|
+
};
|
|
29
|
+
var SandboxPortError = class extends SandboxError {
|
|
30
|
+
};
|
|
31
|
+
var SandboxProcessError = class extends SandboxError {
|
|
32
|
+
};
|
|
33
|
+
|
|
34
|
+
// src/docker-cli.ts
|
|
35
|
+
import { spawn } from "child_process";
|
|
36
|
+
var defaultMaxOutputBytes = 1024 * 1024;
|
|
37
|
+
async function runDockerCli(args, options) {
|
|
38
|
+
const startedAt = Date.now();
|
|
39
|
+
const maxOutputBytes = options.maxOutputBytes ?? defaultMaxOutputBytes;
|
|
40
|
+
const stdout = createOutputCollector(maxOutputBytes, options.onStdout);
|
|
41
|
+
const stderr = createOutputCollector(maxOutputBytes, options.onStderr);
|
|
42
|
+
return new Promise((resolve, reject) => {
|
|
43
|
+
const child = spawn(options.dockerPath, args, {
|
|
44
|
+
stdio: ["pipe", "pipe", "pipe"]
|
|
45
|
+
});
|
|
46
|
+
let timedOut = false;
|
|
47
|
+
let aborted = false;
|
|
48
|
+
let settled = false;
|
|
49
|
+
const timeout = options.timeoutMs === void 0 ? void 0 : setTimeout(() => {
|
|
50
|
+
timedOut = true;
|
|
51
|
+
child.kill("SIGKILL");
|
|
52
|
+
}, options.timeoutMs);
|
|
53
|
+
const abort = () => {
|
|
54
|
+
aborted = true;
|
|
55
|
+
child.kill("SIGKILL");
|
|
56
|
+
};
|
|
57
|
+
if (options.signal?.aborted === true) {
|
|
58
|
+
abort();
|
|
59
|
+
} else {
|
|
60
|
+
options.signal?.addEventListener("abort", abort, { once: true });
|
|
61
|
+
}
|
|
62
|
+
child.stdout.on("data", (chunk) => stdout.accept(chunk));
|
|
63
|
+
child.stderr.on("data", (chunk) => stderr.accept(chunk));
|
|
64
|
+
child.on("error", (error) => {
|
|
65
|
+
if (settled) {
|
|
66
|
+
return;
|
|
67
|
+
}
|
|
68
|
+
settled = true;
|
|
69
|
+
clearTimeout(timeout);
|
|
70
|
+
options.signal?.removeEventListener("abort", abort);
|
|
71
|
+
if (error.code === "ENOENT") {
|
|
72
|
+
reject(new SandboxDockerUnavailableError("Docker CLI was not found.", error));
|
|
73
|
+
return;
|
|
74
|
+
}
|
|
75
|
+
reject(error);
|
|
76
|
+
});
|
|
77
|
+
child.on("close", (code) => {
|
|
78
|
+
if (settled) {
|
|
79
|
+
return;
|
|
80
|
+
}
|
|
81
|
+
settled = true;
|
|
82
|
+
clearTimeout(timeout);
|
|
83
|
+
options.signal?.removeEventListener("abort", abort);
|
|
84
|
+
resolve({
|
|
85
|
+
stdout: stdout.text(),
|
|
86
|
+
stderr: stderr.text(),
|
|
87
|
+
exitCode: code ?? 1,
|
|
88
|
+
durationMs: Date.now() - startedAt,
|
|
89
|
+
timedOut,
|
|
90
|
+
aborted,
|
|
91
|
+
stdoutTruncated: stdout.truncated,
|
|
92
|
+
stderrTruncated: stderr.truncated
|
|
93
|
+
});
|
|
94
|
+
});
|
|
95
|
+
if (options.input !== void 0) {
|
|
96
|
+
child.stdin.end(options.input);
|
|
97
|
+
} else {
|
|
98
|
+
child.stdin.end();
|
|
99
|
+
}
|
|
100
|
+
});
|
|
101
|
+
}
|
|
102
|
+
async function assertDockerCli(args, options) {
|
|
103
|
+
const result = await runDockerCli(args, options);
|
|
104
|
+
if (result.exitCode !== 0) {
|
|
105
|
+
throw new SandboxDockerCommandError(`Docker command failed: docker ${args.join(" ")}`, result);
|
|
106
|
+
}
|
|
107
|
+
return result.stdout.trim();
|
|
108
|
+
}
|
|
109
|
+
function createOutputCollector(maxBytes, onChunk) {
|
|
110
|
+
const chunks = [];
|
|
111
|
+
let length = 0;
|
|
112
|
+
let truncated = false;
|
|
113
|
+
return {
|
|
114
|
+
get truncated() {
|
|
115
|
+
return truncated;
|
|
116
|
+
},
|
|
117
|
+
accept(chunk) {
|
|
118
|
+
onChunk?.(chunk);
|
|
119
|
+
if (length >= maxBytes) {
|
|
120
|
+
truncated = true;
|
|
121
|
+
return;
|
|
122
|
+
}
|
|
123
|
+
const remaining = maxBytes - length;
|
|
124
|
+
const next = chunk.length > remaining ? chunk.subarray(0, remaining) : chunk;
|
|
125
|
+
chunks.push(next);
|
|
126
|
+
length += next.length;
|
|
127
|
+
if (next.length < chunk.length) {
|
|
128
|
+
truncated = true;
|
|
129
|
+
}
|
|
130
|
+
},
|
|
131
|
+
text() {
|
|
132
|
+
return Buffer.concat(chunks, length).toString("utf8");
|
|
133
|
+
}
|
|
134
|
+
};
|
|
135
|
+
}
|
|
136
|
+
|
|
137
|
+
export {
|
|
138
|
+
SandboxError,
|
|
139
|
+
SandboxDockerUnavailableError,
|
|
140
|
+
SandboxDockerCommandError,
|
|
141
|
+
SandboxSessionDestroyedError,
|
|
142
|
+
SandboxPathError,
|
|
143
|
+
SandboxTimeoutError,
|
|
144
|
+
SandboxFileSizeError,
|
|
145
|
+
SandboxToolPolicyError,
|
|
146
|
+
SandboxPortError,
|
|
147
|
+
SandboxProcessError,
|
|
148
|
+
runDockerCli,
|
|
149
|
+
assertDockerCli
|
|
150
|
+
};
|
|
151
|
+
//# sourceMappingURL=chunk-FTNNCT6S.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../src/errors.ts","../src/docker-cli.ts"],"sourcesContent":["export class SandboxError extends Error {\n constructor(\n message: string,\n readonly cause?: unknown,\n ) {\n super(message);\n this.name = new.target.name;\n }\n}\n\nexport class SandboxDockerUnavailableError extends SandboxError {}\n\nexport class SandboxDockerCommandError extends SandboxError {\n constructor(\n message: string,\n readonly result: {\n stdout: string;\n stderr: string;\n exitCode: number;\n },\n ) {\n super(message);\n }\n}\n\nexport class SandboxSessionDestroyedError extends SandboxError {}\n\nexport class SandboxPathError extends SandboxError {}\n\nexport class SandboxTimeoutError extends SandboxError {}\n\nexport class SandboxFileSizeError extends SandboxError {}\n\nexport class SandboxToolPolicyError extends SandboxError {}\n\nexport class SandboxPortError extends SandboxError {}\n\nexport class SandboxProcessError extends SandboxError {}\n","import { spawn } from \"node:child_process\";\nimport { SandboxDockerCommandError, SandboxDockerUnavailableError } from \"./errors\";\n\nexport interface DockerCliResult {\n stdout: string;\n stderr: string;\n exitCode: number;\n durationMs: number;\n timedOut: boolean;\n aborted: boolean;\n stdoutTruncated: boolean;\n stderrTruncated: boolean;\n}\n\nexport interface DockerCliOptions {\n dockerPath: string;\n timeoutMs?: number;\n maxOutputBytes?: number;\n input?: string | Uint8Array;\n signal?: AbortSignal;\n onStdout?: (chunk: Uint8Array) => void;\n onStderr?: (chunk: Uint8Array) => void;\n}\n\nconst defaultMaxOutputBytes = 1024 * 1024;\n\nexport async function runDockerCli(\n args: string[],\n options: DockerCliOptions,\n): Promise<DockerCliResult> {\n const startedAt = Date.now();\n const maxOutputBytes = options.maxOutputBytes ?? defaultMaxOutputBytes;\n const stdout = createOutputCollector(maxOutputBytes, options.onStdout);\n const stderr = createOutputCollector(maxOutputBytes, options.onStderr);\n\n return new Promise((resolve, reject) => {\n const child = spawn(options.dockerPath, args, {\n stdio: [\"pipe\", \"pipe\", \"pipe\"],\n });\n\n let timedOut = false;\n let aborted = false;\n let settled = false;\n\n const timeout =\n options.timeoutMs === undefined\n ? undefined\n : setTimeout(() => {\n timedOut = true;\n child.kill(\"SIGKILL\");\n }, options.timeoutMs);\n\n const abort = () => {\n aborted = true;\n child.kill(\"SIGKILL\");\n };\n\n if (options.signal?.aborted === true) {\n abort();\n } else {\n options.signal?.addEventListener(\"abort\", abort, { once: true });\n }\n\n child.stdout.on(\"data\", (chunk: Buffer) => stdout.accept(chunk));\n child.stderr.on(\"data\", (chunk: Buffer) => stderr.accept(chunk));\n\n child.on(\"error\", (error) => {\n if (settled) {\n return;\n }\n settled = true;\n clearTimeout(timeout);\n options.signal?.removeEventListener(\"abort\", abort);\n\n if ((error as NodeJS.ErrnoException).code === \"ENOENT\") {\n reject(new SandboxDockerUnavailableError(\"Docker CLI was not found.\", error));\n return;\n }\n\n reject(error);\n });\n\n child.on(\"close\", (code) => {\n if (settled) {\n return;\n }\n settled = true;\n clearTimeout(timeout);\n options.signal?.removeEventListener(\"abort\", abort);\n\n resolve({\n stdout: stdout.text(),\n stderr: stderr.text(),\n exitCode: code ?? 1,\n durationMs: Date.now() - startedAt,\n timedOut,\n aborted,\n stdoutTruncated: stdout.truncated,\n stderrTruncated: stderr.truncated,\n });\n });\n\n if (options.input !== undefined) {\n child.stdin.end(options.input);\n } else {\n child.stdin.end();\n }\n });\n}\n\nexport async function assertDockerCli(args: string[], options: DockerCliOptions): Promise<string> {\n const result = await runDockerCli(args, options);\n\n if (result.exitCode !== 0) {\n throw new SandboxDockerCommandError(`Docker command failed: docker ${args.join(\" \")}`, result);\n }\n\n return result.stdout.trim();\n}\n\nfunction createOutputCollector(maxBytes: number, onChunk?: (chunk: Uint8Array) => void) {\n const chunks: Buffer[] = [];\n let length = 0;\n let truncated = false;\n\n return {\n get truncated() {\n return truncated;\n },\n accept(chunk: Buffer) {\n onChunk?.(chunk);\n\n if (length >= maxBytes) {\n truncated = true;\n return;\n }\n\n const remaining = maxBytes - length;\n const next = chunk.length > remaining ? chunk.subarray(0, remaining) : chunk;\n chunks.push(next);\n length += next.length;\n\n if (next.length < chunk.length) {\n truncated = true;\n }\n },\n text() {\n return Buffer.concat(chunks, length).toString(\"utf8\");\n },\n };\n}\n"],"mappings":"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","names":[]}
|
package/dist/cli.d.ts
ADDED
|
@@ -0,0 +1,62 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
type SandboxImageRuntime = "node" | "bun" | "python";
|
|
3
|
+
type SandboxImageFeature = "artifacts" | "playwright";
|
|
4
|
+
interface SandboxImageVersions {
|
|
5
|
+
node: string;
|
|
6
|
+
pnpm: string;
|
|
7
|
+
bun: string;
|
|
8
|
+
python: string;
|
|
9
|
+
uv: string;
|
|
10
|
+
playwright: string;
|
|
11
|
+
}
|
|
12
|
+
|
|
13
|
+
interface CliOptions {
|
|
14
|
+
command?: string;
|
|
15
|
+
name?: string;
|
|
16
|
+
tag?: string;
|
|
17
|
+
output?: string;
|
|
18
|
+
runtimes: SandboxImageRuntime[];
|
|
19
|
+
features: SandboxImageFeature[];
|
|
20
|
+
apt: string[];
|
|
21
|
+
npm: string[];
|
|
22
|
+
uv: string[];
|
|
23
|
+
versions: Partial<SandboxImageVersions>;
|
|
24
|
+
dockerPath: string;
|
|
25
|
+
build: boolean;
|
|
26
|
+
buildExplicit: boolean;
|
|
27
|
+
dryRun: boolean;
|
|
28
|
+
force: boolean;
|
|
29
|
+
help: boolean;
|
|
30
|
+
}
|
|
31
|
+
interface SandboxImageCliIo {
|
|
32
|
+
log(message: string): void;
|
|
33
|
+
warn(message: string): void;
|
|
34
|
+
error(message: string): void;
|
|
35
|
+
stdout(chunk: Uint8Array): void;
|
|
36
|
+
stderr(chunk: Uint8Array): void;
|
|
37
|
+
}
|
|
38
|
+
interface SandboxImagePromptResult {
|
|
39
|
+
name: string;
|
|
40
|
+
runtimes: SandboxImageRuntime[];
|
|
41
|
+
features: SandboxImageFeature[];
|
|
42
|
+
apt: string[];
|
|
43
|
+
npm: string[];
|
|
44
|
+
uv: string[];
|
|
45
|
+
tag?: string;
|
|
46
|
+
output?: string;
|
|
47
|
+
build: boolean;
|
|
48
|
+
}
|
|
49
|
+
interface SandboxImageCliDependencies {
|
|
50
|
+
isTTY?: boolean;
|
|
51
|
+
packageVersion?: string;
|
|
52
|
+
prompt?: (options: Readonly<CliOptions>) => Promise<SandboxImagePromptResult | undefined>;
|
|
53
|
+
buildImage?: (input: {
|
|
54
|
+
contextPath: string;
|
|
55
|
+
tag: string;
|
|
56
|
+
dockerPath: string;
|
|
57
|
+
io: SandboxImageCliIo;
|
|
58
|
+
}) => Promise<void>;
|
|
59
|
+
}
|
|
60
|
+
declare function runCli(argv?: string[], cwd?: string, io?: SandboxImageCliIo, dependencies?: SandboxImageCliDependencies): Promise<number>;
|
|
61
|
+
|
|
62
|
+
export { type SandboxImageCliDependencies, type SandboxImageCliIo, type SandboxImagePromptResult, runCli };
|