@computesdk/docker 1.0.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/LICENSE +21 -0
- package/README.md +349 -0
- package/dist/index.d.mts +120 -0
- package/dist/index.d.ts +120 -0
- package/dist/index.js +470 -0
- package/dist/index.js.map +1 -0
- package/dist/index.mjs +434 -0
- package/dist/index.mjs.map +1 -0
- package/package.json +62 -0
package/LICENSE
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2025 computesdk
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
+
in the Software without restriction, including without limitation the rights
|
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
+
furnished to do so, subject to the following conditions:
|
|
11
|
+
|
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
|
13
|
+
copies or substantial portions of the Software.
|
|
14
|
+
|
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
21
|
+
SOFTWARE.
|
package/README.md
ADDED
|
@@ -0,0 +1,349 @@
|
|
|
1
|
+
# @computesdk/docker
|
|
2
|
+
|
|
3
|
+
A Docker-based provider for [ComputeSDK](https://github.com/computesdk/computesdk) that launches lightweight, configurable containers (Python or Node.js), runs code and shell commands, and offers simple filesystem helpers — all behind a clean, provider-agnostic interface.
|
|
4
|
+
|
|
5
|
+
---
|
|
6
|
+
|
|
7
|
+
## Installation
|
|
8
|
+
|
|
9
|
+
```bash
|
|
10
|
+
# like the other computesdk providers — single package
|
|
11
|
+
pnpm add @computesdk/docker
|
|
12
|
+
# or
|
|
13
|
+
npm i @computesdk/docker
|
|
14
|
+
# or
|
|
15
|
+
yarn add @computesdk/docker
|
|
16
|
+
```
|
|
17
|
+
|
|
18
|
+
> You **do** need a working Docker Engine/Daemon on the host where this runs.
|
|
19
|
+
|
|
20
|
+
---
|
|
21
|
+
|
|
22
|
+
## Setup
|
|
23
|
+
|
|
24
|
+
Nothing special beyond Docker. The provider talks to Docker through `dockerode`, which autodetects your connection from env or the default socket.
|
|
25
|
+
|
|
26
|
+
Common environment variables (used by Docker/dockerode):
|
|
27
|
+
|
|
28
|
+
* `DOCKER_HOST` — e.g. `unix:///var/run/docker.sock` (Linux/macOS) or `tcp://127.0.0.1:2375`
|
|
29
|
+
* `DOCKER_TLS_VERIFY`, `DOCKER_CERT_PATH` — for TLS-secured TCP
|
|
30
|
+
* `HTTP_PROXY`, `HTTPS_PROXY`, `NO_PROXY` — for pulls behind a proxy
|
|
31
|
+
|
|
32
|
+
> On Linux, ensure your user can access Docker: `sudo usermod -aG docker $USER` then re-login, or run with `sudo`.
|
|
33
|
+
|
|
34
|
+
---
|
|
35
|
+
|
|
36
|
+
## Usage
|
|
37
|
+
|
|
38
|
+
You can use the provider directly or via the ComputeSDK singleton.
|
|
39
|
+
|
|
40
|
+
### With ComputeSDK
|
|
41
|
+
|
|
42
|
+
```ts
|
|
43
|
+
import { createCompute } from 'computesdk';
|
|
44
|
+
import { docker } from '@computesdk/docker';
|
|
45
|
+
|
|
46
|
+
const provider = docker({
|
|
47
|
+
runtime: 'python', // or 'node'
|
|
48
|
+
image: { name: 'python:3.11-slim', pullPolicy: 'ifNotPresent' },
|
|
49
|
+
});
|
|
50
|
+
|
|
51
|
+
const compute = createCompute({ defaultProvider: provider });
|
|
52
|
+
|
|
53
|
+
// Create a sandbox and run Python
|
|
54
|
+
const py = await compute.sandbox.create();
|
|
55
|
+
const out = await py.runCode(`print("Hello from Python")`, 'python');
|
|
56
|
+
console.log(out.stdout.trim()); // Hello from Python
|
|
57
|
+
|
|
58
|
+
await py.destroy();
|
|
59
|
+
```
|
|
60
|
+
|
|
61
|
+
### Direct Usage
|
|
62
|
+
|
|
63
|
+
```ts
|
|
64
|
+
import { docker } from '@computesdk/docker';
|
|
65
|
+
|
|
66
|
+
const provider = docker({
|
|
67
|
+
runtime: 'node',
|
|
68
|
+
image: { name: 'node:20-alpine' },
|
|
69
|
+
container: {
|
|
70
|
+
workdir: '/workspace',
|
|
71
|
+
env: { FOO: 'bar' },
|
|
72
|
+
},
|
|
73
|
+
});
|
|
74
|
+
|
|
75
|
+
const sb = await provider.sandbox.create({ runtime: 'node' });
|
|
76
|
+
|
|
77
|
+
const res = await sb.runCode(`console.log("Hello, World!")`, 'node');
|
|
78
|
+
console.log(res.stdout.trim()); // Hello, World!
|
|
79
|
+
|
|
80
|
+
const ls = await sb.runCommand('sh', ['-lc', 'echo Hello from command']);
|
|
81
|
+
console.log(ls.stdout.trim()); // Hello from command
|
|
82
|
+
|
|
83
|
+
await sb.destroy();
|
|
84
|
+
```
|
|
85
|
+
|
|
86
|
+
---
|
|
87
|
+
|
|
88
|
+
## Configuration
|
|
89
|
+
|
|
90
|
+
Type: `DockerConfig`
|
|
91
|
+
|
|
92
|
+
```ts
|
|
93
|
+
{
|
|
94
|
+
// dockerode connection; if omitted, dockerode uses DOCKER_HOST or /var/run/docker.sock
|
|
95
|
+
connection?: import('dockerode').DockerOptions;
|
|
96
|
+
|
|
97
|
+
// default runtime; must be 'python' or 'node'
|
|
98
|
+
runtime?: 'python' | 'node';
|
|
99
|
+
|
|
100
|
+
// provider-side execution timeout (ms)
|
|
101
|
+
timeout?: number;
|
|
102
|
+
|
|
103
|
+
// image to use for containers
|
|
104
|
+
image: {
|
|
105
|
+
name: string; // e.g. 'python:3.11-slim' or 'node:20-alpine'
|
|
106
|
+
pullPolicy?: 'always' | 'ifNotPresent' | 'never';
|
|
107
|
+
auth?: { username?: string; password?: string; serveraddress?: string; identitytoken?: string; registrytoken?: string; };
|
|
108
|
+
};
|
|
109
|
+
|
|
110
|
+
// container defaults
|
|
111
|
+
container?: {
|
|
112
|
+
user?: string;
|
|
113
|
+
workdir?: string;
|
|
114
|
+
env?: Record<string, string>;
|
|
115
|
+
binds?: string[]; // ['/host:/container:ro']
|
|
116
|
+
ports?: Record<`${number}/${'tcp'|'udp'}`, Array<{ hostPort?: number; hostIP?: string }>>;
|
|
117
|
+
networkMode?: string; // 'bridge', 'host', custom
|
|
118
|
+
privileged?: boolean;
|
|
119
|
+
capabilities?: { add?: string[]; drop?: string[] };
|
|
120
|
+
gpus?: 'all' | number | string; // requires NVIDIA runtime/drivers
|
|
121
|
+
resources?: { memory?: number; nanoCPUs?: number; cpuShares?: number; /* … */ };
|
|
122
|
+
logDriver?: string;
|
|
123
|
+
logOpts?: Record<string, string>;
|
|
124
|
+
autoRemove?: boolean; // default true
|
|
125
|
+
tty?: boolean;
|
|
126
|
+
openStdin?: boolean;
|
|
127
|
+
};
|
|
128
|
+
|
|
129
|
+
// raw passthrough if you need full control
|
|
130
|
+
createOptions?: import('dockerode').ContainerCreateOptions;
|
|
131
|
+
startOptions?: import('dockerode').ContainerStartOptions;
|
|
132
|
+
|
|
133
|
+
cleanup?: 'always' | 'onSuccess' | 'never';
|
|
134
|
+
streamLogs?: boolean;
|
|
135
|
+
}
|
|
136
|
+
```
|
|
137
|
+
|
|
138
|
+
**Defaults (excerpt):**
|
|
139
|
+
|
|
140
|
+
```ts
|
|
141
|
+
{
|
|
142
|
+
runtime: 'python',
|
|
143
|
+
image: { name: 'python:3.11-slim', pullPolicy: 'ifNotPresent' },
|
|
144
|
+
container: {
|
|
145
|
+
workdir: '/workspace',
|
|
146
|
+
env: {},
|
|
147
|
+
autoRemove: true,
|
|
148
|
+
tty: false,
|
|
149
|
+
openStdin: false,
|
|
150
|
+
resources: { memory: 512 * 1024 * 1024 },
|
|
151
|
+
},
|
|
152
|
+
}
|
|
153
|
+
```
|
|
154
|
+
|
|
155
|
+
### Environment Variables
|
|
156
|
+
|
|
157
|
+
* Docker connection variables from **Setup**
|
|
158
|
+
* Your workload envs via `container.env` (injected into the container)
|
|
159
|
+
|
|
160
|
+
---
|
|
161
|
+
|
|
162
|
+
## Features
|
|
163
|
+
|
|
164
|
+
* **Python** and **Node.js** runtimes
|
|
165
|
+
* **Code execution** with syntax-error surfacing
|
|
166
|
+
* **Shell commands** (foreground & background with PID)
|
|
167
|
+
* **Filesystem helpers**: `readFile`, `writeFile`, `mkdir`, `readdir`, `exists`, `remove`
|
|
168
|
+
* **Port URL resolution**: `getUrl({ port })` → host URL if published
|
|
169
|
+
* **Typed access**: `getInstance()` returns the dockerode `Container` and client
|
|
170
|
+
* **Image pull policy**: `always | ifNotPresent | never` (+ registry auth)
|
|
171
|
+
|
|
172
|
+
---
|
|
173
|
+
|
|
174
|
+
## API Reference
|
|
175
|
+
|
|
176
|
+
### Code Execution
|
|
177
|
+
|
|
178
|
+
```ts
|
|
179
|
+
sandbox.runCode(code: string, runtime?: 'python' | 'node'): Promise<ExecutionResult>
|
|
180
|
+
```
|
|
181
|
+
|
|
182
|
+
* If `runtime` omitted, the sandbox’s runtime (set at creation) is used.
|
|
183
|
+
* Returns `{ stdout, stderr, exitCode, executionTime, sandboxId, provider }`
|
|
184
|
+
* Syntax errors are **thrown** as `Error("Syntax error: …")`.
|
|
185
|
+
|
|
186
|
+
### Command Execution
|
|
187
|
+
|
|
188
|
+
```ts
|
|
189
|
+
sandbox.runCommand(command: string, args?: string[], options?: { background?: boolean }): Promise<ExecutionResult>
|
|
190
|
+
```
|
|
191
|
+
|
|
192
|
+
* Runs via `/bin/sh -c "…"` with stdout/stderr capture.
|
|
193
|
+
* Background returns `{ isBackground: true, pid?: number }`.
|
|
194
|
+
|
|
195
|
+
### Filesystem Operations
|
|
196
|
+
|
|
197
|
+
```ts
|
|
198
|
+
sandbox.filesystem.readFile(path)
|
|
199
|
+
sandbox.filesystem.writeFile(path, content)
|
|
200
|
+
sandbox.filesystem.mkdir(path)
|
|
201
|
+
sandbox.filesystem.readdir(path)
|
|
202
|
+
sandbox.filesystem.exists(path)
|
|
203
|
+
sandbox.filesystem.remove(path)
|
|
204
|
+
```
|
|
205
|
+
|
|
206
|
+
> Implemented via shell + base64 for portability.
|
|
207
|
+
|
|
208
|
+
### Terminal Operations
|
|
209
|
+
|
|
210
|
+
Interactive terminals aren’t exposed. Use `runCommand('sh', ['-lc', '…'])` for non-interactive sessions.
|
|
211
|
+
|
|
212
|
+
### Sandbox Management
|
|
213
|
+
|
|
214
|
+
```ts
|
|
215
|
+
const sb = await provider.sandbox.create({ runtime?: 'python' | 'node' });
|
|
216
|
+
await provider.sandbox.destroy(sb.sandboxId);
|
|
217
|
+
|
|
218
|
+
await sb.getInfo(); // { id, provider, runtime, status, createdAt, timeout, metadata }
|
|
219
|
+
await sb.getUrl({ port, protocol?: 'http' | 'https' });
|
|
220
|
+
sb.getInstance(); // { docker: Docker, container: Container, ... }
|
|
221
|
+
```
|
|
222
|
+
|
|
223
|
+
---
|
|
224
|
+
|
|
225
|
+
## Runtime Detection
|
|
226
|
+
|
|
227
|
+
There’s **no auto-detection**. Resolution is:
|
|
228
|
+
|
|
229
|
+
1. `runCode(_, runtime)` argument, else
|
|
230
|
+
2. runtime label set at `sandbox.create()` (from `options.runtime` or provider `config.runtime`)
|
|
231
|
+
|
|
232
|
+
If neither yields `'python' | 'node'`, `runCode` throws.
|
|
233
|
+
|
|
234
|
+
---
|
|
235
|
+
|
|
236
|
+
## Error Handling
|
|
237
|
+
|
|
238
|
+
* **Syntax errors** → **thrown** (`Error("Syntax error: …")`)
|
|
239
|
+
* **Runtime/command errors** → returned as non-zero `exitCode` with `stderr`
|
|
240
|
+
* **Docker errors** (pull/start/exec) → **thrown**
|
|
241
|
+
|
|
242
|
+
```ts
|
|
243
|
+
const res = await sb.runCommand('sh', ['-lc', 'bad-command']);
|
|
244
|
+
if (res.exitCode !== 0) {
|
|
245
|
+
console.error('stderr:', res.stderr);
|
|
246
|
+
}
|
|
247
|
+
```
|
|
248
|
+
|
|
249
|
+
---
|
|
250
|
+
|
|
251
|
+
## Web Framework Integration
|
|
252
|
+
|
|
253
|
+
```ts
|
|
254
|
+
import { handleComputeRequest } from 'computesdk';
|
|
255
|
+
import { docker } from '@computesdk/docker';
|
|
256
|
+
|
|
257
|
+
const provider = docker({
|
|
258
|
+
runtime: 'node',
|
|
259
|
+
image: { name: 'node:20-alpine' },
|
|
260
|
+
});
|
|
261
|
+
|
|
262
|
+
export async function POST(req: Request) {
|
|
263
|
+
const body = await req.json(); // ComputeRequest
|
|
264
|
+
return handleComputeRequest(body, provider);
|
|
265
|
+
}
|
|
266
|
+
```
|
|
267
|
+
|
|
268
|
+
---
|
|
269
|
+
|
|
270
|
+
## Examples
|
|
271
|
+
|
|
272
|
+
### Data Science Workflow (Python)
|
|
273
|
+
|
|
274
|
+
```ts
|
|
275
|
+
const py = await provider.sandbox.create({ runtime: 'python' });
|
|
276
|
+
await py.runCommand('sh', ['-lc', 'python3 -m pip install --no-cache-dir pandas']);
|
|
277
|
+
await py.filesystem.writeFile('/workspace/app.py', `
|
|
278
|
+
import pandas as pd
|
|
279
|
+
print("rows:", len(pd.DataFrame({"x":[1,2,3]})))
|
|
280
|
+
`);
|
|
281
|
+
const run = await py.runCommand('sh', ['-lc', 'python3 /workspace/app.py']);
|
|
282
|
+
console.log(run.stdout.trim()); // rows: 3
|
|
283
|
+
await py.destroy();
|
|
284
|
+
```
|
|
285
|
+
|
|
286
|
+
### Interactive-like Loop
|
|
287
|
+
|
|
288
|
+
```ts
|
|
289
|
+
const sb = await provider.sandbox.create({ runtime: 'node' });
|
|
290
|
+
await sb.runCommand('sh', ['-lc', 'echo boot > /tmp/state']);
|
|
291
|
+
await sb.runCommand('sh', ['-lc', 'cat /tmp/state']); // 'boot'
|
|
292
|
+
await sb.destroy();
|
|
293
|
+
```
|
|
294
|
+
|
|
295
|
+
### Machine Learning Pipeline (Python + Ports)
|
|
296
|
+
|
|
297
|
+
```ts
|
|
298
|
+
const sb = await provider.sandbox.create({ runtime: 'python' });
|
|
299
|
+
const bg = await sb.runCommand('sh', ['-lc', 'python3 -m http.server 8080'], { background: true });
|
|
300
|
+
const url = await sb.getUrl({ port: 8080 });
|
|
301
|
+
console.log('Serving at', url);
|
|
302
|
+
await sb.destroy();
|
|
303
|
+
```
|
|
304
|
+
|
|
305
|
+
> To make ports reachable from the host, publish them up front:
|
|
306
|
+
>
|
|
307
|
+
> ```ts
|
|
308
|
+
> const provider = docker({
|
|
309
|
+
> runtime: 'python',
|
|
310
|
+
> image: { name: 'python:3.11-slim' },
|
|
311
|
+
> container: {
|
|
312
|
+
> ports: { '8080/tcp': [{ hostPort: 8080, hostIP: '127.0.0.1' }] },
|
|
313
|
+
> },
|
|
314
|
+
> });
|
|
315
|
+
> ```
|
|
316
|
+
|
|
317
|
+
---
|
|
318
|
+
|
|
319
|
+
## Best Practices
|
|
320
|
+
|
|
321
|
+
* Pre-pull images in CI: `docker pull python:3.11-slim node:20-alpine`
|
|
322
|
+
* Pin image versions; avoid `latest`
|
|
323
|
+
* Set `container.resources` to bound CPU/RAM
|
|
324
|
+
* Use `/workspace` and keep temp files in `/tmp`
|
|
325
|
+
* Publish ports you intend to access via `getUrl()`
|
|
326
|
+
* Prefer non-root `user` and drop unnecessary capabilities
|
|
327
|
+
* For GPU work: `gpus: 'all'` and ensure NVIDIA runtime/drivers
|
|
328
|
+
|
|
329
|
+
---
|
|
330
|
+
|
|
331
|
+
## Limitations
|
|
332
|
+
|
|
333
|
+
* Requires a local or reachable Docker daemon
|
|
334
|
+
* No WebSocket terminal (non-interactive only)
|
|
335
|
+
* Snapshots/templates not implemented in this provider
|
|
336
|
+
* `getUrl()` returns a host URL only for published ports or reachable container IPs
|
|
337
|
+
|
|
338
|
+
---
|
|
339
|
+
|
|
340
|
+
## Support
|
|
341
|
+
|
|
342
|
+
* Issues/PRs: [https://github.com/computesdk/computesdk](https://github.com/computesdk/computesdk)
|
|
343
|
+
* Open issues with title prefix **\[docker provider]**
|
|
344
|
+
|
|
345
|
+
---
|
|
346
|
+
|
|
347
|
+
## License
|
|
348
|
+
|
|
349
|
+
MIT
|
package/dist/index.d.mts
ADDED
|
@@ -0,0 +1,120 @@
|
|
|
1
|
+
import * as computesdk from 'computesdk';
|
|
2
|
+
import { Runtime, CreateSandboxOptions, ExecutionResult, RunCommandOptions, SandboxInfo, FileEntry } from 'computesdk';
|
|
3
|
+
import Docker, { DockerOptions, ContainerCreateOptions, ContainerStartOptions, Container } from 'dockerode';
|
|
4
|
+
|
|
5
|
+
/** When the provider should clean up containers it created */
|
|
6
|
+
type CleanupPolicy = 'always' | 'onSuccess' | 'never';
|
|
7
|
+
/** Image pull strategy */
|
|
8
|
+
type PullPolicy = 'always' | 'ifNotPresent' | 'never';
|
|
9
|
+
/** Connection to the Docker daemon (exactly what dockerode accepts) */
|
|
10
|
+
type DockerConnection = DockerOptions;
|
|
11
|
+
/** Auth when pulling private images (Engine API AuthConfig shape) */
|
|
12
|
+
interface RegistryAuth {
|
|
13
|
+
username?: string;
|
|
14
|
+
password?: string;
|
|
15
|
+
serveraddress?: string;
|
|
16
|
+
identitytoken?: string;
|
|
17
|
+
registrytoken?: string;
|
|
18
|
+
}
|
|
19
|
+
/** Default image & pull policy for sandboxes */
|
|
20
|
+
interface DockerImage {
|
|
21
|
+
name: string;
|
|
22
|
+
pullPolicy?: PullPolicy;
|
|
23
|
+
auth?: RegistryAuth;
|
|
24
|
+
}
|
|
25
|
+
/** Convenience shape for port bindings */
|
|
26
|
+
type PortBindings = Record<`${number}/${'tcp' | 'udp'}`, Array<{
|
|
27
|
+
hostPort?: number;
|
|
28
|
+
hostIP?: string;
|
|
29
|
+
}>>;
|
|
30
|
+
/** Subset of HostConfig resources & knobs that are commonly used */
|
|
31
|
+
interface ResourceLimits {
|
|
32
|
+
cpuShares?: number;
|
|
33
|
+
cpuQuota?: number;
|
|
34
|
+
cpuPeriod?: number;
|
|
35
|
+
nanoCPUs?: number;
|
|
36
|
+
memory?: number;
|
|
37
|
+
memorySwap?: number;
|
|
38
|
+
pidsLimit?: number;
|
|
39
|
+
}
|
|
40
|
+
/** Declarative container defaults that we’ll translate into dockerode create options */
|
|
41
|
+
interface ContainerDefaults {
|
|
42
|
+
user?: string;
|
|
43
|
+
workdir?: string;
|
|
44
|
+
env?: Record<string, string>;
|
|
45
|
+
binds?: string[];
|
|
46
|
+
ports?: PortBindings;
|
|
47
|
+
networkMode?: string;
|
|
48
|
+
privileged?: boolean;
|
|
49
|
+
capabilities?: {
|
|
50
|
+
add?: string[];
|
|
51
|
+
drop?: string[];
|
|
52
|
+
};
|
|
53
|
+
gpus?: 'all' | number | string;
|
|
54
|
+
resources?: ResourceLimits;
|
|
55
|
+
logDriver?: string;
|
|
56
|
+
logOpts?: Record<string, string>;
|
|
57
|
+
autoRemove?: boolean;
|
|
58
|
+
tty?: boolean;
|
|
59
|
+
openStdin?: boolean;
|
|
60
|
+
}
|
|
61
|
+
/** Provider-level configuration for Docker */
|
|
62
|
+
interface DockerConfig {
|
|
63
|
+
connection?: DockerConnection;
|
|
64
|
+
runtime?: Runtime;
|
|
65
|
+
timeout?: number;
|
|
66
|
+
image: DockerImage;
|
|
67
|
+
container?: ContainerDefaults;
|
|
68
|
+
createOptions?: ContainerCreateOptions;
|
|
69
|
+
startOptions?: ContainerStartOptions;
|
|
70
|
+
cleanup?: CleanupPolicy;
|
|
71
|
+
streamLogs?: boolean;
|
|
72
|
+
}
|
|
73
|
+
/** What we keep for each running sandbox */
|
|
74
|
+
interface DockerSandboxHandle {
|
|
75
|
+
docker: Docker;
|
|
76
|
+
container: Container;
|
|
77
|
+
containerId: string;
|
|
78
|
+
image: string;
|
|
79
|
+
createdAt: Date;
|
|
80
|
+
}
|
|
81
|
+
/** URL options for port-forwarded services */
|
|
82
|
+
interface DockerUrlOptions {
|
|
83
|
+
port: number;
|
|
84
|
+
protocol?: 'http' | 'https';
|
|
85
|
+
host?: string;
|
|
86
|
+
}
|
|
87
|
+
/** Optional FS helpers you might expose */
|
|
88
|
+
interface DockerSandboxFileSystem {
|
|
89
|
+
readFile(path: string): Promise<string>;
|
|
90
|
+
writeFile(path: string, content: string): Promise<void>;
|
|
91
|
+
mkdir(path: string): Promise<void>;
|
|
92
|
+
readdir(path: string): Promise<FileEntry[]>;
|
|
93
|
+
exists(path: string): Promise<boolean>;
|
|
94
|
+
remove(path: string): Promise<void>;
|
|
95
|
+
}
|
|
96
|
+
/** Strongly-typed sandbox API shape */
|
|
97
|
+
interface DockerSandboxAPI {
|
|
98
|
+
sandboxId: string;
|
|
99
|
+
provider: 'docker';
|
|
100
|
+
runCode(code: string, runtime?: Runtime): Promise<ExecutionResult>;
|
|
101
|
+
runCommand(command: string, args?: string[], options?: RunCommandOptions): Promise<ExecutionResult>;
|
|
102
|
+
getInfo(): Promise<SandboxInfo>;
|
|
103
|
+
getUrl(options: DockerUrlOptions): Promise<string>;
|
|
104
|
+
getProvider(): any;
|
|
105
|
+
getInstance(): DockerSandboxHandle;
|
|
106
|
+
kill(): Promise<void>;
|
|
107
|
+
destroy(): Promise<void>;
|
|
108
|
+
filesystem: DockerSandboxFileSystem;
|
|
109
|
+
}
|
|
110
|
+
/** Factory return shape mirroring your createE2BCompute helper */
|
|
111
|
+
interface CreateDockerCompute {
|
|
112
|
+
sandbox: {
|
|
113
|
+
create(options?: CreateSandboxOptions): Promise<DockerSandboxAPI>;
|
|
114
|
+
};
|
|
115
|
+
}
|
|
116
|
+
|
|
117
|
+
declare const docker: (config: DockerConfig) => computesdk.Provider<DockerSandboxHandle, any, any>;
|
|
118
|
+
declare function createDockerCompute(config: DockerConfig): CreateDockerCompute;
|
|
119
|
+
|
|
120
|
+
export { createDockerCompute, docker };
|
package/dist/index.d.ts
ADDED
|
@@ -0,0 +1,120 @@
|
|
|
1
|
+
import * as computesdk from 'computesdk';
|
|
2
|
+
import { Runtime, CreateSandboxOptions, ExecutionResult, RunCommandOptions, SandboxInfo, FileEntry } from 'computesdk';
|
|
3
|
+
import Docker, { DockerOptions, ContainerCreateOptions, ContainerStartOptions, Container } from 'dockerode';
|
|
4
|
+
|
|
5
|
+
/** When the provider should clean up containers it created */
|
|
6
|
+
type CleanupPolicy = 'always' | 'onSuccess' | 'never';
|
|
7
|
+
/** Image pull strategy */
|
|
8
|
+
type PullPolicy = 'always' | 'ifNotPresent' | 'never';
|
|
9
|
+
/** Connection to the Docker daemon (exactly what dockerode accepts) */
|
|
10
|
+
type DockerConnection = DockerOptions;
|
|
11
|
+
/** Auth when pulling private images (Engine API AuthConfig shape) */
|
|
12
|
+
interface RegistryAuth {
|
|
13
|
+
username?: string;
|
|
14
|
+
password?: string;
|
|
15
|
+
serveraddress?: string;
|
|
16
|
+
identitytoken?: string;
|
|
17
|
+
registrytoken?: string;
|
|
18
|
+
}
|
|
19
|
+
/** Default image & pull policy for sandboxes */
|
|
20
|
+
interface DockerImage {
|
|
21
|
+
name: string;
|
|
22
|
+
pullPolicy?: PullPolicy;
|
|
23
|
+
auth?: RegistryAuth;
|
|
24
|
+
}
|
|
25
|
+
/** Convenience shape for port bindings */
|
|
26
|
+
type PortBindings = Record<`${number}/${'tcp' | 'udp'}`, Array<{
|
|
27
|
+
hostPort?: number;
|
|
28
|
+
hostIP?: string;
|
|
29
|
+
}>>;
|
|
30
|
+
/** Subset of HostConfig resources & knobs that are commonly used */
|
|
31
|
+
interface ResourceLimits {
|
|
32
|
+
cpuShares?: number;
|
|
33
|
+
cpuQuota?: number;
|
|
34
|
+
cpuPeriod?: number;
|
|
35
|
+
nanoCPUs?: number;
|
|
36
|
+
memory?: number;
|
|
37
|
+
memorySwap?: number;
|
|
38
|
+
pidsLimit?: number;
|
|
39
|
+
}
|
|
40
|
+
/** Declarative container defaults that we’ll translate into dockerode create options */
|
|
41
|
+
interface ContainerDefaults {
|
|
42
|
+
user?: string;
|
|
43
|
+
workdir?: string;
|
|
44
|
+
env?: Record<string, string>;
|
|
45
|
+
binds?: string[];
|
|
46
|
+
ports?: PortBindings;
|
|
47
|
+
networkMode?: string;
|
|
48
|
+
privileged?: boolean;
|
|
49
|
+
capabilities?: {
|
|
50
|
+
add?: string[];
|
|
51
|
+
drop?: string[];
|
|
52
|
+
};
|
|
53
|
+
gpus?: 'all' | number | string;
|
|
54
|
+
resources?: ResourceLimits;
|
|
55
|
+
logDriver?: string;
|
|
56
|
+
logOpts?: Record<string, string>;
|
|
57
|
+
autoRemove?: boolean;
|
|
58
|
+
tty?: boolean;
|
|
59
|
+
openStdin?: boolean;
|
|
60
|
+
}
|
|
61
|
+
/** Provider-level configuration for Docker */
|
|
62
|
+
interface DockerConfig {
|
|
63
|
+
connection?: DockerConnection;
|
|
64
|
+
runtime?: Runtime;
|
|
65
|
+
timeout?: number;
|
|
66
|
+
image: DockerImage;
|
|
67
|
+
container?: ContainerDefaults;
|
|
68
|
+
createOptions?: ContainerCreateOptions;
|
|
69
|
+
startOptions?: ContainerStartOptions;
|
|
70
|
+
cleanup?: CleanupPolicy;
|
|
71
|
+
streamLogs?: boolean;
|
|
72
|
+
}
|
|
73
|
+
/** What we keep for each running sandbox */
|
|
74
|
+
interface DockerSandboxHandle {
|
|
75
|
+
docker: Docker;
|
|
76
|
+
container: Container;
|
|
77
|
+
containerId: string;
|
|
78
|
+
image: string;
|
|
79
|
+
createdAt: Date;
|
|
80
|
+
}
|
|
81
|
+
/** URL options for port-forwarded services */
|
|
82
|
+
interface DockerUrlOptions {
|
|
83
|
+
port: number;
|
|
84
|
+
protocol?: 'http' | 'https';
|
|
85
|
+
host?: string;
|
|
86
|
+
}
|
|
87
|
+
/** Optional FS helpers you might expose */
|
|
88
|
+
interface DockerSandboxFileSystem {
|
|
89
|
+
readFile(path: string): Promise<string>;
|
|
90
|
+
writeFile(path: string, content: string): Promise<void>;
|
|
91
|
+
mkdir(path: string): Promise<void>;
|
|
92
|
+
readdir(path: string): Promise<FileEntry[]>;
|
|
93
|
+
exists(path: string): Promise<boolean>;
|
|
94
|
+
remove(path: string): Promise<void>;
|
|
95
|
+
}
|
|
96
|
+
/** Strongly-typed sandbox API shape */
|
|
97
|
+
interface DockerSandboxAPI {
|
|
98
|
+
sandboxId: string;
|
|
99
|
+
provider: 'docker';
|
|
100
|
+
runCode(code: string, runtime?: Runtime): Promise<ExecutionResult>;
|
|
101
|
+
runCommand(command: string, args?: string[], options?: RunCommandOptions): Promise<ExecutionResult>;
|
|
102
|
+
getInfo(): Promise<SandboxInfo>;
|
|
103
|
+
getUrl(options: DockerUrlOptions): Promise<string>;
|
|
104
|
+
getProvider(): any;
|
|
105
|
+
getInstance(): DockerSandboxHandle;
|
|
106
|
+
kill(): Promise<void>;
|
|
107
|
+
destroy(): Promise<void>;
|
|
108
|
+
filesystem: DockerSandboxFileSystem;
|
|
109
|
+
}
|
|
110
|
+
/** Factory return shape mirroring your createE2BCompute helper */
|
|
111
|
+
interface CreateDockerCompute {
|
|
112
|
+
sandbox: {
|
|
113
|
+
create(options?: CreateSandboxOptions): Promise<DockerSandboxAPI>;
|
|
114
|
+
};
|
|
115
|
+
}
|
|
116
|
+
|
|
117
|
+
declare const docker: (config: DockerConfig) => computesdk.Provider<DockerSandboxHandle, any, any>;
|
|
118
|
+
declare function createDockerCompute(config: DockerConfig): CreateDockerCompute;
|
|
119
|
+
|
|
120
|
+
export { createDockerCompute, docker };
|