@arker-ai/sdk 0.5.1 → 0.6.2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +154 -0
- package/dist/arker-provider-BNIL8NdM.d.ts +7 -0
- package/dist/arker-provider-DwUib5ZW.d.cts +7 -0
- package/dist/chunk-35IEV6BU.js +286 -0
- package/dist/{chunk-PI3H3TGC.js → chunk-7BHPVQNG.js} +265 -23
- package/dist/cli.cjs +621 -160
- package/dist/cli.js +356 -137
- package/dist/common-C5zJ-LkS.d.cts +9 -0
- package/dist/common-C5zJ-LkS.d.ts +9 -0
- package/dist/daytona.cjs +1274 -0
- package/dist/daytona.d.cts +37 -0
- package/dist/daytona.d.ts +37 -0
- package/dist/daytona.js +65 -0
- package/dist/e2b.cjs +1288 -0
- package/dist/e2b.d.cts +29 -0
- package/dist/e2b.d.ts +29 -0
- package/dist/e2b.js +75 -0
- package/dist/index.cjs +275 -23
- package/dist/index.d.cts +229 -101
- package/dist/index.d.ts +229 -101
- package/dist/index.js +1 -1
- package/dist/modal.cjs +1356 -0
- package/dist/modal.d.cts +49 -0
- package/dist/modal.d.ts +49 -0
- package/dist/modal.js +130 -0
- package/package.json +30 -4
package/README.md
CHANGED
|
@@ -29,6 +29,27 @@ const data = await vm.sync("/tmp/data.txt"); // read -> Uint8Array
|
|
|
29
29
|
await vm.delete();
|
|
30
30
|
```
|
|
31
31
|
|
|
32
|
+
## Interactive PTY
|
|
33
|
+
|
|
34
|
+
`arker shell` opens a native PTY session over WebSocket. It does not use SSH and
|
|
35
|
+
does not call `/runs` for each line:
|
|
36
|
+
|
|
37
|
+
```bash
|
|
38
|
+
arker shell vm_123
|
|
39
|
+
arker shell vm_123 --session-id sess_123
|
|
40
|
+
```
|
|
41
|
+
|
|
42
|
+
The SDK exposes the same transport:
|
|
43
|
+
|
|
44
|
+
```ts
|
|
45
|
+
const pty = await vm.connectPty({ cols: 120, rows: 32 });
|
|
46
|
+
pty.onData((chunk) => process.stdout.write(chunk));
|
|
47
|
+
await pty.ready;
|
|
48
|
+
pty.send("echo hello\n");
|
|
49
|
+
pty.resize(100, 30);
|
|
50
|
+
pty.close(); // detach; the session is not deleted
|
|
51
|
+
```
|
|
52
|
+
|
|
32
53
|
## Core API
|
|
33
54
|
|
|
34
55
|
```ts
|
|
@@ -41,6 +62,7 @@ await ar.fork({ sourceVmName, sourceOrgId, name?, durable? });
|
|
|
41
62
|
await ar.listVms({ state? });
|
|
42
63
|
ar.vm(vmId); // bare handle
|
|
43
64
|
await ar.vm(vmId).run(command, options?);
|
|
65
|
+
await ar.vm(vmId).connectPty({ sessionId?, cols?, rows?, command?, persist? });
|
|
44
66
|
await ar.vm(vmId).resize({ vcpu_count, memory_mib });
|
|
45
67
|
await ar.vm(vmId).delete();
|
|
46
68
|
|
|
@@ -61,6 +83,42 @@ await vm.deleteSync(syncId);
|
|
|
61
83
|
|
|
62
84
|
`apiKey` falls back to `ARKER_API_KEY`; `region` to `ARKER_REGION`. Pass `baseUrl` for dev targets. Configure retries with `retry: { attempts, baseDelayMs, maxDelayMs }`, or `retry: false` to disable.
|
|
63
85
|
|
|
86
|
+
## Interactive terminal (PTY)
|
|
87
|
+
|
|
88
|
+
Open a real pseudo-terminal in a VM and drive it interactively — stream raw
|
|
89
|
+
terminal bytes out, send keystrokes in (incl. control chars like Ctrl-C),
|
|
90
|
+
resize, and kill. `isatty()` is true inside, so an interactive shell, `vim`,
|
|
91
|
+
`htop`, a language REPL, and `claude` all work. Transport is a TLS WebSocket;
|
|
92
|
+
a key can only attach to its own org's VMs.
|
|
93
|
+
|
|
94
|
+
```ts
|
|
95
|
+
const vm = await ar.fork("ubuntu-full");
|
|
96
|
+
|
|
97
|
+
const pty = await vm.createPty({
|
|
98
|
+
cols: 80,
|
|
99
|
+
rows: 24,
|
|
100
|
+
// command defaults to the login shell. It is a single executable path —
|
|
101
|
+
// the guest does not shell-split, so launch a shell and `sendInput` it.
|
|
102
|
+
onData: (bytes) => process.stdout.write(bytes), // raw output (ANSI/colors)
|
|
103
|
+
});
|
|
104
|
+
|
|
105
|
+
await pty.sendInput(new TextEncoder().encode("ls -la\n"));
|
|
106
|
+
await pty.resize({ cols: 120, rows: 40 }); // a full-screen app reflows
|
|
107
|
+
await pty.kill(); // tears down the shell
|
|
108
|
+
```
|
|
109
|
+
|
|
110
|
+
Wire it into `xterm.js` in a browser (`term.onData → pty.sendInput`,
|
|
111
|
+
`pty onData → term.write`, `term.onResize → pty.resize`), or pipe it to a local
|
|
112
|
+
TTY in a script. Node needs the optional `ws` package (installed by default).
|
|
113
|
+
|
|
114
|
+
The CLI exposes the same thing — `arker pty <vm>` (and `arker shell` on a TTY)
|
|
115
|
+
drop you into a live terminal you can run `claude` in:
|
|
116
|
+
|
|
117
|
+
```bash
|
|
118
|
+
arker pty <vm_id> # login shell in a fresh/!existing VM
|
|
119
|
+
arker pty --command /usr/bin/htop # launch a program directly
|
|
120
|
+
```
|
|
121
|
+
|
|
64
122
|
## Durability
|
|
65
123
|
|
|
66
124
|
For long-running or non-idempotent work, fork with `durable: true` and pass an idempotency key when retrying a run:
|
|
@@ -72,6 +130,102 @@ await vm.run("python3 train.py", { background: true, idempotencyKey: crypto.rand
|
|
|
72
130
|
|
|
73
131
|
If the host fails mid-run, the run resumes on a healthy host with the VM's filesystem state preserved. Backends without durability return `ArkerError` code `unsupported_operation`.
|
|
74
132
|
|
|
133
|
+
## Compatibility imports
|
|
134
|
+
|
|
135
|
+
The SDK includes limited compatibility layers for common Daytona, E2B, and Modal sandbox workflows. These entrypoints keep the original SDK-shaped calls, route through ComputeSDK, use Arker as the first provider, and fall back to the original provider when resolving an existing non-Arker sandbox ID.
|
|
136
|
+
|
|
137
|
+
For the supported surface below, migration is a one-line import change:
|
|
138
|
+
|
|
139
|
+
| SDK | Replace | With |
|
|
140
|
+
| --- | --- | --- |
|
|
141
|
+
| Daytona | `import { Daytona } from "@daytonaio/sdk";` | `import { Daytona } from "@arker-ai/sdk/daytona";` |
|
|
142
|
+
| E2B | `import { Sandbox } from "e2b";` | `import { Sandbox } from "@arker-ai/sdk/e2b";` |
|
|
143
|
+
| Modal | `import { ModalClient } from "modal";` | `import { ModalClient } from "@arker-ai/sdk/modal";` |
|
|
144
|
+
|
|
145
|
+
### Daytona
|
|
146
|
+
|
|
147
|
+
```ts
|
|
148
|
+
import { Daytona } from "@arker-ai/sdk/daytona";
|
|
149
|
+
|
|
150
|
+
const daytona = new Daytona({ apiKey: process.env.DAYTONA_API_KEY });
|
|
151
|
+
const sandbox = await daytona.create();
|
|
152
|
+
const result = await sandbox.process.exec("echo hello");
|
|
153
|
+
|
|
154
|
+
console.log(result.result);
|
|
155
|
+
await daytona.delete(sandbox);
|
|
156
|
+
```
|
|
157
|
+
|
|
158
|
+
Supported Daytona surface:
|
|
159
|
+
|
|
160
|
+
- `new Daytona({ apiKey?, arker? })`
|
|
161
|
+
- `daytona.create()`
|
|
162
|
+
- `daytona.get(id)`
|
|
163
|
+
- `daytona.delete(idOrSandbox)`
|
|
164
|
+
- `sandbox.id`
|
|
165
|
+
- `sandbox.process.exec(command)`
|
|
166
|
+
- `sandbox.process.executeCommand(command)`
|
|
167
|
+
- `sandbox.delete()`
|
|
168
|
+
|
|
169
|
+
### E2B
|
|
170
|
+
|
|
171
|
+
```ts
|
|
172
|
+
import { Sandbox } from "@arker-ai/sdk/e2b";
|
|
173
|
+
|
|
174
|
+
const sandbox = await Sandbox.create();
|
|
175
|
+
const result = await sandbox.commands.run("echo hello");
|
|
176
|
+
|
|
177
|
+
console.log(result.stdout);
|
|
178
|
+
await sandbox.kill();
|
|
179
|
+
```
|
|
180
|
+
|
|
181
|
+
Supported E2B surface:
|
|
182
|
+
|
|
183
|
+
- `Sandbox.create()`
|
|
184
|
+
- `Sandbox.create(templateId, { timeoutMs? })`
|
|
185
|
+
- `Sandbox.connect(id)`
|
|
186
|
+
- `sandbox.sandboxId`
|
|
187
|
+
- `sandbox.commands.run(command)`
|
|
188
|
+
- `sandbox.files.read/write/makeDir/list/exists/remove`
|
|
189
|
+
- `sandbox.kill()`
|
|
190
|
+
|
|
191
|
+
### Modal
|
|
192
|
+
|
|
193
|
+
```ts
|
|
194
|
+
import { ModalClient } from "@arker-ai/sdk/modal";
|
|
195
|
+
|
|
196
|
+
const client = new ModalClient({
|
|
197
|
+
tokenId: process.env.MODAL_TOKEN_ID,
|
|
198
|
+
tokenSecret: process.env.MODAL_TOKEN_SECRET,
|
|
199
|
+
});
|
|
200
|
+
const sandbox = await client.sandboxes.create();
|
|
201
|
+
const proc = await sandbox.exec(["sh", "-c", "echo hello"]);
|
|
202
|
+
|
|
203
|
+
console.log(await proc.stdout.readText());
|
|
204
|
+
await sandbox.terminate();
|
|
205
|
+
```
|
|
206
|
+
|
|
207
|
+
Supported Modal surface:
|
|
208
|
+
|
|
209
|
+
- `new ModalClient({ tokenId?, tokenSecret?, arker? })`
|
|
210
|
+
- `client.sandboxes.create()`
|
|
211
|
+
- `client.sandboxes.fromId(id)`
|
|
212
|
+
- `sandbox.sandboxId`
|
|
213
|
+
- `sandbox.exec(commandOrArgv, { workdir?, env?, timeoutMs?, stdout?: "pipe", stderr?: "pipe", mode?: "text" })`
|
|
214
|
+
- `process.stdout.readText()`
|
|
215
|
+
- `process.stderr.readText()`
|
|
216
|
+
- `process.wait()`
|
|
217
|
+
- `sandbox.terminate()`
|
|
218
|
+
|
|
219
|
+
Unsupported provider-specific methods and options throw explicit errors instead of being silently ignored. Arker credentials come from `ARKER_API_KEY` and optional `ARKER_REGION` / `ARKER_BASE_URL`; original provider credentials are only used for fallback.
|
|
220
|
+
|
|
221
|
+
Compatibility test commands:
|
|
222
|
+
|
|
223
|
+
```bash
|
|
224
|
+
npm run test:compat
|
|
225
|
+
ARKER_API_KEY=... npm run test:compat-live
|
|
226
|
+
ARKER_API_KEY=... DAYTONA_API_KEY=... E2B_API_KEY=... MODAL_TOKEN_ID=... MODAL_TOKEN_SECRET=... npm run test:compat-fallback-live
|
|
227
|
+
```
|
|
228
|
+
|
|
75
229
|
## License
|
|
76
230
|
|
|
77
231
|
Apache-2.0
|
|
@@ -0,0 +1,286 @@
|
|
|
1
|
+
import {
|
|
2
|
+
Arker,
|
|
3
|
+
ArkerError
|
|
4
|
+
} from "./chunk-7BHPVQNG.js";
|
|
5
|
+
|
|
6
|
+
// src/compat/common.ts
|
|
7
|
+
function shouldGuardNested(value) {
|
|
8
|
+
return !!value && typeof value === "object" && Object.getPrototypeOf(value) === Object.prototype;
|
|
9
|
+
}
|
|
10
|
+
function guardUnsupported(instance, shimName) {
|
|
11
|
+
const passthrough = /* @__PURE__ */ new Set([
|
|
12
|
+
"then",
|
|
13
|
+
"catch",
|
|
14
|
+
"finally",
|
|
15
|
+
"constructor",
|
|
16
|
+
"toJSON",
|
|
17
|
+
"toString",
|
|
18
|
+
"valueOf",
|
|
19
|
+
Symbol.toStringTag
|
|
20
|
+
]);
|
|
21
|
+
const supported = /* @__PURE__ */ new Set();
|
|
22
|
+
for (let current = instance; current && current !== Object.prototype; current = Object.getPrototypeOf(current)) {
|
|
23
|
+
for (const key of Reflect.ownKeys(current)) supported.add(key);
|
|
24
|
+
}
|
|
25
|
+
return new Proxy(instance, {
|
|
26
|
+
get(target, prop) {
|
|
27
|
+
if (typeof prop === "symbol" || passthrough.has(prop) || supported.has(prop)) {
|
|
28
|
+
const value = Reflect.get(target, prop, target);
|
|
29
|
+
if (typeof value === "function") {
|
|
30
|
+
return value.bind(target);
|
|
31
|
+
}
|
|
32
|
+
return shouldGuardNested(value) ? guardUnsupported(value, shimName) : value;
|
|
33
|
+
}
|
|
34
|
+
throw new Error(
|
|
35
|
+
`'${String(prop)}' is not supported by the Arker compatibility layer for ${shimName}. The compatibility layer covers create/connect/get, command execution, and core filesystem operations. Use the native ${shimName} SDK directly for the full API.`
|
|
36
|
+
);
|
|
37
|
+
}
|
|
38
|
+
});
|
|
39
|
+
}
|
|
40
|
+
function isPlainRecord(value) {
|
|
41
|
+
return !!value && typeof value === "object" && !Array.isArray(value);
|
|
42
|
+
}
|
|
43
|
+
function formatKeys(keys) {
|
|
44
|
+
return keys.map((key) => `'${key}'`).join(", ");
|
|
45
|
+
}
|
|
46
|
+
function assertNoUnsupportedArgs(args, shimName, methodName) {
|
|
47
|
+
if (args.length === 0) return;
|
|
48
|
+
throw new Error(
|
|
49
|
+
`${methodName} received unsupported positional argument(s) in the Arker compatibility layer for ${shimName}. Those values would be ignored, so this layer fails fast. Use the native ${shimName} SDK for app/image/provider-specific options.`
|
|
50
|
+
);
|
|
51
|
+
}
|
|
52
|
+
function assertSupportedObjectKeys(value, supportedKeys, shimName, methodName) {
|
|
53
|
+
if (value === void 0) return;
|
|
54
|
+
if (!isPlainRecord(value)) {
|
|
55
|
+
throw new Error(
|
|
56
|
+
`${methodName} only accepts an options object in the Arker compatibility layer for ${shimName}. Use the native ${shimName} SDK for unsupported call signatures.`
|
|
57
|
+
);
|
|
58
|
+
}
|
|
59
|
+
const supported = new Set(supportedKeys);
|
|
60
|
+
const unsupported = Object.keys(value).filter((key) => !supported.has(key));
|
|
61
|
+
if (unsupported.length > 0) {
|
|
62
|
+
throw new Error(
|
|
63
|
+
`${methodName} received unsupported option(s) ${formatKeys(unsupported)} in the Arker compatibility layer for ${shimName}. Those options would be ignored, so this layer fails fast. Supported option(s): ${supportedKeys.length > 0 ? formatKeys([...supportedKeys]) : "(none)"}.`
|
|
64
|
+
);
|
|
65
|
+
}
|
|
66
|
+
}
|
|
67
|
+
function resolveTimeout(opts) {
|
|
68
|
+
if (opts?.timeout !== void 0 && opts.timeoutMs !== void 0 && opts.timeout !== opts.timeoutMs) {
|
|
69
|
+
throw new Error("Received both 'timeout' and 'timeoutMs' with different values. Use one timeout value.");
|
|
70
|
+
}
|
|
71
|
+
return opts?.timeoutMs ?? opts?.timeout;
|
|
72
|
+
}
|
|
73
|
+
function isStringRecord(value) {
|
|
74
|
+
return !!value && typeof value === "object" && !Array.isArray(value) && Object.values(value).every((entry) => typeof entry === "string");
|
|
75
|
+
}
|
|
76
|
+
function shellQuote(value) {
|
|
77
|
+
if (value === "") return "''";
|
|
78
|
+
if (/^[A-Za-z0-9_./:@%+=,-]+$/.test(value)) return value;
|
|
79
|
+
return `'${value.replace(/'/g, `'\\''`)}'`;
|
|
80
|
+
}
|
|
81
|
+
function commandName(command) {
|
|
82
|
+
return command.split("/").pop() || command;
|
|
83
|
+
}
|
|
84
|
+
function argvToCommand(cmd) {
|
|
85
|
+
if (typeof cmd === "string") return cmd;
|
|
86
|
+
const executable = commandName(cmd[0] ?? "");
|
|
87
|
+
if ((executable === "sh" || executable === "bash") && cmd.length >= 3 && (cmd[1] === "-c" || cmd[1] === "-lc")) {
|
|
88
|
+
return cmd[2];
|
|
89
|
+
}
|
|
90
|
+
return cmd.map(shellQuote).join(" ");
|
|
91
|
+
}
|
|
92
|
+
function emitFinalOutput(result, options) {
|
|
93
|
+
if (result.stdout && options?.onStdout) options.onStdout(result.stdout);
|
|
94
|
+
if (result.stderr && options?.onStderr) options.onStderr(result.stderr);
|
|
95
|
+
}
|
|
96
|
+
|
|
97
|
+
// src/compat/runtime.ts
|
|
98
|
+
import { compute } from "computesdk";
|
|
99
|
+
|
|
100
|
+
// src/compat/arker-provider.ts
|
|
101
|
+
var DEFAULT_REGION = "aws-us-east-1";
|
|
102
|
+
var DEFAULT_SOURCE = "ubuntu-full";
|
|
103
|
+
function env(key) {
|
|
104
|
+
const value = globalThis.process?.env?.[key];
|
|
105
|
+
const trimmed = value?.trim();
|
|
106
|
+
return trimmed ? trimmed : void 0;
|
|
107
|
+
}
|
|
108
|
+
function makeClient(config = {}) {
|
|
109
|
+
const endpointConfigured = config.baseUrl || config.region || env("ARKER_BASE_URL") || env("ARKER_REGION");
|
|
110
|
+
return new Arker({
|
|
111
|
+
...config,
|
|
112
|
+
region: config.region ?? (endpointConfigured ? void 0 : DEFAULT_REGION)
|
|
113
|
+
});
|
|
114
|
+
}
|
|
115
|
+
function decode(bytes) {
|
|
116
|
+
return new TextDecoder().decode(bytes);
|
|
117
|
+
}
|
|
118
|
+
function toFileEntries(stdout) {
|
|
119
|
+
const entries = [];
|
|
120
|
+
for (const line of stdout.split("\n")) {
|
|
121
|
+
if (!line) continue;
|
|
122
|
+
const parts = line.split(" ");
|
|
123
|
+
if (parts.length < 4) continue;
|
|
124
|
+
const [type, size, mtime, ...nameParts] = parts;
|
|
125
|
+
entries.push({
|
|
126
|
+
name: nameParts.join(" "),
|
|
127
|
+
type: type === "d" ? "directory" : "file",
|
|
128
|
+
size: Number(size) || 0,
|
|
129
|
+
modified: new Date((Number(mtime) || 0) * 1e3)
|
|
130
|
+
});
|
|
131
|
+
}
|
|
132
|
+
return entries;
|
|
133
|
+
}
|
|
134
|
+
var ArkerComputeSandbox = class {
|
|
135
|
+
constructor(vm, destroyVm) {
|
|
136
|
+
this.vm = vm;
|
|
137
|
+
this.destroyVm = destroyVm;
|
|
138
|
+
this.sandboxId = vm.id;
|
|
139
|
+
this.filesystem = {
|
|
140
|
+
readFile: async (path) => decode(await this.vm.sync(path)),
|
|
141
|
+
writeFile: async (path, content) => {
|
|
142
|
+
await this.vm.sync(path, content);
|
|
143
|
+
},
|
|
144
|
+
mkdir: async (path) => {
|
|
145
|
+
const result = await this.runCommand(`mkdir -p ${shellQuote(path)}`);
|
|
146
|
+
if (result.exitCode !== 0) throw new Error(`Arker mkdir failed for ${path}: ${result.stderr || `exit ${result.exitCode}`}`);
|
|
147
|
+
},
|
|
148
|
+
readdir: async (path) => {
|
|
149
|
+
const p = shellQuote(path);
|
|
150
|
+
const script = `cd ${p} 2>/dev/null || exit 3; for e in * .*; do [ "$e" = "." ] && continue; [ "$e" = ".." ] && continue; [ -e "$e" ] || continue; if [ -d "$e" ]; then t=d; else t=f; fi; s=$(stat -c %s "$e" 2>/dev/null || echo 0); m=$(stat -c %Y "$e" 2>/dev/null || echo 0); printf '%s\\t%s\\t%s\\t%s\\n' "$t" "$s" "$m" "$e"; done`;
|
|
151
|
+
const result = await this.runCommand(script);
|
|
152
|
+
if (result.exitCode !== 0) throw new Error(`Arker readdir failed for ${path}: ${result.stderr || `exit ${result.exitCode}`}`);
|
|
153
|
+
return toFileEntries(result.stdout);
|
|
154
|
+
},
|
|
155
|
+
exists: async (path) => {
|
|
156
|
+
const result = await this.runCommand(`test -e ${shellQuote(path)}`);
|
|
157
|
+
return result.exitCode === 0;
|
|
158
|
+
},
|
|
159
|
+
remove: async (path) => {
|
|
160
|
+
const result = await this.runCommand(`rm -rf ${shellQuote(path)}`);
|
|
161
|
+
if (result.exitCode !== 0) throw new Error(`Arker remove failed for ${path}: ${result.stderr || `exit ${result.exitCode}`}`);
|
|
162
|
+
}
|
|
163
|
+
};
|
|
164
|
+
}
|
|
165
|
+
vm;
|
|
166
|
+
destroyVm;
|
|
167
|
+
sandboxId;
|
|
168
|
+
provider = "arker";
|
|
169
|
+
filesystem;
|
|
170
|
+
getInstance() {
|
|
171
|
+
return this.vm;
|
|
172
|
+
}
|
|
173
|
+
async runCommand(command, options) {
|
|
174
|
+
const startTime = Date.now();
|
|
175
|
+
let fullCommand = command;
|
|
176
|
+
if (options?.env && Object.keys(options.env).length > 0) {
|
|
177
|
+
const envPrefix = Object.entries(options.env).map(([key, value]) => `${key}=${shellQuote(String(value))}`).join(" ");
|
|
178
|
+
fullCommand = `${envPrefix} ${fullCommand}`;
|
|
179
|
+
}
|
|
180
|
+
if (options?.cwd) fullCommand = `cd ${shellQuote(options.cwd)} && ${fullCommand}`;
|
|
181
|
+
if (options?.background) fullCommand = `nohup sh -lc ${shellQuote(fullCommand)} > /dev/null 2>&1 &`;
|
|
182
|
+
const runOptions = {};
|
|
183
|
+
if (options?.timeout) runOptions.timeout = options.timeout;
|
|
184
|
+
const result = await this.vm.run(fullCommand, runOptions);
|
|
185
|
+
if (result.type !== "completed") {
|
|
186
|
+
throw new Error(`Arker run did not complete synchronously (type=${result.type}). runCommand requires a foreground command.`);
|
|
187
|
+
}
|
|
188
|
+
const commandResult = {
|
|
189
|
+
stdout: decode(result.stdout),
|
|
190
|
+
stderr: decode(result.stderr),
|
|
191
|
+
exitCode: result.exitCode,
|
|
192
|
+
durationMs: Date.now() - startTime
|
|
193
|
+
};
|
|
194
|
+
emitFinalOutput(commandResult, options);
|
|
195
|
+
return commandResult;
|
|
196
|
+
}
|
|
197
|
+
async getInfo() {
|
|
198
|
+
return {
|
|
199
|
+
id: this.sandboxId,
|
|
200
|
+
provider: "arker",
|
|
201
|
+
status: "running",
|
|
202
|
+
createdAt: this.vm.created_at ? new Date(this.vm.created_at) : /* @__PURE__ */ new Date(),
|
|
203
|
+
timeout: 0,
|
|
204
|
+
metadata: {
|
|
205
|
+
name: this.vm.name,
|
|
206
|
+
region: this.vm.region,
|
|
207
|
+
provider: this.vm.provider
|
|
208
|
+
}
|
|
209
|
+
};
|
|
210
|
+
}
|
|
211
|
+
async getUrl(_options) {
|
|
212
|
+
throw new ArkerError(
|
|
213
|
+
"unsupported_operation",
|
|
214
|
+
"getUrl is not supported: the Arker VM API does not expose tunnel URLs",
|
|
215
|
+
422
|
|
216
|
+
);
|
|
217
|
+
}
|
|
218
|
+
async destroy() {
|
|
219
|
+
await this.destroyVm(this.sandboxId);
|
|
220
|
+
}
|
|
221
|
+
};
|
|
222
|
+
function createArkerComputeProvider(config = {}) {
|
|
223
|
+
async function destroy(sandboxId) {
|
|
224
|
+
const client = makeClient(config);
|
|
225
|
+
try {
|
|
226
|
+
await client.vm(sandboxId).delete();
|
|
227
|
+
} catch (error) {
|
|
228
|
+
if (error instanceof ArkerError && error.status === 404) return;
|
|
229
|
+
throw error;
|
|
230
|
+
}
|
|
231
|
+
}
|
|
232
|
+
function wrap(vm) {
|
|
233
|
+
return new ArkerComputeSandbox(vm, destroy);
|
|
234
|
+
}
|
|
235
|
+
return {
|
|
236
|
+
name: "arker",
|
|
237
|
+
sandbox: {
|
|
238
|
+
create: async (options) => {
|
|
239
|
+
const client = makeClient(config);
|
|
240
|
+
const source = options?.templateId || options?.snapshotId || config.source || env("ARKER_SOURCE") || DEFAULT_SOURCE;
|
|
241
|
+
const forkRequest = {};
|
|
242
|
+
if (options?.name) forkRequest.name = options.name;
|
|
243
|
+
const vm = await client.fork(source, forkRequest);
|
|
244
|
+
return wrap(vm);
|
|
245
|
+
},
|
|
246
|
+
getById: async (sandboxId) => {
|
|
247
|
+
const client = makeClient(config);
|
|
248
|
+
try {
|
|
249
|
+
return wrap(await client.getVm(sandboxId));
|
|
250
|
+
} catch (error) {
|
|
251
|
+
if (error instanceof ArkerError && error.status === 404) return null;
|
|
252
|
+
throw error;
|
|
253
|
+
}
|
|
254
|
+
},
|
|
255
|
+
list: async () => {
|
|
256
|
+
const client = makeClient(config);
|
|
257
|
+
const { vms } = await client.listVms();
|
|
258
|
+
return (vms ?? []).map(wrap);
|
|
259
|
+
},
|
|
260
|
+
destroy
|
|
261
|
+
}
|
|
262
|
+
};
|
|
263
|
+
}
|
|
264
|
+
|
|
265
|
+
// src/compat/runtime.ts
|
|
266
|
+
var computeFactory = compute;
|
|
267
|
+
function createCompatSdk(options) {
|
|
268
|
+
return computeFactory({
|
|
269
|
+
providers: [
|
|
270
|
+
createArkerComputeProvider(options.arker),
|
|
271
|
+
options.fallbackProvider
|
|
272
|
+
],
|
|
273
|
+
providerStrategy: "priority",
|
|
274
|
+
fallbackOnError: true
|
|
275
|
+
});
|
|
276
|
+
}
|
|
277
|
+
|
|
278
|
+
export {
|
|
279
|
+
guardUnsupported,
|
|
280
|
+
assertNoUnsupportedArgs,
|
|
281
|
+
assertSupportedObjectKeys,
|
|
282
|
+
resolveTimeout,
|
|
283
|
+
isStringRecord,
|
|
284
|
+
argvToCommand,
|
|
285
|
+
createCompatSdk
|
|
286
|
+
};
|