@watasu/sdk 0.1.51 → 0.1.66
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 +9 -0
- 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 +43 -0
- package/dist/filesystem.js +88 -1
- package/dist/git.d.ts +3 -0
- package/dist/git.js +27 -1
- package/dist/index.d.ts +1 -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
package/README.md
CHANGED
|
@@ -156,6 +156,15 @@ await sbx.files.writeFiles([
|
|
|
156
156
|
{ path: '/workspace/project/a.txt', data: 'alpha' },
|
|
157
157
|
{ path: '/workspace/project/b.bin', data: new Uint8Array([0, 1, 2]) },
|
|
158
158
|
])
|
|
159
|
+
const patch = await sbx.files.applyDiff(
|
|
160
|
+
`*** Begin Patch
|
|
161
|
+
*** Update File: /workspace/project/a.txt
|
|
162
|
+
@@
|
|
163
|
+
-alpha
|
|
164
|
+
+beta
|
|
165
|
+
*** End Patch`
|
|
166
|
+
)
|
|
167
|
+
console.log(patch.status)
|
|
159
168
|
|
|
160
169
|
const watcher = sbx.files.watchDir('/workspace/project')
|
|
161
170
|
watcher.addEventListener((event) => {
|
|
@@ -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;
|
|
@@ -62,6 +68,41 @@ export interface FilesystemWriteOpts extends FilesystemRequestOpts {
|
|
|
62
68
|
useOctetStream?: boolean;
|
|
63
69
|
metadata?: Record<string, string>;
|
|
64
70
|
}
|
|
71
|
+
export interface ApplyDiffOpts extends FilesystemRequestOpts {
|
|
72
|
+
cwd?: string;
|
|
73
|
+
}
|
|
74
|
+
export interface ApplyDiffFailedHunk {
|
|
75
|
+
index: number;
|
|
76
|
+
oldStart: number;
|
|
77
|
+
}
|
|
78
|
+
export interface ApplyDiffFailure {
|
|
79
|
+
path: string;
|
|
80
|
+
error: string;
|
|
81
|
+
failedHunk?: ApplyDiffFailedHunk;
|
|
82
|
+
}
|
|
83
|
+
export interface ApplyDiffFileSummary {
|
|
84
|
+
path: string;
|
|
85
|
+
sourcePath?: string;
|
|
86
|
+
kind: string;
|
|
87
|
+
added: number;
|
|
88
|
+
removed: number;
|
|
89
|
+
}
|
|
90
|
+
export interface ApplyDiffSummary {
|
|
91
|
+
requested: number;
|
|
92
|
+
applied: number;
|
|
93
|
+
failed: number;
|
|
94
|
+
}
|
|
95
|
+
export interface ApplyDiffReport {
|
|
96
|
+
status: 'applied' | 'partial' | 'failed' | string;
|
|
97
|
+
parsedDiffBlocks: number;
|
|
98
|
+
patches: number;
|
|
99
|
+
files: ApplyDiffFileSummary[];
|
|
100
|
+
summary: ApplyDiffSummary;
|
|
101
|
+
applied: string[];
|
|
102
|
+
failed: ApplyDiffFailure[];
|
|
103
|
+
touched: string[];
|
|
104
|
+
raw: Record<string, unknown>;
|
|
105
|
+
}
|
|
65
106
|
/** Live filesystem watcher. Call `stop()` to close the local watch stream. */
|
|
66
107
|
export declare class WatchHandle {
|
|
67
108
|
private readonly socket;
|
|
@@ -124,6 +165,8 @@ export declare class Filesystem {
|
|
|
124
165
|
remove(path: string, opts?: FilesystemRequestOpts): Promise<void>;
|
|
125
166
|
/** Move or rename a file. */
|
|
126
167
|
rename(oldPath: string, newPath: string, opts?: FilesystemRequestOpts): Promise<EntryInfo>;
|
|
168
|
+
/** Apply a git-style unified diff or Codex apply_patch payload inside the sandbox. */
|
|
169
|
+
applyDiff(diff: string, opts?: ApplyDiffOpts): Promise<ApplyDiffReport>;
|
|
127
170
|
/** Create a directory. */
|
|
128
171
|
makeDir(path: string, opts?: FilesystemRequestOpts): Promise<boolean>;
|
|
129
172
|
/** Start watching a directory for filesystem events. */
|
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);
|
|
@@ -183,6 +183,17 @@ export class Filesystem {
|
|
|
183
183
|
});
|
|
184
184
|
return entryInfo(payload.file ?? payload);
|
|
185
185
|
}
|
|
186
|
+
/** Apply a git-style unified diff or Codex apply_patch payload inside the sandbox. */
|
|
187
|
+
async applyDiff(diff, opts = {}) {
|
|
188
|
+
const payload = await this.dataPlane.postJson('/runtime/v1/files/apply_diff', {
|
|
189
|
+
...requestOpts(opts),
|
|
190
|
+
json: {
|
|
191
|
+
diff,
|
|
192
|
+
...(opts.cwd ? { cwd: opts.cwd } : {}),
|
|
193
|
+
},
|
|
194
|
+
});
|
|
195
|
+
return applyDiffReport(payload);
|
|
196
|
+
}
|
|
186
197
|
/** Create a directory. */
|
|
187
198
|
async makeDir(path, opts = {}) {
|
|
188
199
|
await this.dataPlane.postJson(withQuery('/runtime/v1/directories', { path }), opts);
|
|
@@ -265,6 +276,11 @@ function entryInfo(value) {
|
|
|
265
276
|
path: String(item.path ?? ''),
|
|
266
277
|
size: numberValue(item.bytes ?? item.size),
|
|
267
278
|
mode: numberValue(item.mode),
|
|
279
|
+
permissions: stringValue(item.permissions),
|
|
280
|
+
owner: stringValue(item.owner),
|
|
281
|
+
group: stringValue(item.group),
|
|
282
|
+
modifiedTime: dateValue(item.modified_time ?? item.modifiedTime ?? item.mtime ?? item.updated_at ?? item.updatedAt),
|
|
283
|
+
symlinkTarget: stringValue(item.symlink_target ?? item.symlinkTarget),
|
|
268
284
|
uid: numberValue(item.uid),
|
|
269
285
|
gid: numberValue(item.gid),
|
|
270
286
|
mtime: numberValue(item.mtime),
|
|
@@ -274,6 +290,23 @@ function entryInfo(value) {
|
|
|
274
290
|
function numberValue(value) {
|
|
275
291
|
return typeof value === 'number' ? value : undefined;
|
|
276
292
|
}
|
|
293
|
+
function stringValue(value) {
|
|
294
|
+
if (typeof value === 'string')
|
|
295
|
+
return value;
|
|
296
|
+
if (typeof value === 'number')
|
|
297
|
+
return String(value);
|
|
298
|
+
return undefined;
|
|
299
|
+
}
|
|
300
|
+
function dateValue(value) {
|
|
301
|
+
if (value instanceof Date)
|
|
302
|
+
return value;
|
|
303
|
+
if (typeof value === 'string' || typeof value === 'number') {
|
|
304
|
+
const date = new Date(value);
|
|
305
|
+
if (!Number.isNaN(date.getTime()))
|
|
306
|
+
return date;
|
|
307
|
+
}
|
|
308
|
+
return undefined;
|
|
309
|
+
}
|
|
277
310
|
function recordOfStrings(value) {
|
|
278
311
|
if (!value || typeof value !== 'object')
|
|
279
312
|
return undefined;
|
|
@@ -290,6 +323,60 @@ function filesystemEvent(value) {
|
|
|
290
323
|
raw: item,
|
|
291
324
|
};
|
|
292
325
|
}
|
|
326
|
+
function applyDiffReport(value) {
|
|
327
|
+
const item = value && typeof value === 'object' ? value : {};
|
|
328
|
+
return {
|
|
329
|
+
status: String(item.status ?? ''),
|
|
330
|
+
parsedDiffBlocks: requiredNumber(item.parsed_diff_blocks),
|
|
331
|
+
patches: requiredNumber(item.patches),
|
|
332
|
+
files: Array.isArray(item.files) ? item.files.map(applyDiffFileSummary) : [],
|
|
333
|
+
summary: applyDiffSummary(item.summary),
|
|
334
|
+
applied: stringArray(item.applied),
|
|
335
|
+
failed: Array.isArray(item.failed) ? item.failed.map(applyDiffFailure) : [],
|
|
336
|
+
touched: stringArray(item.touched),
|
|
337
|
+
raw: item,
|
|
338
|
+
};
|
|
339
|
+
}
|
|
340
|
+
function applyDiffSummary(value) {
|
|
341
|
+
const item = value && typeof value === 'object' ? value : {};
|
|
342
|
+
return {
|
|
343
|
+
requested: requiredNumber(item.requested),
|
|
344
|
+
applied: requiredNumber(item.applied),
|
|
345
|
+
failed: requiredNumber(item.failed),
|
|
346
|
+
};
|
|
347
|
+
}
|
|
348
|
+
function applyDiffFileSummary(value) {
|
|
349
|
+
const item = value && typeof value === 'object' ? value : {};
|
|
350
|
+
return {
|
|
351
|
+
path: String(item.path ?? ''),
|
|
352
|
+
sourcePath: typeof item.source_path === 'string' ? item.source_path : undefined,
|
|
353
|
+
kind: String(item.kind ?? ''),
|
|
354
|
+
added: requiredNumber(item.added),
|
|
355
|
+
removed: requiredNumber(item.removed),
|
|
356
|
+
};
|
|
357
|
+
}
|
|
358
|
+
function applyDiffFailure(value) {
|
|
359
|
+
const item = value && typeof value === 'object' ? value : {};
|
|
360
|
+
const failedHunk = item.failed_hunk && typeof item.failed_hunk === 'object'
|
|
361
|
+
? item.failed_hunk
|
|
362
|
+
: undefined;
|
|
363
|
+
return {
|
|
364
|
+
path: String(item.path ?? ''),
|
|
365
|
+
error: String(item.error ?? ''),
|
|
366
|
+
failedHunk: failedHunk
|
|
367
|
+
? {
|
|
368
|
+
index: requiredNumber(failedHunk.index),
|
|
369
|
+
oldStart: requiredNumber(failedHunk.old_start),
|
|
370
|
+
}
|
|
371
|
+
: undefined,
|
|
372
|
+
};
|
|
373
|
+
}
|
|
374
|
+
function requiredNumber(value) {
|
|
375
|
+
return typeof value === 'number' && Number.isFinite(value) ? value : 0;
|
|
376
|
+
}
|
|
377
|
+
function stringArray(value) {
|
|
378
|
+
return Array.isArray(value) ? value.filter((item) => typeof item === 'string') : [];
|
|
379
|
+
}
|
|
293
380
|
function normalizeEventType(value) {
|
|
294
381
|
if (value === 'delete')
|
|
295
382
|
return FilesystemEventType.REMOVE;
|
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
|
}
|