@capsule-run/sdk 0.2.2 → 0.3.0

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 ADDED
@@ -0,0 +1,135 @@
1
+ # capsule
2
+
3
+ **A secure, durable runtime for agentic workflows**
4
+
5
+ ## Overview
6
+
7
+ Capsule is a runtime for coordinating AI agent tasks in isolated environments. It is designed to handle long-running workflows, large-scale processing, autonomous decision-making securely, or even multi-agent systems.
8
+
9
+ Each task runs inside its own WebAssembly sandbox, providing:
10
+
11
+ - **Isolated execution**: Each task runs isolated from your host system
12
+ - **Resource limits**: Set CPU, memory, and timeout limits per task
13
+ - **Automatic retries**: Handle failures without manual intervention
14
+ - **Lifecycle tracking**: Monitor which tasks are running, completed, or failed
15
+
16
+ ## Installation
17
+
18
+ ```bash
19
+ npm install -g @capsule-run/cli
20
+ npm install @capsule-run/sdk
21
+ ```
22
+
23
+ ## Quick Start
24
+
25
+ Create `hello.ts`:
26
+
27
+ ```typescript
28
+ import { task } from "@capsule-run/sdk";
29
+
30
+ export const main = task({
31
+ name: "main",
32
+ compute: "LOW",
33
+ ram: "64MB"
34
+ }, (): string => {
35
+ return "Hello from Capsule!";
36
+ });
37
+ ```
38
+
39
+ Run it:
40
+
41
+ ```bash
42
+ capsule run hello.ts
43
+ ```
44
+
45
+ ## How It Works
46
+
47
+ Simply use a wrapper function to define your tasks:
48
+
49
+ ```typescript
50
+ import { task } from "@capsule-run/sdk";
51
+
52
+ export const analyzeData = task({
53
+ name: "analyze_data",
54
+ compute: "MEDIUM",
55
+ ram: "512MB",
56
+ timeout: "30s",
57
+ maxRetries: 1
58
+ }, (dataset: number[]): object => {
59
+ // Your code runs safely in a Wasm sandbox
60
+ return { processed: dataset.length, status: "complete" };
61
+ });
62
+
63
+ // The "main" task is required as the entrypoint
64
+ export const main = task({
65
+ name: "main",
66
+ compute: "HIGH"
67
+ }, () => {
68
+ return analyzeData([1, 2, 3, 4, 5]);
69
+ });
70
+ ```
71
+
72
+ When you run `capsule run main.ts`, your code is compiled into a WebAssembly module and executed in a dedicated sandbox.
73
+
74
+ ## Documentation
75
+
76
+ ### Task Configuration Options
77
+
78
+ | Parameter | Description | Type | Default | Example |
79
+ |-----------|-------------|------|---------|---------|
80
+ | `name` | Task identifier | `string` | *required* | `"process_data"` |
81
+ | `compute` | CPU level: `"LOW"`, `"MEDIUM"`, `"HIGH"` | `string` | `"MEDIUM"` | `"HIGH"` |
82
+ | `ram` | Memory limit | `string` | unlimited | `"512MB"`, `"2GB"` |
83
+ | `timeout` | Maximum execution time | `string` or `number` | unlimited | `"30s"`, `"5m"` |
84
+ | `maxRetries` | Retry attempts on failure | `number` | `0` | `3` |
85
+ | `allowedFiles` | Folders accessible in the sandbox | `string[]` | `[]` | `["./data", "./output"]` |
86
+
87
+ ### Compute Levels
88
+
89
+ - **LOW**: Minimal allocation for lightweight tasks
90
+ - **MEDIUM**: Balanced resources for typical workloads
91
+ - **HIGH**: Maximum fuel for compute-intensive operations
92
+ - **CUSTOM**: Specify exact fuel value (e.g., `compute="1000000"`)
93
+
94
+ ### File Access
95
+
96
+ The entry point task (main) has access to the entire project directory. Sub-tasks have no filesystem access by default and must declare `allowedFiles` to access specific paths.
97
+
98
+ Node.js built-ins like `fs` are not available in the WebAssembly sandbox. Instead, use the `files` API provided by the SDK:
99
+
100
+ ```typescript
101
+ import { task, files } from "@capsule-run/sdk";
102
+
103
+ export const restrictedWriter = task({
104
+ name: "restricted_writer",
105
+ allowedFiles: ["./output"]
106
+ }, async () => {
107
+ await files.writeText("./output/result.txt", "result");
108
+ });
109
+
110
+ export const main = task({ name: "main" }, async () => {
111
+ restrictedWriter();
112
+ return await files.readText("./data/input.txt");
113
+ });
114
+ ```
115
+
116
+ Available methods:
117
+ - `files.readText(path)` — Read file as string
118
+ - `files.readBytes(path)` — Read file as `Uint8Array`
119
+ - `files.writeText(path, content)` — Write string to file
120
+ - `files.writeBytes(path, data)` — Write bytes to file
121
+ - `files.list(path)` — List directory contents
122
+ - `files.exists(path)` — Check if file exists
123
+
124
+ ## Compatibility
125
+
126
+ ✅ **Supported:**
127
+ - npm packages and ES modules work
128
+
129
+ ⚠️ **Not yet supported:**
130
+ - Node.js built-ins (`fs`, `path`, `os`) are not available in the sandbox
131
+
132
+ ## Links
133
+
134
+ - [GitHub](https://github.com/mavdol/capsule)
135
+ - [Issues](https://github.com/mavdol/capsule/issues)
package/dist/app.d.ts CHANGED
@@ -11,6 +11,7 @@ export interface TaskConfig {
11
11
  ram?: string;
12
12
  timeout?: string;
13
13
  maxRetries?: number;
14
+ allowedFiles?: string[];
14
15
  }
15
16
  /**
16
17
  * Register a task function by name with its configuration.
package/dist/app.d.ts.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"file":"app.d.ts","sourceRoot":"","sources":["../src/app.ts"],"names":[],"mappings":"AAAA;;GAEG;AAEH,MAAM,WAAW,QAAQ,CAAC,CAAC,SAAS,CAAC,GAAG,IAAI,EAAE,GAAG,EAAE,KAAK,GAAG;IACzD,IAAI,EAAE,CAAC,CAAC;IACR,MAAM,EAAE,UAAU,CAAC;CACpB;AAED,MAAM,WAAW,UAAU;IACzB,IAAI,EAAE,MAAM,CAAC;IACb,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,GAAG,CAAC,EAAE,MAAM,CAAC;IACb,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,UAAU,CAAC,EAAE,MAAM,CAAC;CACrB;AAID;;GAEG;AACH,wBAAgB,YAAY,CAAC,CAAC,SAAS,CAAC,GAAG,IAAI,EAAE,GAAG,EAAE,KAAK,GAAG,EAC5D,IAAI,EAAE,MAAM,EACZ,IAAI,EAAE,CAAC,EACP,MAAM,EAAE,UAAU,GACjB,IAAI,CAEN;AAED;;GAEG;AACH,wBAAgB,OAAO,CAAC,IAAI,EAAE,MAAM,GAAG,CAAC,CAAC,GAAG,IAAI,EAAE,GAAG,EAAE,KAAK,GAAG,CAAC,GAAG,SAAS,CAE3E;AAED;;GAEG;AACH,wBAAgB,aAAa,CAAC,IAAI,EAAE,MAAM,GAAG,UAAU,GAAG,SAAS,CAElE;AAED;;GAEG;AACH,wBAAgB,YAAY,IAAI,MAAM,EAAE,CAEvC;AAcD;;;;;GAKG;AACH,qBAAa,UAAU;IACrB;;;OAGG;IACG,GAAG,CAAC,QAAQ,EAAE,MAAM,GAAG,OAAO,CAAC,MAAM,CAAC;CAuC7C;AAED,eAAO,MAAM,OAAO,YAAmB,CAAC"}
1
+ {"version":3,"file":"app.d.ts","sourceRoot":"","sources":["../src/app.ts"],"names":[],"mappings":"AAAA;;GAEG;AAEH,MAAM,WAAW,QAAQ,CAAC,CAAC,SAAS,CAAC,GAAG,IAAI,EAAE,GAAG,EAAE,KAAK,GAAG;IACzD,IAAI,EAAE,CAAC,CAAC;IACR,MAAM,EAAE,UAAU,CAAC;CACpB;AAED,MAAM,WAAW,UAAU;IACzB,IAAI,EAAE,MAAM,CAAC;IACb,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,GAAG,CAAC,EAAE,MAAM,CAAC;IACb,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,YAAY,CAAC,EAAE,MAAM,EAAE,CAAC;CACzB;AAID;;GAEG;AACH,wBAAgB,YAAY,CAAC,CAAC,SAAS,CAAC,GAAG,IAAI,EAAE,GAAG,EAAE,KAAK,GAAG,EAC5D,IAAI,EAAE,MAAM,EACZ,IAAI,EAAE,CAAC,EACP,MAAM,EAAE,UAAU,GACjB,IAAI,CAEN;AAED;;GAEG;AACH,wBAAgB,OAAO,CAAC,IAAI,EAAE,MAAM,GAAG,CAAC,CAAC,GAAG,IAAI,EAAE,GAAG,EAAE,KAAK,GAAG,CAAC,GAAG,SAAS,CAE3E;AAED;;GAEG;AACH,wBAAgB,aAAa,CAAC,IAAI,EAAE,MAAM,GAAG,UAAU,GAAG,SAAS,CAElE;AAED;;GAEG;AACH,wBAAgB,YAAY,IAAI,MAAM,EAAE,CAEvC;AAQD;;;;;GAKG;AACH,qBAAa,UAAU;IACrB;;;OAGG;IACG,GAAG,CAAC,QAAQ,EAAE,MAAM,GAAG,OAAO,CAAC,MAAM,CAAC;CAuC7C;AAED,eAAO,MAAM,OAAO,YAAmB,CAAC"}
package/dist/app.js.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"file":"app.js","sourceRoot":"","sources":["../src/app.ts"],"names":[],"mappings":"AAAA;;GAEG;AAeH,MAAM,KAAK,GAA+B,IAAI,GAAG,EAAE,CAAC;AAEpD;;GAEG;AACH,MAAM,UAAU,YAAY,CAC1B,IAAY,EACZ,IAAO,EACP,MAAkB;IAElB,KAAK,CAAC,GAAG,CAAC,IAAI,EAAE,EAAE,IAAI,EAAE,MAAM,EAAE,CAAC,CAAC;AACpC,CAAC;AAED;;GAEG;AACH,MAAM,UAAU,OAAO,CAAC,IAAY;IAClC,OAAO,KAAK,CAAC,GAAG,CAAC,IAAI,CAAC,EAAE,IAAI,CAAC;AAC/B,CAAC;AAED;;GAEG;AACH,MAAM,UAAU,aAAa,CAAC,IAAY;IACxC,OAAO,KAAK,CAAC,GAAG,CAAC,IAAI,CAAC,EAAE,MAAM,CAAC;AACjC,CAAC;AAED;;GAEG;AACH,MAAM,UAAU,YAAY;IAC1B,OAAO,KAAK,CAAC,IAAI,CAAC,KAAK,CAAC,IAAI,EAAE,CAAC,CAAC;AAClC,CAAC;AAcD;;;;;GAKG;AACH,MAAM,OAAO,UAAU;IACrB;;;OAGG;IACH,KAAK,CAAC,GAAG,CAAC,QAAgB;QACxB,IAAI,CAAC;YACH,MAAM,IAAI,GAAa,IAAI,CAAC,KAAK,CAAC,QAAQ,CAAC,CAAC;YAC5C,MAAM,QAAQ,GAAG,IAAI,CAAC,SAAS,IAAI,MAAM,CAAC;YAC1C,MAAM,IAAI,GAAG,IAAI,CAAC,IAAI,IAAI,EAAE,CAAC;YAC7B,MAAM,MAAM,GAAG,IAAI,CAAC,MAAM,IAAI,EAAE,CAAC;YAEjC,IAAI,QAAQ,GAAG,OAAO,CAAC,QAAQ,CAAC,CAAC;YAEjC,IAAI,CAAC,QAAQ,IAAI,QAAQ,KAAK,MAAM,EAAE,CAAC;gBACrC,QAAQ,GAAG,OAAO,CAAC,MAAM,CAAC,CAAC;YAC7B,CAAC;YAED,IAAI,CAAC,QAAQ,IAAI,KAAK,CAAC,IAAI,GAAG,CAAC,EAAE,CAAC;gBAChC,MAAM,aAAa,GAAG,KAAK,CAAC,IAAI,EAAE,CAAC,IAAI,EAAE,CAAC,KAAK,CAAC;gBAChD,IAAI,aAAa,EAAE,CAAC;oBAClB,QAAQ,GAAG,OAAO,CAAC,aAAa,CAAC,CAAC;gBACpC,CAAC;YACH,CAAC;YAED,IAAI,CAAC,QAAQ,EAAE,CAAC;gBACd,MAAM,uDAAuD,YAAY,EAAE,CAAC,IAAI,CAAC,IAAI,CAAC,EAAE,CAAC;YAC3F,CAAC;YAED,MAAM,MAAM,GAAG,QAAQ,CAAC,GAAG,IAAI,EAAE,MAAM,CAAC,CAAC;YAEzC,IAAI,MAAM,YAAY,OAAO,EAAE,CAAC;gBAC9B,MAAM,WAAW,GAAG,MAAM,MAAM,CAAC;gBACjC,OAAO,IAAI,CAAC,SAAS,CAAC,EAAE,MAAM,EAAE,WAAW,IAAI,IAAI,EAAE,CAAC,CAAC;YACzD,CAAC;YAED,OAAO,IAAI,CAAC,SAAS,CAAC,EAAE,MAAM,EAAE,MAAM,IAAI,IAAI,EAAE,CAAC,CAAC;QACpD,CAAC;QAAC,OAAO,CAAC,EAAE,CAAC;YACX,MAAM,QAAQ,GAAG,CAAC,YAAY,KAAK;gBACjC,CAAC,CAAC,GAAG,CAAC,CAAC,OAAO,KAAK,CAAC,CAAC,KAAK,IAAI,EAAE,EAAE;gBAClC,CAAC,CAAC,MAAM,CAAC,CAAC,CAAC,CAAC;YACd,MAAM,QAAQ,CAAC;QACjB,CAAC;IACH,CAAC;CACF;AAED,MAAM,CAAC,MAAM,OAAO,GAAG,IAAI,UAAU,EAAE,CAAC"}
1
+ {"version":3,"file":"app.js","sourceRoot":"","sources":["../src/app.ts"],"names":[],"mappings":"AAAA;;GAEG;AAgBH,MAAM,KAAK,GAA+B,IAAI,GAAG,EAAE,CAAC;AAEpD;;GAEG;AACH,MAAM,UAAU,YAAY,CAC1B,IAAY,EACZ,IAAO,EACP,MAAkB;IAElB,KAAK,CAAC,GAAG,CAAC,IAAI,EAAE,EAAE,IAAI,EAAE,MAAM,EAAE,CAAC,CAAC;AACpC,CAAC;AAED;;GAEG;AACH,MAAM,UAAU,OAAO,CAAC,IAAY;IAClC,OAAO,KAAK,CAAC,GAAG,CAAC,IAAI,CAAC,EAAE,IAAI,CAAC;AAC/B,CAAC;AAED;;GAEG;AACH,MAAM,UAAU,aAAa,CAAC,IAAY;IACxC,OAAO,KAAK,CAAC,GAAG,CAAC,IAAI,CAAC,EAAE,MAAM,CAAC;AACjC,CAAC;AAED;;GAEG;AACH,MAAM,UAAU,YAAY;IAC1B,OAAO,KAAK,CAAC,IAAI,CAAC,KAAK,CAAC,IAAI,EAAE,CAAC,CAAC;AAClC,CAAC;AAQD;;;;;GAKG;AACH,MAAM,OAAO,UAAU;IACrB;;;OAGG;IACH,KAAK,CAAC,GAAG,CAAC,QAAgB;QACxB,IAAI,CAAC;YACH,MAAM,IAAI,GAAa,IAAI,CAAC,KAAK,CAAC,QAAQ,CAAC,CAAC;YAC5C,MAAM,QAAQ,GAAG,IAAI,CAAC,SAAS,IAAI,MAAM,CAAC;YAC1C,MAAM,IAAI,GAAG,IAAI,CAAC,IAAI,IAAI,EAAE,CAAC;YAC7B,MAAM,MAAM,GAAG,IAAI,CAAC,MAAM,IAAI,EAAE,CAAC;YAEjC,IAAI,QAAQ,GAAG,OAAO,CAAC,QAAQ,CAAC,CAAC;YAEjC,IAAI,CAAC,QAAQ,IAAI,QAAQ,KAAK,MAAM,EAAE,CAAC;gBACrC,QAAQ,GAAG,OAAO,CAAC,MAAM,CAAC,CAAC;YAC7B,CAAC;YAED,IAAI,CAAC,QAAQ,IAAI,KAAK,CAAC,IAAI,GAAG,CAAC,EAAE,CAAC;gBAChC,MAAM,aAAa,GAAG,KAAK,CAAC,IAAI,EAAE,CAAC,IAAI,EAAE,CAAC,KAAK,CAAC;gBAChD,IAAI,aAAa,EAAE,CAAC;oBAClB,QAAQ,GAAG,OAAO,CAAC,aAAa,CAAC,CAAC;gBACpC,CAAC;YACH,CAAC;YAED,IAAI,CAAC,QAAQ,EAAE,CAAC;gBACd,MAAM,uDAAuD,YAAY,EAAE,CAAC,IAAI,CAAC,IAAI,CAAC,EAAE,CAAC;YAC3F,CAAC;YAED,MAAM,MAAM,GAAG,QAAQ,CAAC,GAAG,IAAI,EAAE,MAAM,CAAC,CAAC;YAEzC,IAAI,MAAM,YAAY,OAAO,EAAE,CAAC;gBAC9B,MAAM,WAAW,GAAG,MAAM,MAAM,CAAC;gBACjC,OAAO,IAAI,CAAC,SAAS,CAAC,EAAE,MAAM,EAAE,WAAW,IAAI,IAAI,EAAE,CAAC,CAAC;YACzD,CAAC;YAED,OAAO,IAAI,CAAC,SAAS,CAAC,EAAE,MAAM,EAAE,MAAM,IAAI,IAAI,EAAE,CAAC,CAAC;QACpD,CAAC;QAAC,OAAO,CAAC,EAAE,CAAC;YACX,MAAM,QAAQ,GAAG,CAAC,YAAY,KAAK;gBACjC,CAAC,CAAC,GAAG,CAAC,CAAC,OAAO,KAAK,CAAC,CAAC,KAAK,IAAI,EAAE,EAAE;gBAClC,CAAC,CAAC,MAAM,CAAC,CAAC,CAAC,CAAC;YACd,MAAM,QAAQ,CAAC;QACjB,CAAC;IACH,CAAC;CACF;AAED,MAAM,CAAC,MAAM,OAAO,GAAG,IAAI,UAAU,EAAE,CAAC"}
@@ -0,0 +1,46 @@
1
+ /**
2
+ * Capsule Files API for WASM filesystem access.
3
+ */
4
+ /**
5
+ * Read a file as text.
6
+ *
7
+ * @param path - The path to read.
8
+ * @returns A promise that resolves to a string containing the file contents.
9
+ */
10
+ export declare function readText(path: string): Promise<string>;
11
+ /**
12
+ * Read a file as bytes.
13
+ *
14
+ * @param path - The path to read.
15
+ * @returns A promise that resolves to a Uint8Array containing the file contents.
16
+ */
17
+ export declare function readBytes(path: string): Promise<Uint8Array>;
18
+ /**
19
+ * Write text content to a file.
20
+ *
21
+ * @param path - The path to write.
22
+ * @param content - The text content to write.
23
+ */
24
+ export declare function writeText(path: string, content: string): Promise<void>;
25
+ /**
26
+ * Write bytes to a file.
27
+ *
28
+ * @param path - The path to write.
29
+ * @param data - The bytes to write.
30
+ */
31
+ export declare function writeBytes(path: string, data: Uint8Array): Promise<void>;
32
+ /**
33
+ * List files/directories at a path.
34
+ *
35
+ * @param path - The path to list.
36
+ * @returns A promise that resolves to an array of strings representing the files and directories at the specified path.
37
+ */
38
+ export declare function list(path?: string): Promise<string[]>;
39
+ /**
40
+ * Check if a file or directory exists.
41
+ *
42
+ * @param path - The path to check.
43
+ * @returns A promise that resolves to a boolean indicating whether the file or directory exists.
44
+ */
45
+ export declare function exists(path: string): Promise<boolean>;
46
+ //# sourceMappingURL=files.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"files.d.ts","sourceRoot":"","sources":["../src/files.ts"],"names":[],"mappings":"AAAA;;GAEG;AAoFH;;;;;GAKG;AACH,wBAAsB,QAAQ,CAAC,IAAI,EAAE,MAAM,GAAG,OAAO,CAAC,MAAM,CAAC,CAG5D;AAED;;;;;GAKG;AACH,wBAAsB,SAAS,CAAC,IAAI,EAAE,MAAM,GAAG,OAAO,CAAC,UAAU,CAAC,CAkBjE;AAED;;;;;GAKG;AACH,wBAAsB,SAAS,CAAC,IAAI,EAAE,MAAM,EAAE,OAAO,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC,CAG5E;AAED;;;;;GAKG;AACH,wBAAsB,UAAU,CAAC,IAAI,EAAE,MAAM,EAAE,IAAI,EAAE,UAAU,GAAG,OAAO,CAAC,IAAI,CAAC,CAgB9E;AAED;;;;;GAKG;AACH,wBAAsB,IAAI,CAAC,IAAI,GAAE,MAAY,GAAG,OAAO,CAAC,MAAM,EAAE,CAAC,CA6BhE;AAED;;;;;GAKG;AACH,wBAAsB,MAAM,CAAC,IAAI,EAAE,MAAM,GAAG,OAAO,CAAC,OAAO,CAAC,CAe3D"}
package/dist/files.js ADDED
@@ -0,0 +1,177 @@
1
+ /**
2
+ * Capsule Files API for WASM filesystem access.
3
+ */
4
+ function getFsBindings() {
5
+ try {
6
+ const types = globalThis['wasi:filesystem/types'];
7
+ const preopens = globalThis['wasi:filesystem/preopens'];
8
+ if (types && preopens) {
9
+ return { types, preopens };
10
+ }
11
+ }
12
+ catch { }
13
+ return null;
14
+ }
15
+ function getPreopenedDirs() {
16
+ const fs = getFsBindings();
17
+ if (!fs)
18
+ return [];
19
+ try {
20
+ const dirs = fs.preopens.getDirectories();
21
+ return (dirs || []).map((entry) => ({
22
+ descriptor: entry[0],
23
+ guestPath: entry[1]
24
+ }));
25
+ }
26
+ catch {
27
+ return [];
28
+ }
29
+ }
30
+ function normalizePath(path) {
31
+ if (path.startsWith('./')) {
32
+ return path.slice(2);
33
+ }
34
+ return path;
35
+ }
36
+ function resolvePath(path) {
37
+ const preopens = getPreopenedDirs();
38
+ if (preopens.length === 0)
39
+ return null;
40
+ const normalizedPath = normalizePath(path);
41
+ for (const { descriptor, guestPath } of preopens) {
42
+ const normalizedGuest = normalizePath(guestPath);
43
+ if (normalizedGuest === '.' || normalizedGuest === '') {
44
+ return { dir: descriptor, relativePath: normalizedPath };
45
+ }
46
+ if (normalizedPath.startsWith(normalizedGuest + '/')) {
47
+ const relativePath = normalizedPath.slice(normalizedGuest.length + 1);
48
+ return { dir: descriptor, relativePath };
49
+ }
50
+ if (normalizedPath === normalizedGuest) {
51
+ return { dir: descriptor, relativePath: '.' };
52
+ }
53
+ }
54
+ return { dir: preopens[0].descriptor, relativePath: normalizedPath };
55
+ }
56
+ /**
57
+ * Read a file as text.
58
+ *
59
+ * @param path - The path to read.
60
+ * @returns A promise that resolves to a string containing the file contents.
61
+ */
62
+ export async function readText(path) {
63
+ const bytes = await readBytes(path);
64
+ return new TextDecoder().decode(bytes);
65
+ }
66
+ /**
67
+ * Read a file as bytes.
68
+ *
69
+ * @param path - The path to read.
70
+ * @returns A promise that resolves to a Uint8Array containing the file contents.
71
+ */
72
+ export async function readBytes(path) {
73
+ const resolved = resolvePath(path);
74
+ if (!resolved) {
75
+ throw new Error("Filesystem not available.");
76
+ }
77
+ try {
78
+ const pathFlags = { symlinkFollow: false };
79
+ const openFlags = {};
80
+ const descriptorFlags = { read: true };
81
+ const fd = resolved.dir.openAt(pathFlags, resolved.relativePath, openFlags, descriptorFlags);
82
+ const stat = fd.stat();
83
+ const [data] = fd.read(stat.size, BigInt(0));
84
+ return data;
85
+ }
86
+ catch (e) {
87
+ throw new Error(`Failed to read file '${path}': ${e}`);
88
+ }
89
+ }
90
+ /**
91
+ * Write text content to a file.
92
+ *
93
+ * @param path - The path to write.
94
+ * @param content - The text content to write.
95
+ */
96
+ export async function writeText(path, content) {
97
+ const bytes = new TextEncoder().encode(content);
98
+ await writeBytes(path, bytes);
99
+ }
100
+ /**
101
+ * Write bytes to a file.
102
+ *
103
+ * @param path - The path to write.
104
+ * @param data - The bytes to write.
105
+ */
106
+ export async function writeBytes(path, data) {
107
+ const resolved = resolvePath(path);
108
+ if (!resolved) {
109
+ throw new Error("Filesystem not available.");
110
+ }
111
+ try {
112
+ const pathFlags = { symlinkFollow: false };
113
+ const openFlags = { create: true, truncate: true };
114
+ const descriptorFlags = { write: true };
115
+ const fd = resolved.dir.openAt(pathFlags, resolved.relativePath, openFlags, descriptorFlags);
116
+ fd.write(data, BigInt(0));
117
+ }
118
+ catch (e) {
119
+ throw new Error(`Failed to write file '${path}': ${e}`);
120
+ }
121
+ }
122
+ /**
123
+ * List files/directories at a path.
124
+ *
125
+ * @param path - The path to list.
126
+ * @returns A promise that resolves to an array of strings representing the files and directories at the specified path.
127
+ */
128
+ export async function list(path = ".") {
129
+ const resolved = resolvePath(path);
130
+ if (!resolved) {
131
+ throw new Error("Filesystem not available.");
132
+ }
133
+ try {
134
+ let targetDir = resolved.dir;
135
+ if (resolved.relativePath !== ".") {
136
+ const pathFlags = { symlinkFollow: false };
137
+ const openFlags = { directory: true };
138
+ const descriptorFlags = { read: true };
139
+ targetDir = resolved.dir.openAt(pathFlags, resolved.relativePath, openFlags, descriptorFlags);
140
+ }
141
+ const stream = targetDir.readDirectory();
142
+ const entries = [];
143
+ let entry;
144
+ while ((entry = stream.readDirectoryEntry()) !== undefined && entry !== null) {
145
+ if (entry.name) {
146
+ entries.push(entry.name);
147
+ }
148
+ }
149
+ return entries;
150
+ }
151
+ catch (e) {
152
+ throw new Error(`Failed to list directory '${path}': ${e}`);
153
+ }
154
+ }
155
+ /**
156
+ * Check if a file or directory exists.
157
+ *
158
+ * @param path - The path to check.
159
+ * @returns A promise that resolves to a boolean indicating whether the file or directory exists.
160
+ */
161
+ export async function exists(path) {
162
+ const resolved = resolvePath(path);
163
+ if (!resolved) {
164
+ return false;
165
+ }
166
+ try {
167
+ const pathFlags = { symlinkFollow: false };
168
+ const openFlags = {};
169
+ const descriptorFlags = { read: true };
170
+ resolved.dir.openAt(pathFlags, resolved.relativePath, openFlags, descriptorFlags);
171
+ return true;
172
+ }
173
+ catch {
174
+ return false;
175
+ }
176
+ }
177
+ //# sourceMappingURL=files.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"files.js","sourceRoot":"","sources":["../src/files.ts"],"names":[],"mappings":"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"}
package/dist/index.d.ts CHANGED
@@ -15,6 +15,6 @@
15
15
  */
16
16
  export { task, type TaskOptions } from "./task.js";
17
17
  export { TaskRunner, exports, type TaskConfig } from "./app.js";
18
- export * as http from "./http.js";
18
+ export * as files from "./files.js";
19
19
  export { isWasmMode } from "./hostApi.js";
20
20
  //# sourceMappingURL=index.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;GAcG;AAEH,OAAO,EAAE,IAAI,EAAE,KAAK,WAAW,EAAE,MAAM,WAAW,CAAC;AACnD,OAAO,EAAE,UAAU,EAAE,OAAO,EAAE,KAAK,UAAU,EAAE,MAAM,UAAU,CAAC;AAChE,OAAO,KAAK,IAAI,MAAM,WAAW,CAAC;AAClC,OAAO,EAAE,UAAU,EAAE,MAAM,cAAc,CAAC"}
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;GAcG;AAEH,OAAO,EAAE,IAAI,EAAE,KAAK,WAAW,EAAE,MAAM,WAAW,CAAC;AACnD,OAAO,EAAE,UAAU,EAAE,OAAO,EAAE,KAAK,UAAU,EAAE,MAAM,UAAU,CAAC;AAChE,OAAO,KAAK,KAAK,MAAM,YAAY,CAAC;AACpC,OAAO,EAAE,UAAU,EAAE,MAAM,cAAc,CAAC"}
package/dist/index.js CHANGED
@@ -15,6 +15,6 @@
15
15
  */
16
16
  export { task } from "./task.js";
17
17
  export { TaskRunner, exports } from "./app.js";
18
- export * as http from "./http.js";
18
+ export * as files from "./files.js";
19
19
  export { isWasmMode } from "./hostApi.js";
20
20
  //# sourceMappingURL=index.js.map
package/dist/index.js.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;GAcG;AAEH,OAAO,EAAE,IAAI,EAAoB,MAAM,WAAW,CAAC;AACnD,OAAO,EAAE,UAAU,EAAE,OAAO,EAAmB,MAAM,UAAU,CAAC;AAChE,OAAO,KAAK,IAAI,MAAM,WAAW,CAAC;AAClC,OAAO,EAAE,UAAU,EAAE,MAAM,cAAc,CAAC"}
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;GAcG;AAEH,OAAO,EAAE,IAAI,EAAoB,MAAM,WAAW,CAAC;AACnD,OAAO,EAAE,UAAU,EAAE,OAAO,EAAmB,MAAM,UAAU,CAAC;AAChE,OAAO,KAAK,KAAK,MAAM,YAAY,CAAC;AACpC,OAAO,EAAE,UAAU,EAAE,MAAM,cAAc,CAAC"}
package/dist/task.d.ts CHANGED
@@ -19,6 +19,8 @@ export interface TaskOptions {
19
19
  timeout?: string | number;
20
20
  /** Maximum number of retries */
21
21
  maxRetries?: number;
22
+ /** Files/folders accessible in the sandbox, e.g., ["./data"] */
23
+ allowedFiles?: string[];
22
24
  }
23
25
  export declare function task<TArgs extends any[], TReturn>(options: TaskOptions, fn: (...args: TArgs) => TReturn): (...args: TArgs) => TReturn;
24
26
  //# sourceMappingURL=task.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"task.d.ts","sourceRoot":"","sources":["../src/task.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAKH,MAAM,WAAW,WAAW;IAC1B,2BAA2B;IAC3B,IAAI,EAAE,MAAM,CAAC;IACb,gDAAgD;IAChD,OAAO,CAAC,EAAE,KAAK,GAAG,QAAQ,GAAG,MAAM,GAAG,MAAM,CAAC;IAC7C,sCAAsC;IACtC,GAAG,CAAC,EAAE,MAAM,CAAC;IACb;;;;OAIG;IACH,OAAO,CAAC,EAAE,MAAM,GAAG,MAAM,CAAC;IAC1B,gCAAgC;IAChC,UAAU,CAAC,EAAE,MAAM,CAAC;CACrB;AAsDD,wBAAgB,IAAI,CAAC,KAAK,SAAS,GAAG,EAAE,EAAE,OAAO,EAC/C,OAAO,EAAE,WAAW,EACpB,EAAE,EAAE,CAAC,GAAG,IAAI,EAAE,KAAK,KAAK,OAAO,GAC9B,CAAC,GAAG,IAAI,EAAE,KAAK,KAAK,OAAO,CAoC7B"}
1
+ {"version":3,"file":"task.d.ts","sourceRoot":"","sources":["../src/task.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAKH,MAAM,WAAW,WAAW;IAC1B,2BAA2B;IAC3B,IAAI,EAAE,MAAM,CAAC;IACb,gDAAgD;IAChD,OAAO,CAAC,EAAE,KAAK,GAAG,QAAQ,GAAG,MAAM,GAAG,MAAM,CAAC;IAC7C,sCAAsC;IACtC,GAAG,CAAC,EAAE,MAAM,CAAC;IACb;;;;OAIG;IACH,OAAO,CAAC,EAAE,MAAM,GAAG,MAAM,CAAC;IAC1B,gCAAgC;IAChC,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,gEAAgE;IAChE,YAAY,CAAC,EAAE,MAAM,EAAE,CAAC;CACzB;AAoDD,wBAAgB,IAAI,CAAC,KAAK,SAAS,GAAG,EAAE,EAAE,OAAO,EAC/C,OAAO,EAAE,WAAW,EACpB,EAAE,EAAE,CAAC,GAAG,IAAI,EAAE,KAAK,KAAK,OAAO,GAC9B,CAAC,GAAG,IAAI,EAAE,KAAK,KAAK,OAAO,CAqC7B"}
package/dist/task.js CHANGED
@@ -11,7 +11,6 @@ import { isWasmMode, callHost } from "./hostApi.js";
11
11
  *
12
12
  * @example
13
13
  * ```typescript
14
- * // String timeout format
15
14
  * export const greet = task({
16
15
  * name: "greet",
17
16
  * compute: "LOW",
@@ -20,11 +19,10 @@ import { isWasmMode, callHost } from "./hostApi.js";
20
19
  * return `Hello, ${name}!`;
21
20
  * });
22
21
  *
23
- * // Numeric timeout format (milliseconds)
24
22
  * export const process = task({
25
23
  * name: "process",
26
24
  * compute: "HIGH",
27
- * timeout: 30000 // 30 seconds
25
+ * timeout: 30000
28
26
  * }, (data: any): any => {
29
27
  * return processData(data);
30
28
  * });
@@ -61,6 +59,7 @@ export function task(options, fn) {
61
59
  ram: options.ram,
62
60
  timeout: normalizeTimeout(options.timeout),
63
61
  maxRetries: options.maxRetries,
62
+ allowedFiles: options.allowedFiles,
64
63
  };
65
64
  const wrapper = (...args) => {
66
65
  if (!isWasmMode()) {
package/dist/task.js.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"file":"task.js","sourceRoot":"","sources":["../src/task.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAEH,OAAO,EAAE,YAAY,EAAmB,MAAM,UAAU,CAAC;AACzD,OAAO,EAAE,UAAU,EAAE,QAAQ,EAAE,MAAM,cAAc,CAAC;AAwBpD;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA+BG;AAEH;;;;;GAKG;AACH,SAAS,gBAAgB,CAAC,OAAyB;IACjD,IAAI,OAAO,KAAK,SAAS;QAAE,OAAO,SAAS,CAAC;IAC5C,IAAI,OAAO,OAAO,KAAK,QAAQ,EAAE,CAAC;QAChC,OAAO,GAAG,OAAO,IAAI,CAAC;IACxB,CAAC;IACD,OAAO,OAAO,CAAC;AACjB,CAAC;AAED,MAAM,UAAU,IAAI,CAClB,OAAoB,EACpB,EAA+B;IAE/B,MAAM,QAAQ,GAAG,OAAO,CAAC,IAAI,CAAC;IAC9B,IAAI,OAAO,GAAG,OAAO,CAAC,OAAO,EAAE,QAAQ,EAAE,CAAC,WAAW,EAAE,IAAI,QAAQ,CAAC;IAEpE,MAAM,UAAU,GAAe;QAC7B,IAAI,EAAE,QAAQ;QACd,OAAO;QACP,GAAG,EAAE,OAAO,CAAC,GAAG;QAChB,OAAO,EAAE,gBAAgB,CAAC,OAAO,CAAC,OAAO,CAAC;QAC1C,UAAU,EAAE,OAAO,CAAC,UAAU;KAC/B,CAAC;IAEF,MAAM,OAAO,GAAG,CAAC,GAAG,IAAW,EAAW,EAAE;QAC1C,IAAI,CAAC,UAAU,EAAE,EAAE,CAAC;YAClB,OAAO,EAAE,CAAC,GAAG,IAAI,CAAC,CAAC;QACrB,CAAC;QAED,MAAM,UAAU,GAAG,QAAQ,CAAC,QAAQ,EAAE,IAAI,EAAE,UAAU,CAAC,CAAC;QAExD,IAAI,CAAC;YACH,MAAM,MAAM,GAAe,IAAI,CAAC,KAAK,CAAC,UAAU,CAAC,CAAC;YAClD,IAAI,MAAM,CAAC,KAAK,EAAE,CAAC;gBACjB,MAAM,IAAI,KAAK,CAAC,QAAQ,QAAQ,YAAY,MAAM,CAAC,KAAK,EAAE,CAAC,CAAC;YAC9D,CAAC;YACD,OAAO,MAAM,CAAC,MAAiB,CAAC;QAClC,CAAC;QAAC,OAAO,CAAC,EAAE,CAAC;YACX,IAAI,CAAC,YAAY,WAAW,EAAE,CAAC;gBAC7B,OAAO,UAAgC,CAAC;YAC1C,CAAC;YACD,MAAM,CAAC,CAAC;QACV,CAAC;IACH,CAAC,CAAC;IAEF,YAAY,CAAC,QAAQ,EAAE,EAAE,EAAE,UAAU,CAAC,CAAC;IAEvC,OAAO,OAAO,CAAC;AACjB,CAAC"}
1
+ {"version":3,"file":"task.js","sourceRoot":"","sources":["../src/task.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAEH,OAAO,EAAE,YAAY,EAAmB,MAAM,UAAU,CAAC;AACzD,OAAO,EAAE,UAAU,EAAE,QAAQ,EAAE,MAAM,cAAc,CAAC;AA0BpD;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA6BG;AAEH;;;;;GAKG;AACH,SAAS,gBAAgB,CAAC,OAAyB;IACjD,IAAI,OAAO,KAAK,SAAS;QAAE,OAAO,SAAS,CAAC;IAC5C,IAAI,OAAO,OAAO,KAAK,QAAQ,EAAE,CAAC;QAChC,OAAO,GAAG,OAAO,IAAI,CAAC;IACxB,CAAC;IACD,OAAO,OAAO,CAAC;AACjB,CAAC;AAED,MAAM,UAAU,IAAI,CAClB,OAAoB,EACpB,EAA+B;IAE/B,MAAM,QAAQ,GAAG,OAAO,CAAC,IAAI,CAAC;IAC9B,IAAI,OAAO,GAAG,OAAO,CAAC,OAAO,EAAE,QAAQ,EAAE,CAAC,WAAW,EAAE,IAAI,QAAQ,CAAC;IAEpE,MAAM,UAAU,GAAe;QAC7B,IAAI,EAAE,QAAQ;QACd,OAAO;QACP,GAAG,EAAE,OAAO,CAAC,GAAG;QAChB,OAAO,EAAE,gBAAgB,CAAC,OAAO,CAAC,OAAO,CAAC;QAC1C,UAAU,EAAE,OAAO,CAAC,UAAU;QAC9B,YAAY,EAAE,OAAO,CAAC,YAAY;KACnC,CAAC;IAEF,MAAM,OAAO,GAAG,CAAC,GAAG,IAAW,EAAW,EAAE;QAC1C,IAAI,CAAC,UAAU,EAAE,EAAE,CAAC;YAClB,OAAO,EAAE,CAAC,GAAG,IAAI,CAAC,CAAC;QACrB,CAAC;QAED,MAAM,UAAU,GAAG,QAAQ,CAAC,QAAQ,EAAE,IAAI,EAAE,UAAU,CAAC,CAAC;QAExD,IAAI,CAAC;YACH,MAAM,MAAM,GAAe,IAAI,CAAC,KAAK,CAAC,UAAU,CAAC,CAAC;YAClD,IAAI,MAAM,CAAC,KAAK,EAAE,CAAC;gBACjB,MAAM,IAAI,KAAK,CAAC,QAAQ,QAAQ,YAAY,MAAM,CAAC,KAAK,EAAE,CAAC,CAAC;YAC9D,CAAC;YACD,OAAO,MAAM,CAAC,MAAiB,CAAC;QAClC,CAAC;QAAC,OAAO,CAAC,EAAE,CAAC;YACX,IAAI,CAAC,YAAY,WAAW,EAAE,CAAC;gBAC7B,OAAO,UAAgC,CAAC;YAC1C,CAAC;YACD,MAAM,CAAC,CAAC;QACV,CAAC;IACH,CAAC,CAAC;IAEF,YAAY,CAAC,QAAQ,EAAE,EAAE,EAAE,UAAU,CAAC,CAAC;IAEvC,OAAO,OAAO,CAAC;AACjB,CAAC"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@capsule-run/sdk",
3
- "version": "0.2.2",
3
+ "version": "0.3.0",
4
4
  "description": "Capsule JavaScript SDK - run AI agent tasks in secure WASM sandboxes",
5
5
  "type": "module",
6
6
  "main": "./dist/index.js",
@@ -22,7 +22,8 @@
22
22
  },
23
23
  "files": [
24
24
  "dist",
25
- "src"
25
+ "src",
26
+ "README.md"
26
27
  ],
27
28
  "scripts": {
28
29
  "build": "tsc",
package/src/app.ts CHANGED
@@ -13,6 +13,7 @@ export interface TaskConfig {
13
13
  ram?: string;
14
14
  timeout?: string;
15
15
  maxRetries?: number;
16
+ allowedFiles?: string[];
16
17
  }
17
18
 
18
19
  const TASKS: Map<string, TaskInfo<any>> = new Map();
@@ -55,12 +56,6 @@ interface TaskArgs {
55
56
  kwargs?: Record<string, any>;
56
57
  }
57
58
 
58
- interface TaskResult {
59
- result?: any;
60
- error?: string;
61
- traceback?: string;
62
- }
63
-
64
59
  /**
65
60
  * Implementation of the capsule:host/task-runner interface.
66
61
  *
package/src/files.ts ADDED
@@ -0,0 +1,217 @@
1
+ /**
2
+ * Capsule Files API for WASM filesystem access.
3
+ */
4
+
5
+ declare const globalThis: {
6
+ 'wasi:filesystem/types': any;
7
+ 'wasi:filesystem/preopens': any;
8
+ };
9
+
10
+ interface Descriptor {
11
+ read(length: bigint, offset: bigint): [Uint8Array, boolean];
12
+ write(buffer: Uint8Array, offset: bigint): bigint;
13
+ stat(): { size: bigint };
14
+ readDirectory(): any;
15
+ openAt(
16
+ pathFlags: { symlinkFollow?: boolean },
17
+ path: string,
18
+ openFlags: { create?: boolean; directory?: boolean; exclusive?: boolean; truncate?: boolean },
19
+ descriptorFlags: { read?: boolean; write?: boolean; mutateDirectory?: boolean }
20
+ ): Descriptor;
21
+ }
22
+
23
+ interface PreopenedDir {
24
+ descriptor: Descriptor;
25
+ guestPath: string;
26
+ }
27
+
28
+ function getFsBindings(): { types: any; preopens: any } | null {
29
+ try {
30
+ const types = globalThis['wasi:filesystem/types'];
31
+ const preopens = globalThis['wasi:filesystem/preopens'];
32
+ if (types && preopens) {
33
+ return { types, preopens };
34
+ }
35
+ } catch {}
36
+ return null;
37
+ }
38
+
39
+ function getPreopenedDirs(): PreopenedDir[] {
40
+ const fs = getFsBindings();
41
+ if (!fs) return [];
42
+
43
+ try {
44
+ const dirs = fs.preopens.getDirectories();
45
+ return (dirs || []).map((entry: [Descriptor, string]) => ({
46
+ descriptor: entry[0],
47
+ guestPath: entry[1]
48
+ }));
49
+ } catch {
50
+ return [];
51
+ }
52
+ }
53
+
54
+ function normalizePath(path: string): string {
55
+ if (path.startsWith('./')) {
56
+ return path.slice(2);
57
+ }
58
+ return path;
59
+ }
60
+
61
+ function resolvePath(path: string): { dir: Descriptor; relativePath: string } | null {
62
+ const preopens = getPreopenedDirs();
63
+ if (preopens.length === 0) return null;
64
+
65
+ const normalizedPath = normalizePath(path);
66
+
67
+ for (const { descriptor, guestPath } of preopens) {
68
+ const normalizedGuest = normalizePath(guestPath);
69
+
70
+ if (normalizedGuest === '.' || normalizedGuest === '') {
71
+ return { dir: descriptor, relativePath: normalizedPath };
72
+ }
73
+
74
+ if (normalizedPath.startsWith(normalizedGuest + '/')) {
75
+ const relativePath = normalizedPath.slice(normalizedGuest.length + 1);
76
+ return { dir: descriptor, relativePath };
77
+ }
78
+
79
+ if (normalizedPath === normalizedGuest) {
80
+ return { dir: descriptor, relativePath: '.' };
81
+ }
82
+ }
83
+
84
+ return { dir: preopens[0].descriptor, relativePath: normalizedPath };
85
+ }
86
+
87
+ /**
88
+ * Read a file as text.
89
+ *
90
+ * @param path - The path to read.
91
+ * @returns A promise that resolves to a string containing the file contents.
92
+ */
93
+ export async function readText(path: string): Promise<string> {
94
+ const bytes = await readBytes(path);
95
+ return new TextDecoder().decode(bytes);
96
+ }
97
+
98
+ /**
99
+ * Read a file as bytes.
100
+ *
101
+ * @param path - The path to read.
102
+ * @returns A promise that resolves to a Uint8Array containing the file contents.
103
+ */
104
+ export async function readBytes(path: string): Promise<Uint8Array> {
105
+ const resolved = resolvePath(path);
106
+ if (!resolved) {
107
+ throw new Error("Filesystem not available.");
108
+ }
109
+
110
+ try {
111
+ const pathFlags = { symlinkFollow: false };
112
+ const openFlags = {};
113
+ const descriptorFlags = { read: true };
114
+
115
+ const fd = resolved.dir.openAt(pathFlags, resolved.relativePath, openFlags, descriptorFlags);
116
+ const stat = fd.stat();
117
+ const [data] = fd.read(stat.size, BigInt(0));
118
+ return data;
119
+ } catch (e) {
120
+ throw new Error(`Failed to read file '${path}': ${e}`);
121
+ }
122
+ }
123
+
124
+ /**
125
+ * Write text content to a file.
126
+ *
127
+ * @param path - The path to write.
128
+ * @param content - The text content to write.
129
+ */
130
+ export async function writeText(path: string, content: string): Promise<void> {
131
+ const bytes = new TextEncoder().encode(content);
132
+ await writeBytes(path, bytes);
133
+ }
134
+
135
+ /**
136
+ * Write bytes to a file.
137
+ *
138
+ * @param path - The path to write.
139
+ * @param data - The bytes to write.
140
+ */
141
+ export async function writeBytes(path: string, data: Uint8Array): Promise<void> {
142
+ const resolved = resolvePath(path);
143
+ if (!resolved) {
144
+ throw new Error("Filesystem not available.");
145
+ }
146
+
147
+ try {
148
+ const pathFlags = { symlinkFollow: false };
149
+ const openFlags = { create: true, truncate: true };
150
+ const descriptorFlags = { write: true };
151
+
152
+ const fd = resolved.dir.openAt(pathFlags, resolved.relativePath, openFlags, descriptorFlags);
153
+ fd.write(data, BigInt(0));
154
+ } catch (e) {
155
+ throw new Error(`Failed to write file '${path}': ${e}`);
156
+ }
157
+ }
158
+
159
+ /**
160
+ * List files/directories at a path.
161
+ *
162
+ * @param path - The path to list.
163
+ * @returns A promise that resolves to an array of strings representing the files and directories at the specified path.
164
+ */
165
+ export async function list(path: string = "."): Promise<string[]> {
166
+ const resolved = resolvePath(path);
167
+ if (!resolved) {
168
+ throw new Error("Filesystem not available.");
169
+ }
170
+
171
+ try {
172
+ let targetDir = resolved.dir;
173
+ if (resolved.relativePath !== ".") {
174
+ const pathFlags = { symlinkFollow: false };
175
+ const openFlags = { directory: true };
176
+ const descriptorFlags = { read: true };
177
+ targetDir = resolved.dir.openAt(pathFlags, resolved.relativePath, openFlags, descriptorFlags);
178
+ }
179
+
180
+ const stream = targetDir.readDirectory();
181
+ const entries: string[] = [];
182
+
183
+ let entry;
184
+ while ((entry = stream.readDirectoryEntry()) !== undefined && entry !== null) {
185
+ if (entry.name) {
186
+ entries.push(entry.name);
187
+ }
188
+ }
189
+
190
+ return entries;
191
+ } catch (e) {
192
+ throw new Error(`Failed to list directory '${path}': ${e}`);
193
+ }
194
+ }
195
+
196
+ /**
197
+ * Check if a file or directory exists.
198
+ *
199
+ * @param path - The path to check.
200
+ * @returns A promise that resolves to a boolean indicating whether the file or directory exists.
201
+ */
202
+ export async function exists(path: string): Promise<boolean> {
203
+ const resolved = resolvePath(path);
204
+ if (!resolved) {
205
+ return false;
206
+ }
207
+
208
+ try {
209
+ const pathFlags = { symlinkFollow: false };
210
+ const openFlags = {};
211
+ const descriptorFlags = { read: true };
212
+ resolved.dir.openAt(pathFlags, resolved.relativePath, openFlags, descriptorFlags);
213
+ return true;
214
+ } catch {
215
+ return false;
216
+ }
217
+ }
package/src/index.ts CHANGED
@@ -16,5 +16,6 @@
16
16
 
17
17
  export { task, type TaskOptions } from "./task.js";
18
18
  export { TaskRunner, exports, type TaskConfig } from "./app.js";
19
- export * as http from "./http.js";
19
+ export * as files from "./files.js";
20
20
  export { isWasmMode } from "./hostApi.js";
21
+
package/src/task.ts CHANGED
@@ -23,6 +23,8 @@ export interface TaskOptions {
23
23
  timeout?: string | number;
24
24
  /** Maximum number of retries */
25
25
  maxRetries?: number;
26
+ /** Files/folders accessible in the sandbox, e.g., ["./data"] */
27
+ allowedFiles?: string[];
26
28
  }
27
29
 
28
30
  interface TaskResult {
@@ -35,7 +37,6 @@ interface TaskResult {
35
37
  *
36
38
  * @example
37
39
  * ```typescript
38
- * // String timeout format
39
40
  * export const greet = task({
40
41
  * name: "greet",
41
42
  * compute: "LOW",
@@ -44,11 +45,10 @@ interface TaskResult {
44
45
  * return `Hello, ${name}!`;
45
46
  * });
46
47
  *
47
- * // Numeric timeout format (milliseconds)
48
48
  * export const process = task({
49
49
  * name: "process",
50
50
  * compute: "HIGH",
51
- * timeout: 30000 // 30 seconds
51
+ * timeout: 30000
52
52
  * }, (data: any): any => {
53
53
  * return processData(data);
54
54
  * });
@@ -90,6 +90,7 @@ export function task<TArgs extends any[], TReturn>(
90
90
  ram: options.ram,
91
91
  timeout: normalizeTimeout(options.timeout),
92
92
  maxRetries: options.maxRetries,
93
+ allowedFiles: options.allowedFiles,
93
94
  };
94
95
 
95
96
  const wrapper = (...args: TArgs): TReturn => {
package/dist/http.d.ts DELETED
@@ -1,72 +0,0 @@
1
- /**
2
- * Capsule SDK - HTTP Client
3
- *
4
- * This module provides HTTP request functions by calling the host's HTTP implementation.
5
- * In WASM mode, requests go through the Rust host.
6
- * In local mode, uses native fetch for testing.
7
- */
8
- export interface RequestOptions {
9
- headers?: Record<string, string>;
10
- body?: string;
11
- json?: any;
12
- }
13
- /**
14
- * HTTP Response wrapper with convenient methods.
15
- */
16
- export declare class Response {
17
- readonly status: number;
18
- readonly headers: Record<string, string>;
19
- readonly body: string;
20
- constructor(status: number, headers: Record<string, string>, body: string);
21
- /**
22
- * Parse response body as JSON.
23
- */
24
- json<T = any>(): T;
25
- /**
26
- * Get response body as text.
27
- */
28
- text(): string;
29
- /**
30
- * Check if response status is 2xx.
31
- */
32
- ok(): boolean;
33
- toString(): string;
34
- }
35
- /**
36
- * Make an HTTP GET request.
37
- *
38
- * @example
39
- * ```typescript
40
- * const response = http.get("https://api.github.com/zen");
41
- * console.log(response.text());
42
- * ```
43
- */
44
- export declare function get(url: string, options?: Omit<RequestOptions, "body" | "json">): Promise<Response>;
45
- /**
46
- * Make an HTTP POST request.
47
- *
48
- * @example
49
- * ```typescript
50
- * const response = http.post("https://api.example.com/data", {
51
- * json: { key: "value" }
52
- * });
53
- * ```
54
- */
55
- export declare function post(url: string, options?: RequestOptions): Promise<Response>;
56
- /**
57
- * Make an HTTP PUT request.
58
- */
59
- export declare function put(url: string, options?: RequestOptions): Promise<Response>;
60
- /**
61
- * Make an HTTP DELETE request.
62
- */
63
- export declare function del(url: string, options?: Omit<RequestOptions, "body" | "json">): Promise<Response>;
64
- /**
65
- * Make an HTTP PATCH request.
66
- */
67
- export declare function patch(url: string, options?: RequestOptions): Promise<Response>;
68
- /**
69
- * Make an HTTP HEAD request.
70
- */
71
- export declare function head(url: string, options?: Omit<RequestOptions, "body" | "json">): Promise<Response>;
72
- //# sourceMappingURL=http.d.ts.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"http.d.ts","sourceRoot":"","sources":["../src/http.ts"],"names":[],"mappings":"AAAA;;;;;;GAMG;AAIH,MAAM,WAAW,cAAc;IAC7B,OAAO,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;IACjC,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,IAAI,CAAC,EAAE,GAAG,CAAC;CACZ;AAED;;GAEG;AACH,qBAAa,QAAQ;IACnB,QAAQ,CAAC,MAAM,EAAE,MAAM,CAAC;IACxB,QAAQ,CAAC,OAAO,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;IACzC,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAC;gBAEV,MAAM,EAAE,MAAM,EAAE,OAAO,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,EAAE,IAAI,EAAE,MAAM;IAMzE;;OAEG;IACH,IAAI,CAAC,CAAC,GAAG,GAAG,KAAK,CAAC;IAIlB;;OAEG;IACH,IAAI,IAAI,MAAM;IAId;;OAEG;IACH,EAAE,IAAI,OAAO;IAIb,QAAQ,IAAI,MAAM;CAGnB;AA+FD;;;;;;;;GAQG;AACH,wBAAsB,GAAG,CACvB,GAAG,EAAE,MAAM,EACX,OAAO,GAAE,IAAI,CAAC,cAAc,EAAE,MAAM,GAAG,MAAM,CAAM,GAClD,OAAO,CAAC,QAAQ,CAAC,CAEnB;AAED;;;;;;;;;GASG;AACH,wBAAsB,IAAI,CACxB,GAAG,EAAE,MAAM,EACX,OAAO,GAAE,cAAmB,GAC3B,OAAO,CAAC,QAAQ,CAAC,CAEnB;AAED;;GAEG;AACH,wBAAsB,GAAG,CACvB,GAAG,EAAE,MAAM,EACX,OAAO,GAAE,cAAmB,GAC3B,OAAO,CAAC,QAAQ,CAAC,CAEnB;AAED;;GAEG;AACH,wBAAsB,GAAG,CACvB,GAAG,EAAE,MAAM,EACX,OAAO,GAAE,IAAI,CAAC,cAAc,EAAE,MAAM,GAAG,MAAM,CAAM,GAClD,OAAO,CAAC,QAAQ,CAAC,CAEnB;AAED;;GAEG;AACH,wBAAsB,KAAK,CACzB,GAAG,EAAE,MAAM,EACX,OAAO,GAAE,cAAmB,GAC3B,OAAO,CAAC,QAAQ,CAAC,CAEnB;AAED;;GAEG;AACH,wBAAsB,IAAI,CACxB,GAAG,EAAE,MAAM,EACX,OAAO,GAAE,IAAI,CAAC,cAAc,EAAE,MAAM,GAAG,MAAM,CAAM,GAClD,OAAO,CAAC,QAAQ,CAAC,CAEnB"}
package/dist/http.js DELETED
@@ -1,154 +0,0 @@
1
- /**
2
- * Capsule SDK - HTTP Client
3
- *
4
- * This module provides HTTP request functions by calling the host's HTTP implementation.
5
- * In WASM mode, requests go through the Rust host.
6
- * In local mode, uses native fetch for testing.
7
- */
8
- import { isWasmMode } from "./hostApi.js";
9
- /**
10
- * HTTP Response wrapper with convenient methods.
11
- */
12
- export class Response {
13
- constructor(status, headers, body) {
14
- this.status = status;
15
- this.headers = headers;
16
- this.body = body;
17
- }
18
- /**
19
- * Parse response body as JSON.
20
- */
21
- json() {
22
- return JSON.parse(this.body);
23
- }
24
- /**
25
- * Get response body as text.
26
- */
27
- text() {
28
- return this.body;
29
- }
30
- /**
31
- * Check if response status is 2xx.
32
- */
33
- ok() {
34
- return this.status >= 200 && this.status < 300;
35
- }
36
- toString() {
37
- return `<Response [${this.status}]>`;
38
- }
39
- }
40
- /**
41
- * Internal function to make HTTP requests.
42
- * In WASM mode: calls the host API
43
- * In local mode: uses fetch
44
- */
45
- async function makeRequest(method, url, options = {}) {
46
- return isWasmMode()
47
- ? makeHostRequest(method, url, options)
48
- : makeLocalRequest(method, url, options);
49
- }
50
- /**
51
- * Make HTTP request using native fetch (local mode only).
52
- */
53
- async function makeLocalRequest(method, url, options = {}) {
54
- const headers = { ...options.headers };
55
- let body = options.body;
56
- if (options.json !== undefined) {
57
- body = JSON.stringify(options.json);
58
- headers["Content-Type"] = "application/json";
59
- }
60
- const fetchOptions = {
61
- method,
62
- headers,
63
- };
64
- if (body !== undefined) {
65
- fetchOptions.body = body;
66
- }
67
- const fetchResponse = await fetch(url, fetchOptions);
68
- const responseText = await fetchResponse.text();
69
- const responseHeaders = {};
70
- fetchResponse.headers.forEach((value, key) => {
71
- responseHeaders[key] = value;
72
- });
73
- return new Response(fetchResponse.status, responseHeaders, responseText);
74
- }
75
- /**
76
- * Make HTTP request via the Rust host (WASM mode).
77
- */
78
- function makeHostRequest(method, url, options = {}) {
79
- try {
80
- const hostModule = globalThis["capsule:host/api"];
81
- if (!hostModule || !hostModule.httpRequest) {
82
- throw new Error("Host HTTP API not available");
83
- }
84
- const headers = [];
85
- const requestHeaders = options.headers || {};
86
- for (const [key, value] of Object.entries(requestHeaders)) {
87
- headers.push([key, value]);
88
- }
89
- let body = options.body;
90
- if (options.json !== undefined) {
91
- body = JSON.stringify(options.json);
92
- headers.push(["Content-Type", "application/json"]);
93
- }
94
- const result = hostModule.httpRequest(method, url, headers, body);
95
- const responseHeaders = {};
96
- for (const [key, value] of result.headers) {
97
- responseHeaders[key] = value;
98
- }
99
- return new Response(result.status, responseHeaders, result.body);
100
- }
101
- catch (error) {
102
- throw new Error(`HTTP request failed: ${error instanceof Error ? error.message : String(error)}`);
103
- }
104
- }
105
- /**
106
- * Make an HTTP GET request.
107
- *
108
- * @example
109
- * ```typescript
110
- * const response = http.get("https://api.github.com/zen");
111
- * console.log(response.text());
112
- * ```
113
- */
114
- export async function get(url, options = {}) {
115
- return makeRequest("GET", url, options);
116
- }
117
- /**
118
- * Make an HTTP POST request.
119
- *
120
- * @example
121
- * ```typescript
122
- * const response = http.post("https://api.example.com/data", {
123
- * json: { key: "value" }
124
- * });
125
- * ```
126
- */
127
- export async function post(url, options = {}) {
128
- return makeRequest("POST", url, options);
129
- }
130
- /**
131
- * Make an HTTP PUT request.
132
- */
133
- export async function put(url, options = {}) {
134
- return makeRequest("PUT", url, options);
135
- }
136
- /**
137
- * Make an HTTP DELETE request.
138
- */
139
- export async function del(url, options = {}) {
140
- return makeRequest("DELETE", url, options);
141
- }
142
- /**
143
- * Make an HTTP PATCH request.
144
- */
145
- export async function patch(url, options = {}) {
146
- return makeRequest("PATCH", url, options);
147
- }
148
- /**
149
- * Make an HTTP HEAD request.
150
- */
151
- export async function head(url, options = {}) {
152
- return makeRequest("HEAD", url, options);
153
- }
154
- //# sourceMappingURL=http.js.map
package/dist/http.js.map DELETED
@@ -1 +0,0 @@
1
- {"version":3,"file":"http.js","sourceRoot":"","sources":["../src/http.ts"],"names":[],"mappings":"AAAA;;;;;;GAMG;AAEH,OAAO,EAAE,UAAU,EAAE,MAAM,cAAc,CAAC;AAQ1C;;GAEG;AACH,MAAM,OAAO,QAAQ;IAKnB,YAAY,MAAc,EAAE,OAA+B,EAAE,IAAY;QACvE,IAAI,CAAC,MAAM,GAAG,MAAM,CAAC;QACrB,IAAI,CAAC,OAAO,GAAG,OAAO,CAAC;QACvB,IAAI,CAAC,IAAI,GAAG,IAAI,CAAC;IACnB,CAAC;IAED;;OAEG;IACH,IAAI;QACF,OAAO,IAAI,CAAC,KAAK,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;IAC/B,CAAC;IAED;;OAEG;IACH,IAAI;QACF,OAAO,IAAI,CAAC,IAAI,CAAC;IACnB,CAAC;IAED;;OAEG;IACH,EAAE;QACA,OAAO,IAAI,CAAC,MAAM,IAAI,GAAG,IAAI,IAAI,CAAC,MAAM,GAAG,GAAG,CAAC;IACjD,CAAC;IAED,QAAQ;QACN,OAAO,cAAc,IAAI,CAAC,MAAM,IAAI,CAAC;IACvC,CAAC;CACF;AAED;;;;GAIG;AACH,KAAK,UAAU,WAAW,CACxB,MAAc,EACd,GAAW,EACX,UAA0B,EAAE;IAE5B,OAAO,UAAU,EAAE;QACjB,CAAC,CAAC,eAAe,CAAC,MAAM,EAAE,GAAG,EAAE,OAAO,CAAC;QACvC,CAAC,CAAC,gBAAgB,CAAC,MAAM,EAAE,GAAG,EAAE,OAAO,CAAC,CAAC;AAC7C,CAAC;AAED;;GAEG;AACH,KAAK,UAAU,gBAAgB,CAC7B,MAAc,EACd,GAAW,EACX,UAA0B,EAAE;IAE5B,MAAM,OAAO,GAA2B,EAAE,GAAG,OAAO,CAAC,OAAO,EAAE,CAAC;IAC/D,IAAI,IAAI,GAAuB,OAAO,CAAC,IAAI,CAAC;IAE5C,IAAI,OAAO,CAAC,IAAI,KAAK,SAAS,EAAE,CAAC;QAC/B,IAAI,GAAG,IAAI,CAAC,SAAS,CAAC,OAAO,CAAC,IAAI,CAAC,CAAC;QACpC,OAAO,CAAC,cAAc,CAAC,GAAG,kBAAkB,CAAC;IAC/C,CAAC;IAED,MAAM,YAAY,GAAgB;QAChC,MAAM;QACN,OAAO;KACR,CAAC;IAEF,IAAI,IAAI,KAAK,SAAS,EAAE,CAAC;QACvB,YAAY,CAAC,IAAI,GAAG,IAAI,CAAC;IAC3B,CAAC;IAED,MAAM,aAAa,GAAG,MAAM,KAAK,CAAC,GAAG,EAAE,YAAY,CAAC,CAAC;IACrD,MAAM,YAAY,GAAG,MAAM,aAAa,CAAC,IAAI,EAAE,CAAC;IAEhD,MAAM,eAAe,GAA2B,EAAE,CAAC;IACnD,aAAa,CAAC,OAAO,CAAC,OAAO,CAAC,CAAC,KAAK,EAAE,GAAG,EAAE,EAAE;QAC3C,eAAe,CAAC,GAAG,CAAC,GAAG,KAAK,CAAC;IAC/B,CAAC,CAAC,CAAC;IAEH,OAAO,IAAI,QAAQ,CAAC,aAAa,CAAC,MAAM,EAAE,eAAe,EAAE,YAAY,CAAC,CAAC;AAC3E,CAAC;AAED;;GAEG;AACH,SAAS,eAAe,CACtB,MAAc,EACd,GAAW,EACX,UAA0B,EAAE;IAE5B,IAAI,CAAC;QACH,MAAM,UAAU,GAAI,UAAkB,CAAC,kBAAkB,CAAC,CAAC;QAE3D,IAAI,CAAC,UAAU,IAAI,CAAC,UAAU,CAAC,WAAW,EAAE,CAAC;YAC3C,MAAM,IAAI,KAAK,CAAC,6BAA6B,CAAC,CAAC;QACjD,CAAC;QAED,MAAM,OAAO,GAAuB,EAAE,CAAC;QACvC,MAAM,cAAc,GAAG,OAAO,CAAC,OAAO,IAAI,EAAE,CAAC;QAE7C,KAAK,MAAM,CAAC,GAAG,EAAE,KAAK,CAAC,IAAI,MAAM,CAAC,OAAO,CAAC,cAAc,CAAC,EAAE,CAAC;YAC1D,OAAO,CAAC,IAAI,CAAC,CAAC,GAAG,EAAE,KAAK,CAAC,CAAC,CAAC;QAC7B,CAAC;QAED,IAAI,IAAI,GAAuB,OAAO,CAAC,IAAI,CAAC;QAE5C,IAAI,OAAO,CAAC,IAAI,KAAK,SAAS,EAAE,CAAC;YAC/B,IAAI,GAAG,IAAI,CAAC,SAAS,CAAC,OAAO,CAAC,IAAI,CAAC,CAAC;YACpC,OAAO,CAAC,IAAI,CAAC,CAAC,cAAc,EAAE,kBAAkB,CAAC,CAAC,CAAC;QACrD,CAAC;QAED,MAAM,MAAM,GAAG,UAAU,CAAC,WAAW,CAAC,MAAM,EAAE,GAAG,EAAE,OAAO,EAAE,IAAI,CAAC,CAAC;QAElE,MAAM,eAAe,GAA2B,EAAE,CAAC;QACnD,KAAK,MAAM,CAAC,GAAG,EAAE,KAAK,CAAC,IAAI,MAAM,CAAC,OAAO,EAAE,CAAC;YAC1C,eAAe,CAAC,GAAG,CAAC,GAAG,KAAK,CAAC;QAC/B,CAAC;QAED,OAAO,IAAI,QAAQ,CAAC,MAAM,CAAC,MAAM,EAAE,eAAe,EAAE,MAAM,CAAC,IAAI,CAAC,CAAC;IACnE,CAAC;IAAC,OAAO,KAAK,EAAE,CAAC;QACf,MAAM,IAAI,KAAK,CAAC,wBAAwB,KAAK,YAAY,KAAK,CAAC,CAAC,CAAC,KAAK,CAAC,OAAO,CAAC,CAAC,CAAC,MAAM,CAAC,KAAK,CAAC,EAAE,CAAC,CAAC;IACpG,CAAC;AACH,CAAC;AAED;;;;;;;;GAQG;AACH,MAAM,CAAC,KAAK,UAAU,GAAG,CACvB,GAAW,EACX,UAAiD,EAAE;IAEnD,OAAO,WAAW,CAAC,KAAK,EAAE,GAAG,EAAE,OAAO,CAAC,CAAC;AAC1C,CAAC;AAED;;;;;;;;;GASG;AACH,MAAM,CAAC,KAAK,UAAU,IAAI,CACxB,GAAW,EACX,UAA0B,EAAE;IAE5B,OAAO,WAAW,CAAC,MAAM,EAAE,GAAG,EAAE,OAAO,CAAC,CAAC;AAC3C,CAAC;AAED;;GAEG;AACH,MAAM,CAAC,KAAK,UAAU,GAAG,CACvB,GAAW,EACX,UAA0B,EAAE;IAE5B,OAAO,WAAW,CAAC,KAAK,EAAE,GAAG,EAAE,OAAO,CAAC,CAAC;AAC1C,CAAC;AAED;;GAEG;AACH,MAAM,CAAC,KAAK,UAAU,GAAG,CACvB,GAAW,EACX,UAAiD,EAAE;IAEnD,OAAO,WAAW,CAAC,QAAQ,EAAE,GAAG,EAAE,OAAO,CAAC,CAAC;AAC7C,CAAC;AAED;;GAEG;AACH,MAAM,CAAC,KAAK,UAAU,KAAK,CACzB,GAAW,EACX,UAA0B,EAAE;IAE5B,OAAO,WAAW,CAAC,OAAO,EAAE,GAAG,EAAE,OAAO,CAAC,CAAC;AAC5C,CAAC;AAED;;GAEG;AACH,MAAM,CAAC,KAAK,UAAU,IAAI,CACxB,GAAW,EACX,UAAiD,EAAE;IAEnD,OAAO,WAAW,CAAC,MAAM,EAAE,GAAG,EAAE,OAAO,CAAC,CAAC;AAC3C,CAAC"}
package/src/http.ts DELETED
@@ -1,221 +0,0 @@
1
- /**
2
- * Capsule SDK - HTTP Client
3
- *
4
- * This module provides HTTP request functions by calling the host's HTTP implementation.
5
- * In WASM mode, requests go through the Rust host.
6
- * In local mode, uses native fetch for testing.
7
- */
8
-
9
- import { isWasmMode } from "./hostApi.js";
10
-
11
- export interface RequestOptions {
12
- headers?: Record<string, string>;
13
- body?: string;
14
- json?: any;
15
- }
16
-
17
- /**
18
- * HTTP Response wrapper with convenient methods.
19
- */
20
- export class Response {
21
- readonly status: number;
22
- readonly headers: Record<string, string>;
23
- readonly body: string;
24
-
25
- constructor(status: number, headers: Record<string, string>, body: string) {
26
- this.status = status;
27
- this.headers = headers;
28
- this.body = body;
29
- }
30
-
31
- /**
32
- * Parse response body as JSON.
33
- */
34
- json<T = any>(): T {
35
- return JSON.parse(this.body);
36
- }
37
-
38
- /**
39
- * Get response body as text.
40
- */
41
- text(): string {
42
- return this.body;
43
- }
44
-
45
- /**
46
- * Check if response status is 2xx.
47
- */
48
- ok(): boolean {
49
- return this.status >= 200 && this.status < 300;
50
- }
51
-
52
- toString(): string {
53
- return `<Response [${this.status}]>`;
54
- }
55
- }
56
-
57
- /**
58
- * Internal function to make HTTP requests.
59
- * In WASM mode: calls the host API
60
- * In local mode: uses fetch
61
- */
62
- async function makeRequest(
63
- method: string,
64
- url: string,
65
- options: RequestOptions = {}
66
- ): Promise<Response> {
67
- return isWasmMode()
68
- ? makeHostRequest(method, url, options)
69
- : makeLocalRequest(method, url, options);
70
- }
71
-
72
- /**
73
- * Make HTTP request using native fetch (local mode only).
74
- */
75
- async function makeLocalRequest(
76
- method: string,
77
- url: string,
78
- options: RequestOptions = {}
79
- ): Promise<Response> {
80
- const headers: Record<string, string> = { ...options.headers };
81
- let body: string | undefined = options.body;
82
-
83
- if (options.json !== undefined) {
84
- body = JSON.stringify(options.json);
85
- headers["Content-Type"] = "application/json";
86
- }
87
-
88
- const fetchOptions: RequestInit = {
89
- method,
90
- headers,
91
- };
92
-
93
- if (body !== undefined) {
94
- fetchOptions.body = body;
95
- }
96
-
97
- const fetchResponse = await fetch(url, fetchOptions);
98
- const responseText = await fetchResponse.text();
99
-
100
- const responseHeaders: Record<string, string> = {};
101
- fetchResponse.headers.forEach((value, key) => {
102
- responseHeaders[key] = value;
103
- });
104
-
105
- return new Response(fetchResponse.status, responseHeaders, responseText);
106
- }
107
-
108
- /**
109
- * Make HTTP request via the Rust host (WASM mode).
110
- */
111
- function makeHostRequest(
112
- method: string,
113
- url: string,
114
- options: RequestOptions = {}
115
- ): Response {
116
- try {
117
- const hostModule = (globalThis as any)["capsule:host/api"];
118
-
119
- if (!hostModule || !hostModule.httpRequest) {
120
- throw new Error("Host HTTP API not available");
121
- }
122
-
123
- const headers: [string, string][] = [];
124
- const requestHeaders = options.headers || {};
125
-
126
- for (const [key, value] of Object.entries(requestHeaders)) {
127
- headers.push([key, value]);
128
- }
129
-
130
- let body: string | undefined = options.body;
131
-
132
- if (options.json !== undefined) {
133
- body = JSON.stringify(options.json);
134
- headers.push(["Content-Type", "application/json"]);
135
- }
136
-
137
- const result = hostModule.httpRequest(method, url, headers, body);
138
-
139
- const responseHeaders: Record<string, string> = {};
140
- for (const [key, value] of result.headers) {
141
- responseHeaders[key] = value;
142
- }
143
-
144
- return new Response(result.status, responseHeaders, result.body);
145
- } catch (error) {
146
- throw new Error(`HTTP request failed: ${error instanceof Error ? error.message : String(error)}`);
147
- }
148
- }
149
-
150
- /**
151
- * Make an HTTP GET request.
152
- *
153
- * @example
154
- * ```typescript
155
- * const response = http.get("https://api.github.com/zen");
156
- * console.log(response.text());
157
- * ```
158
- */
159
- export async function get(
160
- url: string,
161
- options: Omit<RequestOptions, "body" | "json"> = {}
162
- ): Promise<Response> {
163
- return makeRequest("GET", url, options);
164
- }
165
-
166
- /**
167
- * Make an HTTP POST request.
168
- *
169
- * @example
170
- * ```typescript
171
- * const response = http.post("https://api.example.com/data", {
172
- * json: { key: "value" }
173
- * });
174
- * ```
175
- */
176
- export async function post(
177
- url: string,
178
- options: RequestOptions = {}
179
- ): Promise<Response> {
180
- return makeRequest("POST", url, options);
181
- }
182
-
183
- /**
184
- * Make an HTTP PUT request.
185
- */
186
- export async function put(
187
- url: string,
188
- options: RequestOptions = {}
189
- ): Promise<Response> {
190
- return makeRequest("PUT", url, options);
191
- }
192
-
193
- /**
194
- * Make an HTTP DELETE request.
195
- */
196
- export async function del(
197
- url: string,
198
- options: Omit<RequestOptions, "body" | "json"> = {}
199
- ): Promise<Response> {
200
- return makeRequest("DELETE", url, options);
201
- }
202
-
203
- /**
204
- * Make an HTTP PATCH request.
205
- */
206
- export async function patch(
207
- url: string,
208
- options: RequestOptions = {}
209
- ): Promise<Response> {
210
- return makeRequest("PATCH", url, options);
211
- }
212
-
213
- /**
214
- * Make an HTTP HEAD request.
215
- */
216
- export async function head(
217
- url: string,
218
- options: Omit<RequestOptions, "body" | "json"> = {}
219
- ): Promise<Response> {
220
- return makeRequest("HEAD", url, options);
221
- }