@capsule-run/sdk 0.1.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/dist/app.d.ts ADDED
@@ -0,0 +1,45 @@
1
+ /**
2
+ * Capsule SDK - Task Registry and TaskRunner
3
+ */
4
+ export interface TaskInfo<T extends (...args: any[]) => any> {
5
+ func: T;
6
+ config: TaskConfig;
7
+ }
8
+ export interface TaskConfig {
9
+ name: string;
10
+ compute?: string;
11
+ ram?: string;
12
+ timeout?: string;
13
+ maxRetries?: number;
14
+ }
15
+ /**
16
+ * Register a task function by name with its configuration.
17
+ */
18
+ export declare function registerTask<T extends (...args: any[]) => any>(name: string, func: T, config: TaskConfig): void;
19
+ /**
20
+ * Get a registered task by name.
21
+ */
22
+ export declare function getTask(name: string): ((...args: any[]) => any) | undefined;
23
+ /**
24
+ * Get the configuration for a registered task.
25
+ */
26
+ export declare function getTaskConfig(name: string): TaskConfig | undefined;
27
+ /**
28
+ * Get all registered task names.
29
+ */
30
+ export declare function getTaskNames(): string[];
31
+ /**
32
+ * Implementation of the capsule:host/task-runner interface.
33
+ *
34
+ * This class is instantiated by capsule-core when the component is loaded.
35
+ * The Rust host calls `run(argsJson)` to execute a task.
36
+ */
37
+ export declare class TaskRunner {
38
+ /**
39
+ * Execute a task with the given arguments.
40
+ * Returns Ok(result_json) on success, Err(error_message) on failure.
41
+ */
42
+ run(argsJson: string): Promise<string>;
43
+ }
44
+ export declare const exports: TaskRunner;
45
+ //# sourceMappingURL=app.d.ts.map
@@ -0,0 +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"}
package/dist/app.js ADDED
@@ -0,0 +1,75 @@
1
+ /**
2
+ * Capsule SDK - Task Registry and TaskRunner
3
+ */
4
+ const TASKS = new Map();
5
+ /**
6
+ * Register a task function by name with its configuration.
7
+ */
8
+ export function registerTask(name, func, config) {
9
+ TASKS.set(name, { func, config });
10
+ }
11
+ /**
12
+ * Get a registered task by name.
13
+ */
14
+ export function getTask(name) {
15
+ return TASKS.get(name)?.func;
16
+ }
17
+ /**
18
+ * Get the configuration for a registered task.
19
+ */
20
+ export function getTaskConfig(name) {
21
+ return TASKS.get(name)?.config;
22
+ }
23
+ /**
24
+ * Get all registered task names.
25
+ */
26
+ export function getTaskNames() {
27
+ return Array.from(TASKS.keys());
28
+ }
29
+ /**
30
+ * Implementation of the capsule:host/task-runner interface.
31
+ *
32
+ * This class is instantiated by capsule-core when the component is loaded.
33
+ * The Rust host calls `run(argsJson)` to execute a task.
34
+ */
35
+ export class TaskRunner {
36
+ /**
37
+ * Execute a task with the given arguments.
38
+ * Returns Ok(result_json) on success, Err(error_message) on failure.
39
+ */
40
+ async run(argsJson) {
41
+ try {
42
+ const data = JSON.parse(argsJson);
43
+ const taskName = data.task_name ?? "main";
44
+ const args = data.args ?? [];
45
+ const kwargs = data.kwargs ?? {};
46
+ let taskFunc = getTask(taskName);
47
+ if (!taskFunc && taskName !== "main") {
48
+ taskFunc = getTask("main");
49
+ }
50
+ if (!taskFunc && TASKS.size > 0) {
51
+ const firstTaskName = TASKS.keys().next().value;
52
+ if (firstTaskName) {
53
+ taskFunc = getTask(firstTaskName);
54
+ }
55
+ }
56
+ if (!taskFunc) {
57
+ throw `No tasks or main() function found. Available tasks: ${getTaskNames().join(", ")}`;
58
+ }
59
+ const result = taskFunc(...args, kwargs);
60
+ if (result instanceof Promise) {
61
+ const asyncResult = await result;
62
+ return JSON.stringify({ result: asyncResult ?? null });
63
+ }
64
+ return JSON.stringify({ result: result ?? null });
65
+ }
66
+ catch (e) {
67
+ const errorMsg = e instanceof Error
68
+ ? `${e.message}\n${e.stack || ''}`
69
+ : String(e);
70
+ throw errorMsg;
71
+ }
72
+ }
73
+ }
74
+ export const exports = new TaskRunner();
75
+ //# sourceMappingURL=app.js.map
@@ -0,0 +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"}
@@ -0,0 +1,18 @@
1
+ /**
2
+ * Capsule SDK - Host API Interface
3
+ *
4
+ * This module provides the interface to call host functions from JavaScript/TypeScript Wasm code.
5
+ * When running in WASM mode, it imports the auto-generated bindings from jco.
6
+ * When running locally, it provides mock implementations for testing.
7
+ */
8
+ /**
9
+ * Check if running in WASM mode.
10
+ */
11
+ export declare function isWasmMode(): boolean;
12
+ /**
13
+ * Call the host's schedule_task function to create a new isolated task instance.
14
+ *
15
+ * This is the bridge between JavaScript code and the Rust host runtime.
16
+ */
17
+ export declare function callHost(name: string, args: any[], config: Record<string, any>): string;
18
+ //# sourceMappingURL=hostApi.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"hostApi.d.ts","sourceRoot":"","sources":["../src/hostApi.ts"],"names":[],"mappings":"AAAA;;;;;;GAMG;AA4BH;;GAEG;AACH,wBAAgB,UAAU,IAAI,OAAO,CAEpC;AAED;;;;GAIG;AACH,wBAAgB,QAAQ,CACtB,IAAI,EAAE,MAAM,EACZ,IAAI,EAAE,GAAG,EAAE,EACX,MAAM,EAAE,MAAM,CAAC,MAAM,EAAE,GAAG,CAAC,GAC1B,MAAM,CAgBR"}
@@ -0,0 +1,59 @@
1
+ /**
2
+ * Capsule SDK - Host API Interface
3
+ *
4
+ * This module provides the interface to call host functions from JavaScript/TypeScript Wasm code.
5
+ * When running in WASM mode, it imports the auto-generated bindings from jco.
6
+ * When running locally, it provides mock implementations for testing.
7
+ */
8
+ let hostModule = null;
9
+ let isWasmChecked = false;
10
+ let isWasm = false;
11
+ /**
12
+ * Lazily check if we're running in WASM mode.
13
+ */
14
+ function checkWasm() {
15
+ if (!isWasmChecked) {
16
+ try {
17
+ const witBinding = globalThis["capsule:host/api"];
18
+ if (typeof witBinding !== "undefined" && typeof witBinding.scheduleTask === "function") {
19
+ hostModule = witBinding;
20
+ isWasm = true;
21
+ }
22
+ else {
23
+ isWasm = false;
24
+ }
25
+ }
26
+ catch (e) {
27
+ isWasm = false;
28
+ }
29
+ isWasmChecked = true;
30
+ }
31
+ return isWasm;
32
+ }
33
+ /**
34
+ * Check if running in WASM mode.
35
+ */
36
+ export function isWasmMode() {
37
+ return checkWasm();
38
+ }
39
+ /**
40
+ * Call the host's schedule_task function to create a new isolated task instance.
41
+ *
42
+ * This is the bridge between JavaScript code and the Rust host runtime.
43
+ */
44
+ export function callHost(name, args, config) {
45
+ if (checkWasm() && hostModule !== null) {
46
+ try {
47
+ const result = hostModule.scheduleTask(name, JSON.stringify(args), JSON.stringify(config));
48
+ return result;
49
+ }
50
+ catch (e) {
51
+ const error = e instanceof Error ? e.message : String(e);
52
+ return JSON.stringify({ error: `Host call failed: ${error}` });
53
+ }
54
+ }
55
+ else {
56
+ return JSON.stringify({ result: `mock_result_for_${name}` });
57
+ }
58
+ }
59
+ //# sourceMappingURL=hostApi.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"hostApi.js","sourceRoot":"","sources":["../src/hostApi.ts"],"names":[],"mappings":"AAAA;;;;;;GAMG;AAEH,IAAI,UAAU,GAAQ,IAAI,CAAC;AAC3B,IAAI,aAAa,GAAG,KAAK,CAAC;AAC1B,IAAI,MAAM,GAAG,KAAK,CAAC;AAEnB;;GAEG;AACH,SAAS,SAAS;IAChB,IAAI,CAAC,aAAa,EAAE,CAAC;QACnB,IAAI,CAAC;YACH,MAAM,UAAU,GAAI,UAAkB,CAAC,kBAAkB,CAAC,CAAC;YAE3D,IAAI,OAAO,UAAU,KAAK,WAAW,IAAI,OAAO,UAAU,CAAC,YAAY,KAAK,UAAU,EAAE,CAAC;gBACvF,UAAU,GAAG,UAAU,CAAC;gBACxB,MAAM,GAAG,IAAI,CAAC;YAChB,CAAC;iBAAM,CAAC;gBACN,MAAM,GAAG,KAAK,CAAC;YACjB,CAAC;QACH,CAAC;QAAC,OAAO,CAAC,EAAE,CAAC;YACX,MAAM,GAAG,KAAK,CAAC;QACjB,CAAC;QACD,aAAa,GAAG,IAAI,CAAC;IACvB,CAAC;IACD,OAAO,MAAM,CAAC;AAChB,CAAC;AAED;;GAEG;AACH,MAAM,UAAU,UAAU;IACxB,OAAO,SAAS,EAAE,CAAC;AACrB,CAAC;AAED;;;;GAIG;AACH,MAAM,UAAU,QAAQ,CACtB,IAAY,EACZ,IAAW,EACX,MAA2B;IAE3B,IAAI,SAAS,EAAE,IAAI,UAAU,KAAK,IAAI,EAAE,CAAC;QACvC,IAAI,CAAC;YACH,MAAM,MAAM,GAAG,UAAU,CAAC,YAAY,CACpC,IAAI,EACJ,IAAI,CAAC,SAAS,CAAC,IAAI,CAAC,EACpB,IAAI,CAAC,SAAS,CAAC,MAAM,CAAC,CACvB,CAAC;YACF,OAAO,MAAM,CAAC;QAChB,CAAC;QAAC,OAAO,CAAC,EAAE,CAAC;YACX,MAAM,KAAK,GAAG,CAAC,YAAY,KAAK,CAAC,CAAC,CAAC,CAAC,CAAC,OAAO,CAAC,CAAC,CAAC,MAAM,CAAC,CAAC,CAAC,CAAC;YACzD,OAAO,IAAI,CAAC,SAAS,CAAC,EAAE,KAAK,EAAE,qBAAqB,KAAK,EAAE,EAAE,CAAC,CAAC;QACjE,CAAC;IACH,CAAC;SAAM,CAAC;QACN,OAAO,IAAI,CAAC,SAAS,CAAC,EAAE,MAAM,EAAE,mBAAmB,IAAI,EAAE,EAAE,CAAC,CAAC;IAC/D,CAAC;AACH,CAAC"}
package/dist/http.d.ts ADDED
@@ -0,0 +1,72 @@
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
@@ -0,0 +1 @@
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 ADDED
@@ -0,0 +1,154 @@
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
@@ -0,0 +1 @@
1
+ {"version":3,"file":"http.js","sourceRoot":"","sources":["../src/http.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,20 @@
1
+ /**
2
+ * Capsule SDK for JavaScript/TypeScript
3
+ *
4
+ * @example
5
+ * ```typescript
6
+ * import { task } from '@capsule/sdk';
7
+ *
8
+ * export const greet = task({
9
+ * name: "greet",
10
+ * compute: "LOW"
11
+ * }, (name: string): string => {
12
+ * return `Hello, ${name}!`;
13
+ * });
14
+ * ```
15
+ */
16
+ export { task, type TaskOptions } from "./task.js";
17
+ export { TaskRunner, exports, type TaskConfig } from "./app.js";
18
+ export * as http from "./http.js";
19
+ export { isWasmMode } from "./hostApi.js";
20
+ //# sourceMappingURL=index.d.ts.map
@@ -0,0 +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"}
package/dist/index.js ADDED
@@ -0,0 +1,20 @@
1
+ /**
2
+ * Capsule SDK for JavaScript/TypeScript
3
+ *
4
+ * @example
5
+ * ```typescript
6
+ * import { task } from '@capsule/sdk';
7
+ *
8
+ * export const greet = task({
9
+ * name: "greet",
10
+ * compute: "LOW"
11
+ * }, (name: string): string => {
12
+ * return `Hello, ${name}!`;
13
+ * });
14
+ * ```
15
+ */
16
+ export { task } from "./task.js";
17
+ export { TaskRunner, exports } from "./app.js";
18
+ export * as http from "./http.js";
19
+ export { isWasmMode } from "./hostApi.js";
20
+ //# sourceMappingURL=index.js.map
@@ -0,0 +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"}
package/dist/task.d.ts ADDED
@@ -0,0 +1,24 @@
1
+ /**
2
+ * Capsule SDK - Task Wrapper
3
+ *
4
+ * Provides the `task` wrapper function for defining Capsule tasks
5
+ * in an idiomatic TypeScript way.
6
+ */
7
+ export interface TaskOptions {
8
+ /** Task name (required) */
9
+ name: string;
10
+ /** Compute level: "LOW", "MEDIUM", or "HIGH" */
11
+ compute?: "LOW" | "MEDIUM" | "HIGH" | number;
12
+ /** RAM limit, e.g., "512MB", "2GB" */
13
+ ram?: string;
14
+ /**
15
+ * Timeout duration.
16
+ * String format: "30s", "5m", "2h" (e.g., "10s")
17
+ * Number format: milliseconds (e.g., 10000 for 10 seconds)
18
+ */
19
+ timeout?: string | number;
20
+ /** Maximum number of retries */
21
+ maxRetries?: number;
22
+ }
23
+ export declare function task<TArgs extends any[], TReturn>(options: TaskOptions, fn: (...args: TArgs) => TReturn): (...args: TArgs) => TReturn;
24
+ //# sourceMappingURL=task.d.ts.map
@@ -0,0 +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"}
package/dist/task.js ADDED
@@ -0,0 +1,87 @@
1
+ /**
2
+ * Capsule SDK - Task Wrapper
3
+ *
4
+ * Provides the `task` wrapper function for defining Capsule tasks
5
+ * in an idiomatic TypeScript way.
6
+ */
7
+ import { registerTask } from "./app.js";
8
+ import { isWasmMode, callHost } from "./hostApi.js";
9
+ /**
10
+ * Define a Capsule task with configuration.
11
+ *
12
+ * @example
13
+ * ```typescript
14
+ * // String timeout format
15
+ * export const greet = task({
16
+ * name: "greet",
17
+ * compute: "LOW",
18
+ * timeout: "10s"
19
+ * }, (name: string): string => {
20
+ * return `Hello, ${name}!`;
21
+ * });
22
+ *
23
+ * // Numeric timeout format (milliseconds)
24
+ * export const process = task({
25
+ * name: "process",
26
+ * compute: "HIGH",
27
+ * timeout: 30000 // 30 seconds
28
+ * }, (data: any): any => {
29
+ * return processData(data);
30
+ * });
31
+ * ```
32
+ *
33
+ * In WASM mode:
34
+ * - The function is registered in the task registry with its config
35
+ * - When called from within a task, it schedules a new isolated instance
36
+ * - The host creates a new Wasm instance with resource limits
37
+ *
38
+ * In non-WASM mode:
39
+ * - The function executes directly
40
+ */
41
+ /**
42
+ * Normalize timeout to string format for the Rust host.
43
+ *
44
+ * @param timeout - String duration ("10s", "5m") or number (milliseconds)
45
+ * @returns String format for host API, or undefined
46
+ */
47
+ function normalizeTimeout(timeout) {
48
+ if (timeout === undefined)
49
+ return undefined;
50
+ if (typeof timeout === "number") {
51
+ return `${timeout}ms`;
52
+ }
53
+ return timeout;
54
+ }
55
+ export function task(options, fn) {
56
+ const taskName = options.name;
57
+ let compute = options.compute?.toString().toUpperCase() ?? "MEDIUM";
58
+ const taskConfig = {
59
+ name: taskName,
60
+ compute,
61
+ ram: options.ram,
62
+ timeout: normalizeTimeout(options.timeout),
63
+ maxRetries: options.maxRetries,
64
+ };
65
+ const wrapper = (...args) => {
66
+ if (!isWasmMode()) {
67
+ return fn(...args);
68
+ }
69
+ const resultJson = callHost(taskName, args, taskConfig);
70
+ try {
71
+ const result = JSON.parse(resultJson);
72
+ if (result.error) {
73
+ throw new Error(`Task ${taskName} failed: ${result.error}`);
74
+ }
75
+ return result.result;
76
+ }
77
+ catch (e) {
78
+ if (e instanceof SyntaxError) {
79
+ return resultJson;
80
+ }
81
+ throw e;
82
+ }
83
+ };
84
+ registerTask(taskName, fn, taskConfig);
85
+ return wrapper;
86
+ }
87
+ //# sourceMappingURL=task.js.map
@@ -0,0 +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"}
package/package.json ADDED
@@ -0,0 +1,41 @@
1
+ {
2
+ "name": "@capsule-run/sdk",
3
+ "version": "0.1.0",
4
+ "description": "Capsule JavaScript SDK - run AI agent tasks in secure WASM sandboxes",
5
+ "type": "module",
6
+ "main": "./dist/index.js",
7
+ "types": "./dist/index.d.ts",
8
+ "exports": {
9
+ ".": {
10
+ "types": "./dist/index.d.ts",
11
+ "import": "./dist/index.js"
12
+ },
13
+ "./capsule/app.js": {
14
+ "types": "./dist/app.d.ts",
15
+ "import": "./dist/app.js"
16
+ }
17
+ },
18
+ "files": [
19
+ "dist",
20
+ "src"
21
+ ],
22
+ "scripts": {
23
+ "build": "tsc",
24
+ "clean": "rm -rf dist"
25
+ },
26
+ "keywords": [
27
+ "webassembly",
28
+ "agents",
29
+ "isolation",
30
+ "llm",
31
+ "ai"
32
+ ],
33
+ "license": "Apache-2.0",
34
+ "dependencies": {
35
+ "@bytecodealliance/jco": "^1.0.0",
36
+ "esbuild": "^0.27.2"
37
+ },
38
+ "devDependencies": {
39
+ "typescript": "^5.9.3"
40
+ }
41
+ }
package/src/app.ts ADDED
@@ -0,0 +1,116 @@
1
+ /**
2
+ * Capsule SDK - Task Registry and TaskRunner
3
+ */
4
+
5
+ export interface TaskInfo<T extends (...args: any[]) => any> {
6
+ func: T;
7
+ config: TaskConfig;
8
+ }
9
+
10
+ export interface TaskConfig {
11
+ name: string;
12
+ compute?: string;
13
+ ram?: string;
14
+ timeout?: string;
15
+ maxRetries?: number;
16
+ }
17
+
18
+ const TASKS: Map<string, TaskInfo<any>> = new Map();
19
+
20
+ /**
21
+ * Register a task function by name with its configuration.
22
+ */
23
+ export function registerTask<T extends (...args: any[]) => any>(
24
+ name: string,
25
+ func: T,
26
+ config: TaskConfig
27
+ ): void {
28
+ TASKS.set(name, { func, config });
29
+ }
30
+
31
+ /**
32
+ * Get a registered task by name.
33
+ */
34
+ export function getTask(name: string): ((...args: any[]) => any) | undefined {
35
+ return TASKS.get(name)?.func;
36
+ }
37
+
38
+ /**
39
+ * Get the configuration for a registered task.
40
+ */
41
+ export function getTaskConfig(name: string): TaskConfig | undefined {
42
+ return TASKS.get(name)?.config;
43
+ }
44
+
45
+ /**
46
+ * Get all registered task names.
47
+ */
48
+ export function getTaskNames(): string[] {
49
+ return Array.from(TASKS.keys());
50
+ }
51
+
52
+ interface TaskArgs {
53
+ task_name?: string;
54
+ args?: any[];
55
+ kwargs?: Record<string, any>;
56
+ }
57
+
58
+ interface TaskResult {
59
+ result?: any;
60
+ error?: string;
61
+ traceback?: string;
62
+ }
63
+
64
+ /**
65
+ * Implementation of the capsule:host/task-runner interface.
66
+ *
67
+ * This class is instantiated by capsule-core when the component is loaded.
68
+ * The Rust host calls `run(argsJson)` to execute a task.
69
+ */
70
+ export class TaskRunner {
71
+ /**
72
+ * Execute a task with the given arguments.
73
+ * Returns Ok(result_json) on success, Err(error_message) on failure.
74
+ */
75
+ async run(argsJson: string): Promise<string> {
76
+ try {
77
+ const data: TaskArgs = JSON.parse(argsJson);
78
+ const taskName = data.task_name ?? "main";
79
+ const args = data.args ?? [];
80
+ const kwargs = data.kwargs ?? {};
81
+
82
+ let taskFunc = getTask(taskName);
83
+
84
+ if (!taskFunc && taskName !== "main") {
85
+ taskFunc = getTask("main");
86
+ }
87
+
88
+ if (!taskFunc && TASKS.size > 0) {
89
+ const firstTaskName = TASKS.keys().next().value;
90
+ if (firstTaskName) {
91
+ taskFunc = getTask(firstTaskName);
92
+ }
93
+ }
94
+
95
+ if (!taskFunc) {
96
+ throw `No tasks or main() function found. Available tasks: ${getTaskNames().join(", ")}`;
97
+ }
98
+
99
+ const result = taskFunc(...args, kwargs);
100
+
101
+ if (result instanceof Promise) {
102
+ const asyncResult = await result;
103
+ return JSON.stringify({ result: asyncResult ?? null });
104
+ }
105
+
106
+ return JSON.stringify({ result: result ?? null });
107
+ } catch (e) {
108
+ const errorMsg = e instanceof Error
109
+ ? `${e.message}\n${e.stack || ''}`
110
+ : String(e);
111
+ throw errorMsg;
112
+ }
113
+ }
114
+ }
115
+
116
+ export const exports = new TaskRunner();
package/src/hostApi.ts ADDED
@@ -0,0 +1,67 @@
1
+ /**
2
+ * Capsule SDK - Host API Interface
3
+ *
4
+ * This module provides the interface to call host functions from JavaScript/TypeScript Wasm code.
5
+ * When running in WASM mode, it imports the auto-generated bindings from jco.
6
+ * When running locally, it provides mock implementations for testing.
7
+ */
8
+
9
+ let hostModule: any = null;
10
+ let isWasmChecked = false;
11
+ let isWasm = false;
12
+
13
+ /**
14
+ * Lazily check if we're running in WASM mode.
15
+ */
16
+ function checkWasm(): boolean {
17
+ if (!isWasmChecked) {
18
+ try {
19
+ const witBinding = (globalThis as any)["capsule:host/api"];
20
+
21
+ if (typeof witBinding !== "undefined" && typeof witBinding.scheduleTask === "function") {
22
+ hostModule = witBinding;
23
+ isWasm = true;
24
+ } else {
25
+ isWasm = false;
26
+ }
27
+ } catch (e) {
28
+ isWasm = false;
29
+ }
30
+ isWasmChecked = true;
31
+ }
32
+ return isWasm;
33
+ }
34
+
35
+ /**
36
+ * Check if running in WASM mode.
37
+ */
38
+ export function isWasmMode(): boolean {
39
+ return checkWasm();
40
+ }
41
+
42
+ /**
43
+ * Call the host's schedule_task function to create a new isolated task instance.
44
+ *
45
+ * This is the bridge between JavaScript code and the Rust host runtime.
46
+ */
47
+ export function callHost(
48
+ name: string,
49
+ args: any[],
50
+ config: Record<string, any>
51
+ ): string {
52
+ if (checkWasm() && hostModule !== null) {
53
+ try {
54
+ const result = hostModule.scheduleTask(
55
+ name,
56
+ JSON.stringify(args),
57
+ JSON.stringify(config)
58
+ );
59
+ return result;
60
+ } catch (e) {
61
+ const error = e instanceof Error ? e.message : String(e);
62
+ return JSON.stringify({ error: `Host call failed: ${error}` });
63
+ }
64
+ } else {
65
+ return JSON.stringify({ result: `mock_result_for_${name}` });
66
+ }
67
+ }
package/src/http.ts ADDED
@@ -0,0 +1,221 @@
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
+ }
package/src/index.ts ADDED
@@ -0,0 +1,20 @@
1
+ /**
2
+ * Capsule SDK for JavaScript/TypeScript
3
+ *
4
+ * @example
5
+ * ```typescript
6
+ * import { task } from '@capsule/sdk';
7
+ *
8
+ * export const greet = task({
9
+ * name: "greet",
10
+ * compute: "LOW"
11
+ * }, (name: string): string => {
12
+ * return `Hello, ${name}!`;
13
+ * });
14
+ * ```
15
+ */
16
+
17
+ export { task, type TaskOptions } from "./task.js";
18
+ export { TaskRunner, exports, type TaskConfig } from "./app.js";
19
+ export * as http from "./http.js";
20
+ export { isWasmMode } from "./hostApi.js";
package/src/task.ts ADDED
@@ -0,0 +1,119 @@
1
+ /**
2
+ * Capsule SDK - Task Wrapper
3
+ *
4
+ * Provides the `task` wrapper function for defining Capsule tasks
5
+ * in an idiomatic TypeScript way.
6
+ */
7
+
8
+ import { registerTask, type TaskConfig } from "./app.js";
9
+ import { isWasmMode, callHost } from "./hostApi.js";
10
+
11
+ export interface TaskOptions {
12
+ /** Task name (required) */
13
+ name: string;
14
+ /** Compute level: "LOW", "MEDIUM", or "HIGH" */
15
+ compute?: "LOW" | "MEDIUM" | "HIGH" | number;
16
+ /** RAM limit, e.g., "512MB", "2GB" */
17
+ ram?: string;
18
+ /**
19
+ * Timeout duration.
20
+ * String format: "30s", "5m", "2h" (e.g., "10s")
21
+ * Number format: milliseconds (e.g., 10000 for 10 seconds)
22
+ */
23
+ timeout?: string | number;
24
+ /** Maximum number of retries */
25
+ maxRetries?: number;
26
+ }
27
+
28
+ interface TaskResult {
29
+ result?: any;
30
+ error?: string;
31
+ }
32
+
33
+ /**
34
+ * Define a Capsule task with configuration.
35
+ *
36
+ * @example
37
+ * ```typescript
38
+ * // String timeout format
39
+ * export const greet = task({
40
+ * name: "greet",
41
+ * compute: "LOW",
42
+ * timeout: "10s"
43
+ * }, (name: string): string => {
44
+ * return `Hello, ${name}!`;
45
+ * });
46
+ *
47
+ * // Numeric timeout format (milliseconds)
48
+ * export const process = task({
49
+ * name: "process",
50
+ * compute: "HIGH",
51
+ * timeout: 30000 // 30 seconds
52
+ * }, (data: any): any => {
53
+ * return processData(data);
54
+ * });
55
+ * ```
56
+ *
57
+ * In WASM mode:
58
+ * - The function is registered in the task registry with its config
59
+ * - When called from within a task, it schedules a new isolated instance
60
+ * - The host creates a new Wasm instance with resource limits
61
+ *
62
+ * In non-WASM mode:
63
+ * - The function executes directly
64
+ */
65
+
66
+ /**
67
+ * Normalize timeout to string format for the Rust host.
68
+ *
69
+ * @param timeout - String duration ("10s", "5m") or number (milliseconds)
70
+ * @returns String format for host API, or undefined
71
+ */
72
+ function normalizeTimeout(timeout?: string | number): string | undefined {
73
+ if (timeout === undefined) return undefined;
74
+ if (typeof timeout === "number") {
75
+ return `${timeout}ms`;
76
+ }
77
+ return timeout;
78
+ }
79
+
80
+ export function task<TArgs extends any[], TReturn>(
81
+ options: TaskOptions,
82
+ fn: (...args: TArgs) => TReturn
83
+ ): (...args: TArgs) => TReturn {
84
+ const taskName = options.name;
85
+ let compute = options.compute?.toString().toUpperCase() ?? "MEDIUM";
86
+
87
+ const taskConfig: TaskConfig = {
88
+ name: taskName,
89
+ compute,
90
+ ram: options.ram,
91
+ timeout: normalizeTimeout(options.timeout),
92
+ maxRetries: options.maxRetries,
93
+ };
94
+
95
+ const wrapper = (...args: TArgs): TReturn => {
96
+ if (!isWasmMode()) {
97
+ return fn(...args);
98
+ }
99
+
100
+ const resultJson = callHost(taskName, args, taskConfig);
101
+
102
+ try {
103
+ const result: TaskResult = JSON.parse(resultJson);
104
+ if (result.error) {
105
+ throw new Error(`Task ${taskName} failed: ${result.error}`);
106
+ }
107
+ return result.result as TReturn;
108
+ } catch (e) {
109
+ if (e instanceof SyntaxError) {
110
+ return resultJson as unknown as TReturn;
111
+ }
112
+ throw e;
113
+ }
114
+ };
115
+
116
+ registerTask(taskName, fn, taskConfig);
117
+
118
+ return wrapper;
119
+ }