@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.
@@ -1,14 +1,20 @@
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;
6
7
  accessToken?: string;
7
8
  domain?: string;
8
9
  apiUrl?: string;
10
+ /** Absolute sandbox data-plane URL override, primarily for local runtimes. */
11
+ sandboxUrl?: string;
9
12
  dataPlaneDomain?: string;
10
13
  requestTimeoutMs?: number;
11
14
  headers?: Record<string, string>;
15
+ apiHeaders?: Record<string, string>;
16
+ debug?: boolean;
17
+ signal?: AbortSignal;
12
18
  proxy?: unknown;
13
19
  }
14
20
  /** Resolved connection settings used by control-plane and data-plane clients. */
@@ -16,11 +22,30 @@ export declare class ConnectionConfig {
16
22
  readonly apiKey?: string;
17
23
  readonly domain: string;
18
24
  readonly apiUrl: string;
25
+ /** Absolute sandbox data-plane URL override, primarily for local runtimes. */
26
+ readonly sandboxUrl?: string;
19
27
  readonly dataPlaneDomain: string;
20
28
  readonly requestTimeoutMs: number;
21
29
  readonly headers: Record<string, string>;
30
+ readonly apiHeaders: Record<string, string>;
31
+ readonly debug: boolean;
32
+ readonly signal?: AbortSignal;
22
33
  readonly proxy?: unknown;
23
34
  constructor(opts?: ConnectionOpts);
24
35
  /** HTTP headers including the configured bearer token. */
25
36
  get authHeaders(): Record<string, string>;
37
+ /** Return an abort signal that follows the caller signal and optional timeout. */
38
+ getSignal(requestTimeoutMs?: number, signal?: AbortSignal | undefined): AbortSignal | undefined;
39
+ /** Return the sandbox data-plane API URL for a Watasu route token. */
40
+ getSandboxUrl(sandboxId: string, opts: {
41
+ sandboxDomain?: string;
42
+ envdPort: number;
43
+ }): string;
44
+ /** Return the direct sandbox data-plane API URL for a Watasu route token. */
45
+ getSandboxDirectUrl(sandboxId: string, opts: {
46
+ sandboxDomain?: string;
47
+ envdPort: number;
48
+ }): string;
49
+ /** Return the public hostname for a Watasu sandbox route token and port. */
50
+ getHost(sandboxId: string, port: number, sandboxDomain?: string): string;
26
51
  }
@@ -5,9 +5,14 @@ export class ConnectionConfig {
5
5
  apiKey;
6
6
  domain;
7
7
  apiUrl;
8
+ /** Absolute sandbox data-plane URL override, primarily for local runtimes. */
9
+ sandboxUrl;
8
10
  dataPlaneDomain;
9
11
  requestTimeoutMs;
10
12
  headers;
13
+ apiHeaders;
14
+ debug;
15
+ signal;
11
16
  proxy;
12
17
  constructor(opts = {}) {
13
18
  const env = typeof process !== 'undefined' ? process.env : {};
@@ -18,18 +23,60 @@ export class ConnectionConfig {
18
23
  this.domain = opts.domain ?? env.WATASU_DOMAIN ?? 'watasu.io';
19
24
  this.apiUrl =
20
25
  opts.apiUrl ?? env.WATASU_API_URL ?? `https://api.${this.domain}/v1`;
26
+ this.sandboxUrl =
27
+ opts.sandboxUrl ??
28
+ env.WATASU_SANDBOX_URL;
21
29
  this.dataPlaneDomain =
22
30
  opts.dataPlaneDomain ??
23
31
  env.WATASU_DATA_PLANE_DOMAIN ??
24
32
  'watasuhost.com';
25
33
  this.requestTimeoutMs = opts.requestTimeoutMs ?? 60_000;
26
34
  this.headers = opts.headers ?? {};
35
+ this.apiHeaders = opts.apiHeaders ?? {};
36
+ this.debug = opts.debug ?? false;
37
+ this.signal = opts.signal;
27
38
  this.proxy = opts.proxy;
28
39
  }
29
40
  /** HTTP headers including the configured bearer token. */
30
41
  get authHeaders() {
31
42
  return this.apiKey
32
- ? { ...this.headers, Authorization: `Bearer ${this.apiKey}` }
33
- : { ...this.headers };
43
+ ? { ...this.headers, ...this.apiHeaders, Authorization: `Bearer ${this.apiKey}` }
44
+ : { ...this.headers, ...this.apiHeaders };
45
+ }
46
+ /** Return an abort signal that follows the caller signal and optional timeout. */
47
+ getSignal(requestTimeoutMs = this.requestTimeoutMs, signal = this.signal) {
48
+ if (requestTimeoutMs === undefined && signal === undefined)
49
+ return undefined;
50
+ const controller = new AbortController();
51
+ if (signal?.aborted)
52
+ controller.abort();
53
+ else
54
+ signal?.addEventListener('abort', () => controller.abort(), { once: true });
55
+ if (requestTimeoutMs > 0) {
56
+ const timeout = setTimeout(() => controller.abort(), requestTimeoutMs);
57
+ const maybeTimeout = timeout;
58
+ if (typeof maybeTimeout.unref === 'function')
59
+ maybeTimeout.unref();
60
+ controller.signal.addEventListener('abort', () => clearTimeout(timeout), { once: true });
61
+ }
62
+ return controller.signal;
63
+ }
64
+ /** Return the sandbox data-plane API URL for a Watasu route token. */
65
+ getSandboxUrl(sandboxId, opts) {
66
+ if (this.sandboxUrl)
67
+ return this.sandboxUrl;
68
+ if (this.debug)
69
+ return `http://localhost:${opts.envdPort}`;
70
+ return `https://${sandboxId}.sandbox.${opts.sandboxDomain ?? this.dataPlaneDomain}`;
71
+ }
72
+ /** Return the direct sandbox data-plane API URL for a Watasu route token. */
73
+ getSandboxDirectUrl(sandboxId, opts) {
74
+ return this.getSandboxUrl(sandboxId, opts);
75
+ }
76
+ /** Return the public hostname for a Watasu sandbox route token and port. */
77
+ getHost(sandboxId, port, sandboxDomain = this.dataPlaneDomain) {
78
+ if (this.debug)
79
+ return `localhost:${port}`;
80
+ return `p${port}-${sandboxId}.sandbox.${sandboxDomain}`;
34
81
  }
35
82
  }
package/dist/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) {
@@ -8,6 +8,13 @@ export declare enum FileType {
8
8
  /** Symbolic link. */
9
9
  SYMLINK = "symlink"
10
10
  }
11
+ export declare enum FilesystemEventType {
12
+ CHMOD = "chmod",
13
+ CREATE = "create",
14
+ REMOVE = "remove",
15
+ RENAME = "rename",
16
+ WRITE = "write"
17
+ }
11
18
  /** Metadata for one sandbox filesystem entry. */
12
19
  export interface EntryInfo {
13
20
  name: string;
@@ -27,7 +34,8 @@ export interface WriteEntry {
27
34
  data: WriteData;
28
35
  }
29
36
  export interface FilesystemEvent {
30
- type: 'create' | 'write' | 'modify' | 'remove' | 'delete' | 'rename' | string;
37
+ name: string;
38
+ type: FilesystemEventType | string;
31
39
  path: string;
32
40
  entry?: EntryInfo;
33
41
  raw: Record<string, unknown>;
@@ -35,11 +43,15 @@ export interface FilesystemEvent {
35
43
  export interface WatchOpts {
36
44
  recursive?: boolean;
37
45
  includeEntry?: boolean;
46
+ allowNetworkMounts?: boolean;
38
47
  requestTimeoutMs?: number;
48
+ signal?: AbortSignal;
49
+ user?: string;
39
50
  onExit?: (error?: Error) => void | Promise<void>;
40
51
  }
41
52
  export interface FilesystemRequestOpts {
42
53
  requestTimeoutMs?: number;
54
+ signal?: AbortSignal;
43
55
  user?: string;
44
56
  }
45
57
  export interface FilesystemReadOpts extends FilesystemRequestOpts {
@@ -47,6 +59,7 @@ export interface FilesystemReadOpts extends FilesystemRequestOpts {
47
59
  }
48
60
  export interface FilesystemWriteOpts extends FilesystemRequestOpts {
49
61
  gzip?: boolean;
62
+ useOctetStream?: boolean;
50
63
  metadata?: Record<string, string>;
51
64
  }
52
65
  /** Live filesystem watcher. Call `stop()` to close the local watch stream. */
@@ -56,8 +69,6 @@ export declare class WatchHandle {
56
69
  constructor(socket: ProcessSocket, events: AsyncIterable<ProcessFrame>, onEvent: (event: FilesystemEvent) => void | Promise<void>, onExit?: (error?: Error) => void | Promise<void>);
57
70
  /** Stop watching the directory. */
58
71
  stop(): void;
59
- /** Alias for `stop`. */
60
- close(): void;
61
72
  /** Resolves when the watcher stream exits. */
62
73
  wait(): Promise<void>;
63
74
  private pump;
@@ -102,30 +113,19 @@ export declare class Filesystem {
102
113
  /** Write several files in one runtime API call. */
103
114
  writeFiles(files: WriteEntry[], opts?: FilesystemWriteOpts): Promise<WriteInfo[]>;
104
115
  /** List directory entries below `path`. */
105
- list(path: string, opts?: {
106
- requestTimeoutMs?: number;
116
+ list(path: string, opts?: FilesystemRequestOpts & {
107
117
  depth?: number;
108
118
  }): Promise<EntryInfo[]>;
109
119
  /** Return whether a file or directory exists at `path`. */
110
- exists(path: string, opts?: {
111
- requestTimeoutMs?: number;
112
- }): Promise<boolean>;
120
+ exists(path: string, opts?: FilesystemRequestOpts): Promise<boolean>;
113
121
  /** Return stat metadata for `path`. */
114
- getInfo(path: string, opts?: {
115
- requestTimeoutMs?: number;
116
- }): Promise<EntryInfo>;
122
+ getInfo(path: string, opts?: FilesystemRequestOpts): Promise<EntryInfo>;
117
123
  /** Remove a file at `path`. */
118
- remove(path: string, opts?: {
119
- requestTimeoutMs?: number;
120
- }): Promise<void>;
124
+ remove(path: string, opts?: FilesystemRequestOpts): Promise<void>;
121
125
  /** Move or rename a file. */
122
- rename(oldPath: string, newPath: string, opts?: {
123
- requestTimeoutMs?: number;
124
- }): Promise<EntryInfo>;
126
+ rename(oldPath: string, newPath: string, opts?: FilesystemRequestOpts): Promise<EntryInfo>;
125
127
  /** Create a directory. */
126
- makeDir(path: string, opts?: {
127
- requestTimeoutMs?: number;
128
- }): Promise<boolean>;
128
+ makeDir(path: string, opts?: FilesystemRequestOpts): Promise<boolean>;
129
129
  /** Start watching a directory for filesystem events. */
130
130
  watchDir(path: string): FilesystemWatcher;
131
131
  watchDir(path: string, onEvent: (event: FilesystemEvent) => void | Promise<void>, opts?: WatchOpts): Promise<FilesystemWatcher>;
@@ -1,3 +1,4 @@
1
+ import { gzipSync } from 'node:zlib';
1
2
  import { withQuery } from './transport.js';
2
3
  import { FileNotFoundError, InvalidArgumentError } from './errors.js';
3
4
  import { ProcessSocket, base64Encode } from './processSocket.js';
@@ -10,6 +11,14 @@ export var FileType;
10
11
  /** Symbolic link. */
11
12
  FileType["SYMLINK"] = "symlink";
12
13
  })(FileType || (FileType = {}));
14
+ export var FilesystemEventType;
15
+ (function (FilesystemEventType) {
16
+ FilesystemEventType["CHMOD"] = "chmod";
17
+ FilesystemEventType["CREATE"] = "create";
18
+ FilesystemEventType["REMOVE"] = "remove";
19
+ FilesystemEventType["RENAME"] = "rename";
20
+ FilesystemEventType["WRITE"] = "write";
21
+ })(FilesystemEventType || (FilesystemEventType = {}));
13
22
  /** Live filesystem watcher. Call `stop()` to close the local watch stream. */
14
23
  export class WatchHandle {
15
24
  socket;
@@ -22,10 +31,6 @@ export class WatchHandle {
22
31
  stop() {
23
32
  this.socket.close();
24
33
  }
25
- /** Alias for `stop`. */
26
- close() {
27
- this.stop();
28
- }
29
34
  /** Resolves when the watcher stream exits. */
30
35
  wait() {
31
36
  return this.done;
@@ -66,7 +71,12 @@ export class FilesystemWatcher {
66
71
  if (this.handle)
67
72
  return;
68
73
  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();
74
+ const socket = await new ProcessSocket(this.dataPlane.baseUrl, this.dataPlane.token, withQuery('/runtime/v1/files/watch', {
75
+ path: this.path,
76
+ recursive: nextOpts.recursive ?? false,
77
+ include_entry: nextOpts.includeEntry,
78
+ allow_network_mounts: nextOpts.allowNetworkMounts,
79
+ }), nextOpts.requestTimeoutMs, this.dataPlane.headers).connect();
70
80
  this.handle = new WatchHandle(socket, socket, async (event) => {
71
81
  for (const listener of this.listeners)
72
82
  await listener(event);
@@ -113,8 +123,8 @@ export class Filesystem {
113
123
  if (Array.isArray(pathOrFiles)) {
114
124
  return this.writeFiles(pathOrFiles, dataOrOpts);
115
125
  }
116
- const body = await writeDataToBytes(dataOrOpts);
117
- const payload = await this.dataPlane.putJson(withQuery('/runtime/v1/files', { path: pathOrFiles, gzip: opts.gzip }), body, opts);
126
+ const body = maybeGzip(await writeDataToBytes(dataOrOpts), opts.gzip);
127
+ const payload = await this.dataPlane.putJson(withQuery('/runtime/v1/files', { path: pathOrFiles, gzip: opts.gzip }), body, requestOpts(opts, opts.gzip ? { 'content-encoding': 'gzip' } : undefined));
118
128
  return entryInfo(payload.file ?? payload);
119
129
  }
120
130
  /** Write raw bytes to a file. */
@@ -126,11 +136,12 @@ export class Filesystem {
126
136
  if (files.length === 0)
127
137
  return [];
128
138
  const payload = await this.dataPlane.postJson('/runtime/v1/files/write_files', {
129
- ...opts,
139
+ ...requestOpts(opts),
130
140
  json: {
131
141
  files: await Promise.all(files.map(async (file) => ({
132
142
  path: file.path,
133
- data_base64: base64Encode(await writeDataToBytes(file.data)),
143
+ data_base64: base64Encode(maybeGzip(await writeDataToBytes(file.data), opts.gzip)),
144
+ ...(opts.gzip ? { gzip: true } : {}),
134
145
  }))),
135
146
  },
136
147
  });
@@ -198,6 +209,19 @@ async function writeDataToBytes(data) {
198
209
  return readStreamToBytes(data);
199
210
  throw new InvalidArgumentError(`Unsupported file data type: ${Object.prototype.toString.call(data)}`);
200
211
  }
212
+ function requestOpts(opts, headers) {
213
+ const out = {};
214
+ if (opts.requestTimeoutMs !== undefined)
215
+ out.requestTimeoutMs = opts.requestTimeoutMs;
216
+ if (opts.signal !== undefined)
217
+ out.signal = opts.signal;
218
+ if (headers !== undefined)
219
+ out.headers = headers;
220
+ return out;
221
+ }
222
+ function maybeGzip(bytes, enabled) {
223
+ return enabled ? new Uint8Array(gzipSync(bytes)) : bytes;
224
+ }
201
225
  function toArrayBuffer(bytes) {
202
226
  const buffer = new ArrayBuffer(bytes.byteLength);
203
227
  new Uint8Array(buffer).set(bytes);
@@ -257,17 +281,32 @@ function recordOfStrings(value) {
257
281
  }
258
282
  function filesystemEvent(value) {
259
283
  const item = value && typeof value === 'object' ? value : {};
284
+ const path = String(item.path ?? '');
260
285
  return {
261
286
  type: normalizeEventType(String(item.type ?? 'modify')),
262
- path: String(item.path ?? ''),
287
+ name: String(item.name ?? relativeName(path)),
288
+ path,
263
289
  entry: item.file && typeof item.file === 'object' ? entryInfo(item.file) : undefined,
264
290
  raw: item,
265
291
  };
266
292
  }
267
293
  function normalizeEventType(value) {
268
294
  if (value === 'delete')
269
- return 'remove';
295
+ return FilesystemEventType.REMOVE;
270
296
  if (value === 'modify')
271
- return 'write';
297
+ return FilesystemEventType.WRITE;
298
+ if (value === 'chmod')
299
+ return FilesystemEventType.CHMOD;
300
+ if (value === 'create')
301
+ return FilesystemEventType.CREATE;
302
+ if (value === 'remove')
303
+ return FilesystemEventType.REMOVE;
304
+ if (value === 'rename')
305
+ return FilesystemEventType.RENAME;
306
+ if (value === 'write')
307
+ return FilesystemEventType.WRITE;
272
308
  return value;
273
309
  }
310
+ function relativeName(path) {
311
+ return path.split('/').filter(Boolean).pop() ?? '';
312
+ }
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 {
@@ -51,13 +50,15 @@ export interface GitCredentialOpts extends GitRequestOpts {
51
50
  host?: string;
52
51
  protocol?: string;
53
52
  }
53
+ export type GitDangerouslyAuthenticateOpts = GitCredentialOpts;
54
54
  export interface GitConfigureUserOpts extends GitRequestOpts {
55
- scope?: 'global' | 'local';
55
+ scope?: GitConfigScope;
56
56
  path?: string;
57
57
  }
58
58
  export interface GitBranchOpts extends GitRequestOpts {
59
59
  force?: boolean;
60
60
  }
61
+ export type GitDeleteBranchOpts = GitBranchOpts;
61
62
  export interface GitAddOpts extends GitRequestOpts {
62
63
  files?: string[];
63
64
  all?: boolean;
@@ -84,9 +85,10 @@ export interface GitRemoteAddOpts extends GitRequestOpts {
84
85
  overwrite?: boolean;
85
86
  }
86
87
  export interface GitConfigOpts extends GitRequestOpts {
87
- scope?: 'global' | 'local';
88
+ scope?: GitConfigScope;
88
89
  path?: string;
89
90
  }
91
+ export type GitConfigScope = 'global' | 'local' | 'system';
90
92
  export interface GitBranches {
91
93
  path?: string;
92
94
  branches: string[];
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
@@ -1,24 +1,36 @@
1
- export { ApiError, AuthenticationError, ConflictError, FileNotFoundError, InvalidArgumentError, NotEnoughSpaceError, NotFoundError, NotImplementedError, RateLimitError, SandboxError, TimeoutError, } from './errors.js';
1
+ export { ApiError, AuthenticationError, BuildError, ConflictError, FileNotFoundError, FileUploadError, GitAuthError, GitUpstreamError, InvalidArgumentError, NotEnoughSpaceError, NotFoundError, NotImplementedError, RateLimitError, SandboxError, SandboxNotFoundError, TemplateError, TimeoutError, VolumeError, } from './errors.js';
2
2
  export { ConnectionConfig, KEEPALIVE_PING_INTERVAL_SEC } from './connectionConfig.js';
3
- export { Sandbox, SandboxPaginator, SnapshotPaginator } from './sandbox.js';
3
+ export type { ConnectionOpts, Username } from './connectionConfig.js';
4
+ export { ControlClient as ApiClient } from './transport.js';
5
+ export { ALL_TRAFFIC, Sandbox, SandboxPaginator, SnapshotPaginator, getSignature, } from './sandbox.js';
4
6
  export { Sandbox as CodeInterpreterSandbox } from './codeInterpreter.js';
5
- export type { CreateSnapshotOpts, RestoreSnapshotOpts, SandboxCreateOpts, SandboxConnectOpts, SandboxInfo, SandboxInfoLifecycle, SandboxLifecycle, SandboxListOpts, SandboxMetrics, SandboxMetricsOpts, McpServer, McpServerName, SandboxNetworkSelector, SandboxNetworkUpdate, SandboxNetworkUpdateOpts, SandboxUrlOpts, SnapshotInfo, FileUrlInfo, } from './sandbox.js';
7
+ export type { CreateSnapshotOpts, RestoreSnapshotOpts, SandboxApiOpts, SandboxCreateOpts, SandboxConnectOpts, SandboxInfo, SandboxInfoLifecycle, SandboxLifecycle, SandboxListOpts, SandboxMetrics, SandboxMetricsOpts, McpServer, McpServerName, SandboxNetworkInfo, SandboxNetworkOpts, SandboxNetworkRule, SandboxNetworkRuleInfo, SandboxNetworkRules, SandboxNetworkSelector, SandboxNetworkSelectorContext, SandboxNetworkTransform, SandboxNetworkUpdate, SandboxNetworkUpdateOpts, SandboxOpts, SandboxState, SandboxUrlOpts, SignatureOpts, SnapshotInfo, SnapshotListOpts, FileUrlInfo, } from './sandbox.js';
6
8
  export type { CreateCodeContextOpts, RunCodeLanguage, RunCodeOpts, } from './codeInterpreter.js';
7
9
  export { Context as CodeInterpreterContext, Execution as CodeInterpreterExecution, ExecutionError as CodeInterpreterExecutionError, OutputMessage as CodeInterpreterOutputMessage, Result as CodeInterpreterResult, } from './codeInterpreter.js';
8
10
  export { CommandExitError, CommandHandle, Commands } from './commands.js';
9
- export type { CommandResult, CommandStartOpts, ProcessInfo } from './commands.js';
11
+ export type { CommandConnectOpts, CommandRequestOpts, CommandResult, CommandStartOpts, ProcessInfo, PtyOutput, Stderr, Stdout, } from './commands.js';
10
12
  export { Process, ProcessManager, ProcessMessage, ProcessOutput } from './process.js';
11
13
  export type { ProcessOpts } from './process.js';
12
- export { FileType, Filesystem, FilesystemWatcher, WatchHandle } from './filesystem.js';
14
+ export { FileType, Filesystem, FilesystemEventType, FilesystemWatcher, WatchHandle, } from './filesystem.js';
13
15
  export type { EntryInfo, FilesystemEvent, FilesystemReadOpts, FilesystemRequestOpts, FilesystemWriteOpts, WatchOpts, WriteData, WriteEntry, WriteInfo, } from './filesystem.js';
14
16
  export { Git } from './git.js';
15
- export type { GitAddOpts, GitAuthOpts, GitBranches, GitBranchOpts, GitCloneOpts, GitCommandResult, GitConfigOpts, GitConfigureUserOpts, GitCredentialOpts, GitCommitOpts, GitFileStatus, GitInitOpts, GitPullOpts, GitPushOpts, GitRemoteAddOpts, GitResetMode, GitResetOpts, GitRestoreOpts, GitRequestOpts, GitStatus, } from './git.js';
17
+ export type { GitAddOpts, GitAuthOpts, GitBranches, GitBranchOpts, GitCloneOpts, GitCommandResult, GitConfigScope, GitConfigOpts, GitConfigureUserOpts, GitCredentialOpts, GitCommitOpts, GitDangerouslyAuthenticateOpts, GitDeleteBranchOpts, GitFileStatus, GitInitOpts, GitPullOpts, GitPushOpts, GitRemoteAddOpts, GitResetMode, GitResetOpts, GitRestoreOpts, GitRequestOpts, GitStatus, } from './git.js';
16
18
  export { Pty } from './pty.js';
17
19
  export type { PtyConnectOpts, PtyCreateOpts, PtySize } from './pty.js';
18
20
  export { Terminal, TerminalManager, TerminalOutput } from './terminal.js';
19
21
  export type { TerminalOpts } from './terminal.js';
20
- export { Volume } from './volume.js';
21
- export type { VolumeApiParams, VolumeConnectionConfig, VolumeEntryStat, VolumeFileType, VolumeInfo, VolumeListFilesOpts, VolumeListOpts, VolumeMetadataOpts, VolumeReadFileOpts, VolumeReadFormat, VolumeWriteData, VolumeWriteFileOpts, } from './volume.js';
22
+ export { Volume, VolumeConnectionConfig, VolumeFileType } from './volume.js';
23
+ export type { VolumeAndToken, VolumeApiParams, VolumeApiOpts, VolumeEntryStat, VolumeInfo, VolumeListFilesOpts, VolumeListOpts, VolumeMetadataOpts, VolumeMetadataOptions, VolumeReadFileOpts, VolumeReadFormat, VolumeWriteData, VolumeWriteFileOpts, VolumeWriteOptions, } from './volume.js';
22
24
  export { ProcessSocket, base64DecodeBytes, base64DecodeText, base64Encode } from './processSocket.js';
23
- export { ReadyCmd, Template, TemplateBase, waitForFile, waitForPort, waitForProcess, waitForTimeout, waitForURL, waitForUrl, } from './template.js';
24
- export type { BuildInfo, BuildOptions, BuildStatusReason, CopyItem, GetBuildStatusOptions, LogEntry, ReadyCommand, TemplateBuildStatus, TemplateBuildStatusResponse, TemplateBuilder, TemplateClass, TemplateFactory, TemplateFinal, TemplateFromImage, TemplateOptions, TemplateTag, TemplateTagInfo, } from './template.js';
25
+ export { ReadyCmd, Template, TemplateBase, LogEntry, LogEntryEnd, LogEntryStart, defaultBuildLogger, waitForFile, waitForPort, waitForProcess, waitForTimeout, waitForURL, } from './template.js';
26
+ export type { BuildInfo, BuildOptions, BuildStatusReason, CopyItem, GetBuildStatusOptions, LogEntryLevel, Logger, ReadyCommand, TemplateBuildStatus, TemplateBuildStatusResponse, TemplateBuilder, TemplateClass, TemplateFactory, TemplateFinal, TemplateFromImage, TemplateOptions, TemplateTag, TemplateTagInfo, } from './template.js';
27
+ export interface components {
28
+ schemas: Record<string, unknown>;
29
+ responses: Record<string, unknown>;
30
+ parameters: Record<string, unknown>;
31
+ requestBodies: Record<string, unknown>;
32
+ headers: Record<string, unknown>;
33
+ pathItems: Record<string, unknown>;
34
+ }
35
+ export type paths = Record<string, unknown>;
36
+ export { Sandbox as default } from './sandbox.js';
package/dist/index.js CHANGED
@@ -1,14 +1,16 @@
1
- export { ApiError, AuthenticationError, ConflictError, FileNotFoundError, InvalidArgumentError, NotEnoughSpaceError, NotFoundError, NotImplementedError, RateLimitError, SandboxError, TimeoutError, } from './errors.js';
1
+ export { ApiError, AuthenticationError, BuildError, ConflictError, FileNotFoundError, FileUploadError, GitAuthError, GitUpstreamError, InvalidArgumentError, NotEnoughSpaceError, NotFoundError, NotImplementedError, RateLimitError, SandboxError, SandboxNotFoundError, TemplateError, TimeoutError, VolumeError, } from './errors.js';
2
2
  export { ConnectionConfig, KEEPALIVE_PING_INTERVAL_SEC } from './connectionConfig.js';
3
- export { Sandbox, SandboxPaginator, SnapshotPaginator } from './sandbox.js';
3
+ export { ControlClient as ApiClient } from './transport.js';
4
+ export { ALL_TRAFFIC, Sandbox, SandboxPaginator, SnapshotPaginator, getSignature, } from './sandbox.js';
4
5
  export { Sandbox as CodeInterpreterSandbox } from './codeInterpreter.js';
5
6
  export { Context as CodeInterpreterContext, Execution as CodeInterpreterExecution, ExecutionError as CodeInterpreterExecutionError, OutputMessage as CodeInterpreterOutputMessage, Result as CodeInterpreterResult, } from './codeInterpreter.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, waitForUrl, } from './template.js';
15
+ export { ReadyCmd, Template, TemplateBase, LogEntry, LogEntryEnd, LogEntryStart, defaultBuildLogger, waitForFile, waitForPort, waitForProcess, waitForTimeout, waitForURL, } from './template.js';
16
+ export { Sandbox as default } from './sandbox.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
@@ -40,11 +40,15 @@ export class ProcessOutput {
40
40
  this._error = true;
41
41
  }
42
42
  replace(result) {
43
+ const streamedStdout = this.stdout;
44
+ const streamedStderr = this.stderr;
43
45
  this.messages = [];
44
- if (result.stdout)
45
- this.addStdout(processMessage(result.stdout, false));
46
- if (result.stderr)
47
- this.addStderr(processMessage(result.stderr, true));
46
+ const stdout = result.stdout || streamedStdout;
47
+ const stderr = result.stderr || streamedStderr;
48
+ if (stdout)
49
+ this.addStdout(processMessage(stdout, false));
50
+ if (stderr)
51
+ this.addStderr(processMessage(stderr, true));
48
52
  this.setExitCode(result.exitCode);
49
53
  }
50
54
  }
@@ -67,10 +71,10 @@ export class Process {
67
71
  async kill() {
68
72
  await this.handle.kill();
69
73
  }
70
- async wait(timeout) {
74
+ async wait(timeoutMs) {
71
75
  if (!this.waitPromise)
72
76
  this.waitPromise = this.waitOnce();
73
- return waitFor(this.waitPromise, timeout);
77
+ return waitFor(this.waitPromise, timeoutMs);
74
78
  }
75
79
  async waitOnce() {
76
80
  try {
@@ -126,7 +130,7 @@ export class ProcessManager {
126
130
  }
127
131
  async startAndWait(cmdOrOpts) {
128
132
  const process = await this.start(cmdOrOpts);
129
- return process.wait(typeof cmdOrOpts === 'string' ? undefined : cmdOrOpts.timeout);
133
+ return process.wait(typeof cmdOrOpts === 'string' ? undefined : cmdOrOpts.timeoutMs);
130
134
  }
131
135
  }
132
136
  function processOpts(cmdOrOpts) {