@cloudflare/sandbox 0.5.1 → 0.5.2
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/.turbo/turbo-build.log +17 -9
- package/CHANGELOG.md +12 -0
- package/dist/dist-gVyG2H2h.js +612 -0
- package/dist/dist-gVyG2H2h.js.map +1 -0
- package/dist/index.d.ts +2 -1726
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +27 -686
- package/dist/index.js.map +1 -1
- package/dist/openai/index.d.ts +67 -0
- package/dist/openai/index.d.ts.map +1 -0
- package/dist/openai/index.js +362 -0
- package/dist/openai/index.js.map +1 -0
- package/dist/sandbox-B3vJ541e.d.ts +1729 -0
- package/dist/sandbox-B3vJ541e.d.ts.map +1 -0
- package/package.json +15 -1
- package/src/openai/index.ts +465 -0
- package/src/sandbox.ts +47 -38
- package/src/version.ts +1 -1
- package/tests/git-client.test.ts +7 -39
- package/tests/openai-shell-editor.test.ts +434 -0
- package/tests/port-client.test.ts +25 -35
- package/tests/process-client.test.ts +73 -107
- package/tests/sandbox.test.ts +17 -11
- package/tsconfig.json +2 -2
- package/tsdown.config.ts +1 -1
package/.turbo/turbo-build.log
CHANGED
|
@@ -1,15 +1,23 @@
|
|
|
1
1
|
|
|
2
|
-
> @cloudflare/sandbox@0.5.
|
|
2
|
+
> @cloudflare/sandbox@0.5.2 build
|
|
3
3
|
> rm -rf dist && tsdown --config tsdown.config.ts
|
|
4
4
|
|
|
5
|
-
[34mℹ[39m tsdown [2mv0.16.
|
|
5
|
+
[34mℹ[39m tsdown [2mv0.16.6[22m powered by rolldown [2mv1.0.0-beta.51[22m
|
|
6
6
|
[34mℹ[39m Using tsdown config: [4m/home/runner/work/sandbox-sdk/sandbox-sdk/packages/sandbox/tsdown.config.ts[24m
|
|
7
|
-
[34mℹ[39m entry: [34msrc/index.ts[39m
|
|
7
|
+
[34mℹ[39m entry: [34msrc/index.ts, src/openai/index.ts[39m
|
|
8
8
|
[34mℹ[39m tsconfig: [34mtsconfig.json[39m
|
|
9
9
|
[34mℹ[39m Build start
|
|
10
|
-
[34mℹ[39m [2mdist/[22m[1mindex.js[22m
|
|
11
|
-
[34mℹ[39m [2mdist/[
|
|
12
|
-
[34mℹ[39m [2mdist/[22mindex.
|
|
13
|
-
[34mℹ[39m [2mdist/[
|
|
14
|
-
[34mℹ[39m
|
|
15
|
-
[
|
|
10
|
+
[34mℹ[39m [2mdist/[22m[1mindex.js[22m [2m100.84 kB[22m [2m│ gzip: 22.92 kB[22m
|
|
11
|
+
[34mℹ[39m [2mdist/[22m[1mopenai/index.js[22m [2m 10.42 kB[22m [2m│ gzip: 2.63 kB[22m
|
|
12
|
+
[34mℹ[39m [2mdist/[22mindex.js.map [2m214.92 kB[22m [2m│ gzip: 47.84 kB[22m
|
|
13
|
+
[34mℹ[39m [2mdist/[22msandbox-B3vJ541e.d.ts.map [2m 60.94 kB[22m [2m│ gzip: 16.79 kB[22m
|
|
14
|
+
[34mℹ[39m [2mdist/[22mdist-gVyG2H2h.js.map [2m 30.14 kB[22m [2m│ gzip: 8.31 kB[22m
|
|
15
|
+
[34mℹ[39m [2mdist/[22mopenai/index.js.map [2m 21.00 kB[22m [2m│ gzip: 5.13 kB[22m
|
|
16
|
+
[34mℹ[39m [2mdist/[22mdist-gVyG2H2h.js [2m 17.03 kB[22m [2m│ gzip: 5.39 kB[22m
|
|
17
|
+
[34mℹ[39m [2mdist/[22mindex.d.ts.map [2m 8.84 kB[22m [2m│ gzip: 2.71 kB[22m
|
|
18
|
+
[34mℹ[39m [2mdist/[22mopenai/index.d.ts.map [2m 0.72 kB[22m [2m│ gzip: 0.37 kB[22m
|
|
19
|
+
[34mℹ[39m [2mdist/[22m[32m[1mindex.d.ts[22m[39m [2m 10.66 kB[22m [2m│ gzip: 3.21 kB[22m
|
|
20
|
+
[34mℹ[39m [2mdist/[22m[32m[1mopenai/index.d.ts[22m[39m [2m 2.10 kB[22m [2m│ gzip: 0.81 kB[22m
|
|
21
|
+
[34mℹ[39m [2mdist/[22m[32msandbox-B3vJ541e.d.ts[39m [2m 50.82 kB[22m [2m│ gzip: 11.69 kB[22m
|
|
22
|
+
[34mℹ[39m 12 files, total: 528.43 kB
|
|
23
|
+
[32m✔[39m Build complete in [32m3705ms[39m
|
package/CHANGELOG.md
CHANGED
|
@@ -1,5 +1,17 @@
|
|
|
1
1
|
# @cloudflare/sandbox
|
|
2
2
|
|
|
3
|
+
## 0.5.2
|
|
4
|
+
|
|
5
|
+
### Patch Changes
|
|
6
|
+
|
|
7
|
+
- [#234](https://github.com/cloudflare/sandbox-sdk/pull/234) [`d4cee5e`](https://github.com/cloudflare/sandbox-sdk/commit/d4cee5e4617db205c9c1ca714e25493de7ea24ce) Thanks [@ghostwriternr](https://github.com/ghostwriternr)! - Remove unused logging infrastructure (getLogger, runWithLogger) that was never called
|
|
8
|
+
|
|
9
|
+
- [#224](https://github.com/cloudflare/sandbox-sdk/pull/224) [`71e86f4`](https://github.com/cloudflare/sandbox-sdk/commit/71e86f42c3b98424db79c268d55f2d5be5e495b3) Thanks [@ghostwriternr](https://github.com/ghostwriternr)! - Fix memory leaks from listener accumulation, unbounded process storage, and stale DO state
|
|
10
|
+
|
|
11
|
+
- [#221](https://github.com/cloudflare/sandbox-sdk/pull/221) [`3aba9e8`](https://github.com/cloudflare/sandbox-sdk/commit/3aba9e8da6e2e6acd7b40076cc0920a69cb02775) Thanks [@threepointone](https://github.com/threepointone)! - Add OpenAI Agents adapters
|
|
12
|
+
|
|
13
|
+
Add OpenAI Agents adapters (`Shell` and `Editor`) that integrate Cloudflare Sandbox with the OpenAI Agents SDK. These adapters enable AI agents to execute shell commands and perform file operations (create, update, delete) inside sandboxed environments. Both adapters automatically collect and timestamp results from operations, making it easy to track command execution and file modifications during agent sessions. The adapters are exported from `@cloudflare/sandbox/openai` and implement the OpenAI Agents `Shell` and `Editor` interfaces.
|
|
14
|
+
|
|
3
15
|
## 0.5.1
|
|
4
16
|
|
|
5
17
|
### Patch Changes
|
|
@@ -0,0 +1,612 @@
|
|
|
1
|
+
//#region ../shared/dist/env.js
|
|
2
|
+
/**
|
|
3
|
+
* Safely extract a string value from an environment object
|
|
4
|
+
*
|
|
5
|
+
* @param env - Environment object with dynamic keys
|
|
6
|
+
* @param key - The environment variable key to access
|
|
7
|
+
* @returns The string value if present and is a string, undefined otherwise
|
|
8
|
+
*/
|
|
9
|
+
function getEnvString(env, key) {
|
|
10
|
+
const value = env?.[key];
|
|
11
|
+
return typeof value === "string" ? value : void 0;
|
|
12
|
+
}
|
|
13
|
+
|
|
14
|
+
//#endregion
|
|
15
|
+
//#region ../shared/dist/git.js
|
|
16
|
+
/**
|
|
17
|
+
* Redact credentials from URLs for secure logging
|
|
18
|
+
*
|
|
19
|
+
* Replaces any credentials (username:password, tokens, etc.) embedded
|
|
20
|
+
* in URLs with ****** to prevent sensitive data exposure in logs.
|
|
21
|
+
* Works with URLs embedded in text (e.g., "Error: https://token@github.com/repo.git failed")
|
|
22
|
+
*
|
|
23
|
+
* @param text - String that may contain URLs with credentials
|
|
24
|
+
* @returns String with credentials redacted from any URLs
|
|
25
|
+
*/
|
|
26
|
+
function redactCredentials(text) {
|
|
27
|
+
let result = text;
|
|
28
|
+
let pos = 0;
|
|
29
|
+
while (pos < result.length) {
|
|
30
|
+
const httpPos = result.indexOf("http://", pos);
|
|
31
|
+
const httpsPos = result.indexOf("https://", pos);
|
|
32
|
+
let protocolPos = -1;
|
|
33
|
+
let protocolLen = 0;
|
|
34
|
+
if (httpPos === -1 && httpsPos === -1) break;
|
|
35
|
+
if (httpPos !== -1 && (httpsPos === -1 || httpPos < httpsPos)) {
|
|
36
|
+
protocolPos = httpPos;
|
|
37
|
+
protocolLen = 7;
|
|
38
|
+
} else {
|
|
39
|
+
protocolPos = httpsPos;
|
|
40
|
+
protocolLen = 8;
|
|
41
|
+
}
|
|
42
|
+
const searchStart = protocolPos + protocolLen;
|
|
43
|
+
const atPos = result.indexOf("@", searchStart);
|
|
44
|
+
let urlEnd = searchStart;
|
|
45
|
+
while (urlEnd < result.length) {
|
|
46
|
+
const char = result[urlEnd];
|
|
47
|
+
if (/[\s"'`<>,;{}[\]]/.test(char)) break;
|
|
48
|
+
urlEnd++;
|
|
49
|
+
}
|
|
50
|
+
if (atPos !== -1 && atPos < urlEnd) {
|
|
51
|
+
result = `${result.substring(0, searchStart)}******${result.substring(atPos)}`;
|
|
52
|
+
pos = searchStart + 6;
|
|
53
|
+
} else pos = protocolPos + protocolLen;
|
|
54
|
+
}
|
|
55
|
+
return result;
|
|
56
|
+
}
|
|
57
|
+
/**
|
|
58
|
+
* Sanitize data by redacting credentials from any strings
|
|
59
|
+
* Recursively processes objects and arrays to ensure credentials are never leaked
|
|
60
|
+
*/
|
|
61
|
+
function sanitizeGitData(data) {
|
|
62
|
+
if (typeof data === "string") return redactCredentials(data);
|
|
63
|
+
if (data === null || data === void 0) return data;
|
|
64
|
+
if (Array.isArray(data)) return data.map((item) => sanitizeGitData(item));
|
|
65
|
+
if (typeof data === "object") {
|
|
66
|
+
const result = {};
|
|
67
|
+
for (const [key, value] of Object.entries(data)) result[key] = sanitizeGitData(value);
|
|
68
|
+
return result;
|
|
69
|
+
}
|
|
70
|
+
return data;
|
|
71
|
+
}
|
|
72
|
+
/**
|
|
73
|
+
* Logger wrapper that automatically sanitizes git credentials
|
|
74
|
+
*/
|
|
75
|
+
var GitLogger = class GitLogger {
|
|
76
|
+
baseLogger;
|
|
77
|
+
constructor(baseLogger) {
|
|
78
|
+
this.baseLogger = baseLogger;
|
|
79
|
+
}
|
|
80
|
+
sanitizeContext(context) {
|
|
81
|
+
return context ? sanitizeGitData(context) : context;
|
|
82
|
+
}
|
|
83
|
+
sanitizeError(error) {
|
|
84
|
+
if (!error) return error;
|
|
85
|
+
const sanitized = new Error(redactCredentials(error.message));
|
|
86
|
+
sanitized.name = error.name;
|
|
87
|
+
if (error.stack) sanitized.stack = redactCredentials(error.stack);
|
|
88
|
+
const sanitizedRecord = sanitized;
|
|
89
|
+
const errorRecord = error;
|
|
90
|
+
for (const key of Object.keys(error)) if (key !== "message" && key !== "stack" && key !== "name") sanitizedRecord[key] = sanitizeGitData(errorRecord[key]);
|
|
91
|
+
return sanitized;
|
|
92
|
+
}
|
|
93
|
+
debug(message, context) {
|
|
94
|
+
this.baseLogger.debug(message, this.sanitizeContext(context));
|
|
95
|
+
}
|
|
96
|
+
info(message, context) {
|
|
97
|
+
this.baseLogger.info(message, this.sanitizeContext(context));
|
|
98
|
+
}
|
|
99
|
+
warn(message, context) {
|
|
100
|
+
this.baseLogger.warn(message, this.sanitizeContext(context));
|
|
101
|
+
}
|
|
102
|
+
error(message, error, context) {
|
|
103
|
+
this.baseLogger.error(message, this.sanitizeError(error), this.sanitizeContext(context));
|
|
104
|
+
}
|
|
105
|
+
child(context) {
|
|
106
|
+
const sanitized = sanitizeGitData(context);
|
|
107
|
+
return new GitLogger(this.baseLogger.child(sanitized));
|
|
108
|
+
}
|
|
109
|
+
};
|
|
110
|
+
|
|
111
|
+
//#endregion
|
|
112
|
+
//#region ../shared/dist/interpreter-types.js
|
|
113
|
+
var Execution = class {
|
|
114
|
+
code;
|
|
115
|
+
context;
|
|
116
|
+
/**
|
|
117
|
+
* All results from the execution
|
|
118
|
+
*/
|
|
119
|
+
results = [];
|
|
120
|
+
/**
|
|
121
|
+
* Accumulated stdout and stderr
|
|
122
|
+
*/
|
|
123
|
+
logs = {
|
|
124
|
+
stdout: [],
|
|
125
|
+
stderr: []
|
|
126
|
+
};
|
|
127
|
+
/**
|
|
128
|
+
* Execution error if any
|
|
129
|
+
*/
|
|
130
|
+
error;
|
|
131
|
+
/**
|
|
132
|
+
* Execution count (for interpreter)
|
|
133
|
+
*/
|
|
134
|
+
executionCount;
|
|
135
|
+
constructor(code, context) {
|
|
136
|
+
this.code = code;
|
|
137
|
+
this.context = context;
|
|
138
|
+
}
|
|
139
|
+
/**
|
|
140
|
+
* Convert to a plain object for serialization
|
|
141
|
+
*/
|
|
142
|
+
toJSON() {
|
|
143
|
+
return {
|
|
144
|
+
code: this.code,
|
|
145
|
+
logs: this.logs,
|
|
146
|
+
error: this.error,
|
|
147
|
+
executionCount: this.executionCount,
|
|
148
|
+
results: this.results.map((result) => ({
|
|
149
|
+
text: result.text,
|
|
150
|
+
html: result.html,
|
|
151
|
+
png: result.png,
|
|
152
|
+
jpeg: result.jpeg,
|
|
153
|
+
svg: result.svg,
|
|
154
|
+
latex: result.latex,
|
|
155
|
+
markdown: result.markdown,
|
|
156
|
+
javascript: result.javascript,
|
|
157
|
+
json: result.json,
|
|
158
|
+
chart: result.chart,
|
|
159
|
+
data: result.data
|
|
160
|
+
}))
|
|
161
|
+
};
|
|
162
|
+
}
|
|
163
|
+
};
|
|
164
|
+
var ResultImpl = class {
|
|
165
|
+
raw;
|
|
166
|
+
constructor(raw) {
|
|
167
|
+
this.raw = raw;
|
|
168
|
+
}
|
|
169
|
+
get text() {
|
|
170
|
+
return this.raw.text || this.raw.data?.["text/plain"];
|
|
171
|
+
}
|
|
172
|
+
get html() {
|
|
173
|
+
return this.raw.html || this.raw.data?.["text/html"];
|
|
174
|
+
}
|
|
175
|
+
get png() {
|
|
176
|
+
return this.raw.png || this.raw.data?.["image/png"];
|
|
177
|
+
}
|
|
178
|
+
get jpeg() {
|
|
179
|
+
return this.raw.jpeg || this.raw.data?.["image/jpeg"];
|
|
180
|
+
}
|
|
181
|
+
get svg() {
|
|
182
|
+
return this.raw.svg || this.raw.data?.["image/svg+xml"];
|
|
183
|
+
}
|
|
184
|
+
get latex() {
|
|
185
|
+
return this.raw.latex || this.raw.data?.["text/latex"];
|
|
186
|
+
}
|
|
187
|
+
get markdown() {
|
|
188
|
+
return this.raw.markdown || this.raw.data?.["text/markdown"];
|
|
189
|
+
}
|
|
190
|
+
get javascript() {
|
|
191
|
+
return this.raw.javascript || this.raw.data?.["application/javascript"];
|
|
192
|
+
}
|
|
193
|
+
get json() {
|
|
194
|
+
return this.raw.json || this.raw.data?.["application/json"];
|
|
195
|
+
}
|
|
196
|
+
get chart() {
|
|
197
|
+
return this.raw.chart;
|
|
198
|
+
}
|
|
199
|
+
get data() {
|
|
200
|
+
return this.raw.data;
|
|
201
|
+
}
|
|
202
|
+
formats() {
|
|
203
|
+
const formats = [];
|
|
204
|
+
if (this.text) formats.push("text");
|
|
205
|
+
if (this.html) formats.push("html");
|
|
206
|
+
if (this.png) formats.push("png");
|
|
207
|
+
if (this.jpeg) formats.push("jpeg");
|
|
208
|
+
if (this.svg) formats.push("svg");
|
|
209
|
+
if (this.latex) formats.push("latex");
|
|
210
|
+
if (this.markdown) formats.push("markdown");
|
|
211
|
+
if (this.javascript) formats.push("javascript");
|
|
212
|
+
if (this.json) formats.push("json");
|
|
213
|
+
if (this.chart) formats.push("chart");
|
|
214
|
+
return formats;
|
|
215
|
+
}
|
|
216
|
+
};
|
|
217
|
+
|
|
218
|
+
//#endregion
|
|
219
|
+
//#region ../shared/dist/logger/types.js
|
|
220
|
+
/**
|
|
221
|
+
* Logger types for Cloudflare Sandbox SDK
|
|
222
|
+
*
|
|
223
|
+
* Provides structured, trace-aware logging across Worker, Durable Object, and Container.
|
|
224
|
+
*/
|
|
225
|
+
/**
|
|
226
|
+
* Log levels (from most to least verbose)
|
|
227
|
+
*/
|
|
228
|
+
var LogLevel;
|
|
229
|
+
(function(LogLevel$1) {
|
|
230
|
+
LogLevel$1[LogLevel$1["DEBUG"] = 0] = "DEBUG";
|
|
231
|
+
LogLevel$1[LogLevel$1["INFO"] = 1] = "INFO";
|
|
232
|
+
LogLevel$1[LogLevel$1["WARN"] = 2] = "WARN";
|
|
233
|
+
LogLevel$1[LogLevel$1["ERROR"] = 3] = "ERROR";
|
|
234
|
+
})(LogLevel || (LogLevel = {}));
|
|
235
|
+
|
|
236
|
+
//#endregion
|
|
237
|
+
//#region ../shared/dist/logger/logger.js
|
|
238
|
+
/**
|
|
239
|
+
* Logger implementation
|
|
240
|
+
*/
|
|
241
|
+
/**
|
|
242
|
+
* ANSI color codes for terminal output
|
|
243
|
+
*/
|
|
244
|
+
const COLORS = {
|
|
245
|
+
reset: "\x1B[0m",
|
|
246
|
+
debug: "\x1B[36m",
|
|
247
|
+
info: "\x1B[32m",
|
|
248
|
+
warn: "\x1B[33m",
|
|
249
|
+
error: "\x1B[31m",
|
|
250
|
+
dim: "\x1B[2m"
|
|
251
|
+
};
|
|
252
|
+
/**
|
|
253
|
+
* CloudflareLogger implements structured logging with support for
|
|
254
|
+
* both JSON output (production) and pretty printing (development).
|
|
255
|
+
*/
|
|
256
|
+
var CloudflareLogger = class CloudflareLogger {
|
|
257
|
+
baseContext;
|
|
258
|
+
minLevel;
|
|
259
|
+
pretty;
|
|
260
|
+
/**
|
|
261
|
+
* Create a new CloudflareLogger
|
|
262
|
+
*
|
|
263
|
+
* @param baseContext Base context included in all log entries
|
|
264
|
+
* @param minLevel Minimum log level to output (default: INFO)
|
|
265
|
+
* @param pretty Enable pretty printing for human-readable output (default: false)
|
|
266
|
+
*/
|
|
267
|
+
constructor(baseContext, minLevel = LogLevel.INFO, pretty = false) {
|
|
268
|
+
this.baseContext = baseContext;
|
|
269
|
+
this.minLevel = minLevel;
|
|
270
|
+
this.pretty = pretty;
|
|
271
|
+
}
|
|
272
|
+
/**
|
|
273
|
+
* Log debug-level message
|
|
274
|
+
*/
|
|
275
|
+
debug(message, context) {
|
|
276
|
+
if (this.shouldLog(LogLevel.DEBUG)) {
|
|
277
|
+
const logData = this.buildLogData("debug", message, context);
|
|
278
|
+
this.output(console.log, logData);
|
|
279
|
+
}
|
|
280
|
+
}
|
|
281
|
+
/**
|
|
282
|
+
* Log info-level message
|
|
283
|
+
*/
|
|
284
|
+
info(message, context) {
|
|
285
|
+
if (this.shouldLog(LogLevel.INFO)) {
|
|
286
|
+
const logData = this.buildLogData("info", message, context);
|
|
287
|
+
this.output(console.log, logData);
|
|
288
|
+
}
|
|
289
|
+
}
|
|
290
|
+
/**
|
|
291
|
+
* Log warning-level message
|
|
292
|
+
*/
|
|
293
|
+
warn(message, context) {
|
|
294
|
+
if (this.shouldLog(LogLevel.WARN)) {
|
|
295
|
+
const logData = this.buildLogData("warn", message, context);
|
|
296
|
+
this.output(console.warn, logData);
|
|
297
|
+
}
|
|
298
|
+
}
|
|
299
|
+
/**
|
|
300
|
+
* Log error-level message
|
|
301
|
+
*/
|
|
302
|
+
error(message, error, context) {
|
|
303
|
+
if (this.shouldLog(LogLevel.ERROR)) {
|
|
304
|
+
const logData = this.buildLogData("error", message, context, error);
|
|
305
|
+
this.output(console.error, logData);
|
|
306
|
+
}
|
|
307
|
+
}
|
|
308
|
+
/**
|
|
309
|
+
* Create a child logger with additional context
|
|
310
|
+
*/
|
|
311
|
+
child(context) {
|
|
312
|
+
return new CloudflareLogger({
|
|
313
|
+
...this.baseContext,
|
|
314
|
+
...context
|
|
315
|
+
}, this.minLevel, this.pretty);
|
|
316
|
+
}
|
|
317
|
+
/**
|
|
318
|
+
* Check if a log level should be output
|
|
319
|
+
*/
|
|
320
|
+
shouldLog(level) {
|
|
321
|
+
return level >= this.minLevel;
|
|
322
|
+
}
|
|
323
|
+
/**
|
|
324
|
+
* Build log data object
|
|
325
|
+
*/
|
|
326
|
+
buildLogData(level, message, context, error) {
|
|
327
|
+
const logData = {
|
|
328
|
+
level,
|
|
329
|
+
msg: message,
|
|
330
|
+
...this.baseContext,
|
|
331
|
+
...context,
|
|
332
|
+
timestamp: (/* @__PURE__ */ new Date()).toISOString()
|
|
333
|
+
};
|
|
334
|
+
if (error) logData.error = {
|
|
335
|
+
message: error.message,
|
|
336
|
+
stack: error.stack,
|
|
337
|
+
name: error.name
|
|
338
|
+
};
|
|
339
|
+
return logData;
|
|
340
|
+
}
|
|
341
|
+
/**
|
|
342
|
+
* Output log data to console (pretty or JSON)
|
|
343
|
+
*/
|
|
344
|
+
output(consoleFn, data) {
|
|
345
|
+
if (this.pretty) this.outputPretty(consoleFn, data);
|
|
346
|
+
else this.outputJson(consoleFn, data);
|
|
347
|
+
}
|
|
348
|
+
/**
|
|
349
|
+
* Output as JSON (production)
|
|
350
|
+
*/
|
|
351
|
+
outputJson(consoleFn, data) {
|
|
352
|
+
consoleFn(JSON.stringify(data));
|
|
353
|
+
}
|
|
354
|
+
/**
|
|
355
|
+
* Output as pretty-printed, colored text (development)
|
|
356
|
+
*
|
|
357
|
+
* Format: LEVEL [component] message (trace: tr_...) {context}
|
|
358
|
+
* Example: INFO [sandbox-do] Command started (trace: tr_7f3a9b2c) {commandId: "cmd-123"}
|
|
359
|
+
*/
|
|
360
|
+
outputPretty(consoleFn, data) {
|
|
361
|
+
const { level, msg, timestamp, traceId, component, sandboxId, sessionId, processId, commandId, operation, duration, error, ...rest } = data;
|
|
362
|
+
const levelStr = String(level || "INFO").toUpperCase();
|
|
363
|
+
const levelColor = this.getLevelColor(levelStr);
|
|
364
|
+
const componentBadge = component ? `[${component}]` : "";
|
|
365
|
+
const traceIdShort = traceId ? String(traceId).substring(0, 12) : "";
|
|
366
|
+
let logLine = `${levelColor}${levelStr.padEnd(5)}${COLORS.reset} ${componentBadge} ${msg}`;
|
|
367
|
+
if (traceIdShort) logLine += ` ${COLORS.dim}(trace: ${traceIdShort})${COLORS.reset}`;
|
|
368
|
+
const contextFields = [];
|
|
369
|
+
if (operation) contextFields.push(`operation: ${operation}`);
|
|
370
|
+
if (commandId) contextFields.push(`commandId: ${String(commandId).substring(0, 12)}`);
|
|
371
|
+
if (sandboxId) contextFields.push(`sandboxId: ${sandboxId}`);
|
|
372
|
+
if (sessionId) contextFields.push(`sessionId: ${String(sessionId).substring(0, 12)}`);
|
|
373
|
+
if (processId) contextFields.push(`processId: ${processId}`);
|
|
374
|
+
if (duration !== void 0) contextFields.push(`duration: ${duration}ms`);
|
|
375
|
+
if (contextFields.length > 0) logLine += ` ${COLORS.dim}{${contextFields.join(", ")}}${COLORS.reset}`;
|
|
376
|
+
consoleFn(logLine);
|
|
377
|
+
if (error && typeof error === "object") {
|
|
378
|
+
const errorObj = error;
|
|
379
|
+
if (errorObj.message) consoleFn(` ${COLORS.error}Error: ${errorObj.message}${COLORS.reset}`);
|
|
380
|
+
if (errorObj.stack) consoleFn(` ${COLORS.dim}${errorObj.stack}${COLORS.reset}`);
|
|
381
|
+
}
|
|
382
|
+
if (Object.keys(rest).length > 0) consoleFn(` ${COLORS.dim}${JSON.stringify(rest, null, 2)}${COLORS.reset}`);
|
|
383
|
+
}
|
|
384
|
+
/**
|
|
385
|
+
* Get ANSI color code for log level
|
|
386
|
+
*/
|
|
387
|
+
getLevelColor(level) {
|
|
388
|
+
switch (level.toLowerCase()) {
|
|
389
|
+
case "debug": return COLORS.debug;
|
|
390
|
+
case "info": return COLORS.info;
|
|
391
|
+
case "warn": return COLORS.warn;
|
|
392
|
+
case "error": return COLORS.error;
|
|
393
|
+
default: return COLORS.reset;
|
|
394
|
+
}
|
|
395
|
+
}
|
|
396
|
+
};
|
|
397
|
+
|
|
398
|
+
//#endregion
|
|
399
|
+
//#region ../shared/dist/logger/trace-context.js
|
|
400
|
+
/**
|
|
401
|
+
* Trace context utilities for request correlation
|
|
402
|
+
*
|
|
403
|
+
* Trace IDs enable correlating logs across distributed components:
|
|
404
|
+
* Worker → Durable Object → Container → back
|
|
405
|
+
*
|
|
406
|
+
* The trace ID is propagated via the X-Trace-Id HTTP header.
|
|
407
|
+
*/
|
|
408
|
+
/**
|
|
409
|
+
* Utility for managing trace context across distributed components
|
|
410
|
+
*/
|
|
411
|
+
var TraceContext = class TraceContext {
|
|
412
|
+
/**
|
|
413
|
+
* HTTP header name for trace ID propagation
|
|
414
|
+
*/
|
|
415
|
+
static TRACE_HEADER = "X-Trace-Id";
|
|
416
|
+
/**
|
|
417
|
+
* Generate a new trace ID
|
|
418
|
+
*
|
|
419
|
+
* Format: "tr_" + 16 random hex characters
|
|
420
|
+
* Example: "tr_7f3a9b2c4e5d6f1a"
|
|
421
|
+
*
|
|
422
|
+
* @returns Newly generated trace ID
|
|
423
|
+
*/
|
|
424
|
+
static generate() {
|
|
425
|
+
return `tr_${crypto.randomUUID().replace(/-/g, "").substring(0, 16)}`;
|
|
426
|
+
}
|
|
427
|
+
/**
|
|
428
|
+
* Extract trace ID from HTTP request headers
|
|
429
|
+
*
|
|
430
|
+
* @param headers Request headers
|
|
431
|
+
* @returns Trace ID if present, null otherwise
|
|
432
|
+
*/
|
|
433
|
+
static fromHeaders(headers) {
|
|
434
|
+
return headers.get(TraceContext.TRACE_HEADER);
|
|
435
|
+
}
|
|
436
|
+
/**
|
|
437
|
+
* Create headers object with trace ID for outgoing requests
|
|
438
|
+
*
|
|
439
|
+
* @param traceId Trace ID to include
|
|
440
|
+
* @returns Headers object with X-Trace-Id set
|
|
441
|
+
*/
|
|
442
|
+
static toHeaders(traceId) {
|
|
443
|
+
return { [TraceContext.TRACE_HEADER]: traceId };
|
|
444
|
+
}
|
|
445
|
+
/**
|
|
446
|
+
* Get the header name used for trace ID propagation
|
|
447
|
+
*
|
|
448
|
+
* @returns Header name ("X-Trace-Id")
|
|
449
|
+
*/
|
|
450
|
+
static getHeaderName() {
|
|
451
|
+
return TraceContext.TRACE_HEADER;
|
|
452
|
+
}
|
|
453
|
+
};
|
|
454
|
+
|
|
455
|
+
//#endregion
|
|
456
|
+
//#region ../shared/dist/logger/index.js
|
|
457
|
+
/**
|
|
458
|
+
* Logger module
|
|
459
|
+
*
|
|
460
|
+
* Provides structured, trace-aware logging with:
|
|
461
|
+
* - Explicit logger passing via constructor injection
|
|
462
|
+
* - Pretty printing for local development
|
|
463
|
+
* - JSON output for production
|
|
464
|
+
* - Environment auto-detection
|
|
465
|
+
* - Log level configuration
|
|
466
|
+
*
|
|
467
|
+
* Usage:
|
|
468
|
+
*
|
|
469
|
+
* ```typescript
|
|
470
|
+
* // Create a logger at entry point
|
|
471
|
+
* const logger = createLogger({ component: 'sandbox-do', traceId: 'tr_abc123' });
|
|
472
|
+
*
|
|
473
|
+
* // Pass to classes via constructor
|
|
474
|
+
* const service = new MyService(logger);
|
|
475
|
+
*
|
|
476
|
+
* // Create child loggers for additional context
|
|
477
|
+
* const execLogger = logger.child({ operation: 'exec', commandId: 'cmd-456' });
|
|
478
|
+
* execLogger.info('Operation started');
|
|
479
|
+
* ```
|
|
480
|
+
*/
|
|
481
|
+
/**
|
|
482
|
+
* Create a no-op logger for testing
|
|
483
|
+
*
|
|
484
|
+
* Returns a logger that implements the Logger interface but does nothing.
|
|
485
|
+
* Useful for tests that don't need actual logging output.
|
|
486
|
+
*
|
|
487
|
+
* @returns No-op logger instance
|
|
488
|
+
*
|
|
489
|
+
* @example
|
|
490
|
+
* ```typescript
|
|
491
|
+
* // In tests
|
|
492
|
+
* const client = new HttpClient({
|
|
493
|
+
* baseUrl: 'http://test.com',
|
|
494
|
+
* logger: createNoOpLogger() // Optional - tests can enable real logging if needed
|
|
495
|
+
* });
|
|
496
|
+
* ```
|
|
497
|
+
*/
|
|
498
|
+
function createNoOpLogger() {
|
|
499
|
+
return {
|
|
500
|
+
debug: () => {},
|
|
501
|
+
info: () => {},
|
|
502
|
+
warn: () => {},
|
|
503
|
+
error: () => {},
|
|
504
|
+
child: () => createNoOpLogger()
|
|
505
|
+
};
|
|
506
|
+
}
|
|
507
|
+
/**
|
|
508
|
+
* Create a new logger instance
|
|
509
|
+
*
|
|
510
|
+
* @param context Base context for the logger. Must include 'component'.
|
|
511
|
+
* TraceId will be auto-generated if not provided.
|
|
512
|
+
* @returns New logger instance
|
|
513
|
+
*
|
|
514
|
+
* @example
|
|
515
|
+
* ```typescript
|
|
516
|
+
* // In Durable Object
|
|
517
|
+
* const logger = createLogger({
|
|
518
|
+
* component: 'sandbox-do',
|
|
519
|
+
* traceId: TraceContext.fromHeaders(request.headers) || TraceContext.generate(),
|
|
520
|
+
* sandboxId: this.id
|
|
521
|
+
* });
|
|
522
|
+
*
|
|
523
|
+
* // In Container
|
|
524
|
+
* const logger = createLogger({
|
|
525
|
+
* component: 'container',
|
|
526
|
+
* traceId: TraceContext.fromHeaders(request.headers)!,
|
|
527
|
+
* sessionId: this.id
|
|
528
|
+
* });
|
|
529
|
+
* ```
|
|
530
|
+
*/
|
|
531
|
+
function createLogger(context) {
|
|
532
|
+
const minLevel = getLogLevelFromEnv();
|
|
533
|
+
const pretty = isPrettyPrintEnabled();
|
|
534
|
+
return new CloudflareLogger({
|
|
535
|
+
...context,
|
|
536
|
+
traceId: context.traceId || TraceContext.generate(),
|
|
537
|
+
component: context.component
|
|
538
|
+
}, minLevel, pretty);
|
|
539
|
+
}
|
|
540
|
+
/**
|
|
541
|
+
* Get log level from environment variable
|
|
542
|
+
*
|
|
543
|
+
* Checks SANDBOX_LOG_LEVEL env var, falls back to default based on environment.
|
|
544
|
+
* Default: 'debug' for development, 'info' for production
|
|
545
|
+
*/
|
|
546
|
+
function getLogLevelFromEnv() {
|
|
547
|
+
switch ((getEnvVar("SANDBOX_LOG_LEVEL") || "info").toLowerCase()) {
|
|
548
|
+
case "debug": return LogLevel.DEBUG;
|
|
549
|
+
case "info": return LogLevel.INFO;
|
|
550
|
+
case "warn": return LogLevel.WARN;
|
|
551
|
+
case "error": return LogLevel.ERROR;
|
|
552
|
+
default: return LogLevel.INFO;
|
|
553
|
+
}
|
|
554
|
+
}
|
|
555
|
+
/**
|
|
556
|
+
* Check if pretty printing should be enabled
|
|
557
|
+
*
|
|
558
|
+
* Checks SANDBOX_LOG_FORMAT env var, falls back to auto-detection:
|
|
559
|
+
* - Local development: pretty (colored, human-readable)
|
|
560
|
+
* - Production: json (structured)
|
|
561
|
+
*/
|
|
562
|
+
function isPrettyPrintEnabled() {
|
|
563
|
+
const format = getEnvVar("SANDBOX_LOG_FORMAT");
|
|
564
|
+
if (format) return format.toLowerCase() === "pretty";
|
|
565
|
+
return false;
|
|
566
|
+
}
|
|
567
|
+
/**
|
|
568
|
+
* Get environment variable value
|
|
569
|
+
*
|
|
570
|
+
* Supports both Node.js (process.env) and Bun (Bun.env)
|
|
571
|
+
*/
|
|
572
|
+
function getEnvVar(name) {
|
|
573
|
+
if (typeof process !== "undefined" && process.env) return process.env[name];
|
|
574
|
+
if (typeof Bun !== "undefined") {
|
|
575
|
+
const bunEnv = Bun.env;
|
|
576
|
+
if (bunEnv) return bunEnv[name];
|
|
577
|
+
}
|
|
578
|
+
}
|
|
579
|
+
|
|
580
|
+
//#endregion
|
|
581
|
+
//#region ../shared/dist/shell-escape.js
|
|
582
|
+
/**
|
|
583
|
+
* Escapes a string for safe use in shell commands using POSIX single-quote escaping.
|
|
584
|
+
* Prevents command injection by wrapping the string in single quotes and escaping
|
|
585
|
+
* any single quotes within the string.
|
|
586
|
+
*/
|
|
587
|
+
function shellEscape(str) {
|
|
588
|
+
return `'${str.replace(/'/g, "'\\''")}'`;
|
|
589
|
+
}
|
|
590
|
+
|
|
591
|
+
//#endregion
|
|
592
|
+
//#region ../shared/dist/types.js
|
|
593
|
+
function isExecResult(value) {
|
|
594
|
+
return value && typeof value.success === "boolean" && typeof value.exitCode === "number" && typeof value.stdout === "string" && typeof value.stderr === "string";
|
|
595
|
+
}
|
|
596
|
+
function isProcess(value) {
|
|
597
|
+
return value && typeof value.id === "string" && typeof value.command === "string" && typeof value.status === "string";
|
|
598
|
+
}
|
|
599
|
+
function isProcessStatus(value) {
|
|
600
|
+
return [
|
|
601
|
+
"starting",
|
|
602
|
+
"running",
|
|
603
|
+
"completed",
|
|
604
|
+
"failed",
|
|
605
|
+
"killed",
|
|
606
|
+
"error"
|
|
607
|
+
].includes(value);
|
|
608
|
+
}
|
|
609
|
+
|
|
610
|
+
//#endregion
|
|
611
|
+
export { createLogger as a, Execution as c, getEnvString as d, shellEscape as i, ResultImpl as l, isProcess as n, createNoOpLogger as o, isProcessStatus as r, TraceContext as s, isExecResult as t, GitLogger as u };
|
|
612
|
+
//# sourceMappingURL=dist-gVyG2H2h.js.map
|