@watasu/sdk 0.1.50 → 0.1.53

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,5 +1,5 @@
1
- import { Sandbox as BaseSandbox, SandboxConnectOpts, SandboxCreateOpts } from './sandbox.js';
2
- export { ApiError, AuthenticationError, BuildError, ConflictError, FileNotFoundError, FileUploadError, GitAuthError, GitUpstreamError, InvalidArgumentError, NotEnoughSpaceError, NotFoundError, NotImplementedError, RateLimitError, SandboxError, SandboxNotFoundError, TemplateError, TimeoutError, VolumeError, } from './errors.js';
1
+ import { Sandbox as BaseSandbox } from './sandbox.js';
2
+ export { ApiError, AuthenticationError, BuildError, ConflictError, FileNotFoundError, FileUploadError, GitAuthError, GitUpstreamError, InvalidArgumentError, NotEnoughSpaceError, NotFoundError, RateLimitError, SandboxError, SandboxNotFoundError, TemplateError, TimeoutError, VolumeError, } from './errors.js';
3
3
  export { ConnectionConfig, KEEPALIVE_PING_INTERVAL_SEC } from './connectionConfig.js';
4
4
  export type { ConnectionOpts, Username } from './connectionConfig.js';
5
5
  export { ControlClient as ApiClient } from './transport.js';
@@ -138,7 +138,6 @@ export declare class OutputMessage {
138
138
  readonly error: boolean;
139
139
  constructor(line: string, timestamp?: number, error?: boolean);
140
140
  toString(): string;
141
- toJSON(): Record<string, unknown>;
142
141
  }
143
142
  /** Structured exception raised by user code inside the sandbox. */
144
143
  export declare class ExecutionError {
@@ -146,7 +145,6 @@ export declare class ExecutionError {
146
145
  readonly value: string;
147
146
  readonly traceback: string;
148
147
  constructor(name: string, value: string, traceback: string);
149
- toJSON(): Record<string, unknown>;
150
148
  }
151
149
  /** Rich result produced by the last expression of a code execution. */
152
150
  export declare class Result {
@@ -170,8 +168,8 @@ export declare class Result {
170
168
  toJSON(): Record<string, unknown>;
171
169
  }
172
170
  export interface Logs {
173
- stdout: OutputMessage[];
174
- stderr: OutputMessage[];
171
+ stdout: string[];
172
+ stderr: string[];
175
173
  }
176
174
  /** Complete result of a sandbox code execution. */
177
175
  export declare class Execution {
@@ -189,37 +187,33 @@ export declare class Context {
189
187
  readonly language: string;
190
188
  readonly cwd: string;
191
189
  constructor(id: string, language?: string, cwd?: string);
192
- toJSON(): Record<string, unknown>;
193
190
  }
194
191
  /** Sandbox specialized for running Python code. */
195
192
  export declare class Sandbox extends BaseSandbox {
196
- static readonly defaultTemplate = "code-interpreter";
197
- static create(opts?: SandboxCreateOpts): Promise<Sandbox>;
198
- static create(template: string, opts?: SandboxCreateOpts): Promise<Sandbox>;
199
- static connect(sandboxId: string, opts?: SandboxConnectOpts): Promise<Sandbox>;
193
+ protected static readonly defaultTemplate: string;
194
+ protected get jupyterUrl(): string;
200
195
  /** Run Python code in the sandbox and return structured execution output. */
201
196
  runCode(code: string, opts?: RunCodeOpts & {
197
+ /**
198
+ * Language to use for code execution.
199
+ *
200
+ * If not defined, the default Python context is used.
201
+ */
202
202
  language?: RunCodeLanguage;
203
203
  }): Promise<Execution>;
204
204
  runCode(code: string, opts?: RunCodeOpts & {
205
- context?: Context | string;
205
+ /**
206
+ * Context to run the code in.
207
+ */
208
+ context?: Context;
206
209
  }): Promise<Execution>;
207
210
  /** Create a persistent code context. */
208
211
  createCodeContext(opts?: CreateCodeContextOpts): Promise<Context>;
209
212
  /** Remove a persistent code context. */
210
- removeCodeContext(context: Context | string, opts?: {
211
- requestTimeoutMs?: number;
212
- signal?: AbortSignal;
213
- }): Promise<void>;
213
+ removeCodeContext(context: Context | string): Promise<void>;
214
214
  /** List persistent code contexts. */
215
- listCodeContexts(opts?: {
216
- requestTimeoutMs?: number;
217
- signal?: AbortSignal;
218
- }): Promise<Context[]>;
215
+ listCodeContexts(): Promise<Context[]>;
219
216
  /** Restart a persistent code context. */
220
- restartCodeContext(context: Context | string, opts?: {
221
- requestTimeoutMs?: number;
222
- signal?: AbortSignal;
223
- }): Promise<void>;
217
+ restartCodeContext(context: Context | string): Promise<void>;
224
218
  }
225
219
  export { Sandbox as default };
@@ -1,6 +1,6 @@
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';
3
+ export { ApiError, AuthenticationError, BuildError, ConflictError, FileNotFoundError, FileUploadError, GitAuthError, GitUpstreamError, InvalidArgumentError, NotEnoughSpaceError, NotFoundError, RateLimitError, SandboxError, SandboxNotFoundError, TemplateError, TimeoutError, VolumeError, } from './errors.js';
4
4
  export { ConnectionConfig, KEEPALIVE_PING_INTERVAL_SEC } from './connectionConfig.js';
5
5
  export { ControlClient as ApiClient } from './transport.js';
6
6
  export { ALL_TRAFFIC, SandboxPaginator, SnapshotPaginator, getSignature, } from './sandbox.js';
@@ -50,13 +50,6 @@ export class OutputMessage {
50
50
  toString() {
51
51
  return this.line;
52
52
  }
53
- toJSON() {
54
- return {
55
- line: this.line,
56
- timestamp: this.timestamp,
57
- error: this.error,
58
- };
59
- }
60
53
  }
61
54
  /** Structured exception raised by user code inside the sandbox. */
62
55
  export class ExecutionError {
@@ -68,13 +61,6 @@ export class ExecutionError {
68
61
  this.value = value;
69
62
  this.traceback = traceback;
70
63
  }
71
- toJSON() {
72
- return {
73
- name: this.name,
74
- value: this.value,
75
- traceback: this.traceback,
76
- };
77
- }
78
64
  }
79
65
  /** Rich result produced by the last expression of a code execution. */
80
66
  export class Result {
@@ -107,7 +93,7 @@ export class Result {
107
93
  this.javascript = stringValue(payload.javascript);
108
94
  this.data = recordOrUndefined(payload.data);
109
95
  this.chart = chartFromApi(payload.chart);
110
- this.extra = record(payload.extra);
96
+ this.extra = resultExtra(payload);
111
97
  this.isMainResult = Boolean(isMainResult ?? payload.is_main_result ?? payload.isMainResult);
112
98
  }
113
99
  formats() {
@@ -128,10 +114,7 @@ export class Result {
128
114
  latex: this.latex,
129
115
  json: this.json,
130
116
  javascript: this.javascript,
131
- data: this.data,
132
- chart: this.chart,
133
117
  extra: Object.keys(this.extra).length === 0 ? undefined : this.extra,
134
- is_main_result: this.isMainResult,
135
118
  });
136
119
  }
137
120
  }
@@ -153,13 +136,9 @@ export class Execution {
153
136
  }
154
137
  toJSON() {
155
138
  return {
156
- results: this.results.map((result) => result.toJSON()),
157
- logs: {
158
- stdout: this.logs.stdout.map((message) => message.toJSON()),
159
- stderr: this.logs.stderr.map((message) => message.toJSON()),
160
- },
161
- error: this.error?.toJSON() ?? null,
162
- execution_count: this.executionCount,
139
+ results: this.results,
140
+ logs: this.logs,
141
+ error: this.error,
163
142
  };
164
143
  }
165
144
  }
@@ -173,22 +152,12 @@ export class Context {
173
152
  this.language = language;
174
153
  this.cwd = cwd;
175
154
  }
176
- toJSON() {
177
- return compactRecord({
178
- id: this.id,
179
- language: this.language,
180
- cwd: this.cwd,
181
- });
182
- }
183
155
  }
184
156
  /** Sandbox specialized for running Python code. */
185
157
  export class Sandbox extends BaseSandbox {
186
158
  static defaultTemplate = 'code-interpreter';
187
- static async create(templateOrOpts, opts = {}) {
188
- return await super.create(templateOrOpts, opts);
189
- }
190
- static async connect(sandboxId, opts = {}) {
191
- return await super.connect(sandboxId, opts);
159
+ get jupyterUrl() {
160
+ return this.runtimeBaseUrl;
192
161
  }
193
162
  async runCode(code, opts = {}) {
194
163
  if (typeof code !== 'string')
@@ -200,7 +169,7 @@ export class Sandbox extends BaseSandbox {
200
169
  code,
201
170
  language: opts.language,
202
171
  context_id: contextId(opts.context),
203
- env_vars: opts.envs,
172
+ envs: opts.envs,
204
173
  timeout_ms: opts.timeoutMs,
205
174
  });
206
175
  const response = await this.runtimePostJson('/runtime/v1/code/run', payload, {
@@ -222,14 +191,12 @@ export class Sandbox extends BaseSandbox {
222
191
  });
223
192
  return contextFromApi(response);
224
193
  }
225
- /** Remove a persistent code context. */
226
194
  async removeCodeContext(context, opts = {}) {
227
195
  await this.runtimeDeleteJson(`/runtime/v1/code/contexts/${encodeURIComponent(requireContextId(context))}`, {
228
196
  requestTimeoutMs: opts.requestTimeoutMs,
229
197
  signal: opts.signal,
230
198
  });
231
199
  }
232
- /** List persistent code contexts. */
233
200
  async listCodeContexts(opts = {}) {
234
201
  const response = await this.runtimeGetJson('/runtime/v1/code/contexts', {
235
202
  requestTimeoutMs: opts.requestTimeoutMs,
@@ -238,7 +205,6 @@ export class Sandbox extends BaseSandbox {
238
205
  const contexts = Array.isArray(response) ? response : arrayOfUnknown(response.contexts);
239
206
  return contexts.map((item) => contextFromApi(record(item)));
240
207
  }
241
- /** Restart a persistent code context. */
242
208
  async restartCodeContext(context, opts = {}) {
243
209
  await this.runtimePostJson(`/runtime/v1/code/contexts/${encodeURIComponent(requireContextId(context))}/restart`, {}, {
244
210
  requestTimeoutMs: opts.requestTimeoutMs,
@@ -251,16 +217,16 @@ function executionFromApi(payload) {
251
217
  const execution = record(payload.execution ?? payload);
252
218
  const logs = record(execution.logs);
253
219
  return new Execution(arrayOfRecords(execution.results).map((item) => new Result(item)), {
254
- stdout: arrayOfUnknown(logs.stdout).map((item) => outputMessageFromApi(item, false)),
255
- stderr: arrayOfUnknown(logs.stderr).map((item) => outputMessageFromApi(item, true)),
220
+ stdout: arrayOfUnknown(logs.stdout).map(outputLineFromApi),
221
+ stderr: arrayOfUnknown(logs.stderr).map(outputLineFromApi),
256
222
  }, executionErrorFromApi(execution.error), numberValue(execution.execution_count ?? execution.executionCount));
257
223
  }
258
- function outputMessageFromApi(value, error) {
224
+ function outputLineFromApi(value) {
259
225
  if (value && typeof value === 'object' && !Array.isArray(value)) {
260
226
  const item = value;
261
- return new OutputMessage(String(item.line ?? ''), numberValue(item.timestamp) ?? Date.now() / 1000, Boolean(item.error ?? error));
227
+ return String(item.line ?? item.text ?? '');
262
228
  }
263
- return new OutputMessage(String(value), Date.now() / 1000, error);
229
+ return String(value);
264
230
  }
265
231
  function executionErrorFromApi(value) {
266
232
  if (!value || typeof value !== 'object' || Array.isArray(value))
@@ -270,9 +236,9 @@ function executionErrorFromApi(value) {
270
236
  }
271
237
  async function emitCallbacks(execution, opts) {
272
238
  for (const message of execution.logs.stdout)
273
- await opts.onStdout?.(message);
239
+ await opts.onStdout?.(new OutputMessage(message, Date.now() / 1000, false));
274
240
  for (const message of execution.logs.stderr)
275
- await opts.onStderr?.(message);
241
+ await opts.onStderr?.(new OutputMessage(message, Date.now() / 1000, true));
276
242
  for (const result of execution.results)
277
243
  await opts.onResult?.(result);
278
244
  if (execution.error !== undefined)
@@ -297,6 +263,33 @@ function compactRecord(payload) {
297
263
  function record(value) {
298
264
  return value && typeof value === 'object' && !Array.isArray(value) ? value : {};
299
265
  }
266
+ function resultExtra(payload) {
267
+ const extra = record(payload.extra);
268
+ for (const [key, value] of Object.entries(payload)) {
269
+ if (!knownResultKeys.has(key))
270
+ extra[key] = value;
271
+ }
272
+ return extra;
273
+ }
274
+ const knownResultKeys = new Set([
275
+ 'plain',
276
+ 'text',
277
+ 'html',
278
+ 'markdown',
279
+ 'svg',
280
+ 'png',
281
+ 'jpeg',
282
+ 'pdf',
283
+ 'latex',
284
+ 'json',
285
+ 'javascript',
286
+ 'data',
287
+ 'chart',
288
+ 'extra',
289
+ 'type',
290
+ 'is_main_result',
291
+ 'isMainResult',
292
+ ]);
300
293
  function recordOrUndefined(value) {
301
294
  return value && typeof value === 'object' && !Array.isArray(value) ? value : undefined;
302
295
  }
@@ -1,6 +1,12 @@
1
1
  export declare const KEEPALIVE_PING_INTERVAL_SEC = 50;
2
2
  export declare const SESSION_OPERATION_REQUEST_TIMEOUT_MS = 150000;
3
3
  export type Username = string;
4
+ export interface Logger {
5
+ debug?: (...args: unknown[]) => void;
6
+ info?: (...args: unknown[]) => void;
7
+ warn?: (...args: unknown[]) => void;
8
+ error?: (...args: unknown[]) => void;
9
+ }
4
10
  /** Connection options accepted by Watasu SDK entrypoints. */
5
11
  export interface ConnectionOpts {
6
12
  apiKey?: string;
@@ -14,12 +20,21 @@ export interface ConnectionOpts {
14
20
  headers?: Record<string, string>;
15
21
  apiHeaders?: Record<string, string>;
16
22
  debug?: boolean;
23
+ logger?: Logger;
17
24
  signal?: AbortSignal;
18
- proxy?: unknown;
25
+ proxy?: string;
19
26
  }
20
27
  /** Resolved connection settings used by control-plane and data-plane clients. */
21
28
  export declare class ConnectionConfig {
29
+ static envdPort: number;
30
+ static get domain(): string;
31
+ static get apiUrl(): string;
32
+ static get sandboxUrl(): string | undefined;
33
+ static get debug(): boolean;
34
+ static get apiKey(): string | undefined;
35
+ static get accessToken(): string | undefined;
22
36
  readonly apiKey?: string;
37
+ readonly accessToken?: string;
23
38
  readonly domain: string;
24
39
  readonly apiUrl: string;
25
40
  /** Absolute sandbox data-plane URL override, primarily for local runtimes. */
@@ -29,8 +44,9 @@ export declare class ConnectionConfig {
29
44
  readonly headers: Record<string, string>;
30
45
  readonly apiHeaders: Record<string, string>;
31
46
  readonly debug: boolean;
47
+ readonly logger?: Logger;
32
48
  readonly signal?: AbortSignal;
33
- readonly proxy?: unknown;
49
+ readonly proxy?: string;
34
50
  constructor(opts?: ConnectionOpts);
35
51
  /** HTTP headers including the configured bearer token. */
36
52
  get authHeaders(): Record<string, string>;
@@ -38,14 +54,14 @@ export declare class ConnectionConfig {
38
54
  getSignal(requestTimeoutMs?: number, signal?: AbortSignal | undefined): AbortSignal | undefined;
39
55
  /** Return the sandbox data-plane API URL for a Watasu route token. */
40
56
  getSandboxUrl(sandboxId: string, opts: {
41
- sandboxDomain?: string;
57
+ sandboxDomain: string;
42
58
  envdPort: number;
43
59
  }): string;
44
60
  /** Return the direct sandbox data-plane API URL for a Watasu route token. */
45
61
  getSandboxDirectUrl(sandboxId: string, opts: {
46
- sandboxDomain?: string;
62
+ sandboxDomain: string;
47
63
  envdPort: number;
48
64
  }): string;
49
65
  /** Return the public hostname for a Watasu sandbox route token and port. */
50
- getHost(sandboxId: string, port: number, sandboxDomain?: string): string;
66
+ getHost(sandboxId: string, port: number, sandboxDomain: string): string;
51
67
  }
@@ -2,7 +2,34 @@ export const KEEPALIVE_PING_INTERVAL_SEC = 50;
2
2
  export const SESSION_OPERATION_REQUEST_TIMEOUT_MS = 150_000;
3
3
  /** Resolved connection settings used by control-plane and data-plane clients. */
4
4
  export class ConnectionConfig {
5
+ static envdPort = 49983;
6
+ static get domain() {
7
+ const env = typeof process !== 'undefined' ? process.env : {};
8
+ return env.WATASU_DOMAIN ?? 'watasu.io';
9
+ }
10
+ static get apiUrl() {
11
+ const env = typeof process !== 'undefined' ? process.env : {};
12
+ return env.WATASU_API_URL ?? `https://api.${this.domain}/v1`;
13
+ }
14
+ static get sandboxUrl() {
15
+ const env = typeof process !== 'undefined' ? process.env : {};
16
+ return env.WATASU_SANDBOX_URL;
17
+ }
18
+ static get debug() {
19
+ const env = typeof process !== 'undefined' ? process.env : {};
20
+ const value = (env.WATASU_DEBUG ?? 'false').toLowerCase();
21
+ return value === 'true' || value === '1';
22
+ }
23
+ static get apiKey() {
24
+ const env = typeof process !== 'undefined' ? process.env : {};
25
+ return env.WATASU_API_KEY ?? env.WATASU_ACCESS_TOKEN;
26
+ }
27
+ static get accessToken() {
28
+ const env = typeof process !== 'undefined' ? process.env : {};
29
+ return env.WATASU_ACCESS_TOKEN ?? this.apiKey;
30
+ }
5
31
  apiKey;
32
+ accessToken;
6
33
  domain;
7
34
  apiUrl;
8
35
  /** Absolute sandbox data-plane URL override, primarily for local runtimes. */
@@ -12,20 +39,20 @@ export class ConnectionConfig {
12
39
  headers;
13
40
  apiHeaders;
14
41
  debug;
42
+ logger;
15
43
  signal;
16
44
  proxy;
17
45
  constructor(opts = {}) {
18
46
  const env = typeof process !== 'undefined' ? process.env : {};
19
- this.apiKey =
20
- opts.apiKey ??
21
- opts.accessToken ??
22
- env.WATASU_API_KEY;
23
- this.domain = opts.domain ?? env.WATASU_DOMAIN ?? 'watasu.io';
24
- this.apiUrl =
25
- opts.apiUrl ?? env.WATASU_API_URL ?? `https://api.${this.domain}/v1`;
26
- this.sandboxUrl =
27
- opts.sandboxUrl ??
28
- env.WATASU_SANDBOX_URL;
47
+ const token = opts.apiKey ??
48
+ opts.accessToken ??
49
+ ConnectionConfig.apiKey ??
50
+ ConnectionConfig.accessToken;
51
+ this.apiKey = token;
52
+ this.accessToken = opts.accessToken ?? token;
53
+ this.domain = opts.domain ?? ConnectionConfig.domain;
54
+ this.apiUrl = opts.apiUrl ?? env.WATASU_API_URL ?? `https://api.${this.domain}/v1`;
55
+ this.sandboxUrl = opts.sandboxUrl ?? ConnectionConfig.sandboxUrl;
29
56
  this.dataPlaneDomain =
30
57
  opts.dataPlaneDomain ??
31
58
  env.WATASU_DATA_PLANE_DOMAIN ??
@@ -33,14 +60,16 @@ export class ConnectionConfig {
33
60
  this.requestTimeoutMs = opts.requestTimeoutMs ?? 60_000;
34
61
  this.headers = opts.headers ?? {};
35
62
  this.apiHeaders = opts.apiHeaders ?? {};
36
- this.debug = opts.debug ?? false;
63
+ this.debug = opts.debug ?? ConnectionConfig.debug;
64
+ this.logger = opts.logger;
37
65
  this.signal = opts.signal;
38
66
  this.proxy = opts.proxy;
39
67
  }
40
68
  /** HTTP headers including the configured bearer token. */
41
69
  get authHeaders() {
42
- return this.apiKey
43
- ? { ...this.headers, ...this.apiHeaders, Authorization: `Bearer ${this.apiKey}` }
70
+ const token = this.accessToken ?? this.apiKey;
71
+ return token
72
+ ? { ...this.headers, ...this.apiHeaders, Authorization: `Bearer ${token}` }
44
73
  : { ...this.headers, ...this.apiHeaders };
45
74
  }
46
75
  /** Return an abort signal that follows the caller signal and optional timeout. */
@@ -61,7 +90,6 @@ export class ConnectionConfig {
61
90
  }
62
91
  return controller.signal;
63
92
  }
64
- /** Return the sandbox data-plane API URL for a Watasu route token. */
65
93
  getSandboxUrl(sandboxId, opts) {
66
94
  if (this.sandboxUrl)
67
95
  return this.sandboxUrl;
@@ -69,11 +97,12 @@ export class ConnectionConfig {
69
97
  return `http://localhost:${opts.envdPort}`;
70
98
  return `https://${sandboxId}.sandbox.${opts.sandboxDomain ?? this.dataPlaneDomain}`;
71
99
  }
72
- /** Return the direct sandbox data-plane API URL for a Watasu route token. */
73
100
  getSandboxDirectUrl(sandboxId, opts) {
74
- return this.getSandboxUrl(sandboxId, opts);
101
+ return this.getSandboxUrl(sandboxId, {
102
+ sandboxDomain: opts.sandboxDomain ?? this.dataPlaneDomain,
103
+ envdPort: opts.envdPort,
104
+ });
75
105
  }
76
- /** Return the public hostname for a Watasu sandbox route token and port. */
77
106
  getHost(sandboxId, port, sandboxDomain = this.dataPlaneDomain) {
78
107
  if (this.debug)
79
108
  return `localhost:${port}`;
package/dist/errors.d.ts CHANGED
@@ -46,10 +46,6 @@ export declare class FileUploadError extends BuildError {
46
46
  export declare class VolumeError extends Error {
47
47
  constructor(message?: string);
48
48
  }
49
- export declare function unsupported(feature: string): never;
50
- export declare class NotImplementedError extends Error {
51
- constructor(message: string);
52
- }
53
49
  export declare class ApiError extends SandboxError {
54
50
  readonly status: number;
55
51
  readonly code?: string | undefined;
package/dist/errors.js CHANGED
@@ -94,15 +94,6 @@ export class VolumeError extends Error {
94
94
  this.name = 'VolumeError';
95
95
  }
96
96
  }
97
- export function unsupported(feature) {
98
- throw new NotImplementedError(`${feature} is not supported by Watasu yet`);
99
- }
100
- export class NotImplementedError extends Error {
101
- constructor(message) {
102
- super(message);
103
- this.name = 'NotImplementedError';
104
- }
105
- }
106
97
  export class ApiError extends SandboxError {
107
98
  status;
108
99
  code;
@@ -22,6 +22,11 @@ export interface EntryInfo {
22
22
  path: string;
23
23
  size?: number;
24
24
  mode?: number;
25
+ permissions?: string;
26
+ owner?: string;
27
+ group?: string;
28
+ modifiedTime?: Date;
29
+ symlinkTarget?: string;
25
30
  uid?: number;
26
31
  gid?: number;
27
32
  mtime?: number;
@@ -44,6 +49,7 @@ export interface WatchOpts {
44
49
  recursive?: boolean;
45
50
  includeEntry?: boolean;
46
51
  allowNetworkMounts?: boolean;
52
+ timeoutMs?: number;
47
53
  requestTimeoutMs?: number;
48
54
  signal?: AbortSignal;
49
55
  user?: string;
@@ -76,7 +76,7 @@ export class FilesystemWatcher {
76
76
  recursive: nextOpts.recursive ?? false,
77
77
  include_entry: nextOpts.includeEntry,
78
78
  allow_network_mounts: nextOpts.allowNetworkMounts,
79
- }), nextOpts.requestTimeoutMs, this.dataPlane.headers).connect();
79
+ }), nextOpts.requestTimeoutMs ?? nextOpts.timeoutMs, this.dataPlane.headers).connect();
80
80
  this.handle = new WatchHandle(socket, socket, async (event) => {
81
81
  for (const listener of this.listeners)
82
82
  await listener(event);
@@ -265,6 +265,11 @@ function entryInfo(value) {
265
265
  path: String(item.path ?? ''),
266
266
  size: numberValue(item.bytes ?? item.size),
267
267
  mode: numberValue(item.mode),
268
+ permissions: stringValue(item.permissions),
269
+ owner: stringValue(item.owner),
270
+ group: stringValue(item.group),
271
+ modifiedTime: dateValue(item.modified_time ?? item.modifiedTime ?? item.mtime ?? item.updated_at ?? item.updatedAt),
272
+ symlinkTarget: stringValue(item.symlink_target ?? item.symlinkTarget),
268
273
  uid: numberValue(item.uid),
269
274
  gid: numberValue(item.gid),
270
275
  mtime: numberValue(item.mtime),
@@ -274,6 +279,23 @@ function entryInfo(value) {
274
279
  function numberValue(value) {
275
280
  return typeof value === 'number' ? value : undefined;
276
281
  }
282
+ function stringValue(value) {
283
+ if (typeof value === 'string')
284
+ return value;
285
+ if (typeof value === 'number')
286
+ return String(value);
287
+ return undefined;
288
+ }
289
+ function dateValue(value) {
290
+ if (value instanceof Date)
291
+ return value;
292
+ if (typeof value === 'string' || typeof value === 'number') {
293
+ const date = new Date(value);
294
+ if (!Number.isNaN(date.getTime()))
295
+ return date;
296
+ }
297
+ return undefined;
298
+ }
277
299
  function recordOfStrings(value) {
278
300
  if (!value || typeof value !== 'object')
279
301
  return undefined;
package/dist/git.d.ts CHANGED
@@ -169,5 +169,8 @@ export declare class Git {
169
169
  setConfig(key: string, value: string, opts?: GitConfigOpts): Promise<GitCommandResult>;
170
170
  /** Read a Git config value. */
171
171
  getConfig(key: string, opts?: GitConfigOpts): Promise<string>;
172
+ private getRemoteUrl;
173
+ private resolveRemoteName;
174
+ private hasUpstream;
172
175
  private run;
173
176
  }
package/dist/git.js CHANGED
@@ -1,3 +1,4 @@
1
+ import { InvalidArgumentError } from './errors.js';
1
2
  /** Git helper backed by sandbox data-plane routes. */
2
3
  export class Git {
3
4
  dataPlane;
@@ -162,6 +163,31 @@ export class Git {
162
163
  }, opts);
163
164
  return String(result.value ?? '');
164
165
  }
166
+ async getRemoteUrl(path, remote, opts = {}) {
167
+ const url = await this.remoteGet(path, remote, opts);
168
+ if (!url) {
169
+ throw new InvalidArgumentError(`Remote "${remote}" URL not found in repository.`);
170
+ }
171
+ return url;
172
+ }
173
+ async resolveRemoteName(path, remote, opts = {}) {
174
+ if (remote)
175
+ return remote;
176
+ const status = await this.status(path, opts);
177
+ const upstreamRemote = status.upstream?.split('/')[0];
178
+ if (upstreamRemote)
179
+ return upstreamRemote;
180
+ throw new InvalidArgumentError('Remote is required when the repository has no upstream remote.');
181
+ }
182
+ async hasUpstream(path, opts = {}) {
183
+ try {
184
+ const status = await this.status(path, opts);
185
+ return Boolean(status.upstream);
186
+ }
187
+ catch {
188
+ return false;
189
+ }
190
+ }
165
191
  async run(path, json, opts) {
166
192
  const payload = await this.dataPlane.postJson(path, {
167
193
  json: compact(json),
@@ -173,7 +199,7 @@ export class Git {
173
199
  }
174
200
  function gitOpts(opts) {
175
201
  return {
176
- env_vars: opts.envs,
202
+ envs: opts.envs,
177
203
  user: opts.user,
178
204
  cwd: opts.cwd,
179
205
  timeout_seconds: opts.timeoutMs === undefined ? undefined : Math.ceil(opts.timeoutMs / 1000),
package/dist/index.d.ts CHANGED
@@ -1,4 +1,4 @@
1
- export { ApiError, AuthenticationError, BuildError, ConflictError, FileNotFoundError, FileUploadError, GitAuthError, GitUpstreamError, InvalidArgumentError, NotEnoughSpaceError, NotFoundError, NotImplementedError, RateLimitError, SandboxError, SandboxNotFoundError, TemplateError, TimeoutError, VolumeError, } from './errors.js';
1
+ export { ApiError, AuthenticationError, BuildError, ConflictError, FileNotFoundError, FileUploadError, GitAuthError, GitUpstreamError, InvalidArgumentError, NotEnoughSpaceError, NotFoundError, RateLimitError, SandboxError, SandboxNotFoundError, TemplateError, TimeoutError, VolumeError, } from './errors.js';
2
2
  export { ConnectionConfig, KEEPALIVE_PING_INTERVAL_SEC } from './connectionConfig.js';
3
3
  export type { ConnectionOpts, Username } from './connectionConfig.js';
4
4
  export { ControlClient as ApiClient } from './transport.js';
package/dist/index.js CHANGED
@@ -1,4 +1,4 @@
1
- export { ApiError, AuthenticationError, BuildError, ConflictError, FileNotFoundError, FileUploadError, GitAuthError, GitUpstreamError, InvalidArgumentError, NotEnoughSpaceError, NotFoundError, NotImplementedError, RateLimitError, SandboxError, SandboxNotFoundError, TemplateError, TimeoutError, VolumeError, } from './errors.js';
1
+ export { ApiError, AuthenticationError, BuildError, ConflictError, FileNotFoundError, FileUploadError, GitAuthError, GitUpstreamError, InvalidArgumentError, NotEnoughSpaceError, NotFoundError, RateLimitError, SandboxError, SandboxNotFoundError, TemplateError, TimeoutError, VolumeError, } from './errors.js';
2
2
  export { ConnectionConfig, KEEPALIVE_PING_INTERVAL_SEC } from './connectionConfig.js';
3
3
  export { ControlClient as ApiClient } from './transport.js';
4
4
  export { ALL_TRAFFIC, Sandbox, SandboxPaginator, SnapshotPaginator, getSignature, } from './sandbox.js';
package/dist/pty.d.ts CHANGED
@@ -1,16 +1,21 @@
1
- import { CommandHandle, CommandStartOpts } from './commands.js';
2
- import { ConnectionConfig, type ConnectionOpts } from './connectionConfig.js';
1
+ import { CommandHandle } from './commands.js';
2
+ import { ConnectionConfig, type ConnectionOpts, type Username } from './connectionConfig.js';
3
3
  import { DataPlaneClient } from './transport.js';
4
4
  export interface PtySize {
5
5
  cols: number;
6
6
  rows: number;
7
7
  }
8
- export interface PtyCreateOpts extends Omit<CommandStartOpts, 'background' | 'onStdout' | 'onStderr'> {
8
+ export interface PtyCreateOpts extends Pick<ConnectionOpts, 'requestTimeoutMs' | 'signal'> {
9
9
  cols?: number;
10
10
  rows?: number;
11
11
  size?: PtySize;
12
12
  cmd?: string;
13
+ cwd?: string;
14
+ user?: Username;
15
+ envs?: Record<string, string>;
16
+ timeoutMs?: number;
13
17
  onData?: (data: Uint8Array) => void | Promise<void>;
18
+ onPty?: (data: Uint8Array) => void | Promise<void>;
14
19
  }
15
20
  export interface PtyConnectOpts {
16
21
  onData?: (data: Uint8Array) => void | Promise<void>;