@computesdk/docker 1.2.43 → 1.2.45
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 +8 -8
- package/dist/index.d.mts +3 -3
- package/dist/index.d.ts +3 -3
- package/dist/index.js +18 -107
- package/dist/index.js.map +1 -1
- package/dist/index.mjs +18 -107
- package/dist/index.mjs.map +1 -1
- package/package.json +4 -4
package/README.md
CHANGED
|
@@ -45,7 +45,7 @@ import { compute } from 'computesdk';
|
|
|
45
45
|
// Auto-detects Docker (requires Docker daemon running)
|
|
46
46
|
const sandbox = await compute.sandbox.create();
|
|
47
47
|
|
|
48
|
-
const result = await sandbox.
|
|
48
|
+
const result = await sandbox.runCommand('python -c "print(\"Hello from Python\")"');
|
|
49
49
|
console.log(result.stdout.trim()); // Hello from Python
|
|
50
50
|
|
|
51
51
|
await sandbox.destroy();
|
|
@@ -65,7 +65,7 @@ const compute = docker({
|
|
|
65
65
|
|
|
66
66
|
// Create a sandbox and run Python
|
|
67
67
|
const sandbox = await compute.sandbox.create();
|
|
68
|
-
const result = await sandbox.
|
|
68
|
+
const result = await sandbox.runCommand('python -c "print(\"Hello from Python\")"');
|
|
69
69
|
console.log(result.stdout.trim()); // Hello from Python
|
|
70
70
|
|
|
71
71
|
await sandbox.destroy();
|
|
@@ -85,9 +85,9 @@ const compute = docker({
|
|
|
85
85
|
},
|
|
86
86
|
});
|
|
87
87
|
|
|
88
|
-
const sandbox = await compute.sandbox.create(
|
|
88
|
+
const sandbox = await compute.sandbox.create();
|
|
89
89
|
|
|
90
|
-
const result = await sandbox.
|
|
90
|
+
const result = await sandbox.runCommand('node -e "console.log(\"Hello, World!\")"');
|
|
91
91
|
console.log(result.stdout.trim()); // Hello, World!
|
|
92
92
|
|
|
93
93
|
const cmd = await sandbox.runCommand('sh', ['-lc', 'echo Hello from command']);
|
|
@@ -189,7 +189,7 @@ Type: `DockerConfig`
|
|
|
189
189
|
### Code Execution
|
|
190
190
|
|
|
191
191
|
```ts
|
|
192
|
-
sandbox.
|
|
192
|
+
sandbox.runCommand(code: string, runtime?: 'python' | 'node'): Promise<ExecutionResult>
|
|
193
193
|
```
|
|
194
194
|
|
|
195
195
|
* If `runtime` omitted, the sandbox’s runtime (set at creation) is used.
|
|
@@ -239,10 +239,10 @@ await sandbox.destroy();
|
|
|
239
239
|
|
|
240
240
|
There’s **no auto-detection**. Resolution is:
|
|
241
241
|
|
|
242
|
-
1. `
|
|
243
|
-
2.
|
|
242
|
+
1. provider `config.runtime`, else
|
|
243
|
+
2. fallback default in provider config
|
|
244
244
|
|
|
245
|
-
|
|
245
|
+
Use `runCommand('python -c "..."')` or `runCommand('node -e "..."')` when you need language-specific execution.
|
|
246
246
|
|
|
247
247
|
---
|
|
248
248
|
|
package/dist/index.d.mts
CHANGED
|
@@ -1,6 +1,5 @@
|
|
|
1
1
|
import * as _computesdk_provider from '@computesdk/provider';
|
|
2
2
|
import Docker, { DockerOptions, ContainerCreateOptions, ContainerStartOptions, Container } from 'dockerode';
|
|
3
|
-
import { Runtime } from 'computesdk';
|
|
4
3
|
|
|
5
4
|
/** When the provider should clean up containers it created */
|
|
6
5
|
type CleanupPolicy = 'always' | 'onSuccess' | 'never';
|
|
@@ -37,7 +36,7 @@ interface ResourceLimits {
|
|
|
37
36
|
memorySwap?: number;
|
|
38
37
|
pidsLimit?: number;
|
|
39
38
|
}
|
|
40
|
-
/** Declarative container defaults that we
|
|
39
|
+
/** Declarative container defaults that we'll translate into dockerode create options */
|
|
41
40
|
interface ContainerDefaults {
|
|
42
41
|
user?: string;
|
|
43
42
|
workdir?: string;
|
|
@@ -61,7 +60,8 @@ interface ContainerDefaults {
|
|
|
61
60
|
/** Provider-level configuration for Docker */
|
|
62
61
|
interface DockerConfig {
|
|
63
62
|
connection?: DockerConnection;
|
|
64
|
-
runtime
|
|
63
|
+
/** Default image runtime identifier, e.g. 'python' or 'node' */
|
|
64
|
+
runtime?: string;
|
|
65
65
|
timeout?: number;
|
|
66
66
|
image: DockerImage;
|
|
67
67
|
container?: ContainerDefaults;
|
package/dist/index.d.ts
CHANGED
|
@@ -1,6 +1,5 @@
|
|
|
1
1
|
import * as _computesdk_provider from '@computesdk/provider';
|
|
2
2
|
import Docker, { DockerOptions, ContainerCreateOptions, ContainerStartOptions, Container } from 'dockerode';
|
|
3
|
-
import { Runtime } from 'computesdk';
|
|
4
3
|
|
|
5
4
|
/** When the provider should clean up containers it created */
|
|
6
5
|
type CleanupPolicy = 'always' | 'onSuccess' | 'never';
|
|
@@ -37,7 +36,7 @@ interface ResourceLimits {
|
|
|
37
36
|
memorySwap?: number;
|
|
38
37
|
pidsLimit?: number;
|
|
39
38
|
}
|
|
40
|
-
/** Declarative container defaults that we
|
|
39
|
+
/** Declarative container defaults that we'll translate into dockerode create options */
|
|
41
40
|
interface ContainerDefaults {
|
|
42
41
|
user?: string;
|
|
43
42
|
workdir?: string;
|
|
@@ -61,7 +60,8 @@ interface ContainerDefaults {
|
|
|
61
60
|
/** Provider-level configuration for Docker */
|
|
62
61
|
interface DockerConfig {
|
|
63
62
|
connection?: DockerConnection;
|
|
64
|
-
runtime
|
|
63
|
+
/** Default image runtime identifier, e.g. 'python' or 'node' */
|
|
64
|
+
runtime?: string;
|
|
65
65
|
timeout?: number;
|
|
66
66
|
image: DockerImage;
|
|
67
67
|
container?: ContainerDefaults;
|
package/dist/index.js
CHANGED
|
@@ -131,8 +131,7 @@ async function runExec(handle, shellCommand, attachTTY = false) {
|
|
|
131
131
|
stream.on("error", reject);
|
|
132
132
|
});
|
|
133
133
|
const inspect = await exec.inspect();
|
|
134
|
-
|
|
135
|
-
return { stdout, stderr, exitCode };
|
|
134
|
+
return { stdout, stderr, exitCode: inspect.ExitCode ?? 0 };
|
|
136
135
|
}
|
|
137
136
|
function toHostBindings(ports) {
|
|
138
137
|
if (!ports) return void 0;
|
|
@@ -140,10 +139,7 @@ function toHostBindings(ports) {
|
|
|
140
139
|
const bindings = {};
|
|
141
140
|
for (const key of Object.keys(ports)) {
|
|
142
141
|
exposed[key] = {};
|
|
143
|
-
bindings[key] = ports[key].map((p) => ({
|
|
144
|
-
HostPort: p.hostPort ? String(p.hostPort) : void 0,
|
|
145
|
-
HostIp: p.hostIP
|
|
146
|
-
}));
|
|
142
|
+
bindings[key] = ports[key].map((p) => ({ HostPort: p.hostPort ? String(p.hostPort) : void 0, HostIp: p.hostIP }));
|
|
147
143
|
}
|
|
148
144
|
return { ExposedPorts: exposed, PortBindings: bindings };
|
|
149
145
|
}
|
|
@@ -151,8 +147,7 @@ function dockerHostNameFromEnv() {
|
|
|
151
147
|
const hostEnv = process.env.DOCKER_HOST;
|
|
152
148
|
if (hostEnv?.startsWith("tcp://")) {
|
|
153
149
|
try {
|
|
154
|
-
|
|
155
|
-
return u.hostname || "localhost";
|
|
150
|
+
return new URL(hostEnv).hostname || "localhost";
|
|
156
151
|
} catch {
|
|
157
152
|
}
|
|
158
153
|
}
|
|
@@ -180,24 +175,6 @@ var docker = (0, import_provider.defineProvider)({
|
|
|
180
175
|
throw new Error(`Docker provider supports only 'python' or 'node'. Received: ${String(effectiveRuntime)}`);
|
|
181
176
|
}
|
|
182
177
|
const docker2 = new import_dockerode.default(cfg.connection);
|
|
183
|
-
if (options?.sandboxId) {
|
|
184
|
-
try {
|
|
185
|
-
const container2 = docker2.getContainer(options.sandboxId);
|
|
186
|
-
const info = await container2.inspect();
|
|
187
|
-
return {
|
|
188
|
-
sandbox: {
|
|
189
|
-
docker: docker2,
|
|
190
|
-
container: container2,
|
|
191
|
-
containerId: options.sandboxId,
|
|
192
|
-
image: info.Config?.Image ?? cfg.image.name,
|
|
193
|
-
createdAt: new Date(info.Created || Date.now())
|
|
194
|
-
},
|
|
195
|
-
sandboxId: options.sandboxId
|
|
196
|
-
};
|
|
197
|
-
} catch (err) {
|
|
198
|
-
console.warn(`Could not reattach to Docker container with ID ${options.sandboxId}:`, err);
|
|
199
|
-
}
|
|
200
|
-
}
|
|
201
178
|
const chosenImage = pickImageForRuntime(effectiveRuntime, cfg.image);
|
|
202
179
|
await ensureImage(docker2, chosenImage);
|
|
203
180
|
const mergedEnv = { ...cfg.container?.env, ...options?.envs };
|
|
@@ -207,8 +184,6 @@ var docker = (0, import_provider.defineProvider)({
|
|
|
207
184
|
Tty: pick(cfg.container?.tty, false),
|
|
208
185
|
OpenStdin: pick(cfg.container?.openStdin, false),
|
|
209
186
|
Labels: {
|
|
210
|
-
// User metadata is spread first with a namespaced prefix so it
|
|
211
|
-
// cannot overwrite the reserved discovery/runtime labels below.
|
|
212
187
|
...options?.metadata ? Object.fromEntries(
|
|
213
188
|
Object.entries(options.metadata).map(([k, v]) => [`com.computesdk.meta.${k}`, typeof v === "string" ? v : JSON.stringify(v)])
|
|
214
189
|
) : {},
|
|
@@ -218,10 +193,8 @@ var docker = (0, import_provider.defineProvider)({
|
|
|
218
193
|
WorkingDir: cfg.container?.workdir,
|
|
219
194
|
Env: Object.keys(mergedEnv).length > 0 ? Object.entries(mergedEnv).map(([k, v]) => `${k}=${v}`) : void 0,
|
|
220
195
|
Cmd: KEEPALIVE_CMD,
|
|
221
|
-
// keep container alive
|
|
222
196
|
HostConfig: {
|
|
223
197
|
AutoRemove: cfg.container?.autoRemove ?? false,
|
|
224
|
-
// keep around for exec/FS ops
|
|
225
198
|
Binds: cfg.container?.binds,
|
|
226
199
|
NetworkMode: cfg.container?.networkMode,
|
|
227
200
|
Privileged: cfg.container?.privileged,
|
|
@@ -229,14 +202,12 @@ var docker = (0, import_provider.defineProvider)({
|
|
|
229
202
|
CapDrop: cfg.container?.capabilities?.drop,
|
|
230
203
|
LogConfig: cfg.container?.logDriver ? { Type: cfg.container.logDriver, Config: cfg.container.logOpts || {} } : void 0,
|
|
231
204
|
Resources: cfg.container?.resources,
|
|
232
|
-
DeviceRequests: cfg.container?.gpus ? [
|
|
233
|
-
|
|
234
|
-
|
|
235
|
-
|
|
236
|
-
|
|
237
|
-
|
|
238
|
-
}
|
|
239
|
-
] : void 0,
|
|
205
|
+
DeviceRequests: cfg.container?.gpus ? [{
|
|
206
|
+
Driver: "nvidia",
|
|
207
|
+
Count: cfg.container.gpus === "all" ? -1 : typeof cfg.container.gpus === "number" ? cfg.container.gpus : 1,
|
|
208
|
+
DeviceIDs: typeof cfg.container.gpus === "string" && cfg.container.gpus !== "all" ? [String(cfg.container.gpus)] : void 0,
|
|
209
|
+
Capabilities: [["gpu"]]
|
|
210
|
+
}] : void 0,
|
|
240
211
|
...hb ? { PortBindings: hb.PortBindings } : {}
|
|
241
212
|
},
|
|
242
213
|
...hb ? { ExposedPorts: hb.ExposedPorts } : {},
|
|
@@ -260,16 +231,7 @@ var docker = (0, import_provider.defineProvider)({
|
|
|
260
231
|
try {
|
|
261
232
|
const container = docker2.getContainer(sandboxId);
|
|
262
233
|
const info = await container.inspect();
|
|
263
|
-
return {
|
|
264
|
-
sandbox: {
|
|
265
|
-
docker: docker2,
|
|
266
|
-
container,
|
|
267
|
-
containerId: sandboxId,
|
|
268
|
-
image: info.Config?.Image ?? "",
|
|
269
|
-
createdAt: new Date(info.Created || Date.now())
|
|
270
|
-
},
|
|
271
|
-
sandboxId
|
|
272
|
-
};
|
|
234
|
+
return { sandbox: { docker: docker2, container, containerId: sandboxId, image: info.Config?.Image ?? "", createdAt: new Date(info.Created || Date.now()) }, sandboxId };
|
|
273
235
|
} catch {
|
|
274
236
|
return null;
|
|
275
237
|
}
|
|
@@ -277,18 +239,9 @@ var docker = (0, import_provider.defineProvider)({
|
|
|
277
239
|
list: async (config) => {
|
|
278
240
|
const docker2 = new import_dockerode.default((config || defaultDockerConfig).connection);
|
|
279
241
|
try {
|
|
280
|
-
const items = await docker2.listContainers({
|
|
281
|
-
all: true,
|
|
282
|
-
filters: { label: [LABEL_KEY] }
|
|
283
|
-
});
|
|
242
|
+
const items = await docker2.listContainers({ all: true, filters: { label: [LABEL_KEY] } });
|
|
284
243
|
return items.map((ci) => ({
|
|
285
|
-
sandbox: {
|
|
286
|
-
docker: docker2,
|
|
287
|
-
container: docker2.getContainer(ci.Id),
|
|
288
|
-
containerId: ci.Id,
|
|
289
|
-
image: ci.Image,
|
|
290
|
-
createdAt: new Date(ci.Created * 1e3)
|
|
291
|
-
},
|
|
244
|
+
sandbox: { docker: docker2, container: docker2.getContainer(ci.Id), containerId: ci.Id, image: ci.Image, createdAt: new Date(ci.Created * 1e3) },
|
|
292
245
|
sandboxId: ci.Id
|
|
293
246
|
}));
|
|
294
247
|
} catch {
|
|
@@ -307,42 +260,10 @@ var docker = (0, import_provider.defineProvider)({
|
|
|
307
260
|
} catch {
|
|
308
261
|
}
|
|
309
262
|
},
|
|
310
|
-
|
|
311
|
-
const start = Date.now();
|
|
312
|
-
let rt = runtime;
|
|
313
|
-
if (!rt) {
|
|
314
|
-
const info = await handle.container.inspect();
|
|
315
|
-
rt = info.Config?.Labels?.[LABEL_RUNTIME] || void 0;
|
|
316
|
-
}
|
|
317
|
-
if (rt !== "python" && rt !== "node") {
|
|
318
|
-
throw new Error(`Docker runtime must be 'python' or 'node'. Pass runtime in config or as a parameter.`);
|
|
319
|
-
}
|
|
320
|
-
const tmpFile = rt === "python" ? "/tmp/compute_code.py" : "/tmp/compute_code.js";
|
|
321
|
-
const b64 = Buffer.from(code, "utf8").toString("base64");
|
|
322
|
-
const makeAndRun = `printf '%s' "${b64}" | base64 -d > ${tmpFile} && ` + (rt === "python" ? `python3 ${tmpFile}` : `node ${tmpFile}`);
|
|
323
|
-
const { stdout, stderr, exitCode } = await runExec(handle, makeAndRun);
|
|
324
|
-
if (exitCode !== 0 && stderr) {
|
|
325
|
-
const isSyntax = stderr.includes("SyntaxError") || stderr.includes("invalid syntax") || stderr.includes("Unexpected token") || stderr.includes("Unexpected identifier");
|
|
326
|
-
if (isSyntax) {
|
|
327
|
-
const last = stderr.trim().split("\n").slice(-1)[0] || "Syntax error";
|
|
328
|
-
throw new Error(`Syntax error: ${last}`);
|
|
329
|
-
}
|
|
330
|
-
}
|
|
331
|
-
return {
|
|
332
|
-
output: stdout + stderr,
|
|
333
|
-
exitCode,
|
|
334
|
-
language: rt
|
|
335
|
-
};
|
|
336
|
-
},
|
|
337
|
-
runCommand: async (handle, command, options) => {
|
|
263
|
+
runCommand: async (handle, command, _options) => {
|
|
338
264
|
const start = Date.now();
|
|
339
265
|
const { stdout, stderr, exitCode } = await runExec(handle, command);
|
|
340
|
-
return {
|
|
341
|
-
stdout,
|
|
342
|
-
stderr,
|
|
343
|
-
exitCode,
|
|
344
|
-
durationMs: Date.now() - start
|
|
345
|
-
};
|
|
266
|
+
return { stdout, stderr, exitCode, durationMs: Date.now() - start };
|
|
346
267
|
},
|
|
347
268
|
getInfo: async (handle) => {
|
|
348
269
|
const info = await handle.container.inspect();
|
|
@@ -350,13 +271,13 @@ var docker = (0, import_provider.defineProvider)({
|
|
|
350
271
|
return {
|
|
351
272
|
id: handle.containerId,
|
|
352
273
|
provider: PROVIDER,
|
|
353
|
-
runtime: info.Config?.Labels?.[LABEL_RUNTIME] || "python",
|
|
354
274
|
status: state.Running ? "running" : "stopped",
|
|
355
275
|
createdAt: new Date(info.Created || handle.createdAt),
|
|
356
276
|
timeout: 3e5,
|
|
357
277
|
metadata: {
|
|
358
278
|
image: info.Config?.Image,
|
|
359
|
-
name: info.Name
|
|
279
|
+
name: info.Name,
|
|
280
|
+
runtime: info.Config?.Labels?.[LABEL_RUNTIME]
|
|
360
281
|
}
|
|
361
282
|
};
|
|
362
283
|
},
|
|
@@ -394,10 +315,7 @@ var docker = (0, import_provider.defineProvider)({
|
|
|
394
315
|
if (exitCode !== 0) throw new Error(stderr || `Failed to mkdir: ${path}`);
|
|
395
316
|
},
|
|
396
317
|
readdir: async (handle, path) => {
|
|
397
|
-
const { stdout, exitCode, stderr } = await runExec(
|
|
398
|
-
handle,
|
|
399
|
-
`if [ -d ${JSON.stringify(path)} ]; then ls -la ${JSON.stringify(path)}; else exit 1; fi`
|
|
400
|
-
);
|
|
318
|
+
const { stdout, exitCode, stderr } = await runExec(handle, `if [ -d ${JSON.stringify(path)} ]; then ls -la ${JSON.stringify(path)}; else exit 1; fi`);
|
|
401
319
|
if (exitCode !== 0) throw new Error(stderr || `Not a directory: ${path}`);
|
|
402
320
|
const lines = stdout.split("\n").slice(1);
|
|
403
321
|
const entries = [];
|
|
@@ -406,14 +324,7 @@ var docker = (0, import_provider.defineProvider)({
|
|
|
406
324
|
if (parts.length < 9) continue;
|
|
407
325
|
const name = parts.slice(8).join(" ");
|
|
408
326
|
if (name === "." || name === "..") continue;
|
|
409
|
-
|
|
410
|
-
const size = Number(parts[4]) || 0;
|
|
411
|
-
entries.push({
|
|
412
|
-
name,
|
|
413
|
-
type: isDir ? "directory" : "file",
|
|
414
|
-
size,
|
|
415
|
-
modified: /* @__PURE__ */ new Date()
|
|
416
|
-
});
|
|
327
|
+
entries.push({ name, type: parts[0].startsWith("d") ? "directory" : "file", size: Number(parts[4]) || 0, modified: /* @__PURE__ */ new Date() });
|
|
417
328
|
}
|
|
418
329
|
return entries;
|
|
419
330
|
},
|
package/dist/index.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../src/index.ts","../src/types/types.ts"],"sourcesContent":["import Docker from 'dockerode';\nimport { PassThrough } from 'stream';\nimport { defineProvider } from '@computesdk/provider';\nimport type {\n Runtime,\n CodeResult,\n CommandResult,\n RunCommandOptions,\n CreateSandboxOptions,\n SandboxInfo,\n FileEntry,\n} from '@computesdk/provider';\n\nimport { defaultDockerConfig } from './types/types';\nimport type {\n DockerConfig,\n DockerSandboxHandle,\n DockerImage,\n PortBindings,\n} from './types/types';\n\nconst PROVIDER = 'docker' as const;\nconst LABEL_KEY = 'com.computesdk.sandbox';\nconst LABEL_RUNTIME = 'com.computesdk.runtime';\nconst KEEPALIVE_CMD = ['/bin/sh', '-c', 'while :; do sleep 3600; done'];\n\nfunction pick<T>(val: T | undefined, fallback: T): T {\n return typeof val === 'undefined' ? fallback : val;\n}\n\nasync function ensureImage(docker: Docker, image: DockerImage): Promise<void> {\n const policy = image.pullPolicy ?? 'ifNotPresent';\n if (policy === 'never') return;\n\n const images = await docker.listImages();\n const hasImage = images.some(img => (img.RepoTags || []).includes(image.name));\n\n if (policy === 'always' || (policy === 'ifNotPresent' && !hasImage)) {\n await new Promise<void>((resolve, reject) => {\n const cb = (err: any, stream?: NodeJS.ReadableStream) => {\n if (err) return reject(err);\n if (!stream) return reject(new Error('docker.pull returned no stream'));\n (docker as any).modem.followProgress(stream, (err2: any) => (err2 ? reject(err2) : resolve()));\n };\n if (image.auth) docker.pull(image.name, { authconfig: image.auth } as any, cb);\n else docker.pull(image.name, cb);\n });\n }\n}\n\nasync function waitUntilRunning(container: Docker.Container, timeoutMs = 4000) {\n const start = Date.now();\n try {\n const s = await container.inspect();\n if (s.State?.Running) return;\n } catch { /* ignore */ }\n\n while (Date.now() - start < timeoutMs) {\n const s = await container.inspect();\n if (s.State?.Running) return;\n await new Promise(r => setTimeout(r, 100));\n }\n throw new Error('Container did not reach Running state in time');\n}\n\nasync function runExec(\n handle: DockerSandboxHandle,\n shellCommand: string,\n attachTTY = false\n): Promise<{ stdout: string; stderr: string; exitCode: number }> {\n await waitUntilRunning(handle.container);\n\n const exec = await handle.container.exec({\n Cmd: ['/bin/sh', '-c', shellCommand],\n AttachStdout: true,\n AttachStderr: true,\n Tty: attachTTY,\n });\n\n const stream = (await exec.start({ hijack: true, stdin: false })) as NodeJS.ReadableStream;\n\n let stdout = '';\n let stderr = '';\n\n await new Promise<void>((resolve, reject) => {\n if (attachTTY) {\n stream.on('data', (chunk: Buffer) => (stdout += chunk.toString('utf8')));\n stream.on('end', resolve);\n stream.on('error', reject);\n return;\n }\n const out = new PassThrough();\n const err = new PassThrough();\n out.on('data', (c: Buffer) => (stdout += c.toString('utf8')));\n err.on('data', (c: Buffer) => (stderr += c.toString('utf8')));\n (handle.docker as any).modem.demuxStream(stream as any, out as any, err as any);\n stream.on('end', resolve);\n stream.on('error', reject);\n });\n\n const inspect = await exec.inspect();\n const exitCode = inspect.ExitCode ?? 0;\n return { stdout, stderr, exitCode };\n}\n\nfunction toHostBindings(ports?: PortBindings) {\n if (!ports) return undefined;\n const exposed: Record<string, {}> = {};\n const bindings: Record<string, Array<{ HostPort?: string; HostIp?: string }>> = {};\n for (const key of Object.keys(ports)) {\n exposed[key] = {};\n bindings[key] = (ports as any)[key].map((p: any) => ({\n HostPort: p.hostPort ? String(p.hostPort) : undefined,\n HostIp: p.hostIP,\n }));\n }\n return { ExposedPorts: exposed, PortBindings: bindings };\n}\n\nfunction dockerHostNameFromEnv(): string {\n const hostEnv = process.env.DOCKER_HOST;\n if (hostEnv?.startsWith('tcp://')) {\n try {\n const u = new URL(hostEnv);\n return u.hostname || 'localhost';\n } catch { /* noop */ }\n }\n return 'localhost';\n}\n\nfunction pickImageForRuntime(runtime: Runtime, configured?: DockerImage): DockerImage {\n // If user supplied an image that already matches, use it. Otherwise pick a sensible default.\n if (configured?.name) {\n if (runtime === 'python' && /python|conda|pypy/i.test(configured.name)) return configured;\n if (runtime === 'node' && /node/i.test(configured.name)) return configured;\n }\n return {\n name: runtime === 'python' ? 'python:3.11-slim' : 'node:20-alpine',\n pullPolicy: configured?.pullPolicy ?? 'ifNotPresent',\n auth: configured?.auth,\n };\n}\n\nexport const docker = defineProvider<DockerSandboxHandle, DockerConfig>({\n name: PROVIDER,\n methods: {\n sandbox: {\n create: async (config: DockerConfig, options?: CreateSandboxOptions) => {\n const cfg: DockerConfig = { ...defaultDockerConfig, ...config };\n const effectiveRuntime: Runtime = (options?.runtime ?? cfg.runtime ?? 'python') as Runtime;\n\n if (effectiveRuntime !== 'python' && effectiveRuntime !== 'node') {\n throw new Error(`Docker provider supports only 'python' or 'node'. Received: ${String(effectiveRuntime)}`);\n }\n\n const docker = new Docker(cfg.connection as any);\n\n // Reattach?\n if (options?.sandboxId) {\n try {\n const container = docker.getContainer(options.sandboxId);\n const info = await container.inspect();\n return {\n sandbox: <DockerSandboxHandle>{\n docker,\n container,\n containerId: options.sandboxId,\n image: info.Config?.Image ?? cfg.image.name,\n createdAt: new Date(info.Created || Date.now()),\n },\n sandboxId: options.sandboxId,\n };\n } catch (err) {\n // Failed to reattach to existing container; will create a new one.\n console.warn(`Could not reattach to Docker container with ID ${options.sandboxId}:`, err);\n }\n }\n\n // Choose image based on runtime if needed\n const chosenImage = pickImageForRuntime(effectiveRuntime, cfg.image);\n await ensureImage(docker, chosenImage);\n\n // Merge environment variables: config.container.env < options.envs\n const mergedEnv = { ...cfg.container?.env, ...options?.envs };\n\n // Build container create options\n const hb = toHostBindings(cfg.container?.ports);\n const createOptions = {\n Image: chosenImage.name,\n Tty: pick(cfg.container?.tty, false),\n OpenStdin: pick(cfg.container?.openStdin, false),\n Labels: {\n // User metadata is spread first with a namespaced prefix so it\n // cannot overwrite the reserved discovery/runtime labels below.\n ...(options?.metadata ? Object.fromEntries(\n Object.entries(options.metadata).map(([k, v]) => [`com.computesdk.meta.${k}`, typeof v === 'string' ? v : JSON.stringify(v)])\n ) : {}),\n [LABEL_KEY]: 'true',\n [LABEL_RUNTIME]: effectiveRuntime,\n },\n WorkingDir: cfg.container?.workdir,\n Env: Object.keys(mergedEnv).length > 0\n ? Object.entries(mergedEnv).map(([k, v]) => `${k}=${v}`)\n : undefined,\n Cmd: KEEPALIVE_CMD, // keep container alive\n HostConfig: {\n AutoRemove: cfg.container?.autoRemove ?? false, // keep around for exec/FS ops\n Binds: cfg.container?.binds,\n NetworkMode: cfg.container?.networkMode,\n Privileged: cfg.container?.privileged,\n CapAdd: cfg.container?.capabilities?.add,\n CapDrop: cfg.container?.capabilities?.drop,\n LogConfig: cfg.container?.logDriver\n ? { Type: cfg.container.logDriver, Config: cfg.container.logOpts || {} }\n : undefined,\n Resources: cfg.container?.resources,\n DeviceRequests: cfg.container?.gpus\n ? [\n {\n Driver: 'nvidia',\n Count:\n cfg.container.gpus === 'all'\n ? -1\n : typeof cfg.container.gpus === 'number'\n ? cfg.container.gpus\n : 1,\n DeviceIDs:\n typeof cfg.container.gpus === 'string' && cfg.container.gpus !== 'all'\n ? [String(cfg.container.gpus)]\n : undefined,\n Capabilities: [['gpu']],\n },\n ]\n : undefined,\n ...(hb ? { PortBindings: hb.PortBindings } : {}),\n },\n ...(hb ? { ExposedPorts: hb.ExposedPorts } : {}),\n ...(cfg.createOptions || {}),\n } as import('dockerode').ContainerCreateOptions;\n\n const container = await docker.createContainer(createOptions);\n await container.start(cfg.startOptions || {});\n await waitUntilRunning(container);\n\n const inspect = await container.inspect();\n const handle: DockerSandboxHandle = {\n docker,\n container,\n containerId: inspect.Id,\n image: inspect.Config?.Image ?? chosenImage.name,\n createdAt: new Date(inspect.Created || Date.now()),\n };\n\n return { sandbox: handle, sandboxId: handle.containerId };\n },\n\n getById: async (config: DockerConfig, sandboxId: string) => {\n const docker = new Docker((config || defaultDockerConfig).connection as any);\n try {\n const container = docker.getContainer(sandboxId);\n const info = await container.inspect();\n return {\n sandbox: <DockerSandboxHandle>{\n docker,\n container,\n containerId: sandboxId,\n image: info.Config?.Image ?? '',\n createdAt: new Date(info.Created || Date.now()),\n },\n sandboxId,\n };\n } catch {\n return null;\n }\n },\n\n list: async (config: DockerConfig) => {\n const docker = new Docker((config || defaultDockerConfig).connection as any);\n try {\n const items = await docker.listContainers({\n all: true,\n filters: { label: [LABEL_KEY] } as any,\n });\n return items.map(ci => ({\n sandbox: <DockerSandboxHandle>{\n docker,\n container: docker.getContainer(ci.Id),\n containerId: ci.Id,\n image: ci.Image,\n createdAt: new Date((ci as any).Created * 1000),\n },\n sandboxId: ci.Id,\n }));\n } catch {\n return [];\n }\n },\n\n destroy: async (config: DockerConfig, sandboxId: string) => {\n const docker = new Docker((config || defaultDockerConfig).connection as any);\n try {\n const c = docker.getContainer(sandboxId);\n try { await c.stop({ t: 5 } as any); } catch { /* stopped */ }\n await c.remove({ force: true });\n } catch {\n // ok if already gone\n }\n },\n\n runCode: async (handle: DockerSandboxHandle, code: string, runtime?: Runtime): Promise<CodeResult> => {\n const start = Date.now();\n\n // Resolve runtime: param → label → error\n let rt: Runtime | undefined = runtime;\n if (!rt) {\n const info = await handle.container.inspect();\n rt = (info.Config?.Labels?.[LABEL_RUNTIME] as Runtime) || undefined;\n }\n if (rt !== 'python' && rt !== 'node') {\n throw new Error(`Docker runtime must be 'python' or 'node'. Pass runtime in config or as a parameter.`);\n }\n\n // Write to file, then execute. This is robust on Alpine/Debian.\n const tmpFile = rt === 'python' ? '/tmp/compute_code.py' : '/tmp/compute_code.js';\n const b64 = Buffer.from(code, 'utf8').toString('base64');\n const makeAndRun =\n `printf '%s' \"${b64}\" | base64 -d > ${tmpFile} && ` +\n (rt === 'python' ? `python3 ${tmpFile}` : `node ${tmpFile}`);\n\n const { stdout, stderr, exitCode } = await runExec(handle, makeAndRun);\n\n if (exitCode !== 0 && stderr) {\n // Throw ONLY on syntax errors (SDK contract)\n const isSyntax =\n stderr.includes('SyntaxError') ||\n stderr.includes('invalid syntax') ||\n stderr.includes('Unexpected token') ||\n stderr.includes('Unexpected identifier');\n if (isSyntax) {\n const last = stderr.trim().split('\\n').slice(-1)[0] || 'Syntax error';\n throw new Error(`Syntax error: ${last}`);\n }\n }\n\n return {\n output: stdout + stderr,\n exitCode,\n language: rt,\n };\n },\n\n runCommand: async (\n handle: DockerSandboxHandle,\n command: string,\n options?: RunCommandOptions\n ): Promise<CommandResult> => {\n const start = Date.now();\n\n const { stdout, stderr, exitCode } = await runExec(handle, command);\n\n return {\n stdout,\n stderr,\n exitCode,\n durationMs: Date.now() - start,\n };\n },\n\n getInfo: async (handle: DockerSandboxHandle): Promise<SandboxInfo> => {\n const info = await handle.container.inspect();\n const state = info.State || {};\n return {\n id: handle.containerId,\n provider: PROVIDER,\n runtime: (info.Config?.Labels?.[LABEL_RUNTIME] as Runtime) || 'python',\n status: state.Running ? 'running' : 'stopped',\n createdAt: new Date(info.Created || handle.createdAt),\n timeout: 300000,\n metadata: {\n image: info.Config?.Image,\n name: info.Name,\n },\n };\n },\n\n getUrl: async (handle: DockerSandboxHandle, options: { port: number; protocol?: string }): Promise<string> => {\n const info = await handle.container.inspect();\n const protocol = options.protocol || 'http';\n const portKeyTcp = `${options.port}/tcp`;\n\n const ports = info.NetworkSettings?.Ports || {};\n const bindings = ports[portKeyTcp] || ports[`${options.port}/udp`] || [];\n\n let host = dockerHostNameFromEnv();\n let hostPort = String(options.port);\n\n if (Array.isArray(bindings) && bindings.length > 0) {\n hostPort = bindings[0].HostPort || hostPort;\n } else {\n const ip =\n info.NetworkSettings?.IPAddress ||\n Object.values(info.NetworkSettings?.Networks || {})[0]?.IPAddress;\n if (ip) host = ip;\n }\n\n return `${protocol}://${host}:${hostPort}`;\n },\n\n filesystem: {\n readFile: async (handle: DockerSandboxHandle, path: string): Promise<string> => {\n const cmd = `if [ -f ${JSON.stringify(path)} ]; then base64 ${JSON.stringify(path)} | tr -d '\\\\n'; else exit 1; fi`;\n const { stdout, exitCode, stderr } = await runExec(handle, cmd);\n if (exitCode !== 0) throw new Error(stderr || `File not found: ${path}`);\n return Buffer.from(stdout, 'base64').toString('utf8');\n },\n\n writeFile: async (handle: DockerSandboxHandle, path: string, content: string): Promise<void> => {\n const b64 = Buffer.from(content, 'utf8').toString('base64');\n const cmd = `mkdir -p $(dirname ${JSON.stringify(path)}) && echo \"${b64}\" | base64 -d > ${JSON.stringify(path)}`;\n const { exitCode, stderr } = await runExec(handle, cmd);\n if (exitCode !== 0) throw new Error(stderr || `Failed to write: ${path}`);\n },\n\n mkdir: async (handle: DockerSandboxHandle, path: string): Promise<void> => {\n const { exitCode, stderr } = await runExec(handle, `mkdir -p ${JSON.stringify(path)}`);\n if (exitCode !== 0) throw new Error(stderr || `Failed to mkdir: ${path}`);\n },\n\n readdir: async (handle: DockerSandboxHandle, path: string): Promise<FileEntry[]> => {\n const { stdout, exitCode, stderr } = await runExec(\n handle,\n `if [ -d ${JSON.stringify(path)} ]; then ls -la ${JSON.stringify(path)}; else exit 1; fi`\n );\n if (exitCode !== 0) throw new Error(stderr || `Not a directory: ${path}`);\n\n const lines = stdout.split('\\n').slice(1);\n const entries: FileEntry[] = [];\n for (const line of lines) {\n const parts = line.trim().split(/\\s+/);\n if (parts.length < 9) continue;\n const name = parts.slice(8).join(' ');\n if (name === '.' || name === '..') continue;\n const isDir = parts[0].startsWith('d');\n const size = Number(parts[4]) || 0;\n entries.push({\n name,\n type: isDir ? 'directory' as const : 'file' as const,\n size,\n modified: new Date(),\n });\n }\n return entries;\n },\n\n exists: async (handle: DockerSandboxHandle, path: string): Promise<boolean> => {\n const { exitCode } = await runExec(handle, `test -e ${JSON.stringify(path)}`);\n return exitCode === 0;\n },\n\n remove: async (handle: DockerSandboxHandle, path: string): Promise<void> => {\n const { exitCode, stderr } = await runExec(handle, `rm -rf ${JSON.stringify(path)}`);\n if (exitCode !== 0) throw new Error(stderr || `Failed to remove: ${path}`);\n },\n },\n\n getInstance: (handle: DockerSandboxHandle): DockerSandboxHandle => handle,\n },\n },\n});\n\n","import type Docker from 'dockerode';\nimport type {\n DockerOptions,\n Container,\n ContainerCreateOptions,\n ContainerStartOptions,\n ContainerInspectInfo,\n ContainerInfo,\n Exec,\n ImageInfo,\n ImageBuildOptions,\n Network,\n} from 'dockerode';\n\nimport type {\n Runtime,\n FileEntry,\n RunCommandOptions,\n CreateSandboxOptions,\n SandboxInfo,\n} from 'computesdk';\n\n/** When the provider should clean up containers it created */\nexport type CleanupPolicy = 'always' | 'onSuccess' | 'never';\n\n/** Image pull strategy */\nexport type PullPolicy = 'always' | 'ifNotPresent' | 'never';\n\n/** Connection to the Docker daemon (exactly what dockerode accepts) */\nexport type DockerConnection = DockerOptions;\n\n/** Auth when pulling private images (Engine API AuthConfig shape) */\nexport interface RegistryAuth {\n username?: string;\n password?: string;\n serveraddress?: string;\n identitytoken?: string;\n registrytoken?: string;\n}\n\n/** Default image & pull policy for sandboxes */\nexport interface DockerImage {\n name: string; // e.g. 'python:3.11-slim'\n pullPolicy?: PullPolicy; // default: 'ifNotPresent'\n auth?: RegistryAuth;\n}\n\n/** Convenience shape for port bindings */\nexport type PortBindings = Record<\n `${number}/${'tcp' | 'udp'}`,\n Array<{ hostPort?: number; hostIP?: string }>\n>;\n\n/** Subset of HostConfig resources & knobs that are commonly used */\nexport interface ResourceLimits {\n cpuShares?: number;\n cpuQuota?: number;\n cpuPeriod?: number;\n nanoCPUs?: number;\n memory?: number;\n memorySwap?: number;\n pidsLimit?: number;\n}\n\n/** Declarative container defaults that we’ll translate into dockerode create options */\nexport interface ContainerDefaults {\n user?: string;\n workdir?: string;\n env?: Record<string, string>;\n binds?: string[];\n ports?: PortBindings;\n networkMode?: string;\n privileged?: boolean;\n capabilities?: { add?: string[]; drop?: string[] };\n gpus?: 'all' | number | string;\n resources?: ResourceLimits;\n logDriver?: string;\n logOpts?: Record<string, string>;\n autoRemove?: boolean;\n tty?: boolean;\n openStdin?: boolean;\n}\n\n/** Provider-level configuration for Docker */\nexport interface DockerConfig {\n connection?: DockerConnection;\n runtime?: Runtime; // 'python' | 'node'\n timeout?: number;\n image: DockerImage;\n container?: ContainerDefaults;\n createOptions?: ContainerCreateOptions;\n startOptions?: ContainerStartOptions;\n cleanup?: CleanupPolicy;\n streamLogs?: boolean;\n}\n\n/** What we keep for each running sandbox */\nexport interface DockerSandboxHandle {\n docker: Docker;\n container: Container;\n containerId: string;\n image: string;\n createdAt: Date;\n}\n\n/** URL options for port-forwarded services */\nexport interface DockerUrlOptions {\n port: number;\n protocol?: 'http' | 'https';\n host?: string;\n}\n\n/** Optional FS helpers you might expose */\nexport interface DockerSandboxFileSystem {\n readFile(path: string): Promise<string>;\n writeFile(path: string, content: string): Promise<void>;\n mkdir(path: string): Promise<void>;\n readdir(path: string): Promise<FileEntry[]>;\n exists(path: string): Promise<boolean>;\n remove(path: string): Promise<void>;\n}\n\n/** Sensible, safe defaults */\nexport const defaultDockerConfig: DockerConfig = {\n connection: {\n // Let dockerode fall back to DOCKER_HOST or /var/run/docker.sock\n timeout: 60_000,\n version: 'v1.43',\n },\n runtime: 'python',\n timeout: 300_000, // 5 minutes\n image: {\n name: 'python:3.11-slim',\n pullPolicy: 'ifNotPresent',\n },\n container: {\n workdir: '/workspace',\n env: {},\n autoRemove: false, // Keep container around for exec/FS/background\n tty: false, // Non-tty so we can demux stdout/stderr\n openStdin: false,\n resources: { memory: 512 * 1024 * 1024 },\n },\n cleanup: 'always',\n streamLogs: false,\n};\n\n/** Re-exports for convenience */\nexport type {\n Docker,\n Container,\n Exec,\n ContainerCreateOptions,\n ContainerStartOptions,\n ContainerInspectInfo,\n ContainerInfo,\n ImageInfo,\n ImageBuildOptions,\n Network,\n};\n"],"mappings":"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","names":["docker","Docker","container"]}
|
|
1
|
+
{"version":3,"sources":["../src/index.ts","../src/types/types.ts"],"sourcesContent":["import Docker from 'dockerode';\nimport { PassThrough } from 'stream';\nimport { defineProvider } from '@computesdk/provider';\nimport type {\n CommandResult,\n RunCommandOptions,\n CreateSandboxOptions,\n SandboxInfo,\n FileEntry,\n} from '@computesdk/provider';\n\nimport { defaultDockerConfig } from './types/types';\nimport type {\n DockerConfig,\n DockerSandboxHandle,\n DockerImage,\n PortBindings,\n} from './types/types';\n\nconst PROVIDER = 'docker' as const;\nconst LABEL_KEY = 'com.computesdk.sandbox';\nconst LABEL_RUNTIME = 'com.computesdk.runtime';\nconst KEEPALIVE_CMD = ['/bin/sh', '-c', 'while :; do sleep 3600; done'];\n\nfunction pick<T>(val: T | undefined, fallback: T): T {\n return typeof val === 'undefined' ? fallback : val;\n}\n\nasync function ensureImage(docker: Docker, image: DockerImage): Promise<void> {\n const policy = image.pullPolicy ?? 'ifNotPresent';\n if (policy === 'never') return;\n const images = await docker.listImages();\n const hasImage = images.some(img => (img.RepoTags || []).includes(image.name));\n if (policy === 'always' || (policy === 'ifNotPresent' && !hasImage)) {\n await new Promise<void>((resolve, reject) => {\n const cb = (err: any, stream?: NodeJS.ReadableStream) => {\n if (err) return reject(err);\n if (!stream) return reject(new Error('docker.pull returned no stream'));\n (docker as any).modem.followProgress(stream, (err2: any) => (err2 ? reject(err2) : resolve()));\n };\n if (image.auth) docker.pull(image.name, { authconfig: image.auth } as any, cb);\n else docker.pull(image.name, cb);\n });\n }\n}\n\nasync function waitUntilRunning(container: Docker.Container, timeoutMs = 4000) {\n const start = Date.now();\n try {\n const s = await container.inspect();\n if (s.State?.Running) return;\n } catch { /* ignore */ }\n while (Date.now() - start < timeoutMs) {\n const s = await container.inspect();\n if (s.State?.Running) return;\n await new Promise(r => setTimeout(r, 100));\n }\n throw new Error('Container did not reach Running state in time');\n}\n\nasync function runExec(\n handle: DockerSandboxHandle,\n shellCommand: string,\n attachTTY = false\n): Promise<{ stdout: string; stderr: string; exitCode: number }> {\n await waitUntilRunning(handle.container);\n const exec = await handle.container.exec({\n Cmd: ['/bin/sh', '-c', shellCommand],\n AttachStdout: true,\n AttachStderr: true,\n Tty: attachTTY,\n });\n const stream = (await exec.start({ hijack: true, stdin: false })) as NodeJS.ReadableStream;\n let stdout = '';\n let stderr = '';\n await new Promise<void>((resolve, reject) => {\n if (attachTTY) {\n stream.on('data', (chunk: Buffer) => (stdout += chunk.toString('utf8')));\n stream.on('end', resolve);\n stream.on('error', reject);\n return;\n }\n const out = new PassThrough();\n const err = new PassThrough();\n out.on('data', (c: Buffer) => (stdout += c.toString('utf8')));\n err.on('data', (c: Buffer) => (stderr += c.toString('utf8')));\n (handle.docker as any).modem.demuxStream(stream as any, out as any, err as any);\n stream.on('end', resolve);\n stream.on('error', reject);\n });\n const inspect = await exec.inspect();\n return { stdout, stderr, exitCode: inspect.ExitCode ?? 0 };\n}\n\nfunction toHostBindings(ports?: PortBindings) {\n if (!ports) return undefined;\n const exposed: Record<string, {}> = {};\n const bindings: Record<string, Array<{ HostPort?: string; HostIp?: string }>> = {};\n for (const key of Object.keys(ports)) {\n exposed[key] = {};\n bindings[key] = (ports as any)[key].map((p: any) => ({ HostPort: p.hostPort ? String(p.hostPort) : undefined, HostIp: p.hostIP }));\n }\n return { ExposedPorts: exposed, PortBindings: bindings };\n}\n\nfunction dockerHostNameFromEnv(): string {\n const hostEnv = process.env.DOCKER_HOST;\n if (hostEnv?.startsWith('tcp://')) {\n try { return new URL(hostEnv).hostname || 'localhost'; } catch { /* noop */ }\n }\n return 'localhost';\n}\n\nfunction pickImageForRuntime(runtime: string, configured?: DockerImage): DockerImage {\n if (configured?.name) {\n if (runtime === 'python' && /python|conda|pypy/i.test(configured.name)) return configured;\n if (runtime === 'node' && /node/i.test(configured.name)) return configured;\n }\n return {\n name: runtime === 'python' ? 'python:3.11-slim' : 'node:20-alpine',\n pullPolicy: configured?.pullPolicy ?? 'ifNotPresent',\n auth: configured?.auth,\n };\n}\n\nexport const docker = defineProvider<DockerSandboxHandle, DockerConfig>({\n name: PROVIDER,\n methods: {\n sandbox: {\n create: async (config: DockerConfig, options?: CreateSandboxOptions) => {\n const cfg: DockerConfig = { ...defaultDockerConfig, ...config };\n const effectiveRuntime: string = ((options as any)?.runtime ?? cfg.runtime ?? 'python') as string;\n\n if (effectiveRuntime !== 'python' && effectiveRuntime !== 'node') {\n throw new Error(`Docker provider supports only 'python' or 'node'. Received: ${String(effectiveRuntime)}`);\n }\n\n const docker = new Docker(cfg.connection as any);\n const chosenImage = pickImageForRuntime(effectiveRuntime, cfg.image);\n await ensureImage(docker, chosenImage);\n\n const mergedEnv = { ...cfg.container?.env, ...options?.envs };\n const hb = toHostBindings(cfg.container?.ports);\n const createOptions = {\n Image: chosenImage.name,\n Tty: pick(cfg.container?.tty, false),\n OpenStdin: pick(cfg.container?.openStdin, false),\n Labels: {\n ...(options?.metadata ? Object.fromEntries(\n Object.entries(options.metadata).map(([k, v]) => [`com.computesdk.meta.${k}`, typeof v === 'string' ? v : JSON.stringify(v)])\n ) : {}),\n [LABEL_KEY]: 'true',\n [LABEL_RUNTIME]: effectiveRuntime,\n },\n WorkingDir: cfg.container?.workdir,\n Env: Object.keys(mergedEnv).length > 0\n ? Object.entries(mergedEnv).map(([k, v]) => `${k}=${v}`)\n : undefined,\n Cmd: KEEPALIVE_CMD,\n HostConfig: {\n AutoRemove: cfg.container?.autoRemove ?? false,\n Binds: cfg.container?.binds,\n NetworkMode: cfg.container?.networkMode,\n Privileged: cfg.container?.privileged,\n CapAdd: cfg.container?.capabilities?.add,\n CapDrop: cfg.container?.capabilities?.drop,\n LogConfig: cfg.container?.logDriver\n ? { Type: cfg.container.logDriver, Config: cfg.container.logOpts || {} }\n : undefined,\n Resources: cfg.container?.resources,\n DeviceRequests: cfg.container?.gpus ? [{\n Driver: 'nvidia',\n Count: cfg.container.gpus === 'all' ? -1 : typeof cfg.container.gpus === 'number' ? cfg.container.gpus : 1,\n DeviceIDs: typeof cfg.container.gpus === 'string' && cfg.container.gpus !== 'all' ? [String(cfg.container.gpus)] : undefined,\n Capabilities: [['gpu']],\n }] : undefined,\n ...(hb ? { PortBindings: hb.PortBindings } : {}),\n },\n ...(hb ? { ExposedPorts: hb.ExposedPorts } : {}),\n ...(cfg.createOptions || {}),\n } as import('dockerode').ContainerCreateOptions;\n\n const container = await docker.createContainer(createOptions);\n await container.start(cfg.startOptions || {});\n await waitUntilRunning(container);\n const inspect = await container.inspect();\n const handle: DockerSandboxHandle = {\n docker, container, containerId: inspect.Id,\n image: inspect.Config?.Image ?? chosenImage.name,\n createdAt: new Date(inspect.Created || Date.now()),\n };\n return { sandbox: handle, sandboxId: handle.containerId };\n },\n\n getById: async (config: DockerConfig, sandboxId: string) => {\n const docker = new Docker((config || defaultDockerConfig).connection as any);\n try {\n const container = docker.getContainer(sandboxId);\n const info = await container.inspect();\n return { sandbox: { docker, container, containerId: sandboxId, image: info.Config?.Image ?? '', createdAt: new Date(info.Created || Date.now()) } as DockerSandboxHandle, sandboxId };\n } catch { return null; }\n },\n\n list: async (config: DockerConfig) => {\n const docker = new Docker((config || defaultDockerConfig).connection as any);\n try {\n const items = await docker.listContainers({ all: true, filters: { label: [LABEL_KEY] } as any });\n return items.map(ci => ({\n sandbox: { docker, container: docker.getContainer(ci.Id), containerId: ci.Id, image: ci.Image, createdAt: new Date((ci as any).Created * 1000) } as DockerSandboxHandle,\n sandboxId: ci.Id,\n }));\n } catch { return []; }\n },\n\n destroy: async (config: DockerConfig, sandboxId: string) => {\n const docker = new Docker((config || defaultDockerConfig).connection as any);\n try {\n const c = docker.getContainer(sandboxId);\n try { await c.stop({ t: 5 } as any); } catch { /* stopped */ }\n await c.remove({ force: true });\n } catch { /* ok if already gone */ }\n },\n\n runCommand: async (handle: DockerSandboxHandle, command: string, _options?: RunCommandOptions): Promise<CommandResult> => {\n const start = Date.now();\n const { stdout, stderr, exitCode } = await runExec(handle, command);\n return { stdout, stderr, exitCode, durationMs: Date.now() - start };\n },\n\n getInfo: async (handle: DockerSandboxHandle): Promise<SandboxInfo> => {\n const info = await handle.container.inspect();\n const state = info.State || {};\n return {\n id: handle.containerId,\n provider: PROVIDER,\n status: state.Running ? 'running' : 'stopped',\n createdAt: new Date(info.Created || handle.createdAt),\n timeout: 300000,\n metadata: {\n image: info.Config?.Image,\n name: info.Name,\n runtime: info.Config?.Labels?.[LABEL_RUNTIME],\n },\n };\n },\n\n getUrl: async (handle: DockerSandboxHandle, options: { port: number; protocol?: string }): Promise<string> => {\n const info = await handle.container.inspect();\n const protocol = options.protocol || 'http';\n const portKeyTcp = `${options.port}/tcp`;\n const ports = info.NetworkSettings?.Ports || {};\n const bindings = ports[portKeyTcp] || ports[`${options.port}/udp`] || [];\n let host = dockerHostNameFromEnv();\n let hostPort = String(options.port);\n if (Array.isArray(bindings) && bindings.length > 0) {\n hostPort = bindings[0].HostPort || hostPort;\n } else {\n const ip = info.NetworkSettings?.IPAddress || Object.values(info.NetworkSettings?.Networks || {})[0]?.IPAddress;\n if (ip) host = ip;\n }\n return `${protocol}://${host}:${hostPort}`;\n },\n\n filesystem: {\n readFile: async (handle: DockerSandboxHandle, path: string): Promise<string> => {\n const cmd = `if [ -f ${JSON.stringify(path)} ]; then base64 ${JSON.stringify(path)} | tr -d '\\\\n'; else exit 1; fi`;\n const { stdout, exitCode, stderr } = await runExec(handle, cmd);\n if (exitCode !== 0) throw new Error(stderr || `File not found: ${path}`);\n return Buffer.from(stdout, 'base64').toString('utf8');\n },\n writeFile: async (handle: DockerSandboxHandle, path: string, content: string): Promise<void> => {\n const b64 = Buffer.from(content, 'utf8').toString('base64');\n const cmd = `mkdir -p $(dirname ${JSON.stringify(path)}) && echo \"${b64}\" | base64 -d > ${JSON.stringify(path)}`;\n const { exitCode, stderr } = await runExec(handle, cmd);\n if (exitCode !== 0) throw new Error(stderr || `Failed to write: ${path}`);\n },\n mkdir: async (handle: DockerSandboxHandle, path: string): Promise<void> => {\n const { exitCode, stderr } = await runExec(handle, `mkdir -p ${JSON.stringify(path)}`);\n if (exitCode !== 0) throw new Error(stderr || `Failed to mkdir: ${path}`);\n },\n readdir: async (handle: DockerSandboxHandle, path: string): Promise<FileEntry[]> => {\n const { stdout, exitCode, stderr } = await runExec(handle, `if [ -d ${JSON.stringify(path)} ]; then ls -la ${JSON.stringify(path)}; else exit 1; fi`);\n if (exitCode !== 0) throw new Error(stderr || `Not a directory: ${path}`);\n const lines = stdout.split('\\n').slice(1);\n const entries: FileEntry[] = [];\n for (const line of lines) {\n const parts = line.trim().split(/\\s+/);\n if (parts.length < 9) continue;\n const name = parts.slice(8).join(' ');\n if (name === '.' || name === '..') continue;\n entries.push({ name, type: parts[0].startsWith('d') ? 'directory' as const : 'file' as const, size: Number(parts[4]) || 0, modified: new Date() });\n }\n return entries;\n },\n exists: async (handle: DockerSandboxHandle, path: string): Promise<boolean> => {\n const { exitCode } = await runExec(handle, `test -e ${JSON.stringify(path)}`);\n return exitCode === 0;\n },\n remove: async (handle: DockerSandboxHandle, path: string): Promise<void> => {\n const { exitCode, stderr } = await runExec(handle, `rm -rf ${JSON.stringify(path)}`);\n if (exitCode !== 0) throw new Error(stderr || `Failed to remove: ${path}`);\n },\n },\n\n getInstance: (handle: DockerSandboxHandle): DockerSandboxHandle => handle,\n },\n },\n});\n","import type Docker from 'dockerode';\nimport type {\n DockerOptions,\n Container,\n ContainerCreateOptions,\n ContainerStartOptions,\n ContainerInspectInfo,\n ContainerInfo,\n Exec,\n ImageInfo,\n ImageBuildOptions,\n Network,\n} from 'dockerode';\n\nimport type {\n FileEntry,\n RunCommandOptions,\n CreateSandboxOptions,\n SandboxInfo,\n} from 'computesdk';\n\n/** When the provider should clean up containers it created */\nexport type CleanupPolicy = 'always' | 'onSuccess' | 'never';\n\n/** Image pull strategy */\nexport type PullPolicy = 'always' | 'ifNotPresent' | 'never';\n\n/** Connection to the Docker daemon (exactly what dockerode accepts) */\nexport type DockerConnection = DockerOptions;\n\n/** Auth when pulling private images (Engine API AuthConfig shape) */\nexport interface RegistryAuth {\n username?: string;\n password?: string;\n serveraddress?: string;\n identitytoken?: string;\n registrytoken?: string;\n}\n\n/** Default image & pull policy for sandboxes */\nexport interface DockerImage {\n name: string; // e.g. 'python:3.11-slim'\n pullPolicy?: PullPolicy; // default: 'ifNotPresent'\n auth?: RegistryAuth;\n}\n\n/** Convenience shape for port bindings */\nexport type PortBindings = Record<\n `${number}/${'tcp' | 'udp'}`,\n Array<{ hostPort?: number; hostIP?: string }>\n>;\n\n/** Subset of HostConfig resources & knobs that are commonly used */\nexport interface ResourceLimits {\n cpuShares?: number;\n cpuQuota?: number;\n cpuPeriod?: number;\n nanoCPUs?: number;\n memory?: number;\n memorySwap?: number;\n pidsLimit?: number;\n}\n\n/** Declarative container defaults that we'll translate into dockerode create options */\nexport interface ContainerDefaults {\n user?: string;\n workdir?: string;\n env?: Record<string, string>;\n binds?: string[];\n ports?: PortBindings;\n networkMode?: string;\n privileged?: boolean;\n capabilities?: { add?: string[]; drop?: string[] };\n gpus?: 'all' | number | string;\n resources?: ResourceLimits;\n logDriver?: string;\n logOpts?: Record<string, string>;\n autoRemove?: boolean;\n tty?: boolean;\n openStdin?: boolean;\n}\n\n/** Provider-level configuration for Docker */\nexport interface DockerConfig {\n connection?: DockerConnection;\n /** Default image runtime identifier, e.g. 'python' or 'node' */\n runtime?: string;\n timeout?: number;\n image: DockerImage;\n container?: ContainerDefaults;\n createOptions?: ContainerCreateOptions;\n startOptions?: ContainerStartOptions;\n cleanup?: CleanupPolicy;\n streamLogs?: boolean;\n}\n\n/** What we keep for each running sandbox */\nexport interface DockerSandboxHandle {\n docker: Docker;\n container: Container;\n containerId: string;\n image: string;\n createdAt: Date;\n}\n\n/** URL options for port-forwarded services */\nexport interface DockerUrlOptions {\n port: number;\n protocol?: 'http' | 'https';\n host?: string;\n}\n\n/** Optional FS helpers you might expose */\nexport interface DockerSandboxFileSystem {\n readFile(path: string): Promise<string>;\n writeFile(path: string, content: string): Promise<void>;\n mkdir(path: string): Promise<void>;\n readdir(path: string): Promise<FileEntry[]>;\n exists(path: string): Promise<boolean>;\n remove(path: string): Promise<void>;\n}\n\n/** Sensible, safe defaults */\nexport const defaultDockerConfig: DockerConfig = {\n connection: {\n // Let dockerode fall back to DOCKER_HOST or /var/run/docker.sock\n timeout: 60_000,\n version: 'v1.43',\n },\n runtime: 'python',\n timeout: 300_000, // 5 minutes\n image: {\n name: 'python:3.11-slim',\n pullPolicy: 'ifNotPresent',\n },\n container: {\n workdir: '/workspace',\n env: {},\n autoRemove: false, // Keep container around for exec/FS/background\n tty: false, // Non-tty so we can demux stdout/stderr\n openStdin: false,\n resources: { memory: 512 * 1024 * 1024 },\n },\n cleanup: 'always',\n streamLogs: false,\n};\n\n/** Re-exports for convenience */\nexport type {\n Docker,\n Container,\n Exec,\n ContainerCreateOptions,\n ContainerStartOptions,\n ContainerInspectInfo,\n ContainerInfo,\n ImageInfo,\n ImageBuildOptions,\n Network,\n};\n"],"mappings":"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","names":["docker","Docker"]}
|
package/dist/index.mjs
CHANGED
|
@@ -97,8 +97,7 @@ async function runExec(handle, shellCommand, attachTTY = false) {
|
|
|
97
97
|
stream.on("error", reject);
|
|
98
98
|
});
|
|
99
99
|
const inspect = await exec.inspect();
|
|
100
|
-
|
|
101
|
-
return { stdout, stderr, exitCode };
|
|
100
|
+
return { stdout, stderr, exitCode: inspect.ExitCode ?? 0 };
|
|
102
101
|
}
|
|
103
102
|
function toHostBindings(ports) {
|
|
104
103
|
if (!ports) return void 0;
|
|
@@ -106,10 +105,7 @@ function toHostBindings(ports) {
|
|
|
106
105
|
const bindings = {};
|
|
107
106
|
for (const key of Object.keys(ports)) {
|
|
108
107
|
exposed[key] = {};
|
|
109
|
-
bindings[key] = ports[key].map((p) => ({
|
|
110
|
-
HostPort: p.hostPort ? String(p.hostPort) : void 0,
|
|
111
|
-
HostIp: p.hostIP
|
|
112
|
-
}));
|
|
108
|
+
bindings[key] = ports[key].map((p) => ({ HostPort: p.hostPort ? String(p.hostPort) : void 0, HostIp: p.hostIP }));
|
|
113
109
|
}
|
|
114
110
|
return { ExposedPorts: exposed, PortBindings: bindings };
|
|
115
111
|
}
|
|
@@ -117,8 +113,7 @@ function dockerHostNameFromEnv() {
|
|
|
117
113
|
const hostEnv = process.env.DOCKER_HOST;
|
|
118
114
|
if (hostEnv?.startsWith("tcp://")) {
|
|
119
115
|
try {
|
|
120
|
-
|
|
121
|
-
return u.hostname || "localhost";
|
|
116
|
+
return new URL(hostEnv).hostname || "localhost";
|
|
122
117
|
} catch {
|
|
123
118
|
}
|
|
124
119
|
}
|
|
@@ -146,24 +141,6 @@ var docker = defineProvider({
|
|
|
146
141
|
throw new Error(`Docker provider supports only 'python' or 'node'. Received: ${String(effectiveRuntime)}`);
|
|
147
142
|
}
|
|
148
143
|
const docker2 = new Docker(cfg.connection);
|
|
149
|
-
if (options?.sandboxId) {
|
|
150
|
-
try {
|
|
151
|
-
const container2 = docker2.getContainer(options.sandboxId);
|
|
152
|
-
const info = await container2.inspect();
|
|
153
|
-
return {
|
|
154
|
-
sandbox: {
|
|
155
|
-
docker: docker2,
|
|
156
|
-
container: container2,
|
|
157
|
-
containerId: options.sandboxId,
|
|
158
|
-
image: info.Config?.Image ?? cfg.image.name,
|
|
159
|
-
createdAt: new Date(info.Created || Date.now())
|
|
160
|
-
},
|
|
161
|
-
sandboxId: options.sandboxId
|
|
162
|
-
};
|
|
163
|
-
} catch (err) {
|
|
164
|
-
console.warn(`Could not reattach to Docker container with ID ${options.sandboxId}:`, err);
|
|
165
|
-
}
|
|
166
|
-
}
|
|
167
144
|
const chosenImage = pickImageForRuntime(effectiveRuntime, cfg.image);
|
|
168
145
|
await ensureImage(docker2, chosenImage);
|
|
169
146
|
const mergedEnv = { ...cfg.container?.env, ...options?.envs };
|
|
@@ -173,8 +150,6 @@ var docker = defineProvider({
|
|
|
173
150
|
Tty: pick(cfg.container?.tty, false),
|
|
174
151
|
OpenStdin: pick(cfg.container?.openStdin, false),
|
|
175
152
|
Labels: {
|
|
176
|
-
// User metadata is spread first with a namespaced prefix so it
|
|
177
|
-
// cannot overwrite the reserved discovery/runtime labels below.
|
|
178
153
|
...options?.metadata ? Object.fromEntries(
|
|
179
154
|
Object.entries(options.metadata).map(([k, v]) => [`com.computesdk.meta.${k}`, typeof v === "string" ? v : JSON.stringify(v)])
|
|
180
155
|
) : {},
|
|
@@ -184,10 +159,8 @@ var docker = defineProvider({
|
|
|
184
159
|
WorkingDir: cfg.container?.workdir,
|
|
185
160
|
Env: Object.keys(mergedEnv).length > 0 ? Object.entries(mergedEnv).map(([k, v]) => `${k}=${v}`) : void 0,
|
|
186
161
|
Cmd: KEEPALIVE_CMD,
|
|
187
|
-
// keep container alive
|
|
188
162
|
HostConfig: {
|
|
189
163
|
AutoRemove: cfg.container?.autoRemove ?? false,
|
|
190
|
-
// keep around for exec/FS ops
|
|
191
164
|
Binds: cfg.container?.binds,
|
|
192
165
|
NetworkMode: cfg.container?.networkMode,
|
|
193
166
|
Privileged: cfg.container?.privileged,
|
|
@@ -195,14 +168,12 @@ var docker = defineProvider({
|
|
|
195
168
|
CapDrop: cfg.container?.capabilities?.drop,
|
|
196
169
|
LogConfig: cfg.container?.logDriver ? { Type: cfg.container.logDriver, Config: cfg.container.logOpts || {} } : void 0,
|
|
197
170
|
Resources: cfg.container?.resources,
|
|
198
|
-
DeviceRequests: cfg.container?.gpus ? [
|
|
199
|
-
|
|
200
|
-
|
|
201
|
-
|
|
202
|
-
|
|
203
|
-
|
|
204
|
-
}
|
|
205
|
-
] : void 0,
|
|
171
|
+
DeviceRequests: cfg.container?.gpus ? [{
|
|
172
|
+
Driver: "nvidia",
|
|
173
|
+
Count: cfg.container.gpus === "all" ? -1 : typeof cfg.container.gpus === "number" ? cfg.container.gpus : 1,
|
|
174
|
+
DeviceIDs: typeof cfg.container.gpus === "string" && cfg.container.gpus !== "all" ? [String(cfg.container.gpus)] : void 0,
|
|
175
|
+
Capabilities: [["gpu"]]
|
|
176
|
+
}] : void 0,
|
|
206
177
|
...hb ? { PortBindings: hb.PortBindings } : {}
|
|
207
178
|
},
|
|
208
179
|
...hb ? { ExposedPorts: hb.ExposedPorts } : {},
|
|
@@ -226,16 +197,7 @@ var docker = defineProvider({
|
|
|
226
197
|
try {
|
|
227
198
|
const container = docker2.getContainer(sandboxId);
|
|
228
199
|
const info = await container.inspect();
|
|
229
|
-
return {
|
|
230
|
-
sandbox: {
|
|
231
|
-
docker: docker2,
|
|
232
|
-
container,
|
|
233
|
-
containerId: sandboxId,
|
|
234
|
-
image: info.Config?.Image ?? "",
|
|
235
|
-
createdAt: new Date(info.Created || Date.now())
|
|
236
|
-
},
|
|
237
|
-
sandboxId
|
|
238
|
-
};
|
|
200
|
+
return { sandbox: { docker: docker2, container, containerId: sandboxId, image: info.Config?.Image ?? "", createdAt: new Date(info.Created || Date.now()) }, sandboxId };
|
|
239
201
|
} catch {
|
|
240
202
|
return null;
|
|
241
203
|
}
|
|
@@ -243,18 +205,9 @@ var docker = defineProvider({
|
|
|
243
205
|
list: async (config) => {
|
|
244
206
|
const docker2 = new Docker((config || defaultDockerConfig).connection);
|
|
245
207
|
try {
|
|
246
|
-
const items = await docker2.listContainers({
|
|
247
|
-
all: true,
|
|
248
|
-
filters: { label: [LABEL_KEY] }
|
|
249
|
-
});
|
|
208
|
+
const items = await docker2.listContainers({ all: true, filters: { label: [LABEL_KEY] } });
|
|
250
209
|
return items.map((ci) => ({
|
|
251
|
-
sandbox: {
|
|
252
|
-
docker: docker2,
|
|
253
|
-
container: docker2.getContainer(ci.Id),
|
|
254
|
-
containerId: ci.Id,
|
|
255
|
-
image: ci.Image,
|
|
256
|
-
createdAt: new Date(ci.Created * 1e3)
|
|
257
|
-
},
|
|
210
|
+
sandbox: { docker: docker2, container: docker2.getContainer(ci.Id), containerId: ci.Id, image: ci.Image, createdAt: new Date(ci.Created * 1e3) },
|
|
258
211
|
sandboxId: ci.Id
|
|
259
212
|
}));
|
|
260
213
|
} catch {
|
|
@@ -273,42 +226,10 @@ var docker = defineProvider({
|
|
|
273
226
|
} catch {
|
|
274
227
|
}
|
|
275
228
|
},
|
|
276
|
-
|
|
277
|
-
const start = Date.now();
|
|
278
|
-
let rt = runtime;
|
|
279
|
-
if (!rt) {
|
|
280
|
-
const info = await handle.container.inspect();
|
|
281
|
-
rt = info.Config?.Labels?.[LABEL_RUNTIME] || void 0;
|
|
282
|
-
}
|
|
283
|
-
if (rt !== "python" && rt !== "node") {
|
|
284
|
-
throw new Error(`Docker runtime must be 'python' or 'node'. Pass runtime in config or as a parameter.`);
|
|
285
|
-
}
|
|
286
|
-
const tmpFile = rt === "python" ? "/tmp/compute_code.py" : "/tmp/compute_code.js";
|
|
287
|
-
const b64 = Buffer.from(code, "utf8").toString("base64");
|
|
288
|
-
const makeAndRun = `printf '%s' "${b64}" | base64 -d > ${tmpFile} && ` + (rt === "python" ? `python3 ${tmpFile}` : `node ${tmpFile}`);
|
|
289
|
-
const { stdout, stderr, exitCode } = await runExec(handle, makeAndRun);
|
|
290
|
-
if (exitCode !== 0 && stderr) {
|
|
291
|
-
const isSyntax = stderr.includes("SyntaxError") || stderr.includes("invalid syntax") || stderr.includes("Unexpected token") || stderr.includes("Unexpected identifier");
|
|
292
|
-
if (isSyntax) {
|
|
293
|
-
const last = stderr.trim().split("\n").slice(-1)[0] || "Syntax error";
|
|
294
|
-
throw new Error(`Syntax error: ${last}`);
|
|
295
|
-
}
|
|
296
|
-
}
|
|
297
|
-
return {
|
|
298
|
-
output: stdout + stderr,
|
|
299
|
-
exitCode,
|
|
300
|
-
language: rt
|
|
301
|
-
};
|
|
302
|
-
},
|
|
303
|
-
runCommand: async (handle, command, options) => {
|
|
229
|
+
runCommand: async (handle, command, _options) => {
|
|
304
230
|
const start = Date.now();
|
|
305
231
|
const { stdout, stderr, exitCode } = await runExec(handle, command);
|
|
306
|
-
return {
|
|
307
|
-
stdout,
|
|
308
|
-
stderr,
|
|
309
|
-
exitCode,
|
|
310
|
-
durationMs: Date.now() - start
|
|
311
|
-
};
|
|
232
|
+
return { stdout, stderr, exitCode, durationMs: Date.now() - start };
|
|
312
233
|
},
|
|
313
234
|
getInfo: async (handle) => {
|
|
314
235
|
const info = await handle.container.inspect();
|
|
@@ -316,13 +237,13 @@ var docker = defineProvider({
|
|
|
316
237
|
return {
|
|
317
238
|
id: handle.containerId,
|
|
318
239
|
provider: PROVIDER,
|
|
319
|
-
runtime: info.Config?.Labels?.[LABEL_RUNTIME] || "python",
|
|
320
240
|
status: state.Running ? "running" : "stopped",
|
|
321
241
|
createdAt: new Date(info.Created || handle.createdAt),
|
|
322
242
|
timeout: 3e5,
|
|
323
243
|
metadata: {
|
|
324
244
|
image: info.Config?.Image,
|
|
325
|
-
name: info.Name
|
|
245
|
+
name: info.Name,
|
|
246
|
+
runtime: info.Config?.Labels?.[LABEL_RUNTIME]
|
|
326
247
|
}
|
|
327
248
|
};
|
|
328
249
|
},
|
|
@@ -360,10 +281,7 @@ var docker = defineProvider({
|
|
|
360
281
|
if (exitCode !== 0) throw new Error(stderr || `Failed to mkdir: ${path}`);
|
|
361
282
|
},
|
|
362
283
|
readdir: async (handle, path) => {
|
|
363
|
-
const { stdout, exitCode, stderr } = await runExec(
|
|
364
|
-
handle,
|
|
365
|
-
`if [ -d ${JSON.stringify(path)} ]; then ls -la ${JSON.stringify(path)}; else exit 1; fi`
|
|
366
|
-
);
|
|
284
|
+
const { stdout, exitCode, stderr } = await runExec(handle, `if [ -d ${JSON.stringify(path)} ]; then ls -la ${JSON.stringify(path)}; else exit 1; fi`);
|
|
367
285
|
if (exitCode !== 0) throw new Error(stderr || `Not a directory: ${path}`);
|
|
368
286
|
const lines = stdout.split("\n").slice(1);
|
|
369
287
|
const entries = [];
|
|
@@ -372,14 +290,7 @@ var docker = defineProvider({
|
|
|
372
290
|
if (parts.length < 9) continue;
|
|
373
291
|
const name = parts.slice(8).join(" ");
|
|
374
292
|
if (name === "." || name === "..") continue;
|
|
375
|
-
|
|
376
|
-
const size = Number(parts[4]) || 0;
|
|
377
|
-
entries.push({
|
|
378
|
-
name,
|
|
379
|
-
type: isDir ? "directory" : "file",
|
|
380
|
-
size,
|
|
381
|
-
modified: /* @__PURE__ */ new Date()
|
|
382
|
-
});
|
|
293
|
+
entries.push({ name, type: parts[0].startsWith("d") ? "directory" : "file", size: Number(parts[4]) || 0, modified: /* @__PURE__ */ new Date() });
|
|
383
294
|
}
|
|
384
295
|
return entries;
|
|
385
296
|
},
|
package/dist/index.mjs.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../src/index.ts","../src/types/types.ts"],"sourcesContent":["import Docker from 'dockerode';\nimport { PassThrough } from 'stream';\nimport { defineProvider } from '@computesdk/provider';\nimport type {\n Runtime,\n CodeResult,\n CommandResult,\n RunCommandOptions,\n CreateSandboxOptions,\n SandboxInfo,\n FileEntry,\n} from '@computesdk/provider';\n\nimport { defaultDockerConfig } from './types/types';\nimport type {\n DockerConfig,\n DockerSandboxHandle,\n DockerImage,\n PortBindings,\n} from './types/types';\n\nconst PROVIDER = 'docker' as const;\nconst LABEL_KEY = 'com.computesdk.sandbox';\nconst LABEL_RUNTIME = 'com.computesdk.runtime';\nconst KEEPALIVE_CMD = ['/bin/sh', '-c', 'while :; do sleep 3600; done'];\n\nfunction pick<T>(val: T | undefined, fallback: T): T {\n return typeof val === 'undefined' ? fallback : val;\n}\n\nasync function ensureImage(docker: Docker, image: DockerImage): Promise<void> {\n const policy = image.pullPolicy ?? 'ifNotPresent';\n if (policy === 'never') return;\n\n const images = await docker.listImages();\n const hasImage = images.some(img => (img.RepoTags || []).includes(image.name));\n\n if (policy === 'always' || (policy === 'ifNotPresent' && !hasImage)) {\n await new Promise<void>((resolve, reject) => {\n const cb = (err: any, stream?: NodeJS.ReadableStream) => {\n if (err) return reject(err);\n if (!stream) return reject(new Error('docker.pull returned no stream'));\n (docker as any).modem.followProgress(stream, (err2: any) => (err2 ? reject(err2) : resolve()));\n };\n if (image.auth) docker.pull(image.name, { authconfig: image.auth } as any, cb);\n else docker.pull(image.name, cb);\n });\n }\n}\n\nasync function waitUntilRunning(container: Docker.Container, timeoutMs = 4000) {\n const start = Date.now();\n try {\n const s = await container.inspect();\n if (s.State?.Running) return;\n } catch { /* ignore */ }\n\n while (Date.now() - start < timeoutMs) {\n const s = await container.inspect();\n if (s.State?.Running) return;\n await new Promise(r => setTimeout(r, 100));\n }\n throw new Error('Container did not reach Running state in time');\n}\n\nasync function runExec(\n handle: DockerSandboxHandle,\n shellCommand: string,\n attachTTY = false\n): Promise<{ stdout: string; stderr: string; exitCode: number }> {\n await waitUntilRunning(handle.container);\n\n const exec = await handle.container.exec({\n Cmd: ['/bin/sh', '-c', shellCommand],\n AttachStdout: true,\n AttachStderr: true,\n Tty: attachTTY,\n });\n\n const stream = (await exec.start({ hijack: true, stdin: false })) as NodeJS.ReadableStream;\n\n let stdout = '';\n let stderr = '';\n\n await new Promise<void>((resolve, reject) => {\n if (attachTTY) {\n stream.on('data', (chunk: Buffer) => (stdout += chunk.toString('utf8')));\n stream.on('end', resolve);\n stream.on('error', reject);\n return;\n }\n const out = new PassThrough();\n const err = new PassThrough();\n out.on('data', (c: Buffer) => (stdout += c.toString('utf8')));\n err.on('data', (c: Buffer) => (stderr += c.toString('utf8')));\n (handle.docker as any).modem.demuxStream(stream as any, out as any, err as any);\n stream.on('end', resolve);\n stream.on('error', reject);\n });\n\n const inspect = await exec.inspect();\n const exitCode = inspect.ExitCode ?? 0;\n return { stdout, stderr, exitCode };\n}\n\nfunction toHostBindings(ports?: PortBindings) {\n if (!ports) return undefined;\n const exposed: Record<string, {}> = {};\n const bindings: Record<string, Array<{ HostPort?: string; HostIp?: string }>> = {};\n for (const key of Object.keys(ports)) {\n exposed[key] = {};\n bindings[key] = (ports as any)[key].map((p: any) => ({\n HostPort: p.hostPort ? String(p.hostPort) : undefined,\n HostIp: p.hostIP,\n }));\n }\n return { ExposedPorts: exposed, PortBindings: bindings };\n}\n\nfunction dockerHostNameFromEnv(): string {\n const hostEnv = process.env.DOCKER_HOST;\n if (hostEnv?.startsWith('tcp://')) {\n try {\n const u = new URL(hostEnv);\n return u.hostname || 'localhost';\n } catch { /* noop */ }\n }\n return 'localhost';\n}\n\nfunction pickImageForRuntime(runtime: Runtime, configured?: DockerImage): DockerImage {\n // If user supplied an image that already matches, use it. Otherwise pick a sensible default.\n if (configured?.name) {\n if (runtime === 'python' && /python|conda|pypy/i.test(configured.name)) return configured;\n if (runtime === 'node' && /node/i.test(configured.name)) return configured;\n }\n return {\n name: runtime === 'python' ? 'python:3.11-slim' : 'node:20-alpine',\n pullPolicy: configured?.pullPolicy ?? 'ifNotPresent',\n auth: configured?.auth,\n };\n}\n\nexport const docker = defineProvider<DockerSandboxHandle, DockerConfig>({\n name: PROVIDER,\n methods: {\n sandbox: {\n create: async (config: DockerConfig, options?: CreateSandboxOptions) => {\n const cfg: DockerConfig = { ...defaultDockerConfig, ...config };\n const effectiveRuntime: Runtime = (options?.runtime ?? cfg.runtime ?? 'python') as Runtime;\n\n if (effectiveRuntime !== 'python' && effectiveRuntime !== 'node') {\n throw new Error(`Docker provider supports only 'python' or 'node'. Received: ${String(effectiveRuntime)}`);\n }\n\n const docker = new Docker(cfg.connection as any);\n\n // Reattach?\n if (options?.sandboxId) {\n try {\n const container = docker.getContainer(options.sandboxId);\n const info = await container.inspect();\n return {\n sandbox: <DockerSandboxHandle>{\n docker,\n container,\n containerId: options.sandboxId,\n image: info.Config?.Image ?? cfg.image.name,\n createdAt: new Date(info.Created || Date.now()),\n },\n sandboxId: options.sandboxId,\n };\n } catch (err) {\n // Failed to reattach to existing container; will create a new one.\n console.warn(`Could not reattach to Docker container with ID ${options.sandboxId}:`, err);\n }\n }\n\n // Choose image based on runtime if needed\n const chosenImage = pickImageForRuntime(effectiveRuntime, cfg.image);\n await ensureImage(docker, chosenImage);\n\n // Merge environment variables: config.container.env < options.envs\n const mergedEnv = { ...cfg.container?.env, ...options?.envs };\n\n // Build container create options\n const hb = toHostBindings(cfg.container?.ports);\n const createOptions = {\n Image: chosenImage.name,\n Tty: pick(cfg.container?.tty, false),\n OpenStdin: pick(cfg.container?.openStdin, false),\n Labels: {\n // User metadata is spread first with a namespaced prefix so it\n // cannot overwrite the reserved discovery/runtime labels below.\n ...(options?.metadata ? Object.fromEntries(\n Object.entries(options.metadata).map(([k, v]) => [`com.computesdk.meta.${k}`, typeof v === 'string' ? v : JSON.stringify(v)])\n ) : {}),\n [LABEL_KEY]: 'true',\n [LABEL_RUNTIME]: effectiveRuntime,\n },\n WorkingDir: cfg.container?.workdir,\n Env: Object.keys(mergedEnv).length > 0\n ? Object.entries(mergedEnv).map(([k, v]) => `${k}=${v}`)\n : undefined,\n Cmd: KEEPALIVE_CMD, // keep container alive\n HostConfig: {\n AutoRemove: cfg.container?.autoRemove ?? false, // keep around for exec/FS ops\n Binds: cfg.container?.binds,\n NetworkMode: cfg.container?.networkMode,\n Privileged: cfg.container?.privileged,\n CapAdd: cfg.container?.capabilities?.add,\n CapDrop: cfg.container?.capabilities?.drop,\n LogConfig: cfg.container?.logDriver\n ? { Type: cfg.container.logDriver, Config: cfg.container.logOpts || {} }\n : undefined,\n Resources: cfg.container?.resources,\n DeviceRequests: cfg.container?.gpus\n ? [\n {\n Driver: 'nvidia',\n Count:\n cfg.container.gpus === 'all'\n ? -1\n : typeof cfg.container.gpus === 'number'\n ? cfg.container.gpus\n : 1,\n DeviceIDs:\n typeof cfg.container.gpus === 'string' && cfg.container.gpus !== 'all'\n ? [String(cfg.container.gpus)]\n : undefined,\n Capabilities: [['gpu']],\n },\n ]\n : undefined,\n ...(hb ? { PortBindings: hb.PortBindings } : {}),\n },\n ...(hb ? { ExposedPorts: hb.ExposedPorts } : {}),\n ...(cfg.createOptions || {}),\n } as import('dockerode').ContainerCreateOptions;\n\n const container = await docker.createContainer(createOptions);\n await container.start(cfg.startOptions || {});\n await waitUntilRunning(container);\n\n const inspect = await container.inspect();\n const handle: DockerSandboxHandle = {\n docker,\n container,\n containerId: inspect.Id,\n image: inspect.Config?.Image ?? chosenImage.name,\n createdAt: new Date(inspect.Created || Date.now()),\n };\n\n return { sandbox: handle, sandboxId: handle.containerId };\n },\n\n getById: async (config: DockerConfig, sandboxId: string) => {\n const docker = new Docker((config || defaultDockerConfig).connection as any);\n try {\n const container = docker.getContainer(sandboxId);\n const info = await container.inspect();\n return {\n sandbox: <DockerSandboxHandle>{\n docker,\n container,\n containerId: sandboxId,\n image: info.Config?.Image ?? '',\n createdAt: new Date(info.Created || Date.now()),\n },\n sandboxId,\n };\n } catch {\n return null;\n }\n },\n\n list: async (config: DockerConfig) => {\n const docker = new Docker((config || defaultDockerConfig).connection as any);\n try {\n const items = await docker.listContainers({\n all: true,\n filters: { label: [LABEL_KEY] } as any,\n });\n return items.map(ci => ({\n sandbox: <DockerSandboxHandle>{\n docker,\n container: docker.getContainer(ci.Id),\n containerId: ci.Id,\n image: ci.Image,\n createdAt: new Date((ci as any).Created * 1000),\n },\n sandboxId: ci.Id,\n }));\n } catch {\n return [];\n }\n },\n\n destroy: async (config: DockerConfig, sandboxId: string) => {\n const docker = new Docker((config || defaultDockerConfig).connection as any);\n try {\n const c = docker.getContainer(sandboxId);\n try { await c.stop({ t: 5 } as any); } catch { /* stopped */ }\n await c.remove({ force: true });\n } catch {\n // ok if already gone\n }\n },\n\n runCode: async (handle: DockerSandboxHandle, code: string, runtime?: Runtime): Promise<CodeResult> => {\n const start = Date.now();\n\n // Resolve runtime: param → label → error\n let rt: Runtime | undefined = runtime;\n if (!rt) {\n const info = await handle.container.inspect();\n rt = (info.Config?.Labels?.[LABEL_RUNTIME] as Runtime) || undefined;\n }\n if (rt !== 'python' && rt !== 'node') {\n throw new Error(`Docker runtime must be 'python' or 'node'. Pass runtime in config or as a parameter.`);\n }\n\n // Write to file, then execute. This is robust on Alpine/Debian.\n const tmpFile = rt === 'python' ? '/tmp/compute_code.py' : '/tmp/compute_code.js';\n const b64 = Buffer.from(code, 'utf8').toString('base64');\n const makeAndRun =\n `printf '%s' \"${b64}\" | base64 -d > ${tmpFile} && ` +\n (rt === 'python' ? `python3 ${tmpFile}` : `node ${tmpFile}`);\n\n const { stdout, stderr, exitCode } = await runExec(handle, makeAndRun);\n\n if (exitCode !== 0 && stderr) {\n // Throw ONLY on syntax errors (SDK contract)\n const isSyntax =\n stderr.includes('SyntaxError') ||\n stderr.includes('invalid syntax') ||\n stderr.includes('Unexpected token') ||\n stderr.includes('Unexpected identifier');\n if (isSyntax) {\n const last = stderr.trim().split('\\n').slice(-1)[0] || 'Syntax error';\n throw new Error(`Syntax error: ${last}`);\n }\n }\n\n return {\n output: stdout + stderr,\n exitCode,\n language: rt,\n };\n },\n\n runCommand: async (\n handle: DockerSandboxHandle,\n command: string,\n options?: RunCommandOptions\n ): Promise<CommandResult> => {\n const start = Date.now();\n\n const { stdout, stderr, exitCode } = await runExec(handle, command);\n\n return {\n stdout,\n stderr,\n exitCode,\n durationMs: Date.now() - start,\n };\n },\n\n getInfo: async (handle: DockerSandboxHandle): Promise<SandboxInfo> => {\n const info = await handle.container.inspect();\n const state = info.State || {};\n return {\n id: handle.containerId,\n provider: PROVIDER,\n runtime: (info.Config?.Labels?.[LABEL_RUNTIME] as Runtime) || 'python',\n status: state.Running ? 'running' : 'stopped',\n createdAt: new Date(info.Created || handle.createdAt),\n timeout: 300000,\n metadata: {\n image: info.Config?.Image,\n name: info.Name,\n },\n };\n },\n\n getUrl: async (handle: DockerSandboxHandle, options: { port: number; protocol?: string }): Promise<string> => {\n const info = await handle.container.inspect();\n const protocol = options.protocol || 'http';\n const portKeyTcp = `${options.port}/tcp`;\n\n const ports = info.NetworkSettings?.Ports || {};\n const bindings = ports[portKeyTcp] || ports[`${options.port}/udp`] || [];\n\n let host = dockerHostNameFromEnv();\n let hostPort = String(options.port);\n\n if (Array.isArray(bindings) && bindings.length > 0) {\n hostPort = bindings[0].HostPort || hostPort;\n } else {\n const ip =\n info.NetworkSettings?.IPAddress ||\n Object.values(info.NetworkSettings?.Networks || {})[0]?.IPAddress;\n if (ip) host = ip;\n }\n\n return `${protocol}://${host}:${hostPort}`;\n },\n\n filesystem: {\n readFile: async (handle: DockerSandboxHandle, path: string): Promise<string> => {\n const cmd = `if [ -f ${JSON.stringify(path)} ]; then base64 ${JSON.stringify(path)} | tr -d '\\\\n'; else exit 1; fi`;\n const { stdout, exitCode, stderr } = await runExec(handle, cmd);\n if (exitCode !== 0) throw new Error(stderr || `File not found: ${path}`);\n return Buffer.from(stdout, 'base64').toString('utf8');\n },\n\n writeFile: async (handle: DockerSandboxHandle, path: string, content: string): Promise<void> => {\n const b64 = Buffer.from(content, 'utf8').toString('base64');\n const cmd = `mkdir -p $(dirname ${JSON.stringify(path)}) && echo \"${b64}\" | base64 -d > ${JSON.stringify(path)}`;\n const { exitCode, stderr } = await runExec(handle, cmd);\n if (exitCode !== 0) throw new Error(stderr || `Failed to write: ${path}`);\n },\n\n mkdir: async (handle: DockerSandboxHandle, path: string): Promise<void> => {\n const { exitCode, stderr } = await runExec(handle, `mkdir -p ${JSON.stringify(path)}`);\n if (exitCode !== 0) throw new Error(stderr || `Failed to mkdir: ${path}`);\n },\n\n readdir: async (handle: DockerSandboxHandle, path: string): Promise<FileEntry[]> => {\n const { stdout, exitCode, stderr } = await runExec(\n handle,\n `if [ -d ${JSON.stringify(path)} ]; then ls -la ${JSON.stringify(path)}; else exit 1; fi`\n );\n if (exitCode !== 0) throw new Error(stderr || `Not a directory: ${path}`);\n\n const lines = stdout.split('\\n').slice(1);\n const entries: FileEntry[] = [];\n for (const line of lines) {\n const parts = line.trim().split(/\\s+/);\n if (parts.length < 9) continue;\n const name = parts.slice(8).join(' ');\n if (name === '.' || name === '..') continue;\n const isDir = parts[0].startsWith('d');\n const size = Number(parts[4]) || 0;\n entries.push({\n name,\n type: isDir ? 'directory' as const : 'file' as const,\n size,\n modified: new Date(),\n });\n }\n return entries;\n },\n\n exists: async (handle: DockerSandboxHandle, path: string): Promise<boolean> => {\n const { exitCode } = await runExec(handle, `test -e ${JSON.stringify(path)}`);\n return exitCode === 0;\n },\n\n remove: async (handle: DockerSandboxHandle, path: string): Promise<void> => {\n const { exitCode, stderr } = await runExec(handle, `rm -rf ${JSON.stringify(path)}`);\n if (exitCode !== 0) throw new Error(stderr || `Failed to remove: ${path}`);\n },\n },\n\n getInstance: (handle: DockerSandboxHandle): DockerSandboxHandle => handle,\n },\n },\n});\n\n","import type Docker from 'dockerode';\nimport type {\n DockerOptions,\n Container,\n ContainerCreateOptions,\n ContainerStartOptions,\n ContainerInspectInfo,\n ContainerInfo,\n Exec,\n ImageInfo,\n ImageBuildOptions,\n Network,\n} from 'dockerode';\n\nimport type {\n Runtime,\n FileEntry,\n RunCommandOptions,\n CreateSandboxOptions,\n SandboxInfo,\n} from 'computesdk';\n\n/** When the provider should clean up containers it created */\nexport type CleanupPolicy = 'always' | 'onSuccess' | 'never';\n\n/** Image pull strategy */\nexport type PullPolicy = 'always' | 'ifNotPresent' | 'never';\n\n/** Connection to the Docker daemon (exactly what dockerode accepts) */\nexport type DockerConnection = DockerOptions;\n\n/** Auth when pulling private images (Engine API AuthConfig shape) */\nexport interface RegistryAuth {\n username?: string;\n password?: string;\n serveraddress?: string;\n identitytoken?: string;\n registrytoken?: string;\n}\n\n/** Default image & pull policy for sandboxes */\nexport interface DockerImage {\n name: string; // e.g. 'python:3.11-slim'\n pullPolicy?: PullPolicy; // default: 'ifNotPresent'\n auth?: RegistryAuth;\n}\n\n/** Convenience shape for port bindings */\nexport type PortBindings = Record<\n `${number}/${'tcp' | 'udp'}`,\n Array<{ hostPort?: number; hostIP?: string }>\n>;\n\n/** Subset of HostConfig resources & knobs that are commonly used */\nexport interface ResourceLimits {\n cpuShares?: number;\n cpuQuota?: number;\n cpuPeriod?: number;\n nanoCPUs?: number;\n memory?: number;\n memorySwap?: number;\n pidsLimit?: number;\n}\n\n/** Declarative container defaults that we’ll translate into dockerode create options */\nexport interface ContainerDefaults {\n user?: string;\n workdir?: string;\n env?: Record<string, string>;\n binds?: string[];\n ports?: PortBindings;\n networkMode?: string;\n privileged?: boolean;\n capabilities?: { add?: string[]; drop?: string[] };\n gpus?: 'all' | number | string;\n resources?: ResourceLimits;\n logDriver?: string;\n logOpts?: Record<string, string>;\n autoRemove?: boolean;\n tty?: boolean;\n openStdin?: boolean;\n}\n\n/** Provider-level configuration for Docker */\nexport interface DockerConfig {\n connection?: DockerConnection;\n runtime?: Runtime; // 'python' | 'node'\n timeout?: number;\n image: DockerImage;\n container?: ContainerDefaults;\n createOptions?: ContainerCreateOptions;\n startOptions?: ContainerStartOptions;\n cleanup?: CleanupPolicy;\n streamLogs?: boolean;\n}\n\n/** What we keep for each running sandbox */\nexport interface DockerSandboxHandle {\n docker: Docker;\n container: Container;\n containerId: string;\n image: string;\n createdAt: Date;\n}\n\n/** URL options for port-forwarded services */\nexport interface DockerUrlOptions {\n port: number;\n protocol?: 'http' | 'https';\n host?: string;\n}\n\n/** Optional FS helpers you might expose */\nexport interface DockerSandboxFileSystem {\n readFile(path: string): Promise<string>;\n writeFile(path: string, content: string): Promise<void>;\n mkdir(path: string): Promise<void>;\n readdir(path: string): Promise<FileEntry[]>;\n exists(path: string): Promise<boolean>;\n remove(path: string): Promise<void>;\n}\n\n/** Sensible, safe defaults */\nexport const defaultDockerConfig: DockerConfig = {\n connection: {\n // Let dockerode fall back to DOCKER_HOST or /var/run/docker.sock\n timeout: 60_000,\n version: 'v1.43',\n },\n runtime: 'python',\n timeout: 300_000, // 5 minutes\n image: {\n name: 'python:3.11-slim',\n pullPolicy: 'ifNotPresent',\n },\n container: {\n workdir: '/workspace',\n env: {},\n autoRemove: false, // Keep container around for exec/FS/background\n tty: false, // Non-tty so we can demux stdout/stderr\n openStdin: false,\n resources: { memory: 512 * 1024 * 1024 },\n },\n cleanup: 'always',\n streamLogs: false,\n};\n\n/** Re-exports for convenience */\nexport type {\n Docker,\n Container,\n Exec,\n ContainerCreateOptions,\n ContainerStartOptions,\n ContainerInspectInfo,\n ContainerInfo,\n ImageInfo,\n ImageBuildOptions,\n Network,\n};\n"],"mappings":"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","names":["docker","container"]}
|
|
1
|
+
{"version":3,"sources":["../src/index.ts","../src/types/types.ts"],"sourcesContent":["import Docker from 'dockerode';\nimport { PassThrough } from 'stream';\nimport { defineProvider } from '@computesdk/provider';\nimport type {\n CommandResult,\n RunCommandOptions,\n CreateSandboxOptions,\n SandboxInfo,\n FileEntry,\n} from '@computesdk/provider';\n\nimport { defaultDockerConfig } from './types/types';\nimport type {\n DockerConfig,\n DockerSandboxHandle,\n DockerImage,\n PortBindings,\n} from './types/types';\n\nconst PROVIDER = 'docker' as const;\nconst LABEL_KEY = 'com.computesdk.sandbox';\nconst LABEL_RUNTIME = 'com.computesdk.runtime';\nconst KEEPALIVE_CMD = ['/bin/sh', '-c', 'while :; do sleep 3600; done'];\n\nfunction pick<T>(val: T | undefined, fallback: T): T {\n return typeof val === 'undefined' ? fallback : val;\n}\n\nasync function ensureImage(docker: Docker, image: DockerImage): Promise<void> {\n const policy = image.pullPolicy ?? 'ifNotPresent';\n if (policy === 'never') return;\n const images = await docker.listImages();\n const hasImage = images.some(img => (img.RepoTags || []).includes(image.name));\n if (policy === 'always' || (policy === 'ifNotPresent' && !hasImage)) {\n await new Promise<void>((resolve, reject) => {\n const cb = (err: any, stream?: NodeJS.ReadableStream) => {\n if (err) return reject(err);\n if (!stream) return reject(new Error('docker.pull returned no stream'));\n (docker as any).modem.followProgress(stream, (err2: any) => (err2 ? reject(err2) : resolve()));\n };\n if (image.auth) docker.pull(image.name, { authconfig: image.auth } as any, cb);\n else docker.pull(image.name, cb);\n });\n }\n}\n\nasync function waitUntilRunning(container: Docker.Container, timeoutMs = 4000) {\n const start = Date.now();\n try {\n const s = await container.inspect();\n if (s.State?.Running) return;\n } catch { /* ignore */ }\n while (Date.now() - start < timeoutMs) {\n const s = await container.inspect();\n if (s.State?.Running) return;\n await new Promise(r => setTimeout(r, 100));\n }\n throw new Error('Container did not reach Running state in time');\n}\n\nasync function runExec(\n handle: DockerSandboxHandle,\n shellCommand: string,\n attachTTY = false\n): Promise<{ stdout: string; stderr: string; exitCode: number }> {\n await waitUntilRunning(handle.container);\n const exec = await handle.container.exec({\n Cmd: ['/bin/sh', '-c', shellCommand],\n AttachStdout: true,\n AttachStderr: true,\n Tty: attachTTY,\n });\n const stream = (await exec.start({ hijack: true, stdin: false })) as NodeJS.ReadableStream;\n let stdout = '';\n let stderr = '';\n await new Promise<void>((resolve, reject) => {\n if (attachTTY) {\n stream.on('data', (chunk: Buffer) => (stdout += chunk.toString('utf8')));\n stream.on('end', resolve);\n stream.on('error', reject);\n return;\n }\n const out = new PassThrough();\n const err = new PassThrough();\n out.on('data', (c: Buffer) => (stdout += c.toString('utf8')));\n err.on('data', (c: Buffer) => (stderr += c.toString('utf8')));\n (handle.docker as any).modem.demuxStream(stream as any, out as any, err as any);\n stream.on('end', resolve);\n stream.on('error', reject);\n });\n const inspect = await exec.inspect();\n return { stdout, stderr, exitCode: inspect.ExitCode ?? 0 };\n}\n\nfunction toHostBindings(ports?: PortBindings) {\n if (!ports) return undefined;\n const exposed: Record<string, {}> = {};\n const bindings: Record<string, Array<{ HostPort?: string; HostIp?: string }>> = {};\n for (const key of Object.keys(ports)) {\n exposed[key] = {};\n bindings[key] = (ports as any)[key].map((p: any) => ({ HostPort: p.hostPort ? String(p.hostPort) : undefined, HostIp: p.hostIP }));\n }\n return { ExposedPorts: exposed, PortBindings: bindings };\n}\n\nfunction dockerHostNameFromEnv(): string {\n const hostEnv = process.env.DOCKER_HOST;\n if (hostEnv?.startsWith('tcp://')) {\n try { return new URL(hostEnv).hostname || 'localhost'; } catch { /* noop */ }\n }\n return 'localhost';\n}\n\nfunction pickImageForRuntime(runtime: string, configured?: DockerImage): DockerImage {\n if (configured?.name) {\n if (runtime === 'python' && /python|conda|pypy/i.test(configured.name)) return configured;\n if (runtime === 'node' && /node/i.test(configured.name)) return configured;\n }\n return {\n name: runtime === 'python' ? 'python:3.11-slim' : 'node:20-alpine',\n pullPolicy: configured?.pullPolicy ?? 'ifNotPresent',\n auth: configured?.auth,\n };\n}\n\nexport const docker = defineProvider<DockerSandboxHandle, DockerConfig>({\n name: PROVIDER,\n methods: {\n sandbox: {\n create: async (config: DockerConfig, options?: CreateSandboxOptions) => {\n const cfg: DockerConfig = { ...defaultDockerConfig, ...config };\n const effectiveRuntime: string = ((options as any)?.runtime ?? cfg.runtime ?? 'python') as string;\n\n if (effectiveRuntime !== 'python' && effectiveRuntime !== 'node') {\n throw new Error(`Docker provider supports only 'python' or 'node'. Received: ${String(effectiveRuntime)}`);\n }\n\n const docker = new Docker(cfg.connection as any);\n const chosenImage = pickImageForRuntime(effectiveRuntime, cfg.image);\n await ensureImage(docker, chosenImage);\n\n const mergedEnv = { ...cfg.container?.env, ...options?.envs };\n const hb = toHostBindings(cfg.container?.ports);\n const createOptions = {\n Image: chosenImage.name,\n Tty: pick(cfg.container?.tty, false),\n OpenStdin: pick(cfg.container?.openStdin, false),\n Labels: {\n ...(options?.metadata ? Object.fromEntries(\n Object.entries(options.metadata).map(([k, v]) => [`com.computesdk.meta.${k}`, typeof v === 'string' ? v : JSON.stringify(v)])\n ) : {}),\n [LABEL_KEY]: 'true',\n [LABEL_RUNTIME]: effectiveRuntime,\n },\n WorkingDir: cfg.container?.workdir,\n Env: Object.keys(mergedEnv).length > 0\n ? Object.entries(mergedEnv).map(([k, v]) => `${k}=${v}`)\n : undefined,\n Cmd: KEEPALIVE_CMD,\n HostConfig: {\n AutoRemove: cfg.container?.autoRemove ?? false,\n Binds: cfg.container?.binds,\n NetworkMode: cfg.container?.networkMode,\n Privileged: cfg.container?.privileged,\n CapAdd: cfg.container?.capabilities?.add,\n CapDrop: cfg.container?.capabilities?.drop,\n LogConfig: cfg.container?.logDriver\n ? { Type: cfg.container.logDriver, Config: cfg.container.logOpts || {} }\n : undefined,\n Resources: cfg.container?.resources,\n DeviceRequests: cfg.container?.gpus ? [{\n Driver: 'nvidia',\n Count: cfg.container.gpus === 'all' ? -1 : typeof cfg.container.gpus === 'number' ? cfg.container.gpus : 1,\n DeviceIDs: typeof cfg.container.gpus === 'string' && cfg.container.gpus !== 'all' ? [String(cfg.container.gpus)] : undefined,\n Capabilities: [['gpu']],\n }] : undefined,\n ...(hb ? { PortBindings: hb.PortBindings } : {}),\n },\n ...(hb ? { ExposedPorts: hb.ExposedPorts } : {}),\n ...(cfg.createOptions || {}),\n } as import('dockerode').ContainerCreateOptions;\n\n const container = await docker.createContainer(createOptions);\n await container.start(cfg.startOptions || {});\n await waitUntilRunning(container);\n const inspect = await container.inspect();\n const handle: DockerSandboxHandle = {\n docker, container, containerId: inspect.Id,\n image: inspect.Config?.Image ?? chosenImage.name,\n createdAt: new Date(inspect.Created || Date.now()),\n };\n return { sandbox: handle, sandboxId: handle.containerId };\n },\n\n getById: async (config: DockerConfig, sandboxId: string) => {\n const docker = new Docker((config || defaultDockerConfig).connection as any);\n try {\n const container = docker.getContainer(sandboxId);\n const info = await container.inspect();\n return { sandbox: { docker, container, containerId: sandboxId, image: info.Config?.Image ?? '', createdAt: new Date(info.Created || Date.now()) } as DockerSandboxHandle, sandboxId };\n } catch { return null; }\n },\n\n list: async (config: DockerConfig) => {\n const docker = new Docker((config || defaultDockerConfig).connection as any);\n try {\n const items = await docker.listContainers({ all: true, filters: { label: [LABEL_KEY] } as any });\n return items.map(ci => ({\n sandbox: { docker, container: docker.getContainer(ci.Id), containerId: ci.Id, image: ci.Image, createdAt: new Date((ci as any).Created * 1000) } as DockerSandboxHandle,\n sandboxId: ci.Id,\n }));\n } catch { return []; }\n },\n\n destroy: async (config: DockerConfig, sandboxId: string) => {\n const docker = new Docker((config || defaultDockerConfig).connection as any);\n try {\n const c = docker.getContainer(sandboxId);\n try { await c.stop({ t: 5 } as any); } catch { /* stopped */ }\n await c.remove({ force: true });\n } catch { /* ok if already gone */ }\n },\n\n runCommand: async (handle: DockerSandboxHandle, command: string, _options?: RunCommandOptions): Promise<CommandResult> => {\n const start = Date.now();\n const { stdout, stderr, exitCode } = await runExec(handle, command);\n return { stdout, stderr, exitCode, durationMs: Date.now() - start };\n },\n\n getInfo: async (handle: DockerSandboxHandle): Promise<SandboxInfo> => {\n const info = await handle.container.inspect();\n const state = info.State || {};\n return {\n id: handle.containerId,\n provider: PROVIDER,\n status: state.Running ? 'running' : 'stopped',\n createdAt: new Date(info.Created || handle.createdAt),\n timeout: 300000,\n metadata: {\n image: info.Config?.Image,\n name: info.Name,\n runtime: info.Config?.Labels?.[LABEL_RUNTIME],\n },\n };\n },\n\n getUrl: async (handle: DockerSandboxHandle, options: { port: number; protocol?: string }): Promise<string> => {\n const info = await handle.container.inspect();\n const protocol = options.protocol || 'http';\n const portKeyTcp = `${options.port}/tcp`;\n const ports = info.NetworkSettings?.Ports || {};\n const bindings = ports[portKeyTcp] || ports[`${options.port}/udp`] || [];\n let host = dockerHostNameFromEnv();\n let hostPort = String(options.port);\n if (Array.isArray(bindings) && bindings.length > 0) {\n hostPort = bindings[0].HostPort || hostPort;\n } else {\n const ip = info.NetworkSettings?.IPAddress || Object.values(info.NetworkSettings?.Networks || {})[0]?.IPAddress;\n if (ip) host = ip;\n }\n return `${protocol}://${host}:${hostPort}`;\n },\n\n filesystem: {\n readFile: async (handle: DockerSandboxHandle, path: string): Promise<string> => {\n const cmd = `if [ -f ${JSON.stringify(path)} ]; then base64 ${JSON.stringify(path)} | tr -d '\\\\n'; else exit 1; fi`;\n const { stdout, exitCode, stderr } = await runExec(handle, cmd);\n if (exitCode !== 0) throw new Error(stderr || `File not found: ${path}`);\n return Buffer.from(stdout, 'base64').toString('utf8');\n },\n writeFile: async (handle: DockerSandboxHandle, path: string, content: string): Promise<void> => {\n const b64 = Buffer.from(content, 'utf8').toString('base64');\n const cmd = `mkdir -p $(dirname ${JSON.stringify(path)}) && echo \"${b64}\" | base64 -d > ${JSON.stringify(path)}`;\n const { exitCode, stderr } = await runExec(handle, cmd);\n if (exitCode !== 0) throw new Error(stderr || `Failed to write: ${path}`);\n },\n mkdir: async (handle: DockerSandboxHandle, path: string): Promise<void> => {\n const { exitCode, stderr } = await runExec(handle, `mkdir -p ${JSON.stringify(path)}`);\n if (exitCode !== 0) throw new Error(stderr || `Failed to mkdir: ${path}`);\n },\n readdir: async (handle: DockerSandboxHandle, path: string): Promise<FileEntry[]> => {\n const { stdout, exitCode, stderr } = await runExec(handle, `if [ -d ${JSON.stringify(path)} ]; then ls -la ${JSON.stringify(path)}; else exit 1; fi`);\n if (exitCode !== 0) throw new Error(stderr || `Not a directory: ${path}`);\n const lines = stdout.split('\\n').slice(1);\n const entries: FileEntry[] = [];\n for (const line of lines) {\n const parts = line.trim().split(/\\s+/);\n if (parts.length < 9) continue;\n const name = parts.slice(8).join(' ');\n if (name === '.' || name === '..') continue;\n entries.push({ name, type: parts[0].startsWith('d') ? 'directory' as const : 'file' as const, size: Number(parts[4]) || 0, modified: new Date() });\n }\n return entries;\n },\n exists: async (handle: DockerSandboxHandle, path: string): Promise<boolean> => {\n const { exitCode } = await runExec(handle, `test -e ${JSON.stringify(path)}`);\n return exitCode === 0;\n },\n remove: async (handle: DockerSandboxHandle, path: string): Promise<void> => {\n const { exitCode, stderr } = await runExec(handle, `rm -rf ${JSON.stringify(path)}`);\n if (exitCode !== 0) throw new Error(stderr || `Failed to remove: ${path}`);\n },\n },\n\n getInstance: (handle: DockerSandboxHandle): DockerSandboxHandle => handle,\n },\n },\n});\n","import type Docker from 'dockerode';\nimport type {\n DockerOptions,\n Container,\n ContainerCreateOptions,\n ContainerStartOptions,\n ContainerInspectInfo,\n ContainerInfo,\n Exec,\n ImageInfo,\n ImageBuildOptions,\n Network,\n} from 'dockerode';\n\nimport type {\n FileEntry,\n RunCommandOptions,\n CreateSandboxOptions,\n SandboxInfo,\n} from 'computesdk';\n\n/** When the provider should clean up containers it created */\nexport type CleanupPolicy = 'always' | 'onSuccess' | 'never';\n\n/** Image pull strategy */\nexport type PullPolicy = 'always' | 'ifNotPresent' | 'never';\n\n/** Connection to the Docker daemon (exactly what dockerode accepts) */\nexport type DockerConnection = DockerOptions;\n\n/** Auth when pulling private images (Engine API AuthConfig shape) */\nexport interface RegistryAuth {\n username?: string;\n password?: string;\n serveraddress?: string;\n identitytoken?: string;\n registrytoken?: string;\n}\n\n/** Default image & pull policy for sandboxes */\nexport interface DockerImage {\n name: string; // e.g. 'python:3.11-slim'\n pullPolicy?: PullPolicy; // default: 'ifNotPresent'\n auth?: RegistryAuth;\n}\n\n/** Convenience shape for port bindings */\nexport type PortBindings = Record<\n `${number}/${'tcp' | 'udp'}`,\n Array<{ hostPort?: number; hostIP?: string }>\n>;\n\n/** Subset of HostConfig resources & knobs that are commonly used */\nexport interface ResourceLimits {\n cpuShares?: number;\n cpuQuota?: number;\n cpuPeriod?: number;\n nanoCPUs?: number;\n memory?: number;\n memorySwap?: number;\n pidsLimit?: number;\n}\n\n/** Declarative container defaults that we'll translate into dockerode create options */\nexport interface ContainerDefaults {\n user?: string;\n workdir?: string;\n env?: Record<string, string>;\n binds?: string[];\n ports?: PortBindings;\n networkMode?: string;\n privileged?: boolean;\n capabilities?: { add?: string[]; drop?: string[] };\n gpus?: 'all' | number | string;\n resources?: ResourceLimits;\n logDriver?: string;\n logOpts?: Record<string, string>;\n autoRemove?: boolean;\n tty?: boolean;\n openStdin?: boolean;\n}\n\n/** Provider-level configuration for Docker */\nexport interface DockerConfig {\n connection?: DockerConnection;\n /** Default image runtime identifier, e.g. 'python' or 'node' */\n runtime?: string;\n timeout?: number;\n image: DockerImage;\n container?: ContainerDefaults;\n createOptions?: ContainerCreateOptions;\n startOptions?: ContainerStartOptions;\n cleanup?: CleanupPolicy;\n streamLogs?: boolean;\n}\n\n/** What we keep for each running sandbox */\nexport interface DockerSandboxHandle {\n docker: Docker;\n container: Container;\n containerId: string;\n image: string;\n createdAt: Date;\n}\n\n/** URL options for port-forwarded services */\nexport interface DockerUrlOptions {\n port: number;\n protocol?: 'http' | 'https';\n host?: string;\n}\n\n/** Optional FS helpers you might expose */\nexport interface DockerSandboxFileSystem {\n readFile(path: string): Promise<string>;\n writeFile(path: string, content: string): Promise<void>;\n mkdir(path: string): Promise<void>;\n readdir(path: string): Promise<FileEntry[]>;\n exists(path: string): Promise<boolean>;\n remove(path: string): Promise<void>;\n}\n\n/** Sensible, safe defaults */\nexport const defaultDockerConfig: DockerConfig = {\n connection: {\n // Let dockerode fall back to DOCKER_HOST or /var/run/docker.sock\n timeout: 60_000,\n version: 'v1.43',\n },\n runtime: 'python',\n timeout: 300_000, // 5 minutes\n image: {\n name: 'python:3.11-slim',\n pullPolicy: 'ifNotPresent',\n },\n container: {\n workdir: '/workspace',\n env: {},\n autoRemove: false, // Keep container around for exec/FS/background\n tty: false, // Non-tty so we can demux stdout/stderr\n openStdin: false,\n resources: { memory: 512 * 1024 * 1024 },\n },\n cleanup: 'always',\n streamLogs: false,\n};\n\n/** Re-exports for convenience */\nexport type {\n Docker,\n Container,\n Exec,\n ContainerCreateOptions,\n ContainerStartOptions,\n ContainerInspectInfo,\n ContainerInfo,\n ImageInfo,\n ImageBuildOptions,\n Network,\n};\n"],"mappings":"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","names":["docker"]}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@computesdk/docker",
|
|
3
|
-
"version": "1.2.
|
|
3
|
+
"version": "1.2.45",
|
|
4
4
|
"description": "Docker provider for ComputeSDK - local containerized sandboxes for development and testing",
|
|
5
5
|
"author": "IberAI",
|
|
6
6
|
"license": "MIT",
|
|
@@ -19,8 +19,8 @@
|
|
|
19
19
|
],
|
|
20
20
|
"dependencies": {
|
|
21
21
|
"dockerode": "^4.0.8",
|
|
22
|
-
"@computesdk/provider": "
|
|
23
|
-
"computesdk": "
|
|
22
|
+
"@computesdk/provider": "2.0.0",
|
|
23
|
+
"computesdk": "4.0.0"
|
|
24
24
|
},
|
|
25
25
|
"keywords": [
|
|
26
26
|
"computesdk",
|
|
@@ -53,7 +53,7 @@
|
|
|
53
53
|
"tsup": "^8.0.0",
|
|
54
54
|
"typescript": "^5.0.0",
|
|
55
55
|
"vitest": "^1.0.0",
|
|
56
|
-
"@computesdk/test-utils": "
|
|
56
|
+
"@computesdk/test-utils": "2.0.0"
|
|
57
57
|
},
|
|
58
58
|
"scripts": {
|
|
59
59
|
"build": "tsup",
|