@watasu/sdk 0.1.30 → 0.1.50

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())
@@ -71,7 +71,7 @@ await volume.destroy()
71
71
  ## Code Interpreter
72
72
 
73
73
  ```ts
74
- import { Sandbox } from '@watasu/sdk/code-interpreter'
74
+ import { Sandbox } from '@watasu/code-interpreter'
75
75
 
76
76
  const sbx = await Sandbox.create()
77
77
  const context = await sbx.createCodeContext()
@@ -85,7 +85,7 @@ await sbx.removeCodeContext(context)
85
85
  await sbx.kill()
86
86
  ```
87
87
 
88
- `@watasu/sdk/code-interpreter` starts the `code-interpreter` template by default.
88
+ `@watasu/code-interpreter` starts the `code-interpreter` template by default.
89
89
  Code runs in persistent Python contexts and returns structured `results`, `logs`,
90
90
  and `error` fields for each execution.
91
91
 
@@ -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
  })
@@ -182,15 +182,21 @@ await sbx.kill()
182
182
  ```ts
183
183
  const sbx = await Sandbox.create({
184
184
  network: {
185
- allowOut: ['pypi.org:443'],
185
+ allowOut: ({ rules }) => [...rules.keys(), 'pypi.org:443'],
186
186
  denyOut: ['169.254.169.254'],
187
+ rules: {
188
+ 'api.example.com': [
189
+ { transform: { headers: { authorization: 'Bearer token' } } },
190
+ ],
191
+ },
192
+ maskRequestHost: '${PORT}-sandbox.example.com',
187
193
  },
188
194
  })
189
195
 
190
196
  await sbx.updateNetwork({
191
197
  allowInternetAccess: false,
192
198
  allowPackageRegistryAccess: true,
193
- allowOut: ['pypi.org:443', 'registry.npmjs.org:443'],
199
+ allowOut: ['registry.npmjs.org:443'],
194
200
  })
195
201
  ```
196
202
 
@@ -1,21 +1,136 @@
1
1
  import { Sandbox as BaseSandbox, SandboxConnectOpts, SandboxCreateOpts } from './sandbox.js';
2
- export type RunCodeLanguage = 'python' | 'python3' | string;
2
+ export { ApiError, AuthenticationError, BuildError, ConflictError, FileNotFoundError, FileUploadError, GitAuthError, GitUpstreamError, InvalidArgumentError, NotEnoughSpaceError, NotFoundError, NotImplementedError, RateLimitError, SandboxError, SandboxNotFoundError, TemplateError, TimeoutError, VolumeError, } from './errors.js';
3
+ export { ConnectionConfig, KEEPALIVE_PING_INTERVAL_SEC } from './connectionConfig.js';
4
+ export type { ConnectionOpts, Username } from './connectionConfig.js';
5
+ export { ControlClient as ApiClient } from './transport.js';
6
+ export { ALL_TRAFFIC, SandboxPaginator, SnapshotPaginator, getSignature, } from './sandbox.js';
7
+ export type { CreateSnapshotOpts, FileUrlInfo, McpServer, McpServerName, RestoreSnapshotOpts, SandboxApiOpts, SandboxConnectOpts, SandboxCreateOpts, SandboxInfo, SandboxInfoLifecycle, SandboxLifecycle, SandboxListOpts, SandboxMetrics, SandboxMetricsOpts, SandboxNetworkInfo, SandboxNetworkOpts, SandboxNetworkRule, SandboxNetworkRuleInfo, SandboxNetworkRules, SandboxNetworkSelector, SandboxNetworkSelectorContext, SandboxNetworkTransform, SandboxNetworkUpdate, SandboxNetworkUpdateOpts, SandboxOpts, SandboxState, SandboxUrlOpts, SignatureOpts, SnapshotInfo, SnapshotListOpts, } from './sandbox.js';
8
+ export { CommandExitError, CommandHandle, Commands } from './commands.js';
9
+ export type { CommandConnectOpts, CommandRequestOpts, CommandResult, CommandStartOpts, ProcessInfo, PtyOutput, Stderr, Stdout, } from './commands.js';
10
+ export { Process, ProcessManager, ProcessMessage, ProcessOutput } from './process.js';
11
+ export type { ProcessOpts } from './process.js';
12
+ export { FileType, Filesystem, FilesystemEventType, FilesystemWatcher, WatchHandle, } from './filesystem.js';
13
+ export type { EntryInfo, FilesystemEvent, FilesystemReadOpts, FilesystemRequestOpts, FilesystemWriteOpts, WatchOpts, WriteData, WriteEntry, WriteInfo, } from './filesystem.js';
14
+ export { Git } from './git.js';
15
+ export type { GitAddOpts, GitAuthOpts, GitBranches, GitBranchOpts, GitCloneOpts, GitCommandResult, GitCommitOpts, GitConfigScope, GitConfigOpts, GitConfigureUserOpts, GitCredentialOpts, GitDangerouslyAuthenticateOpts, GitDeleteBranchOpts, GitFileStatus, GitInitOpts, GitPullOpts, GitPushOpts, GitRemoteAddOpts, GitResetMode, GitResetOpts, GitRestoreOpts, GitStatus, } from './git.js';
16
+ export { Pty } from './pty.js';
17
+ export type { PtyConnectOpts, PtyCreateOpts, PtySize } from './pty.js';
18
+ export { Terminal, TerminalManager, TerminalOutput } from './terminal.js';
19
+ export type { TerminalOpts } from './terminal.js';
20
+ export { Volume, VolumeConnectionConfig, VolumeFileType } from './volume.js';
21
+ export type { VolumeAndToken, VolumeApiParams, VolumeApiOpts, VolumeEntryStat, VolumeInfo, VolumeListFilesOpts, VolumeListOpts, VolumeMetadataOpts, VolumeMetadataOptions, VolumeReadFileOpts, VolumeReadFormat, VolumeWriteData, VolumeWriteFileOpts, VolumeWriteOptions, } from './volume.js';
22
+ export { ProcessSocket, base64DecodeBytes, base64DecodeText, base64Encode } from './processSocket.js';
23
+ export { ReadyCmd, Template, TemplateBase, LogEntry, LogEntryEnd, LogEntryStart, defaultBuildLogger, waitForFile, waitForPort, waitForProcess, waitForTimeout, waitForURL, } from './template.js';
24
+ export type { BuildInfo, BuildOptions, BuildStatusReason, CopyItem, GetBuildStatusOptions, LogEntryLevel, Logger, ReadyCommand, TemplateBuilder, TemplateBuildStatus, TemplateBuildStatusResponse, TemplateClass, TemplateFactory, TemplateFinal, TemplateFromImage, TemplateOptions, TemplateTag, TemplateTagInfo, } from './template.js';
25
+ export type { components, paths } from './index.js';
26
+ export type RunCodeLanguage = 'python' | 'javascript' | 'typescript' | 'r' | 'java' | 'bash' | (string & {});
27
+ type OutputHandler<T> = (output: T) => Promise<unknown> | unknown;
3
28
  export interface RunCodeOpts {
4
- language?: RunCodeLanguage;
5
- context?: Context | string;
6
- onStdout?: (message: OutputMessage) => void;
7
- onStderr?: (message: OutputMessage) => void;
8
- onResult?: (result: Result) => void;
9
- onError?: (error: ExecutionError) => void;
29
+ onStdout?: OutputHandler<OutputMessage>;
30
+ onStderr?: OutputHandler<OutputMessage>;
31
+ onResult?: OutputHandler<Result>;
32
+ onError?: OutputHandler<ExecutionError>;
10
33
  envs?: Record<string, string>;
11
- timeout?: number;
34
+ timeoutMs?: number;
12
35
  requestTimeoutMs?: number;
36
+ signal?: AbortSignal;
13
37
  }
14
38
  export interface CreateCodeContextOpts {
15
39
  cwd?: string;
16
40
  language?: RunCodeLanguage;
17
41
  requestTimeoutMs?: number;
42
+ signal?: AbortSignal;
43
+ }
44
+ /** Chart types returned by code execution results. */
45
+ export declare enum ChartType {
46
+ LINE = "line",
47
+ SCATTER = "scatter",
48
+ BAR = "bar",
49
+ PIE = "pie",
50
+ BOX_AND_WHISKER = "box_and_whisker",
51
+ SUPERCHART = "superchart",
52
+ UNKNOWN = "unknown"
53
+ }
54
+ /** Axis scale types returned by chart results. */
55
+ export declare enum ScaleType {
56
+ LINEAR = "linear",
57
+ DATETIME = "datetime",
58
+ CATEGORICAL = "categorical",
59
+ LOG = "log",
60
+ SYMLOG = "symlog",
61
+ LOGIT = "logit",
62
+ FUNCTION = "function",
63
+ FUNCTIONLOG = "functionlog",
64
+ ASINH = "asinh"
18
65
  }
66
+ export type Chart = {
67
+ type: ChartType;
68
+ title: string;
69
+ elements: unknown[];
70
+ };
71
+ export type Chart2D = Chart & {
72
+ x_label?: string;
73
+ y_label?: string;
74
+ x_unit?: string;
75
+ y_unit?: string;
76
+ };
77
+ export type PointData = {
78
+ label: string;
79
+ points: [number | string, number | string][];
80
+ };
81
+ export type PointChart = Chart2D & {
82
+ x_ticks: (number | string)[];
83
+ x_scale: ScaleType;
84
+ x_tick_labels: string[];
85
+ y_ticks: (number | string)[];
86
+ y_scale: ScaleType;
87
+ y_tick_labels: string[];
88
+ elements: PointData[];
89
+ };
90
+ export type LineChart = PointChart & {
91
+ type: ChartType.LINE;
92
+ };
93
+ export type ScatterChart = PointChart & {
94
+ type: ChartType.SCATTER;
95
+ };
96
+ export type BarData = {
97
+ label: string;
98
+ value: string;
99
+ group: string;
100
+ };
101
+ export type BarChart = Chart2D & {
102
+ type: ChartType.BAR;
103
+ elements: BarData[];
104
+ };
105
+ export type PieData = {
106
+ label: string;
107
+ angle: number;
108
+ radius: number;
109
+ };
110
+ export type PieChart = Chart & {
111
+ type: ChartType.PIE;
112
+ elements: PieData[];
113
+ };
114
+ export type BoxAndWhiskerData = {
115
+ label: string;
116
+ min: number;
117
+ first_quartile: number;
118
+ median: number;
119
+ third_quartile: number;
120
+ max: number;
121
+ outliers: number[];
122
+ };
123
+ export type BoxAndWhiskerChart = Chart2D & {
124
+ type: ChartType.BOX_AND_WHISKER;
125
+ elements: BoxAndWhiskerData[];
126
+ };
127
+ export type SuperChart = Chart & {
128
+ type: ChartType.SUPERCHART;
129
+ elements: Chart[];
130
+ };
131
+ export type ChartTypes = LineChart | ScatterChart | BarChart | PieChart | BoxAndWhiskerChart | SuperChart;
132
+ export type MIMEType = string;
133
+ export type RawData = Record<string, unknown>;
19
134
  /** One stdout or stderr line emitted by code execution. */
20
135
  export declare class OutputMessage {
21
136
  readonly line: string;
@@ -35,6 +150,7 @@ export declare class ExecutionError {
35
150
  }
36
151
  /** Rich result produced by the last expression of a code execution. */
37
152
  export declare class Result {
153
+ readonly raw: RawData;
38
154
  readonly text?: string;
39
155
  readonly html?: string;
40
156
  readonly markdown?: string;
@@ -45,11 +161,11 @@ export declare class Result {
45
161
  readonly latex?: string;
46
162
  readonly json?: unknown;
47
163
  readonly javascript?: string;
48
- readonly data?: unknown;
49
- readonly chart?: unknown;
164
+ readonly data?: Record<string, unknown>;
165
+ readonly chart?: ChartTypes;
50
166
  readonly extra: Record<string, unknown>;
51
167
  readonly isMainResult: boolean;
52
- constructor(payload?: Record<string, unknown>);
168
+ constructor(payload?: RawData, isMainResult?: boolean);
53
169
  formats(): string[];
54
170
  toJSON(): Record<string, unknown>;
55
171
  }
@@ -70,9 +186,9 @@ export declare class Execution {
70
186
  /** Code execution context metadata. */
71
187
  export declare class Context {
72
188
  readonly id: string;
73
- readonly language?: string | undefined;
74
- readonly cwd?: string | undefined;
75
- constructor(id: string, language?: string | undefined, cwd?: string | undefined);
189
+ readonly language: string;
190
+ readonly cwd: string;
191
+ constructor(id: string, language?: string, cwd?: string);
76
192
  toJSON(): Record<string, unknown>;
77
193
  }
78
194
  /** Sandbox specialized for running Python code. */
@@ -82,19 +198,28 @@ export declare class Sandbox extends BaseSandbox {
82
198
  static create(template: string, opts?: SandboxCreateOpts): Promise<Sandbox>;
83
199
  static connect(sandboxId: string, opts?: SandboxConnectOpts): Promise<Sandbox>;
84
200
  /** Run Python code in the sandbox and return structured execution output. */
85
- runCode(code: string, opts?: RunCodeOpts): Promise<Execution>;
201
+ runCode(code: string, opts?: RunCodeOpts & {
202
+ language?: RunCodeLanguage;
203
+ }): Promise<Execution>;
204
+ runCode(code: string, opts?: RunCodeOpts & {
205
+ context?: Context | string;
206
+ }): Promise<Execution>;
86
207
  /** Create a persistent code context. */
87
- createCodeContext(_opts?: CreateCodeContextOpts): Promise<Context>;
208
+ createCodeContext(opts?: CreateCodeContextOpts): Promise<Context>;
88
209
  /** Remove a persistent code context. */
89
210
  removeCodeContext(context: Context | string, opts?: {
90
211
  requestTimeoutMs?: number;
212
+ signal?: AbortSignal;
91
213
  }): Promise<void>;
92
214
  /** List persistent code contexts. */
93
215
  listCodeContexts(opts?: {
94
216
  requestTimeoutMs?: number;
217
+ signal?: AbortSignal;
95
218
  }): Promise<Context[]>;
96
219
  /** Restart a persistent code context. */
97
220
  restartCodeContext(context: Context | string, opts?: {
98
221
  requestTimeoutMs?: number;
222
+ signal?: AbortSignal;
99
223
  }): Promise<void>;
100
224
  }
225
+ export { Sandbox as default };
@@ -1,5 +1,42 @@
1
1
  import { InvalidArgumentError } from './errors.js';
2
2
  import { Sandbox as BaseSandbox } from './sandbox.js';
3
+ export { ApiError, AuthenticationError, BuildError, ConflictError, FileNotFoundError, FileUploadError, GitAuthError, GitUpstreamError, InvalidArgumentError, NotEnoughSpaceError, NotFoundError, NotImplementedError, RateLimitError, SandboxError, SandboxNotFoundError, TemplateError, TimeoutError, VolumeError, } from './errors.js';
4
+ export { ConnectionConfig, KEEPALIVE_PING_INTERVAL_SEC } from './connectionConfig.js';
5
+ export { ControlClient as ApiClient } from './transport.js';
6
+ export { ALL_TRAFFIC, SandboxPaginator, SnapshotPaginator, getSignature, } from './sandbox.js';
7
+ export { CommandExitError, CommandHandle, Commands } from './commands.js';
8
+ export { Process, ProcessManager, ProcessMessage, ProcessOutput } from './process.js';
9
+ export { FileType, Filesystem, FilesystemEventType, FilesystemWatcher, WatchHandle, } from './filesystem.js';
10
+ export { Git } from './git.js';
11
+ export { Pty } from './pty.js';
12
+ export { Terminal, TerminalManager, TerminalOutput } from './terminal.js';
13
+ export { Volume, VolumeConnectionConfig, VolumeFileType } from './volume.js';
14
+ export { ProcessSocket, base64DecodeBytes, base64DecodeText, base64Encode } from './processSocket.js';
15
+ export { ReadyCmd, Template, TemplateBase, LogEntry, LogEntryEnd, LogEntryStart, defaultBuildLogger, waitForFile, waitForPort, waitForProcess, waitForTimeout, waitForURL, } from './template.js';
16
+ /** Chart types returned by code execution results. */
17
+ export var ChartType;
18
+ (function (ChartType) {
19
+ ChartType["LINE"] = "line";
20
+ ChartType["SCATTER"] = "scatter";
21
+ ChartType["BAR"] = "bar";
22
+ ChartType["PIE"] = "pie";
23
+ ChartType["BOX_AND_WHISKER"] = "box_and_whisker";
24
+ ChartType["SUPERCHART"] = "superchart";
25
+ ChartType["UNKNOWN"] = "unknown";
26
+ })(ChartType || (ChartType = {}));
27
+ /** Axis scale types returned by chart results. */
28
+ export var ScaleType;
29
+ (function (ScaleType) {
30
+ ScaleType["LINEAR"] = "linear";
31
+ ScaleType["DATETIME"] = "datetime";
32
+ ScaleType["CATEGORICAL"] = "categorical";
33
+ ScaleType["LOG"] = "log";
34
+ ScaleType["SYMLOG"] = "symlog";
35
+ ScaleType["LOGIT"] = "logit";
36
+ ScaleType["FUNCTION"] = "function";
37
+ ScaleType["FUNCTIONLOG"] = "functionlog";
38
+ ScaleType["ASINH"] = "asinh";
39
+ })(ScaleType || (ScaleType = {}));
3
40
  /** One stdout or stderr line emitted by code execution. */
4
41
  export class OutputMessage {
5
42
  line;
@@ -41,6 +78,7 @@ export class ExecutionError {
41
78
  }
42
79
  /** Rich result produced by the last expression of a code execution. */
43
80
  export class Result {
81
+ raw;
44
82
  text;
45
83
  html;
46
84
  markdown;
@@ -55,7 +93,8 @@ export class Result {
55
93
  chart;
56
94
  extra;
57
95
  isMainResult;
58
- constructor(payload = {}) {
96
+ constructor(payload = {}, isMainResult) {
97
+ this.raw = payload;
59
98
  this.text = stringValue(payload.text);
60
99
  this.html = stringValue(payload.html);
61
100
  this.markdown = stringValue(payload.markdown);
@@ -66,14 +105,16 @@ export class Result {
66
105
  this.latex = stringValue(payload.latex);
67
106
  this.json = payload.json;
68
107
  this.javascript = stringValue(payload.javascript);
69
- this.data = payload.data;
70
- this.chart = payload.chart;
108
+ this.data = recordOrUndefined(payload.data);
109
+ this.chart = chartFromApi(payload.chart);
71
110
  this.extra = record(payload.extra);
72
- this.isMainResult = Boolean(payload.is_main_result ?? payload.isMainResult);
111
+ this.isMainResult = Boolean(isMainResult ?? payload.is_main_result ?? payload.isMainResult);
73
112
  }
74
113
  formats() {
75
114
  const names = ['text', 'html', 'markdown', 'svg', 'png', 'jpeg', 'pdf', 'latex', 'json', 'javascript', 'data', 'chart'];
76
- return names.filter((name) => this[name] !== undefined);
115
+ const formats = names.filter((name) => this[name] !== undefined);
116
+ formats.push(...Object.keys(this.extra));
117
+ return formats;
77
118
  }
78
119
  toJSON() {
79
120
  return compactRecord({
@@ -127,7 +168,7 @@ export class Context {
127
168
  id;
128
169
  language;
129
170
  cwd;
130
- constructor(id, language, cwd) {
171
+ constructor(id, language = '', cwd = '') {
131
172
  this.id = id;
132
173
  this.language = language;
133
174
  this.cwd = cwd;
@@ -149,7 +190,6 @@ export class Sandbox extends BaseSandbox {
149
190
  static async connect(sandboxId, opts = {}) {
150
191
  return await super.connect(sandboxId, opts);
151
192
  }
152
- /** Run Python code in the sandbox and return structured execution output. */
153
193
  async runCode(code, opts = {}) {
154
194
  if (typeof code !== 'string')
155
195
  throw new InvalidArgumentError('code must be a string');
@@ -161,22 +201,24 @@ export class Sandbox extends BaseSandbox {
161
201
  language: opts.language,
162
202
  context_id: contextId(opts.context),
163
203
  env_vars: opts.envs,
164
- timeout_seconds: opts.timeout,
204
+ timeout_ms: opts.timeoutMs,
165
205
  });
166
206
  const response = await this.runtimePostJson('/runtime/v1/code/run', payload, {
167
207
  requestTimeoutMs: opts.requestTimeoutMs,
208
+ signal: opts.signal,
168
209
  });
169
210
  const execution = executionFromApi(response);
170
- emitCallbacks(execution, opts);
211
+ await emitCallbacks(execution, opts);
171
212
  return execution;
172
213
  }
173
214
  /** Create a persistent code context. */
174
- async createCodeContext(_opts = {}) {
215
+ async createCodeContext(opts = {}) {
175
216
  const response = await this.runtimePostJson('/runtime/v1/code/contexts', compactRecord({
176
- cwd: _opts.cwd,
177
- language: _opts.language,
217
+ cwd: opts.cwd,
218
+ language: opts.language,
178
219
  }), {
179
- requestTimeoutMs: _opts.requestTimeoutMs,
220
+ requestTimeoutMs: opts.requestTimeoutMs,
221
+ signal: opts.signal,
180
222
  });
181
223
  return contextFromApi(response);
182
224
  }
@@ -184,12 +226,14 @@ export class Sandbox extends BaseSandbox {
184
226
  async removeCodeContext(context, opts = {}) {
185
227
  await this.runtimeDeleteJson(`/runtime/v1/code/contexts/${encodeURIComponent(requireContextId(context))}`, {
186
228
  requestTimeoutMs: opts.requestTimeoutMs,
229
+ signal: opts.signal,
187
230
  });
188
231
  }
189
232
  /** List persistent code contexts. */
190
233
  async listCodeContexts(opts = {}) {
191
234
  const response = await this.runtimeGetJson('/runtime/v1/code/contexts', {
192
235
  requestTimeoutMs: opts.requestTimeoutMs,
236
+ signal: opts.signal,
193
237
  });
194
238
  const contexts = Array.isArray(response) ? response : arrayOfUnknown(response.contexts);
195
239
  return contexts.map((item) => contextFromApi(record(item)));
@@ -198,9 +242,11 @@ export class Sandbox extends BaseSandbox {
198
242
  async restartCodeContext(context, opts = {}) {
199
243
  await this.runtimePostJson(`/runtime/v1/code/contexts/${encodeURIComponent(requireContextId(context))}/restart`, {}, {
200
244
  requestTimeoutMs: opts.requestTimeoutMs,
245
+ signal: opts.signal,
201
246
  });
202
247
  }
203
248
  }
249
+ export { Sandbox as default };
204
250
  function executionFromApi(payload) {
205
251
  const execution = record(payload.execution ?? payload);
206
252
  const logs = record(execution.logs);
@@ -222,15 +268,15 @@ function executionErrorFromApi(value) {
222
268
  const item = value;
223
269
  return new ExecutionError(String(item.name ?? ''), String(item.value ?? ''), String(item.traceback ?? ''));
224
270
  }
225
- function emitCallbacks(execution, opts) {
271
+ async function emitCallbacks(execution, opts) {
226
272
  for (const message of execution.logs.stdout)
227
- opts.onStdout?.(message);
273
+ await opts.onStdout?.(message);
228
274
  for (const message of execution.logs.stderr)
229
- opts.onStderr?.(message);
275
+ await opts.onStderr?.(message);
230
276
  for (const result of execution.results)
231
- opts.onResult?.(result);
277
+ await opts.onResult?.(result);
232
278
  if (execution.error !== undefined)
233
- opts.onError?.(execution.error);
279
+ await opts.onError?.(execution.error);
234
280
  }
235
281
  function contextId(context) {
236
282
  if (context === undefined)
@@ -243,7 +289,7 @@ function requireContextId(context) {
243
289
  return context.id;
244
290
  }
245
291
  function contextFromApi(payload) {
246
- return new Context(String(payload.id ?? ''), stringValue(payload.language), stringValue(payload.cwd));
292
+ return new Context(String(payload.id ?? ''), stringValue(payload.language) ?? '', stringValue(payload.cwd) ?? '');
247
293
  }
248
294
  function compactRecord(payload) {
249
295
  return Object.fromEntries(Object.entries(payload).filter(([, value]) => value !== undefined));
@@ -251,6 +297,15 @@ function compactRecord(payload) {
251
297
  function record(value) {
252
298
  return value && typeof value === 'object' && !Array.isArray(value) ? value : {};
253
299
  }
300
+ function recordOrUndefined(value) {
301
+ return value && typeof value === 'object' && !Array.isArray(value) ? value : undefined;
302
+ }
303
+ function chartFromApi(value) {
304
+ const item = recordOrUndefined(value);
305
+ if (item === undefined)
306
+ return undefined;
307
+ return item;
308
+ }
254
309
  function arrayOfRecords(value) {
255
310
  return Array.isArray(value) ? value.map((item) => record(item)) : [];
256
311
  }
@@ -34,23 +34,27 @@ 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
  }
49
+ export type CommandRequestOpts = Pick<CommandStartOpts, 'requestTimeoutMs' | 'signal'>;
50
+ export interface CommandConnectOpts extends CommandRequestOpts {
51
+ timeoutMs?: number;
52
+ onStdout?: (data: string) => void | Promise<void>;
53
+ onStderr?: (data: string) => void | Promise<void>;
54
+ }
55
+ export type Stdout = string;
56
+ export type Stderr = string;
57
+ export type PtyOutput = Uint8Array;
54
58
  /** Live handle for one sandbox process stream. */
55
59
  export declare class CommandHandle implements Partial<CommandResult> {
56
60
  readonly pid: number | string;
@@ -75,9 +79,9 @@ export declare class CommandHandle implements Partial<CommandResult> {
75
79
  /** Kill the process. */
76
80
  kill(): Promise<boolean>;
77
81
  /** Send stdin bytes or text to the process. */
78
- sendStdin(data: string | Uint8Array): Promise<void>;
82
+ sendStdin(data: string | Uint8Array, opts?: CommandRequestOpts): Promise<void>;
79
83
  /** Close the stdin stream and signal EOF to the process. */
80
- closeStdin(): Promise<void>;
84
+ closeStdin(opts?: CommandRequestOpts): Promise<void>;
81
85
  /** Resize the attached PTY stream when this handle was created as a PTY. */
82
86
  resize(size: {
83
87
  cols: number;
@@ -98,18 +102,22 @@ export declare class Commands {
98
102
  /** List processes currently known by the sandbox runtime. */
99
103
  list(opts?: {
100
104
  requestTimeoutMs?: number;
105
+ signal?: AbortSignal;
101
106
  }): Promise<ProcessInfo[]>;
102
107
  /** Send SIGKILL to a process by pid. */
103
108
  kill(pid: number | string, opts?: {
104
109
  requestTimeoutMs?: number;
110
+ signal?: AbortSignal;
105
111
  }): Promise<boolean>;
106
112
  /** Attach to a process and send stdin bytes or text. */
107
113
  sendStdin(pid: number | string, data: string | Uint8Array, opts?: {
108
114
  requestTimeoutMs?: number;
115
+ signal?: AbortSignal;
109
116
  }): Promise<void>;
110
117
  /** Attach to a process and close stdin, signalling EOF. */
111
118
  closeStdin(pid: number | string, opts?: {
112
119
  requestTimeoutMs?: number;
120
+ signal?: AbortSignal;
113
121
  }): Promise<void>;
114
122
  run(cmd: string, opts: CommandStartOpts & {
115
123
  background: true;
package/dist/commands.js CHANGED
@@ -56,16 +56,16 @@ export class CommandHandle {
56
56
  return this.handleKill();
57
57
  }
58
58
  /** Send stdin bytes or text to the process. */
59
- async sendStdin(data) {
60
- this.socket.sendStdin(data);
59
+ async sendStdin(data, opts = {}) {
60
+ await this.socket.sendStdin(data, opts);
61
61
  }
62
62
  /** Close the stdin stream and signal EOF to the process. */
63
- async closeStdin() {
64
- this.socket.closeStdin();
63
+ async closeStdin(opts = {}) {
64
+ await this.socket.closeStdin(opts);
65
65
  }
66
66
  /** Resize the attached PTY stream when this handle was created as a PTY. */
67
67
  async resize(size) {
68
- this.socket.sendJson({ type: 'resize', cols: size.cols, rows: size.rows });
68
+ await this.socket.sendJson({ type: 'resize', cols: size.cols, rows: size.rows });
69
69
  }
70
70
  /** Detach the local stream without killing the process. */
71
71
  async disconnect() {
@@ -146,7 +146,7 @@ export class Commands {
146
146
  async sendStdin(pid, data, opts = {}) {
147
147
  const handle = await this.connect(pid, opts);
148
148
  try {
149
- await handle.sendStdin(data);
149
+ await handle.sendStdin(data, opts);
150
150
  }
151
151
  finally {
152
152
  await handle.disconnect();
@@ -156,7 +156,7 @@ export class Commands {
156
156
  async closeStdin(pid, opts = {}) {
157
157
  const handle = await this.connect(pid, opts);
158
158
  try {
159
- await handle.closeStdin();
159
+ await handle.closeStdin(opts);
160
160
  }
161
161
  finally {
162
162
  await handle.disconnect();
@@ -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
- socket.sendJson({
184
+ await 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);
@@ -233,10 +233,11 @@ function framePid(frame) {
233
233
  function processInfo(value) {
234
234
  const item = value && typeof value === 'object' ? value : {};
235
235
  const process = item.process && typeof item.process === 'object' ? item.process : item;
236
+ const stablePid = typeof process.id === 'number' || typeof process.id === 'string' ? process.id : framePid(process);
236
237
  return {
237
- pid: framePid(process) ?? '',
238
+ pid: stablePid ?? '',
238
239
  tag: typeof process.tag === 'string' ? process.tag : undefined,
239
- cmd: typeof process.cmd === 'string' ? process.cmd : undefined,
240
+ cmd: typeof process.cmd === 'string' ? process.cmd : typeof process.command === 'string' ? process.command : undefined,
240
241
  args: Array.isArray(process.args) ? process.args.map(String) : [],
241
242
  envs: recordOfStrings(process.envs ?? process.environment),
242
243
  cwd: typeof process.cwd === 'string' ? process.cwd : undefined,