@watasu/sdk 0.1.30 → 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 +3 -3
- package/dist/codeInterpreter.d.ts +27 -1
- package/dist/codeInterpreter.js +18 -1
- 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 +1 -1
- package/dist/index.js +1 -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 +10 -25
- package/dist/sandbox.js +55 -45
- 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 +0 -4
- package/dist/volume.js +20 -9
- 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())
|
|
@@ -152,12 +152,12 @@ const remoteUrl = await sbx.git.remoteGet('/workspace/project', 'origin')
|
|
|
152
152
|
await sbx.git.restore('/workspace/project', { paths: ['README.md'] })
|
|
153
153
|
await sbx.git.reset('/workspace/project', { mode: 'hard', target: 'HEAD' })
|
|
154
154
|
|
|
155
|
-
await sbx.
|
|
155
|
+
await sbx.files.writeFiles([
|
|
156
156
|
{ path: '/workspace/project/a.txt', data: 'alpha' },
|
|
157
157
|
{ path: '/workspace/project/b.bin', data: new Uint8Array([0, 1, 2]) },
|
|
158
158
|
])
|
|
159
159
|
|
|
160
|
-
const watcher = sbx.
|
|
160
|
+
const watcher = sbx.files.watchDir('/workspace/project')
|
|
161
161
|
watcher.addEventListener((event) => {
|
|
162
162
|
console.log(event.type, event.path)
|
|
163
163
|
})
|
|
@@ -1,4 +1,25 @@
|
|
|
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;
|
|
@@ -8,13 +29,15 @@ export interface RunCodeOpts {
|
|
|
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 {
|
|
@@ -88,13 +111,16 @@ export declare class Sandbox extends BaseSandbox {
|
|
|
88
111
|
/** Remove a persistent code context. */
|
|
89
112
|
removeCodeContext(context: Context | string, opts?: {
|
|
90
113
|
requestTimeoutMs?: number;
|
|
114
|
+
signal?: AbortSignal;
|
|
91
115
|
}): Promise<void>;
|
|
92
116
|
/** List persistent code contexts. */
|
|
93
117
|
listCodeContexts(opts?: {
|
|
94
118
|
requestTimeoutMs?: number;
|
|
119
|
+
signal?: AbortSignal;
|
|
95
120
|
}): Promise<Context[]>;
|
|
96
121
|
/** Restart a persistent code context. */
|
|
97
122
|
restartCodeContext(context: Context | string, opts?: {
|
|
98
123
|
requestTimeoutMs?: number;
|
|
124
|
+
signal?: AbortSignal;
|
|
99
125
|
}): Promise<void>;
|
|
100
126
|
}
|
package/dist/codeInterpreter.js
CHANGED
|
@@ -1,5 +1,17 @@
|
|
|
1
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);
|
|
@@ -177,6 +190,7 @@ export class Sandbox extends BaseSandbox {
|
|
|
177
190
|
language: _opts.language,
|
|
178
191
|
}), {
|
|
179
192
|
requestTimeoutMs: _opts.requestTimeoutMs,
|
|
193
|
+
signal: _opts.signal,
|
|
180
194
|
});
|
|
181
195
|
return contextFromApi(response);
|
|
182
196
|
}
|
|
@@ -184,12 +198,14 @@ export class Sandbox extends BaseSandbox {
|
|
|
184
198
|
async removeCodeContext(context, opts = {}) {
|
|
185
199
|
await this.runtimeDeleteJson(`/runtime/v1/code/contexts/${encodeURIComponent(requireContextId(context))}`, {
|
|
186
200
|
requestTimeoutMs: opts.requestTimeoutMs,
|
|
201
|
+
signal: opts.signal,
|
|
187
202
|
});
|
|
188
203
|
}
|
|
189
204
|
/** List persistent code contexts. */
|
|
190
205
|
async listCodeContexts(opts = {}) {
|
|
191
206
|
const response = await this.runtimeGetJson('/runtime/v1/code/contexts', {
|
|
192
207
|
requestTimeoutMs: opts.requestTimeoutMs,
|
|
208
|
+
signal: opts.signal,
|
|
193
209
|
});
|
|
194
210
|
const contexts = Array.isArray(response) ? response : arrayOfUnknown(response.contexts);
|
|
195
211
|
return contexts.map((item) => contextFromApi(record(item)));
|
|
@@ -198,6 +214,7 @@ export class Sandbox extends BaseSandbox {
|
|
|
198
214
|
async restartCodeContext(context, opts = {}) {
|
|
199
215
|
await this.runtimePostJson(`/runtime/v1/code/contexts/${encodeURIComponent(requireContextId(context))}/restart`, {}, {
|
|
200
216
|
requestTimeoutMs: opts.requestTimeoutMs,
|
|
217
|
+
signal: opts.signal,
|
|
201
218
|
});
|
|
202
219
|
}
|
|
203
220
|
}
|
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
|
@@ -20,5 +20,5 @@ export type { TerminalOpts } from './terminal.js';
|
|
|
20
20
|
export { Volume } from './volume.js';
|
|
21
21
|
export type { VolumeApiParams, VolumeConnectionConfig, VolumeEntryStat, VolumeFileType, VolumeInfo, VolumeListFilesOpts, VolumeListOpts, VolumeMetadataOpts, VolumeReadFileOpts, VolumeReadFormat, VolumeWriteData, VolumeWriteFileOpts, } from './volume.js';
|
|
22
22
|
export { ProcessSocket, base64DecodeBytes, base64DecodeText, base64Encode } from './processSocket.js';
|
|
23
|
-
export { ReadyCmd, Template, TemplateBase, waitForFile, waitForPort, waitForProcess, waitForTimeout, waitForURL,
|
|
23
|
+
export { ReadyCmd, Template, TemplateBase, waitForFile, waitForPort, waitForProcess, waitForTimeout, waitForURL, } from './template.js';
|
|
24
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
|
@@ -11,4 +11,4 @@ export { Pty } from './pty.js';
|
|
|
11
11
|
export { Terminal, TerminalManager, TerminalOutput } from './terminal.js';
|
|
12
12
|
export { Volume } from './volume.js';
|
|
13
13
|
export { ProcessSocket, base64DecodeBytes, base64DecodeText, base64Encode } from './processSocket.js';
|
|
14
|
-
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
|
}
|
package/dist/process.js
CHANGED
|
@@ -67,10 +67,10 @@ export class Process {
|
|
|
67
67
|
async kill() {
|
|
68
68
|
await this.handle.kill();
|
|
69
69
|
}
|
|
70
|
-
async wait(
|
|
70
|
+
async wait(timeoutMs) {
|
|
71
71
|
if (!this.waitPromise)
|
|
72
72
|
this.waitPromise = this.waitOnce();
|
|
73
|
-
return waitFor(this.waitPromise,
|
|
73
|
+
return waitFor(this.waitPromise, timeoutMs);
|
|
74
74
|
}
|
|
75
75
|
async waitOnce() {
|
|
76
76
|
try {
|
|
@@ -126,7 +126,7 @@ export class ProcessManager {
|
|
|
126
126
|
}
|
|
127
127
|
async startAndWait(cmdOrOpts) {
|
|
128
128
|
const process = await this.start(cmdOrOpts);
|
|
129
|
-
return process.wait(typeof cmdOrOpts === 'string' ? undefined : cmdOrOpts.
|
|
129
|
+
return process.wait(typeof cmdOrOpts === 'string' ? undefined : cmdOrOpts.timeoutMs);
|
|
130
130
|
}
|
|
131
131
|
}
|
|
132
132
|
function processOpts(cmdOrOpts) {
|
package/dist/processSocket.d.ts
CHANGED
|
@@ -5,12 +5,13 @@ export declare class ProcessSocket implements AsyncIterable<ProcessFrame> {
|
|
|
5
5
|
private readonly token;
|
|
6
6
|
private readonly path;
|
|
7
7
|
private readonly requestTimeoutMs;
|
|
8
|
+
private readonly headers;
|
|
8
9
|
private ws?;
|
|
9
10
|
private queue;
|
|
10
11
|
private waiters;
|
|
11
12
|
private closed;
|
|
12
13
|
private keepalive?;
|
|
13
|
-
constructor(baseUrl: string, token: string, path: string, requestTimeoutMs?: number);
|
|
14
|
+
constructor(baseUrl: string, token: string, path: string, requestTimeoutMs?: number, headers?: Record<string, string>);
|
|
14
15
|
connect(): Promise<this>;
|
|
15
16
|
sendJson(payload: ProcessFrame): void;
|
|
16
17
|
sendStdin(data: string | Uint8Array): void;
|
package/dist/processSocket.js
CHANGED
|
@@ -8,20 +8,22 @@ export class ProcessSocket {
|
|
|
8
8
|
token;
|
|
9
9
|
path;
|
|
10
10
|
requestTimeoutMs;
|
|
11
|
+
headers;
|
|
11
12
|
ws;
|
|
12
13
|
queue = [];
|
|
13
14
|
waiters = [];
|
|
14
15
|
closed = false;
|
|
15
16
|
keepalive;
|
|
16
|
-
constructor(baseUrl, token, path, requestTimeoutMs = 60_000) {
|
|
17
|
+
constructor(baseUrl, token, path, requestTimeoutMs = 60_000, headers = {}) {
|
|
17
18
|
this.baseUrl = baseUrl;
|
|
18
19
|
this.token = token;
|
|
19
20
|
this.path = path;
|
|
20
21
|
this.requestTimeoutMs = requestTimeoutMs;
|
|
22
|
+
this.headers = headers;
|
|
21
23
|
}
|
|
22
24
|
async connect() {
|
|
23
25
|
const ws = new WebSocket(wsUrl(this.baseUrl, this.path), {
|
|
24
|
-
headers: { Authorization: `Bearer ${this.token}` },
|
|
26
|
+
headers: { ...this.headers, Authorization: `Bearer ${this.token}` },
|
|
25
27
|
});
|
|
26
28
|
this.ws = ws;
|
|
27
29
|
ws.on('message', (data) => this.onMessage(data));
|
package/dist/pty.d.ts
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { CommandHandle, CommandStartOpts } from './commands.js';
|
|
2
|
-
import { ConnectionConfig } from './connectionConfig.js';
|
|
2
|
+
import { ConnectionConfig, type ConnectionOpts } from './connectionConfig.js';
|
|
3
3
|
import { DataPlaneClient } from './transport.js';
|
|
4
4
|
export interface PtySize {
|
|
5
5
|
cols: number;
|
|
@@ -28,10 +28,10 @@ export declare class Pty {
|
|
|
28
28
|
connect(pid: number | string, opts?: PtyConnectOpts): Promise<CommandHandle>;
|
|
29
29
|
/** Send input bytes or text to a PTY. */
|
|
30
30
|
sendStdin(pid: number | string, data: string | Uint8Array, opts?: PtyConnectOpts): Promise<void>;
|
|
31
|
-
/**
|
|
31
|
+
/** Send input bytes or text to a PTY. */
|
|
32
32
|
sendInput(pid: number | string, data: string | Uint8Array, opts?: PtyConnectOpts): Promise<void>;
|
|
33
33
|
/** Resize a running PTY. */
|
|
34
34
|
resize(pid: number | string, size: PtySize, opts?: PtyConnectOpts): Promise<void>;
|
|
35
35
|
/** Kill a running PTY. */
|
|
36
|
-
kill(pid: number | string): Promise<boolean>;
|
|
36
|
+
kill(pid: number | string, opts?: Pick<ConnectionOpts, 'requestTimeoutMs' | 'signal'>): Promise<boolean>;
|
|
37
37
|
}
|
package/dist/pty.js
CHANGED
|
@@ -11,21 +11,21 @@ export class Pty {
|
|
|
11
11
|
}
|
|
12
12
|
/** Create an interactive shell PTY and return its live command handle. */
|
|
13
13
|
async create(opts) {
|
|
14
|
-
const socket = await new ProcessSocket(this.dataPlane.baseUrl, this.dataPlane.token, '/runtime/v1/process', opts.requestTimeoutMs ?? this.config.requestTimeoutMs).connect();
|
|
15
|
-
const envs = { TERM: 'xterm-256color', LANG: 'C.UTF-8', LC_ALL: 'C.UTF-8', ...(opts.
|
|
14
|
+
const socket = await new ProcessSocket(this.dataPlane.baseUrl, this.dataPlane.token, '/runtime/v1/process', opts.requestTimeoutMs ?? this.config.requestTimeoutMs, this.config.headers).connect();
|
|
15
|
+
const envs = { TERM: 'xterm-256color', LANG: 'C.UTF-8', LC_ALL: 'C.UTF-8', ...(opts.envs ?? {}) };
|
|
16
16
|
const size = opts.size ?? { cols: opts.cols ?? 80, rows: opts.rows ?? 24 };
|
|
17
17
|
const args = opts.cmd === undefined ? ['-i', '-l'] : ['-l', '-c', opts.cmd];
|
|
18
18
|
socket.sendJson({
|
|
19
19
|
type: 'start',
|
|
20
20
|
cmd: '/bin/bash',
|
|
21
21
|
args,
|
|
22
|
-
cwd: opts.cwd
|
|
22
|
+
cwd: opts.cwd,
|
|
23
23
|
user: opts.user,
|
|
24
24
|
environment: envs,
|
|
25
25
|
envs,
|
|
26
26
|
stdin: true,
|
|
27
27
|
pty: { cols: size.cols, rows: size.rows },
|
|
28
|
-
timeout_ms: opts.timeoutMs ??
|
|
28
|
+
timeout_ms: opts.timeoutMs ?? 60_000,
|
|
29
29
|
});
|
|
30
30
|
const first = await nextStarted(socket);
|
|
31
31
|
const pid = framePid(first);
|
|
@@ -35,7 +35,7 @@ export class Pty {
|
|
|
35
35
|
}
|
|
36
36
|
/** Connect to a running PTY by pid. */
|
|
37
37
|
async connect(pid, opts = {}) {
|
|
38
|
-
const socket = await new ProcessSocket(this.dataPlane.baseUrl, this.dataPlane.token, `/runtime/v1/process/${pid}/connect?since=0`, opts.requestTimeoutMs ?? this.config.requestTimeoutMs).connect();
|
|
38
|
+
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();
|
|
39
39
|
const first = await nextStarted(socket);
|
|
40
40
|
const actualPid = framePid(first) ?? pid;
|
|
41
41
|
return new CommandHandle(actualPid, socket, () => this.kill(actualPid), withFirst(first, socket), undefined, undefined, opts.onData);
|
|
@@ -50,7 +50,7 @@ export class Pty {
|
|
|
50
50
|
await handle.disconnect();
|
|
51
51
|
}
|
|
52
52
|
}
|
|
53
|
-
/**
|
|
53
|
+
/** Send input bytes or text to a PTY. */
|
|
54
54
|
async sendInput(pid, data, opts = {}) {
|
|
55
55
|
return this.sendStdin(pid, data, opts);
|
|
56
56
|
}
|
|
@@ -65,9 +65,11 @@ export class Pty {
|
|
|
65
65
|
}
|
|
66
66
|
}
|
|
67
67
|
/** Kill a running PTY. */
|
|
68
|
-
async kill(pid) {
|
|
68
|
+
async kill(pid, opts = {}) {
|
|
69
69
|
await this.dataPlane.postJson(`/runtime/v1/process/${pid}/signal`, {
|
|
70
70
|
json: { signal: 'SIGKILL' },
|
|
71
|
+
requestTimeoutMs: opts.requestTimeoutMs,
|
|
72
|
+
signal: opts.signal,
|
|
71
73
|
});
|
|
72
74
|
return true;
|
|
73
75
|
}
|