@watasu/sdk 0.1.30 → 0.1.40
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +3 -3
- package/dist/codeInterpreter.d.ts +27 -1
- package/dist/codeInterpreter.js +18 -1
- package/dist/commands.d.ts +5 -6
- package/dist/commands.js +6 -6
- package/dist/connectionConfig.d.ts +24 -0
- package/dist/connectionConfig.js +49 -2
- package/dist/filesystem.d.ts +7 -19
- package/dist/filesystem.js +1 -5
- package/dist/git.d.ts +1 -2
- package/dist/git.js +7 -3
- package/dist/index.d.ts +1 -1
- package/dist/index.js +1 -1
- package/dist/process.d.ts +1 -1
- package/dist/process.js +3 -3
- package/dist/processSocket.d.ts +2 -1
- package/dist/processSocket.js +4 -2
- package/dist/pty.d.ts +3 -3
- package/dist/pty.js +9 -7
- package/dist/sandbox.d.ts +10 -25
- package/dist/sandbox.js +55 -45
- package/dist/template.d.ts +3 -2
- package/dist/template.js +13 -2
- package/dist/terminal.d.ts +2 -3
- package/dist/terminal.js +2 -3
- package/dist/transport.d.ts +2 -0
- package/dist/transport.js +23 -6
- package/dist/volume.d.ts +0 -4
- package/dist/volume.js +20 -9
- package/package.json +1 -1
package/dist/sandbox.d.ts
CHANGED
|
@@ -6,6 +6,7 @@ import { Git } from './git.js';
|
|
|
6
6
|
import { Pty } from './pty.js';
|
|
7
7
|
import { ProcessManager } from './process.js';
|
|
8
8
|
import { TerminalManager } from './terminal.js';
|
|
9
|
+
import type { Volume } from './volume.js';
|
|
9
10
|
export interface SandboxCreateOpts extends ConnectionOpts {
|
|
10
11
|
/** Template slug to create. Defaults to "base". */
|
|
11
12
|
template?: string;
|
|
@@ -22,7 +23,7 @@ export interface SandboxCreateOpts extends ConnectionOpts {
|
|
|
22
23
|
/** Timeout lifecycle policy. Defaults to killing the sandbox at timeout. */
|
|
23
24
|
lifecycle?: SandboxLifecycle;
|
|
24
25
|
/** Persistent volumes to mount, keyed by guest path. */
|
|
25
|
-
volumeMounts?: Record<string, string | {
|
|
26
|
+
volumeMounts?: Record<string, string | Volume | {
|
|
26
27
|
name: string;
|
|
27
28
|
}>;
|
|
28
29
|
}
|
|
@@ -62,6 +63,7 @@ export interface SandboxListOpts extends ConnectionOpts {
|
|
|
62
63
|
/** Team slug to list within. */
|
|
63
64
|
team?: string;
|
|
64
65
|
}
|
|
66
|
+
type SandboxRequestOpts = Pick<ConnectionOpts, 'requestTimeoutMs' | 'signal'>;
|
|
65
67
|
export interface SandboxInfo {
|
|
66
68
|
sandboxId: string;
|
|
67
69
|
templateId?: string;
|
|
@@ -138,7 +140,6 @@ export interface SnapshotListOpts extends ConnectionOpts {
|
|
|
138
140
|
export interface RestoreSnapshotOpts extends ConnectionOpts {
|
|
139
141
|
checkpointId?: string | number;
|
|
140
142
|
snapshotId?: string | number;
|
|
141
|
-
timeout?: number;
|
|
142
143
|
timeoutMs?: number;
|
|
143
144
|
}
|
|
144
145
|
/** Paginator for listing sandbox snapshots. */
|
|
@@ -172,14 +173,12 @@ export declare class Sandbox {
|
|
|
172
173
|
/** Default sandbox lifetime in milliseconds. */
|
|
173
174
|
static readonly defaultSandboxTimeoutMs = 300000;
|
|
174
175
|
files: Filesystem;
|
|
175
|
-
filesystem: Filesystem;
|
|
176
176
|
commands: Commands;
|
|
177
177
|
process: ProcessManager;
|
|
178
178
|
pty: Pty;
|
|
179
179
|
terminal: TerminalManager;
|
|
180
180
|
git: Git;
|
|
181
181
|
cwd: string | undefined;
|
|
182
|
-
envVars: Record<string, string>;
|
|
183
182
|
readonly sandboxId: string;
|
|
184
183
|
private readonly mcpPort;
|
|
185
184
|
private mcpToken;
|
|
@@ -202,18 +201,13 @@ export declare class Sandbox {
|
|
|
202
201
|
static create(template: string, opts?: SandboxCreateOpts): Promise<Sandbox>;
|
|
203
202
|
/** Connect to an existing sandbox and return it with a fresh data-plane session. */
|
|
204
203
|
static connect(sandboxId: string, opts?: SandboxConnectOpts): Promise<Sandbox>;
|
|
205
|
-
/** Alias for `connect`. */
|
|
206
|
-
static reconnect(sandboxId: string, opts?: SandboxConnectOpts): Promise<Sandbox>;
|
|
207
|
-
static reconnect(opts: SandboxConnectOpts & {
|
|
208
|
-
sandboxID: string;
|
|
209
|
-
}): Promise<Sandbox>;
|
|
210
204
|
/** Refresh this sandbox's data-plane session in place. */
|
|
211
205
|
connect(opts?: SandboxConnectOpts): Promise<this>;
|
|
212
206
|
/** Resume a paused sandbox by id. */
|
|
213
207
|
static resume(sandboxId: string, opts?: SandboxConnectOpts): Promise<boolean>;
|
|
214
208
|
/** Pause a sandbox by id. Returns false when it was already paused. */
|
|
215
209
|
static betaPause(sandboxId: string, opts?: ConnectionOpts): Promise<boolean>;
|
|
216
|
-
/**
|
|
210
|
+
/** Pause a sandbox by id. */
|
|
217
211
|
static pause(sandboxId: string, opts?: ConnectionOpts): Promise<boolean>;
|
|
218
212
|
/** Destroy a sandbox by id. */
|
|
219
213
|
static kill(sandboxId: string, opts?: ConnectionOpts | string): Promise<boolean>;
|
|
@@ -222,8 +216,6 @@ export declare class Sandbox {
|
|
|
222
216
|
/** Atomically replace a sandbox's network egress policy by id. */
|
|
223
217
|
static updateNetwork(sandboxId: string, network: SandboxNetworkUpdate, opts?: SandboxNetworkUpdateOpts): Promise<void>;
|
|
224
218
|
private static putNetwork;
|
|
225
|
-
/** Deprecated alias for `getInfo`. */
|
|
226
|
-
static getFullInfo(sandboxId: string, opts?: ConnectionOpts): Promise<SandboxInfo>;
|
|
227
219
|
/** Create a Watasu checkpoint using snapshot naming. */
|
|
228
220
|
static createSnapshot(sandboxId: string, opts?: CreateSnapshotOpts): Promise<SnapshotInfo>;
|
|
229
221
|
/** List snapshots visible to the configured API key. */
|
|
@@ -231,19 +223,17 @@ export declare class Sandbox {
|
|
|
231
223
|
/** Delete a snapshot by id. Returns `false` when the snapshot does not exist. */
|
|
232
224
|
static deleteSnapshot(snapshotId: string, opts?: ConnectionOpts): Promise<boolean>;
|
|
233
225
|
/** Destroy this sandbox. */
|
|
234
|
-
kill(): Promise<boolean>;
|
|
226
|
+
kill(opts?: SandboxRequestOpts): Promise<boolean>;
|
|
235
227
|
/** Check if this sandbox is in a runtime-active lifecycle state. */
|
|
236
|
-
isRunning(opts?:
|
|
228
|
+
isRunning(opts?: SandboxRequestOpts): Promise<boolean>;
|
|
237
229
|
/** Set a sandbox's lifetime by id. */
|
|
238
230
|
static setTimeout(sandboxId: string, timeoutMs: number, opts?: ConnectionOpts): Promise<void>;
|
|
239
231
|
/** Set this sandbox's lifetime. */
|
|
240
|
-
setTimeout(timeoutMs: number): Promise<void>;
|
|
241
|
-
/** Keep the sandbox alive for `duration` milliseconds. */
|
|
242
|
-
keepAlive(duration: number): Promise<void>;
|
|
232
|
+
setTimeout(timeoutMs: number, opts?: SandboxRequestOpts): Promise<void>;
|
|
243
233
|
/** Fetch control-plane metadata for a sandbox by id. */
|
|
244
234
|
static getInfo(sandboxId: string, opts?: ConnectionOpts): Promise<SandboxInfo>;
|
|
245
235
|
/** Fetch the latest control-plane metadata for this sandbox. */
|
|
246
|
-
getInfo(): Promise<SandboxInfo>;
|
|
236
|
+
getInfo(opts?: SandboxRequestOpts): Promise<SandboxInfo>;
|
|
247
237
|
/** Fetch latest sandbox metrics. */
|
|
248
238
|
getMetrics(opts?: SandboxMetricsOpts): Promise<SandboxMetrics[]>;
|
|
249
239
|
/** Create a Watasu checkpoint using snapshot naming. */
|
|
@@ -260,16 +250,10 @@ export declare class Sandbox {
|
|
|
260
250
|
static list(opts?: SandboxListOpts | string): SandboxPaginator;
|
|
261
251
|
/** Return the public hostname for an exposed sandbox port. */
|
|
262
252
|
getHost(port: number): string;
|
|
263
|
-
/** Return the public hostname for the sandbox or an exposed sandbox port. */
|
|
264
|
-
getHostname(port?: number): string;
|
|
265
253
|
/** Return the conventional MCP URL for this sandbox. */
|
|
266
254
|
getMcpUrl(): string;
|
|
267
255
|
/** Return the MCP gateway token when the sandbox contains one. */
|
|
268
256
|
getMcpToken(): Promise<string | undefined>;
|
|
269
|
-
/** Return a protocol string for a secure or insecure sandbox URL. */
|
|
270
|
-
getProtocol(baseProtocol?: string, secure?: boolean): string;
|
|
271
|
-
/** Close the local SDK attachment. This does not destroy the sandbox. */
|
|
272
|
-
close(): Promise<void>;
|
|
273
257
|
/** Get a signed URL that accepts a POST upload for a sandbox file path. */
|
|
274
258
|
uploadUrl(path?: string, opts?: SandboxUrlOpts): Promise<string>;
|
|
275
259
|
/** Get a signed URL that accepts a GET download for a sandbox file path. */
|
|
@@ -282,7 +266,7 @@ export declare class Sandbox {
|
|
|
282
266
|
updateNetwork(network: SandboxNetworkUpdate, opts?: SandboxNetworkUpdateOpts): Promise<void>;
|
|
283
267
|
/** Pause this sandbox. Returns false when it was already paused. */
|
|
284
268
|
betaPause(opts?: ConnectionOpts): Promise<boolean>;
|
|
285
|
-
/**
|
|
269
|
+
/** Pause this sandbox. Returns false when it was already paused. */
|
|
286
270
|
pause(opts?: ConnectionOpts): Promise<boolean>;
|
|
287
271
|
/** Resume this sandbox and refresh its data-plane session. */
|
|
288
272
|
resume(opts?: SandboxConnectOpts): Promise<boolean>;
|
|
@@ -295,3 +279,4 @@ export declare class Sandbox {
|
|
|
295
279
|
protected runtimeDeleteJson(path: string, opts?: ConnectionOpts): Promise<Record<string, unknown>>;
|
|
296
280
|
private configOptions;
|
|
297
281
|
}
|
|
282
|
+
export {};
|
package/dist/sandbox.js
CHANGED
|
@@ -24,6 +24,7 @@ export class SnapshotPaginator {
|
|
|
24
24
|
const control = new ControlClient(config);
|
|
25
25
|
const payload = await control.get(snapshotListPath(this.opts, this.nextToken), {
|
|
26
26
|
requestTimeoutMs: opts.requestTimeoutMs,
|
|
27
|
+
signal: opts.signal,
|
|
27
28
|
});
|
|
28
29
|
this.nextToken = stringValue(payload.next_token ?? payload.nextToken);
|
|
29
30
|
this.hasNext = this.nextToken !== undefined;
|
|
@@ -57,6 +58,7 @@ export class SandboxPaginator {
|
|
|
57
58
|
const control = new ControlClient(config);
|
|
58
59
|
const payload = await control.get(sandboxListPath(this.opts, this.nextToken), {
|
|
59
60
|
requestTimeoutMs: opts.requestTimeoutMs,
|
|
61
|
+
signal: opts.signal,
|
|
60
62
|
});
|
|
61
63
|
this.nextToken = stringValue(payload.next_token ?? payload.nextToken);
|
|
62
64
|
this.hasNext = this.nextToken !== undefined;
|
|
@@ -80,14 +82,12 @@ export class Sandbox {
|
|
|
80
82
|
/** Default sandbox lifetime in milliseconds. */
|
|
81
83
|
static defaultSandboxTimeoutMs = 300_000;
|
|
82
84
|
files;
|
|
83
|
-
filesystem;
|
|
84
85
|
commands;
|
|
85
86
|
process;
|
|
86
87
|
pty;
|
|
87
88
|
terminal;
|
|
88
89
|
git;
|
|
89
90
|
cwd;
|
|
90
|
-
envVars;
|
|
91
91
|
sandboxId;
|
|
92
92
|
mcpPort = 50005;
|
|
93
93
|
mcpToken;
|
|
@@ -101,12 +101,10 @@ export class Sandbox {
|
|
|
101
101
|
this.config = opts.connectionConfig;
|
|
102
102
|
this.control = opts.control ?? new ControlClient(this.config);
|
|
103
103
|
this.envs = opts.envs ?? {};
|
|
104
|
-
this.envVars = this.envs;
|
|
105
104
|
this.sandbox = opts.sandbox ?? {};
|
|
106
105
|
const dataPlane = dataPlaneFromSession(opts.session, this.config);
|
|
107
106
|
this.dataPlane = dataPlane;
|
|
108
107
|
this.files = new Filesystem(dataPlane);
|
|
109
|
-
this.filesystem = this.files;
|
|
110
108
|
this.commands = new Commands(dataPlane, this.config, this.envs);
|
|
111
109
|
this.process = new ProcessManager(this.commands);
|
|
112
110
|
this.pty = new Pty(dataPlane, this.config);
|
|
@@ -141,6 +139,7 @@ export class Sandbox {
|
|
|
141
139
|
const response = await control.post('/sandboxes', {
|
|
142
140
|
json: sandboxPayload,
|
|
143
141
|
requestTimeoutMs: sessionOperationRequestTimeout(config, sandboxOpts),
|
|
142
|
+
signal: sandboxOpts.signal,
|
|
144
143
|
});
|
|
145
144
|
const sandbox = record(response.sandbox ?? response);
|
|
146
145
|
const sandboxId = sandbox.id ?? sandbox.sandbox_id;
|
|
@@ -160,10 +159,14 @@ export class Sandbox {
|
|
|
160
159
|
static async connect(sandboxId, opts = {}) {
|
|
161
160
|
const config = new ConnectionConfig(opts);
|
|
162
161
|
const control = new ControlClient(config);
|
|
163
|
-
const info = await control.get(`/sandboxes/${sandboxId}
|
|
162
|
+
const info = await control.get(`/sandboxes/${sandboxId}`, {
|
|
163
|
+
requestTimeoutMs: opts.requestTimeoutMs,
|
|
164
|
+
signal: opts.signal,
|
|
165
|
+
});
|
|
164
166
|
const response = await control.post(`/sandboxes/${sandboxId}/resume`, {
|
|
165
167
|
json: opts.timeoutMs ? { timeout: Math.ceil(opts.timeoutMs / 1000) } : {},
|
|
166
168
|
requestTimeoutMs: sessionOperationRequestTimeout(config, opts),
|
|
169
|
+
signal: opts.signal,
|
|
167
170
|
});
|
|
168
171
|
return new this({
|
|
169
172
|
sandboxId,
|
|
@@ -173,22 +176,17 @@ export class Sandbox {
|
|
|
173
176
|
sandbox: record(response.sandbox ?? info.sandbox ?? {}),
|
|
174
177
|
});
|
|
175
178
|
}
|
|
176
|
-
static async reconnect(sandboxOrOpts, opts = {}) {
|
|
177
|
-
if (typeof sandboxOrOpts === 'string')
|
|
178
|
-
return this.connect(sandboxOrOpts, opts);
|
|
179
|
-
return this.connect(sandboxOrOpts.sandboxID, sandboxOrOpts);
|
|
180
|
-
}
|
|
181
179
|
/** Refresh this sandbox's data-plane session in place. */
|
|
182
180
|
async connect(opts = {}) {
|
|
183
181
|
const response = await this.control.post(`/sandboxes/${this.sandboxId}/resume`, {
|
|
184
182
|
json: opts.timeoutMs ? { timeout: Math.ceil(opts.timeoutMs / 1000) } : {},
|
|
185
183
|
requestTimeoutMs: sessionOperationRequestTimeout(this.config, opts),
|
|
184
|
+
signal: opts.signal,
|
|
186
185
|
});
|
|
187
186
|
this.sandbox = record(response.sandbox ?? this.sandbox);
|
|
188
187
|
const dataPlane = dataPlaneFromSession(response.session, this.config);
|
|
189
188
|
this.dataPlane = dataPlane;
|
|
190
189
|
this.files = new Filesystem(dataPlane);
|
|
191
|
-
this.filesystem = this.files;
|
|
192
190
|
this.commands = new Commands(dataPlane, this.config, this.envs);
|
|
193
191
|
this.process = new ProcessManager(this.commands);
|
|
194
192
|
this.pty = new Pty(dataPlane, this.config);
|
|
@@ -207,6 +205,7 @@ export class Sandbox {
|
|
|
207
205
|
try {
|
|
208
206
|
await control.post(`/sandboxes/${sandboxId}/pause`, {
|
|
209
207
|
requestTimeoutMs: opts.requestTimeoutMs,
|
|
208
|
+
signal: opts.signal,
|
|
210
209
|
});
|
|
211
210
|
return true;
|
|
212
211
|
}
|
|
@@ -216,14 +215,18 @@ export class Sandbox {
|
|
|
216
215
|
throw error;
|
|
217
216
|
}
|
|
218
217
|
}
|
|
219
|
-
/**
|
|
218
|
+
/** Pause a sandbox by id. */
|
|
220
219
|
static async pause(sandboxId, opts = {}) {
|
|
221
220
|
return this.betaPause(sandboxId, opts);
|
|
222
221
|
}
|
|
223
222
|
/** Destroy a sandbox by id. */
|
|
224
223
|
static async kill(sandboxId, opts = {}) {
|
|
224
|
+
const requestOpts = typeof opts === 'string' ? {} : opts;
|
|
225
225
|
const control = new ControlClient(new ConnectionConfig(typeof opts === 'string' ? { apiKey: opts } : opts));
|
|
226
|
-
await control.delete(`/sandboxes/${sandboxId}
|
|
226
|
+
await control.delete(`/sandboxes/${sandboxId}`, {
|
|
227
|
+
requestTimeoutMs: requestOpts.requestTimeoutMs,
|
|
228
|
+
signal: requestOpts.signal,
|
|
229
|
+
});
|
|
227
230
|
return true;
|
|
228
231
|
}
|
|
229
232
|
/** Fetch sandbox metrics by id. */
|
|
@@ -231,6 +234,7 @@ export class Sandbox {
|
|
|
231
234
|
const control = new ControlClient(new ConnectionConfig(opts));
|
|
232
235
|
const payload = await control.get(metricsPath(sandboxId, opts), {
|
|
233
236
|
requestTimeoutMs: opts.requestTimeoutMs,
|
|
237
|
+
signal: opts.signal,
|
|
234
238
|
});
|
|
235
239
|
return metricsList(payload.metrics ?? payload);
|
|
236
240
|
}
|
|
@@ -243,19 +247,17 @@ export class Sandbox {
|
|
|
243
247
|
const response = await control.put(`/sandboxes/${sandboxId}/network`, {
|
|
244
248
|
json: networkUpdatePayload(network),
|
|
245
249
|
requestTimeoutMs: opts.requestTimeoutMs,
|
|
250
|
+
signal: opts.signal,
|
|
246
251
|
});
|
|
247
252
|
return response.sandbox === undefined ? undefined : record(response.sandbox);
|
|
248
253
|
}
|
|
249
|
-
/** Deprecated alias for `getInfo`. */
|
|
250
|
-
static async getFullInfo(sandboxId, opts = {}) {
|
|
251
|
-
return this.getInfo(sandboxId, opts);
|
|
252
|
-
}
|
|
253
254
|
/** Create a Watasu checkpoint using snapshot naming. */
|
|
254
255
|
static async createSnapshot(sandboxId, opts = {}) {
|
|
255
256
|
const control = new ControlClient(new ConnectionConfig(opts));
|
|
256
257
|
const payload = await control.post(`/sandboxes/${sandboxId}/snapshots`, {
|
|
257
258
|
json: snapshotPayload(opts),
|
|
258
259
|
requestTimeoutMs: opts.requestTimeoutMs,
|
|
260
|
+
signal: opts.signal,
|
|
259
261
|
});
|
|
260
262
|
return snapshotInfo(record(payload.sandbox_checkpoint ?? payload.snapshot ?? payload));
|
|
261
263
|
}
|
|
@@ -269,6 +271,7 @@ export class Sandbox {
|
|
|
269
271
|
try {
|
|
270
272
|
await control.delete(`/sandbox_snapshots/${snapshotId}`, {
|
|
271
273
|
requestTimeoutMs: opts.requestTimeoutMs,
|
|
274
|
+
signal: opts.signal,
|
|
272
275
|
});
|
|
273
276
|
return true;
|
|
274
277
|
}
|
|
@@ -279,8 +282,11 @@ export class Sandbox {
|
|
|
279
282
|
}
|
|
280
283
|
}
|
|
281
284
|
/** Destroy this sandbox. */
|
|
282
|
-
async kill() {
|
|
283
|
-
await this.control.delete(`/sandboxes/${this.sandboxId}
|
|
285
|
+
async kill(opts = {}) {
|
|
286
|
+
await this.control.delete(`/sandboxes/${this.sandboxId}`, {
|
|
287
|
+
requestTimeoutMs: opts.requestTimeoutMs,
|
|
288
|
+
signal: opts.signal,
|
|
289
|
+
});
|
|
284
290
|
return true;
|
|
285
291
|
}
|
|
286
292
|
/** Check if this sandbox is in a runtime-active lifecycle state. */
|
|
@@ -288,6 +294,7 @@ export class Sandbox {
|
|
|
288
294
|
try {
|
|
289
295
|
const payload = await this.control.get(`/sandboxes/${this.sandboxId}`, {
|
|
290
296
|
requestTimeoutMs: opts.requestTimeoutMs,
|
|
297
|
+
signal: opts.signal,
|
|
291
298
|
});
|
|
292
299
|
const item = record(payload.sandbox ?? payload);
|
|
293
300
|
return ['creating', 'ready', 'checkpointing', 'restoring', 'stopping'].includes(String(item.state ?? ''));
|
|
@@ -303,27 +310,33 @@ export class Sandbox {
|
|
|
303
310
|
const control = new ControlClient(new ConnectionConfig(opts));
|
|
304
311
|
await control.post(`/sandboxes/${sandboxId}/timeout`, {
|
|
305
312
|
json: { timeout: Math.ceil(timeoutMs / 1000) },
|
|
313
|
+
requestTimeoutMs: opts.requestTimeoutMs,
|
|
314
|
+
signal: opts.signal,
|
|
306
315
|
});
|
|
307
316
|
}
|
|
308
317
|
/** Set this sandbox's lifetime. */
|
|
309
|
-
async setTimeout(timeoutMs) {
|
|
318
|
+
async setTimeout(timeoutMs, opts = {}) {
|
|
310
319
|
await this.control.post(`/sandboxes/${this.sandboxId}/timeout`, {
|
|
311
320
|
json: { timeout: Math.ceil(timeoutMs / 1000) },
|
|
321
|
+
requestTimeoutMs: opts.requestTimeoutMs,
|
|
322
|
+
signal: opts.signal,
|
|
312
323
|
});
|
|
313
324
|
}
|
|
314
|
-
/** Keep the sandbox alive for `duration` milliseconds. */
|
|
315
|
-
async keepAlive(duration) {
|
|
316
|
-
await this.setTimeout(duration);
|
|
317
|
-
}
|
|
318
325
|
/** Fetch control-plane metadata for a sandbox by id. */
|
|
319
326
|
static async getInfo(sandboxId, opts = {}) {
|
|
320
327
|
const control = new ControlClient(new ConnectionConfig(opts));
|
|
321
|
-
const payload = await control.get(`/sandboxes/${sandboxId}
|
|
328
|
+
const payload = await control.get(`/sandboxes/${sandboxId}`, {
|
|
329
|
+
requestTimeoutMs: opts.requestTimeoutMs,
|
|
330
|
+
signal: opts.signal,
|
|
331
|
+
});
|
|
322
332
|
return sandboxInfo(record(payload.sandbox ?? payload));
|
|
323
333
|
}
|
|
324
334
|
/** Fetch the latest control-plane metadata for this sandbox. */
|
|
325
|
-
async getInfo() {
|
|
326
|
-
const payload = await this.control.get(`/sandboxes/${this.sandboxId}
|
|
335
|
+
async getInfo(opts = {}) {
|
|
336
|
+
const payload = await this.control.get(`/sandboxes/${this.sandboxId}`, {
|
|
337
|
+
requestTimeoutMs: opts.requestTimeoutMs,
|
|
338
|
+
signal: opts.signal,
|
|
339
|
+
});
|
|
327
340
|
return sandboxInfo(record(payload.sandbox ?? payload));
|
|
328
341
|
}
|
|
329
342
|
/** Fetch latest sandbox metrics. */
|
|
@@ -355,13 +368,12 @@ export class Sandbox {
|
|
|
355
368
|
if (checkpointId === undefined)
|
|
356
369
|
throw new SandboxError('checkpointId or snapshotId is required');
|
|
357
370
|
const payload = { checkpoint_id: checkpointId };
|
|
358
|
-
if (restoreOpts.timeout !== undefined)
|
|
359
|
-
payload.timeout_seconds = restoreOpts.timeout;
|
|
360
371
|
if (restoreOpts.timeoutMs !== undefined)
|
|
361
372
|
payload.timeout_seconds = Math.ceil(restoreOpts.timeoutMs / 1000);
|
|
362
373
|
const response = await this.control.post(`/sandboxes/${this.sandboxId}/restore`, {
|
|
363
374
|
json: payload,
|
|
364
375
|
requestTimeoutMs: restoreOpts.requestTimeoutMs,
|
|
376
|
+
signal: restoreOpts.signal,
|
|
365
377
|
});
|
|
366
378
|
return sandboxInfo(record(response.sandbox ?? response));
|
|
367
379
|
}
|
|
@@ -379,12 +391,6 @@ export class Sandbox {
|
|
|
379
391
|
throw new SandboxError('port response did not include host or url');
|
|
380
392
|
return `p${port}-${routeToken}.sandbox.${this.config.dataPlaneDomain}`;
|
|
381
393
|
}
|
|
382
|
-
/** Return the public hostname for the sandbox or an exposed sandbox port. */
|
|
383
|
-
getHostname(port) {
|
|
384
|
-
if (port !== undefined)
|
|
385
|
-
return this.getHost(port);
|
|
386
|
-
return new URL(this.dataPlane.baseUrl).host;
|
|
387
|
-
}
|
|
388
394
|
/** Return the conventional MCP URL for this sandbox. */
|
|
389
395
|
getMcpUrl() {
|
|
390
396
|
return `https://${this.getHost(this.mcpPort)}/mcp`;
|
|
@@ -404,12 +410,6 @@ export class Sandbox {
|
|
|
404
410
|
throw error;
|
|
405
411
|
}
|
|
406
412
|
}
|
|
407
|
-
/** Return a protocol string for a secure or insecure sandbox URL. */
|
|
408
|
-
getProtocol(baseProtocol = 'http', secure = true) {
|
|
409
|
-
return `${baseProtocol}${secure ? 's' : ''}`;
|
|
410
|
-
}
|
|
411
|
-
/** Close the local SDK attachment. This does not destroy the sandbox. */
|
|
412
|
-
async close() { }
|
|
413
413
|
/** Get a signed URL that accepts a POST upload for a sandbox file path. */
|
|
414
414
|
async uploadUrl(path = '', opts = {}) {
|
|
415
415
|
const fileUrl = await this.fileUrl('/upload_url', path, opts);
|
|
@@ -437,7 +437,7 @@ export class Sandbox {
|
|
|
437
437
|
async betaPause(opts = {}) {
|
|
438
438
|
return Sandbox.betaPause(this.sandboxId, { ...this.configOptions(), ...opts });
|
|
439
439
|
}
|
|
440
|
-
/**
|
|
440
|
+
/** Pause this sandbox. Returns false when it was already paused. */
|
|
441
441
|
async pause(opts = {}) {
|
|
442
442
|
return this.betaPause(opts);
|
|
443
443
|
}
|
|
@@ -455,6 +455,7 @@ export class Sandbox {
|
|
|
455
455
|
expires_in_seconds: opts.expiresInSeconds,
|
|
456
456
|
}),
|
|
457
457
|
requestTimeoutMs: opts.requestTimeoutMs,
|
|
458
|
+
signal: opts.signal,
|
|
458
459
|
});
|
|
459
460
|
return fileUrlInfo(record(payload.file_url ?? payload));
|
|
460
461
|
}
|
|
@@ -463,33 +464,42 @@ export class Sandbox {
|
|
|
463
464
|
return this.dataPlane.postJson(path, {
|
|
464
465
|
json,
|
|
465
466
|
requestTimeoutMs: opts.requestTimeoutMs,
|
|
467
|
+
signal: opts.signal,
|
|
466
468
|
});
|
|
467
469
|
}
|
|
468
470
|
/** GET JSON from the sandbox data-plane runtime API. */
|
|
469
471
|
async runtimeGetJson(path, opts = {}) {
|
|
470
472
|
return this.dataPlane.getJson(path, {
|
|
471
473
|
requestTimeoutMs: opts.requestTimeoutMs,
|
|
474
|
+
signal: opts.signal,
|
|
472
475
|
});
|
|
473
476
|
}
|
|
474
477
|
/** DELETE JSON from the sandbox data-plane runtime API. */
|
|
475
478
|
async runtimeDeleteJson(path, opts = {}) {
|
|
476
479
|
return this.dataPlane.deleteJson(path, {
|
|
477
480
|
requestTimeoutMs: opts.requestTimeoutMs,
|
|
481
|
+
signal: opts.signal,
|
|
478
482
|
});
|
|
479
483
|
}
|
|
480
484
|
configOptions() {
|
|
481
485
|
return {
|
|
482
486
|
apiKey: this.config.apiKey,
|
|
483
487
|
apiUrl: this.config.apiUrl,
|
|
488
|
+
sandboxUrl: this.config.sandboxUrl,
|
|
484
489
|
dataPlaneDomain: this.config.dataPlaneDomain,
|
|
485
490
|
requestTimeoutMs: this.config.requestTimeoutMs,
|
|
491
|
+
headers: this.config.headers,
|
|
492
|
+
apiHeaders: this.config.apiHeaders,
|
|
493
|
+
debug: this.config.debug,
|
|
494
|
+
signal: this.config.signal,
|
|
495
|
+
proxy: this.config.proxy,
|
|
486
496
|
};
|
|
487
497
|
}
|
|
488
498
|
}
|
|
489
499
|
function dataPlaneFromSession(session, config) {
|
|
490
500
|
const item = record(session);
|
|
491
501
|
const token = item.token ?? item.access_token;
|
|
492
|
-
const url = item.data_plane_url;
|
|
502
|
+
const url = config.sandboxUrl ?? item.data_plane_url;
|
|
493
503
|
if (!session)
|
|
494
504
|
throw new SandboxError('sandbox session is required for data-plane operations');
|
|
495
505
|
if (typeof token !== 'string' || typeof url !== 'string') {
|
|
@@ -499,8 +509,8 @@ function dataPlaneFromSession(session, config) {
|
|
|
499
509
|
}
|
|
500
510
|
function sandboxListPath(opts, nextToken) {
|
|
501
511
|
const params = new URLSearchParams();
|
|
502
|
-
if (opts.team)
|
|
503
|
-
params.set('team', opts.team);
|
|
512
|
+
if (opts.team !== undefined)
|
|
513
|
+
params.set('team', String(opts.team));
|
|
504
514
|
if (opts.limit !== undefined)
|
|
505
515
|
params.set('limit', String(opts.limit));
|
|
506
516
|
if (nextToken)
|
package/dist/template.d.ts
CHANGED
|
@@ -102,8 +102,6 @@ export declare class ReadyCmd {
|
|
|
102
102
|
export declare function waitForPort(port: number): ReadyCmd;
|
|
103
103
|
/** Return a ready check that waits for a URL to return an HTTP status code. */
|
|
104
104
|
export declare function waitForURL(url: string, statusCode?: number): ReadyCmd;
|
|
105
|
-
/** Alias for `waitForURL`. */
|
|
106
|
-
export declare const waitForUrl: typeof waitForURL;
|
|
107
105
|
/** Return a ready check that waits for a process name. */
|
|
108
106
|
export declare function waitForProcess(processName: string): ReadyCmd;
|
|
109
107
|
/** Return a ready check that waits for a file to exist. */
|
|
@@ -204,10 +202,13 @@ export declare class TemplateBase {
|
|
|
204
202
|
}): TemplateBuilder;
|
|
205
203
|
setStartCmd(startCommand: string, readyCommand: ReadyCommand): TemplateFinal;
|
|
206
204
|
setReadyCmd(readyCommand: ReadyCommand): TemplateFinal;
|
|
205
|
+
betaDevContainerPrebuild(devcontainerDirectory: string): TemplateBuilder;
|
|
206
|
+
betaSetDevContainerStart(devcontainerDirectory: string): TemplateFinal;
|
|
207
207
|
setEnvs(envs: Record<string, string>): TemplateBuilder;
|
|
208
208
|
skipCache(): TemplateBuilder;
|
|
209
209
|
toBuildSpec(): BuildSpec;
|
|
210
210
|
private addPackages;
|
|
211
|
+
private requireDevContainerTemplate;
|
|
211
212
|
private addCopySource;
|
|
212
213
|
private addFileSpec;
|
|
213
214
|
private resolveContextPath;
|
package/dist/template.js
CHANGED
|
@@ -22,8 +22,6 @@ export function waitForPort(port) {
|
|
|
22
22
|
export function waitForURL(url, statusCode = 200) {
|
|
23
23
|
return new ReadyCmd(`curl -s -o /dev/null -w "%{http_code}" ${url} | grep -q "${statusCode}"`);
|
|
24
24
|
}
|
|
25
|
-
/** Alias for `waitForURL`. */
|
|
26
|
-
export const waitForUrl = waitForURL;
|
|
27
25
|
/** Return a ready check that waits for a process name. */
|
|
28
26
|
export function waitForProcess(processName) {
|
|
29
27
|
return new ReadyCmd(`pgrep ${processName} > /dev/null`);
|
|
@@ -286,6 +284,14 @@ export class TemplateBase {
|
|
|
286
284
|
this.readyCmd = readyCommandText(readyCommand);
|
|
287
285
|
return this;
|
|
288
286
|
}
|
|
287
|
+
betaDevContainerPrebuild(devcontainerDirectory) {
|
|
288
|
+
this.requireDevContainerTemplate('betaDevContainerPrebuild');
|
|
289
|
+
return this.runCmd(`devcontainer build --workspace-folder ${devcontainerDirectory}`, { user: 'root' });
|
|
290
|
+
}
|
|
291
|
+
betaSetDevContainerStart(devcontainerDirectory) {
|
|
292
|
+
this.requireDevContainerTemplate('betaSetDevContainerStart');
|
|
293
|
+
return this.setStartCmd(`sudo devcontainer up --workspace-folder ${devcontainerDirectory} && sudo /prepare-exec.sh ${devcontainerDirectory} | sudo tee /devcontainer.sh > /dev/null && sudo chmod +x /devcontainer.sh && sudo touch /devcontainer.up`, waitForFile('/devcontainer.up'));
|
|
294
|
+
}
|
|
289
295
|
setEnvs(envs) {
|
|
290
296
|
Object.assign(this.env, envs);
|
|
291
297
|
return this;
|
|
@@ -315,6 +321,11 @@ export class TemplateBase {
|
|
|
315
321
|
addPackages(manager, packages) {
|
|
316
322
|
this.packages[manager] = [...(this.packages[manager] ?? []), ...packages];
|
|
317
323
|
}
|
|
324
|
+
requireDevContainerTemplate(method) {
|
|
325
|
+
if (this.base !== 'devcontainer') {
|
|
326
|
+
throw new SandboxError(`${method} can only be used with the devcontainer template`);
|
|
327
|
+
}
|
|
328
|
+
}
|
|
318
329
|
addCopySource(source, dest, options, multipleSources) {
|
|
319
330
|
const sourcePath = this.resolveContextPath(source);
|
|
320
331
|
const stat = fs.statSync(sourcePath);
|
package/dist/terminal.d.ts
CHANGED
|
@@ -13,9 +13,8 @@ export type TerminalOpts = {
|
|
|
13
13
|
terminalID?: string;
|
|
14
14
|
cmd?: string;
|
|
15
15
|
cwd?: string;
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
timeout?: number;
|
|
16
|
+
envs?: Record<string, string>;
|
|
17
|
+
timeoutMs?: number;
|
|
19
18
|
};
|
|
20
19
|
/** A running terminal session in a sandbox. */
|
|
21
20
|
export declare class Terminal {
|
package/dist/terminal.js
CHANGED
|
@@ -59,10 +59,9 @@ export class TerminalManager {
|
|
|
59
59
|
const handle = await this.pty.create({
|
|
60
60
|
cmd: opts.cmd,
|
|
61
61
|
cwd: opts.cwd,
|
|
62
|
-
|
|
63
|
-
envVars: opts.envVars,
|
|
62
|
+
envs: opts.envs,
|
|
64
63
|
size: opts.size,
|
|
65
|
-
|
|
64
|
+
timeoutMs: opts.timeoutMs,
|
|
66
65
|
onData: async (bytes) => {
|
|
67
66
|
const data = new TextDecoder().decode(bytes);
|
|
68
67
|
output.addData(data);
|
package/dist/transport.d.ts
CHANGED
|
@@ -15,6 +15,7 @@ export declare class DataPlaneClient {
|
|
|
15
15
|
readonly token: string;
|
|
16
16
|
private readonly config;
|
|
17
17
|
constructor(baseUrl: string, token: string, config: ConnectionConfig);
|
|
18
|
+
get headers(): Record<string, string>;
|
|
18
19
|
getJson(path: string, opts?: RequestOpts): Promise<JsonRecord>;
|
|
19
20
|
postJson(path: string, opts?: RequestOpts): Promise<JsonRecord>;
|
|
20
21
|
deleteJson(path: string, opts?: RequestOpts): Promise<JsonRecord>;
|
|
@@ -29,6 +30,7 @@ export interface RequestOpts {
|
|
|
29
30
|
body?: BodyInit | Uint8Array;
|
|
30
31
|
headers?: Record<string, string>;
|
|
31
32
|
requestTimeoutMs?: number;
|
|
33
|
+
signal?: AbortSignal;
|
|
32
34
|
}
|
|
33
35
|
export declare function withQuery(path: string, params: Record<string, string | number | boolean | undefined>): string;
|
|
34
36
|
export {};
|
package/dist/transport.js
CHANGED
|
@@ -28,9 +28,10 @@ export class ControlClient {
|
|
|
28
28
|
headers: {
|
|
29
29
|
...this.config.authHeaders,
|
|
30
30
|
...(opts.json ? { 'content-type': 'application/json' } : {}),
|
|
31
|
+
...(opts.headers ?? {}),
|
|
31
32
|
},
|
|
32
33
|
body: opts.json ? JSON.stringify(opts.json) : undefined,
|
|
33
|
-
}, opts.requestTimeoutMs ?? this.config.requestTimeoutMs);
|
|
34
|
+
}, opts.requestTimeoutMs ?? this.config.requestTimeoutMs, opts.signal ?? this.config.signal);
|
|
34
35
|
return parseJsonResponse(response);
|
|
35
36
|
}
|
|
36
37
|
}
|
|
@@ -43,6 +44,9 @@ export class DataPlaneClient {
|
|
|
43
44
|
this.token = token;
|
|
44
45
|
this.config = config;
|
|
45
46
|
}
|
|
47
|
+
get headers() {
|
|
48
|
+
return this.config.headers;
|
|
49
|
+
}
|
|
46
50
|
getJson(path, opts = {}) {
|
|
47
51
|
return this.request(path, { ...opts, method: 'GET' });
|
|
48
52
|
}
|
|
@@ -68,12 +72,13 @@ export class DataPlaneClient {
|
|
|
68
72
|
const response = await fetchWithTimeout(joinUrl(this.baseUrl, path), {
|
|
69
73
|
method: opts.method,
|
|
70
74
|
headers: {
|
|
75
|
+
...this.config.headers,
|
|
71
76
|
Authorization: `Bearer ${this.token}`,
|
|
72
77
|
...(opts.json ? { 'content-type': 'application/json' } : {}),
|
|
73
78
|
...(opts.headers ?? {}),
|
|
74
79
|
},
|
|
75
80
|
body: opts.json ? JSON.stringify(opts.json) : opts.body,
|
|
76
|
-
}, opts.requestTimeoutMs ?? this.config.requestTimeoutMs);
|
|
81
|
+
}, opts.requestTimeoutMs ?? this.config.requestTimeoutMs, opts.signal ?? this.config.signal);
|
|
77
82
|
if (!response.ok) {
|
|
78
83
|
throw errorFromResponse(response.status, await readJsonOrText(response));
|
|
79
84
|
}
|
|
@@ -109,14 +114,26 @@ async function readJsonOrText(response) {
|
|
|
109
114
|
return { message: text };
|
|
110
115
|
}
|
|
111
116
|
}
|
|
112
|
-
function fetchWithTimeout(url, init, timeoutMs) {
|
|
117
|
+
function fetchWithTimeout(url, init, timeoutMs, signal) {
|
|
113
118
|
const controller = new AbortController();
|
|
114
|
-
|
|
119
|
+
let timedOut = false;
|
|
120
|
+
const abortFromCaller = () => controller.abort();
|
|
121
|
+
if (signal?.aborted)
|
|
122
|
+
controller.abort();
|
|
123
|
+
else
|
|
124
|
+
signal?.addEventListener('abort', abortFromCaller, { once: true });
|
|
125
|
+
const timeout = setTimeout(() => {
|
|
126
|
+
timedOut = true;
|
|
127
|
+
controller.abort();
|
|
128
|
+
}, timeoutMs);
|
|
115
129
|
return fetch(url, { ...init, signal: controller.signal }).catch((error) => {
|
|
116
|
-
if (error?.name === 'AbortError')
|
|
130
|
+
if (error?.name === 'AbortError' && timedOut)
|
|
117
131
|
throw new TimeoutError();
|
|
118
132
|
throw error;
|
|
119
|
-
}).finally(() =>
|
|
133
|
+
}).finally(() => {
|
|
134
|
+
clearTimeout(timeout);
|
|
135
|
+
signal?.removeEventListener('abort', abortFromCaller);
|
|
136
|
+
});
|
|
120
137
|
}
|
|
121
138
|
function joinUrl(base, path) {
|
|
122
139
|
const normalizedBase = base.replace(/\/+$/, '');
|
package/dist/volume.d.ts
CHANGED
|
@@ -83,8 +83,6 @@ export declare class Volume {
|
|
|
83
83
|
static list(opts?: VolumeListOpts): Promise<VolumeInfo[]>;
|
|
84
84
|
/** Destroy a volume by id or name. Returns false when it does not exist. */
|
|
85
85
|
static destroy(volumeId: string, opts?: VolumeConnectionConfig): Promise<boolean>;
|
|
86
|
-
/** Alias for `destroy`. */
|
|
87
|
-
static delete(volumeId: string, opts?: VolumeConnectionConfig): Promise<boolean>;
|
|
88
86
|
/** Fetch this volume's latest metadata. */
|
|
89
87
|
getInfo(): Promise<VolumeInfo>;
|
|
90
88
|
/** Fetch metadata for a path inside this volume. */
|
|
@@ -114,7 +112,5 @@ export declare class Volume {
|
|
|
114
112
|
remove(path: string, opts?: ConnectionOpts): Promise<boolean>;
|
|
115
113
|
/** Destroy this volume. Returns false when it no longer exists. */
|
|
116
114
|
destroy(opts?: ConnectionOpts): Promise<boolean>;
|
|
117
|
-
/** Alias for `destroy`. */
|
|
118
|
-
delete(opts?: ConnectionOpts): Promise<boolean>;
|
|
119
115
|
private configOptions;
|
|
120
116
|
}
|