@watasu/sdk 0.1.25 → 0.1.40
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 +50 -7
- package/dist/codeInterpreter.d.ts +33 -7
- package/dist/codeInterpreter.js +51 -10
- package/dist/commands.d.ts +5 -6
- package/dist/commands.js +6 -6
- package/dist/connectionConfig.d.ts +24 -0
- package/dist/connectionConfig.js +49 -2
- package/dist/filesystem.d.ts +7 -19
- package/dist/filesystem.js +1 -5
- package/dist/git.d.ts +1 -2
- package/dist/git.js +7 -3
- package/dist/index.d.ts +4 -2
- package/dist/index.js +2 -1
- package/dist/process.d.ts +1 -1
- package/dist/process.js +3 -3
- package/dist/processSocket.d.ts +2 -1
- package/dist/processSocket.js +4 -2
- package/dist/pty.d.ts +3 -3
- package/dist/pty.js +9 -7
- package/dist/sandbox.d.ts +40 -27
- package/dist/sandbox.js +130 -49
- package/dist/template.d.ts +3 -2
- package/dist/template.js +13 -2
- package/dist/terminal.d.ts +2 -3
- package/dist/terminal.js +2 -3
- package/dist/transport.d.ts +2 -0
- package/dist/transport.js +23 -6
- package/dist/volume.d.ts +116 -0
- package/dist/volume.js +278 -0
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -16,7 +16,7 @@ Set `WATASU_API_KEY` before using the SDK.
|
|
|
16
16
|
import { Sandbox } from '@watasu/sdk'
|
|
17
17
|
|
|
18
18
|
const sbx = await Sandbox.create()
|
|
19
|
-
await sbx.
|
|
19
|
+
await sbx.files.write('/home/user/a.js', 'console.log(2 + 2)')
|
|
20
20
|
const result = await sbx.process.startAndWait('node /home/user/a.js')
|
|
21
21
|
console.log(result.stdout)
|
|
22
22
|
console.log(await sbx.isRunning())
|
|
@@ -31,23 +31,63 @@ await sbx.betaPause()
|
|
|
31
31
|
await sbx.resume({ timeoutMs: 300_000 })
|
|
32
32
|
```
|
|
33
33
|
|
|
34
|
+
Choose what happens when the sandbox timeout expires:
|
|
35
|
+
|
|
36
|
+
```ts
|
|
37
|
+
const sbx = await Sandbox.create({
|
|
38
|
+
lifecycle: { onTimeout: 'pause', autoResume: true },
|
|
39
|
+
})
|
|
40
|
+
```
|
|
41
|
+
|
|
42
|
+
`onTimeout: 'kill'` is the default. `onTimeout: 'pause'` keeps the retained
|
|
43
|
+
disk after timeout; `autoResume` lets a later data-plane request resume that
|
|
44
|
+
paused sandbox automatically.
|
|
45
|
+
|
|
46
|
+
Mount a named persistent volume when the sandbox starts:
|
|
47
|
+
|
|
48
|
+
```ts
|
|
49
|
+
const sbx = await Sandbox.create({
|
|
50
|
+
volumeMounts: {
|
|
51
|
+
'/workspace/cache': 'cache',
|
|
52
|
+
'/data/models': { name: 'models' },
|
|
53
|
+
},
|
|
54
|
+
})
|
|
55
|
+
```
|
|
56
|
+
|
|
57
|
+
Create and edit a persistent volume while it is detached:
|
|
58
|
+
|
|
59
|
+
```ts
|
|
60
|
+
import { Volume } from '@watasu/sdk'
|
|
61
|
+
|
|
62
|
+
const volume = await Volume.create('cache')
|
|
63
|
+
await volume.makeDir('/workspace')
|
|
64
|
+
await volume.writeFile('/workspace/status.txt', 'ready\n', { mode: '0644' })
|
|
65
|
+
console.log(await volume.readFile('/workspace/status.txt'))
|
|
66
|
+
console.log((await volume.list('/workspace')).map((entry) => entry.path))
|
|
67
|
+
await volume.remove('/workspace/status.txt')
|
|
68
|
+
await volume.destroy()
|
|
69
|
+
```
|
|
70
|
+
|
|
34
71
|
## Code Interpreter
|
|
35
72
|
|
|
36
73
|
```ts
|
|
37
74
|
import { Sandbox } from '@watasu/sdk/code-interpreter'
|
|
38
75
|
|
|
39
76
|
const sbx = await Sandbox.create()
|
|
77
|
+
const context = await sbx.createCodeContext()
|
|
40
78
|
const execution = await sbx.runCode("print('hello')\n2 + 3", {
|
|
41
|
-
|
|
79
|
+
context,
|
|
42
80
|
onStdout: (message) => console.log(message.line),
|
|
43
81
|
})
|
|
44
82
|
|
|
45
83
|
console.log(execution.text)
|
|
84
|
+
await sbx.removeCodeContext(context)
|
|
46
85
|
await sbx.kill()
|
|
47
86
|
```
|
|
48
87
|
|
|
49
|
-
`@watasu/sdk/code-interpreter` starts the `code-interpreter` template by default
|
|
50
|
-
and returns structured `results`, `logs`,
|
|
88
|
+
`@watasu/sdk/code-interpreter` starts the `code-interpreter` template by default.
|
|
89
|
+
Code runs in persistent Python contexts and returns structured `results`, `logs`,
|
|
90
|
+
and `error` fields for each execution.
|
|
51
91
|
|
|
52
92
|
## MCP Gateway
|
|
53
93
|
|
|
@@ -112,12 +152,12 @@ const remoteUrl = await sbx.git.remoteGet('/workspace/project', 'origin')
|
|
|
112
152
|
await sbx.git.restore('/workspace/project', { paths: ['README.md'] })
|
|
113
153
|
await sbx.git.reset('/workspace/project', { mode: 'hard', target: 'HEAD' })
|
|
114
154
|
|
|
115
|
-
await sbx.
|
|
155
|
+
await sbx.files.writeFiles([
|
|
116
156
|
{ path: '/workspace/project/a.txt', data: 'alpha' },
|
|
117
157
|
{ path: '/workspace/project/b.bin', data: new Uint8Array([0, 1, 2]) },
|
|
118
158
|
])
|
|
119
159
|
|
|
120
|
-
const watcher = sbx.
|
|
160
|
+
const watcher = sbx.files.watchDir('/workspace/project')
|
|
121
161
|
watcher.addEventListener((event) => {
|
|
122
162
|
console.log(event.type, event.path)
|
|
123
163
|
})
|
|
@@ -191,7 +231,10 @@ instructions into Watasu's package-spec builder.
|
|
|
191
231
|
import { Sandbox } from '@watasu/sdk'
|
|
192
232
|
|
|
193
233
|
const sbx = await Sandbox.create()
|
|
194
|
-
const metrics = await sbx.getMetrics(
|
|
234
|
+
const metrics = await sbx.getMetrics({
|
|
235
|
+
start: new Date(Date.now() - 5 * 60_000),
|
|
236
|
+
end: new Date(),
|
|
237
|
+
})
|
|
195
238
|
const snapshot = await sbx.createSnapshot({ name: 'ready' })
|
|
196
239
|
const snapshots = await sbx.listSnapshots().nextItems()
|
|
197
240
|
const allSnapshots = await Sandbox.listSnapshots({ limit: 100 }).nextItems()
|
|
@@ -1,20 +1,43 @@
|
|
|
1
1
|
import { Sandbox as BaseSandbox, SandboxConnectOpts, SandboxCreateOpts } from './sandbox.js';
|
|
2
|
+
export { ApiError, AuthenticationError, ConflictError, FileNotFoundError, InvalidArgumentError, NotEnoughSpaceError, NotFoundError, NotImplementedError, RateLimitError, SandboxError, TimeoutError, } from './errors.js';
|
|
3
|
+
export { ConnectionConfig, KEEPALIVE_PING_INTERVAL_SEC } from './connectionConfig.js';
|
|
4
|
+
export { SandboxPaginator, SnapshotPaginator } from './sandbox.js';
|
|
5
|
+
export type { CreateSnapshotOpts, FileUrlInfo, McpServer, McpServerName, RestoreSnapshotOpts, SandboxConnectOpts, SandboxCreateOpts, SandboxInfo, SandboxInfoLifecycle, SandboxLifecycle, SandboxListOpts, SandboxMetrics, SandboxMetricsOpts, SandboxNetworkSelector, SandboxNetworkUpdate, SandboxNetworkUpdateOpts, SandboxUrlOpts, SnapshotInfo, } from './sandbox.js';
|
|
6
|
+
export { CommandExitError, CommandHandle, Commands } from './commands.js';
|
|
7
|
+
export type { CommandResult, CommandStartOpts, ProcessInfo } from './commands.js';
|
|
8
|
+
export { Process, ProcessManager, ProcessMessage, ProcessOutput } from './process.js';
|
|
9
|
+
export type { ProcessOpts } from './process.js';
|
|
10
|
+
export { FileType, Filesystem, FilesystemWatcher, WatchHandle } from './filesystem.js';
|
|
11
|
+
export type { EntryInfo, FilesystemEvent, FilesystemReadOpts, FilesystemRequestOpts, FilesystemWriteOpts, WatchOpts, WriteData, WriteEntry, WriteInfo, } from './filesystem.js';
|
|
12
|
+
export { Git } from './git.js';
|
|
13
|
+
export type { GitAddOpts, GitAuthOpts, GitBranches, GitBranchOpts, GitCloneOpts, GitCommandResult, GitCommitOpts, GitConfigOpts, GitConfigureUserOpts, GitCredentialOpts, GitFileStatus, GitInitOpts, GitPullOpts, GitPushOpts, GitRemoteAddOpts, GitResetMode, GitResetOpts, GitRestoreOpts, GitStatus, } from './git.js';
|
|
14
|
+
export { Pty } from './pty.js';
|
|
15
|
+
export type { PtyConnectOpts, PtyCreateOpts, PtySize } from './pty.js';
|
|
16
|
+
export { Terminal, TerminalManager, TerminalOutput } from './terminal.js';
|
|
17
|
+
export type { TerminalOpts } from './terminal.js';
|
|
18
|
+
export { Volume } from './volume.js';
|
|
19
|
+
export type { VolumeApiParams, VolumeConnectionConfig, VolumeEntryStat, VolumeFileType, VolumeInfo, VolumeListFilesOpts, VolumeListOpts, VolumeMetadataOpts, VolumeReadFileOpts, VolumeReadFormat, VolumeWriteData, VolumeWriteFileOpts, } from './volume.js';
|
|
20
|
+
export { ProcessSocket, base64DecodeBytes, base64DecodeText, base64Encode } from './processSocket.js';
|
|
21
|
+
export { ReadyCmd, Template, TemplateBase, waitForFile, waitForPort, waitForProcess, waitForTimeout, waitForURL, } from './template.js';
|
|
22
|
+
export type { BuildInfo, BuildOptions, BuildStatusReason, CopyItem, GetBuildStatusOptions, LogEntry, ReadyCommand, TemplateBuilder, TemplateBuildStatus, TemplateBuildStatusResponse, TemplateClass, TemplateFactory, TemplateFinal, TemplateFromImage, TemplateOptions, TemplateTag, TemplateTagInfo, } from './template.js';
|
|
2
23
|
export type RunCodeLanguage = 'python' | 'python3' | string;
|
|
3
24
|
export interface RunCodeOpts {
|
|
4
25
|
language?: RunCodeLanguage;
|
|
5
|
-
context?: Context;
|
|
26
|
+
context?: Context | string;
|
|
6
27
|
onStdout?: (message: OutputMessage) => void;
|
|
7
28
|
onStderr?: (message: OutputMessage) => void;
|
|
8
29
|
onResult?: (result: Result) => void;
|
|
9
30
|
onError?: (error: ExecutionError) => void;
|
|
10
31
|
envs?: Record<string, string>;
|
|
11
|
-
|
|
32
|
+
timeoutMs?: number;
|
|
12
33
|
requestTimeoutMs?: number;
|
|
34
|
+
signal?: AbortSignal;
|
|
13
35
|
}
|
|
14
36
|
export interface CreateCodeContextOpts {
|
|
15
37
|
cwd?: string;
|
|
16
38
|
language?: RunCodeLanguage;
|
|
17
39
|
requestTimeoutMs?: number;
|
|
40
|
+
signal?: AbortSignal;
|
|
18
41
|
}
|
|
19
42
|
/** One stdout or stderr line emitted by code execution. */
|
|
20
43
|
export declare class OutputMessage {
|
|
@@ -86,15 +109,18 @@ export declare class Sandbox extends BaseSandbox {
|
|
|
86
109
|
/** Create a persistent code context. */
|
|
87
110
|
createCodeContext(_opts?: CreateCodeContextOpts): Promise<Context>;
|
|
88
111
|
/** Remove a persistent code context. */
|
|
89
|
-
removeCodeContext(
|
|
112
|
+
removeCodeContext(context: Context | string, opts?: {
|
|
90
113
|
requestTimeoutMs?: number;
|
|
91
|
-
|
|
114
|
+
signal?: AbortSignal;
|
|
115
|
+
}): Promise<void>;
|
|
92
116
|
/** List persistent code contexts. */
|
|
93
|
-
listCodeContexts(
|
|
117
|
+
listCodeContexts(opts?: {
|
|
94
118
|
requestTimeoutMs?: number;
|
|
119
|
+
signal?: AbortSignal;
|
|
95
120
|
}): Promise<Context[]>;
|
|
96
121
|
/** Restart a persistent code context. */
|
|
97
|
-
restartCodeContext(
|
|
122
|
+
restartCodeContext(context: Context | string, opts?: {
|
|
98
123
|
requestTimeoutMs?: number;
|
|
99
|
-
|
|
124
|
+
signal?: AbortSignal;
|
|
125
|
+
}): Promise<void>;
|
|
100
126
|
}
|
package/dist/codeInterpreter.js
CHANGED
|
@@ -1,5 +1,17 @@
|
|
|
1
|
-
import { InvalidArgumentError
|
|
1
|
+
import { InvalidArgumentError } from './errors.js';
|
|
2
2
|
import { Sandbox as BaseSandbox } from './sandbox.js';
|
|
3
|
+
export { ApiError, AuthenticationError, ConflictError, FileNotFoundError, InvalidArgumentError, NotEnoughSpaceError, NotFoundError, NotImplementedError, RateLimitError, SandboxError, TimeoutError, } from './errors.js';
|
|
4
|
+
export { ConnectionConfig, KEEPALIVE_PING_INTERVAL_SEC } from './connectionConfig.js';
|
|
5
|
+
export { SandboxPaginator, SnapshotPaginator } from './sandbox.js';
|
|
6
|
+
export { CommandExitError, CommandHandle, Commands } from './commands.js';
|
|
7
|
+
export { Process, ProcessManager, ProcessMessage, ProcessOutput } from './process.js';
|
|
8
|
+
export { FileType, Filesystem, FilesystemWatcher, WatchHandle } from './filesystem.js';
|
|
9
|
+
export { Git } from './git.js';
|
|
10
|
+
export { Pty } from './pty.js';
|
|
11
|
+
export { Terminal, TerminalManager, TerminalOutput } from './terminal.js';
|
|
12
|
+
export { Volume } from './volume.js';
|
|
13
|
+
export { ProcessSocket, base64DecodeBytes, base64DecodeText, base64Encode } from './processSocket.js';
|
|
14
|
+
export { ReadyCmd, Template, TemplateBase, waitForFile, waitForPort, waitForProcess, waitForTimeout, waitForURL, } from './template.js';
|
|
3
15
|
/** One stdout or stderr line emitted by code execution. */
|
|
4
16
|
export class OutputMessage {
|
|
5
17
|
line;
|
|
@@ -161,10 +173,11 @@ export class Sandbox extends BaseSandbox {
|
|
|
161
173
|
language: opts.language,
|
|
162
174
|
context_id: contextId(opts.context),
|
|
163
175
|
env_vars: opts.envs,
|
|
164
|
-
|
|
176
|
+
timeout_ms: opts.timeoutMs,
|
|
165
177
|
});
|
|
166
178
|
const response = await this.runtimePostJson('/runtime/v1/code/run', payload, {
|
|
167
179
|
requestTimeoutMs: opts.requestTimeoutMs,
|
|
180
|
+
signal: opts.signal,
|
|
168
181
|
});
|
|
169
182
|
const execution = executionFromApi(response);
|
|
170
183
|
emitCallbacks(execution, opts);
|
|
@@ -172,19 +185,37 @@ export class Sandbox extends BaseSandbox {
|
|
|
172
185
|
}
|
|
173
186
|
/** Create a persistent code context. */
|
|
174
187
|
async createCodeContext(_opts = {}) {
|
|
175
|
-
|
|
188
|
+
const response = await this.runtimePostJson('/runtime/v1/code/contexts', compactRecord({
|
|
189
|
+
cwd: _opts.cwd,
|
|
190
|
+
language: _opts.language,
|
|
191
|
+
}), {
|
|
192
|
+
requestTimeoutMs: _opts.requestTimeoutMs,
|
|
193
|
+
signal: _opts.signal,
|
|
194
|
+
});
|
|
195
|
+
return contextFromApi(response);
|
|
176
196
|
}
|
|
177
197
|
/** Remove a persistent code context. */
|
|
178
|
-
async removeCodeContext(
|
|
179
|
-
|
|
198
|
+
async removeCodeContext(context, opts = {}) {
|
|
199
|
+
await this.runtimeDeleteJson(`/runtime/v1/code/contexts/${encodeURIComponent(requireContextId(context))}`, {
|
|
200
|
+
requestTimeoutMs: opts.requestTimeoutMs,
|
|
201
|
+
signal: opts.signal,
|
|
202
|
+
});
|
|
180
203
|
}
|
|
181
204
|
/** List persistent code contexts. */
|
|
182
|
-
async listCodeContexts(
|
|
183
|
-
|
|
205
|
+
async listCodeContexts(opts = {}) {
|
|
206
|
+
const response = await this.runtimeGetJson('/runtime/v1/code/contexts', {
|
|
207
|
+
requestTimeoutMs: opts.requestTimeoutMs,
|
|
208
|
+
signal: opts.signal,
|
|
209
|
+
});
|
|
210
|
+
const contexts = Array.isArray(response) ? response : arrayOfUnknown(response.contexts);
|
|
211
|
+
return contexts.map((item) => contextFromApi(record(item)));
|
|
184
212
|
}
|
|
185
213
|
/** Restart a persistent code context. */
|
|
186
|
-
async restartCodeContext(
|
|
187
|
-
|
|
214
|
+
async restartCodeContext(context, opts = {}) {
|
|
215
|
+
await this.runtimePostJson(`/runtime/v1/code/contexts/${encodeURIComponent(requireContextId(context))}/restart`, {}, {
|
|
216
|
+
requestTimeoutMs: opts.requestTimeoutMs,
|
|
217
|
+
signal: opts.signal,
|
|
218
|
+
});
|
|
188
219
|
}
|
|
189
220
|
}
|
|
190
221
|
function executionFromApi(payload) {
|
|
@@ -219,7 +250,17 @@ function emitCallbacks(execution, opts) {
|
|
|
219
250
|
opts.onError?.(execution.error);
|
|
220
251
|
}
|
|
221
252
|
function contextId(context) {
|
|
222
|
-
|
|
253
|
+
if (context === undefined)
|
|
254
|
+
return undefined;
|
|
255
|
+
return requireContextId(context);
|
|
256
|
+
}
|
|
257
|
+
function requireContextId(context) {
|
|
258
|
+
if (typeof context === 'string')
|
|
259
|
+
return context;
|
|
260
|
+
return context.id;
|
|
261
|
+
}
|
|
262
|
+
function contextFromApi(payload) {
|
|
263
|
+
return new Context(String(payload.id ?? ''), stringValue(payload.language), stringValue(payload.cwd));
|
|
223
264
|
}
|
|
224
265
|
function compactRecord(payload) {
|
|
225
266
|
return Object.fromEntries(Object.entries(payload).filter(([, value]) => value !== undefined));
|
package/dist/commands.d.ts
CHANGED
|
@@ -34,22 +34,17 @@ export interface CommandStartOpts {
|
|
|
34
34
|
/** Arguments for `cmd` when starting a direct executable. */
|
|
35
35
|
args?: string[];
|
|
36
36
|
cwd?: string;
|
|
37
|
-
/** Deprecated alias for `cwd`. */
|
|
38
|
-
rootDir?: string;
|
|
39
37
|
user?: string;
|
|
40
38
|
envs?: Record<string, string>;
|
|
41
|
-
/** Alias for `envs`. */
|
|
42
|
-
envVars?: Record<string, string>;
|
|
43
39
|
onStdout?: (data: string) => void | Promise<void>;
|
|
44
40
|
onStderr?: (data: string) => void | Promise<void>;
|
|
45
41
|
onPty?: (data: Uint8Array) => void | Promise<void>;
|
|
46
42
|
onExit?: (exitCode: number) => void | Promise<void>;
|
|
47
43
|
stdin?: boolean;
|
|
48
44
|
timeoutMs?: number;
|
|
49
|
-
/** Alias for `timeoutMs`. */
|
|
50
|
-
timeout?: number;
|
|
51
45
|
processID?: string;
|
|
52
46
|
requestTimeoutMs?: number;
|
|
47
|
+
signal?: AbortSignal;
|
|
53
48
|
}
|
|
54
49
|
/** Live handle for one sandbox process stream. */
|
|
55
50
|
export declare class CommandHandle implements Partial<CommandResult> {
|
|
@@ -98,18 +93,22 @@ export declare class Commands {
|
|
|
98
93
|
/** List processes currently known by the sandbox runtime. */
|
|
99
94
|
list(opts?: {
|
|
100
95
|
requestTimeoutMs?: number;
|
|
96
|
+
signal?: AbortSignal;
|
|
101
97
|
}): Promise<ProcessInfo[]>;
|
|
102
98
|
/** Send SIGKILL to a process by pid. */
|
|
103
99
|
kill(pid: number | string, opts?: {
|
|
104
100
|
requestTimeoutMs?: number;
|
|
101
|
+
signal?: AbortSignal;
|
|
105
102
|
}): Promise<boolean>;
|
|
106
103
|
/** Attach to a process and send stdin bytes or text. */
|
|
107
104
|
sendStdin(pid: number | string, data: string | Uint8Array, opts?: {
|
|
108
105
|
requestTimeoutMs?: number;
|
|
106
|
+
signal?: AbortSignal;
|
|
109
107
|
}): Promise<void>;
|
|
110
108
|
/** Attach to a process and close stdin, signalling EOF. */
|
|
111
109
|
closeStdin(pid: number | string, opts?: {
|
|
112
110
|
requestTimeoutMs?: number;
|
|
111
|
+
signal?: AbortSignal;
|
|
113
112
|
}): Promise<void>;
|
|
114
113
|
run(cmd: string, opts: CommandStartOpts & {
|
|
115
114
|
background: true;
|
package/dist/commands.js
CHANGED
|
@@ -167,31 +167,31 @@ export class Commands {
|
|
|
167
167
|
const handle = await this.start(cmd, opts);
|
|
168
168
|
if (opts.background)
|
|
169
169
|
return handle;
|
|
170
|
-
return handle.wait(opts.timeoutMs
|
|
170
|
+
return handle.wait(opts.timeoutMs);
|
|
171
171
|
}
|
|
172
172
|
/** Reconnect to a live process stream by pid. */
|
|
173
173
|
async connect(pid, opts = {}) {
|
|
174
|
-
const socket = await new ProcessSocket(this.dataPlane.baseUrl, this.dataPlane.token, `/runtime/v1/process/${pid}/connect?since=0`, opts.requestTimeoutMs ?? this.config.requestTimeoutMs).connect();
|
|
174
|
+
const socket = await new ProcessSocket(this.dataPlane.baseUrl, this.dataPlane.token, `/runtime/v1/process/${pid}/connect?since=0`, opts.requestTimeoutMs ?? this.config.requestTimeoutMs, this.config.headers).connect();
|
|
175
175
|
const first = await nextStarted(socket);
|
|
176
176
|
const actualPid = framePid(first) ?? pid;
|
|
177
177
|
return new CommandHandle(actualPid, socket, () => this.kill(actualPid), socket, opts.onStdout, opts.onStderr, opts.onPty);
|
|
178
178
|
}
|
|
179
179
|
/** Start a command and return a live handle immediately. */
|
|
180
180
|
async start(cmd, opts = {}) {
|
|
181
|
-
const socket = await new ProcessSocket(this.dataPlane.baseUrl, this.dataPlane.token, '/runtime/v1/process', opts.requestTimeoutMs ?? this.config.requestTimeoutMs).connect();
|
|
182
|
-
const environment = { ...this.sandboxEnvs, ...(opts.
|
|
181
|
+
const socket = await new ProcessSocket(this.dataPlane.baseUrl, this.dataPlane.token, '/runtime/v1/process', opts.requestTimeoutMs ?? this.config.requestTimeoutMs, this.config.headers).connect();
|
|
182
|
+
const environment = { ...this.sandboxEnvs, ...(opts.envs ?? {}) };
|
|
183
183
|
const processConfig = processStartConfig(cmd, opts);
|
|
184
184
|
socket.sendJson({
|
|
185
185
|
type: 'start',
|
|
186
186
|
id: opts.processID,
|
|
187
187
|
cmd: processConfig.cmd,
|
|
188
188
|
args: processConfig.args,
|
|
189
|
-
cwd: opts.cwd
|
|
189
|
+
cwd: opts.cwd,
|
|
190
190
|
user: opts.user,
|
|
191
191
|
environment,
|
|
192
192
|
envs: environment,
|
|
193
193
|
stdin: opts.stdin ?? false,
|
|
194
|
-
timeout_ms: opts.timeoutMs ??
|
|
194
|
+
timeout_ms: opts.timeoutMs ?? 60_000,
|
|
195
195
|
});
|
|
196
196
|
const first = await nextStarted(socket);
|
|
197
197
|
const pid = framePid(first);
|
|
@@ -6,9 +6,14 @@ export interface ConnectionOpts {
|
|
|
6
6
|
accessToken?: string;
|
|
7
7
|
domain?: string;
|
|
8
8
|
apiUrl?: string;
|
|
9
|
+
/** Absolute sandbox data-plane URL override, primarily for local runtimes. */
|
|
10
|
+
sandboxUrl?: string;
|
|
9
11
|
dataPlaneDomain?: string;
|
|
10
12
|
requestTimeoutMs?: number;
|
|
11
13
|
headers?: Record<string, string>;
|
|
14
|
+
apiHeaders?: Record<string, string>;
|
|
15
|
+
debug?: boolean;
|
|
16
|
+
signal?: AbortSignal;
|
|
12
17
|
proxy?: unknown;
|
|
13
18
|
}
|
|
14
19
|
/** Resolved connection settings used by control-plane and data-plane clients. */
|
|
@@ -16,11 +21,30 @@ export declare class ConnectionConfig {
|
|
|
16
21
|
readonly apiKey?: string;
|
|
17
22
|
readonly domain: string;
|
|
18
23
|
readonly apiUrl: string;
|
|
24
|
+
/** Absolute sandbox data-plane URL override, primarily for local runtimes. */
|
|
25
|
+
readonly sandboxUrl?: string;
|
|
19
26
|
readonly dataPlaneDomain: string;
|
|
20
27
|
readonly requestTimeoutMs: number;
|
|
21
28
|
readonly headers: Record<string, string>;
|
|
29
|
+
readonly apiHeaders: Record<string, string>;
|
|
30
|
+
readonly debug: boolean;
|
|
31
|
+
readonly signal?: AbortSignal;
|
|
22
32
|
readonly proxy?: unknown;
|
|
23
33
|
constructor(opts?: ConnectionOpts);
|
|
24
34
|
/** HTTP headers including the configured bearer token. */
|
|
25
35
|
get authHeaders(): Record<string, string>;
|
|
36
|
+
/** Return an abort signal that follows the caller signal and optional timeout. */
|
|
37
|
+
getSignal(requestTimeoutMs?: number, signal?: AbortSignal | undefined): AbortSignal | undefined;
|
|
38
|
+
/** Return the sandbox data-plane API URL for a Watasu route token. */
|
|
39
|
+
getSandboxUrl(sandboxId: string, opts: {
|
|
40
|
+
sandboxDomain?: string;
|
|
41
|
+
envdPort: number;
|
|
42
|
+
}): string;
|
|
43
|
+
/** Return the direct sandbox data-plane API URL for a Watasu route token. */
|
|
44
|
+
getSandboxDirectUrl(sandboxId: string, opts: {
|
|
45
|
+
sandboxDomain?: string;
|
|
46
|
+
envdPort: number;
|
|
47
|
+
}): string;
|
|
48
|
+
/** Return the public hostname for a Watasu sandbox route token and port. */
|
|
49
|
+
getHost(sandboxId: string, port: number, sandboxDomain?: string): string;
|
|
26
50
|
}
|
package/dist/connectionConfig.js
CHANGED
|
@@ -5,9 +5,14 @@ export class ConnectionConfig {
|
|
|
5
5
|
apiKey;
|
|
6
6
|
domain;
|
|
7
7
|
apiUrl;
|
|
8
|
+
/** Absolute sandbox data-plane URL override, primarily for local runtimes. */
|
|
9
|
+
sandboxUrl;
|
|
8
10
|
dataPlaneDomain;
|
|
9
11
|
requestTimeoutMs;
|
|
10
12
|
headers;
|
|
13
|
+
apiHeaders;
|
|
14
|
+
debug;
|
|
15
|
+
signal;
|
|
11
16
|
proxy;
|
|
12
17
|
constructor(opts = {}) {
|
|
13
18
|
const env = typeof process !== 'undefined' ? process.env : {};
|
|
@@ -18,18 +23,60 @@ export class ConnectionConfig {
|
|
|
18
23
|
this.domain = opts.domain ?? env.WATASU_DOMAIN ?? 'watasu.io';
|
|
19
24
|
this.apiUrl =
|
|
20
25
|
opts.apiUrl ?? env.WATASU_API_URL ?? `https://api.${this.domain}/v1`;
|
|
26
|
+
this.sandboxUrl =
|
|
27
|
+
opts.sandboxUrl ??
|
|
28
|
+
env.WATASU_SANDBOX_URL;
|
|
21
29
|
this.dataPlaneDomain =
|
|
22
30
|
opts.dataPlaneDomain ??
|
|
23
31
|
env.WATASU_DATA_PLANE_DOMAIN ??
|
|
24
32
|
'watasuhost.com';
|
|
25
33
|
this.requestTimeoutMs = opts.requestTimeoutMs ?? 60_000;
|
|
26
34
|
this.headers = opts.headers ?? {};
|
|
35
|
+
this.apiHeaders = opts.apiHeaders ?? {};
|
|
36
|
+
this.debug = opts.debug ?? false;
|
|
37
|
+
this.signal = opts.signal;
|
|
27
38
|
this.proxy = opts.proxy;
|
|
28
39
|
}
|
|
29
40
|
/** HTTP headers including the configured bearer token. */
|
|
30
41
|
get authHeaders() {
|
|
31
42
|
return this.apiKey
|
|
32
|
-
? { ...this.headers, Authorization: `Bearer ${this.apiKey}` }
|
|
33
|
-
: { ...this.headers };
|
|
43
|
+
? { ...this.headers, ...this.apiHeaders, Authorization: `Bearer ${this.apiKey}` }
|
|
44
|
+
: { ...this.headers, ...this.apiHeaders };
|
|
45
|
+
}
|
|
46
|
+
/** Return an abort signal that follows the caller signal and optional timeout. */
|
|
47
|
+
getSignal(requestTimeoutMs = this.requestTimeoutMs, signal = this.signal) {
|
|
48
|
+
if (requestTimeoutMs === undefined && signal === undefined)
|
|
49
|
+
return undefined;
|
|
50
|
+
const controller = new AbortController();
|
|
51
|
+
if (signal?.aborted)
|
|
52
|
+
controller.abort();
|
|
53
|
+
else
|
|
54
|
+
signal?.addEventListener('abort', () => controller.abort(), { once: true });
|
|
55
|
+
if (requestTimeoutMs > 0) {
|
|
56
|
+
const timeout = setTimeout(() => controller.abort(), requestTimeoutMs);
|
|
57
|
+
const maybeTimeout = timeout;
|
|
58
|
+
if (typeof maybeTimeout.unref === 'function')
|
|
59
|
+
maybeTimeout.unref();
|
|
60
|
+
controller.signal.addEventListener('abort', () => clearTimeout(timeout), { once: true });
|
|
61
|
+
}
|
|
62
|
+
return controller.signal;
|
|
63
|
+
}
|
|
64
|
+
/** Return the sandbox data-plane API URL for a Watasu route token. */
|
|
65
|
+
getSandboxUrl(sandboxId, opts) {
|
|
66
|
+
if (this.sandboxUrl)
|
|
67
|
+
return this.sandboxUrl;
|
|
68
|
+
if (this.debug)
|
|
69
|
+
return `http://localhost:${opts.envdPort}`;
|
|
70
|
+
return `https://${sandboxId}.sandbox.${opts.sandboxDomain ?? this.dataPlaneDomain}`;
|
|
71
|
+
}
|
|
72
|
+
/** Return the direct sandbox data-plane API URL for a Watasu route token. */
|
|
73
|
+
getSandboxDirectUrl(sandboxId, opts) {
|
|
74
|
+
return this.getSandboxUrl(sandboxId, opts);
|
|
75
|
+
}
|
|
76
|
+
/** Return the public hostname for a Watasu sandbox route token and port. */
|
|
77
|
+
getHost(sandboxId, port, sandboxDomain = this.dataPlaneDomain) {
|
|
78
|
+
if (this.debug)
|
|
79
|
+
return `localhost:${port}`;
|
|
80
|
+
return `p${port}-${sandboxId}.sandbox.${sandboxDomain}`;
|
|
34
81
|
}
|
|
35
82
|
}
|
package/dist/filesystem.d.ts
CHANGED
|
@@ -40,6 +40,7 @@ export interface WatchOpts {
|
|
|
40
40
|
}
|
|
41
41
|
export interface FilesystemRequestOpts {
|
|
42
42
|
requestTimeoutMs?: number;
|
|
43
|
+
signal?: AbortSignal;
|
|
43
44
|
user?: string;
|
|
44
45
|
}
|
|
45
46
|
export interface FilesystemReadOpts extends FilesystemRequestOpts {
|
|
@@ -56,8 +57,6 @@ export declare class WatchHandle {
|
|
|
56
57
|
constructor(socket: ProcessSocket, events: AsyncIterable<ProcessFrame>, onEvent: (event: FilesystemEvent) => void | Promise<void>, onExit?: (error?: Error) => void | Promise<void>);
|
|
57
58
|
/** Stop watching the directory. */
|
|
58
59
|
stop(): void;
|
|
59
|
-
/** Alias for `stop`. */
|
|
60
|
-
close(): void;
|
|
61
60
|
/** Resolves when the watcher stream exits. */
|
|
62
61
|
wait(): Promise<void>;
|
|
63
62
|
private pump;
|
|
@@ -102,30 +101,19 @@ export declare class Filesystem {
|
|
|
102
101
|
/** Write several files in one runtime API call. */
|
|
103
102
|
writeFiles(files: WriteEntry[], opts?: FilesystemWriteOpts): Promise<WriteInfo[]>;
|
|
104
103
|
/** List directory entries below `path`. */
|
|
105
|
-
list(path: string, opts?: {
|
|
106
|
-
requestTimeoutMs?: number;
|
|
104
|
+
list(path: string, opts?: FilesystemRequestOpts & {
|
|
107
105
|
depth?: number;
|
|
108
106
|
}): Promise<EntryInfo[]>;
|
|
109
107
|
/** Return whether a file or directory exists at `path`. */
|
|
110
|
-
exists(path: string, opts?:
|
|
111
|
-
requestTimeoutMs?: number;
|
|
112
|
-
}): Promise<boolean>;
|
|
108
|
+
exists(path: string, opts?: FilesystemRequestOpts): Promise<boolean>;
|
|
113
109
|
/** Return stat metadata for `path`. */
|
|
114
|
-
getInfo(path: string, opts?:
|
|
115
|
-
requestTimeoutMs?: number;
|
|
116
|
-
}): Promise<EntryInfo>;
|
|
110
|
+
getInfo(path: string, opts?: FilesystemRequestOpts): Promise<EntryInfo>;
|
|
117
111
|
/** Remove a file at `path`. */
|
|
118
|
-
remove(path: string, opts?:
|
|
119
|
-
requestTimeoutMs?: number;
|
|
120
|
-
}): Promise<void>;
|
|
112
|
+
remove(path: string, opts?: FilesystemRequestOpts): Promise<void>;
|
|
121
113
|
/** Move or rename a file. */
|
|
122
|
-
rename(oldPath: string, newPath: string, opts?:
|
|
123
|
-
requestTimeoutMs?: number;
|
|
124
|
-
}): Promise<EntryInfo>;
|
|
114
|
+
rename(oldPath: string, newPath: string, opts?: FilesystemRequestOpts): Promise<EntryInfo>;
|
|
125
115
|
/** Create a directory. */
|
|
126
|
-
makeDir(path: string, opts?:
|
|
127
|
-
requestTimeoutMs?: number;
|
|
128
|
-
}): Promise<boolean>;
|
|
116
|
+
makeDir(path: string, opts?: FilesystemRequestOpts): Promise<boolean>;
|
|
129
117
|
/** Start watching a directory for filesystem events. */
|
|
130
118
|
watchDir(path: string): FilesystemWatcher;
|
|
131
119
|
watchDir(path: string, onEvent: (event: FilesystemEvent) => void | Promise<void>, opts?: WatchOpts): Promise<FilesystemWatcher>;
|
package/dist/filesystem.js
CHANGED
|
@@ -22,10 +22,6 @@ export class WatchHandle {
|
|
|
22
22
|
stop() {
|
|
23
23
|
this.socket.close();
|
|
24
24
|
}
|
|
25
|
-
/** Alias for `stop`. */
|
|
26
|
-
close() {
|
|
27
|
-
this.stop();
|
|
28
|
-
}
|
|
29
25
|
/** Resolves when the watcher stream exits. */
|
|
30
26
|
wait() {
|
|
31
27
|
return this.done;
|
|
@@ -66,7 +62,7 @@ export class FilesystemWatcher {
|
|
|
66
62
|
if (this.handle)
|
|
67
63
|
return;
|
|
68
64
|
const nextOpts = { ...this.opts, ...opts };
|
|
69
|
-
const socket = await new ProcessSocket(this.dataPlane.baseUrl, this.dataPlane.token, withQuery('/runtime/v1/files/watch', { path: this.path, recursive: nextOpts.recursive ?? false, include_entry: nextOpts.includeEntry }), nextOpts.requestTimeoutMs).connect();
|
|
65
|
+
const socket = await new ProcessSocket(this.dataPlane.baseUrl, this.dataPlane.token, withQuery('/runtime/v1/files/watch', { path: this.path, recursive: nextOpts.recursive ?? false, include_entry: nextOpts.includeEntry }), nextOpts.requestTimeoutMs, this.dataPlane.headers).connect();
|
|
70
66
|
this.handle = new WatchHandle(socket, socket, async (event) => {
|
|
71
67
|
for (const listener of this.listeners)
|
|
72
68
|
await listener(event);
|
package/dist/git.d.ts
CHANGED
|
@@ -20,16 +20,15 @@ export interface GitAuthOpts {
|
|
|
20
20
|
envs?: Record<string, string>;
|
|
21
21
|
user?: string;
|
|
22
22
|
cwd?: string;
|
|
23
|
-
timeout?: number;
|
|
24
23
|
timeoutMs?: number;
|
|
25
24
|
requestTimeoutMs?: number;
|
|
25
|
+
signal?: AbortSignal;
|
|
26
26
|
}
|
|
27
27
|
export interface GitCloneOpts extends GitAuthOpts {
|
|
28
28
|
path?: string;
|
|
29
29
|
branch?: string;
|
|
30
30
|
depth?: number;
|
|
31
31
|
recursive?: boolean;
|
|
32
|
-
submodules?: boolean;
|
|
33
32
|
dangerouslyStoreCredentials?: boolean;
|
|
34
33
|
}
|
|
35
34
|
export interface GitRequestOpts extends GitAuthOpts {
|
package/dist/git.js
CHANGED
|
@@ -9,7 +9,7 @@ export class Git {
|
|
|
9
9
|
return this.run('/runtime/v1/git/clone', {
|
|
10
10
|
url,
|
|
11
11
|
...gitOpts(opts),
|
|
12
|
-
...pick(opts, ['path', 'branch', 'depth', 'recursive', '
|
|
12
|
+
...pick(opts, ['path', 'branch', 'depth', 'recursive', 'username', 'password']),
|
|
13
13
|
dangerously_store_credentials: opts.dangerouslyStoreCredentials,
|
|
14
14
|
}, opts);
|
|
15
15
|
}
|
|
@@ -163,7 +163,11 @@ export class Git {
|
|
|
163
163
|
return String(result.value ?? '');
|
|
164
164
|
}
|
|
165
165
|
async run(path, json, opts) {
|
|
166
|
-
const payload = await this.dataPlane.postJson(path, {
|
|
166
|
+
const payload = await this.dataPlane.postJson(path, {
|
|
167
|
+
json: compact(json),
|
|
168
|
+
requestTimeoutMs: opts.requestTimeoutMs,
|
|
169
|
+
signal: opts.signal,
|
|
170
|
+
});
|
|
167
171
|
return gitResult(payload.git ?? payload);
|
|
168
172
|
}
|
|
169
173
|
}
|
|
@@ -172,7 +176,7 @@ function gitOpts(opts) {
|
|
|
172
176
|
env_vars: opts.envs,
|
|
173
177
|
user: opts.user,
|
|
174
178
|
cwd: opts.cwd,
|
|
175
|
-
timeout_seconds: opts.
|
|
179
|
+
timeout_seconds: opts.timeoutMs === undefined ? undefined : Math.ceil(opts.timeoutMs / 1000),
|
|
176
180
|
};
|
|
177
181
|
}
|
|
178
182
|
function pick(source, keys) {
|
package/dist/index.d.ts
CHANGED
|
@@ -2,7 +2,7 @@ export { ApiError, AuthenticationError, ConflictError, FileNotFoundError, Invali
|
|
|
2
2
|
export { ConnectionConfig, KEEPALIVE_PING_INTERVAL_SEC } from './connectionConfig.js';
|
|
3
3
|
export { Sandbox, SandboxPaginator, SnapshotPaginator } from './sandbox.js';
|
|
4
4
|
export { Sandbox as CodeInterpreterSandbox } from './codeInterpreter.js';
|
|
5
|
-
export type { CreateSnapshotOpts, RestoreSnapshotOpts, SandboxCreateOpts, SandboxConnectOpts, SandboxInfo, SandboxListOpts, SandboxMetrics, McpServer, McpServerName, SandboxNetworkSelector, SandboxNetworkUpdate, SandboxNetworkUpdateOpts, SandboxUrlOpts, SnapshotInfo, FileUrlInfo, } from './sandbox.js';
|
|
5
|
+
export type { CreateSnapshotOpts, RestoreSnapshotOpts, SandboxCreateOpts, SandboxConnectOpts, SandboxInfo, SandboxInfoLifecycle, SandboxLifecycle, SandboxListOpts, SandboxMetrics, SandboxMetricsOpts, McpServer, McpServerName, SandboxNetworkSelector, SandboxNetworkUpdate, SandboxNetworkUpdateOpts, SandboxUrlOpts, SnapshotInfo, FileUrlInfo, } from './sandbox.js';
|
|
6
6
|
export type { CreateCodeContextOpts, RunCodeLanguage, RunCodeOpts, } from './codeInterpreter.js';
|
|
7
7
|
export { Context as CodeInterpreterContext, Execution as CodeInterpreterExecution, ExecutionError as CodeInterpreterExecutionError, OutputMessage as CodeInterpreterOutputMessage, Result as CodeInterpreterResult, } from './codeInterpreter.js';
|
|
8
8
|
export { CommandExitError, CommandHandle, Commands } from './commands.js';
|
|
@@ -17,6 +17,8 @@ export { Pty } from './pty.js';
|
|
|
17
17
|
export type { PtyConnectOpts, PtyCreateOpts, PtySize } from './pty.js';
|
|
18
18
|
export { Terminal, TerminalManager, TerminalOutput } from './terminal.js';
|
|
19
19
|
export type { TerminalOpts } from './terminal.js';
|
|
20
|
+
export { Volume } from './volume.js';
|
|
21
|
+
export type { VolumeApiParams, VolumeConnectionConfig, VolumeEntryStat, VolumeFileType, VolumeInfo, VolumeListFilesOpts, VolumeListOpts, VolumeMetadataOpts, VolumeReadFileOpts, VolumeReadFormat, VolumeWriteData, VolumeWriteFileOpts, } from './volume.js';
|
|
20
22
|
export { ProcessSocket, base64DecodeBytes, base64DecodeText, base64Encode } from './processSocket.js';
|
|
21
|
-
export { ReadyCmd, Template, TemplateBase, waitForFile, waitForPort, waitForProcess, waitForTimeout, waitForURL,
|
|
23
|
+
export { ReadyCmd, Template, TemplateBase, waitForFile, waitForPort, waitForProcess, waitForTimeout, waitForURL, } from './template.js';
|
|
22
24
|
export type { BuildInfo, BuildOptions, BuildStatusReason, CopyItem, GetBuildStatusOptions, LogEntry, ReadyCommand, TemplateBuildStatus, TemplateBuildStatusResponse, TemplateBuilder, TemplateClass, TemplateFactory, TemplateFinal, TemplateFromImage, TemplateOptions, TemplateTag, TemplateTagInfo, } from './template.js';
|
package/dist/index.js
CHANGED
|
@@ -9,5 +9,6 @@ export { FileType, Filesystem, FilesystemWatcher, WatchHandle } from './filesyst
|
|
|
9
9
|
export { Git } from './git.js';
|
|
10
10
|
export { Pty } from './pty.js';
|
|
11
11
|
export { Terminal, TerminalManager, TerminalOutput } from './terminal.js';
|
|
12
|
+
export { Volume } from './volume.js';
|
|
12
13
|
export { ProcessSocket, base64DecodeBytes, base64DecodeText, base64Encode } from './processSocket.js';
|
|
13
|
-
export { ReadyCmd, Template, TemplateBase, waitForFile, waitForPort, waitForProcess, waitForTimeout, waitForURL,
|
|
14
|
+
export { ReadyCmd, Template, TemplateBase, waitForFile, waitForPort, waitForProcess, waitForTimeout, waitForURL, } from './template.js';
|
package/dist/process.d.ts
CHANGED
|
@@ -41,7 +41,7 @@ export declare class Process {
|
|
|
41
41
|
private waitPromise?;
|
|
42
42
|
constructor(processID: string, handle: CommandHandle, output: ProcessOutput, onExit?: ((exitCode: number) => Promise<void> | void) | undefined);
|
|
43
43
|
kill(): Promise<void>;
|
|
44
|
-
wait(
|
|
44
|
+
wait(timeoutMs?: number): Promise<ProcessOutput>;
|
|
45
45
|
private waitOnce;
|
|
46
46
|
sendStdin(data: string): Promise<void>;
|
|
47
47
|
}
|