@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 +0 -3
- package/container_src/index.ts +3 -289
- package/package.json +3 -5
- package/src/client.ts +3 -229
- package/src/index.ts +17 -72
- package/tests/test2.ts +0 -219
- package/CHANGELOG.md +0 -39
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.
|
package/container_src/index.ts
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { spawn } from "node:child_process";
|
|
2
|
-
import { mkdir,
|
|
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(
|
|
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://
|
|
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-
|
|
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.
|
|
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": "
|
|
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
|
-
|
|
207
|
-
|
|
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
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
}
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
}
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
}
|
|
27
|
-
|
|
28
|
-
|
|
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!
|