@watasu/sdk 0.1.40 → 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
@@ -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
 
@@ -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,33 +1,35 @@
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';
2
+ export { ApiError, AuthenticationError, BuildError, ConflictError, FileNotFoundError, FileUploadError, GitAuthError, GitUpstreamError, InvalidArgumentError, NotEnoughSpaceError, NotFoundError, NotImplementedError, RateLimitError, SandboxError, SandboxNotFoundError, TemplateError, TimeoutError, VolumeError, } from './errors.js';
3
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';
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';
6
8
  export { CommandExitError, CommandHandle, Commands } from './commands.js';
7
- export type { CommandResult, CommandStartOpts, ProcessInfo } from './commands.js';
9
+ export type { CommandConnectOpts, CommandRequestOpts, CommandResult, CommandStartOpts, ProcessInfo, PtyOutput, Stderr, Stdout, } from './commands.js';
8
10
  export { Process, ProcessManager, ProcessMessage, ProcessOutput } from './process.js';
9
11
  export type { ProcessOpts } from './process.js';
10
- export { FileType, Filesystem, FilesystemWatcher, WatchHandle } from './filesystem.js';
12
+ export { FileType, Filesystem, FilesystemEventType, FilesystemWatcher, WatchHandle, } from './filesystem.js';
11
13
  export type { EntryInfo, FilesystemEvent, FilesystemReadOpts, FilesystemRequestOpts, FilesystemWriteOpts, WatchOpts, WriteData, WriteEntry, WriteInfo, } from './filesystem.js';
12
14
  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';
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';
14
16
  export { Pty } from './pty.js';
15
17
  export type { PtyConnectOpts, PtyCreateOpts, PtySize } from './pty.js';
16
18
  export { Terminal, TerminalManager, TerminalOutput } from './terminal.js';
17
19
  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 { 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';
20
22
  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';
23
- export type RunCodeLanguage = 'python' | 'python3' | string;
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;
24
28
  export interface RunCodeOpts {
25
- language?: RunCodeLanguage;
26
- context?: Context | string;
27
- onStdout?: (message: OutputMessage) => void;
28
- onStderr?: (message: OutputMessage) => void;
29
- onResult?: (result: Result) => void;
30
- onError?: (error: ExecutionError) => void;
29
+ onStdout?: OutputHandler<OutputMessage>;
30
+ onStderr?: OutputHandler<OutputMessage>;
31
+ onResult?: OutputHandler<Result>;
32
+ onError?: OutputHandler<ExecutionError>;
31
33
  envs?: Record<string, string>;
32
34
  timeoutMs?: number;
33
35
  requestTimeoutMs?: number;
@@ -39,6 +41,96 @@ export interface CreateCodeContextOpts {
39
41
  requestTimeoutMs?: number;
40
42
  signal?: AbortSignal;
41
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"
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>;
42
134
  /** One stdout or stderr line emitted by code execution. */
43
135
  export declare class OutputMessage {
44
136
  readonly line: string;
@@ -58,6 +150,7 @@ export declare class ExecutionError {
58
150
  }
59
151
  /** Rich result produced by the last expression of a code execution. */
60
152
  export declare class Result {
153
+ readonly raw: RawData;
61
154
  readonly text?: string;
62
155
  readonly html?: string;
63
156
  readonly markdown?: string;
@@ -68,11 +161,11 @@ export declare class Result {
68
161
  readonly latex?: string;
69
162
  readonly json?: unknown;
70
163
  readonly javascript?: string;
71
- readonly data?: unknown;
72
- readonly chart?: unknown;
164
+ readonly data?: Record<string, unknown>;
165
+ readonly chart?: ChartTypes;
73
166
  readonly extra: Record<string, unknown>;
74
167
  readonly isMainResult: boolean;
75
- constructor(payload?: Record<string, unknown>);
168
+ constructor(payload?: RawData, isMainResult?: boolean);
76
169
  formats(): string[];
77
170
  toJSON(): Record<string, unknown>;
78
171
  }
@@ -93,9 +186,9 @@ export declare class Execution {
93
186
  /** Code execution context metadata. */
94
187
  export declare class Context {
95
188
  readonly id: string;
96
- readonly language?: string | undefined;
97
- readonly cwd?: string | undefined;
98
- 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);
99
192
  toJSON(): Record<string, unknown>;
100
193
  }
101
194
  /** Sandbox specialized for running Python code. */
@@ -105,9 +198,14 @@ export declare class Sandbox extends BaseSandbox {
105
198
  static create(template: string, opts?: SandboxCreateOpts): Promise<Sandbox>;
106
199
  static connect(sandboxId: string, opts?: SandboxConnectOpts): Promise<Sandbox>;
107
200
  /** Run Python code in the sandbox and return structured execution output. */
108
- 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>;
109
207
  /** Create a persistent code context. */
110
- createCodeContext(_opts?: CreateCodeContextOpts): Promise<Context>;
208
+ createCodeContext(opts?: CreateCodeContextOpts): Promise<Context>;
111
209
  /** Remove a persistent code context. */
112
210
  removeCodeContext(context: Context | string, opts?: {
113
211
  requestTimeoutMs?: number;
@@ -124,3 +222,4 @@ export declare class Sandbox extends BaseSandbox {
124
222
  signal?: AbortSignal;
125
223
  }): Promise<void>;
126
224
  }
225
+ export { Sandbox as default };
@@ -1,17 +1,42 @@
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';
3
+ export { ApiError, AuthenticationError, BuildError, ConflictError, FileNotFoundError, FileUploadError, GitAuthError, GitUpstreamError, InvalidArgumentError, NotEnoughSpaceError, NotFoundError, NotImplementedError, RateLimitError, SandboxError, SandboxNotFoundError, TemplateError, TimeoutError, VolumeError, } from './errors.js';
4
4
  export { ConnectionConfig, KEEPALIVE_PING_INTERVAL_SEC } from './connectionConfig.js';
5
- export { SandboxPaginator, SnapshotPaginator } from './sandbox.js';
5
+ export { ControlClient as ApiClient } from './transport.js';
6
+ export { ALL_TRAFFIC, SandboxPaginator, SnapshotPaginator, getSignature, } from './sandbox.js';
6
7
  export { CommandExitError, CommandHandle, Commands } from './commands.js';
7
8
  export { Process, ProcessManager, ProcessMessage, ProcessOutput } from './process.js';
8
- export { FileType, Filesystem, FilesystemWatcher, WatchHandle } from './filesystem.js';
9
+ export { FileType, Filesystem, FilesystemEventType, FilesystemWatcher, WatchHandle, } from './filesystem.js';
9
10
  export { Git } from './git.js';
10
11
  export { Pty } from './pty.js';
11
12
  export { Terminal, TerminalManager, TerminalOutput } from './terminal.js';
12
- export { Volume } from './volume.js';
13
+ export { Volume, VolumeConnectionConfig, VolumeFileType } from './volume.js';
13
14
  export { ProcessSocket, base64DecodeBytes, base64DecodeText, base64Encode } from './processSocket.js';
14
- export { ReadyCmd, Template, TemplateBase, waitForFile, waitForPort, waitForProcess, waitForTimeout, waitForURL, } from './template.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 = {}));
15
40
  /** One stdout or stderr line emitted by code execution. */
16
41
  export class OutputMessage {
17
42
  line;
@@ -53,6 +78,7 @@ export class ExecutionError {
53
78
  }
54
79
  /** Rich result produced by the last expression of a code execution. */
55
80
  export class Result {
81
+ raw;
56
82
  text;
57
83
  html;
58
84
  markdown;
@@ -67,7 +93,8 @@ export class Result {
67
93
  chart;
68
94
  extra;
69
95
  isMainResult;
70
- constructor(payload = {}) {
96
+ constructor(payload = {}, isMainResult) {
97
+ this.raw = payload;
71
98
  this.text = stringValue(payload.text);
72
99
  this.html = stringValue(payload.html);
73
100
  this.markdown = stringValue(payload.markdown);
@@ -78,14 +105,16 @@ export class Result {
78
105
  this.latex = stringValue(payload.latex);
79
106
  this.json = payload.json;
80
107
  this.javascript = stringValue(payload.javascript);
81
- this.data = payload.data;
82
- this.chart = payload.chart;
108
+ this.data = recordOrUndefined(payload.data);
109
+ this.chart = chartFromApi(payload.chart);
83
110
  this.extra = record(payload.extra);
84
- this.isMainResult = Boolean(payload.is_main_result ?? payload.isMainResult);
111
+ this.isMainResult = Boolean(isMainResult ?? payload.is_main_result ?? payload.isMainResult);
85
112
  }
86
113
  formats() {
87
114
  const names = ['text', 'html', 'markdown', 'svg', 'png', 'jpeg', 'pdf', 'latex', 'json', 'javascript', 'data', 'chart'];
88
- 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;
89
118
  }
90
119
  toJSON() {
91
120
  return compactRecord({
@@ -139,7 +168,7 @@ export class Context {
139
168
  id;
140
169
  language;
141
170
  cwd;
142
- constructor(id, language, cwd) {
171
+ constructor(id, language = '', cwd = '') {
143
172
  this.id = id;
144
173
  this.language = language;
145
174
  this.cwd = cwd;
@@ -161,7 +190,6 @@ export class Sandbox extends BaseSandbox {
161
190
  static async connect(sandboxId, opts = {}) {
162
191
  return await super.connect(sandboxId, opts);
163
192
  }
164
- /** Run Python code in the sandbox and return structured execution output. */
165
193
  async runCode(code, opts = {}) {
166
194
  if (typeof code !== 'string')
167
195
  throw new InvalidArgumentError('code must be a string');
@@ -180,17 +208,17 @@ export class Sandbox extends BaseSandbox {
180
208
  signal: opts.signal,
181
209
  });
182
210
  const execution = executionFromApi(response);
183
- emitCallbacks(execution, opts);
211
+ await emitCallbacks(execution, opts);
184
212
  return execution;
185
213
  }
186
214
  /** Create a persistent code context. */
187
- async createCodeContext(_opts = {}) {
215
+ async createCodeContext(opts = {}) {
188
216
  const response = await this.runtimePostJson('/runtime/v1/code/contexts', compactRecord({
189
- cwd: _opts.cwd,
190
- language: _opts.language,
217
+ cwd: opts.cwd,
218
+ language: opts.language,
191
219
  }), {
192
- requestTimeoutMs: _opts.requestTimeoutMs,
193
- signal: _opts.signal,
220
+ requestTimeoutMs: opts.requestTimeoutMs,
221
+ signal: opts.signal,
194
222
  });
195
223
  return contextFromApi(response);
196
224
  }
@@ -218,6 +246,7 @@ export class Sandbox extends BaseSandbox {
218
246
  });
219
247
  }
220
248
  }
249
+ export { Sandbox as default };
221
250
  function executionFromApi(payload) {
222
251
  const execution = record(payload.execution ?? payload);
223
252
  const logs = record(execution.logs);
@@ -239,15 +268,15 @@ function executionErrorFromApi(value) {
239
268
  const item = value;
240
269
  return new ExecutionError(String(item.name ?? ''), String(item.value ?? ''), String(item.traceback ?? ''));
241
270
  }
242
- function emitCallbacks(execution, opts) {
271
+ async function emitCallbacks(execution, opts) {
243
272
  for (const message of execution.logs.stdout)
244
- opts.onStdout?.(message);
273
+ await opts.onStdout?.(message);
245
274
  for (const message of execution.logs.stderr)
246
- opts.onStderr?.(message);
275
+ await opts.onStderr?.(message);
247
276
  for (const result of execution.results)
248
- opts.onResult?.(result);
277
+ await opts.onResult?.(result);
249
278
  if (execution.error !== undefined)
250
- opts.onError?.(execution.error);
279
+ await opts.onError?.(execution.error);
251
280
  }
252
281
  function contextId(context) {
253
282
  if (context === undefined)
@@ -260,7 +289,7 @@ function requireContextId(context) {
260
289
  return context.id;
261
290
  }
262
291
  function contextFromApi(payload) {
263
- 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) ?? '');
264
293
  }
265
294
  function compactRecord(payload) {
266
295
  return Object.fromEntries(Object.entries(payload).filter(([, value]) => value !== undefined));
@@ -268,6 +297,15 @@ function compactRecord(payload) {
268
297
  function record(value) {
269
298
  return value && typeof value === 'object' && !Array.isArray(value) ? value : {};
270
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
+ }
271
309
  function arrayOfRecords(value) {
272
310
  return Array.isArray(value) ? value.map((item) => record(item)) : [];
273
311
  }
@@ -46,6 +46,15 @@ export interface CommandStartOpts {
46
46
  requestTimeoutMs?: number;
47
47
  signal?: AbortSignal;
48
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;
49
58
  /** Live handle for one sandbox process stream. */
50
59
  export declare class CommandHandle implements Partial<CommandResult> {
51
60
  readonly pid: number | string;
@@ -70,9 +79,9 @@ export declare class CommandHandle implements Partial<CommandResult> {
70
79
  /** Kill the process. */
71
80
  kill(): Promise<boolean>;
72
81
  /** Send stdin bytes or text to the process. */
73
- sendStdin(data: string | Uint8Array): Promise<void>;
82
+ sendStdin(data: string | Uint8Array, opts?: CommandRequestOpts): Promise<void>;
74
83
  /** Close the stdin stream and signal EOF to the process. */
75
- closeStdin(): Promise<void>;
84
+ closeStdin(opts?: CommandRequestOpts): Promise<void>;
76
85
  /** Resize the attached PTY stream when this handle was created as a PTY. */
77
86
  resize(size: {
78
87
  cols: number;
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();
@@ -181,7 +181,7 @@ export class Commands {
181
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
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,
@@ -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,
@@ -1,5 +1,6 @@
1
1
  export declare const KEEPALIVE_PING_INTERVAL_SEC = 50;
2
2
  export declare const SESSION_OPERATION_REQUEST_TIMEOUT_MS = 150000;
3
+ export type Username = string;
3
4
  /** Connection options accepted by Watasu SDK entrypoints. */
4
5
  export interface ConnectionOpts {
5
6
  apiKey?: string;
package/dist/errors.d.ts CHANGED
@@ -25,6 +25,27 @@ export declare class NotEnoughSpaceError extends SandboxError {
25
25
  export declare class FileNotFoundError extends NotFoundError {
26
26
  constructor(message?: string);
27
27
  }
28
+ export declare class SandboxNotFoundError extends NotFoundError {
29
+ constructor(message?: string);
30
+ }
31
+ export declare class GitAuthError extends AuthenticationError {
32
+ constructor(message?: string);
33
+ }
34
+ export declare class GitUpstreamError extends SandboxError {
35
+ constructor(message?: string);
36
+ }
37
+ export declare class TemplateError extends SandboxError {
38
+ constructor(message?: string);
39
+ }
40
+ export declare class BuildError extends Error {
41
+ constructor(message?: string);
42
+ }
43
+ export declare class FileUploadError extends BuildError {
44
+ constructor(message?: string);
45
+ }
46
+ export declare class VolumeError extends Error {
47
+ constructor(message?: string);
48
+ }
28
49
  export declare function unsupported(feature: string): never;
29
50
  export declare class NotImplementedError extends Error {
30
51
  constructor(message: string);
package/dist/errors.js CHANGED
@@ -52,6 +52,48 @@ export class FileNotFoundError extends NotFoundError {
52
52
  this.name = 'FileNotFoundError';
53
53
  }
54
54
  }
55
+ export class SandboxNotFoundError extends NotFoundError {
56
+ constructor(message = 'Sandbox not found') {
57
+ super(message);
58
+ this.name = 'SandboxNotFoundError';
59
+ }
60
+ }
61
+ export class GitAuthError extends AuthenticationError {
62
+ constructor(message = 'Git authentication failed') {
63
+ super(message);
64
+ this.name = 'GitAuthError';
65
+ }
66
+ }
67
+ export class GitUpstreamError extends SandboxError {
68
+ constructor(message = 'Git upstream tracking is missing') {
69
+ super(message);
70
+ this.name = 'GitUpstreamError';
71
+ }
72
+ }
73
+ export class TemplateError extends SandboxError {
74
+ constructor(message = 'Template error') {
75
+ super(message);
76
+ this.name = 'TemplateError';
77
+ }
78
+ }
79
+ export class BuildError extends Error {
80
+ constructor(message = 'Build error') {
81
+ super(message);
82
+ this.name = 'BuildError';
83
+ }
84
+ }
85
+ export class FileUploadError extends BuildError {
86
+ constructor(message = 'File upload failed') {
87
+ super(message);
88
+ this.name = 'FileUploadError';
89
+ }
90
+ }
91
+ export class VolumeError extends Error {
92
+ constructor(message = 'Volume error') {
93
+ super(message);
94
+ this.name = 'VolumeError';
95
+ }
96
+ }
55
97
  export function unsupported(feature) {
56
98
  throw new NotImplementedError(`${feature} is not supported by Watasu yet`);
57
99
  }
@@ -78,6 +120,18 @@ export function errorFromResponse(status, payload) {
78
120
  listMessage(body.errors) ||
79
121
  code ||
80
122
  `Request failed with status ${status}`;
123
+ if (code === 'not_enough_space')
124
+ return new NotEnoughSpaceError(message);
125
+ if (code === 'file_not_found')
126
+ return new FileNotFoundError(message);
127
+ if (code === 'sandbox_not_found')
128
+ return new SandboxNotFoundError(message);
129
+ if (code === 'git_auth')
130
+ return new GitAuthError(message);
131
+ if (code === 'git_upstream')
132
+ return new GitUpstreamError(message);
133
+ if (code === 'template_error')
134
+ return new TemplateError(message);
81
135
  if (status === 401 || status === 403)
82
136
  return new AuthenticationError(message);
83
137
  if (status === 404)
@@ -90,10 +144,6 @@ export function errorFromResponse(status, payload) {
90
144
  return new InvalidArgumentError(message);
91
145
  if (status === 429)
92
146
  return new RateLimitError(message);
93
- if (code === 'not_enough_space')
94
- return new NotEnoughSpaceError(message);
95
- if (code === 'file_not_found')
96
- return new FileNotFoundError(message);
97
147
  return new ApiError(message, status, code);
98
148
  }
99
149
  function asRecord(value) {