@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 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.filesystem.write('/home/user/a.js', 'console.log(2 + 2)')
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.filesystem.writeFiles([
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.filesystem.watchDir('/workspace/project')
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
- timeout?: number;
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
  }
@@ -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
- timeout_seconds: opts.timeout,
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
  }
@@ -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 ?? opts.timeout);
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.envVars ?? opts.envs ?? {}) };
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 ?? opts.rootDir,
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 ?? opts.timeout ?? 60_000,
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
  }
@@ -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
  }
@@ -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>;
@@ -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', 'submodules', 'username', 'password']),
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, { json: compact(json), requestTimeoutMs: opts.requestTimeoutMs });
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.timeout ?? (opts.timeoutMs === undefined ? undefined : Math.ceil(opts.timeoutMs / 1000)),
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, waitForUrl, } from './template.js';
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, waitForUrl, } from './template.js';
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(timeout?: number): Promise<ProcessOutput>;
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(timeout) {
70
+ async wait(timeoutMs) {
71
71
  if (!this.waitPromise)
72
72
  this.waitPromise = this.waitOnce();
73
- return waitFor(this.waitPromise, timeout);
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.timeout);
129
+ return process.wait(typeof cmdOrOpts === 'string' ? undefined : cmdOrOpts.timeoutMs);
130
130
  }
131
131
  }
132
132
  function processOpts(cmdOrOpts) {
@@ -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;
@@ -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
- /** Alias for `sendStdin`. */
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.envVars ?? opts.envs ?? {}) };
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 ?? opts.rootDir,
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 ?? opts.timeout ?? 60_000,
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
- /** Alias for `sendStdin`. */
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
  }