@cloudflare/sandbox 0.0.0-18fac92 → 0.0.0-211d237

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/README.md CHANGED
@@ -1,7 +1,5 @@
1
1
  ## @cloudflare/sandbox
2
2
 
3
- > **⚠️ Experimental** - This library is currently experimental and we're actively seeking feedback. Please try it out and let us know what you think!
4
-
5
3
  A library to spin up a sandboxed environment.
6
4
 
7
5
  First, setup your wrangler.json to use the sandbox:
@@ -58,7 +56,6 @@ export default {
58
56
  - `gitCheckout(repoUrl: string, options: { branch?: string; targetDir?: string; stream?: boolean })`: Checkout a git repository in the sandbox.
59
57
  - `mkdir(path: string, options: { recursive?: boolean; stream?: boolean })`: Create a directory in the sandbox.
60
58
  - `writeFile(path: string, content: string, options: { encoding?: string; stream?: boolean })`: Write content to a file in the sandbox.
61
- - `readFile(path: string, options: { encoding?: string; stream?: boolean })`: Read content from a file in the sandbox.
62
59
  - `deleteFile(path: string, options?: { stream?: boolean })`: Delete a file from the sandbox.
63
60
  - `renameFile(oldPath: string, newPath: string, options?: { stream?: boolean })`: Rename a file in the sandbox.
64
61
  - `moveFile(sourcePath: string, destinationPath: string, options?: { stream?: boolean })`: Move a file from one location to another in the sandbox.
@@ -1,5 +1,5 @@
1
1
  import { spawn } from "node:child_process";
2
- import { mkdir, readFile, rename, unlink, writeFile } from "node:fs/promises";
2
+ import { mkdir, rename, unlink, writeFile } from "node:fs/promises";
3
3
  import { dirname } from "node:path";
4
4
  import { serve } from "bun";
5
5
 
@@ -28,12 +28,6 @@ interface WriteFileRequest {
28
28
  sessionId?: string;
29
29
  }
30
30
 
31
- interface ReadFileRequest {
32
- path: string;
33
- encoding?: string;
34
- sessionId?: string;
35
- }
36
-
37
31
  interface DeleteFileRequest {
38
32
  path: string;
39
33
  sessionId?: string;
@@ -84,8 +78,6 @@ const server = serve({
84
78
  const url = new URL(req.url);
85
79
  const pathname = url.pathname;
86
80
 
87
- console.log(`[Container] Incoming ${req.method} request to ${pathname}`);
88
-
89
81
  // Handle CORS
90
82
  const corsHeaders = {
91
83
  "Access-Control-Allow-Headers": "Content-Type, Authorization",
@@ -95,13 +87,11 @@ const server = serve({
95
87
 
96
88
  // Handle preflight requests
97
89
  if (req.method === "OPTIONS") {
98
- console.log(`[Container] Handling CORS preflight for ${pathname}`);
99
90
  return new Response(null, { headers: corsHeaders, status: 200 });
100
91
  }
101
92
 
102
93
  try {
103
94
  // Handle different routes
104
- console.log(`[Container] Processing ${req.method} ${pathname}`);
105
95
  switch (pathname) {
106
96
  case "/":
107
97
  return new Response("Hello from Bun server! 🚀", {
@@ -307,18 +297,6 @@ const server = serve({
307
297
  }
308
298
  break;
309
299
 
310
- case "/api/read":
311
- if (req.method === "POST") {
312
- return handleReadFileRequest(req, corsHeaders);
313
- }
314
- break;
315
-
316
- case "/api/read/stream":
317
- if (req.method === "POST") {
318
- return handleStreamingReadFileRequest(req, corsHeaders);
319
- }
320
- break;
321
-
322
300
  case "/api/delete":
323
301
  if (req.method === "POST") {
324
302
  return handleDeleteFileRequest(req, corsHeaders);
@@ -356,14 +334,13 @@ const server = serve({
356
334
  break;
357
335
 
358
336
  default:
359
- console.log(`[Container] Route not found: ${pathname}`);
360
337
  return new Response("Not Found", {
361
338
  headers: corsHeaders,
362
339
  status: 404,
363
340
  });
364
341
  }
365
342
  } catch (error) {
366
- console.error(`[Container] Error handling ${req.method} ${pathname}:`, error);
343
+ console.error("[Server] Error handling request:", error);
367
344
  return new Response(
368
345
  JSON.stringify({
369
346
  error: "Internal server error",
@@ -379,7 +356,6 @@ const server = serve({
379
356
  );
380
357
  }
381
358
  },
382
- hostname: "0.0.0.0",
383
359
  port: 3000,
384
360
  } as any);
385
361
 
@@ -1500,235 +1476,6 @@ async function handleStreamingWriteFileRequest(
1500
1476
  }
1501
1477
  }
1502
1478
 
1503
- async function handleReadFileRequest(
1504
- req: Request,
1505
- corsHeaders: Record<string, string>
1506
- ): Promise<Response> {
1507
- try {
1508
- const body = (await req.json()) as ReadFileRequest;
1509
- const { path, encoding = "utf-8", sessionId } = body;
1510
-
1511
- if (!path || typeof path !== "string") {
1512
- return new Response(
1513
- JSON.stringify({
1514
- error: "Path is required and must be a string",
1515
- }),
1516
- {
1517
- headers: {
1518
- "Content-Type": "application/json",
1519
- ...corsHeaders,
1520
- },
1521
- status: 400,
1522
- }
1523
- );
1524
- }
1525
-
1526
- // Basic safety check - prevent dangerous paths
1527
- const dangerousPatterns = [
1528
- /^\/$/, // Root directory
1529
- /^\/etc/, // System directories
1530
- /^\/var/, // System directories
1531
- /^\/usr/, // System directories
1532
- /^\/bin/, // System directories
1533
- /^\/sbin/, // System directories
1534
- /^\/boot/, // System directories
1535
- /^\/dev/, // System directories
1536
- /^\/proc/, // System directories
1537
- /^\/sys/, // System directories
1538
- /^\/tmp\/\.\./, // Path traversal attempts
1539
- /\.\./, // Path traversal attempts
1540
- ];
1541
-
1542
- if (dangerousPatterns.some((pattern) => pattern.test(path))) {
1543
- return new Response(
1544
- JSON.stringify({
1545
- error: "Dangerous path not allowed",
1546
- }),
1547
- {
1548
- headers: {
1549
- "Content-Type": "application/json",
1550
- ...corsHeaders,
1551
- },
1552
- status: 400,
1553
- }
1554
- );
1555
- }
1556
-
1557
- console.log(`[Server] Reading file: ${path}`);
1558
-
1559
- const result = await executeReadFile(path, encoding, sessionId);
1560
-
1561
- return new Response(
1562
- JSON.stringify({
1563
- content: result.content,
1564
- exitCode: result.exitCode,
1565
- path,
1566
- success: result.success,
1567
- timestamp: new Date().toISOString(),
1568
- }),
1569
- {
1570
- headers: {
1571
- "Content-Type": "application/json",
1572
- ...corsHeaders,
1573
- },
1574
- }
1575
- );
1576
- } catch (error) {
1577
- console.error("[Server] Error in handleReadFileRequest:", error);
1578
- return new Response(
1579
- JSON.stringify({
1580
- error: "Failed to read file",
1581
- message: error instanceof Error ? error.message : "Unknown error",
1582
- }),
1583
- {
1584
- headers: {
1585
- "Content-Type": "application/json",
1586
- ...corsHeaders,
1587
- },
1588
- status: 500,
1589
- }
1590
- );
1591
- }
1592
- }
1593
-
1594
- async function handleStreamingReadFileRequest(
1595
- req: Request,
1596
- corsHeaders: Record<string, string>
1597
- ): Promise<Response> {
1598
- try {
1599
- const body = (await req.json()) as ReadFileRequest;
1600
- const { path, encoding = "utf-8", sessionId } = body;
1601
-
1602
- if (!path || typeof path !== "string") {
1603
- return new Response(
1604
- JSON.stringify({
1605
- error: "Path is required and must be a string",
1606
- }),
1607
- {
1608
- headers: {
1609
- "Content-Type": "application/json",
1610
- ...corsHeaders,
1611
- },
1612
- status: 400,
1613
- }
1614
- );
1615
- }
1616
-
1617
- // Basic safety check - prevent dangerous paths
1618
- const dangerousPatterns = [
1619
- /^\/$/, // Root directory
1620
- /^\/etc/, // System directories
1621
- /^\/var/, // System directories
1622
- /^\/usr/, // System directories
1623
- /^\/bin/, // System directories
1624
- /^\/sbin/, // System directories
1625
- /^\/boot/, // System directories
1626
- /^\/dev/, // System directories
1627
- /^\/proc/, // System directories
1628
- /^\/sys/, // System directories
1629
- /^\/tmp\/\.\./, // Path traversal attempts
1630
- /\.\./, // Path traversal attempts
1631
- ];
1632
-
1633
- if (dangerousPatterns.some((pattern) => pattern.test(path))) {
1634
- return new Response(
1635
- JSON.stringify({
1636
- error: "Dangerous path not allowed",
1637
- }),
1638
- {
1639
- headers: {
1640
- "Content-Type": "application/json",
1641
- ...corsHeaders,
1642
- },
1643
- status: 400,
1644
- }
1645
- );
1646
- }
1647
-
1648
- console.log(`[Server] Reading file (streaming): ${path}`);
1649
-
1650
- const stream = new ReadableStream({
1651
- start(controller) {
1652
- (async () => {
1653
- try {
1654
- // Send command start event
1655
- controller.enqueue(
1656
- new TextEncoder().encode(
1657
- `data: ${JSON.stringify({
1658
- path,
1659
- timestamp: new Date().toISOString(),
1660
- type: "command_start",
1661
- })}\n\n`
1662
- )
1663
- );
1664
-
1665
- // Read the file
1666
- const content = await readFile(path, {
1667
- encoding: encoding as BufferEncoding,
1668
- });
1669
-
1670
- console.log(`[Server] File read successfully: ${path}`);
1671
-
1672
- // Send command completion event
1673
- controller.enqueue(
1674
- new TextEncoder().encode(
1675
- `data: ${JSON.stringify({
1676
- content,
1677
- path,
1678
- success: true,
1679
- timestamp: new Date().toISOString(),
1680
- type: "command_complete",
1681
- })}\n\n`
1682
- )
1683
- );
1684
-
1685
- controller.close();
1686
- } catch (error) {
1687
- console.error(`[Server] Error reading file: ${path}`, error);
1688
-
1689
- controller.enqueue(
1690
- new TextEncoder().encode(
1691
- `data: ${JSON.stringify({
1692
- error:
1693
- error instanceof Error ? error.message : "Unknown error",
1694
- path,
1695
- type: "error",
1696
- })}\n\n`
1697
- )
1698
- );
1699
-
1700
- controller.close();
1701
- }
1702
- })();
1703
- },
1704
- });
1705
-
1706
- return new Response(stream, {
1707
- headers: {
1708
- "Cache-Control": "no-cache",
1709
- Connection: "keep-alive",
1710
- "Content-Type": "text/event-stream",
1711
- ...corsHeaders,
1712
- },
1713
- });
1714
- } catch (error) {
1715
- console.error("[Server] Error in handleStreamingReadFileRequest:", error);
1716
- return new Response(
1717
- JSON.stringify({
1718
- error: "Failed to read file",
1719
- message: error instanceof Error ? error.message : "Unknown error",
1720
- }),
1721
- {
1722
- headers: {
1723
- "Content-Type": "application/json",
1724
- ...corsHeaders,
1725
- },
1726
- status: 500,
1727
- }
1728
- );
1729
- }
1730
- }
1731
-
1732
1479
  async function handleDeleteFileRequest(
1733
1480
  req: Request,
1734
1481
  corsHeaders: Record<string, string>
@@ -2759,37 +2506,6 @@ function executeWriteFile(
2759
2506
  });
2760
2507
  }
2761
2508
 
2762
- function executeReadFile(
2763
- path: string,
2764
- encoding: string,
2765
- sessionId?: string
2766
- ): Promise<{
2767
- success: boolean;
2768
- exitCode: number;
2769
- content: string;
2770
- }> {
2771
- return new Promise((resolve, reject) => {
2772
- (async () => {
2773
- try {
2774
- // Read the file
2775
- const content = await readFile(path, {
2776
- encoding: encoding as BufferEncoding,
2777
- });
2778
-
2779
- console.log(`[Server] File read successfully: ${path}`);
2780
- resolve({
2781
- content,
2782
- exitCode: 0,
2783
- success: true,
2784
- });
2785
- } catch (error) {
2786
- console.error(`[Server] Error reading file: ${path}`, error);
2787
- reject(error);
2788
- }
2789
- })();
2790
- });
2791
- }
2792
-
2793
2509
  function executeDeleteFile(
2794
2510
  path: string,
2795
2511
  sessionId?: string
@@ -2880,7 +2596,7 @@ function executeMoveFile(
2880
2596
  });
2881
2597
  }
2882
2598
 
2883
- console.log(`🚀 Bun server running on http://0.0.0.0:${server.port}`);
2599
+ console.log(`🚀 Bun server running on http://localhost:${server.port}`);
2884
2600
  console.log(`📡 HTTP API endpoints available:`);
2885
2601
  console.log(` POST /api/session/create - Create a new session`);
2886
2602
  console.log(` GET /api/session/list - List all sessions`);
@@ -2894,8 +2610,6 @@ console.log(` POST /api/mkdir - Create a directory`);
2894
2610
  console.log(` POST /api/mkdir/stream - Create a directory (streaming)`);
2895
2611
  console.log(` POST /api/write - Write a file`);
2896
2612
  console.log(` POST /api/write/stream - Write a file (streaming)`);
2897
- console.log(` POST /api/read - Read a file`);
2898
- console.log(` POST /api/read/stream - Read a file (streaming)`);
2899
2613
  console.log(` POST /api/delete - Delete a file`);
2900
2614
  console.log(` POST /api/delete/stream - Delete a file (streaming)`);
2901
2615
  console.log(` POST /api/rename - Rename a file`);
package/package.json CHANGED
@@ -1,13 +1,13 @@
1
1
  {
2
2
  "name": "@cloudflare/sandbox",
3
- "version": "0.0.0-18fac92",
3
+ "version": "0.0.0-211d237",
4
4
  "repository": {
5
5
  "type": "git",
6
6
  "url": "https://github.com/cloudflare/sandbox-sdk"
7
7
  },
8
8
  "description": "A sandboxed environment for running commands",
9
9
  "dependencies": {
10
- "@cloudflare/containers": "^0.0.13"
10
+ "@cloudflare/containers": "^0.0.8"
11
11
  },
12
12
  "tags": [
13
13
  "sandbox",
@@ -17,9 +17,7 @@
17
17
  "durable objects"
18
18
  ],
19
19
  "scripts": {
20
- "build": "rm -rf dist && tsup src/*.ts --outDir dist --dts --sourcemap --format esm",
21
- "docker:build": "docker build -t ghostwriternr/cloudflare-sandbox:$npm_package_version .",
22
- "docker:publish": "docker push docker.io/ghostwriternr/cloudflare-sandbox:$npm_package_version"
20
+ "build": "tsup src/*.ts --outDir dist --dts --sourcemap --format esm"
23
21
  },
24
22
  "exports": {
25
23
  ".": {
package/src/client.ts CHANGED
@@ -85,20 +85,6 @@ export interface WriteFileResponse {
85
85
  timestamp: string;
86
86
  }
87
87
 
88
- interface ReadFileRequest {
89
- path: string;
90
- encoding?: string;
91
- sessionId?: string;
92
- }
93
-
94
- export interface ReadFileResponse {
95
- success: boolean;
96
- exitCode: number;
97
- path: string;
98
- content: string;
99
- timestamp: string;
100
- }
101
-
102
88
  interface DeleteFileRequest {
103
89
  path: string;
104
90
  sessionId?: string;
@@ -156,7 +142,6 @@ interface StreamEvent {
156
142
  newPath?: string;
157
143
  sourcePath?: string;
158
144
  destinationPath?: string;
159
- content?: string;
160
145
  success?: boolean;
161
146
  exitCode?: number;
162
147
  stdout?: string;
@@ -203,31 +188,10 @@ export class HttpClient {
203
188
  path: string,
204
189
  options?: RequestInit
205
190
  ): Promise<Response> {
206
- const url = this.options.stub ? `stub:${path}` : `${this.baseUrl}${path}`;
207
- const method = options?.method || "GET";
208
-
209
- console.log(`[HTTP Client] Making ${method} request to ${url}`);
210
-
211
- try {
212
- let response: Response;
213
-
214
- if (this.options.stub) {
215
- response = await this.options.stub.containerFetch(this.baseUrl + path, options, this.options.port);
216
- } else {
217
- response = await fetch(this.baseUrl + path, options);
218
- }
219
-
220
- console.log(`[HTTP Client] Response: ${response.status} ${response.statusText}`);
221
-
222
- if (!response.ok) {
223
- console.error(`[HTTP Client] Request failed: ${method} ${url} - ${response.status} ${response.statusText}`);
224
- }
225
-
226
- return response;
227
- } catch (error) {
228
- console.error(`[HTTP Client] Request error: ${method} ${url}`, error);
229
- throw error;
191
+ if (this.options.stub) {
192
+ return this.options.stub.containerFetch(path, options, this.options.port);
230
193
  }
194
+ return fetch(this.baseUrl + path, options);
231
195
  }
232
196
  // Public methods to set event handlers
233
197
  setOnOutput(
@@ -1014,164 +978,6 @@ export class HttpClient {
1014
978
  }
1015
979
  }
1016
980
 
1017
- async readFile(
1018
- path: string,
1019
- encoding: string = "utf-8",
1020
- sessionId?: string
1021
- ): Promise<ReadFileResponse> {
1022
- try {
1023
- const targetSessionId = sessionId || this.sessionId;
1024
-
1025
- const response = await this.doFetch(`/api/read`, {
1026
- body: JSON.stringify({
1027
- encoding,
1028
- path,
1029
- sessionId: targetSessionId,
1030
- }),
1031
- headers: {
1032
- "Content-Type": "application/json",
1033
- },
1034
- method: "POST",
1035
- });
1036
-
1037
- if (!response.ok) {
1038
- const errorData = (await response.json().catch(() => ({}))) as {
1039
- error?: string;
1040
- };
1041
- throw new Error(
1042
- errorData.error || `HTTP error! status: ${response.status}`
1043
- );
1044
- }
1045
-
1046
- const data: ReadFileResponse = await response.json();
1047
- console.log(
1048
- `[HTTP Client] File read: ${path}, Success: ${data.success}, Content length: ${data.content.length}`
1049
- );
1050
-
1051
- return data;
1052
- } catch (error) {
1053
- console.error("[HTTP Client] Error reading file:", error);
1054
- throw error;
1055
- }
1056
- }
1057
-
1058
- async readFileStream(
1059
- path: string,
1060
- encoding: string = "utf-8",
1061
- sessionId?: string
1062
- ): Promise<void> {
1063
- try {
1064
- const targetSessionId = sessionId || this.sessionId;
1065
-
1066
- const response = await this.doFetch(`/api/read/stream`, {
1067
- body: JSON.stringify({
1068
- encoding,
1069
- path,
1070
- sessionId: targetSessionId,
1071
- }),
1072
- headers: {
1073
- "Content-Type": "application/json",
1074
- },
1075
- method: "POST",
1076
- });
1077
-
1078
- if (!response.ok) {
1079
- const errorData = (await response.json().catch(() => ({}))) as {
1080
- error?: string;
1081
- };
1082
- throw new Error(
1083
- errorData.error || `HTTP error! status: ${response.status}`
1084
- );
1085
- }
1086
-
1087
- if (!response.body) {
1088
- throw new Error("No response body for streaming request");
1089
- }
1090
-
1091
- const reader = response.body.getReader();
1092
- const decoder = new TextDecoder();
1093
-
1094
- try {
1095
- while (true) {
1096
- const { done, value } = await reader.read();
1097
-
1098
- if (done) {
1099
- break;
1100
- }
1101
-
1102
- const chunk = decoder.decode(value, { stream: true });
1103
- const lines = chunk.split("\n");
1104
-
1105
- for (const line of lines) {
1106
- if (line.startsWith("data: ")) {
1107
- try {
1108
- const eventData = line.slice(6); // Remove 'data: ' prefix
1109
- const event: StreamEvent = JSON.parse(eventData);
1110
-
1111
- console.log(
1112
- `[HTTP Client] Read file stream event: ${event.type}`
1113
- );
1114
- this.options.onStreamEvent?.(event);
1115
-
1116
- switch (event.type) {
1117
- case "command_start":
1118
- console.log(
1119
- `[HTTP Client] Read file started: ${event.path}`
1120
- );
1121
- this.options.onCommandStart?.("read", [path, encoding]);
1122
- break;
1123
-
1124
- case "command_complete":
1125
- console.log(
1126
- `[HTTP Client] Read file completed: ${
1127
- event.path
1128
- }, Success: ${event.success}, Content length: ${
1129
- event.content?.length || 0
1130
- }`
1131
- );
1132
- this.options.onCommandComplete?.(
1133
- event.success!,
1134
- 0,
1135
- event.content || "",
1136
- "",
1137
- "read",
1138
- [path, encoding]
1139
- );
1140
- break;
1141
-
1142
- case "error":
1143
- console.error(
1144
- `[HTTP Client] Read file error: ${event.error}`
1145
- );
1146
- this.options.onError?.(event.error!, "read", [
1147
- path,
1148
- encoding,
1149
- ]);
1150
- break;
1151
- }
1152
- } catch (parseError) {
1153
- console.warn(
1154
- "[HTTP Client] Failed to parse read file stream event:",
1155
- parseError
1156
- );
1157
- }
1158
- }
1159
- }
1160
- }
1161
- } finally {
1162
- reader.releaseLock();
1163
- }
1164
- } catch (error) {
1165
- console.error("[HTTP Client] Error in streaming read file:", error);
1166
- this.options.onError?.(
1167
- error instanceof Error ? error.message : "Unknown error",
1168
- "read",
1169
- [path, encoding]
1170
- );
1171
- throw error;
1172
- }
1173
- }
1174
-
1175
981
  async deleteFile(
1176
982
  path: string,
1177
983
  sessionId?: string
@@ -1823,38 +1629,6 @@ export async function quickWriteFileStream(
1823
1629
  }
1824
1630
  }
1825
1631
 
1826
- // Convenience function for quick file reading
1827
- export async function quickReadFile(
1828
- path: string,
1829
- encoding: string = "utf-8",
1830
- options?: HttpClientOptions
1831
- ): Promise<ReadFileResponse> {
1832
- const client = createClient(options);
1833
- await client.createSession();
1834
-
1835
- try {
1836
- return await client.readFile(path, encoding);
1837
- } finally {
1838
- client.clearSession();
1839
- }
1840
- }
1841
-
1842
- // Convenience function for quick streaming file reading
1843
- export async function quickReadFileStream(
1844
- path: string,
1845
- encoding: string = "utf-8",
1846
- options?: HttpClientOptions
1847
- ): Promise<void> {
1848
- const client = createClient(options);
1849
- await client.createSession();
1850
-
1851
- try {
1852
- await client.readFileStream(path, encoding);
1853
- } finally {
1854
- client.clearSession();
1855
- }
1856
- }
1857
-
1858
1632
  // Convenience function for quick file deletion
1859
1633
  export async function quickDeleteFile(
1860
1634
  path: string,
package/src/index.ts CHANGED
@@ -8,29 +8,24 @@ export function getSandbox(ns: DurableObjectNamespace<Sandbox>, id: string) {
8
8
  export class Sandbox<Env = unknown> extends Container<Env> {
9
9
  defaultPort = 3000; // The default port for the container to listen on
10
10
  sleepAfter = "3m"; // Sleep the sandbox if no requests are made in this timeframe
11
- client: HttpClient;
12
11
 
13
- constructor(ctx: DurableObjectState, env: Env) {
14
- super(ctx, env);
15
- this.client = new HttpClient({
16
- onCommandComplete: (success, exitCode, stdout, stderr, command, args) => {
17
- console.log(
18
- `[Container] Command completed: ${command}, Success: ${success}, Exit code: ${exitCode}`
19
- );
20
- },
21
- onCommandStart: (command, args) => {
22
- console.log(`[Container] Command started: ${command} ${args.join(" ")}`);
23
- },
24
- onError: (error, command, args) => {
25
- console.error(`[Container] Command error: ${error}`);
26
- },
27
- onOutput: (stream, data, command) => {
28
- console.log(`[Container] [${stream}] ${data}`);
29
- },
30
- port: this.defaultPort,
31
- stub: this,
32
- });
33
- }
12
+ client: HttpClient = new HttpClient({
13
+ onCommandComplete: (success, exitCode, stdout, stderr, command, args) => {
14
+ console.log(
15
+ `[Container] Command completed: ${command}, Success: ${success}, Exit code: ${exitCode}`
16
+ );
17
+ },
18
+ onCommandStart: (command, args) => {
19
+ console.log(`[Container] Command started: ${command} ${args.join(" ")}`);
20
+ },
21
+ onError: (error, command, args) => {
22
+ console.error(`[Container] Command error: ${error}`);
23
+ },
24
+ onOutput: (stream, data, command) => {
25
+ console.log(`[Container] [${stream}] ${data}`);
26
+ },
27
+ port: this.defaultPort,
28
+ });
34
29
 
35
30
  envVars = {
36
31
  MESSAGE: "I was passed in via the Sandbox class!",
@@ -81,54 +76,4 @@ export class Sandbox<Env = unknown> extends Container<Env> {
81
76
  }
82
77
  return this.client.mkdir(path, options.recursive);
83
78
  }
84
-
85
- async writeFile(
86
- path: string,
87
- content: string,
88
- options: { encoding?: string; stream?: boolean }
89
- ) {
90
- if (options?.stream) {
91
- return this.client.writeFileStream(path, content, options.encoding);
92
- }
93
- return this.client.writeFile(path, content, options.encoding);
94
- }
95
-
96
- async deleteFile(path: string, options: { stream?: boolean }) {
97
- if (options?.stream) {
98
- return this.client.deleteFileStream(path);
99
- }
100
- return this.client.deleteFile(path);
101
- }
102
-
103
- async renameFile(
104
- oldPath: string,
105
- newPath: string,
106
- options: { stream?: boolean }
107
- ) {
108
- if (options?.stream) {
109
- return this.client.renameFileStream(oldPath, newPath);
110
- }
111
- return this.client.renameFile(oldPath, newPath);
112
- }
113
-
114
- async moveFile(
115
- sourcePath: string,
116
- destinationPath: string,
117
- options: { stream?: boolean }
118
- ) {
119
- if (options?.stream) {
120
- return this.client.moveFileStream(sourcePath, destinationPath);
121
- }
122
- return this.client.moveFile(sourcePath, destinationPath);
123
- }
124
-
125
- async readFile(
126
- path: string,
127
- options: { encoding?: string; stream?: boolean }
128
- ) {
129
- if (options?.stream) {
130
- return this.client.readFileStream(path, options.encoding);
131
- }
132
- return this.client.readFile(path, options.encoding);
133
- }
134
79
  }
package/tests/test2.ts CHANGED
@@ -7,8 +7,6 @@ import {
7
7
  quickExecuteStream,
8
8
  quickMoveFile,
9
9
  quickMoveFileStream,
10
- quickReadFile,
11
- quickReadFileStream,
12
10
  quickRenameFile,
13
11
  quickRenameFileStream,
14
12
  quickWriteFile,
@@ -685,223 +683,6 @@ async function testHttpClient() {
685
683
  );
686
684
  }
687
685
 
688
- // Test 25: File reading
689
- console.log("Test 25: File reading");
690
- try {
691
- // First create a file to read
692
- const readContent = "This is a test file for reading\nLine 2\nLine 3";
693
- await quickWriteFile("file-to-read.txt", readContent);
694
- console.log("✅ Test file created for reading");
695
-
696
- // Read the file
697
- const result = await quickReadFile("file-to-read.txt");
698
- console.log("✅ File read successfully:", result.success);
699
- console.log(" Path:", result.path);
700
- console.log(" Content length:", result.content.length, "characters");
701
- console.log(" Exit code:", result.exitCode);
702
-
703
- // Verify the content
704
- console.log("✅ File content verified:", result.content === readContent);
705
- console.log(" Content:", result.content);
706
- console.log("✅ File reading test completed\n");
707
- } catch (error) {
708
- console.error("❌ Test 25 failed:", error);
709
- }
710
-
711
- // Test 26: File reading with custom encoding
712
- console.log("Test 26: File reading with custom encoding");
713
- try {
714
- // Create a file with special characters
715
- const specialContent = "Hello 世界! 🌍 Test with emojis and unicode";
716
- await quickWriteFile("special-chars.txt", specialContent, "utf-8");
717
- console.log("✅ Special characters file created");
718
-
719
- // Read with explicit UTF-8 encoding
720
- const result = await quickReadFile("special-chars.txt", "utf-8");
721
- console.log(
722
- "✅ Special characters file read successfully:",
723
- result.success
724
- );
725
- console.log(
726
- "✅ Special characters verified:",
727
- result.content === specialContent
728
- );
729
- console.log(" Content:", result.content);
730
- console.log("✅ Custom encoding test completed\n");
731
- } catch (error) {
732
- console.error("❌ Test 26 failed:", error);
733
- }
734
-
735
- // Test 27: File reading in nested directories
736
- console.log("Test 27: File reading in nested directories");
737
- try {
738
- // Create a file in a nested directory
739
- const nestedContent = "This file is in a nested directory for reading";
740
- await quickWriteFile("nested/read/test-nested-read.txt", nestedContent);
741
- console.log("✅ Nested file created for reading");
742
-
743
- // Read the nested file
744
- const result = await quickReadFile("nested/read/test-nested-read.txt");
745
- console.log("✅ Nested file read successfully:", result.success);
746
- console.log(
747
- "✅ Nested file content verified:",
748
- result.content === nestedContent
749
- );
750
- console.log(" Content:", result.content);
751
- console.log("✅ Nested directory reading test completed\n");
752
- } catch (error) {
753
- console.error("❌ Test 27 failed:", error);
754
- }
755
-
756
- // Test 28: Streaming file reading
757
- console.log("Test 28: Streaming file reading");
758
- try {
759
- const client = createClient();
760
- await client.createSession();
761
-
762
- // Create a file to read via streaming
763
- const streamReadContent =
764
- "This file will be read via streaming\nLine 2\nLine 3";
765
- await client.writeFile("stream-read-file.txt", streamReadContent);
766
- console.log("✅ Test file created for streaming reading");
767
-
768
- let readContent = "";
769
- let readCompleted = false;
770
-
771
- // Set up event handlers for streaming
772
- client.setOnStreamEvent((event) => {
773
- if (event.type === "command_complete" && event.content) {
774
- readContent = event.content;
775
- readCompleted = true;
776
- }
777
- });
778
-
779
- console.log(" Starting streaming file reading...");
780
- await client.readFileStream("stream-read-file.txt");
781
- console.log("✅ Streaming file reading completed");
782
-
783
- // Verify the content was read correctly
784
- console.log(
785
- "✅ Streaming read content verified:",
786
- readContent === streamReadContent
787
- );
788
- console.log(" Content length:", readContent.length, "characters");
789
-
790
- client.clearSession();
791
- console.log("✅ Streaming file reading test completed\n");
792
- } catch (error) {
793
- console.error("❌ Test 28 failed:", error);
794
- }
795
-
796
- // Test 29: Quick streaming file reading
797
- console.log("Test 29: Quick streaming file reading");
798
- try {
799
- // Create a file for quick streaming read
800
- const quickReadContent = "Quick streaming read test content";
801
- await quickWriteFile("quick-read-stream.txt", quickReadContent);
802
- console.log("✅ Test file created for quick streaming reading");
803
-
804
- let quickReadContentReceived = "";
805
- let quickReadCompleted = false;
806
-
807
- console.log(" Starting quick streaming file reading...");
808
- await quickReadFileStream("quick-read-stream.txt", "utf-8", {
809
- onStreamEvent: (event) => {
810
- if (event.type === "command_complete" && event.content) {
811
- quickReadContentReceived = event.content;
812
- quickReadCompleted = true;
813
- }
814
- },
815
- });
816
- console.log("✅ Quick streaming file reading completed");
817
-
818
- // Verify the content
819
- console.log(
820
- "✅ Quick streaming read verified:",
821
- quickReadContentReceived === quickReadContent
822
- );
823
- console.log(" Content:", quickReadContentReceived);
824
- console.log("✅ Quick streaming file reading test completed\n");
825
- } catch (error) {
826
- console.error("❌ Test 29 failed:", error);
827
- }
828
-
829
- // Test 30: File reading with session management
830
- console.log("Test 30: File reading with session management");
831
- try {
832
- const client = createClient();
833
- const sessionId = await client.createSession();
834
-
835
- // Create a file in session
836
- const sessionReadContent =
837
- "This file was created and read with session management";
838
- await client.writeFile(
839
- "session-read-file.txt",
840
- sessionReadContent,
841
- "utf-8",
842
- sessionId
843
- );
844
- console.log("✅ Session file created for reading");
845
-
846
- // Read the file in the same session
847
- const result = await client.readFile(
848
- "session-read-file.txt",
849
- "utf-8",
850
- sessionId
851
- );
852
- console.log("✅ Session file read successfully:", result.success);
853
- console.log(
854
- "✅ Session file content verified:",
855
- result.content === sessionReadContent
856
- );
857
- console.log(" Session ID:", sessionId);
858
- console.log(" Content:", result.content);
859
-
860
- client.clearSession();
861
- console.log("✅ Session file reading test completed\n");
862
- } catch (error) {
863
- console.error("❌ Test 30 failed:", error);
864
- }
865
-
866
- // Test 31: Error handling for file reading
867
- console.log("Test 31: Error handling for file reading");
868
- try {
869
- // Try to read a non-existent file
870
- await quickReadFile("non-existent-read-file.txt");
871
- console.log("❌ Should have failed for non-existent file");
872
- } catch (error) {
873
- console.log("✅ Error handling works for non-existent files");
874
- console.log(
875
- " Error:",
876
- error instanceof Error ? error.message : "Unknown error"
877
- );
878
- }
879
-
880
- try {
881
- // Try to read from a dangerous path
882
- await quickReadFile("/etc/passwd");
883
- console.log("❌ Should have failed for dangerous path");
884
- } catch (error) {
885
- console.log("✅ Error handling works for dangerous paths");
886
- console.log(
887
- " Error:",
888
- error instanceof Error ? error.message : "Unknown error"
889
- );
890
- }
891
-
892
- try {
893
- // Try to read with empty path
894
- await quickReadFile("");
895
- console.log("❌ Should have failed for empty path");
896
- } catch (error) {
897
- console.log("✅ Error handling works for empty paths");
898
- console.log(
899
- " Error:",
900
- error instanceof Error ? error.message : "Unknown error",
901
- "\n"
902
- );
903
- }
904
-
905
686
  console.log("🎉 All tests completed!");
906
687
  }
907
688
 
package/CHANGELOG.md DELETED
@@ -1,39 +0,0 @@
1
- # @cloudflare/sandbox
2
-
3
- ## 0.0.6
4
-
5
- ### Patch Changes
6
-
7
- - [#9](https://github.com/cloudflare/sandbox-sdk/pull/9) [`24f5470`](https://github.com/cloudflare/sandbox-sdk/commit/24f547048d5a26137de4656cea13d83ad2cc0b43) Thanks [@ItsWendell](https://github.com/ItsWendell)! - fix baseUrl for stub and stub forwarding
8
-
9
- ## 0.0.5
10
-
11
- ### Patch Changes
12
-
13
- - [#5](https://github.com/cloudflare/sandbox-sdk/pull/5) [`7c15b81`](https://github.com/cloudflare/sandbox-sdk/commit/7c15b817899e4d9e1f25747aaf439e5e9e880d15) Thanks [@ghostwriternr](https://github.com/ghostwriternr)! - Make package ready for deployment
14
-
15
- ## 0.0.4
16
-
17
- ### Patch Changes
18
-
19
- - [`c0d9d33`](https://github.com/cloudflare/sandbox-sdk/commit/c0d9d3396badee1eab45e6b4a73d48957f31409b) Thanks [@threepointone](https://github.com/threepointone)! - actually work
20
-
21
- - [`444d2da`](https://github.com/cloudflare/sandbox-sdk/commit/444d2dafde9a0f190e50c879b0e768da1b289b51) Thanks [@threepointone](https://github.com/threepointone)! - add experimental label
22
-
23
- ## 0.0.3
24
-
25
- ### Patch Changes
26
-
27
- - [`2b087c4`](https://github.com/cloudflare/sandbox-sdk/commit/2b087c40a29697c20dad19b4e3b8512f5d404bd3) Thanks [@ghostwriternr](https://github.com/ghostwriternr)! - Fix worker unable to find container port
28
-
29
- ## 0.0.2
30
-
31
- ### Patch Changes
32
-
33
- - [`52f02f0`](https://github.com/cloudflare/sandbox-sdk/commit/52f02f0625ef9f8eac695e51f93fa79651c0206d) Thanks [@threepointone](https://github.com/threepointone)! - readFile
34
-
35
- ## 0.0.1
36
-
37
- ### Patch Changes
38
-
39
- - [`f786c3c`](https://github.com/cloudflare/sandbox-sdk/commit/f786c3cee6bd9777bd74918ae9fdf381aa99f913) Thanks [@threepointone](https://github.com/threepointone)! - Release!