@computesdk/docker 1.2.44 → 1.2.46

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 CHANGED
@@ -35,26 +35,6 @@ Common environment variables (used by Docker/dockerode):
35
35
 
36
36
  ## Usage
37
37
 
38
- ### Gateway Mode (Recommended)
39
-
40
- Use the gateway for zero-config auto-detection:
41
-
42
- ```ts
43
- import { compute } from 'computesdk';
44
-
45
- // Auto-detects Docker (requires Docker daemon running)
46
- const sandbox = await compute.sandbox.create();
47
-
48
- const result = await sandbox.runCommand('python -c "print(\"Hello from Python\")"');
49
- console.log(result.stdout.trim()); // Hello from Python
50
-
51
- await sandbox.destroy();
52
- ```
53
-
54
- ### Direct Mode
55
-
56
- For direct SDK usage without the gateway:
57
-
58
38
  ```ts
59
39
  import { docker } from '@computesdk/docker';
60
40
 
@@ -90,7 +70,7 @@ const sandbox = await compute.sandbox.create();
90
70
  const result = await sandbox.runCommand('node -e "console.log(\"Hello, World!\")"');
91
71
  console.log(result.stdout.trim()); // Hello, World!
92
72
 
93
- const cmd = await sandbox.runCommand('sh', ['-lc', 'echo Hello from command']);
73
+ const cmd = await sandbox.runCommand('echo Hello from command');
94
74
  console.log(cmd.stdout.trim()); // Hello from command
95
75
 
96
76
  await sandbox.destroy();
@@ -186,24 +166,15 @@ Type: `DockerConfig`
186
166
 
187
167
  ## API Reference
188
168
 
189
- ### Code Execution
190
-
191
- ```ts
192
- sandbox.runCommand(code: string, runtime?: 'python' | 'node'): Promise<ExecutionResult>
193
- ```
194
-
195
- * If `runtime` omitted, the sandbox’s runtime (set at creation) is used.
196
- * Returns `{ stdout, stderr, exitCode, executionTime, sandboxId, provider }`
197
- * Syntax errors are **thrown** as `Error("Syntax error: …")`.
198
-
199
169
  ### Command Execution
200
170
 
201
171
  ```ts
202
- sandbox.runCommand(command: string, args?: string[], options?: { background?: boolean }): Promise<ExecutionResult>
172
+ sandbox.runCommand(command: string, options?: RunCommandOptions): Promise<CommandResult>
203
173
  ```
204
174
 
205
175
  * Runs via `/bin/sh -c "…"` with stdout/stderr capture.
206
- * Background returns `{ isBackground: true, pid?: number }`.
176
+ * Returns `{ stdout, stderr, exitCode, durationMs }`.
177
+ * Options: `{ cwd?, env?, timeout?, background? }`.
207
178
 
208
179
  ### Filesystem Operations
209
180
 
@@ -220,14 +191,14 @@ sandbox.filesystem.remove(path)
220
191
 
221
192
  ### Terminal Operations
222
193
 
223
- Interactive terminals aren’t exposed. Use `runCommand('sh', ['-lc', '…'])` for non-interactive sessions.
194
+ Interactive terminals aren’t exposed. Use `runCommand('…')` for non-interactive sessions.
224
195
 
225
196
  ### Sandbox Management
226
197
 
227
198
  ```ts
228
- const sandbox = await compute.sandbox.create({ runtime?: 'python' | 'node' });
199
+ const sandbox = await compute.sandbox.create();
229
200
 
230
- await sandbox.getInfo(); // { id, provider, runtime, status, createdAt, timeout, metadata }
201
+ await sandbox.getInfo(); // { id, provider, status, createdAt, timeout, metadata }
231
202
  await sandbox.getUrl({ port, protocol?: 'http' | 'https' });
232
203
  sandbox.getInstance(); // { docker: Docker, container: Container, ... }
233
204
  await sandbox.destroy();
@@ -235,25 +206,13 @@ await sandbox.destroy();
235
206
 
236
207
  ---
237
208
 
238
- ## Runtime Detection
239
-
240
- There’s **no auto-detection**. Resolution is:
241
-
242
- 1. provider `config.runtime`, else
243
- 2. fallback default in provider config
244
-
245
- Use `runCommand('python -c "..."')` or `runCommand('node -e "..."')` when you need language-specific execution.
246
-
247
- ---
248
-
249
209
  ## Error Handling
250
210
 
251
- * **Syntax errors** → **thrown** (`Error("Syntax error: …")`)
252
- * **Runtime/command errors** → returned as non-zero `exitCode` with `stderr`
211
+ * **Command errors** → returned as non-zero `exitCode` with `stderr`
253
212
  * **Docker errors** (pull/start/exec) → **thrown**
254
213
 
255
214
  ```ts
256
- const res = await sb.runCommand('sh', ['-lc', 'bad-command']);
215
+ const res = await sb.runCommand('bad-command');
257
216
  if (res.exitCode !== 0) {
258
217
  console.error('stderr:', res.stderr);
259
218
  }
@@ -261,55 +220,36 @@ if (res.exitCode !== 0) {
261
220
 
262
221
  ---
263
222
 
264
- ## Web Framework Integration
265
-
266
- ```ts
267
- import { handleComputeRequest } from 'computesdk';
268
- import { docker } from '@computesdk/docker';
269
-
270
- const compute = docker({
271
- runtime: 'node',
272
- image: { name: 'node:20-alpine' },
273
- });
274
-
275
- export async function POST(req: Request) {
276
- const body = await req.json(); // ComputeRequest
277
- return handleComputeRequest(body, compute);
278
- }
279
- ```
280
-
281
- ---
282
-
283
223
  ## Examples
284
224
 
285
225
  ### Data Science Workflow (Python)
286
226
 
287
227
  ```ts
288
- const sandbox = await compute.sandbox.create({ runtime: 'python' });
289
- await sandbox.runCommand('sh', ['-lc', 'python3 -m pip install --no-cache-dir pandas']);
228
+ const sandbox = await compute.sandbox.create();
229
+ await sandbox.runCommand('python3 -m pip install --no-cache-dir pandas');
290
230
  await sandbox.filesystem.writeFile('/workspace/app.py', `
291
231
  import pandas as pd
292
232
  print("rows:", len(pd.DataFrame({"x":[1,2,3]})))
293
233
  `);
294
- const run = await sandbox.runCommand('sh', ['-lc', 'python3 /workspace/app.py']);
234
+ const run = await sandbox.runCommand('python3 /workspace/app.py');
295
235
  console.log(run.stdout.trim()); // rows: 3
296
236
  await sandbox.destroy();
297
237
  ```
298
238
 
299
- ### Interactive-like Loop
239
+ ### Stateful Loop
300
240
 
301
241
  ```ts
302
- const sandbox = await compute.sandbox.create({ runtime: 'node' });
303
- await sandbox.runCommand('sh', ['-lc', 'echo boot > /tmp/state']);
304
- await sandbox.runCommand('sh', ['-lc', 'cat /tmp/state']); // 'boot'
242
+ const sandbox = await compute.sandbox.create();
243
+ await sandbox.runCommand('echo boot > /tmp/state');
244
+ const res = await sandbox.runCommand('cat /tmp/state'); // 'boot'
305
245
  await sandbox.destroy();
306
246
  ```
307
247
 
308
- ### Machine Learning Pipeline (Python + Ports)
248
+ ### Background Process + Ports
309
249
 
310
250
  ```ts
311
- const sandbox = await compute.sandbox.create({ runtime: 'python' });
312
- const bg = await sandbox.runCommand('sh', ['-lc', 'python3 -m http.server 8080'], { background: true });
251
+ const sandbox = await compute.sandbox.create();
252
+ await sandbox.runCommand('python3 -m http.server 8080', { background: true });
313
253
  const url = await sandbox.getUrl({ port: 8080 });
314
254
  console.log('Serving at', url);
315
255
  await sandbox.destroy();
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’ll translate into dockerode create options */
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?: 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’ll translate into dockerode create options */
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?: 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
- const exitCode = inspect.ExitCode ?? 0;
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
- const u = new URL(hostEnv);
155
- return u.hostname || "localhost";
150
+ return new URL(hostEnv).hostname || "localhost";
156
151
  } catch {
157
152
  }
158
153
  }
@@ -189,8 +184,6 @@ var docker = (0, import_provider.defineProvider)({
189
184
  Tty: pick(cfg.container?.tty, false),
190
185
  OpenStdin: pick(cfg.container?.openStdin, false),
191
186
  Labels: {
192
- // User metadata is spread first with a namespaced prefix so it
193
- // cannot overwrite the reserved discovery/runtime labels below.
194
187
  ...options?.metadata ? Object.fromEntries(
195
188
  Object.entries(options.metadata).map(([k, v]) => [`com.computesdk.meta.${k}`, typeof v === "string" ? v : JSON.stringify(v)])
196
189
  ) : {},
@@ -200,10 +193,8 @@ var docker = (0, import_provider.defineProvider)({
200
193
  WorkingDir: cfg.container?.workdir,
201
194
  Env: Object.keys(mergedEnv).length > 0 ? Object.entries(mergedEnv).map(([k, v]) => `${k}=${v}`) : void 0,
202
195
  Cmd: KEEPALIVE_CMD,
203
- // keep container alive
204
196
  HostConfig: {
205
197
  AutoRemove: cfg.container?.autoRemove ?? false,
206
- // keep around for exec/FS ops
207
198
  Binds: cfg.container?.binds,
208
199
  NetworkMode: cfg.container?.networkMode,
209
200
  Privileged: cfg.container?.privileged,
@@ -211,14 +202,12 @@ var docker = (0, import_provider.defineProvider)({
211
202
  CapDrop: cfg.container?.capabilities?.drop,
212
203
  LogConfig: cfg.container?.logDriver ? { Type: cfg.container.logDriver, Config: cfg.container.logOpts || {} } : void 0,
213
204
  Resources: cfg.container?.resources,
214
- DeviceRequests: cfg.container?.gpus ? [
215
- {
216
- Driver: "nvidia",
217
- Count: cfg.container.gpus === "all" ? -1 : typeof cfg.container.gpus === "number" ? cfg.container.gpus : 1,
218
- DeviceIDs: typeof cfg.container.gpus === "string" && cfg.container.gpus !== "all" ? [String(cfg.container.gpus)] : void 0,
219
- Capabilities: [["gpu"]]
220
- }
221
- ] : 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,
222
211
  ...hb ? { PortBindings: hb.PortBindings } : {}
223
212
  },
224
213
  ...hb ? { ExposedPorts: hb.ExposedPorts } : {},
@@ -242,16 +231,7 @@ var docker = (0, import_provider.defineProvider)({
242
231
  try {
243
232
  const container = docker2.getContainer(sandboxId);
244
233
  const info = await container.inspect();
245
- return {
246
- sandbox: {
247
- docker: docker2,
248
- container,
249
- containerId: sandboxId,
250
- image: info.Config?.Image ?? "",
251
- createdAt: new Date(info.Created || Date.now())
252
- },
253
- sandboxId
254
- };
234
+ return { sandbox: { docker: docker2, container, containerId: sandboxId, image: info.Config?.Image ?? "", createdAt: new Date(info.Created || Date.now()) }, sandboxId };
255
235
  } catch {
256
236
  return null;
257
237
  }
@@ -259,18 +239,9 @@ var docker = (0, import_provider.defineProvider)({
259
239
  list: async (config) => {
260
240
  const docker2 = new import_dockerode.default((config || defaultDockerConfig).connection);
261
241
  try {
262
- const items = await docker2.listContainers({
263
- all: true,
264
- filters: { label: [LABEL_KEY] }
265
- });
242
+ const items = await docker2.listContainers({ all: true, filters: { label: [LABEL_KEY] } });
266
243
  return items.map((ci) => ({
267
- sandbox: {
268
- docker: docker2,
269
- container: docker2.getContainer(ci.Id),
270
- containerId: ci.Id,
271
- image: ci.Image,
272
- createdAt: new Date(ci.Created * 1e3)
273
- },
244
+ sandbox: { docker: docker2, container: docker2.getContainer(ci.Id), containerId: ci.Id, image: ci.Image, createdAt: new Date(ci.Created * 1e3) },
274
245
  sandboxId: ci.Id
275
246
  }));
276
247
  } catch {
@@ -289,15 +260,10 @@ var docker = (0, import_provider.defineProvider)({
289
260
  } catch {
290
261
  }
291
262
  },
292
- runCommand: async (handle, command, options) => {
263
+ runCommand: async (handle, command, _options) => {
293
264
  const start = Date.now();
294
265
  const { stdout, stderr, exitCode } = await runExec(handle, command);
295
- return {
296
- stdout,
297
- stderr,
298
- exitCode,
299
- durationMs: Date.now() - start
300
- };
266
+ return { stdout, stderr, exitCode, durationMs: Date.now() - start };
301
267
  },
302
268
  getInfo: async (handle) => {
303
269
  const info = await handle.container.inspect();
@@ -305,13 +271,13 @@ var docker = (0, import_provider.defineProvider)({
305
271
  return {
306
272
  id: handle.containerId,
307
273
  provider: PROVIDER,
308
- runtime: info.Config?.Labels?.[LABEL_RUNTIME] || "python",
309
274
  status: state.Running ? "running" : "stopped",
310
275
  createdAt: new Date(info.Created || handle.createdAt),
311
276
  timeout: 3e5,
312
277
  metadata: {
313
278
  image: info.Config?.Image,
314
- name: info.Name
279
+ name: info.Name,
280
+ runtime: info.Config?.Labels?.[LABEL_RUNTIME]
315
281
  }
316
282
  };
317
283
  },
@@ -349,10 +315,7 @@ var docker = (0, import_provider.defineProvider)({
349
315
  if (exitCode !== 0) throw new Error(stderr || `Failed to mkdir: ${path}`);
350
316
  },
351
317
  readdir: async (handle, path) => {
352
- const { stdout, exitCode, stderr } = await runExec(
353
- handle,
354
- `if [ -d ${JSON.stringify(path)} ]; then ls -la ${JSON.stringify(path)}; else exit 1; fi`
355
- );
318
+ const { stdout, exitCode, stderr } = await runExec(handle, `if [ -d ${JSON.stringify(path)} ]; then ls -la ${JSON.stringify(path)}; else exit 1; fi`);
356
319
  if (exitCode !== 0) throw new Error(stderr || `Not a directory: ${path}`);
357
320
  const lines = stdout.split("\n").slice(1);
358
321
  const entries = [];
@@ -361,14 +324,7 @@ var docker = (0, import_provider.defineProvider)({
361
324
  if (parts.length < 9) continue;
362
325
  const name = parts.slice(8).join(" ");
363
326
  if (name === "." || name === "..") continue;
364
- const isDir = parts[0].startsWith("d");
365
- const size = Number(parts[4]) || 0;
366
- entries.push({
367
- name,
368
- type: isDir ? "directory" : "file",
369
- size,
370
- modified: /* @__PURE__ */ new Date()
371
- });
327
+ entries.push({ name, type: parts[0].startsWith("d") ? "directory" : "file", size: Number(parts[4]) || 0, modified: /* @__PURE__ */ new Date() });
372
328
  }
373
329
  return entries;
374
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 // 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 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","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"]}
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
- const exitCode = inspect.ExitCode ?? 0;
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
- const u = new URL(hostEnv);
121
- return u.hostname || "localhost";
116
+ return new URL(hostEnv).hostname || "localhost";
122
117
  } catch {
123
118
  }
124
119
  }
@@ -155,8 +150,6 @@ var docker = defineProvider({
155
150
  Tty: pick(cfg.container?.tty, false),
156
151
  OpenStdin: pick(cfg.container?.openStdin, false),
157
152
  Labels: {
158
- // User metadata is spread first with a namespaced prefix so it
159
- // cannot overwrite the reserved discovery/runtime labels below.
160
153
  ...options?.metadata ? Object.fromEntries(
161
154
  Object.entries(options.metadata).map(([k, v]) => [`com.computesdk.meta.${k}`, typeof v === "string" ? v : JSON.stringify(v)])
162
155
  ) : {},
@@ -166,10 +159,8 @@ var docker = defineProvider({
166
159
  WorkingDir: cfg.container?.workdir,
167
160
  Env: Object.keys(mergedEnv).length > 0 ? Object.entries(mergedEnv).map(([k, v]) => `${k}=${v}`) : void 0,
168
161
  Cmd: KEEPALIVE_CMD,
169
- // keep container alive
170
162
  HostConfig: {
171
163
  AutoRemove: cfg.container?.autoRemove ?? false,
172
- // keep around for exec/FS ops
173
164
  Binds: cfg.container?.binds,
174
165
  NetworkMode: cfg.container?.networkMode,
175
166
  Privileged: cfg.container?.privileged,
@@ -177,14 +168,12 @@ var docker = defineProvider({
177
168
  CapDrop: cfg.container?.capabilities?.drop,
178
169
  LogConfig: cfg.container?.logDriver ? { Type: cfg.container.logDriver, Config: cfg.container.logOpts || {} } : void 0,
179
170
  Resources: cfg.container?.resources,
180
- DeviceRequests: cfg.container?.gpus ? [
181
- {
182
- Driver: "nvidia",
183
- Count: cfg.container.gpus === "all" ? -1 : typeof cfg.container.gpus === "number" ? cfg.container.gpus : 1,
184
- DeviceIDs: typeof cfg.container.gpus === "string" && cfg.container.gpus !== "all" ? [String(cfg.container.gpus)] : void 0,
185
- Capabilities: [["gpu"]]
186
- }
187
- ] : 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,
188
177
  ...hb ? { PortBindings: hb.PortBindings } : {}
189
178
  },
190
179
  ...hb ? { ExposedPorts: hb.ExposedPorts } : {},
@@ -208,16 +197,7 @@ var docker = defineProvider({
208
197
  try {
209
198
  const container = docker2.getContainer(sandboxId);
210
199
  const info = await container.inspect();
211
- return {
212
- sandbox: {
213
- docker: docker2,
214
- container,
215
- containerId: sandboxId,
216
- image: info.Config?.Image ?? "",
217
- createdAt: new Date(info.Created || Date.now())
218
- },
219
- sandboxId
220
- };
200
+ return { sandbox: { docker: docker2, container, containerId: sandboxId, image: info.Config?.Image ?? "", createdAt: new Date(info.Created || Date.now()) }, sandboxId };
221
201
  } catch {
222
202
  return null;
223
203
  }
@@ -225,18 +205,9 @@ var docker = defineProvider({
225
205
  list: async (config) => {
226
206
  const docker2 = new Docker((config || defaultDockerConfig).connection);
227
207
  try {
228
- const items = await docker2.listContainers({
229
- all: true,
230
- filters: { label: [LABEL_KEY] }
231
- });
208
+ const items = await docker2.listContainers({ all: true, filters: { label: [LABEL_KEY] } });
232
209
  return items.map((ci) => ({
233
- sandbox: {
234
- docker: docker2,
235
- container: docker2.getContainer(ci.Id),
236
- containerId: ci.Id,
237
- image: ci.Image,
238
- createdAt: new Date(ci.Created * 1e3)
239
- },
210
+ sandbox: { docker: docker2, container: docker2.getContainer(ci.Id), containerId: ci.Id, image: ci.Image, createdAt: new Date(ci.Created * 1e3) },
240
211
  sandboxId: ci.Id
241
212
  }));
242
213
  } catch {
@@ -255,15 +226,10 @@ var docker = defineProvider({
255
226
  } catch {
256
227
  }
257
228
  },
258
- runCommand: async (handle, command, options) => {
229
+ runCommand: async (handle, command, _options) => {
259
230
  const start = Date.now();
260
231
  const { stdout, stderr, exitCode } = await runExec(handle, command);
261
- return {
262
- stdout,
263
- stderr,
264
- exitCode,
265
- durationMs: Date.now() - start
266
- };
232
+ return { stdout, stderr, exitCode, durationMs: Date.now() - start };
267
233
  },
268
234
  getInfo: async (handle) => {
269
235
  const info = await handle.container.inspect();
@@ -271,13 +237,13 @@ var docker = defineProvider({
271
237
  return {
272
238
  id: handle.containerId,
273
239
  provider: PROVIDER,
274
- runtime: info.Config?.Labels?.[LABEL_RUNTIME] || "python",
275
240
  status: state.Running ? "running" : "stopped",
276
241
  createdAt: new Date(info.Created || handle.createdAt),
277
242
  timeout: 3e5,
278
243
  metadata: {
279
244
  image: info.Config?.Image,
280
- name: info.Name
245
+ name: info.Name,
246
+ runtime: info.Config?.Labels?.[LABEL_RUNTIME]
281
247
  }
282
248
  };
283
249
  },
@@ -315,10 +281,7 @@ var docker = defineProvider({
315
281
  if (exitCode !== 0) throw new Error(stderr || `Failed to mkdir: ${path}`);
316
282
  },
317
283
  readdir: async (handle, path) => {
318
- const { stdout, exitCode, stderr } = await runExec(
319
- handle,
320
- `if [ -d ${JSON.stringify(path)} ]; then ls -la ${JSON.stringify(path)}; else exit 1; fi`
321
- );
284
+ const { stdout, exitCode, stderr } = await runExec(handle, `if [ -d ${JSON.stringify(path)} ]; then ls -la ${JSON.stringify(path)}; else exit 1; fi`);
322
285
  if (exitCode !== 0) throw new Error(stderr || `Not a directory: ${path}`);
323
286
  const lines = stdout.split("\n").slice(1);
324
287
  const entries = [];
@@ -327,14 +290,7 @@ var docker = defineProvider({
327
290
  if (parts.length < 9) continue;
328
291
  const name = parts.slice(8).join(" ");
329
292
  if (name === "." || name === "..") continue;
330
- const isDir = parts[0].startsWith("d");
331
- const size = Number(parts[4]) || 0;
332
- entries.push({
333
- name,
334
- type: isDir ? "directory" : "file",
335
- size,
336
- modified: /* @__PURE__ */ new Date()
337
- });
293
+ entries.push({ name, type: parts[0].startsWith("d") ? "directory" : "file", size: Number(parts[4]) || 0, modified: /* @__PURE__ */ new Date() });
338
294
  }
339
295
  return entries;
340
296
  },
@@ -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 // 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 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","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"]}
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.44",
3
+ "version": "1.2.46",
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": "1.4.0",
23
- "computesdk": "3.0.0"
22
+ "@computesdk/provider": "2.1.0",
23
+ "computesdk": "4.1.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": "1.6.1"
56
+ "@computesdk/test-utils": "2.0.0"
57
57
  },
58
58
  "scripts": {
59
59
  "build": "tsup",