@watasu/sdk 0.1.51 → 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.
- package/dist/codeInterpreter.d.ts +17 -23
- package/dist/codeInterpreter.js +41 -48
- package/dist/connectionConfig.d.ts +21 -5
- package/dist/connectionConfig.js +46 -17
- package/dist/filesystem.d.ts +6 -0
- package/dist/filesystem.js +23 -1
- package/dist/git.d.ts +3 -0
- package/dist/git.js +27 -1
- package/dist/pty.d.ts +8 -3
- package/dist/sandbox.d.ts +62 -26
- package/dist/sandbox.js +148 -66
- package/dist/template.d.ts +2 -0
- package/dist/template.js +7 -1
- package/dist/volume.d.ts +12 -6
- package/dist/volume.js +22 -2
- package/package.json +1 -1
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { Sandbox as BaseSandbox
|
|
1
|
+
import { Sandbox as BaseSandbox } from './sandbox.js';
|
|
2
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';
|
|
@@ -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:
|
|
174
|
-
stderr:
|
|
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
|
|
197
|
-
|
|
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
|
-
|
|
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
|
|
211
|
-
requestTimeoutMs?: number;
|
|
212
|
-
signal?: AbortSignal;
|
|
213
|
-
}): Promise<void>;
|
|
213
|
+
removeCodeContext(context: Context | string): Promise<void>;
|
|
214
214
|
/** List persistent code contexts. */
|
|
215
|
-
listCodeContexts(
|
|
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
|
|
221
|
-
requestTimeoutMs?: number;
|
|
222
|
-
signal?: AbortSignal;
|
|
223
|
-
}): Promise<void>;
|
|
217
|
+
restartCodeContext(context: Context | string): Promise<void>;
|
|
224
218
|
}
|
|
225
219
|
export { Sandbox as default };
|
package/dist/codeInterpreter.js
CHANGED
|
@@ -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 =
|
|
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
|
|
157
|
-
logs:
|
|
158
|
-
|
|
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
|
-
|
|
188
|
-
return
|
|
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
|
-
|
|
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(
|
|
255
|
-
stderr: arrayOfUnknown(logs.stderr).map(
|
|
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
|
|
224
|
+
function outputLineFromApi(value) {
|
|
259
225
|
if (value && typeof value === 'object' && !Array.isArray(value)) {
|
|
260
226
|
const item = value;
|
|
261
|
-
return
|
|
227
|
+
return String(item.line ?? item.text ?? '');
|
|
262
228
|
}
|
|
263
|
-
return
|
|
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?:
|
|
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?:
|
|
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
|
|
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
|
|
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
|
|
66
|
+
getHost(sandboxId: string, port: number, sandboxDomain: string): string;
|
|
51
67
|
}
|
package/dist/connectionConfig.js
CHANGED
|
@@ -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
|
-
|
|
20
|
-
opts.
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
this.
|
|
24
|
-
this.
|
|
25
|
-
|
|
26
|
-
this.
|
|
27
|
-
|
|
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 ??
|
|
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
|
-
|
|
43
|
-
|
|
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,
|
|
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/filesystem.d.ts
CHANGED
|
@@ -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;
|
package/dist/filesystem.js
CHANGED
|
@@ -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
|
-
|
|
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/pty.d.ts
CHANGED
|
@@ -1,16 +1,21 @@
|
|
|
1
|
-
import { CommandHandle
|
|
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
|
|
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>;
|
package/dist/sandbox.d.ts
CHANGED
|
@@ -81,31 +81,55 @@ export interface SandboxListOpts extends ConnectionOpts {
|
|
|
81
81
|
/** Team slug to list within. */
|
|
82
82
|
team?: string;
|
|
83
83
|
}
|
|
84
|
-
type SandboxRequestOpts = Pick<ConnectionOpts, 'requestTimeoutMs' | 'signal'>;
|
|
85
84
|
export interface SandboxInfo {
|
|
86
85
|
sandboxId: string;
|
|
87
86
|
templateId?: string;
|
|
88
87
|
name?: string;
|
|
89
88
|
state?: string;
|
|
89
|
+
cpuCount?: number;
|
|
90
|
+
memoryMB?: number;
|
|
91
|
+
envdVersion?: string;
|
|
92
|
+
allowInternetAccess?: boolean;
|
|
93
|
+
network?: SandboxNetworkInfo;
|
|
94
|
+
sandboxDomain?: string;
|
|
90
95
|
lifecycle?: SandboxInfoLifecycle;
|
|
91
96
|
volumeMounts?: Array<{
|
|
92
97
|
name: string;
|
|
93
98
|
path: string;
|
|
94
99
|
}>;
|
|
95
100
|
metadata: Record<string, string>;
|
|
96
|
-
startedAt?:
|
|
97
|
-
endAt?:
|
|
101
|
+
startedAt?: Date;
|
|
102
|
+
endAt?: Date;
|
|
98
103
|
}
|
|
99
104
|
export interface SandboxInfoLifecycle {
|
|
100
105
|
onTimeout: 'kill' | 'pause' | string;
|
|
101
106
|
autoResume: boolean;
|
|
102
107
|
}
|
|
108
|
+
type SandboxConnectionDetails = {
|
|
109
|
+
sandboxId: string;
|
|
110
|
+
sandboxDomain: string | undefined;
|
|
111
|
+
envdVersion: string;
|
|
112
|
+
envdAccessToken: string | undefined;
|
|
113
|
+
trafficAccessToken: string | undefined;
|
|
114
|
+
connectionConfig: ConnectionConfig;
|
|
115
|
+
control: ControlClient;
|
|
116
|
+
session: unknown;
|
|
117
|
+
sandbox: Record<string, unknown>;
|
|
118
|
+
envs?: Record<string, string>;
|
|
119
|
+
};
|
|
103
120
|
export interface SandboxMetrics {
|
|
121
|
+
timestamp?: Date;
|
|
104
122
|
sandboxId?: string;
|
|
105
123
|
state?: string;
|
|
106
124
|
node?: string;
|
|
107
125
|
backend?: string;
|
|
108
126
|
cpuCount?: number;
|
|
127
|
+
cpuUsedPct?: number;
|
|
128
|
+
memUsed?: number;
|
|
129
|
+
memTotal?: number;
|
|
130
|
+
memCache?: number;
|
|
131
|
+
diskUsed?: number;
|
|
132
|
+
diskTotal?: number;
|
|
109
133
|
memoryMb?: number;
|
|
110
134
|
raw: Record<string, unknown>;
|
|
111
135
|
}
|
|
@@ -117,6 +141,7 @@ export interface SandboxMetricsOpts extends ConnectionOpts {
|
|
|
117
141
|
}
|
|
118
142
|
export interface SnapshotInfo {
|
|
119
143
|
snapshotId: string;
|
|
144
|
+
names: string[];
|
|
120
145
|
sandboxId?: string;
|
|
121
146
|
name?: string;
|
|
122
147
|
status?: string;
|
|
@@ -196,22 +221,28 @@ export declare class SandboxPaginator {
|
|
|
196
221
|
/** Running Watasu sandbox with ready `files` and `commands` helpers. */
|
|
197
222
|
export declare class Sandbox {
|
|
198
223
|
/** Default template slug used when create is called without a template. */
|
|
199
|
-
static readonly defaultTemplate: string;
|
|
224
|
+
protected static readonly defaultTemplate: string;
|
|
200
225
|
/** Default template slug used by MCP creation once Watasu supports it. */
|
|
201
|
-
static readonly defaultMcpTemplate: string;
|
|
226
|
+
protected static readonly defaultMcpTemplate: string;
|
|
202
227
|
/** Default sandbox lifetime in milliseconds. */
|
|
203
|
-
static readonly defaultSandboxTimeoutMs = 300000;
|
|
204
|
-
files: Filesystem;
|
|
205
|
-
commands: Commands;
|
|
206
|
-
process: ProcessManager;
|
|
207
|
-
pty: Pty;
|
|
208
|
-
terminal: TerminalManager;
|
|
209
|
-
git: Git;
|
|
228
|
+
protected static readonly defaultSandboxTimeoutMs = 300000;
|
|
229
|
+
readonly files: Filesystem;
|
|
230
|
+
readonly commands: Commands;
|
|
231
|
+
readonly process: ProcessManager;
|
|
232
|
+
readonly pty: Pty;
|
|
233
|
+
readonly terminal: TerminalManager;
|
|
234
|
+
readonly git: Git;
|
|
210
235
|
cwd: string | undefined;
|
|
211
236
|
readonly sandboxId: string;
|
|
212
|
-
|
|
213
|
-
|
|
214
|
-
|
|
237
|
+
readonly sandboxDomain: string;
|
|
238
|
+
readonly trafficAccessToken?: string;
|
|
239
|
+
protected readonly mcpPort = 50005;
|
|
240
|
+
protected readonly envdPort = 49983;
|
|
241
|
+
protected readonly connectionConfig: ConnectionConfig;
|
|
242
|
+
protected readonly envdAccessToken?: string;
|
|
243
|
+
private readonly envdApiUrl;
|
|
244
|
+
private readonly envdDirectUrl;
|
|
245
|
+
private mcpToken?;
|
|
215
246
|
private readonly control;
|
|
216
247
|
private readonly envs;
|
|
217
248
|
private dataPlane;
|
|
@@ -226,10 +257,13 @@ export declare class Sandbox {
|
|
|
226
257
|
});
|
|
227
258
|
/** Unique sandbox identifier. */
|
|
228
259
|
get id(): string;
|
|
229
|
-
static create(opts?:
|
|
230
|
-
static create(template: string, opts?:
|
|
260
|
+
static create<S extends typeof Sandbox>(this: S, opts?: SandboxOpts): Promise<InstanceType<S>>;
|
|
261
|
+
static create<S extends typeof Sandbox>(this: S, template: string, opts?: SandboxOpts): Promise<InstanceType<S>>;
|
|
262
|
+
protected static createSandbox(template: string, timeoutMs: number, opts?: SandboxCreateOpts): Promise<SandboxConnectionDetails>;
|
|
263
|
+
protected static createSandbox(template: string | undefined, timeoutMs: number, opts?: SandboxCreateOpts): Promise<SandboxConnectionDetails>;
|
|
231
264
|
/** Connect to an existing sandbox and return it with a fresh data-plane session. */
|
|
232
|
-
static connect(sandboxId: string, opts?: SandboxConnectOpts): Promise<
|
|
265
|
+
static connect<S extends typeof Sandbox>(this: S, sandboxId: string, opts?: SandboxConnectOpts): Promise<InstanceType<S>>;
|
|
266
|
+
protected static connectSandbox(sandboxId: string, opts?: SandboxConnectOpts): Promise<SandboxConnectionDetails>;
|
|
233
267
|
/** Refresh this sandbox's data-plane session in place. */
|
|
234
268
|
connect(opts?: SandboxConnectOpts): Promise<this>;
|
|
235
269
|
/** Resume a paused sandbox by id. */
|
|
@@ -239,7 +273,7 @@ export declare class Sandbox {
|
|
|
239
273
|
/** Pause a sandbox by id. */
|
|
240
274
|
static pause(sandboxId: string, opts?: ConnectionOpts): Promise<boolean>;
|
|
241
275
|
/** Destroy a sandbox by id. */
|
|
242
|
-
static kill(sandboxId: string, opts?: ConnectionOpts
|
|
276
|
+
static kill(sandboxId: string, opts?: ConnectionOpts): Promise<boolean>;
|
|
243
277
|
/** Fetch sandbox metrics by id. */
|
|
244
278
|
static getMetrics(sandboxId: string, opts?: SandboxMetricsOpts): Promise<SandboxMetrics[]>;
|
|
245
279
|
/** Atomically replace a sandbox's network egress policy by id. */
|
|
@@ -252,19 +286,19 @@ export declare class Sandbox {
|
|
|
252
286
|
/** Delete a snapshot by id. Returns `false` when the snapshot does not exist. */
|
|
253
287
|
static deleteSnapshot(snapshotId: string, opts?: ConnectionOpts): Promise<boolean>;
|
|
254
288
|
/** Destroy this sandbox. */
|
|
255
|
-
kill(opts?:
|
|
289
|
+
kill(opts?: Pick<SandboxOpts, 'requestTimeoutMs' | 'signal'>): Promise<boolean>;
|
|
256
290
|
/** Check if this sandbox is in a runtime-active lifecycle state. */
|
|
257
|
-
isRunning(opts?:
|
|
291
|
+
isRunning(opts?: Pick<ConnectionOpts, 'requestTimeoutMs' | 'signal'>): Promise<boolean>;
|
|
258
292
|
/** Set a sandbox's lifetime by id. */
|
|
259
293
|
static setTimeout(sandboxId: string, timeoutMs: number, opts?: ConnectionOpts): Promise<void>;
|
|
260
294
|
/** Set this sandbox's lifetime. */
|
|
261
|
-
setTimeout(timeoutMs: number, opts?:
|
|
295
|
+
setTimeout(timeoutMs: number, opts?: Pick<SandboxOpts, 'requestTimeoutMs' | 'signal'>): Promise<void>;
|
|
262
296
|
/** Fetch control-plane metadata for a sandbox by id. */
|
|
263
297
|
static getInfo(sandboxId: string, opts?: ConnectionOpts): Promise<SandboxInfo>;
|
|
264
298
|
/** Fetch full control-plane metadata for a sandbox by id. */
|
|
265
299
|
static getFullInfo(sandboxId: string, opts?: ConnectionOpts): Promise<SandboxInfo>;
|
|
266
300
|
/** Fetch the latest control-plane metadata for this sandbox. */
|
|
267
|
-
getInfo(opts?:
|
|
301
|
+
getInfo(opts?: Pick<SandboxOpts, 'requestTimeoutMs' | 'signal'>): Promise<SandboxInfo>;
|
|
268
302
|
/** Fetch latest sandbox metrics. */
|
|
269
303
|
getMetrics(opts?: SandboxMetricsOpts): Promise<SandboxMetrics[]>;
|
|
270
304
|
/** Create a Watasu checkpoint using snapshot naming. */
|
|
@@ -276,7 +310,7 @@ export declare class Sandbox {
|
|
|
276
310
|
/** Restore a checkpoint into a new sandbox and return its control-plane info. */
|
|
277
311
|
restore(opts?: RestoreSnapshotOpts | string | number): Promise<SandboxInfo>;
|
|
278
312
|
/** Return a paginator for sandboxes visible to the configured API key. */
|
|
279
|
-
static list(opts?: SandboxListOpts
|
|
313
|
+
static list(opts?: SandboxListOpts): SandboxPaginator;
|
|
280
314
|
/** Return the public hostname for an exposed sandbox port. */
|
|
281
315
|
getHost(port: number): string;
|
|
282
316
|
/** Return the conventional MCP URL for this sandbox. */
|
|
@@ -292,7 +326,7 @@ export declare class Sandbox {
|
|
|
292
326
|
/** Get signed download URL metadata for a sandbox file path. */
|
|
293
327
|
downloadUrlInfo(path: string, opts?: SandboxUrlOpts): Promise<FileUrlInfo>;
|
|
294
328
|
/** Atomically replace this sandbox's network egress policy. */
|
|
295
|
-
updateNetwork(network: SandboxNetworkUpdate, opts?:
|
|
329
|
+
updateNetwork(network: SandboxNetworkUpdate, opts?: Pick<SandboxOpts, 'requestTimeoutMs' | 'signal'>): Promise<void>;
|
|
296
330
|
/** Pause this sandbox. Returns false when it was already paused. */
|
|
297
331
|
betaPause(opts?: ConnectionOpts): Promise<boolean>;
|
|
298
332
|
/** Pause this sandbox. Returns false when it was already paused. */
|
|
@@ -300,12 +334,14 @@ export declare class Sandbox {
|
|
|
300
334
|
/** Resume this sandbox and refresh its data-plane session. */
|
|
301
335
|
resume(opts?: SandboxConnectOpts): Promise<boolean>;
|
|
302
336
|
private fileUrl;
|
|
337
|
+
/** Base URL for the sandbox data-plane runtime API. */
|
|
338
|
+
protected get runtimeBaseUrl(): string;
|
|
303
339
|
/** POST JSON to the sandbox data-plane runtime API. */
|
|
304
340
|
protected runtimePostJson(path: string, json: Record<string, unknown>, opts?: ConnectionOpts): Promise<Record<string, unknown>>;
|
|
305
341
|
/** GET JSON from the sandbox data-plane runtime API. */
|
|
306
342
|
protected runtimeGetJson(path: string, opts?: ConnectionOpts): Promise<Record<string, unknown>>;
|
|
307
343
|
/** DELETE JSON from the sandbox data-plane runtime API. */
|
|
308
344
|
protected runtimeDeleteJson(path: string, opts?: ConnectionOpts): Promise<Record<string, unknown>>;
|
|
309
|
-
private
|
|
345
|
+
private resolveApiOpts;
|
|
310
346
|
}
|
|
311
347
|
export {};
|
package/dist/sandbox.js
CHANGED
|
@@ -101,25 +101,37 @@ export class Sandbox {
|
|
|
101
101
|
git;
|
|
102
102
|
cwd;
|
|
103
103
|
sandboxId;
|
|
104
|
+
sandboxDomain;
|
|
105
|
+
trafficAccessToken;
|
|
104
106
|
mcpPort = 50005;
|
|
107
|
+
envdPort = 49983;
|
|
108
|
+
connectionConfig;
|
|
109
|
+
envdAccessToken;
|
|
110
|
+
envdApiUrl;
|
|
111
|
+
envdDirectUrl;
|
|
105
112
|
mcpToken;
|
|
106
|
-
config;
|
|
107
113
|
control;
|
|
108
114
|
envs;
|
|
109
115
|
dataPlane;
|
|
110
116
|
sandbox;
|
|
111
117
|
constructor(opts) {
|
|
112
118
|
this.sandboxId = String(opts.sandboxId);
|
|
113
|
-
this.
|
|
114
|
-
this.control = opts.control ?? new ControlClient(this.
|
|
119
|
+
this.connectionConfig = opts.connectionConfig;
|
|
120
|
+
this.control = opts.control ?? new ControlClient(this.connectionConfig);
|
|
115
121
|
this.envs = opts.envs ?? {};
|
|
116
122
|
this.sandbox = opts.sandbox ?? {};
|
|
117
|
-
const
|
|
123
|
+
const session = record(opts.session);
|
|
124
|
+
this.sandboxDomain = stringValue(session.sandbox_domain ?? session.sandboxDomain ?? this.sandbox.sandbox_domain ?? this.sandbox.domain) ?? '';
|
|
125
|
+
this.trafficAccessToken = stringValue(session.traffic_access_token ?? session.trafficAccessToken ?? this.sandbox.traffic_access_token ?? this.sandbox.trafficAccessToken);
|
|
126
|
+
this.envdAccessToken = stringValue(session.envd_access_token ?? session.envdAccessToken ?? session.token);
|
|
127
|
+
const dataPlane = dataPlaneFromSession(opts.session, this.connectionConfig);
|
|
118
128
|
this.dataPlane = dataPlane;
|
|
129
|
+
this.envdApiUrl = dataPlane.baseUrl;
|
|
130
|
+
this.envdDirectUrl = dataPlane.baseUrl;
|
|
119
131
|
this.files = new Filesystem(dataPlane);
|
|
120
|
-
this.commands = new Commands(dataPlane, this.
|
|
132
|
+
this.commands = new Commands(dataPlane, this.connectionConfig, this.envs);
|
|
121
133
|
this.process = new ProcessManager(this.commands);
|
|
122
|
-
this.pty = new Pty(dataPlane, this.
|
|
134
|
+
this.pty = new Pty(dataPlane, this.connectionConfig);
|
|
123
135
|
this.terminal = new TerminalManager(this.pty);
|
|
124
136
|
this.git = new Git(dataPlane);
|
|
125
137
|
}
|
|
@@ -133,42 +145,62 @@ export class Sandbox {
|
|
|
133
145
|
const template = typeof templateOrOpts === 'string'
|
|
134
146
|
? templateOrOpts
|
|
135
147
|
: templateOrOpts?.template ?? (sandboxOpts.mcp === undefined ? this.defaultTemplate : undefined);
|
|
136
|
-
const
|
|
148
|
+
const sandboxInfo = await this.createSandbox(template, sandboxOpts.timeoutMs ?? this.defaultSandboxTimeoutMs, sandboxOpts);
|
|
149
|
+
return new this({
|
|
150
|
+
sandboxId: sandboxInfo.sandboxId,
|
|
151
|
+
connectionConfig: sandboxInfo.connectionConfig,
|
|
152
|
+
control: sandboxInfo.control,
|
|
153
|
+
session: sandboxInfo.session,
|
|
154
|
+
sandbox: sandboxInfo.sandbox,
|
|
155
|
+
envs: sandboxInfo.envs,
|
|
156
|
+
});
|
|
157
|
+
}
|
|
158
|
+
static async createSandbox(template, timeoutMs, opts = {}) {
|
|
159
|
+
const config = new ConnectionConfig(opts);
|
|
137
160
|
const control = new ControlClient(config);
|
|
138
161
|
const sandboxPayload = {
|
|
139
|
-
timeout: Math.ceil(
|
|
140
|
-
metadata:
|
|
141
|
-
|
|
142
|
-
secure:
|
|
143
|
-
allow_internet_access:
|
|
162
|
+
timeout: Math.ceil(timeoutMs / 1000),
|
|
163
|
+
metadata: opts.metadata ?? {},
|
|
164
|
+
envs: opts.envs ?? {},
|
|
165
|
+
secure: opts.secure ?? true,
|
|
166
|
+
allow_internet_access: opts.allowInternetAccess ?? true,
|
|
144
167
|
};
|
|
145
|
-
putIfPresent(sandboxPayload, '
|
|
146
|
-
putIfPresent(sandboxPayload, 'mcp',
|
|
147
|
-
putIfPresent(sandboxPayload, 'lifecycle', lifecyclePayload(
|
|
148
|
-
putIfPresent(sandboxPayload, 'volume_mounts', volumeMountsPayload(
|
|
149
|
-
Object.assign(sandboxPayload, networkUpdatePayload(
|
|
150
|
-
putIfPresent(sandboxPayload, 'team',
|
|
168
|
+
putIfPresent(sandboxPayload, 'template', template);
|
|
169
|
+
putIfPresent(sandboxPayload, 'mcp', opts.mcp);
|
|
170
|
+
putIfPresent(sandboxPayload, 'lifecycle', lifecyclePayload(opts.lifecycle));
|
|
171
|
+
putIfPresent(sandboxPayload, 'volume_mounts', volumeMountsPayload(opts.volumeMounts));
|
|
172
|
+
Object.assign(sandboxPayload, networkUpdatePayload(opts.network));
|
|
173
|
+
putIfPresent(sandboxPayload, 'team', opts.team);
|
|
151
174
|
const response = await control.post('/sandboxes', {
|
|
152
175
|
json: sandboxPayload,
|
|
153
|
-
requestTimeoutMs: sessionOperationRequestTimeout(config,
|
|
154
|
-
signal:
|
|
176
|
+
requestTimeoutMs: sessionOperationRequestTimeout(config, opts),
|
|
177
|
+
signal: opts.signal,
|
|
155
178
|
});
|
|
156
179
|
const sandbox = record(response.sandbox ?? response);
|
|
157
180
|
const sandboxId = sandbox.id ?? sandbox.sandbox_id;
|
|
158
181
|
if (sandboxId === undefined)
|
|
159
182
|
throw new SandboxError('create response did not include sandbox id');
|
|
160
|
-
|
|
183
|
+
return sandboxConnectionDetails({
|
|
161
184
|
sandboxId: String(sandboxId),
|
|
162
|
-
|
|
185
|
+
config,
|
|
163
186
|
control,
|
|
164
187
|
session: response.session,
|
|
165
188
|
sandbox,
|
|
166
|
-
envs:
|
|
189
|
+
envs: opts.envs,
|
|
167
190
|
});
|
|
168
|
-
return sandboxInstance;
|
|
169
191
|
}
|
|
170
192
|
/** Connect to an existing sandbox and return it with a fresh data-plane session. */
|
|
171
193
|
static async connect(sandboxId, opts = {}) {
|
|
194
|
+
const sandboxInfo = await this.connectSandbox(sandboxId, opts);
|
|
195
|
+
return new this({
|
|
196
|
+
sandboxId: sandboxInfo.sandboxId,
|
|
197
|
+
connectionConfig: sandboxInfo.connectionConfig,
|
|
198
|
+
control: sandboxInfo.control,
|
|
199
|
+
session: sandboxInfo.session,
|
|
200
|
+
sandbox: sandboxInfo.sandbox,
|
|
201
|
+
});
|
|
202
|
+
}
|
|
203
|
+
static async connectSandbox(sandboxId, opts = {}) {
|
|
172
204
|
const config = new ConnectionConfig(opts);
|
|
173
205
|
const control = new ControlClient(config);
|
|
174
206
|
const info = await control.get(`/sandboxes/${sandboxId}`, {
|
|
@@ -180,9 +212,9 @@ export class Sandbox {
|
|
|
180
212
|
requestTimeoutMs: sessionOperationRequestTimeout(config, opts),
|
|
181
213
|
signal: opts.signal,
|
|
182
214
|
});
|
|
183
|
-
return
|
|
215
|
+
return sandboxConnectionDetails({
|
|
184
216
|
sandboxId,
|
|
185
|
-
|
|
217
|
+
config,
|
|
186
218
|
control,
|
|
187
219
|
session: response.session,
|
|
188
220
|
sandbox: record(response.sandbox ?? info.sandbox ?? {}),
|
|
@@ -192,18 +224,19 @@ export class Sandbox {
|
|
|
192
224
|
async connect(opts = {}) {
|
|
193
225
|
const response = await this.control.post(`/sandboxes/${this.sandboxId}/resume`, {
|
|
194
226
|
json: opts.timeoutMs ? { timeout: Math.ceil(opts.timeoutMs / 1000) } : {},
|
|
195
|
-
requestTimeoutMs: sessionOperationRequestTimeout(this.
|
|
227
|
+
requestTimeoutMs: sessionOperationRequestTimeout(this.connectionConfig, opts),
|
|
196
228
|
signal: opts.signal,
|
|
197
229
|
});
|
|
198
230
|
this.sandbox = record(response.sandbox ?? this.sandbox);
|
|
199
|
-
const dataPlane = dataPlaneFromSession(response.session, this.
|
|
231
|
+
const dataPlane = dataPlaneFromSession(response.session, this.connectionConfig);
|
|
232
|
+
const mutable = this;
|
|
200
233
|
this.dataPlane = dataPlane;
|
|
201
|
-
|
|
202
|
-
|
|
203
|
-
|
|
204
|
-
|
|
205
|
-
|
|
206
|
-
|
|
234
|
+
mutable.files = new Filesystem(dataPlane);
|
|
235
|
+
mutable.commands = new Commands(dataPlane, this.connectionConfig, this.envs);
|
|
236
|
+
mutable.process = new ProcessManager(this.commands);
|
|
237
|
+
mutable.pty = new Pty(dataPlane, this.connectionConfig);
|
|
238
|
+
mutable.terminal = new TerminalManager(this.pty);
|
|
239
|
+
mutable.git = new Git(dataPlane);
|
|
207
240
|
return this;
|
|
208
241
|
}
|
|
209
242
|
/** Resume a paused sandbox by id. */
|
|
@@ -233,11 +266,10 @@ export class Sandbox {
|
|
|
233
266
|
}
|
|
234
267
|
/** Destroy a sandbox by id. */
|
|
235
268
|
static async kill(sandboxId, opts = {}) {
|
|
236
|
-
const
|
|
237
|
-
const control = new ControlClient(new ConnectionConfig(typeof opts === 'string' ? { apiKey: opts } : opts));
|
|
269
|
+
const control = new ControlClient(new ConnectionConfig(opts));
|
|
238
270
|
await control.delete(`/sandboxes/${sandboxId}`, {
|
|
239
|
-
requestTimeoutMs:
|
|
240
|
-
signal:
|
|
271
|
+
requestTimeoutMs: opts.requestTimeoutMs,
|
|
272
|
+
signal: opts.signal,
|
|
241
273
|
});
|
|
242
274
|
return true;
|
|
243
275
|
}
|
|
@@ -357,19 +389,19 @@ export class Sandbox {
|
|
|
357
389
|
}
|
|
358
390
|
/** Fetch latest sandbox metrics. */
|
|
359
391
|
async getMetrics(opts = {}) {
|
|
360
|
-
return Sandbox.getMetrics(this.sandboxId, { ...this.
|
|
392
|
+
return Sandbox.getMetrics(this.sandboxId, { ...this.resolveApiOpts(), ...opts });
|
|
361
393
|
}
|
|
362
394
|
/** Create a Watasu checkpoint using snapshot naming. */
|
|
363
395
|
async createSnapshot(opts = {}) {
|
|
364
|
-
return Sandbox.createSnapshot(this.sandboxId, { ...this.
|
|
396
|
+
return Sandbox.createSnapshot(this.sandboxId, { ...this.resolveApiOpts(), ...opts });
|
|
365
397
|
}
|
|
366
398
|
/** Delete a snapshot by id. */
|
|
367
399
|
async deleteSnapshot(snapshotId, opts = {}) {
|
|
368
|
-
return Sandbox.deleteSnapshot(snapshotId, { ...this.
|
|
400
|
+
return Sandbox.deleteSnapshot(snapshotId, { ...this.resolveApiOpts(), ...opts });
|
|
369
401
|
}
|
|
370
402
|
/** List checkpoints for this sandbox using snapshot naming. */
|
|
371
403
|
listSnapshots(opts = {}) {
|
|
372
|
-
return Sandbox.listSnapshots({ ...this.
|
|
404
|
+
return Sandbox.listSnapshots({ ...this.resolveApiOpts(), ...opts, sandboxId: this.sandboxId });
|
|
373
405
|
}
|
|
374
406
|
/** Restore a checkpoint into a new sandbox and return its control-plane info. */
|
|
375
407
|
async restore(opts = {}) {
|
|
@@ -391,17 +423,16 @@ export class Sandbox {
|
|
|
391
423
|
}
|
|
392
424
|
/** Return a paginator for sandboxes visible to the configured API key. */
|
|
393
425
|
static list(opts = {}) {
|
|
394
|
-
|
|
395
|
-
return new SandboxPaginator(listOpts);
|
|
426
|
+
return new SandboxPaginator(opts);
|
|
396
427
|
}
|
|
397
428
|
/** Return the public hostname for an exposed sandbox port. */
|
|
398
429
|
getHost(port) {
|
|
399
430
|
const routeToken = this.sandbox.route_token ??
|
|
400
431
|
this.sandbox.routeToken ??
|
|
401
|
-
routeTokenFromDataPlaneUrl(this.dataPlane.baseUrl, this.
|
|
432
|
+
routeTokenFromDataPlaneUrl(this.dataPlane.baseUrl, this.connectionConfig.dataPlaneDomain);
|
|
402
433
|
if (typeof routeToken !== 'string')
|
|
403
434
|
throw new SandboxError('port response did not include host or url');
|
|
404
|
-
return `p${port}-${routeToken}.sandbox.${this.
|
|
435
|
+
return `p${port}-${routeToken}.sandbox.${this.connectionConfig.dataPlaneDomain}`;
|
|
405
436
|
}
|
|
406
437
|
/** Return the conventional MCP URL for this sandbox. */
|
|
407
438
|
getMcpUrl() {
|
|
@@ -442,12 +473,12 @@ export class Sandbox {
|
|
|
442
473
|
}
|
|
443
474
|
/** Atomically replace this sandbox's network egress policy. */
|
|
444
475
|
async updateNetwork(network, opts = {}) {
|
|
445
|
-
const sandbox = await Sandbox.putNetwork(this.sandboxId, network, { ...this.
|
|
476
|
+
const sandbox = await Sandbox.putNetwork(this.sandboxId, network, { ...this.resolveApiOpts(), ...opts });
|
|
446
477
|
this.sandbox = sandbox ?? this.sandbox;
|
|
447
478
|
}
|
|
448
479
|
/** Pause this sandbox. Returns false when it was already paused. */
|
|
449
480
|
async betaPause(opts = {}) {
|
|
450
|
-
return Sandbox.betaPause(this.sandboxId, { ...this.
|
|
481
|
+
return Sandbox.betaPause(this.sandboxId, { ...this.resolveApiOpts(), ...opts });
|
|
451
482
|
}
|
|
452
483
|
/** Pause this sandbox. Returns false when it was already paused. */
|
|
453
484
|
async pause(opts = {}) {
|
|
@@ -471,6 +502,10 @@ export class Sandbox {
|
|
|
471
502
|
});
|
|
472
503
|
return fileUrlInfo(record(payload.file_url ?? payload));
|
|
473
504
|
}
|
|
505
|
+
/** Base URL for the sandbox data-plane runtime API. */
|
|
506
|
+
get runtimeBaseUrl() {
|
|
507
|
+
return this.dataPlane.baseUrl;
|
|
508
|
+
}
|
|
474
509
|
/** POST JSON to the sandbox data-plane runtime API. */
|
|
475
510
|
async runtimePostJson(path, json, opts = {}) {
|
|
476
511
|
return this.dataPlane.postJson(path, {
|
|
@@ -493,18 +528,18 @@ export class Sandbox {
|
|
|
493
528
|
signal: opts.signal,
|
|
494
529
|
});
|
|
495
530
|
}
|
|
496
|
-
|
|
531
|
+
resolveApiOpts() {
|
|
497
532
|
return {
|
|
498
|
-
apiKey: this.
|
|
499
|
-
apiUrl: this.
|
|
500
|
-
sandboxUrl: this.
|
|
501
|
-
dataPlaneDomain: this.
|
|
502
|
-
requestTimeoutMs: this.
|
|
503
|
-
headers: this.
|
|
504
|
-
apiHeaders: this.
|
|
505
|
-
debug: this.
|
|
506
|
-
signal: this.
|
|
507
|
-
proxy: this.
|
|
533
|
+
apiKey: this.connectionConfig.apiKey,
|
|
534
|
+
apiUrl: this.connectionConfig.apiUrl,
|
|
535
|
+
sandboxUrl: this.connectionConfig.sandboxUrl,
|
|
536
|
+
dataPlaneDomain: this.connectionConfig.dataPlaneDomain,
|
|
537
|
+
requestTimeoutMs: this.connectionConfig.requestTimeoutMs,
|
|
538
|
+
headers: this.connectionConfig.headers,
|
|
539
|
+
apiHeaders: this.connectionConfig.apiHeaders,
|
|
540
|
+
debug: this.connectionConfig.debug,
|
|
541
|
+
signal: this.connectionConfig.signal,
|
|
542
|
+
proxy: this.connectionConfig.proxy,
|
|
508
543
|
};
|
|
509
544
|
}
|
|
510
545
|
}
|
|
@@ -567,6 +602,21 @@ function fileUrlInfo(payload) {
|
|
|
567
602
|
raw: payload,
|
|
568
603
|
};
|
|
569
604
|
}
|
|
605
|
+
function sandboxConnectionDetails(opts) {
|
|
606
|
+
const session = record(opts.session);
|
|
607
|
+
return {
|
|
608
|
+
sandboxId: opts.sandboxId,
|
|
609
|
+
sandboxDomain: stringValue(session.sandbox_domain ?? session.sandboxDomain ?? opts.sandbox.sandbox_domain ?? opts.sandbox.domain),
|
|
610
|
+
envdVersion: stringValue(session.envd_version ?? session.envdVersion ?? opts.sandbox.envd_version ?? opts.sandbox.envdVersion) ?? '',
|
|
611
|
+
envdAccessToken: stringValue(session.envd_access_token ?? session.envdAccessToken ?? session.token),
|
|
612
|
+
trafficAccessToken: stringValue(session.traffic_access_token ?? session.trafficAccessToken ?? opts.sandbox.traffic_access_token ?? opts.sandbox.trafficAccessToken),
|
|
613
|
+
connectionConfig: opts.config,
|
|
614
|
+
control: opts.control,
|
|
615
|
+
session: opts.session,
|
|
616
|
+
sandbox: opts.sandbox,
|
|
617
|
+
envs: opts.envs,
|
|
618
|
+
};
|
|
619
|
+
}
|
|
570
620
|
function compactRecord(payload) {
|
|
571
621
|
return Object.fromEntries(Object.entries(payload).filter(([, value]) => value !== undefined));
|
|
572
622
|
}
|
|
@@ -581,15 +631,17 @@ function sandboxInfo(payload) {
|
|
|
581
631
|
templateId: typeof payload.template_id === 'string' ? payload.template_id : templateSlug(payload.template),
|
|
582
632
|
name: typeof payload.name === 'string' ? payload.name : undefined,
|
|
583
633
|
state: typeof payload.state === 'string' ? payload.state : undefined,
|
|
634
|
+
cpuCount: numberValue(payload.cpu_count ?? payload.cpuCount),
|
|
635
|
+
memoryMB: numberValue(payload.memory_mb ?? payload.memoryMB ?? payload.memoryMb),
|
|
636
|
+
envdVersion: stringValue(payload.envd_version ?? payload.envdVersion),
|
|
637
|
+
allowInternetAccess: booleanValue(payload.allow_internet_access ?? payload.allowInternetAccess),
|
|
638
|
+
network: sandboxNetworkInfo(payload.network),
|
|
639
|
+
sandboxDomain: stringValue(payload.sandbox_domain ?? payload.sandboxDomain),
|
|
584
640
|
lifecycle: sandboxLifecycleInfo(payload.lifecycle),
|
|
585
641
|
volumeMounts: volumeMountsInfo(payload.volume_mounts ?? payload.volumeMounts),
|
|
586
642
|
metadata: recordOfStrings(payload.metadata),
|
|
587
|
-
startedAt:
|
|
588
|
-
|
|
589
|
-
: typeof payload.created_at === 'string' ? payload.created_at : undefined,
|
|
590
|
-
endAt: typeof payload.end_at === 'string'
|
|
591
|
-
? payload.end_at
|
|
592
|
-
: typeof payload.deadline_at === 'string' ? payload.deadline_at : undefined,
|
|
643
|
+
startedAt: dateValue(payload.started_at ?? payload.startedAt ?? payload.created_at ?? payload.createdAt ?? payload.ready_at ?? payload.readyAt),
|
|
644
|
+
endAt: dateValue(payload.end_at ?? payload.endAt ?? payload.deadline_at ?? payload.deadlineAt),
|
|
593
645
|
};
|
|
594
646
|
}
|
|
595
647
|
function lifecyclePayload(lifecycle) {
|
|
@@ -631,6 +683,10 @@ function sandboxLifecycleInfo(value) {
|
|
|
631
683
|
autoResume: autoResume ?? false,
|
|
632
684
|
};
|
|
633
685
|
}
|
|
686
|
+
function sandboxNetworkInfo(value) {
|
|
687
|
+
const item = record(value);
|
|
688
|
+
return Object.keys(item).length > 0 ? item : undefined;
|
|
689
|
+
}
|
|
634
690
|
function metricsList(value) {
|
|
635
691
|
if (Array.isArray(value))
|
|
636
692
|
return value.map((item) => metricsInfo(record(item)));
|
|
@@ -638,11 +694,18 @@ function metricsList(value) {
|
|
|
638
694
|
}
|
|
639
695
|
function metricsInfo(value) {
|
|
640
696
|
return {
|
|
697
|
+
timestamp: dateValue(value.timestamp ?? value.time ?? value.created_at ?? value.createdAt),
|
|
641
698
|
sandboxId: stringValue(value.sandbox_id ?? value.sandboxId),
|
|
642
699
|
state: stringValue(value.state),
|
|
643
700
|
node: stringValue(value.node),
|
|
644
701
|
backend: stringValue(value.backend),
|
|
645
702
|
cpuCount: numberValue(value.cpu_count ?? value.cpuCount),
|
|
703
|
+
cpuUsedPct: numberValue(value.cpu_used_pct ?? value.cpuUsedPct ?? value.cpu_pct ?? value.cpuPct),
|
|
704
|
+
memUsed: numberValue(value.mem_used ?? value.memUsed ?? value.memory_used ?? value.memoryUsed),
|
|
705
|
+
memTotal: numberValue(value.mem_total ?? value.memTotal ?? value.memory_total ?? value.memoryTotal),
|
|
706
|
+
memCache: numberValue(value.mem_cache ?? value.memCache ?? value.memory_cache ?? value.memoryCache),
|
|
707
|
+
diskUsed: numberValue(value.disk_used ?? value.diskUsed),
|
|
708
|
+
diskTotal: numberValue(value.disk_total ?? value.diskTotal),
|
|
646
709
|
memoryMb: numberValue(value.memory_mb ?? value.memoryMb),
|
|
647
710
|
raw: value,
|
|
648
711
|
};
|
|
@@ -659,10 +722,12 @@ function snapshotInfo(value) {
|
|
|
659
722
|
const id = value.snapshot_id ?? value.snapshotId ?? value.checkpoint_id ?? value.checkpointId ?? value.id;
|
|
660
723
|
if (id === undefined)
|
|
661
724
|
throw new SandboxError('snapshot response did not include id');
|
|
725
|
+
const name = stringValue(value.name);
|
|
662
726
|
return {
|
|
663
727
|
snapshotId: String(id),
|
|
728
|
+
names: arrayOfStrings(value.names ?? value.name ?? value.snapshot_names ?? value.snapshotNames),
|
|
664
729
|
sandboxId: stringValue(value.sandbox_id ?? value.sandboxId),
|
|
665
|
-
name
|
|
730
|
+
name,
|
|
666
731
|
status: stringValue(value.status),
|
|
667
732
|
sizeBytes: numberValue(value.size_bytes ?? value.sizeBytes),
|
|
668
733
|
createdAt: stringValue(value.created_at ?? value.createdAt),
|
|
@@ -677,9 +742,26 @@ function stringValue(value) {
|
|
|
677
742
|
return String(value);
|
|
678
743
|
return undefined;
|
|
679
744
|
}
|
|
745
|
+
function arrayOfStrings(value) {
|
|
746
|
+
if (Array.isArray(value))
|
|
747
|
+
return value.map(String);
|
|
748
|
+
if (value === undefined || value === null || value === '')
|
|
749
|
+
return [];
|
|
750
|
+
return [String(value)];
|
|
751
|
+
}
|
|
680
752
|
function numberValue(value) {
|
|
681
753
|
return typeof value === 'number' ? value : undefined;
|
|
682
754
|
}
|
|
755
|
+
function dateValue(value) {
|
|
756
|
+
if (value instanceof Date)
|
|
757
|
+
return value;
|
|
758
|
+
if (typeof value === 'string' || typeof value === 'number') {
|
|
759
|
+
const date = new Date(value);
|
|
760
|
+
if (!Number.isNaN(date.getTime()))
|
|
761
|
+
return date;
|
|
762
|
+
}
|
|
763
|
+
return undefined;
|
|
764
|
+
}
|
|
683
765
|
function booleanValue(value) {
|
|
684
766
|
if (typeof value === 'boolean')
|
|
685
767
|
return value;
|
package/dist/template.d.ts
CHANGED
|
@@ -236,6 +236,8 @@ export declare class TemplateBase {
|
|
|
236
236
|
setEnvs(envs: Record<string, string>): TemplateBuilder;
|
|
237
237
|
skipCache(): TemplateBuilder;
|
|
238
238
|
toBuildSpec(): BuildSpec;
|
|
239
|
+
private toJSON;
|
|
240
|
+
private serialize;
|
|
239
241
|
private addPackages;
|
|
240
242
|
private requireDevContainerTemplate;
|
|
241
243
|
private addCopySource;
|
package/dist/template.js
CHANGED
|
@@ -167,7 +167,7 @@ export class TemplateBase {
|
|
|
167
167
|
return tags.map((item) => templateTag(record(item)));
|
|
168
168
|
}
|
|
169
169
|
static async toJSON(template) {
|
|
170
|
-
return
|
|
170
|
+
return template.toJSON();
|
|
171
171
|
}
|
|
172
172
|
static toDockerfile(template) {
|
|
173
173
|
return template.toDockerfile();
|
|
@@ -392,6 +392,12 @@ export class TemplateBase {
|
|
|
392
392
|
spec.ready_cmd = this.readyCmd;
|
|
393
393
|
return spec;
|
|
394
394
|
}
|
|
395
|
+
async toJSON(_computeHashes = true) {
|
|
396
|
+
return JSON.stringify(this.serialize());
|
|
397
|
+
}
|
|
398
|
+
serialize(_steps) {
|
|
399
|
+
return this.toBuildSpec();
|
|
400
|
+
}
|
|
395
401
|
addPackages(manager, packages) {
|
|
396
402
|
this.packages[manager] = [...(this.packages[manager] ?? []), ...packages];
|
|
397
403
|
}
|
package/dist/volume.d.ts
CHANGED
|
@@ -41,8 +41,11 @@ export interface VolumeEntryStat {
|
|
|
41
41
|
export interface VolumeApiParams extends ConnectionOpts {
|
|
42
42
|
team?: string;
|
|
43
43
|
}
|
|
44
|
-
export type
|
|
45
|
-
export declare
|
|
44
|
+
export type VolumeApiOpts = ConnectionOpts;
|
|
45
|
+
export declare class VolumeConnectionConfig extends ConnectionConfig {
|
|
46
|
+
readonly token?: string;
|
|
47
|
+
constructor(volume: Volume, opts?: VolumeApiOpts);
|
|
48
|
+
}
|
|
46
49
|
export interface VolumeListOpts extends ConnectionOpts {
|
|
47
50
|
team?: string;
|
|
48
51
|
}
|
|
@@ -66,7 +69,6 @@ export interface VolumeMetadataOpts extends ConnectionOpts {
|
|
|
66
69
|
export type VolumeAndToken = VolumeInfo & {
|
|
67
70
|
token: string;
|
|
68
71
|
};
|
|
69
|
-
export type VolumeApiOpts = ConnectionOpts;
|
|
70
72
|
export type VolumeMetadataOptions = Omit<VolumeMetadataOpts, keyof ConnectionOpts>;
|
|
71
73
|
export type VolumeWriteOptions = Omit<VolumeWriteFileOpts, keyof ConnectionOpts>;
|
|
72
74
|
/** Persistent volume that can be mounted into sandboxes and edited while detached. */
|
|
@@ -75,8 +77,12 @@ export declare class Volume {
|
|
|
75
77
|
readonly id: string;
|
|
76
78
|
readonly name: string;
|
|
77
79
|
readonly token?: string;
|
|
80
|
+
readonly domain?: string;
|
|
81
|
+
readonly debug?: boolean;
|
|
82
|
+
readonly proxy?: string;
|
|
78
83
|
private readonly config;
|
|
79
84
|
private readonly control;
|
|
85
|
+
constructor(volumeId: string, name: string, token: string, domain?: string, debug?: boolean, proxy?: string);
|
|
80
86
|
constructor(opts: {
|
|
81
87
|
volumeId: string;
|
|
82
88
|
name?: string;
|
|
@@ -87,13 +93,13 @@ export declare class Volume {
|
|
|
87
93
|
/** Create a persistent volume and return a connected SDK object. */
|
|
88
94
|
static create(name: string, opts?: VolumeApiParams): Promise<Volume>;
|
|
89
95
|
/** Connect to an existing volume by id or name. */
|
|
90
|
-
static connect(volumeId: string, opts?:
|
|
96
|
+
static connect(volumeId: string, opts?: VolumeApiOpts): Promise<Volume>;
|
|
91
97
|
/** Fetch metadata for an existing volume by id or name. */
|
|
92
|
-
static getInfo(volumeId: string, opts?:
|
|
98
|
+
static getInfo(volumeId: string, opts?: VolumeApiOpts): Promise<VolumeInfo>;
|
|
93
99
|
/** List volumes visible to the configured API key. */
|
|
94
100
|
static list(opts?: VolumeListOpts): Promise<VolumeInfo[]>;
|
|
95
101
|
/** Destroy a volume by id or name. Returns false when it does not exist. */
|
|
96
|
-
static destroy(volumeId: string, opts?:
|
|
102
|
+
static destroy(volumeId: string, opts?: VolumeApiOpts): Promise<boolean>;
|
|
97
103
|
/** Fetch this volume's latest metadata. */
|
|
98
104
|
getInfo(): Promise<VolumeInfo>;
|
|
99
105
|
/** Fetch metadata for a path inside this volume. */
|
package/dist/volume.js
CHANGED
|
@@ -10,21 +10,41 @@ export var VolumeFileType;
|
|
|
10
10
|
VolumeFileType["DIRECTORY"] = "directory";
|
|
11
11
|
VolumeFileType["SYMLINK"] = "symlink";
|
|
12
12
|
})(VolumeFileType || (VolumeFileType = {}));
|
|
13
|
-
export
|
|
13
|
+
export class VolumeConnectionConfig extends ConnectionConfig {
|
|
14
|
+
token;
|
|
15
|
+
constructor(volume, opts = {}) {
|
|
16
|
+
super(opts);
|
|
17
|
+
this.token = volume.token;
|
|
18
|
+
}
|
|
19
|
+
}
|
|
14
20
|
/** Persistent volume that can be mounted into sandboxes and edited while detached. */
|
|
15
21
|
export class Volume {
|
|
16
22
|
volumeId;
|
|
17
23
|
id;
|
|
18
24
|
name;
|
|
19
25
|
token;
|
|
26
|
+
domain;
|
|
27
|
+
debug;
|
|
28
|
+
proxy;
|
|
20
29
|
config;
|
|
21
30
|
control;
|
|
22
|
-
constructor(
|
|
31
|
+
constructor(volumeOrOpts, name, token, domain, debug, proxy) {
|
|
32
|
+
const opts = typeof volumeOrOpts === 'string'
|
|
33
|
+
? {
|
|
34
|
+
volumeId: volumeOrOpts,
|
|
35
|
+
name,
|
|
36
|
+
token,
|
|
37
|
+
connectionConfig: new ConnectionConfig({ domain, debug, proxy }),
|
|
38
|
+
}
|
|
39
|
+
: volumeOrOpts;
|
|
23
40
|
this.volumeId = String(opts.volumeId);
|
|
24
41
|
this.id = this.volumeId;
|
|
25
42
|
this.name = opts.name ?? this.volumeId;
|
|
26
43
|
this.token = opts.token;
|
|
27
44
|
this.config = opts.connectionConfig;
|
|
45
|
+
this.domain = this.config.domain;
|
|
46
|
+
this.debug = this.config.debug;
|
|
47
|
+
this.proxy = this.config.proxy;
|
|
28
48
|
this.control = opts.control ?? new ControlClient(this.config);
|
|
29
49
|
}
|
|
30
50
|
/** Create a persistent volume and return a connected SDK object. */
|