@cloudflare/sandbox 0.13.0-next.649.1 → 0.13.0-next.681.1
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/Dockerfile +6 -11
- package/README.md +2 -2
- package/dist/bridge/index.d.ts.map +1 -1
- package/dist/bridge/index.js +68 -49
- package/dist/bridge/index.js.map +1 -1
- package/dist/codes-y-U76vnQ.d.ts +79 -0
- package/dist/codes-y-U76vnQ.d.ts.map +1 -0
- package/dist/contexts-DY1LHU1v.d.ts +327 -0
- package/dist/contexts-DY1LHU1v.d.ts.map +1 -0
- package/dist/{dist-mAH_7Ui7.js → dist-BStBkGIC.js} +50 -93
- package/dist/dist-BStBkGIC.js.map +1 -0
- package/dist/errors/index.d.ts +4 -0
- package/dist/errors/index.js +4 -0
- package/dist/errors-ewgSNicb.js +741 -0
- package/dist/errors-ewgSNicb.js.map +1 -0
- package/dist/{errors-CpoDEfUZ.js → errors-k3B8orjH.js} +41 -4
- package/dist/errors-k3B8orjH.js.map +1 -0
- package/dist/extensions/index.d.ts +2 -0
- package/dist/extensions/index.js +4 -0
- package/dist/extensions-CepYdzro.js +191 -0
- package/dist/extensions-CepYdzro.js.map +1 -0
- package/dist/git/index.d.ts +74 -0
- package/dist/git/index.d.ts.map +1 -0
- package/dist/git/index.js +345 -0
- package/dist/git/index.js.map +1 -0
- package/dist/index-B7QgIs0N.d.ts +1841 -0
- package/dist/index-B7QgIs0N.d.ts.map +1 -0
- package/dist/index-Dy6u9r60.d.ts +390 -0
- package/dist/index-Dy6u9r60.d.ts.map +1 -0
- package/dist/index.d.ts +27 -189
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +12 -43
- package/dist/index.js.map +1 -1
- package/dist/interpreter/index.d.ts +309 -0
- package/dist/interpreter/index.d.ts.map +1 -0
- package/dist/interpreter/index.js +264 -0
- package/dist/interpreter/index.js.map +1 -0
- package/dist/openai/index.d.ts +3 -2
- package/dist/openai/index.d.ts.map +1 -1
- package/dist/openai/index.js +2 -2
- package/dist/openai/index.js.map +1 -1
- package/dist/opencode/index.d.ts +137 -160
- package/dist/opencode/index.d.ts.map +1 -1
- package/dist/opencode/index.js +269 -159
- package/dist/opencode/index.js.map +1 -1
- package/dist/sandbox-DHNO89IF.d.ts +828 -0
- package/dist/sandbox-DHNO89IF.d.ts.map +1 -0
- package/dist/{sandbox-B-FLGbkP.js → sandbox-boKWPIcd.js} +8214 -7267
- package/dist/sandbox-boKWPIcd.js.map +1 -0
- package/dist/sidecar/index.d.ts +77 -0
- package/dist/sidecar/index.d.ts.map +1 -0
- package/dist/sidecar/index.js +201 -0
- package/dist/sidecar/index.js.map +1 -0
- package/dist/xterm/index.d.ts +6 -6
- package/dist/xterm/index.d.ts.map +1 -1
- package/dist/xterm/index.js +6 -6
- package/dist/xterm/index.js.map +1 -1
- package/package.json +36 -3
- package/dist/contexts-DPFhc2nR.d.ts +0 -238
- package/dist/contexts-DPFhc2nR.d.ts.map +0 -1
- package/dist/dist-mAH_7Ui7.js.map +0 -1
- package/dist/errors-CpoDEfUZ.js.map +0 -1
- package/dist/sandbox-44kEJjAc.d.ts +0 -2652
- package/dist/sandbox-44kEJjAc.d.ts.map +0 -1
- package/dist/sandbox-B-FLGbkP.js.map +0 -1
|
@@ -1,2652 +0,0 @@
|
|
|
1
|
-
import { Container, ContainerProxy } from "@cloudflare/containers";
|
|
2
|
-
import { RpcTarget } from "capnweb";
|
|
3
|
-
|
|
4
|
-
//#region ../shared/dist/logger/types.d.ts
|
|
5
|
-
|
|
6
|
-
type LogComponent = 'container' | 'sandbox-do' | 'executor';
|
|
7
|
-
/**
|
|
8
|
-
* Context metadata included in every log entry
|
|
9
|
-
*/
|
|
10
|
-
interface LogContext {
|
|
11
|
-
/**
|
|
12
|
-
* Unique trace ID for request correlation across distributed components
|
|
13
|
-
* Format: "tr_" + 16 hex chars (e.g., "tr_7f3a9b2c4e5d6f1a")
|
|
14
|
-
*/
|
|
15
|
-
traceId: string;
|
|
16
|
-
/**
|
|
17
|
-
* Component that generated the log
|
|
18
|
-
*/
|
|
19
|
-
component: LogComponent;
|
|
20
|
-
/**
|
|
21
|
-
* Sandbox identifier (which sandbox instance)
|
|
22
|
-
*/
|
|
23
|
-
sandboxId?: string;
|
|
24
|
-
/**
|
|
25
|
-
* Session identifier (which session within sandbox)
|
|
26
|
-
*/
|
|
27
|
-
sessionId?: string;
|
|
28
|
-
/**
|
|
29
|
-
* Process identifier (which background process)
|
|
30
|
-
*/
|
|
31
|
-
processId?: string;
|
|
32
|
-
/**
|
|
33
|
-
* Command identifier (which command execution)
|
|
34
|
-
*/
|
|
35
|
-
commandId?: string;
|
|
36
|
-
/**
|
|
37
|
-
* Duration in milliseconds
|
|
38
|
-
*/
|
|
39
|
-
durationMs?: number;
|
|
40
|
-
/**
|
|
41
|
-
* Service version (from SANDBOX_VERSION env var)
|
|
42
|
-
*/
|
|
43
|
-
serviceVersion?: string;
|
|
44
|
-
/**
|
|
45
|
-
* Instance identifier (hostname or container ID)
|
|
46
|
-
*/
|
|
47
|
-
instanceId?: string;
|
|
48
|
-
/**
|
|
49
|
-
* Extensible for additional metadata
|
|
50
|
-
*/
|
|
51
|
-
[key: string]: unknown;
|
|
52
|
-
}
|
|
53
|
-
/**
|
|
54
|
-
* Logger interface for structured logging
|
|
55
|
-
*
|
|
56
|
-
* All methods accept optional context that gets merged with the logger's base context.
|
|
57
|
-
*/
|
|
58
|
-
interface Logger {
|
|
59
|
-
/**
|
|
60
|
-
* Log debug-level message (most verbose, typically disabled in production)
|
|
61
|
-
*
|
|
62
|
-
* @param message Human-readable message
|
|
63
|
-
* @param context Optional additional context
|
|
64
|
-
*/
|
|
65
|
-
debug(message: string, context?: Partial<LogContext>): void;
|
|
66
|
-
/**
|
|
67
|
-
* Log info-level message (normal operational events)
|
|
68
|
-
*
|
|
69
|
-
* @param message Human-readable message
|
|
70
|
-
* @param context Optional additional context
|
|
71
|
-
*/
|
|
72
|
-
info(message: string, context?: Partial<LogContext>): void;
|
|
73
|
-
/**
|
|
74
|
-
* Log warning-level message (recoverable issues, degraded state)
|
|
75
|
-
*
|
|
76
|
-
* @param message Human-readable message
|
|
77
|
-
* @param context Optional additional context
|
|
78
|
-
*/
|
|
79
|
-
warn(message: string, context?: Partial<LogContext>): void;
|
|
80
|
-
/**
|
|
81
|
-
* Log error-level message (failures, exceptions)
|
|
82
|
-
*
|
|
83
|
-
* @param message Human-readable message
|
|
84
|
-
* @param error Optional Error object to include
|
|
85
|
-
* @param context Optional additional context
|
|
86
|
-
*/
|
|
87
|
-
error(message: string, error?: Error, context?: Partial<LogContext>): void;
|
|
88
|
-
/**
|
|
89
|
-
* Create a child logger with additional context
|
|
90
|
-
*
|
|
91
|
-
* The child logger inherits all context from the parent and adds new context.
|
|
92
|
-
* This is useful for adding request-specific context without passing through parameters.
|
|
93
|
-
*
|
|
94
|
-
* @param context Additional context to merge
|
|
95
|
-
* @returns New logger instance with merged context
|
|
96
|
-
*
|
|
97
|
-
* @example
|
|
98
|
-
* const logger = createLogger({ component: 'sandbox-do', traceId: 'tr_abc123' });
|
|
99
|
-
* const execLogger = logger.child({ commandId: 'cmd-456' });
|
|
100
|
-
* execLogger.info('Command started'); // Includes all context: component, traceId, commandId
|
|
101
|
-
*/
|
|
102
|
-
child(context: Partial<LogContext>): Logger;
|
|
103
|
-
}
|
|
104
|
-
//#endregion
|
|
105
|
-
//#region ../shared/dist/interpreter-types.d.ts
|
|
106
|
-
interface CreateContextOptions {
|
|
107
|
-
/**
|
|
108
|
-
* Programming language for the context
|
|
109
|
-
* @default 'python'
|
|
110
|
-
*/
|
|
111
|
-
language?: 'python' | 'javascript' | 'typescript';
|
|
112
|
-
/**
|
|
113
|
-
* Working directory for the context
|
|
114
|
-
* @default '/workspace'
|
|
115
|
-
*/
|
|
116
|
-
cwd?: string;
|
|
117
|
-
/**
|
|
118
|
-
* Environment variables for the context.
|
|
119
|
-
* Undefined values are skipped (treated as "not configured").
|
|
120
|
-
*/
|
|
121
|
-
envVars?: Record<string, string | undefined>;
|
|
122
|
-
/**
|
|
123
|
-
* Request timeout in milliseconds
|
|
124
|
-
* @default 30000
|
|
125
|
-
*/
|
|
126
|
-
timeout?: number;
|
|
127
|
-
}
|
|
128
|
-
interface CodeContext {
|
|
129
|
-
/**
|
|
130
|
-
* Unique identifier for the context
|
|
131
|
-
*/
|
|
132
|
-
readonly id: string;
|
|
133
|
-
/**
|
|
134
|
-
* Programming language of the context
|
|
135
|
-
*/
|
|
136
|
-
readonly language: string;
|
|
137
|
-
/**
|
|
138
|
-
* Current working directory
|
|
139
|
-
*/
|
|
140
|
-
readonly cwd: string;
|
|
141
|
-
/**
|
|
142
|
-
* When the context was created
|
|
143
|
-
*/
|
|
144
|
-
readonly createdAt: Date;
|
|
145
|
-
/**
|
|
146
|
-
* When the context was last used
|
|
147
|
-
*/
|
|
148
|
-
readonly lastUsed: Date;
|
|
149
|
-
}
|
|
150
|
-
interface RunCodeOptions {
|
|
151
|
-
/**
|
|
152
|
-
* Context to run the code in. If not provided, uses default context for the language
|
|
153
|
-
*/
|
|
154
|
-
context?: CodeContext;
|
|
155
|
-
/**
|
|
156
|
-
* Language to use if context is not provided
|
|
157
|
-
* @default 'python'
|
|
158
|
-
*/
|
|
159
|
-
language?: 'python' | 'javascript' | 'typescript';
|
|
160
|
-
/**
|
|
161
|
-
* Environment variables for this execution.
|
|
162
|
-
* Undefined values are skipped (treated as "not configured").
|
|
163
|
-
*/
|
|
164
|
-
envVars?: Record<string, string | undefined>;
|
|
165
|
-
/**
|
|
166
|
-
* Execution timeout in milliseconds
|
|
167
|
-
* @default 60000
|
|
168
|
-
*/
|
|
169
|
-
timeout?: number;
|
|
170
|
-
/**
|
|
171
|
-
* AbortSignal for cancelling execution
|
|
172
|
-
*/
|
|
173
|
-
signal?: AbortSignal;
|
|
174
|
-
/**
|
|
175
|
-
* Callback for stdout output
|
|
176
|
-
*/
|
|
177
|
-
onStdout?: (output: OutputMessage) => void | Promise<void>;
|
|
178
|
-
/**
|
|
179
|
-
* Callback for stderr output
|
|
180
|
-
*/
|
|
181
|
-
onStderr?: (output: OutputMessage) => void | Promise<void>;
|
|
182
|
-
/**
|
|
183
|
-
* Callback for execution results (charts, tables, etc)
|
|
184
|
-
*/
|
|
185
|
-
onResult?: (result: Result) => void | Promise<void>;
|
|
186
|
-
/**
|
|
187
|
-
* Callback for execution errors
|
|
188
|
-
*/
|
|
189
|
-
onError?: (error: ExecutionError) => void | Promise<void>;
|
|
190
|
-
}
|
|
191
|
-
interface OutputMessage {
|
|
192
|
-
/**
|
|
193
|
-
* The output text
|
|
194
|
-
*/
|
|
195
|
-
text: string;
|
|
196
|
-
/**
|
|
197
|
-
* Timestamp of the output
|
|
198
|
-
*/
|
|
199
|
-
timestamp: number;
|
|
200
|
-
}
|
|
201
|
-
interface Result {
|
|
202
|
-
/**
|
|
203
|
-
* Plain text representation
|
|
204
|
-
*/
|
|
205
|
-
text?: string;
|
|
206
|
-
/**
|
|
207
|
-
* HTML representation (tables, formatted output)
|
|
208
|
-
*/
|
|
209
|
-
html?: string;
|
|
210
|
-
/**
|
|
211
|
-
* PNG image data (base64 encoded)
|
|
212
|
-
*/
|
|
213
|
-
png?: string;
|
|
214
|
-
/**
|
|
215
|
-
* JPEG image data (base64 encoded)
|
|
216
|
-
*/
|
|
217
|
-
jpeg?: string;
|
|
218
|
-
/**
|
|
219
|
-
* SVG image data
|
|
220
|
-
*/
|
|
221
|
-
svg?: string;
|
|
222
|
-
/**
|
|
223
|
-
* LaTeX representation
|
|
224
|
-
*/
|
|
225
|
-
latex?: string;
|
|
226
|
-
/**
|
|
227
|
-
* Markdown representation
|
|
228
|
-
*/
|
|
229
|
-
markdown?: string;
|
|
230
|
-
/**
|
|
231
|
-
* JavaScript code to execute
|
|
232
|
-
*/
|
|
233
|
-
javascript?: string;
|
|
234
|
-
/**
|
|
235
|
-
* JSON data
|
|
236
|
-
*/
|
|
237
|
-
json?: any;
|
|
238
|
-
/**
|
|
239
|
-
* Chart data if the result is a visualization
|
|
240
|
-
*/
|
|
241
|
-
chart?: ChartData;
|
|
242
|
-
/**
|
|
243
|
-
* Raw data object
|
|
244
|
-
*/
|
|
245
|
-
data?: any;
|
|
246
|
-
/**
|
|
247
|
-
* Available output formats
|
|
248
|
-
*/
|
|
249
|
-
formats(): string[];
|
|
250
|
-
}
|
|
251
|
-
interface ChartData {
|
|
252
|
-
/**
|
|
253
|
-
* Type of chart
|
|
254
|
-
*/
|
|
255
|
-
type: 'line' | 'bar' | 'scatter' | 'pie' | 'histogram' | 'heatmap' | 'unknown';
|
|
256
|
-
/**
|
|
257
|
-
* Chart title
|
|
258
|
-
*/
|
|
259
|
-
title?: string;
|
|
260
|
-
/**
|
|
261
|
-
* Chart data (format depends on library)
|
|
262
|
-
*/
|
|
263
|
-
data: any;
|
|
264
|
-
/**
|
|
265
|
-
* Chart layout/configuration
|
|
266
|
-
*/
|
|
267
|
-
layout?: any;
|
|
268
|
-
/**
|
|
269
|
-
* Additional configuration
|
|
270
|
-
*/
|
|
271
|
-
config?: any;
|
|
272
|
-
/**
|
|
273
|
-
* Library that generated the chart
|
|
274
|
-
*/
|
|
275
|
-
library?: 'matplotlib' | 'plotly' | 'altair' | 'seaborn' | 'unknown';
|
|
276
|
-
/**
|
|
277
|
-
* Base64 encoded image if available
|
|
278
|
-
*/
|
|
279
|
-
image?: string;
|
|
280
|
-
}
|
|
281
|
-
interface ExecutionError {
|
|
282
|
-
/**
|
|
283
|
-
* Error name/type (e.g., 'NameError', 'SyntaxError')
|
|
284
|
-
*/
|
|
285
|
-
name: string;
|
|
286
|
-
/**
|
|
287
|
-
* Error message
|
|
288
|
-
*/
|
|
289
|
-
message: string;
|
|
290
|
-
/**
|
|
291
|
-
* Stack trace
|
|
292
|
-
*/
|
|
293
|
-
traceback: string[];
|
|
294
|
-
/**
|
|
295
|
-
* Line number where error occurred
|
|
296
|
-
*/
|
|
297
|
-
lineNumber?: number;
|
|
298
|
-
}
|
|
299
|
-
interface ExecutionResult {
|
|
300
|
-
code: string;
|
|
301
|
-
logs: {
|
|
302
|
-
stdout: string[];
|
|
303
|
-
stderr: string[];
|
|
304
|
-
};
|
|
305
|
-
error?: ExecutionError;
|
|
306
|
-
executionCount?: number;
|
|
307
|
-
results: Array<{
|
|
308
|
-
text?: string;
|
|
309
|
-
html?: string;
|
|
310
|
-
png?: string;
|
|
311
|
-
jpeg?: string;
|
|
312
|
-
svg?: string;
|
|
313
|
-
latex?: string;
|
|
314
|
-
markdown?: string;
|
|
315
|
-
javascript?: string;
|
|
316
|
-
json?: any;
|
|
317
|
-
chart?: ChartData;
|
|
318
|
-
data?: any;
|
|
319
|
-
}>;
|
|
320
|
-
}
|
|
321
|
-
declare class Execution {
|
|
322
|
-
readonly code: string;
|
|
323
|
-
readonly context: CodeContext;
|
|
324
|
-
/**
|
|
325
|
-
* All results from the execution
|
|
326
|
-
*/
|
|
327
|
-
results: Result[];
|
|
328
|
-
/**
|
|
329
|
-
* Accumulated stdout and stderr
|
|
330
|
-
*/
|
|
331
|
-
logs: {
|
|
332
|
-
stdout: string[];
|
|
333
|
-
stderr: string[];
|
|
334
|
-
};
|
|
335
|
-
/**
|
|
336
|
-
* Execution error if any
|
|
337
|
-
*/
|
|
338
|
-
error?: ExecutionError;
|
|
339
|
-
/**
|
|
340
|
-
* Execution count (for interpreter)
|
|
341
|
-
*/
|
|
342
|
-
executionCount?: number;
|
|
343
|
-
constructor(code: string, context: CodeContext);
|
|
344
|
-
/**
|
|
345
|
-
* Convert to a plain object for serialization
|
|
346
|
-
*/
|
|
347
|
-
toJSON(): ExecutionResult;
|
|
348
|
-
}
|
|
349
|
-
//#endregion
|
|
350
|
-
//#region ../shared/dist/pty-types.d.ts
|
|
351
|
-
interface PtyOptions {
|
|
352
|
-
cols?: number;
|
|
353
|
-
rows?: number;
|
|
354
|
-
shell?: string;
|
|
355
|
-
}
|
|
356
|
-
//#endregion
|
|
357
|
-
//#region ../shared/dist/types.d.ts
|
|
358
|
-
interface BaseExecOptions {
|
|
359
|
-
/**
|
|
360
|
-
* Maximum execution time in milliseconds
|
|
361
|
-
*/
|
|
362
|
-
timeout?: number;
|
|
363
|
-
/**
|
|
364
|
-
* Environment variables for this command invocation.
|
|
365
|
-
* Values temporarily override session-level/container-level env for the
|
|
366
|
-
* duration of the command but do not persist after it completes.
|
|
367
|
-
* Undefined values are skipped (treated as "not configured").
|
|
368
|
-
*/
|
|
369
|
-
env?: Record<string, string | undefined>;
|
|
370
|
-
/**
|
|
371
|
-
* Working directory for command execution
|
|
372
|
-
*/
|
|
373
|
-
cwd?: string;
|
|
374
|
-
/**
|
|
375
|
-
* Text encoding for output (default: 'utf8')
|
|
376
|
-
*/
|
|
377
|
-
encoding?: string;
|
|
378
|
-
}
|
|
379
|
-
interface ExecOptions extends BaseExecOptions {
|
|
380
|
-
/**
|
|
381
|
-
* Enable real-time output streaming via callbacks
|
|
382
|
-
*/
|
|
383
|
-
stream?: boolean;
|
|
384
|
-
/**
|
|
385
|
-
* Callback for real-time output data
|
|
386
|
-
*/
|
|
387
|
-
onOutput?: (stream: 'stdout' | 'stderr', data: string) => void;
|
|
388
|
-
/**
|
|
389
|
-
* Callback when command completes (only when stream: true)
|
|
390
|
-
*/
|
|
391
|
-
onComplete?: (result: ExecResult) => void;
|
|
392
|
-
/**
|
|
393
|
-
* Callback for execution errors
|
|
394
|
-
*/
|
|
395
|
-
onError?: (error: Error) => void;
|
|
396
|
-
/**
|
|
397
|
-
* AbortSignal for cancelling execution
|
|
398
|
-
*/
|
|
399
|
-
signal?: AbortSignal;
|
|
400
|
-
/**
|
|
401
|
-
* Whether this command was initiated by the user or by internal
|
|
402
|
-
* infrastructure (backup, bucket mount, env setup, etc.).
|
|
403
|
-
* Defaults to 'user' when omitted.
|
|
404
|
-
*/
|
|
405
|
-
origin?: 'user' | 'internal';
|
|
406
|
-
}
|
|
407
|
-
interface ExecResult {
|
|
408
|
-
/**
|
|
409
|
-
* Whether the command succeeded (exitCode === 0)
|
|
410
|
-
*/
|
|
411
|
-
success: boolean;
|
|
412
|
-
/**
|
|
413
|
-
* Process exit code
|
|
414
|
-
*/
|
|
415
|
-
exitCode: number;
|
|
416
|
-
/**
|
|
417
|
-
* Standard output content
|
|
418
|
-
*/
|
|
419
|
-
stdout: string;
|
|
420
|
-
/**
|
|
421
|
-
* Standard error content
|
|
422
|
-
*/
|
|
423
|
-
stderr: string;
|
|
424
|
-
/**
|
|
425
|
-
* Command that was executed
|
|
426
|
-
*/
|
|
427
|
-
command: string;
|
|
428
|
-
/**
|
|
429
|
-
* Execution duration in milliseconds
|
|
430
|
-
*/
|
|
431
|
-
duration: number;
|
|
432
|
-
/**
|
|
433
|
-
* ISO timestamp when command started
|
|
434
|
-
*/
|
|
435
|
-
timestamp: string;
|
|
436
|
-
/**
|
|
437
|
-
* Session ID if provided
|
|
438
|
-
*/
|
|
439
|
-
sessionId?: string;
|
|
440
|
-
}
|
|
441
|
-
/**
|
|
442
|
-
* Result from waiting for a log pattern
|
|
443
|
-
*/
|
|
444
|
-
interface WaitForLogResult {
|
|
445
|
-
/** The log line that matched */
|
|
446
|
-
line: string;
|
|
447
|
-
/** Regex capture groups (if condition was a RegExp) */
|
|
448
|
-
match?: RegExpMatchArray;
|
|
449
|
-
}
|
|
450
|
-
/**
|
|
451
|
-
* Result from waiting for process exit
|
|
452
|
-
*/
|
|
453
|
-
interface WaitForExitResult {
|
|
454
|
-
/** Process exit code */
|
|
455
|
-
exitCode: number;
|
|
456
|
-
}
|
|
457
|
-
/**
|
|
458
|
-
* Options for waiting for a port to become ready
|
|
459
|
-
*/
|
|
460
|
-
interface WaitForPortOptions {
|
|
461
|
-
/**
|
|
462
|
-
* Check mode
|
|
463
|
-
* - 'http': Make an HTTP request and check for success status (default)
|
|
464
|
-
* - 'tcp': Just check if TCP connection succeeds
|
|
465
|
-
* @default 'http'
|
|
466
|
-
*/
|
|
467
|
-
mode?: 'http' | 'tcp';
|
|
468
|
-
/**
|
|
469
|
-
* HTTP path to check (only used when mode is 'http')
|
|
470
|
-
* @default '/'
|
|
471
|
-
*/
|
|
472
|
-
path?: string;
|
|
473
|
-
/**
|
|
474
|
-
* Expected HTTP status code or range (only used when mode is 'http')
|
|
475
|
-
* - Single number: exact match (e.g., 200)
|
|
476
|
-
* - Object with min/max: range match (e.g., { min: 200, max: 399 })
|
|
477
|
-
* @default { min: 200, max: 399 }
|
|
478
|
-
*/
|
|
479
|
-
status?: number | {
|
|
480
|
-
min: number;
|
|
481
|
-
max: number;
|
|
482
|
-
};
|
|
483
|
-
/**
|
|
484
|
-
* Maximum time to wait in milliseconds
|
|
485
|
-
* @default no timeout
|
|
486
|
-
*/
|
|
487
|
-
timeout?: number;
|
|
488
|
-
/**
|
|
489
|
-
* Interval between checks in milliseconds
|
|
490
|
-
* @default 500
|
|
491
|
-
*/
|
|
492
|
-
interval?: number;
|
|
493
|
-
}
|
|
494
|
-
/**
|
|
495
|
-
* Request body for port readiness check endpoint
|
|
496
|
-
*/
|
|
497
|
-
interface PortCheckRequest {
|
|
498
|
-
port: number;
|
|
499
|
-
mode: 'http' | 'tcp';
|
|
500
|
-
path?: string;
|
|
501
|
-
statusMin?: number;
|
|
502
|
-
statusMax?: number;
|
|
503
|
-
}
|
|
504
|
-
/**
|
|
505
|
-
* Request body for streaming port watch endpoint
|
|
506
|
-
*/
|
|
507
|
-
interface PortWatchRequest extends PortCheckRequest {
|
|
508
|
-
/** Process ID to monitor - stream closes if process exits */
|
|
509
|
-
processId?: string;
|
|
510
|
-
/** Internal polling interval in ms (default: 500) */
|
|
511
|
-
interval?: number;
|
|
512
|
-
}
|
|
513
|
-
interface ProcessOptions extends BaseExecOptions {
|
|
514
|
-
/**
|
|
515
|
-
* Optional session ID to run the background process in.
|
|
516
|
-
*
|
|
517
|
-
* When omitted, the sandbox's default execution policy applies.
|
|
518
|
-
*/
|
|
519
|
-
sessionId?: string;
|
|
520
|
-
/**
|
|
521
|
-
* Custom process ID for later reference
|
|
522
|
-
* If not provided, a UUID will be generated
|
|
523
|
-
*/
|
|
524
|
-
processId?: string;
|
|
525
|
-
/**
|
|
526
|
-
* Automatically cleanup process record after exit (default: true)
|
|
527
|
-
*/
|
|
528
|
-
autoCleanup?: boolean;
|
|
529
|
-
/**
|
|
530
|
-
* Callback when process exits
|
|
531
|
-
*/
|
|
532
|
-
onExit?: (code: number | null) => void;
|
|
533
|
-
/**
|
|
534
|
-
* Callback for real-time output (background processes)
|
|
535
|
-
*/
|
|
536
|
-
onOutput?: (stream: 'stdout' | 'stderr', data: string) => void;
|
|
537
|
-
/**
|
|
538
|
-
* Callback when process starts successfully
|
|
539
|
-
*/
|
|
540
|
-
onStart?: (process: Process) => void;
|
|
541
|
-
/**
|
|
542
|
-
* Callback for process errors
|
|
543
|
-
*/
|
|
544
|
-
onError?: (error: Error) => void;
|
|
545
|
-
}
|
|
546
|
-
type ProcessStatus = 'starting' | 'running' | 'completed' | 'failed' | 'killed' | 'error';
|
|
547
|
-
interface Process {
|
|
548
|
-
/**
|
|
549
|
-
* Unique process identifier
|
|
550
|
-
*/
|
|
551
|
-
readonly id: string;
|
|
552
|
-
/**
|
|
553
|
-
* System process ID (if available and running)
|
|
554
|
-
*/
|
|
555
|
-
readonly pid?: number;
|
|
556
|
-
/**
|
|
557
|
-
* Command that was executed
|
|
558
|
-
*/
|
|
559
|
-
readonly command: string;
|
|
560
|
-
/**
|
|
561
|
-
* Current process status
|
|
562
|
-
*/
|
|
563
|
-
readonly status: ProcessStatus;
|
|
564
|
-
/**
|
|
565
|
-
* When the process was started
|
|
566
|
-
*/
|
|
567
|
-
readonly startTime: Date;
|
|
568
|
-
/**
|
|
569
|
-
* When the process ended (if completed)
|
|
570
|
-
*/
|
|
571
|
-
readonly endTime?: Date;
|
|
572
|
-
/**
|
|
573
|
-
* Process exit code (if completed)
|
|
574
|
-
*/
|
|
575
|
-
readonly exitCode?: number;
|
|
576
|
-
/**
|
|
577
|
-
* Session ID if provided
|
|
578
|
-
*/
|
|
579
|
-
readonly sessionId?: string;
|
|
580
|
-
/**
|
|
581
|
-
* Kill the process
|
|
582
|
-
*/
|
|
583
|
-
kill(signal?: string): Promise<void>;
|
|
584
|
-
/**
|
|
585
|
-
* Get current process status (refreshed)
|
|
586
|
-
*/
|
|
587
|
-
getStatus(): Promise<ProcessStatus>;
|
|
588
|
-
/**
|
|
589
|
-
* Get accumulated logs
|
|
590
|
-
*/
|
|
591
|
-
getLogs(): Promise<{
|
|
592
|
-
stdout: string;
|
|
593
|
-
stderr: string;
|
|
594
|
-
}>;
|
|
595
|
-
/**
|
|
596
|
-
* Wait for a log pattern to appear in process output
|
|
597
|
-
*
|
|
598
|
-
* @example
|
|
599
|
-
* const proc = await sandbox.startProcess("python train.py");
|
|
600
|
-
* await proc.waitForLog("Epoch 1 complete");
|
|
601
|
-
* await proc.waitForLog(/Epoch (\d+) complete/);
|
|
602
|
-
*/
|
|
603
|
-
waitForLog(pattern: string | RegExp, timeout?: number): Promise<WaitForLogResult>;
|
|
604
|
-
/**
|
|
605
|
-
* Wait for a port to become ready
|
|
606
|
-
*
|
|
607
|
-
* @example
|
|
608
|
-
* // Wait for HTTP endpoint to return 200-399
|
|
609
|
-
* const proc = await sandbox.startProcess("npm run dev");
|
|
610
|
-
* await proc.waitForPort(3000);
|
|
611
|
-
*
|
|
612
|
-
* @example
|
|
613
|
-
* // Wait for specific health endpoint
|
|
614
|
-
* await proc.waitForPort(3000, { path: '/health', status: 200 });
|
|
615
|
-
*
|
|
616
|
-
* @example
|
|
617
|
-
* // TCP-only check (just verify port is accepting connections)
|
|
618
|
-
* await proc.waitForPort(5432, { mode: 'tcp' });
|
|
619
|
-
*/
|
|
620
|
-
waitForPort(port: number, options?: WaitForPortOptions): Promise<void>;
|
|
621
|
-
/**
|
|
622
|
-
* Wait for the process to exit
|
|
623
|
-
*
|
|
624
|
-
* Returns the exit code. Use getProcessLogs() or streamProcessLogs()
|
|
625
|
-
* to retrieve output after the process exits.
|
|
626
|
-
*/
|
|
627
|
-
waitForExit(timeout?: number): Promise<WaitForExitResult>;
|
|
628
|
-
}
|
|
629
|
-
interface ExecEvent {
|
|
630
|
-
type: 'start' | 'stdout' | 'stderr' | 'complete' | 'error';
|
|
631
|
-
timestamp: string;
|
|
632
|
-
data?: string;
|
|
633
|
-
command?: string;
|
|
634
|
-
exitCode?: number;
|
|
635
|
-
result?: ExecResult;
|
|
636
|
-
error?: string;
|
|
637
|
-
sessionId?: string;
|
|
638
|
-
pid?: number;
|
|
639
|
-
}
|
|
640
|
-
interface LogEvent {
|
|
641
|
-
type: 'stdout' | 'stderr' | 'exit' | 'error';
|
|
642
|
-
timestamp: string;
|
|
643
|
-
data: string;
|
|
644
|
-
processId: string;
|
|
645
|
-
sessionId?: string;
|
|
646
|
-
exitCode?: number;
|
|
647
|
-
}
|
|
648
|
-
interface StreamOptions extends BaseExecOptions {
|
|
649
|
-
/**
|
|
650
|
-
* Optional session ID to run the streaming command in.
|
|
651
|
-
*
|
|
652
|
-
* When omitted, the sandbox's default execution policy applies.
|
|
653
|
-
*/
|
|
654
|
-
sessionId?: string;
|
|
655
|
-
/**
|
|
656
|
-
* Buffer size for streaming output
|
|
657
|
-
*/
|
|
658
|
-
bufferSize?: number;
|
|
659
|
-
/**
|
|
660
|
-
* AbortSignal for cancelling stream
|
|
661
|
-
*/
|
|
662
|
-
signal?: AbortSignal;
|
|
663
|
-
}
|
|
664
|
-
interface SessionOptions {
|
|
665
|
-
/**
|
|
666
|
-
* Optional session ID (auto-generated if not provided)
|
|
667
|
-
*/
|
|
668
|
-
id?: string;
|
|
669
|
-
/**
|
|
670
|
-
* Session name for identification
|
|
671
|
-
*/
|
|
672
|
-
name?: string;
|
|
673
|
-
/**
|
|
674
|
-
* Environment variables for this session.
|
|
675
|
-
* Undefined values are skipped (treated as "not configured").
|
|
676
|
-
*/
|
|
677
|
-
env?: Record<string, string | undefined>;
|
|
678
|
-
/**
|
|
679
|
-
* Working directory
|
|
680
|
-
*/
|
|
681
|
-
cwd?: string;
|
|
682
|
-
/**
|
|
683
|
-
* Enable PID namespace isolation (requires CAP_SYS_ADMIN)
|
|
684
|
-
*/
|
|
685
|
-
isolation?: boolean;
|
|
686
|
-
/**
|
|
687
|
-
* Maximum amount of time a command can run in milliseconds
|
|
688
|
-
*/
|
|
689
|
-
commandTimeoutMs?: number;
|
|
690
|
-
}
|
|
691
|
-
interface SandboxOptions {
|
|
692
|
-
/**
|
|
693
|
-
* Duration after which the sandbox instance will sleep if no requests are received
|
|
694
|
-
* Can be:
|
|
695
|
-
* - A string like "30s", "3m", "5m", "1h" (seconds, minutes, or hours)
|
|
696
|
-
* - A number representing seconds (e.g., 180 for 3 minutes)
|
|
697
|
-
* Default: "10m" (10 minutes)
|
|
698
|
-
*
|
|
699
|
-
* Note: Ignored when keepAlive is true
|
|
700
|
-
*/
|
|
701
|
-
sleepAfter?: string | number;
|
|
702
|
-
/**
|
|
703
|
-
* Keep the container alive indefinitely by preventing automatic shutdown
|
|
704
|
-
* When true, the container will never auto-timeout and must be explicitly destroyed
|
|
705
|
-
* - Any scenario where activity can't be automatically detected
|
|
706
|
-
*
|
|
707
|
-
* Important: You MUST call sandbox.destroy() when done to avoid resource leaks
|
|
708
|
-
*
|
|
709
|
-
* Default: false
|
|
710
|
-
*/
|
|
711
|
-
keepAlive?: boolean;
|
|
712
|
-
/**
|
|
713
|
-
* When true (the default), implicit operations automatically create and reuse
|
|
714
|
-
* a persistent default shell session. Set to false to run implicit top-level
|
|
715
|
-
* operations sessionlessly, where each command spawns a fresh process with no
|
|
716
|
-
* shared shell state. Explicit per-call session IDs continue to work normally
|
|
717
|
-
* when this is false.
|
|
718
|
-
*
|
|
719
|
-
* Default: true
|
|
720
|
-
*/
|
|
721
|
-
enableDefaultSession?: boolean;
|
|
722
|
-
/**
|
|
723
|
-
* Normalize sandbox ID to lowercase for preview URL compatibility
|
|
724
|
-
*
|
|
725
|
-
* Required for preview URLs because hostnames are case-insensitive (RFC 3986), which
|
|
726
|
-
* would route requests to a different Durable Object instance with IDs containing uppercase letters.
|
|
727
|
-
*
|
|
728
|
-
* **Important:** Different normalizeId values create different Durable Object instances:
|
|
729
|
-
* - `getSandbox(ns, "MyProject")` → DO key: "MyProject"
|
|
730
|
-
* - `getSandbox(ns, "MyProject", {normalizeId: true})` → DO key: "myproject"
|
|
731
|
-
*
|
|
732
|
-
* **Future change:** In a future version, this will default to `true` (automatically lowercase all IDs).
|
|
733
|
-
* IDs with uppercase letters will trigger a warning. To prepare, use lowercase IDs or explicitly
|
|
734
|
-
* pass `normalizeId: true`.
|
|
735
|
-
*
|
|
736
|
-
* @example
|
|
737
|
-
* getSandbox(ns, "my-project") // Works with preview URLs (lowercase)
|
|
738
|
-
* getSandbox(ns, "MyProject", {normalizeId: true}) // Normalized to "myproject"
|
|
739
|
-
*
|
|
740
|
-
* @default false
|
|
741
|
-
*/
|
|
742
|
-
normalizeId?: boolean;
|
|
743
|
-
/**
|
|
744
|
-
* Container startup timeout configuration
|
|
745
|
-
*
|
|
746
|
-
* Tune timeouts based on your container's characteristics. SDK defaults (30s instance, 90s ports)
|
|
747
|
-
* work for most use cases. Adjust for heavy containers or fail-fast applications.
|
|
748
|
-
*
|
|
749
|
-
* Can also be configured via environment variables:
|
|
750
|
-
* - SANDBOX_INSTANCE_TIMEOUT_MS
|
|
751
|
-
* - SANDBOX_PORT_TIMEOUT_MS
|
|
752
|
-
* - SANDBOX_POLL_INTERVAL_MS
|
|
753
|
-
*
|
|
754
|
-
* Precedence: options > env vars > SDK defaults
|
|
755
|
-
*
|
|
756
|
-
* @example
|
|
757
|
-
* // Heavy containers (ML models, large apps)
|
|
758
|
-
* getSandbox(ns, id, {
|
|
759
|
-
* containerTimeouts: { portReadyTimeoutMS: 180_000 }
|
|
760
|
-
* })
|
|
761
|
-
*
|
|
762
|
-
* @example
|
|
763
|
-
* // Fail-fast for latency-sensitive apps
|
|
764
|
-
* getSandbox(ns, id, {
|
|
765
|
-
* containerTimeouts: {
|
|
766
|
-
* instanceGetTimeoutMS: 15_000,
|
|
767
|
-
* portReadyTimeoutMS: 30_000
|
|
768
|
-
* }
|
|
769
|
-
* })
|
|
770
|
-
*/
|
|
771
|
-
containerTimeouts?: {
|
|
772
|
-
/**
|
|
773
|
-
* Time to wait for container instance provisioning
|
|
774
|
-
* @default 30000 (30s) - or SANDBOX_INSTANCE_TIMEOUT_MS env var
|
|
775
|
-
*/
|
|
776
|
-
instanceGetTimeoutMS?: number;
|
|
777
|
-
/**
|
|
778
|
-
* Time to wait for application startup and ports to be ready
|
|
779
|
-
* @default 90000 (90s) - or SANDBOX_PORT_TIMEOUT_MS env var
|
|
780
|
-
*/
|
|
781
|
-
portReadyTimeoutMS?: number;
|
|
782
|
-
/**
|
|
783
|
-
* How often to poll for container readiness
|
|
784
|
-
* @default 300 (300ms) - or SANDBOX_POLL_INTERVAL_MS env var
|
|
785
|
-
*/
|
|
786
|
-
waitIntervalMS?: number;
|
|
787
|
-
};
|
|
788
|
-
}
|
|
789
|
-
/**
|
|
790
|
-
* Execution session - isolated execution context within a sandbox
|
|
791
|
-
* Returned by sandbox.createSession()
|
|
792
|
-
* Provides the same API as ISandbox but bound to a specific session
|
|
793
|
-
*/
|
|
794
|
-
interface MkdirResult {
|
|
795
|
-
success: boolean;
|
|
796
|
-
path: string;
|
|
797
|
-
recursive: boolean;
|
|
798
|
-
timestamp: string;
|
|
799
|
-
exitCode?: number;
|
|
800
|
-
}
|
|
801
|
-
interface WriteFileResult {
|
|
802
|
-
success: boolean;
|
|
803
|
-
path: string;
|
|
804
|
-
timestamp: string;
|
|
805
|
-
exitCode?: number;
|
|
806
|
-
}
|
|
807
|
-
/**
|
|
808
|
-
* Valid `encoding` values accepted by `readFile` / `writeFile` options.
|
|
809
|
-
*
|
|
810
|
-
* - `'utf-8'` / `'utf8'` — treat content as text.
|
|
811
|
-
* - `'base64'` — treat content as base64-encoded binary.
|
|
812
|
-
* - `'none'` — streaming variant of `readFile`, returns a
|
|
813
|
-
* `ReadableStream<Uint8Array>` of raw bytes (see `ReadFileStreamResult`).
|
|
814
|
-
*/
|
|
815
|
-
type FileEncoding = 'utf-8' | 'utf8' | 'base64' | 'none';
|
|
816
|
-
interface ReadFileResult {
|
|
817
|
-
success: boolean;
|
|
818
|
-
path: string;
|
|
819
|
-
content: string;
|
|
820
|
-
timestamp: string;
|
|
821
|
-
exitCode?: number;
|
|
822
|
-
/**
|
|
823
|
-
* Encoding used for content (utf-8 for text, base64 for binary)
|
|
824
|
-
*/
|
|
825
|
-
encoding?: 'utf-8' | 'base64';
|
|
826
|
-
/**
|
|
827
|
-
* Whether the file is detected as binary
|
|
828
|
-
*/
|
|
829
|
-
isBinary?: boolean;
|
|
830
|
-
/**
|
|
831
|
-
* MIME type of the file (e.g., 'image/png', 'text/plain')
|
|
832
|
-
*/
|
|
833
|
-
mimeType?: string;
|
|
834
|
-
/**
|
|
835
|
-
* File size in bytes
|
|
836
|
-
*/
|
|
837
|
-
size?: number;
|
|
838
|
-
}
|
|
839
|
-
/**
|
|
840
|
-
* Result of `readFile()` with `encoding: 'none'`.
|
|
841
|
-
*
|
|
842
|
-
* `content` is a raw binary `ReadableStream<Uint8Array>` delivered directly
|
|
843
|
-
* over the capnp channel — no base64 encoding, no SSE framing, no buffering.
|
|
844
|
-
*/
|
|
845
|
-
interface ReadFileStreamResult {
|
|
846
|
-
success: true;
|
|
847
|
-
path: string;
|
|
848
|
-
content: ReadableStream<Uint8Array>;
|
|
849
|
-
size: number;
|
|
850
|
-
mimeType: string;
|
|
851
|
-
timestamp: string;
|
|
852
|
-
}
|
|
853
|
-
interface DeleteFileResult {
|
|
854
|
-
success: boolean;
|
|
855
|
-
path: string;
|
|
856
|
-
timestamp: string;
|
|
857
|
-
exitCode?: number;
|
|
858
|
-
}
|
|
859
|
-
interface RenameFileResult {
|
|
860
|
-
success: boolean;
|
|
861
|
-
path: string;
|
|
862
|
-
newPath: string;
|
|
863
|
-
timestamp: string;
|
|
864
|
-
exitCode?: number;
|
|
865
|
-
}
|
|
866
|
-
interface MoveFileResult {
|
|
867
|
-
success: boolean;
|
|
868
|
-
path: string;
|
|
869
|
-
newPath: string;
|
|
870
|
-
timestamp: string;
|
|
871
|
-
exitCode?: number;
|
|
872
|
-
}
|
|
873
|
-
interface FileExistsResult {
|
|
874
|
-
success: boolean;
|
|
875
|
-
path: string;
|
|
876
|
-
exists: boolean;
|
|
877
|
-
timestamp: string;
|
|
878
|
-
}
|
|
879
|
-
interface FileInfo {
|
|
880
|
-
name: string;
|
|
881
|
-
absolutePath: string;
|
|
882
|
-
relativePath: string;
|
|
883
|
-
type: 'file' | 'directory' | 'symlink' | 'other';
|
|
884
|
-
size: number;
|
|
885
|
-
modifiedAt: string;
|
|
886
|
-
mode: string;
|
|
887
|
-
permissions: {
|
|
888
|
-
readable: boolean;
|
|
889
|
-
writable: boolean;
|
|
890
|
-
executable: boolean;
|
|
891
|
-
};
|
|
892
|
-
}
|
|
893
|
-
interface ListFilesOptions {
|
|
894
|
-
recursive?: boolean;
|
|
895
|
-
includeHidden?: boolean;
|
|
896
|
-
/**
|
|
897
|
-
* Optional session ID used to resolve relative paths and execution context.
|
|
898
|
-
*
|
|
899
|
-
* When omitted, the sandbox's default execution policy applies.
|
|
900
|
-
*/
|
|
901
|
-
sessionId?: string;
|
|
902
|
-
}
|
|
903
|
-
interface ListFilesResult {
|
|
904
|
-
success: boolean;
|
|
905
|
-
path: string;
|
|
906
|
-
files: FileInfo[];
|
|
907
|
-
count: number;
|
|
908
|
-
timestamp: string;
|
|
909
|
-
exitCode?: number;
|
|
910
|
-
}
|
|
911
|
-
interface GitCheckoutResult {
|
|
912
|
-
success: boolean;
|
|
913
|
-
repoUrl: string;
|
|
914
|
-
branch: string;
|
|
915
|
-
targetDir: string;
|
|
916
|
-
timestamp: string;
|
|
917
|
-
exitCode?: number;
|
|
918
|
-
}
|
|
919
|
-
/**
|
|
920
|
-
* SSE events for file streaming
|
|
921
|
-
*/
|
|
922
|
-
type FileStreamEvent = {
|
|
923
|
-
type: 'metadata';
|
|
924
|
-
mimeType: string;
|
|
925
|
-
size: number;
|
|
926
|
-
isBinary: boolean;
|
|
927
|
-
encoding: 'utf-8' | 'base64';
|
|
928
|
-
} | {
|
|
929
|
-
type: 'chunk';
|
|
930
|
-
data: string;
|
|
931
|
-
} | {
|
|
932
|
-
type: 'complete';
|
|
933
|
-
bytesRead: number;
|
|
934
|
-
} | {
|
|
935
|
-
type: 'error';
|
|
936
|
-
error: string;
|
|
937
|
-
};
|
|
938
|
-
/**
|
|
939
|
-
* File metadata from streaming
|
|
940
|
-
*/
|
|
941
|
-
interface FileMetadata {
|
|
942
|
-
mimeType: string;
|
|
943
|
-
size: number;
|
|
944
|
-
isBinary: boolean;
|
|
945
|
-
encoding: 'utf-8' | 'base64';
|
|
946
|
-
}
|
|
947
|
-
/**
|
|
948
|
-
* File stream chunk - either string (text) or Uint8Array (binary, auto-decoded)
|
|
949
|
-
*/
|
|
950
|
-
type FileChunk = string | Uint8Array;
|
|
951
|
-
/**
|
|
952
|
-
* Options for watching a directory.
|
|
953
|
-
*
|
|
954
|
-
* `watch()` resolves only after the watcher is established on the filesystem.
|
|
955
|
-
* The returned SSE stream can be consumed with `parseSSEStream()`.
|
|
956
|
-
*/
|
|
957
|
-
interface WatchOptions {
|
|
958
|
-
/**
|
|
959
|
-
* Watch subdirectories recursively
|
|
960
|
-
* @default true
|
|
961
|
-
*/
|
|
962
|
-
recursive?: boolean;
|
|
963
|
-
/**
|
|
964
|
-
* Glob patterns to include (e.g., '*.ts', '*.js').
|
|
965
|
-
* If not specified, all files are included.
|
|
966
|
-
* Cannot be used together with `exclude`.
|
|
967
|
-
*/
|
|
968
|
-
include?: string[];
|
|
969
|
-
/**
|
|
970
|
-
* Glob patterns to exclude (e.g., 'node_modules', '.git').
|
|
971
|
-
* Cannot be used together with `include`.
|
|
972
|
-
* @default ['.git', 'node_modules', '.DS_Store']
|
|
973
|
-
*/
|
|
974
|
-
exclude?: string[];
|
|
975
|
-
/**
|
|
976
|
-
* Session to run the watch in.
|
|
977
|
-
* If omitted, the default session is used.
|
|
978
|
-
*/
|
|
979
|
-
sessionId?: string;
|
|
980
|
-
}
|
|
981
|
-
/**
|
|
982
|
-
* Options for checking whether a path changed while disconnected.
|
|
983
|
-
*
|
|
984
|
-
* Pass the `version` returned from a previous `checkChanges()` call to learn
|
|
985
|
-
* whether the path is unchanged, changed, or needs a full resync because the
|
|
986
|
-
* retained change state was reset. Change state lives only for the current
|
|
987
|
-
* container lifetime and may expire while idle.
|
|
988
|
-
*/
|
|
989
|
-
interface CheckChangesOptions extends WatchOptions {
|
|
990
|
-
/**
|
|
991
|
-
* Version returned by a previous `checkChanges()` call.
|
|
992
|
-
*/
|
|
993
|
-
since?: string;
|
|
994
|
-
}
|
|
995
|
-
/**
|
|
996
|
-
* @internal SSE event types for container communication
|
|
997
|
-
*/
|
|
998
|
-
type FileWatchEventType = 'create' | 'modify' | 'delete' | 'move_from' | 'move_to' | 'attrib';
|
|
999
|
-
/**
|
|
1000
|
-
* @internal Request body for starting a file watch
|
|
1001
|
-
*/
|
|
1002
|
-
interface WatchRequest {
|
|
1003
|
-
path: string;
|
|
1004
|
-
recursive?: boolean;
|
|
1005
|
-
events?: FileWatchEventType[];
|
|
1006
|
-
include?: string[];
|
|
1007
|
-
exclude?: string[];
|
|
1008
|
-
sessionId?: string;
|
|
1009
|
-
}
|
|
1010
|
-
/**
|
|
1011
|
-
* @internal Request body for checking retained change state.
|
|
1012
|
-
*/
|
|
1013
|
-
interface CheckChangesRequest extends WatchRequest {
|
|
1014
|
-
since?: string;
|
|
1015
|
-
}
|
|
1016
|
-
/**
|
|
1017
|
-
* SSE events emitted by `sandbox.watch()`.
|
|
1018
|
-
*/
|
|
1019
|
-
type FileWatchSSEEvent = {
|
|
1020
|
-
type: 'watching';
|
|
1021
|
-
path: string;
|
|
1022
|
-
watchId: string;
|
|
1023
|
-
} | {
|
|
1024
|
-
type: 'event';
|
|
1025
|
-
eventType: FileWatchEventType;
|
|
1026
|
-
path: string;
|
|
1027
|
-
isDirectory: boolean;
|
|
1028
|
-
timestamp: string;
|
|
1029
|
-
} | {
|
|
1030
|
-
type: 'error';
|
|
1031
|
-
error: string;
|
|
1032
|
-
} | {
|
|
1033
|
-
type: 'stopped';
|
|
1034
|
-
reason: string;
|
|
1035
|
-
};
|
|
1036
|
-
/**
|
|
1037
|
-
* Result returned by `checkChanges()`.
|
|
1038
|
-
*/
|
|
1039
|
-
type CheckChangesResult = {
|
|
1040
|
-
success: true;
|
|
1041
|
-
status: 'unchanged' | 'changed';
|
|
1042
|
-
version: string;
|
|
1043
|
-
timestamp: string;
|
|
1044
|
-
} | {
|
|
1045
|
-
success: true;
|
|
1046
|
-
status: 'resync';
|
|
1047
|
-
reason: 'expired' | 'restarted';
|
|
1048
|
-
version: string;
|
|
1049
|
-
timestamp: string;
|
|
1050
|
-
};
|
|
1051
|
-
interface ProcessStartResult {
|
|
1052
|
-
success: boolean;
|
|
1053
|
-
processId: string;
|
|
1054
|
-
pid?: number;
|
|
1055
|
-
command: string;
|
|
1056
|
-
timestamp: string;
|
|
1057
|
-
}
|
|
1058
|
-
interface ProcessListResult {
|
|
1059
|
-
success: boolean;
|
|
1060
|
-
processes: Array<{
|
|
1061
|
-
id: string;
|
|
1062
|
-
pid?: number;
|
|
1063
|
-
command: string;
|
|
1064
|
-
status: ProcessStatus;
|
|
1065
|
-
startTime: string;
|
|
1066
|
-
endTime?: string;
|
|
1067
|
-
exitCode?: number;
|
|
1068
|
-
}>;
|
|
1069
|
-
timestamp: string;
|
|
1070
|
-
}
|
|
1071
|
-
interface ProcessInfoResult {
|
|
1072
|
-
success: boolean;
|
|
1073
|
-
process: {
|
|
1074
|
-
id: string;
|
|
1075
|
-
pid?: number;
|
|
1076
|
-
command: string;
|
|
1077
|
-
status: ProcessStatus;
|
|
1078
|
-
startTime: string;
|
|
1079
|
-
endTime?: string;
|
|
1080
|
-
exitCode?: number;
|
|
1081
|
-
};
|
|
1082
|
-
timestamp: string;
|
|
1083
|
-
}
|
|
1084
|
-
interface ProcessKillResult {
|
|
1085
|
-
success: boolean;
|
|
1086
|
-
processId: string;
|
|
1087
|
-
signal?: string;
|
|
1088
|
-
timestamp: string;
|
|
1089
|
-
}
|
|
1090
|
-
interface ProcessLogsResult {
|
|
1091
|
-
success: boolean;
|
|
1092
|
-
processId: string;
|
|
1093
|
-
stdout: string;
|
|
1094
|
-
stderr: string;
|
|
1095
|
-
timestamp: string;
|
|
1096
|
-
}
|
|
1097
|
-
interface ProcessCleanupResult {
|
|
1098
|
-
success: boolean;
|
|
1099
|
-
message?: string;
|
|
1100
|
-
killedCount?: number;
|
|
1101
|
-
cleanedCount: number;
|
|
1102
|
-
timestamp: string;
|
|
1103
|
-
}
|
|
1104
|
-
interface SessionDeleteResult {
|
|
1105
|
-
success: boolean;
|
|
1106
|
-
sessionId: string;
|
|
1107
|
-
timestamp: string;
|
|
1108
|
-
}
|
|
1109
|
-
interface ExecutionSession {
|
|
1110
|
-
/** Unique session identifier */
|
|
1111
|
-
readonly id: string;
|
|
1112
|
-
exec(command: string, options?: ExecOptions): Promise<ExecResult>;
|
|
1113
|
-
execStream(command: string, options?: StreamOptions): Promise<ReadableStream<Uint8Array>>;
|
|
1114
|
-
startProcess(command: string, options?: ProcessOptions): Promise<Process>;
|
|
1115
|
-
listProcesses(sessionId?: string): Promise<Process[]>;
|
|
1116
|
-
getProcess(id: string, sessionId?: string): Promise<Process | null>;
|
|
1117
|
-
killProcess(id: string, signal?: string): Promise<void>;
|
|
1118
|
-
killAllProcesses(): Promise<number>;
|
|
1119
|
-
cleanupCompletedProcesses(): Promise<number>;
|
|
1120
|
-
getProcessLogs(id: string): Promise<{
|
|
1121
|
-
stdout: string;
|
|
1122
|
-
stderr: string;
|
|
1123
|
-
processId: string;
|
|
1124
|
-
}>;
|
|
1125
|
-
streamProcessLogs(processId: string, options?: {
|
|
1126
|
-
signal?: AbortSignal;
|
|
1127
|
-
}): Promise<ReadableStream<Uint8Array>>;
|
|
1128
|
-
writeFile(path: string, content: string | ReadableStream<Uint8Array>, options?: {
|
|
1129
|
-
encoding?: string;
|
|
1130
|
-
}): Promise<WriteFileResult>;
|
|
1131
|
-
readFile(path: string, options: {
|
|
1132
|
-
encoding: 'none';
|
|
1133
|
-
}): Promise<ReadFileStreamResult>;
|
|
1134
|
-
readFile(path: string, options?: {
|
|
1135
|
-
encoding?: Exclude<FileEncoding, 'none'>;
|
|
1136
|
-
}): Promise<ReadFileResult>;
|
|
1137
|
-
readFileStream(path: string): Promise<ReadableStream<Uint8Array>>;
|
|
1138
|
-
watch(path: string, options?: Omit<WatchOptions, 'sessionId'>): Promise<ReadableStream<Uint8Array>>;
|
|
1139
|
-
checkChanges(path: string, options?: Omit<CheckChangesOptions, 'sessionId'>): Promise<CheckChangesResult>;
|
|
1140
|
-
mkdir(path: string, options?: {
|
|
1141
|
-
recursive?: boolean;
|
|
1142
|
-
}): Promise<MkdirResult>;
|
|
1143
|
-
deleteFile(path: string): Promise<DeleteFileResult>;
|
|
1144
|
-
renameFile(oldPath: string, newPath: string): Promise<RenameFileResult>;
|
|
1145
|
-
moveFile(sourcePath: string, destinationPath: string): Promise<MoveFileResult>;
|
|
1146
|
-
listFiles(path: string, options?: ListFilesOptions): Promise<ListFilesResult>;
|
|
1147
|
-
exists(path: string): Promise<FileExistsResult>;
|
|
1148
|
-
gitCheckout(repoUrl: string, options?: {
|
|
1149
|
-
branch?: string;
|
|
1150
|
-
targetDir?: string;
|
|
1151
|
-
/** Clone depth for shallow clones (e.g., 1 for latest commit only) */
|
|
1152
|
-
depth?: number;
|
|
1153
|
-
/** Maximum wall-clock time for the git clone subprocess in milliseconds */
|
|
1154
|
-
cloneTimeoutMs?: number;
|
|
1155
|
-
}): Promise<GitCheckoutResult>;
|
|
1156
|
-
setEnvVars(envVars: Record<string, string | undefined>): Promise<void>;
|
|
1157
|
-
createCodeContext(options?: CreateContextOptions): Promise<CodeContext>;
|
|
1158
|
-
runCode(code: string, options?: RunCodeOptions): Promise<ExecutionResult>;
|
|
1159
|
-
runCodeStream(code: string, options?: RunCodeOptions): Promise<ReadableStream<Uint8Array>>;
|
|
1160
|
-
listCodeContexts(): Promise<CodeContext[]>;
|
|
1161
|
-
deleteCodeContext(contextId: string): Promise<void>;
|
|
1162
|
-
mountBucket(bucket: string, mountPath: string, options: MountBucketOptions): Promise<void>;
|
|
1163
|
-
unmountBucket(mountPath: string): Promise<void>;
|
|
1164
|
-
createBackup(options: BackupOptions): Promise<DirectoryBackup>;
|
|
1165
|
-
restoreBackup(backup: DirectoryBackup): Promise<RestoreBackupResult>;
|
|
1166
|
-
terminal(request: Request, options?: PtyOptions): Promise<Response>;
|
|
1167
|
-
}
|
|
1168
|
-
/**
|
|
1169
|
-
* Options for creating a directory backup
|
|
1170
|
-
*/
|
|
1171
|
-
interface BackupCompressionOptions {
|
|
1172
|
-
format?: 'gzip' | 'lz4' | 'zstd';
|
|
1173
|
-
threads?: number;
|
|
1174
|
-
}
|
|
1175
|
-
interface BackupOptions {
|
|
1176
|
-
/** Directory to back up. Must be absolute and under `/workspace`, `/home`, `/tmp`, `/var/tmp`, or `/app`. */
|
|
1177
|
-
dir: string;
|
|
1178
|
-
/** Human-readable name for this backup. Optional. */
|
|
1179
|
-
name?: string;
|
|
1180
|
-
/** Seconds until automatic garbage collection. Default: 259200 (3 days). No upper limit. */
|
|
1181
|
-
ttl?: number;
|
|
1182
|
-
/**
|
|
1183
|
-
* Respect git ignore rules for the backup directory when it is inside a git repository.
|
|
1184
|
-
*
|
|
1185
|
-
* Default: false.
|
|
1186
|
-
* If the directory is not inside a git repository, no git-based exclusions are applied.
|
|
1187
|
-
* If git is not installed in the container, a warning is logged and gitignore rules are skipped.
|
|
1188
|
-
*/
|
|
1189
|
-
gitignore?: boolean;
|
|
1190
|
-
/**
|
|
1191
|
-
* Glob patterns to exclude from the backup.
|
|
1192
|
-
* These are passed directly to mksquashfs as wildcard exclude patterns.
|
|
1193
|
-
*
|
|
1194
|
-
* @example ['node_modules', '*.log', '.cache']
|
|
1195
|
-
*/
|
|
1196
|
-
excludes?: string[];
|
|
1197
|
-
/**
|
|
1198
|
-
* Use local R2 binding for backup storage instead of presigned URLs.
|
|
1199
|
-
* Required for local development where presigned URLs and FUSE are unavailable.
|
|
1200
|
-
* When true, the DO resolves BACKUP_BUCKET from its own env as an R2 binding.
|
|
1201
|
-
*/
|
|
1202
|
-
localBucket?: boolean;
|
|
1203
|
-
compression?: BackupCompressionOptions;
|
|
1204
|
-
/**
|
|
1205
|
-
* Use parallel multipart upload to R2 for large archives.
|
|
1206
|
-
* Significantly speeds up uploads for archives over 10 MiB.
|
|
1207
|
-
* Default: true.
|
|
1208
|
-
*/
|
|
1209
|
-
multipart?: boolean;
|
|
1210
|
-
}
|
|
1211
|
-
/**
|
|
1212
|
-
* Handle representing a stored directory backup.
|
|
1213
|
-
* Serializable metadata returned by createBackup().
|
|
1214
|
-
* Store it anywhere and later pass it to restoreBackup().
|
|
1215
|
-
*/
|
|
1216
|
-
interface DirectoryBackup {
|
|
1217
|
-
/** Unique backup identifier */
|
|
1218
|
-
readonly id: string;
|
|
1219
|
-
/** Directory to restore into. Must be under `/workspace`, `/home`, `/tmp`, `/var/tmp`, or `/app`. */
|
|
1220
|
-
readonly dir: string;
|
|
1221
|
-
/** Whether this backup was created with local R2 binding mode. */
|
|
1222
|
-
readonly localBucket?: boolean;
|
|
1223
|
-
}
|
|
1224
|
-
/**
|
|
1225
|
-
* Result returned from a successful restoreBackup() call
|
|
1226
|
-
*/
|
|
1227
|
-
interface RestoreBackupResult {
|
|
1228
|
-
success: boolean;
|
|
1229
|
-
/** The directory that was restored */
|
|
1230
|
-
dir: string;
|
|
1231
|
-
/** Backup ID that was restored */
|
|
1232
|
-
id: string;
|
|
1233
|
-
}
|
|
1234
|
-
/**
|
|
1235
|
-
* Supported S3-compatible storage providers
|
|
1236
|
-
*/
|
|
1237
|
-
type BucketProvider = 'r2' | 's3' | 'gcs';
|
|
1238
|
-
/**
|
|
1239
|
-
* Credentials for S3-compatible storage
|
|
1240
|
-
*/
|
|
1241
|
-
interface BucketCredentials {
|
|
1242
|
-
accessKeyId: string;
|
|
1243
|
-
secretAccessKey: string;
|
|
1244
|
-
}
|
|
1245
|
-
/**
|
|
1246
|
-
* Options for mounting an S3-compatible bucket via s3fs-FUSE (production)
|
|
1247
|
-
*/
|
|
1248
|
-
interface RemoteMountBucketOptions {
|
|
1249
|
-
/**
|
|
1250
|
-
* S3-compatible endpoint URL
|
|
1251
|
-
*
|
|
1252
|
-
* Examples:
|
|
1253
|
-
* - R2: 'https://abc123.r2.cloudflarestorage.com'
|
|
1254
|
-
* - AWS S3: 'https://s3.us-west-2.amazonaws.com'
|
|
1255
|
-
* - GCS: 'https://storage.googleapis.com'
|
|
1256
|
-
*/
|
|
1257
|
-
endpoint: string;
|
|
1258
|
-
/**
|
|
1259
|
-
* Optional provider hint for automatic s3fs flag configuration
|
|
1260
|
-
* If not specified, will attempt to detect from endpoint URL.
|
|
1261
|
-
*
|
|
1262
|
-
* Examples:
|
|
1263
|
-
* - 'r2' - Cloudflare R2 (adds nomixupload)
|
|
1264
|
-
* - 's3' - Amazon S3 (standard configuration)
|
|
1265
|
-
* - 'gcs' - Google Cloud Storage (no special flags needed)
|
|
1266
|
-
*/
|
|
1267
|
-
provider?: BucketProvider;
|
|
1268
|
-
/**
|
|
1269
|
-
* Explicit credentials (overrides env var auto-detection)
|
|
1270
|
-
*/
|
|
1271
|
-
credentials?: BucketCredentials;
|
|
1272
|
-
/**
|
|
1273
|
-
* Mount filesystem as read-only
|
|
1274
|
-
* Default: false
|
|
1275
|
-
*/
|
|
1276
|
-
readOnly?: boolean;
|
|
1277
|
-
/**
|
|
1278
|
-
* Advanced: Override or extend s3fs options
|
|
1279
|
-
*
|
|
1280
|
-
* These will be merged with provider-specific defaults.
|
|
1281
|
-
* To override defaults completely, specify all options here.
|
|
1282
|
-
*
|
|
1283
|
-
* Common options:
|
|
1284
|
-
* - 'use_path_request_style' - Use path-style URLs (bucket/path vs bucket.host/path)
|
|
1285
|
-
* - 'nomixupload' - Disable mixed multipart uploads (needed for some providers)
|
|
1286
|
-
* - 'nomultipart' - Disable all multipart operations
|
|
1287
|
-
* - 'sigv2' - Use signature version 2 instead of v4
|
|
1288
|
-
* - 'no_check_certificate' - Skip SSL certificate validation (dev/testing only)
|
|
1289
|
-
*/
|
|
1290
|
-
s3fsOptions?: string[];
|
|
1291
|
-
/**
|
|
1292
|
-
* Optional prefix/subdirectory within the bucket to mount.
|
|
1293
|
-
*
|
|
1294
|
-
* When specified, only the contents under this prefix are visible at the
|
|
1295
|
-
* mount point, scoping the mount to a subdirectory of the bucket.
|
|
1296
|
-
*
|
|
1297
|
-
* Must start with '/' (e.g., '/workspaces/project123' or '/data/uploads/')
|
|
1298
|
-
*/
|
|
1299
|
-
prefix?: string;
|
|
1300
|
-
/**
|
|
1301
|
-
* Keep real credentials in the Durable Object; write dummy credentials into
|
|
1302
|
-
* the container-side s3fs password file. Outbound s3fs requests are
|
|
1303
|
-
* intercepted by the DO, signed with real credentials, and forwarded to the
|
|
1304
|
-
* configured endpoint.
|
|
1305
|
-
*
|
|
1306
|
-
* Default: false (real credentials are written into the container)
|
|
1307
|
-
*/
|
|
1308
|
-
credentialProxy?: boolean;
|
|
1309
|
-
}
|
|
1310
|
-
/**
|
|
1311
|
-
* Options for mounting a local R2 binding via bidirectional sync (local dev)
|
|
1312
|
-
*
|
|
1313
|
-
* Used during local development with `wrangler dev`. The Durable Object
|
|
1314
|
-
* resolves the R2 binding from its own env using the `bucket` parameter
|
|
1315
|
-
* and syncs files via polling instead of s3fs-FUSE.
|
|
1316
|
-
*/
|
|
1317
|
-
interface LocalMountBucketOptions {
|
|
1318
|
-
/**
|
|
1319
|
-
* Must be true to indicate local R2 binding mode.
|
|
1320
|
-
*/
|
|
1321
|
-
localBucket: true;
|
|
1322
|
-
/**
|
|
1323
|
-
* Optional prefix/subdirectory within the bucket to sync.
|
|
1324
|
-
*
|
|
1325
|
-
* When specified, only the contents under this prefix will be visible
|
|
1326
|
-
* at the mount point.
|
|
1327
|
-
*/
|
|
1328
|
-
prefix?: string;
|
|
1329
|
-
/**
|
|
1330
|
-
* Mount filesystem as read-only
|
|
1331
|
-
* Default: false
|
|
1332
|
-
*/
|
|
1333
|
-
readOnly?: boolean;
|
|
1334
|
-
}
|
|
1335
|
-
/**
|
|
1336
|
-
* Options for mounting an R2 binding via credential-less egress interception.
|
|
1337
|
-
*/
|
|
1338
|
-
interface R2BindingMountBucketOptions {
|
|
1339
|
-
/**
|
|
1340
|
-
* Must not be set — distinguishes this variant from RemoteMountBucketOptions.
|
|
1341
|
-
*/
|
|
1342
|
-
endpoint?: never;
|
|
1343
|
-
/**
|
|
1344
|
-
* Optional prefix/subdirectory within the bucket to mount.
|
|
1345
|
-
*
|
|
1346
|
-
* When specified, only the contents under this prefix will be visible
|
|
1347
|
-
* at the mount point.
|
|
1348
|
-
*/
|
|
1349
|
-
prefix?: string;
|
|
1350
|
-
/**
|
|
1351
|
-
* Mount filesystem as read-only
|
|
1352
|
-
* Default: false
|
|
1353
|
-
*/
|
|
1354
|
-
readOnly?: boolean;
|
|
1355
|
-
/**
|
|
1356
|
-
* Advanced: Override or extend s3fs options.
|
|
1357
|
-
* Provider defaults for R2 are still applied automatically.
|
|
1358
|
-
*/
|
|
1359
|
-
s3fsOptions?: string[];
|
|
1360
|
-
}
|
|
1361
|
-
/**
|
|
1362
|
-
* Options for mounting a bucket — remote (s3fs-FUSE), local (R2 binding sync),
|
|
1363
|
-
* or R2 egress (credential-less s3fs via egress interception).
|
|
1364
|
-
*/
|
|
1365
|
-
type MountBucketOptions = RemoteMountBucketOptions | LocalMountBucketOptions | R2BindingMountBucketOptions;
|
|
1366
|
-
interface ISandbox {
|
|
1367
|
-
exec(command: string, options?: ExecOptions): Promise<ExecResult>;
|
|
1368
|
-
startProcess(command: string, options?: ProcessOptions): Promise<Process>;
|
|
1369
|
-
listProcesses(sessionId?: string): Promise<Process[]>;
|
|
1370
|
-
getProcess(id: string, sessionId?: string): Promise<Process | null>;
|
|
1371
|
-
killProcess(id: string, signal?: string): Promise<void>;
|
|
1372
|
-
killAllProcesses(): Promise<number>;
|
|
1373
|
-
execStream(command: string, options?: StreamOptions): Promise<ReadableStream<Uint8Array>>;
|
|
1374
|
-
streamProcessLogs(processId: string, options?: {
|
|
1375
|
-
signal?: AbortSignal;
|
|
1376
|
-
}): Promise<ReadableStream<Uint8Array>>;
|
|
1377
|
-
cleanupCompletedProcesses(): Promise<number>;
|
|
1378
|
-
getProcessLogs(id: string): Promise<{
|
|
1379
|
-
stdout: string;
|
|
1380
|
-
stderr: string;
|
|
1381
|
-
processId: string;
|
|
1382
|
-
}>;
|
|
1383
|
-
writeFile(path: string, content: string | ReadableStream<Uint8Array>, options?: {
|
|
1384
|
-
encoding?: string;
|
|
1385
|
-
}): Promise<WriteFileResult>;
|
|
1386
|
-
readFile(path: string, options: {
|
|
1387
|
-
encoding: 'none';
|
|
1388
|
-
}): Promise<ReadFileStreamResult>;
|
|
1389
|
-
readFile(path: string, options?: {
|
|
1390
|
-
encoding?: Exclude<FileEncoding, 'none'>;
|
|
1391
|
-
}): Promise<ReadFileResult>;
|
|
1392
|
-
readFileStream(path: string): Promise<ReadableStream<Uint8Array>>;
|
|
1393
|
-
watch(path: string, options?: WatchOptions): Promise<ReadableStream<Uint8Array>>;
|
|
1394
|
-
checkChanges(path: string, options?: CheckChangesOptions): Promise<CheckChangesResult>;
|
|
1395
|
-
mkdir(path: string, options?: {
|
|
1396
|
-
recursive?: boolean;
|
|
1397
|
-
}): Promise<MkdirResult>;
|
|
1398
|
-
deleteFile(path: string): Promise<DeleteFileResult>;
|
|
1399
|
-
renameFile(oldPath: string, newPath: string): Promise<RenameFileResult>;
|
|
1400
|
-
moveFile(sourcePath: string, destinationPath: string): Promise<MoveFileResult>;
|
|
1401
|
-
listFiles(path: string, options?: ListFilesOptions): Promise<ListFilesResult>;
|
|
1402
|
-
exists(path: string, sessionId?: string): Promise<FileExistsResult>;
|
|
1403
|
-
gitCheckout(repoUrl: string, options?: {
|
|
1404
|
-
branch?: string;
|
|
1405
|
-
targetDir?: string;
|
|
1406
|
-
sessionId?: string;
|
|
1407
|
-
/** Clone depth for shallow clones (e.g., 1 for latest commit only) */
|
|
1408
|
-
depth?: number;
|
|
1409
|
-
/** Maximum wall-clock time for the git clone subprocess in milliseconds */
|
|
1410
|
-
cloneTimeoutMs?: number;
|
|
1411
|
-
}): Promise<GitCheckoutResult>;
|
|
1412
|
-
setEnvVars(envVars: Record<string, string | undefined>): Promise<void>;
|
|
1413
|
-
mountBucket(bucket: string, mountPath: string, options: MountBucketOptions): Promise<void>;
|
|
1414
|
-
unmountBucket(mountPath: string): Promise<void>;
|
|
1415
|
-
createSession(options?: SessionOptions): Promise<ExecutionSession>;
|
|
1416
|
-
deleteSession(sessionId: string): Promise<SessionDeleteResult>;
|
|
1417
|
-
/**
|
|
1418
|
-
* Returns the Cloudflare placement ID observed during the most recent
|
|
1419
|
-
* session-create handshake with the container. `null` when the container
|
|
1420
|
-
* does not expose `CLOUDFLARE_PLACEMENT_ID` (local development). `undefined`
|
|
1421
|
-
* when no handshake has been observed yet on this sandbox.
|
|
1422
|
-
*/
|
|
1423
|
-
getContainerPlacementId(): Promise<string | null | undefined>;
|
|
1424
|
-
createCodeContext(options?: CreateContextOptions): Promise<CodeContext>;
|
|
1425
|
-
runCode(code: string, options?: RunCodeOptions): Promise<ExecutionResult>;
|
|
1426
|
-
runCodeStream(code: string, options?: RunCodeOptions): Promise<ReadableStream>;
|
|
1427
|
-
listCodeContexts(): Promise<CodeContext[]>;
|
|
1428
|
-
deleteCodeContext(contextId: string): Promise<void>;
|
|
1429
|
-
createBackup(options: BackupOptions): Promise<DirectoryBackup>;
|
|
1430
|
-
restoreBackup(backup: DirectoryBackup): Promise<RestoreBackupResult>;
|
|
1431
|
-
wsConnect(request: Request, port: number): Promise<Response>;
|
|
1432
|
-
}
|
|
1433
|
-
declare function isExecResult(value: any): value is ExecResult;
|
|
1434
|
-
declare function isProcess(value: any): value is Process;
|
|
1435
|
-
declare function isProcessStatus(value: string): value is ProcessStatus;
|
|
1436
|
-
//#endregion
|
|
1437
|
-
//#region ../shared/dist/request-types.d.ts
|
|
1438
|
-
/**
|
|
1439
|
-
* Result for a single uploaded part (ETag returned by R2).
|
|
1440
|
-
*/
|
|
1441
|
-
interface UploadedPart {
|
|
1442
|
-
partNumber: number;
|
|
1443
|
-
etag: string;
|
|
1444
|
-
}
|
|
1445
|
-
/**
|
|
1446
|
-
* Response after the container has uploaded all parts.
|
|
1447
|
-
*/
|
|
1448
|
-
interface UploadPartsResponse {
|
|
1449
|
-
success: boolean;
|
|
1450
|
-
parts: UploadedPart[];
|
|
1451
|
-
}
|
|
1452
|
-
/**
|
|
1453
|
-
* Response from the container after creating a backup archive
|
|
1454
|
-
*/
|
|
1455
|
-
interface CreateBackupResponse {
|
|
1456
|
-
success: boolean;
|
|
1457
|
-
/** Size of the archive in bytes */
|
|
1458
|
-
sizeBytes: number;
|
|
1459
|
-
/** Path to the archive file in the container */
|
|
1460
|
-
archivePath: string;
|
|
1461
|
-
}
|
|
1462
|
-
/**
|
|
1463
|
-
* Response from the container after restoring a backup
|
|
1464
|
-
*/
|
|
1465
|
-
interface RestoreBackupResponse {
|
|
1466
|
-
success: boolean;
|
|
1467
|
-
/** Directory that was restored */
|
|
1468
|
-
dir: string;
|
|
1469
|
-
}
|
|
1470
|
-
//#endregion
|
|
1471
|
-
//#region ../shared/dist/rpc-types.d.ts
|
|
1472
|
-
interface SandboxCommandsAPI {
|
|
1473
|
-
execute(command: string, sessionId: string, options?: {
|
|
1474
|
-
timeoutMs?: number;
|
|
1475
|
-
env?: Record<string, string | undefined>;
|
|
1476
|
-
cwd?: string;
|
|
1477
|
-
origin?: 'user' | 'internal';
|
|
1478
|
-
}): Promise<{
|
|
1479
|
-
success: boolean;
|
|
1480
|
-
exitCode: number;
|
|
1481
|
-
stdout: string;
|
|
1482
|
-
stderr: string;
|
|
1483
|
-
command: string;
|
|
1484
|
-
timestamp: string;
|
|
1485
|
-
}>;
|
|
1486
|
-
executeStream(command: string, sessionId: string, options?: {
|
|
1487
|
-
timeoutMs?: number;
|
|
1488
|
-
env?: Record<string, string | undefined>;
|
|
1489
|
-
cwd?: string;
|
|
1490
|
-
origin?: 'user' | 'internal';
|
|
1491
|
-
}): Promise<ReadableStream<Uint8Array>>;
|
|
1492
|
-
}
|
|
1493
|
-
interface SandboxFilesAPI {
|
|
1494
|
-
readFile(path: string, sessionId: string, options: {
|
|
1495
|
-
encoding: 'none';
|
|
1496
|
-
}): Promise<ReadFileStreamResult>;
|
|
1497
|
-
readFile(path: string, sessionId: string, options?: {
|
|
1498
|
-
encoding?: Exclude<FileEncoding, 'none'>;
|
|
1499
|
-
}): Promise<ReadFileResult>;
|
|
1500
|
-
readFileStream(path: string, sessionId: string): Promise<ReadableStream<Uint8Array>>;
|
|
1501
|
-
writeFile(path: string, content: string, sessionId: string, options?: {
|
|
1502
|
-
encoding?: string;
|
|
1503
|
-
permissions?: string;
|
|
1504
|
-
}): Promise<WriteFileResult>;
|
|
1505
|
-
writeFileStream(path: string, stream: ReadableStream<Uint8Array>, sessionId: string): Promise<{
|
|
1506
|
-
success: boolean;
|
|
1507
|
-
path: string;
|
|
1508
|
-
bytesWritten: number;
|
|
1509
|
-
timestamp: string;
|
|
1510
|
-
}>;
|
|
1511
|
-
deleteFile(path: string, sessionId: string): Promise<DeleteFileResult>;
|
|
1512
|
-
renameFile(oldPath: string, newPath: string, sessionId: string): Promise<RenameFileResult>;
|
|
1513
|
-
moveFile(sourcePath: string, destinationPath: string, sessionId: string): Promise<MoveFileResult>;
|
|
1514
|
-
mkdir(path: string, sessionId: string, options?: {
|
|
1515
|
-
recursive?: boolean;
|
|
1516
|
-
}): Promise<MkdirResult>;
|
|
1517
|
-
listFiles(path: string, sessionId: string, options?: ListFilesOptions): Promise<ListFilesResult>;
|
|
1518
|
-
exists(path: string, sessionId: string): Promise<FileExistsResult>;
|
|
1519
|
-
}
|
|
1520
|
-
interface SandboxProcessesAPI {
|
|
1521
|
-
startProcess(command: string, sessionId: string, options?: {
|
|
1522
|
-
processId?: string;
|
|
1523
|
-
timeoutMs?: number;
|
|
1524
|
-
}): Promise<ProcessStartResult>;
|
|
1525
|
-
listProcesses(): Promise<ProcessListResult>;
|
|
1526
|
-
getProcess(id: string): Promise<ProcessInfoResult>;
|
|
1527
|
-
killProcess(id: string): Promise<ProcessKillResult>;
|
|
1528
|
-
killAllProcesses(): Promise<ProcessCleanupResult>;
|
|
1529
|
-
getProcessLogs(id: string): Promise<ProcessLogsResult>;
|
|
1530
|
-
streamProcessLogs(id: string): Promise<ReadableStream<Uint8Array>>;
|
|
1531
|
-
}
|
|
1532
|
-
interface SandboxPortsAPI {
|
|
1533
|
-
watchPort(request: PortWatchRequest): Promise<ReadableStream<Uint8Array>>;
|
|
1534
|
-
}
|
|
1535
|
-
interface SandboxGitAPI {
|
|
1536
|
-
checkout(repoUrl: string, sessionId: string, options?: {
|
|
1537
|
-
branch?: string;
|
|
1538
|
-
targetDir?: string;
|
|
1539
|
-
depth?: number;
|
|
1540
|
-
timeoutMs?: number;
|
|
1541
|
-
}): Promise<GitCheckoutResult>;
|
|
1542
|
-
}
|
|
1543
|
-
interface SandboxInterpreterAPI {
|
|
1544
|
-
createCodeContext(options?: CreateContextOptions): Promise<CodeContext>;
|
|
1545
|
-
streamCode(contextId: string, code: string, language?: string): Promise<ReadableStream<Uint8Array>>;
|
|
1546
|
-
runCodeStream(contextId: string | undefined, code: string, language: string | undefined, callbacks: {
|
|
1547
|
-
onStdout?: (output: OutputMessage) => void | Promise<void>;
|
|
1548
|
-
onStderr?: (output: OutputMessage) => void | Promise<void>;
|
|
1549
|
-
onResult?: (result: Result) => void | Promise<void>;
|
|
1550
|
-
onError?: (error: ExecutionError) => void | Promise<void>;
|
|
1551
|
-
}, timeoutMs?: number): Promise<void>;
|
|
1552
|
-
listCodeContexts(): Promise<CodeContext[]>;
|
|
1553
|
-
deleteCodeContext(contextId: string): Promise<void>;
|
|
1554
|
-
}
|
|
1555
|
-
interface SandboxUtilsAPI {
|
|
1556
|
-
ping(): Promise<string>;
|
|
1557
|
-
getVersion(): Promise<string>;
|
|
1558
|
-
getCommands(): Promise<string[]>;
|
|
1559
|
-
createSession(options: {
|
|
1560
|
-
id: string;
|
|
1561
|
-
env?: Record<string, string | undefined>;
|
|
1562
|
-
cwd?: string;
|
|
1563
|
-
}): Promise<{
|
|
1564
|
-
success: boolean;
|
|
1565
|
-
id: string;
|
|
1566
|
-
message: string;
|
|
1567
|
-
timestamp: string;
|
|
1568
|
-
containerPlacementId?: string | null;
|
|
1569
|
-
}>;
|
|
1570
|
-
deleteSession(sessionId: string): Promise<{
|
|
1571
|
-
success: boolean;
|
|
1572
|
-
sessionId: string;
|
|
1573
|
-
timestamp: string;
|
|
1574
|
-
}>;
|
|
1575
|
-
listSessions(): Promise<{
|
|
1576
|
-
sessions: string[];
|
|
1577
|
-
}>;
|
|
1578
|
-
}
|
|
1579
|
-
interface SandboxBackupAPI {
|
|
1580
|
-
createArchive(dir: string, archivePath: string, sessionId: string, options?: {
|
|
1581
|
-
excludes?: string[];
|
|
1582
|
-
gitignore?: boolean;
|
|
1583
|
-
compression?: BackupCompressionOptions;
|
|
1584
|
-
}): Promise<CreateBackupResponse>;
|
|
1585
|
-
restoreArchive(dir: string, archivePath: string, sessionId: string): Promise<RestoreBackupResponse>;
|
|
1586
|
-
uploadParts(request: {
|
|
1587
|
-
archivePath: string;
|
|
1588
|
-
parts: Array<{
|
|
1589
|
-
partNumber: number;
|
|
1590
|
-
url: string;
|
|
1591
|
-
offset: number;
|
|
1592
|
-
size: number;
|
|
1593
|
-
}>;
|
|
1594
|
-
sessionId?: string;
|
|
1595
|
-
}): Promise<UploadPartsResponse>;
|
|
1596
|
-
}
|
|
1597
|
-
interface SandboxWatchAPI {
|
|
1598
|
-
watch(request: WatchRequest): Promise<ReadableStream<Uint8Array>>;
|
|
1599
|
-
checkChanges(request: CheckChangesRequest): Promise<CheckChangesResult>;
|
|
1600
|
-
}
|
|
1601
|
-
/**
|
|
1602
|
-
* Public-facing tunnel record. Discriminated on the presence of `name`:
|
|
1603
|
-
* quick tunnels (`*.trycloudflare.com`) omit it, named tunnels carry the
|
|
1604
|
-
* label that was passed to `get(port, { name })`.
|
|
1605
|
-
*/
|
|
1606
|
-
type TunnelInfo = QuickTunnelInfo | NamedTunnelInfo;
|
|
1607
|
-
interface QuickTunnelInfo {
|
|
1608
|
-
id: string;
|
|
1609
|
-
port: number;
|
|
1610
|
-
/** `https://<random>.trycloudflare.com`. */
|
|
1611
|
-
url: string;
|
|
1612
|
-
/** Hostname portion of `url`. */
|
|
1613
|
-
hostname: string;
|
|
1614
|
-
createdAt: string;
|
|
1615
|
-
/** Absent on quick tunnels; narrows the union. */
|
|
1616
|
-
name?: never;
|
|
1617
|
-
}
|
|
1618
|
-
interface NamedTunnelInfo {
|
|
1619
|
-
/** Cloudflare tunnel UUID (8-4-4-4-12). */
|
|
1620
|
-
id: string;
|
|
1621
|
-
port: number;
|
|
1622
|
-
/** `https://<hostname>`. */
|
|
1623
|
-
url: string;
|
|
1624
|
-
/** Full hostname bound to the tunnel (without scheme). */
|
|
1625
|
-
hostname: string;
|
|
1626
|
-
createdAt: string;
|
|
1627
|
-
/** Label originally passed via `TunnelOptions.name`. */
|
|
1628
|
-
name: string;
|
|
1629
|
-
}
|
|
1630
|
-
/**
|
|
1631
|
-
* Options accepted by `sandbox.tunnels.get(port, options)`. Omitting
|
|
1632
|
-
* `name` (or omitting the options object) selects the zero-config quick
|
|
1633
|
-
* tunnel; setting `name` selects the named-tunnel flow.
|
|
1634
|
-
*/
|
|
1635
|
-
interface TunnelOptions {
|
|
1636
|
-
/**
|
|
1637
|
-
* Single DNS label under the configured zone. The full hostname is
|
|
1638
|
-
* `<name>.<zone-name>`. See `validateTunnelName` for the format rules.
|
|
1639
|
-
*/
|
|
1640
|
-
name?: string;
|
|
1641
|
-
}
|
|
1642
|
-
interface SandboxTunnelsAPI {
|
|
1643
|
-
/** Spawn `cloudflared tunnel --url`. No credentials required. */
|
|
1644
|
-
runQuickTunnel(id: string, port: number): Promise<TunnelInfo>;
|
|
1645
|
-
/**
|
|
1646
|
-
* Spawn `cloudflared tunnel run --token <token> --url http://localhost:<port>`.
|
|
1647
|
-
*
|
|
1648
|
-
* The SDK is the source of truth for the hostname this tunnel binds to;
|
|
1649
|
-
* the container only sees the opaque token and the local port. The
|
|
1650
|
-
* returned `TunnelInfo` carries empty `url`/`hostname` fields — the SDK
|
|
1651
|
-
* enriches them with the values from the Cloudflare API before handing
|
|
1652
|
-
* the record to user code.
|
|
1653
|
-
*
|
|
1654
|
-
* The token must never be logged, persisted, or echoed back to callers.
|
|
1655
|
-
*/
|
|
1656
|
-
runNamedTunnel(id: string, token: string, port: number): Promise<TunnelInfo>;
|
|
1657
|
-
/** Stop the cloudflared process for the given tunnel id. */
|
|
1658
|
-
destroyTunnel(id: string): Promise<{
|
|
1659
|
-
success: true;
|
|
1660
|
-
id: string;
|
|
1661
|
-
}>;
|
|
1662
|
-
/** List tunnels currently running inside the container. */
|
|
1663
|
-
listTunnels(): Promise<TunnelInfo[]>;
|
|
1664
|
-
}
|
|
1665
|
-
/**
|
|
1666
|
-
* RPC surface the Sandbox DO exposes to the container over the existing
|
|
1667
|
-
* capnweb session. The container reaches it via
|
|
1668
|
-
* `session.getRemoteMain<SandboxControlCallback>()` and invokes methods
|
|
1669
|
-
* to push control-plane events (today: tunnel exits) back to the DO.
|
|
1670
|
-
*
|
|
1671
|
-
* One stable target per sandbox; not per-tunnel. Reusable seam for
|
|
1672
|
-
* future container→DO events.
|
|
1673
|
-
*/
|
|
1674
|
-
interface SandboxControlCallback {
|
|
1675
|
-
/**
|
|
1676
|
-
* Called by the container when a `cloudflared` process exits for any
|
|
1677
|
-
* reason — SIGTERM from `destroyTunnel`, container-initiated SIGKILL,
|
|
1678
|
-
* network failure, segfault. `exitCode` is `null` if the process was
|
|
1679
|
-
* signalled rather than exited cleanly.
|
|
1680
|
-
*/
|
|
1681
|
-
onTunnelExit(id: string, port: number, exitCode: number | null): Promise<void>;
|
|
1682
|
-
}
|
|
1683
|
-
//#endregion
|
|
1684
|
-
//#region src/container-control/connection.d.ts
|
|
1685
|
-
/** Stub that can issue a WebSocket-upgrade fetch through the DO's Container base class. */
|
|
1686
|
-
interface ContainerFetchStub {
|
|
1687
|
-
fetch(request: Request): Promise<Response>;
|
|
1688
|
-
}
|
|
1689
|
-
interface ContainerControlConnectionOptions {
|
|
1690
|
-
stub: ContainerFetchStub;
|
|
1691
|
-
port?: number;
|
|
1692
|
-
logger?: Logger;
|
|
1693
|
-
/**
|
|
1694
|
-
* Total retry budget (ms) for retryable upgrade responses while the
|
|
1695
|
-
* container is unavailable. Defaults to 120 000 (2 minutes). Set to 0 to
|
|
1696
|
-
* disable retries.
|
|
1697
|
-
*/
|
|
1698
|
-
retryTimeoutMs?: number;
|
|
1699
|
-
/**
|
|
1700
|
-
* Optional `localMain` exposed to the container side of the capnweb
|
|
1701
|
-
* session. The container reaches it via
|
|
1702
|
-
* `session.getRemoteMain()` and uses it for control-plane callbacks
|
|
1703
|
-
* (e.g. notifying the DO when a tunnel's cloudflared process has
|
|
1704
|
-
* exited). When omitted, the container sees an empty remote main.
|
|
1705
|
-
*/
|
|
1706
|
-
localMain?: SandboxControlCallback & RpcTarget;
|
|
1707
|
-
/**
|
|
1708
|
-
* Invoked when an active WebSocket transitions to closed/errored.
|
|
1709
|
-
* Fired at most once per successful connection from the WS event
|
|
1710
|
-
* handlers in `doConnect`. Gives owners a synchronous teardown
|
|
1711
|
-
* signal so recovery doesn't depend on a periodic poller running
|
|
1712
|
-
* inside what may be an idle isolate.
|
|
1713
|
-
*
|
|
1714
|
-
* Also fired for `doConnect` failures after the deferred transport is
|
|
1715
|
-
* aborted. A failed upgrade poisons the transport, so owners must discard
|
|
1716
|
-
* the connection and create a fresh one for subsequent calls. Not fired for
|
|
1717
|
-
* `disconnect()`.
|
|
1718
|
-
*/
|
|
1719
|
-
onClose?: () => void;
|
|
1720
|
-
}
|
|
1721
|
-
//#endregion
|
|
1722
|
-
//#region src/container-control/client.d.ts
|
|
1723
|
-
interface ContainerControlClientOptions extends ContainerControlConnectionOptions {
|
|
1724
|
-
/** Idle timeout before disconnecting the WebSocket (ms). Defaults to 1 000. */
|
|
1725
|
-
idleDisconnectMs?: number;
|
|
1726
|
-
/** Busy/idle poll interval (ms). Defaults to 1 000. */
|
|
1727
|
-
busyPollIntervalMs?: number;
|
|
1728
|
-
/**
|
|
1729
|
-
* Renew the DO's activity timeout. Fires at the start of every RPC call
|
|
1730
|
-
* and on every busy-poll tick while the session has work in flight.
|
|
1731
|
-
* Mirrors what `containerFetch()` does at the top of each HTTP request.
|
|
1732
|
-
*/
|
|
1733
|
-
onActivity?: () => void;
|
|
1734
|
-
/**
|
|
1735
|
-
* Fires once when the capnweb session transitions from idle to busy
|
|
1736
|
-
* (an RPC call was started or a stream return is now in flight). The
|
|
1737
|
-
* Sandbox DO wires this to increment the Container base class's
|
|
1738
|
-
* in-flight request counter, which makes `isActivityExpired()` skip the
|
|
1739
|
-
* sleepAfter comparison.
|
|
1740
|
-
*/
|
|
1741
|
-
onSessionBusy?: () => void;
|
|
1742
|
-
/**
|
|
1743
|
-
* Fires once when the session transitions from busy back to idle
|
|
1744
|
-
* (all RPC promises settled and all stream exports released). The
|
|
1745
|
-
* Sandbox DO wires this to `inflightRequests = max(0, n-1)` and a
|
|
1746
|
-
* final `renewActivityTimeout()`, matching containerFetch's finally
|
|
1747
|
-
* block.
|
|
1748
|
-
*/
|
|
1749
|
-
onSessionIdle?: () => void;
|
|
1750
|
-
}
|
|
1751
|
-
/**
|
|
1752
|
-
* Sandbox control facade backed by direct capnweb RPC.
|
|
1753
|
-
*
|
|
1754
|
-
* All operations call the container's SandboxAPI control interface directly
|
|
1755
|
-
* over capnweb, bypassing the HTTP handler/router layer entirely.
|
|
1756
|
-
*
|
|
1757
|
-
* Manages its own WebSocket lifecycle: a fresh `ContainerControlConnection` is
|
|
1758
|
-
* created on demand and torn down after `idleDisconnectMs` of inactivity.
|
|
1759
|
-
* Busy/idle detection relies on `RpcSession.getStats()` which tracks all
|
|
1760
|
-
* in-flight RPC calls and stream exports — including long-lived streaming
|
|
1761
|
-
* RPCs that would be invisible to a simple per-call request counter (see
|
|
1762
|
-
* the file-level comment for the full rationale).
|
|
1763
|
-
*/
|
|
1764
|
-
declare class ContainerControlClient {
|
|
1765
|
-
private readonly connOptions;
|
|
1766
|
-
private readonly idleDisconnectMs;
|
|
1767
|
-
private readonly busyPollIntervalMs;
|
|
1768
|
-
private readonly logger;
|
|
1769
|
-
private readonly onActivity;
|
|
1770
|
-
private readonly onSessionBusy;
|
|
1771
|
-
private readonly onSessionIdle;
|
|
1772
|
-
private conn;
|
|
1773
|
-
private idleTimer;
|
|
1774
|
-
private busyPollTimer;
|
|
1775
|
-
/** Tracks whether we currently believe the session is busy. */
|
|
1776
|
-
private busy;
|
|
1777
|
-
constructor(options: ContainerControlClientOptions);
|
|
1778
|
-
/**
|
|
1779
|
-
* Return the current connection, creating one when the client is disconnected.
|
|
1780
|
-
* Starts the busy-poll timer the first time a connection is materialized.
|
|
1781
|
-
*/
|
|
1782
|
-
private getConnection;
|
|
1783
|
-
/**
|
|
1784
|
-
* Called synchronously at the start of each RPC method invocation.
|
|
1785
|
-
* Renews the DO activity timeout so the sleepAfter alarm is pushed
|
|
1786
|
-
* forward before the container processes the call.
|
|
1787
|
-
*/
|
|
1788
|
-
private renewActivity;
|
|
1789
|
-
/**
|
|
1790
|
-
* Sample `getStats()` and update busy/idle state. While busy, renews the
|
|
1791
|
-
* activity timeout each tick so an in-flight stream keeps pushing the
|
|
1792
|
-
* sleepAfter deadline forward. On the busy → idle edge, fires
|
|
1793
|
-
* `onSessionIdle` and schedules the WebSocket disconnect.
|
|
1794
|
-
*
|
|
1795
|
-
* If the WebSocket has dropped underneath us (container crash, network
|
|
1796
|
-
* blip) we tear the connection down here. `destroyConnection()` fires
|
|
1797
|
-
* `onSessionIdle` if we were busy, so the DO's inflight counter doesn't
|
|
1798
|
-
* stay pinned forever waiting for a peer that's never going to reply.
|
|
1799
|
-
*/
|
|
1800
|
-
private pollBusyState;
|
|
1801
|
-
private startBusyPoll;
|
|
1802
|
-
private stopBusyPoll;
|
|
1803
|
-
private scheduleIdleDisconnect;
|
|
1804
|
-
private clearIdleTimer;
|
|
1805
|
-
private destroyConnection;
|
|
1806
|
-
get commands(): SandboxCommandsAPI;
|
|
1807
|
-
get files(): SandboxFilesAPI;
|
|
1808
|
-
get processes(): SandboxProcessesAPI;
|
|
1809
|
-
get ports(): SandboxPortsAPI;
|
|
1810
|
-
get git(): SandboxGitAPI;
|
|
1811
|
-
get utils(): SandboxUtilsAPI;
|
|
1812
|
-
get backup(): SandboxBackupAPI;
|
|
1813
|
-
get watch(): SandboxWatchAPI;
|
|
1814
|
-
get tunnels(): SandboxTunnelsAPI;
|
|
1815
|
-
get interpreter(): SandboxInterpreterAPI;
|
|
1816
|
-
/**
|
|
1817
|
-
* Update the upgrade retry budget. Applies to the current connection
|
|
1818
|
-
* (if any) and is remembered for any future connections created after the
|
|
1819
|
-
* client is torn down and reconnected.
|
|
1820
|
-
*/
|
|
1821
|
-
setRetryTimeoutMs(ms: number): void;
|
|
1822
|
-
isWebSocketConnected(): boolean;
|
|
1823
|
-
connect(): Promise<void>;
|
|
1824
|
-
disconnect(): void;
|
|
1825
|
-
}
|
|
1826
|
-
//#endregion
|
|
1827
|
-
//#region src/tunnels/tunnels-handler.d.ts
|
|
1828
|
-
interface TunnelsHandler {
|
|
1829
|
-
get(port: number, options?: TunnelOptions): Promise<TunnelInfo>;
|
|
1830
|
-
list(): Promise<TunnelInfo[]>;
|
|
1831
|
-
destroy(portOrInfo: number | TunnelInfo): Promise<void>;
|
|
1832
|
-
}
|
|
1833
|
-
//#endregion
|
|
1834
|
-
//#region src/sandbox.d.ts
|
|
1835
|
-
type SandboxConfiguration = {
|
|
1836
|
-
sandboxName?: {
|
|
1837
|
-
name: string;
|
|
1838
|
-
normalizeId?: boolean;
|
|
1839
|
-
};
|
|
1840
|
-
sleepAfter?: string | number;
|
|
1841
|
-
keepAlive?: boolean;
|
|
1842
|
-
containerTimeouts?: NonNullable<SandboxOptions['containerTimeouts']>;
|
|
1843
|
-
};
|
|
1844
|
-
/**
|
|
1845
|
-
* SDK-level ContainerProxy that directly dispatches SDK-internal mount hosts
|
|
1846
|
-
* (r2.internal, s3-credential-proxy.internal) without relying on
|
|
1847
|
-
* outboundHandlersRegistry lookups, which are NOT shared between the Durable
|
|
1848
|
-
* Object's execution context and the ContainerProxy WorkerEntrypoint context.
|
|
1849
|
-
*
|
|
1850
|
-
* Users must export this class from their Worker entrypoint so the Sandbox DO
|
|
1851
|
-
* can create outbound-interception fetchers that reference it.
|
|
1852
|
-
*/
|
|
1853
|
-
declare class ContainerProxy$1 extends ContainerProxy {
|
|
1854
|
-
fetch(request: Request): Promise<Response>;
|
|
1855
|
-
}
|
|
1856
|
-
declare function getSandbox<T extends Sandbox<any>>(ns: DurableObjectNamespace<T>, id: string, options?: SandboxOptions): T;
|
|
1857
|
-
declare class Sandbox<Env = unknown> extends Container<Env> implements ISandbox {
|
|
1858
|
-
defaultPort: number;
|
|
1859
|
-
sleepAfter: string | number;
|
|
1860
|
-
client: ContainerControlClient;
|
|
1861
|
-
private codeInterpreter;
|
|
1862
|
-
private sandboxName;
|
|
1863
|
-
private tunnelsHandler;
|
|
1864
|
-
private tunnelExitHandler;
|
|
1865
|
-
private destroyAllTunnels;
|
|
1866
|
-
private readonly controlCallback;
|
|
1867
|
-
private normalizeId;
|
|
1868
|
-
private defaultSession;
|
|
1869
|
-
private containerGeneration;
|
|
1870
|
-
private defaultSessionInit;
|
|
1871
|
-
envVars: Record<string, string>;
|
|
1872
|
-
private logger;
|
|
1873
|
-
private keepAliveEnabled;
|
|
1874
|
-
private activeMounts;
|
|
1875
|
-
private mountOperationQueue;
|
|
1876
|
-
private currentRuntime;
|
|
1877
|
-
private backupBucket;
|
|
1878
|
-
/**
|
|
1879
|
-
* Serializes backup operations to prevent concurrent create/restore on the same sandbox.
|
|
1880
|
-
*
|
|
1881
|
-
* This is in-memory state — it resets if the Durable Object is evicted and
|
|
1882
|
-
* re-instantiated (e.g. after sleep). This is acceptable because the container
|
|
1883
|
-
* filesystem is also lost on eviction, so there is no archive to race on.
|
|
1884
|
-
*/
|
|
1885
|
-
private backupInProgress;
|
|
1886
|
-
/**
|
|
1887
|
-
* R2 presigned URL credentials for direct container-to-R2 transfers.
|
|
1888
|
-
* All four fields plus the R2 binding must be configured for backup to work.
|
|
1889
|
-
*/
|
|
1890
|
-
private r2AccessKeyId;
|
|
1891
|
-
private r2SecretAccessKey;
|
|
1892
|
-
private r2AccountId;
|
|
1893
|
-
private backupBucketName;
|
|
1894
|
-
private backupBucketEndpoint;
|
|
1895
|
-
private r2Client;
|
|
1896
|
-
/**
|
|
1897
|
-
* Lazily-resolved Cloudflare account id for named-tunnel provisioning.
|
|
1898
|
-
* Resolved on first access via `tunnels/credentials.ts` and cached for
|
|
1899
|
-
* the lifetime of this DO instance. See the credentials helper for
|
|
1900
|
-
* the precedence chain.
|
|
1901
|
-
*/
|
|
1902
|
-
private tunnelAccountIdPromise;
|
|
1903
|
-
/**
|
|
1904
|
-
* Lazily-resolved Cloudflare zone id for named-tunnel provisioning.
|
|
1905
|
-
* Falls back to the single zone the token can see under the resolved
|
|
1906
|
-
* account id when `CLOUDFLARE_ZONE_ID` is not set. Cached for the
|
|
1907
|
-
* lifetime of this DO instance.
|
|
1908
|
-
*/
|
|
1909
|
-
private tunnelZoneIdPromise;
|
|
1910
|
-
/**
|
|
1911
|
-
* Default container startup timeouts (conservative for production)
|
|
1912
|
-
* Based on Cloudflare docs: "Containers take several minutes to provision"
|
|
1913
|
-
*/
|
|
1914
|
-
private readonly DEFAULT_CONTAINER_TIMEOUTS;
|
|
1915
|
-
/**
|
|
1916
|
-
* Active container timeout configuration
|
|
1917
|
-
* Can be set via options, env vars, or defaults
|
|
1918
|
-
*/
|
|
1919
|
-
private containerTimeouts;
|
|
1920
|
-
/**
|
|
1921
|
-
* True once containerTimeouts has been written to storage at least once
|
|
1922
|
-
* (either via setContainerTimeouts or restored on cold start). Gates the
|
|
1923
|
-
* idempotency check in setContainerTimeouts so a first explicit call
|
|
1924
|
-
* persists even when the requested values already equal the in-memory
|
|
1925
|
-
* defaults, distinguishing "user intent recorded" from "running on
|
|
1926
|
-
* env/SDK defaults".
|
|
1927
|
-
*/
|
|
1928
|
-
private hasStoredContainerTimeouts;
|
|
1929
|
-
/**
|
|
1930
|
-
* Dispatch method for tunnel operations.
|
|
1931
|
-
* Called by the client-side proxy created in getSandbox() to provide
|
|
1932
|
-
* the `sandbox.tunnels` API without relying on RPC pipelining
|
|
1933
|
-
* through property getters which is broken when using vite-plugin.
|
|
1934
|
-
*/
|
|
1935
|
-
callTunnels(method: string, args: unknown[]): Promise<unknown>;
|
|
1936
|
-
/**
|
|
1937
|
-
* Compute the control-channel upgrade retry budget from current container
|
|
1938
|
-
* timeouts.
|
|
1939
|
-
*
|
|
1940
|
-
* The budget covers the full container startup window (instance provisioning
|
|
1941
|
-
* + port readiness) plus a 30s margin for the maximum single backoff delay.
|
|
1942
|
-
* The 120s floor preserves the default for short timeout configurations.
|
|
1943
|
-
*/
|
|
1944
|
-
private computeRetryTimeoutMs;
|
|
1945
|
-
/**
|
|
1946
|
-
* Create the single control-plane client used for all SDK operations.
|
|
1947
|
-
*/
|
|
1948
|
-
private createClient;
|
|
1949
|
-
constructor(ctx: DurableObjectState<{}>, env: Env);
|
|
1950
|
-
setSandboxName(name: string, normalizeId?: boolean): Promise<void>;
|
|
1951
|
-
configure(configuration: SandboxConfiguration): Promise<void>;
|
|
1952
|
-
setSleepAfter(sleepAfter: string | number): Promise<void>;
|
|
1953
|
-
setKeepAlive(keepAlive: boolean): Promise<void>;
|
|
1954
|
-
setEnvVars(envVars: Record<string, string | undefined>): Promise<void>;
|
|
1955
|
-
setContainerTimeouts(timeouts: NonNullable<SandboxOptions['containerTimeouts']>): Promise<void>;
|
|
1956
|
-
private validateTimeout;
|
|
1957
|
-
private getDefaultTimeouts;
|
|
1958
|
-
/**
|
|
1959
|
-
* Mount an S3-compatible bucket as a local directory.
|
|
1960
|
-
*
|
|
1961
|
-
* Requires explicit endpoint URL for production. Credentials are auto-detected from environment
|
|
1962
|
-
* variables or can be provided explicitly.
|
|
1963
|
-
*
|
|
1964
|
-
* @param bucket - Bucket name (or R2 binding name when localBucket is true)
|
|
1965
|
-
* @param mountPath - Absolute path in container to mount at
|
|
1966
|
-
* @param options - Mount configuration
|
|
1967
|
-
* @throws MissingCredentialsError if no credentials found in environment
|
|
1968
|
-
* @throws S3FSMountError if S3FS mount command fails
|
|
1969
|
-
* @throws InvalidMountConfigError if bucket name, mount path, or endpoint is invalid
|
|
1970
|
-
*/
|
|
1971
|
-
mountBucket(bucket: string, mountPath: string, options: MountBucketOptions): Promise<void>;
|
|
1972
|
-
private runMountOperation;
|
|
1973
|
-
private mountBucketUnlocked;
|
|
1974
|
-
/**
|
|
1975
|
-
* Local dev mount: bidirectional sync via R2 binding + file/watch APIs
|
|
1976
|
-
*/
|
|
1977
|
-
private mountBucketLocal;
|
|
1978
|
-
private getR2EgressParams;
|
|
1979
|
-
private validateProtectedS3fsOptions;
|
|
1980
|
-
private getS3CredentialProxyParams;
|
|
1981
|
-
private resolveCredentialProxyAuthStrategy;
|
|
1982
|
-
/**
|
|
1983
|
-
* Credential-less R2 mount: egress interception routes s3fs requests to the
|
|
1984
|
-
* R2 binding. No S3 credentials are needed in the container or Worker env.
|
|
1985
|
-
*/
|
|
1986
|
-
private mountBucketR2Egress;
|
|
1987
|
-
/**
|
|
1988
|
-
* Production mount: S3FS-FUSE inside the container
|
|
1989
|
-
*/
|
|
1990
|
-
private mountBucketFuse;
|
|
1991
|
-
/**
|
|
1992
|
-
* Manually unmount a bucket filesystem
|
|
1993
|
-
*
|
|
1994
|
-
* @param mountPath - Absolute path where the bucket is mounted
|
|
1995
|
-
* @throws InvalidMountConfigError if mount path doesn't exist or isn't mounted
|
|
1996
|
-
*/
|
|
1997
|
-
unmountBucket(mountPath: string): Promise<void>;
|
|
1998
|
-
private unmountBucketUnlocked;
|
|
1999
|
-
/**
|
|
2000
|
-
* Shared validation for mount path (absolute, not already in use).
|
|
2001
|
-
*/
|
|
2002
|
-
private validateMountPath;
|
|
2003
|
-
/**
|
|
2004
|
-
* Validate mount options for remote (FUSE) mounts
|
|
2005
|
-
*/
|
|
2006
|
-
private validateMountOptions;
|
|
2007
|
-
/**
|
|
2008
|
-
* Generate unique password file path for s3fs credentials
|
|
2009
|
-
*/
|
|
2010
|
-
private generatePasswordFilePath;
|
|
2011
|
-
/**
|
|
2012
|
-
* Generate unique ahbe_conf file path for s3fs additional header config
|
|
2013
|
-
*/
|
|
2014
|
-
private generateS3FSAdditionalHeaderFilePath;
|
|
2015
|
-
/**
|
|
2016
|
-
* Create s3fs ahbe_conf file that suppresses the Expect: 100-continue header.
|
|
2017
|
-
* Restricted to 0600 so s3fs will accept it (same requirement as passwd files).
|
|
2018
|
-
*/
|
|
2019
|
-
private createDisableExpectHeaderFile;
|
|
2020
|
-
/**
|
|
2021
|
-
* Create password file with s3fs credentials
|
|
2022
|
-
* Format: bucket:accessKeyId:secretAccessKey
|
|
2023
|
-
*/
|
|
2024
|
-
private createPasswordFile;
|
|
2025
|
-
/**
|
|
2026
|
-
* Delete password file
|
|
2027
|
-
*/
|
|
2028
|
-
private deletePasswordFile;
|
|
2029
|
-
private deleteAdditionalHeaderFile;
|
|
2030
|
-
/**
|
|
2031
|
-
* Execute S3FS mount command
|
|
2032
|
-
*/
|
|
2033
|
-
private executeS3FSMount;
|
|
2034
|
-
private unmountTrackedFuseMount;
|
|
2035
|
-
/**
|
|
2036
|
-
* In-flight `destroy()` promise. While set, concurrent callers coalesce
|
|
2037
|
-
* onto the same teardown instead of triggering a second one. Cleared when
|
|
2038
|
-
* the underlying work settles, so a later call that genuinely needs to
|
|
2039
|
-
* recreate a destroyed sandbox still runs.
|
|
2040
|
-
*
|
|
2041
|
-
* If the underlying teardown hangs (e.g. `super.destroy()` never resolves
|
|
2042
|
-
* because the Containers control plane is unresponsive), every coalesced
|
|
2043
|
-
* caller hangs on the same promise until the Durable Object is evicted.
|
|
2044
|
-
* This is deliberate: a second concurrent teardown would not make a stuck
|
|
2045
|
-
* control plane unstuck, and spawning one would defeat the point of
|
|
2046
|
-
* coalescing. Callers that need bounded waits must apply their own
|
|
2047
|
-
* timeout around `destroy()`.
|
|
2048
|
-
*/
|
|
2049
|
-
private inflightDestroy;
|
|
2050
|
-
/**
|
|
2051
|
-
* Cleanup and destroy the sandbox container.
|
|
2052
|
-
*
|
|
2053
|
-
* Concurrent calls coalesce: if a previous `destroy()` is still in flight,
|
|
2054
|
-
* subsequent calls await the same underlying work instead of starting a
|
|
2055
|
-
* second teardown. A canonical `sandbox.destroy.coalesced` event is logged
|
|
2056
|
-
* per coalesced call so repeated destroy traffic is observable.
|
|
2057
|
-
*/
|
|
2058
|
-
destroy(): Promise<void>;
|
|
2059
|
-
private doDestroy;
|
|
2060
|
-
onStart(): Promise<void>;
|
|
2061
|
-
stop(signal?: Parameters<Container<Env>['stop']>[0]): Promise<void>;
|
|
2062
|
-
/**
|
|
2063
|
-
* Read the `portTokens` map from DO storage, normalizing the legacy
|
|
2064
|
-
* string-valued format (just a token) to the current object format
|
|
2065
|
-
* ({ token, name? }). The legacy format predates port-name persistence and
|
|
2066
|
-
* can appear on any DO whose storage was written before that change.
|
|
2067
|
-
*/
|
|
2068
|
-
private readPortTokens;
|
|
2069
|
-
private readActivePreviewPorts;
|
|
2070
|
-
private writeActivePreviewPorts;
|
|
2071
|
-
private readPreviewState;
|
|
2072
|
-
private clearActivePreviewPorts;
|
|
2073
|
-
/**
|
|
2074
|
-
* Check if the container version matches the SDK version
|
|
2075
|
-
* Logs a warning if there's a mismatch
|
|
2076
|
-
*/
|
|
2077
|
-
private checkVersionCompatibility;
|
|
2078
|
-
onStop(): Promise<void>;
|
|
2079
|
-
onError(error: unknown): void;
|
|
2080
|
-
/**
|
|
2081
|
-
* Override Container.containerFetch to use production-friendly timeouts
|
|
2082
|
-
* Automatically starts container with longer timeouts if not running
|
|
2083
|
-
*/
|
|
2084
|
-
containerFetch(requestOrUrl: Request | string | URL, portOrInit?: number | RequestInit, portParam?: number): Promise<Response>;
|
|
2085
|
-
/**
|
|
2086
|
-
* Helper: Check if error is "no container instance available"
|
|
2087
|
-
* This indicates the container VM is still being provisioned.
|
|
2088
|
-
*/
|
|
2089
|
-
private isNoInstanceError;
|
|
2090
|
-
/**
|
|
2091
|
-
* Helper: Check if error is a transient startup error that should trigger retry
|
|
2092
|
-
*
|
|
2093
|
-
* These errors occur during normal container startup and are recoverable:
|
|
2094
|
-
* - Port not yet mapped (container starting, app not listening yet)
|
|
2095
|
-
* - Connection refused (port mapped but app not ready)
|
|
2096
|
-
* - Timeouts during startup (recoverable with retry)
|
|
2097
|
-
* - Network transients (temporary connectivity issues)
|
|
2098
|
-
*
|
|
2099
|
-
* Errors NOT included (permanent failures):
|
|
2100
|
-
* - "no such image" - missing Docker image
|
|
2101
|
-
* - "container already exists" - name collision
|
|
2102
|
-
* - Configuration errors
|
|
2103
|
-
*/
|
|
2104
|
-
private isTransientStartupError;
|
|
2105
|
-
/**
|
|
2106
|
-
* Helper: Check if error is a permanent startup failure that will never recover
|
|
2107
|
-
*
|
|
2108
|
-
* These errors indicate resource exhaustion, misconfiguration, or missing images.
|
|
2109
|
-
* Retrying will never succeed, so the SDK should fail fast with HTTP 500.
|
|
2110
|
-
*
|
|
2111
|
-
* Error sources (traced from platform internals):
|
|
2112
|
-
* - Container runtime: OOM, PID limit
|
|
2113
|
-
* - Scheduling/provisioning: no matching app, no namespace configured
|
|
2114
|
-
* - workerd container-client.c++: no such image
|
|
2115
|
-
* - @cloudflare/containers: did not call start
|
|
2116
|
-
*/
|
|
2117
|
-
private isPermanentStartupError;
|
|
2118
|
-
/**
|
|
2119
|
-
* Helper: Parse containerFetch arguments (supports multiple signatures)
|
|
2120
|
-
*/
|
|
2121
|
-
private parseContainerFetchArgs;
|
|
2122
|
-
/**
|
|
2123
|
-
* Override onActivityExpired to prevent automatic shutdown when keepAlive is enabled
|
|
2124
|
-
* When keepAlive is disabled, calls parent implementation which stops the container
|
|
2125
|
-
*/
|
|
2126
|
-
onActivityExpired(): Promise<void>;
|
|
2127
|
-
private isPreviewProxyRequest;
|
|
2128
|
-
private invalidPreviewTokenResponse;
|
|
2129
|
-
private stalePreviewURLResponse;
|
|
2130
|
-
private getPreviewForwardingContainer;
|
|
2131
|
-
private beginPreviewForward;
|
|
2132
|
-
private fetchPreviewIfRunning;
|
|
2133
|
-
private buildPreviewProxyRequest;
|
|
2134
|
-
private proxyPreviewRequest;
|
|
2135
|
-
fetch(request: Request): Promise<Response>;
|
|
2136
|
-
wsConnect(request: Request, port: number): Promise<Response>;
|
|
2137
|
-
private determinePort;
|
|
2138
|
-
/**
|
|
2139
|
-
* Return the default session id, lazily creating the container session
|
|
2140
|
-
* on first use. Called by every public method that needs a session.
|
|
2141
|
-
* Concurrent callers that target the same sessionId share one
|
|
2142
|
-
* in-flight initialization promise.
|
|
2143
|
-
*/
|
|
2144
|
-
private ensureDefaultSession;
|
|
2145
|
-
private getOrInitializeDefaultSession;
|
|
2146
|
-
private isDefaultSessionInitContainerRestart;
|
|
2147
|
-
private initializeDefaultSession;
|
|
2148
|
-
/**
|
|
2149
|
-
* Persist the container's placement ID in DO storage.
|
|
2150
|
-
*
|
|
2151
|
-
* Called from the session-create handshake so subsequent reads via
|
|
2152
|
-
* `getContainerPlacementId()` do not require a round-trip to the container. The value
|
|
2153
|
-
* is overwritten on every handshake so that container replacements (which
|
|
2154
|
-
* assign a new placement ID) are reflected on the next session-create.
|
|
2155
|
-
*
|
|
2156
|
-
* A value of `undefined` means the handshake response omitted the field
|
|
2157
|
-
* (older container, unexpected error shape) and the stored value is left
|
|
2158
|
-
* untouched. `null` means the env var is not set in the container and is
|
|
2159
|
-
* stored as-is so callers can distinguish "observed and absent" from "not
|
|
2160
|
-
* yet observed."
|
|
2161
|
-
*/
|
|
2162
|
-
private capturePlacementId;
|
|
2163
|
-
private resolveExecution;
|
|
2164
|
-
private validateExplicitSessionId;
|
|
2165
|
-
private serializeExecutionContext;
|
|
2166
|
-
private getPublicExecutionSessionId;
|
|
2167
|
-
/**
|
|
2168
|
-
* Resolves the session ID to annotate returned Process objects.
|
|
2169
|
-
*
|
|
2170
|
-
* Unlike `resolveExecution`, this is synchronous and never creates a
|
|
2171
|
-
* session. When the default session hasn't been established yet, it returns
|
|
2172
|
-
* `undefined` rather than triggering session creation. The resolved value is
|
|
2173
|
-
* only used to populate `Process.sessionId` on the returned object — it is
|
|
2174
|
-
* never sent to the container API.
|
|
2175
|
-
*/
|
|
2176
|
-
private getProcessSessionBinding;
|
|
2177
|
-
private resolveExecutionEnv;
|
|
2178
|
-
private buildExecutionRequestOptions;
|
|
2179
|
-
exec(command: string, options?: ExecOptions): Promise<ExecResult>;
|
|
2180
|
-
execWithSessionToken(command: string, sessionId: string, options?: ExecOptions): Promise<ExecResult>;
|
|
2181
|
-
/**
|
|
2182
|
-
* Execute an infrastructure command (backup, mount, env setup, etc.)
|
|
2183
|
-
* tagged with origin: 'internal' so logging demotes it to debug level.
|
|
2184
|
-
*/
|
|
2185
|
-
private execInternal;
|
|
2186
|
-
/**
|
|
2187
|
-
* Internal session-aware exec implementation
|
|
2188
|
-
* Used by both public exec() and session wrappers
|
|
2189
|
-
*/
|
|
2190
|
-
private execWithSession;
|
|
2191
|
-
private executeWithStreaming;
|
|
2192
|
-
private mapExecuteResponseToExecResult;
|
|
2193
|
-
/**
|
|
2194
|
-
* Create a Process domain object from HTTP client DTO
|
|
2195
|
-
* Centralizes process object creation with bound methods
|
|
2196
|
-
* This eliminates duplication across startProcess, listProcesses, getProcess, and session wrappers
|
|
2197
|
-
*/
|
|
2198
|
-
private createProcessFromDTO;
|
|
2199
|
-
/**
|
|
2200
|
-
* Wait for a log pattern to appear in process output
|
|
2201
|
-
*/
|
|
2202
|
-
private waitForLogPattern;
|
|
2203
|
-
/**
|
|
2204
|
-
* Wait for a port to become available (for process readiness checking)
|
|
2205
|
-
*/
|
|
2206
|
-
private waitForPortReady;
|
|
2207
|
-
/**
|
|
2208
|
-
* Wait for a process to exit
|
|
2209
|
-
* Returns the exit code
|
|
2210
|
-
*/
|
|
2211
|
-
private waitForProcessExit;
|
|
2212
|
-
/**
|
|
2213
|
-
* Match a pattern against text
|
|
2214
|
-
*/
|
|
2215
|
-
private matchPattern;
|
|
2216
|
-
/**
|
|
2217
|
-
* Convert a log pattern to a human-readable string
|
|
2218
|
-
*/
|
|
2219
|
-
private conditionToString;
|
|
2220
|
-
/**
|
|
2221
|
-
* Create a ProcessReadyTimeoutError
|
|
2222
|
-
*/
|
|
2223
|
-
private createReadyTimeoutError;
|
|
2224
|
-
/**
|
|
2225
|
-
* Create a ProcessExitedBeforeReadyError
|
|
2226
|
-
*/
|
|
2227
|
-
private createExitedBeforeReadyError;
|
|
2228
|
-
startProcess(command: string, options?: ProcessOptions, sessionId?: string): Promise<Process>;
|
|
2229
|
-
/**
|
|
2230
|
-
* Start background streaming for process callbacks
|
|
2231
|
-
* Opens SSE stream to container and routes events to callbacks
|
|
2232
|
-
*/
|
|
2233
|
-
private startProcessCallbackStream;
|
|
2234
|
-
listProcesses(sessionId?: string): Promise<Process[]>;
|
|
2235
|
-
getProcess(id: string, sessionId?: string): Promise<Process | null>;
|
|
2236
|
-
killProcess(id: string, signal?: string, sessionId?: string): Promise<void>;
|
|
2237
|
-
killAllProcesses(sessionId?: string): Promise<number>;
|
|
2238
|
-
cleanupCompletedProcesses(sessionId?: string): Promise<number>;
|
|
2239
|
-
getProcessLogs(id: string, sessionId?: string): Promise<{
|
|
2240
|
-
stdout: string;
|
|
2241
|
-
stderr: string;
|
|
2242
|
-
processId: string;
|
|
2243
|
-
}>;
|
|
2244
|
-
execStream(command: string, options?: StreamOptions): Promise<ReadableStream<Uint8Array>>;
|
|
2245
|
-
execStreamWithSessionToken(command: string, sessionId: string, options?: StreamOptions): Promise<ReadableStream<Uint8Array>>;
|
|
2246
|
-
/**
|
|
2247
|
-
* Internal session-aware execStream implementation
|
|
2248
|
-
*/
|
|
2249
|
-
private execStreamWithSession;
|
|
2250
|
-
/**
|
|
2251
|
-
* Stream logs from a background process as a ReadableStream.
|
|
2252
|
-
*/
|
|
2253
|
-
streamProcessLogs(processId: string, options?: {
|
|
2254
|
-
signal?: AbortSignal;
|
|
2255
|
-
}): Promise<ReadableStream<Uint8Array>>;
|
|
2256
|
-
gitCheckout(repoUrl: string, options?: {
|
|
2257
|
-
branch?: string;
|
|
2258
|
-
targetDir?: string;
|
|
2259
|
-
sessionId?: string;
|
|
2260
|
-
/** Clone depth for shallow clones (e.g., 1 for latest commit only) */
|
|
2261
|
-
depth?: number;
|
|
2262
|
-
/** Maximum wall-clock time for the git clone subprocess in milliseconds */
|
|
2263
|
-
cloneTimeoutMs?: number;
|
|
2264
|
-
}): Promise<GitCheckoutResult>;
|
|
2265
|
-
mkdir(path: string, options?: {
|
|
2266
|
-
recursive?: boolean;
|
|
2267
|
-
sessionId?: string;
|
|
2268
|
-
}): Promise<MkdirResult>;
|
|
2269
|
-
writeFile(path: string, content: string | ReadableStream<Uint8Array>, options?: {
|
|
2270
|
-
encoding?: string;
|
|
2271
|
-
sessionId?: string;
|
|
2272
|
-
}): Promise<{
|
|
2273
|
-
success: boolean;
|
|
2274
|
-
path: string;
|
|
2275
|
-
bytesWritten: number;
|
|
2276
|
-
timestamp: string;
|
|
2277
|
-
} | WriteFileResult>;
|
|
2278
|
-
deleteFile(path: string, sessionId?: string): Promise<DeleteFileResult>;
|
|
2279
|
-
renameFile(oldPath: string, newPath: string, sessionId?: string): Promise<RenameFileResult>;
|
|
2280
|
-
moveFile(sourcePath: string, destinationPath: string, sessionId?: string): Promise<MoveFileResult>;
|
|
2281
|
-
/**
|
|
2282
|
-
* Read a file from the sandbox.
|
|
2283
|
-
*
|
|
2284
|
-
* @param encoding - How to encode the returned content:
|
|
2285
|
-
* - `undefined` (default): auto-detect from MIME type (text → UTF-8 string, binary → base64 string)
|
|
2286
|
-
* - `'utf-8'` / `'utf8'`: always return as UTF-8 string
|
|
2287
|
-
* - `'base64'`: always return as base64-encoded string
|
|
2288
|
-
* - `'none'`: return a result whose `content` is a raw binary `ReadableStream<Uint8Array>`
|
|
2289
|
-
* with no encoding overhead.
|
|
2290
|
-
*/
|
|
2291
|
-
readFile(path: string, options: {
|
|
2292
|
-
encoding: 'none';
|
|
2293
|
-
sessionId?: string;
|
|
2294
|
-
}): Promise<ReadFileStreamResult>;
|
|
2295
|
-
readFile(path: string, options?: {
|
|
2296
|
-
encoding?: Exclude<FileEncoding, 'none'>;
|
|
2297
|
-
sessionId?: string;
|
|
2298
|
-
}): Promise<ReadFileResult>;
|
|
2299
|
-
/**
|
|
2300
|
-
* Stream a file from the sandbox using Server-Sent Events
|
|
2301
|
-
* Returns a ReadableStream that can be consumed with streamFile() or collectFile() utilities
|
|
2302
|
-
* @param path - Path to the file to stream
|
|
2303
|
-
* @param options - Optional session ID
|
|
2304
|
-
*/
|
|
2305
|
-
readFileStream(path: string, options?: {
|
|
2306
|
-
sessionId?: string;
|
|
2307
|
-
}): Promise<ReadableStream<Uint8Array>>;
|
|
2308
|
-
listFiles(path: string, options?: ListFilesOptions): Promise<ListFilesResult>;
|
|
2309
|
-
exists(path: string, sessionId?: string): Promise<FileExistsResult>;
|
|
2310
|
-
/**
|
|
2311
|
-
* Watch a directory for file system changes using native inotify.
|
|
2312
|
-
*
|
|
2313
|
-
* The returned promise resolves only after the watcher is established on the
|
|
2314
|
-
* filesystem, so callers can immediately perform actions that depend on the
|
|
2315
|
-
* watch being active. The returned stream contains the full event sequence
|
|
2316
|
-
* starting with the `watching` event.
|
|
2317
|
-
*
|
|
2318
|
-
* Consume the stream with `parseSSEStream<FileWatchSSEEvent>(stream)`.
|
|
2319
|
-
*
|
|
2320
|
-
* @param path - Path to watch (absolute or relative to /workspace)
|
|
2321
|
-
* @param options - Watch options
|
|
2322
|
-
*/
|
|
2323
|
-
watch(path: string, options?: WatchOptions): Promise<ReadableStream<Uint8Array>>;
|
|
2324
|
-
/**
|
|
2325
|
-
* Check whether a path changed while this caller was disconnected.
|
|
2326
|
-
*
|
|
2327
|
-
* Pass the `version` returned from a prior call in `options.since` to learn
|
|
2328
|
-
* whether the path is unchanged, changed, or needs a full resync because the
|
|
2329
|
-
* retained change state was reset.
|
|
2330
|
-
*
|
|
2331
|
-
* @param path - Path to check (absolute or relative to /workspace)
|
|
2332
|
-
* @param options - Change-check options
|
|
2333
|
-
*/
|
|
2334
|
-
checkChanges(path: string, options?: CheckChangesOptions): Promise<CheckChangesResult>;
|
|
2335
|
-
/**
|
|
2336
|
-
* Expose a port and get a preview URL for accessing services running in the sandbox
|
|
2337
|
-
*
|
|
2338
|
-
* Preview URL authorization survives transient container restarts, but
|
|
2339
|
-
* forwarding is active only for the runtime where `exposePort()` was last
|
|
2340
|
-
* called. Call `exposePort()` again after a restart to reactivate an
|
|
2341
|
-
* existing URL for the current runtime.
|
|
2342
|
-
*
|
|
2343
|
-
* @param port - Port number to expose (1024-65535)
|
|
2344
|
-
* @param options - Configuration options
|
|
2345
|
-
* @param options.hostname - Your Worker's domain name (required for preview URL construction)
|
|
2346
|
-
* @param options.name - Optional friendly name for the port
|
|
2347
|
-
* @param options.token - Optional custom token for the preview URL (1-16 characters: lowercase letters, numbers, underscores)
|
|
2348
|
-
* If not provided, a random 16-character token will be generated automatically
|
|
2349
|
-
* @returns Preview URL information including the full URL, port number, and optional name
|
|
2350
|
-
*
|
|
2351
|
-
* @example
|
|
2352
|
-
* // With auto-generated token
|
|
2353
|
-
* const { url } = await sandbox.exposePort(8080, { hostname: 'example.com' });
|
|
2354
|
-
* // url: https://8080-sandbox-id-abc123random4567.example.com
|
|
2355
|
-
*
|
|
2356
|
-
* @example
|
|
2357
|
-
* // With custom token for stable URLs across deployments
|
|
2358
|
-
* const { url } = await sandbox.exposePort(8080, {
|
|
2359
|
-
* hostname: 'example.com',
|
|
2360
|
-
* token: 'my_token_v1'
|
|
2361
|
-
* });
|
|
2362
|
-
* // url: https://8080-sandbox-id-my_token_v1.example.com
|
|
2363
|
-
*/
|
|
2364
|
-
exposePort(port: number, options: {
|
|
2365
|
-
name?: string;
|
|
2366
|
-
hostname: string;
|
|
2367
|
-
token?: string;
|
|
2368
|
-
}): Promise<{
|
|
2369
|
-
url: string;
|
|
2370
|
-
port: number;
|
|
2371
|
-
name: string | undefined;
|
|
2372
|
-
}>;
|
|
2373
|
-
/**
|
|
2374
|
-
* Revoke preview URL authorization and current-runtime activation for a port.
|
|
2375
|
-
*
|
|
2376
|
-
* Revocation is idempotent: calling this for a port with no preview state is
|
|
2377
|
-
* still successful. The operation clears Durable Object-owned preview state
|
|
2378
|
-
* only and does not contact, probe, wake, or clean up the container runtime.
|
|
2379
|
-
*/
|
|
2380
|
-
unexposePort(port: number): Promise<void>;
|
|
2381
|
-
/**
|
|
2382
|
-
* Returns preview URLs that are currently forwardable in the active runtime.
|
|
2383
|
-
* Durable authorization without current-runtime activation is omitted.
|
|
2384
|
-
*/
|
|
2385
|
-
getExposedPorts(hostname: string): Promise<{
|
|
2386
|
-
url: string;
|
|
2387
|
-
port: number;
|
|
2388
|
-
status: "active";
|
|
2389
|
-
}[]>;
|
|
2390
|
-
/**
|
|
2391
|
-
* Namespaced tunnel API. Quick tunnels are zero-config preview URLs
|
|
2392
|
-
* backed by Cloudflare's trycloudflare service. Named tunnels bind a
|
|
2393
|
-
* stable hostname under the configured Cloudflare zone.
|
|
2394
|
-
*
|
|
2395
|
-
* - `tunnels.get(port)` — idempotent. Returns the cached tunnel for
|
|
2396
|
-
* `port` if one exists in DO storage, otherwise spawns a fresh
|
|
2397
|
-
* cloudflared process and persists the record.
|
|
2398
|
-
* - `tunnels.list()` — records currently known to this sandbox, from
|
|
2399
|
-
* DO storage.
|
|
2400
|
-
* - `tunnels.destroy(portOrInfo)` — tear down by port number or by
|
|
2401
|
-
* the record returned from `get()`.
|
|
2402
|
-
*
|
|
2403
|
-
* Container restarts drop quick-tunnel records because their
|
|
2404
|
-
* `*.trycloudflare.com` URLs are tied to the dead cloudflared process.
|
|
2405
|
-
* Named-tunnel records stay in storage and are marked for respawn so the
|
|
2406
|
-
* next `get(port, { name })` call reuses the Cloudflare tunnel and DNS
|
|
2407
|
-
* record while starting a fresh cloudflared process.
|
|
2408
|
-
*/
|
|
2409
|
-
get tunnels(): TunnelsHandler;
|
|
2410
|
-
/**
|
|
2411
|
-
* Lazily construct both the public tunnels handler and its sibling
|
|
2412
|
-
* exit-handler callback. Called from the `tunnels` getter on first
|
|
2413
|
-
* access.
|
|
2414
|
-
*/
|
|
2415
|
-
private ensureTunnelsBuilt;
|
|
2416
|
-
/**
|
|
2417
|
-
* Resolve the Cloudflare account id used for named-tunnel provisioning.
|
|
2418
|
-
*
|
|
2419
|
-
* Memoised for the lifetime of this DO instance. The first call may hit
|
|
2420
|
-
* `GET /user/tokens/verify` to derive the account id from the configured
|
|
2421
|
-
* `CLOUDFLARE_API_TOKEN`; subsequent calls return the cached promise.
|
|
2422
|
-
*
|
|
2423
|
-
* Only successful resolutions are cached: a rejected lookup clears the
|
|
2424
|
-
* slot so the next caller retries. Otherwise a transient failure on
|
|
2425
|
-
* first use would permanently poison every later named-tunnel `get()`
|
|
2426
|
-
* on this DO instance.
|
|
2427
|
-
*/
|
|
2428
|
-
private getTunnelAccountId;
|
|
2429
|
-
/**
|
|
2430
|
-
* Resolve the Cloudflare zone id used for named-tunnel provisioning.
|
|
2431
|
-
*
|
|
2432
|
-
* Memoised for the lifetime of this DO instance. Falls back to the
|
|
2433
|
-
* single zone the token can see under `accountId` via `GET /zones`
|
|
2434
|
-
* when `CLOUDFLARE_ZONE_ID` is not set. Failed lookups clear the cache
|
|
2435
|
-
* so the next caller retries — see `getTunnelAccountId` for the
|
|
2436
|
-
* rationale.
|
|
2437
|
-
*/
|
|
2438
|
-
private getTunnelZoneId;
|
|
2439
|
-
/**
|
|
2440
|
-
* Returns whether a port is currently preview-forwardable.
|
|
2441
|
-
* This checks Durable Object-owned auth and runtime activation without
|
|
2442
|
-
* contacting or waking the container.
|
|
2443
|
-
*/
|
|
2444
|
-
isPortExposed(port: number): Promise<boolean>;
|
|
2445
|
-
/**
|
|
2446
|
-
* Checks durable preview URL authorization for a port/token pair.
|
|
2447
|
-
*
|
|
2448
|
-
* This does not check whether the port is activated for the current runtime
|
|
2449
|
-
* and is not sufficient to decide whether preview traffic may forward.
|
|
2450
|
-
*/
|
|
2451
|
-
validatePortToken(port: number, token: string): Promise<boolean>;
|
|
2452
|
-
private validatePreviewURLForRuntime;
|
|
2453
|
-
private getCurrentPreviewPorts;
|
|
2454
|
-
private previewTokensMatch;
|
|
2455
|
-
private validateCustomToken;
|
|
2456
|
-
private generatePortToken;
|
|
2457
|
-
private constructPreviewUrl;
|
|
2458
|
-
/**
|
|
2459
|
-
* Create isolated execution session for advanced use cases
|
|
2460
|
-
* Returns ExecutionSession with full sandbox API bound to specific session
|
|
2461
|
-
*/
|
|
2462
|
-
createSession(options?: SessionOptions): Promise<ExecutionSession>;
|
|
2463
|
-
/**
|
|
2464
|
-
* Get an existing session by ID
|
|
2465
|
-
* Returns ExecutionSession wrapper bound to the specified session
|
|
2466
|
-
*
|
|
2467
|
-
* This is useful for retrieving sessions across different requests/contexts
|
|
2468
|
-
* without storing the ExecutionSession object (which has RPC lifecycle limitations)
|
|
2469
|
-
*
|
|
2470
|
-
* @param sessionId - The ID of an existing session
|
|
2471
|
-
* @returns ExecutionSession wrapper bound to the session
|
|
2472
|
-
*/
|
|
2473
|
-
getSession(sessionId: string): Promise<ExecutionSession>;
|
|
2474
|
-
/**
|
|
2475
|
-
* Delete an execution session
|
|
2476
|
-
* Cleans up session resources and removes it from the container
|
|
2477
|
-
* Note: Cannot delete the default session. To reset the default session,
|
|
2478
|
-
* use sandbox.destroy() to terminate the entire sandbox.
|
|
2479
|
-
*
|
|
2480
|
-
* @param sessionId - The ID of the session to delete
|
|
2481
|
-
* @returns Result with success status, sessionId, and timestamp
|
|
2482
|
-
* @throws Error if attempting to delete the default session
|
|
2483
|
-
*/
|
|
2484
|
-
deleteSession(sessionId: string): Promise<SessionDeleteResult>;
|
|
2485
|
-
/**
|
|
2486
|
-
* Get the Cloudflare placement ID observed for the underlying container.
|
|
2487
|
-
*
|
|
2488
|
-
* The placement ID is captured during the first session-create handshake
|
|
2489
|
-
* after a container start and stored in Durable Object storage, so this
|
|
2490
|
-
* method returns the cached value without contacting the container. A new
|
|
2491
|
-
* placement ID is captured on each subsequent session-create handshake,
|
|
2492
|
-
* which occurs whenever the container has been replaced.
|
|
2493
|
-
*
|
|
2494
|
-
* Returns `null` when a handshake has completed but the container's
|
|
2495
|
-
* `CLOUDFLARE_PLACEMENT_ID` environment variable is not set (for example,
|
|
2496
|
-
* in local development).
|
|
2497
|
-
*
|
|
2498
|
-
* Returns `undefined` when no handshake has been observed yet on this
|
|
2499
|
-
* sandbox. Call any method that triggers session creation (such as
|
|
2500
|
-
* `exec()`) to populate the value.
|
|
2501
|
-
*/
|
|
2502
|
-
getContainerPlacementId(): Promise<string | null | undefined>;
|
|
2503
|
-
private getSessionWrapper;
|
|
2504
|
-
createCodeContext(options?: CreateContextOptions): Promise<CodeContext>;
|
|
2505
|
-
runCode(code: string, options?: RunCodeOptions): Promise<ExecutionResult>;
|
|
2506
|
-
runCodeStream(code: string, options?: RunCodeOptions): Promise<ReadableStream>;
|
|
2507
|
-
listCodeContexts(): Promise<CodeContext[]>;
|
|
2508
|
-
deleteCodeContext(contextId: string): Promise<void>;
|
|
2509
|
-
/** UUID v4 format validator for backup IDs */
|
|
2510
|
-
private static readonly UUID_REGEX;
|
|
2511
|
-
/**
|
|
2512
|
-
* Validate that a directory path is safe for backup operations.
|
|
2513
|
-
* Rejects empty, relative, traversal, null-byte, and unsupported-root paths.
|
|
2514
|
-
*/
|
|
2515
|
-
private static validateBackupDir;
|
|
2516
|
-
/**
|
|
2517
|
-
* Returns the R2 bucket or throws if backup is not configured.
|
|
2518
|
-
*/
|
|
2519
|
-
private requireBackupBucket;
|
|
2520
|
-
private normalizeBackupExcludes;
|
|
2521
|
-
private resolveBackupCompression;
|
|
2522
|
-
private static readonly PRESIGNED_URL_EXPIRY_SECONDS;
|
|
2523
|
-
/**
|
|
2524
|
-
* Create a unique, dedicated session for a single backup operation.
|
|
2525
|
-
* Each call produces a fresh session ID so concurrent or sequential
|
|
2526
|
-
* operations never share shell state. Callers must destroy the session
|
|
2527
|
-
* in a finally block via `client.utils.deleteSession()`.
|
|
2528
|
-
*/
|
|
2529
|
-
private ensureBackupSession;
|
|
2530
|
-
/**
|
|
2531
|
-
* Returns validated presigned URL configuration or throws if not configured.
|
|
2532
|
-
* All credential fields plus the R2 binding are required for backup to work.
|
|
2533
|
-
*/
|
|
2534
|
-
private requirePresignedURLSupport;
|
|
2535
|
-
private getBackupBucketEndpoint;
|
|
2536
|
-
private getBackupObjectURL;
|
|
2537
|
-
/**
|
|
2538
|
-
* Generate a presigned GET URL for downloading an object from R2.
|
|
2539
|
-
* The container can curl this URL directly without credentials.
|
|
2540
|
-
*/
|
|
2541
|
-
private generatePresignedGetURL;
|
|
2542
|
-
/**
|
|
2543
|
-
* Generate a presigned PUT URL for uploading an object to R2.
|
|
2544
|
-
* The container can curl PUT to this URL directly without credentials.
|
|
2545
|
-
*/
|
|
2546
|
-
private generatePresignedPutURL;
|
|
2547
|
-
/**
|
|
2548
|
-
* Upload a backup archive via presigned PUT URL.
|
|
2549
|
-
* The container curls the archive directly to R2, bypassing the DO.
|
|
2550
|
-
* ~24 MB/s throughput vs ~0.6 MB/s for base64 readFile.
|
|
2551
|
-
*/
|
|
2552
|
-
private uploadBackupPresigned;
|
|
2553
|
-
/**
|
|
2554
|
-
* Generate a presigned PUT URL for a single part in a multipart upload.
|
|
2555
|
-
*/
|
|
2556
|
-
private generatePresignedPartURL;
|
|
2557
|
-
/**
|
|
2558
|
-
* Upload a backup archive to R2 using parallel multipart upload.
|
|
2559
|
-
* Uses the S3-compatible API exclusively for create/complete/abort so that
|
|
2560
|
-
* the uploadId is in the same namespace as the presigned part PUT URLs.
|
|
2561
|
-
*/
|
|
2562
|
-
private uploadBackupMultipart;
|
|
2563
|
-
/**
|
|
2564
|
-
* Download a backup archive from R2 via presigned GET URL.
|
|
2565
|
-
* For archives >= BACKUP_DOWNLOAD_PARALLEL_MIN_SIZE, uses BACKUP_DOWNLOAD_PARALLEL_PARTS
|
|
2566
|
-
* concurrent curl processes (each downloading a byte-range) to maximise both
|
|
2567
|
-
* network and disk-write throughput. Parts are written into a pre-sized file
|
|
2568
|
-
* with dd using byte offsets, then atomically moved to the final path.
|
|
2569
|
-
*/
|
|
2570
|
-
private downloadBackupParallel;
|
|
2571
|
-
/**
|
|
2572
|
-
* Serialize backup operations on this sandbox instance.
|
|
2573
|
-
* Concurrent backup/restore calls are queued so the multi-step
|
|
2574
|
-
* create-archive → read → upload (or mount → extract) flow
|
|
2575
|
-
* is not interleaved with another backup operation on the same directory.
|
|
2576
|
-
*/
|
|
2577
|
-
private enqueueBackupOp;
|
|
2578
|
-
/**
|
|
2579
|
-
* Create a backup of a directory and upload it to R2.
|
|
2580
|
-
*
|
|
2581
|
-
* Flow:
|
|
2582
|
-
* 1. Container creates squashfs archive from the directory
|
|
2583
|
-
* 2. Container uploads the archive directly to R2 via presigned URL
|
|
2584
|
-
* 3. DO writes metadata to R2
|
|
2585
|
-
* 4. Container cleans up the local archive
|
|
2586
|
-
*
|
|
2587
|
-
* The returned DirectoryBackup handle is serializable. Store it anywhere
|
|
2588
|
-
* (KV, D1, DO storage) and pass it to restoreBackup() later.
|
|
2589
|
-
*
|
|
2590
|
-
* Concurrent backup/restore calls on the same sandbox are serialized.
|
|
2591
|
-
*
|
|
2592
|
-
* Partially-written files in the target directory may not be captured
|
|
2593
|
-
* consistently. Completed writes are captured.
|
|
2594
|
-
*
|
|
2595
|
-
* NOTE: Expired backups are not automatically deleted from R2. Configure
|
|
2596
|
-
* R2 lifecycle rules on the BACKUP_BUCKET to garbage-collect objects
|
|
2597
|
-
* under the `backups/` prefix after the desired retention period.
|
|
2598
|
-
*/
|
|
2599
|
-
createBackup(options: BackupOptions): Promise<DirectoryBackup>;
|
|
2600
|
-
private doCreateBackup;
|
|
2601
|
-
/**
|
|
2602
|
-
* Local-dev implementation of createBackup.
|
|
2603
|
-
* Uses the R2 binding directly instead of presigned URLs.
|
|
2604
|
-
* Archive format is identical to production (squashfs + meta.json).
|
|
2605
|
-
*/
|
|
2606
|
-
private doCreateBackupLocal;
|
|
2607
|
-
/**
|
|
2608
|
-
* Restore a backup from R2 into a directory.
|
|
2609
|
-
*
|
|
2610
|
-
* **Production flow** (`localBucket` not set):
|
|
2611
|
-
* 1. DO reads metadata from R2 and checks TTL
|
|
2612
|
-
* 2. Container mounts the backup archive from R2 via s3fs
|
|
2613
|
-
* 3. Container mounts the squashfs archive with FUSE overlayfs
|
|
2614
|
-
*
|
|
2615
|
-
* The target directory becomes an overlay mount with the backup as a
|
|
2616
|
-
* read-only lower layer and a writable upper layer for copy-on-write.
|
|
2617
|
-
* Any processes writing to the directory should be stopped first.
|
|
2618
|
-
*
|
|
2619
|
-
* **Mount Lifecycle**: The FUSE overlay mount persists only while the
|
|
2620
|
-
* container is running. When the sandbox sleeps or the container restarts,
|
|
2621
|
-
* the mount is lost and the directory becomes empty. Re-restore from the
|
|
2622
|
-
* backup handle to recover. This is an ephemeral restore, not a persistent
|
|
2623
|
-
* extraction.
|
|
2624
|
-
*
|
|
2625
|
-
* **Local-dev flow** (`localBucket: true` on the originating `createBackup` call):
|
|
2626
|
-
* 1. DO reads metadata and checks TTL via R2 binding
|
|
2627
|
-
* 2. DO downloads the archive from R2 and writes it to the container
|
|
2628
|
-
* 3. Container extracts the archive with `unsquashfs` (no FUSE needed)
|
|
2629
|
-
*
|
|
2630
|
-
* The backup is restored into `backup.dir`. This may differ from the
|
|
2631
|
-
* directory that was originally backed up, allowing cross-directory restore.
|
|
2632
|
-
*
|
|
2633
|
-
* Overlapping backups are independent: restoring a parent directory
|
|
2634
|
-
* overwrites everything inside it, including subdirectories that were
|
|
2635
|
-
* backed up separately. When restoring both, restore the parent first.
|
|
2636
|
-
*
|
|
2637
|
-
* Concurrent backup/restore calls on the same sandbox are serialized.
|
|
2638
|
-
*/
|
|
2639
|
-
restoreBackup(backup: DirectoryBackup): Promise<RestoreBackupResult>;
|
|
2640
|
-
private doRestoreBackup;
|
|
2641
|
-
/**
|
|
2642
|
-
* Local-dev implementation of restoreBackup.
|
|
2643
|
-
* Uses the R2 binding directly instead of presigned URLs, and
|
|
2644
|
-
* unsquashfs for extraction instead of squashfuse + fuse-overlayfs.
|
|
2645
|
-
*/
|
|
2646
|
-
private doRestoreBackupLocal;
|
|
2647
|
-
private configureR2EgressOutbound;
|
|
2648
|
-
private configureS3CredentialProxyOutbound;
|
|
2649
|
-
}
|
|
2650
|
-
//#endregion
|
|
2651
|
-
export { Process as A, WatchOptions as B, FileWatchSSEEvent as C, LocalMountBucketOptions as D, ListFilesOptions as E, SandboxOptions as F, CodeContext as G, isProcess as H, SessionOptions as I, ExecutionResult as J, CreateContextOptions as K, StreamOptions as L, ProcessStatus as M, RemoteMountBucketOptions as N, LogEvent as O, RestoreBackupResult as P, WaitForLogResult as R, FileStreamEvent as S, ISandbox as T, isProcessStatus as U, isExecResult as V, PtyOptions as W, RunCodeOptions as Y, ExecOptions as _, QuickTunnelInfo as a, FileChunk as b, TunnelOptions as c, BucketCredentials as d, BucketProvider as f, ExecEvent as g, DirectoryBackup as h, NamedTunnelInfo as i, ProcessOptions as j, MountBucketOptions as k, BackupOptions as l, CheckChangesResult as m, Sandbox as n, SandboxInterpreterAPI as o, CheckChangesOptions as p, Execution as q, getSandbox as r, TunnelInfo as s, ContainerProxy$1 as t, BaseExecOptions as u, ExecResult as v, GitCheckoutResult as w, FileMetadata as x, ExecutionSession as y, WaitForPortOptions as z };
|
|
2652
|
-
//# sourceMappingURL=sandbox-44kEJjAc.d.ts.map
|