@aresdefencelabs/wasm-http-runtime 0.0.1

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/abi.d.ts ADDED
@@ -0,0 +1,7 @@
1
+ import type { RuntimeState } from "./types";
2
+ export declare function createAresAbiImports<Env>(state: RuntimeState<Env>): {
3
+ ares_abi: {
4
+ abi_log(messagePtr: number): void;
5
+ abi_http_get_user_agent_name(): number;
6
+ };
7
+ };
package/dist/abi.js ADDED
@@ -0,0 +1,35 @@
1
+ import { readCString, writeCString } from "./memory";
2
+ function getInstanceOrThrow(state) {
3
+ if (!state.instance) {
4
+ throw new Error("Wasm instance has not been initialised yet.");
5
+ }
6
+ return state.instance;
7
+ }
8
+ function getRequestContextOrThrow(state) {
9
+ if (!state.requestContext) {
10
+ throw new Error("No active request context.");
11
+ }
12
+ return state.requestContext;
13
+ }
14
+ export function createAresAbiImports(state) {
15
+ return {
16
+ ares_abi: {
17
+ abi_log(messagePtr) {
18
+ const instance = getInstanceOrThrow(state);
19
+ const message = readCString(instance.exports.memory, messagePtr);
20
+ if (state.options.onLog) {
21
+ state.options.onLog(message);
22
+ }
23
+ else if (state.options.debug) {
24
+ console.log("[AresWasm]", message);
25
+ }
26
+ },
27
+ abi_http_get_user_agent_name() {
28
+ const instance = getInstanceOrThrow(state);
29
+ const ctx = getRequestContextOrThrow(state);
30
+ const userAgent = ctx.request.headers.get("user-agent") ?? "Cloudflare-Worker";
31
+ return writeCString(instance.exports.memory, instance.exports.alloc, userAgent);
32
+ }
33
+ }
34
+ };
35
+ }
@@ -0,0 +1,5 @@
1
+ export * from "./types";
2
+ export * from "./memory";
3
+ export * from "./abi";
4
+ export * from "./runtime";
5
+ export * from "./worker";
package/dist/index.js ADDED
@@ -0,0 +1,5 @@
1
+ export * from "./types";
2
+ export * from "./memory";
3
+ export * from "./abi";
4
+ export * from "./runtime";
5
+ export * from "./worker";
@@ -0,0 +1,4 @@
1
+ export declare function readCString(memory: WebAssembly.Memory, ptr: number): string;
2
+ export declare function writeCString(memory: WebAssembly.Memory, alloc: (size: number) => number, value: string): number;
3
+ export declare function writeJsonCString(memory: WebAssembly.Memory, alloc: (size: number) => number, value: unknown): number;
4
+ export declare function headersToObject(headers: Headers): Record<string, string>;
package/dist/memory.js ADDED
@@ -0,0 +1,24 @@
1
+ const encoder = new TextEncoder();
2
+ const decoder = new TextDecoder();
3
+ export function readCString(memory, ptr) {
4
+ const bytes = new Uint8Array(memory.buffer);
5
+ let end = ptr;
6
+ while (bytes[end] !== 0) {
7
+ end++;
8
+ }
9
+ return decoder.decode(bytes.subarray(ptr, end));
10
+ }
11
+ export function writeCString(memory, alloc, value) {
12
+ const encoded = encoder.encode(value);
13
+ const ptr = alloc(encoded.length + 1);
14
+ const bytes = new Uint8Array(memory.buffer);
15
+ bytes.set(encoded, ptr);
16
+ bytes[ptr + encoded.length] = 0;
17
+ return ptr;
18
+ }
19
+ export function writeJsonCString(memory, alloc, value) {
20
+ return writeCString(memory, alloc, JSON.stringify(value));
21
+ }
22
+ export function headersToObject(headers) {
23
+ return Object.fromEntries(headers.entries());
24
+ }
@@ -0,0 +1,10 @@
1
+ import type { RequestScopedContext, RuntimeOptions, WasmInstanceWithExports, WorkerExecutionContext } from "./types";
2
+ export declare class AresWorkerRuntime<Env = unknown> {
3
+ private readonly state;
4
+ constructor(options: RuntimeOptions<Env>);
5
+ init(): Promise<void>;
6
+ setRequestContext(context: RequestScopedContext<Env>): void;
7
+ clearRequestContext(): void;
8
+ get instance(): WasmInstanceWithExports;
9
+ handleFetch(request: Request, env: Env, ctx: WorkerExecutionContext): Promise<Response>;
10
+ }
@@ -0,0 +1,64 @@
1
+ import { createAresAbiImports } from "./abi";
2
+ import { headersToObject, readCString, writeJsonCString } from "./memory";
3
+ export class AresWorkerRuntime {
4
+ state;
5
+ constructor(options) {
6
+ this.state = {
7
+ instance: null,
8
+ options,
9
+ requestContext: null
10
+ };
11
+ }
12
+ async init() {
13
+ if (this.state.instance) {
14
+ return;
15
+ }
16
+ const imports = createAresAbiImports(this.state);
17
+ const instance = await WebAssembly.instantiate(this.state.options.wasm, imports);
18
+ this.state.instance = instance;
19
+ if (instance.exports.app_init) {
20
+ instance.exports.app_init();
21
+ }
22
+ }
23
+ setRequestContext(context) {
24
+ this.state.requestContext = context;
25
+ }
26
+ clearRequestContext() {
27
+ this.state.requestContext = null;
28
+ }
29
+ get instance() {
30
+ if (!this.state.instance) {
31
+ throw new Error("Runtime not initialised. Call init() first.");
32
+ }
33
+ return this.state.instance;
34
+ }
35
+ async handleFetch(request, env, ctx) {
36
+ await this.init();
37
+ this.setRequestContext({ request, env, ctx });
38
+ try {
39
+ if (!this.instance.exports.handle_http) {
40
+ throw new Error("Wasm export handle_http() was not found.");
41
+ }
42
+ const requestBody = await request.text();
43
+ const inboundEnvelope = {
44
+ url: request.url,
45
+ method: request.method,
46
+ headers: headersToObject(request.headers),
47
+ body: requestBody
48
+ };
49
+ const requestPtr = writeJsonCString(this.instance.exports.memory, this.instance.exports.alloc, inboundEnvelope);
50
+ const responsePtr = this.instance.exports.handle_http(requestPtr);
51
+ const responseJson = readCString(this.instance.exports.memory, responsePtr);
52
+ const responseEnvelope = JSON.parse(responseJson);
53
+ return new Response(typeof responseEnvelope.body === "string"
54
+ ? responseEnvelope.body
55
+ : JSON.stringify(responseEnvelope.body), {
56
+ status: responseEnvelope.status,
57
+ headers: responseEnvelope.headers
58
+ });
59
+ }
60
+ finally {
61
+ this.clearRequestContext();
62
+ }
63
+ }
64
+ }
@@ -0,0 +1,41 @@
1
+ export interface WorkerExecutionContext {
2
+ waitUntil(promise: Promise<unknown>): void;
3
+ passThroughOnException?(): void;
4
+ }
5
+ export type WasmExports = {
6
+ memory: WebAssembly.Memory;
7
+ alloc: (size: number) => number;
8
+ free_mem?: (ptr: number, size: number) => void;
9
+ app_init?: () => number;
10
+ handle_http?: (requestJsonPtr: number) => number;
11
+ };
12
+ export type WasmInstanceWithExports = WebAssembly.Instance & {
13
+ exports: WasmExports;
14
+ };
15
+ export type RequestEnvelope = {
16
+ url: string;
17
+ method: string;
18
+ headers: Record<string, string>;
19
+ body?: string | null;
20
+ };
21
+ export type ResponseEnvelope = {
22
+ status: number;
23
+ headers: Record<string, string>;
24
+ body: unknown;
25
+ };
26
+ export type RuntimeOptions<Env = unknown> = {
27
+ wasm: WebAssembly.Module;
28
+ debug?: boolean;
29
+ onLog?: (message: string) => void;
30
+ env?: Env;
31
+ };
32
+ export type RequestScopedContext<Env = unknown> = {
33
+ request: Request;
34
+ env: Env;
35
+ ctx: WorkerExecutionContext;
36
+ };
37
+ export type RuntimeState<Env = unknown> = {
38
+ instance: WasmInstanceWithExports | null;
39
+ options: RuntimeOptions<Env>;
40
+ requestContext: RequestScopedContext<Env> | null;
41
+ };
package/dist/types.js ADDED
@@ -0,0 +1 @@
1
+ export {};
@@ -0,0 +1,4 @@
1
+ import type { RuntimeOptions, WorkerExecutionContext } from "./types";
2
+ export declare function createAresWorkerHandler<Env = unknown>(wasm: WebAssembly.Module, options?: Omit<RuntimeOptions<Env>, "wasm">): {
3
+ fetch(request: Request, env: Env, ctx: WorkerExecutionContext): Promise<Response>;
4
+ };
package/dist/worker.js ADDED
@@ -0,0 +1,12 @@
1
+ import { AresWorkerRuntime } from "./runtime";
2
+ export function createAresWorkerHandler(wasm, options) {
3
+ const runtime = new AresWorkerRuntime({
4
+ wasm,
5
+ ...options
6
+ });
7
+ return {
8
+ async fetch(request, env, ctx) {
9
+ return runtime.handleFetch(request, env, ctx);
10
+ }
11
+ };
12
+ }
package/package.json ADDED
@@ -0,0 +1,40 @@
1
+ {
2
+ "name": "@aresdefencelabs/wasm-http-runtime",
3
+ "version": "0.0.1",
4
+ "description": "Runtime adapter that connects C++ WebAssembly workers to the Cloudflare Workers runtime via an ABI bridge.",
5
+ "type": "module",
6
+ "private": false,
7
+ "repository": {
8
+ "type": "git",
9
+ "url": "https://github.com/Ares-Defence-Labs/wasm-workers-http.git"
10
+ },
11
+
12
+ "homepage": "https://github.com/Ares-Defence-Labs/wasm-workers-http",
13
+
14
+ "bugs": {
15
+ "url": "https://github.com/Ares-Defence-Labs/wasm-workers-http/issues"
16
+ },
17
+
18
+ "author": "Ares Defence Labs",
19
+ "license": "MIT",
20
+
21
+ "keywords": [
22
+ "cloudflare",
23
+ "cloudflare-workers",
24
+ "webassembly",
25
+ "wasm",
26
+ "cpp",
27
+ "wasm-runtime",
28
+ "workers-runtime",
29
+ "http-client",
30
+ "serverless",
31
+ "edge"
32
+ ],
33
+
34
+ "scripts": {
35
+ "build": "tsc -p tsconfig.json"
36
+ },
37
+ "main": "./dist/index.js",
38
+ "types": "./dist/index.d.ts",
39
+ "files": ["dist"]
40
+ }