ziex 0.1.0-dev.786 → 0.1.0-dev.804

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/app.d.ts ADDED
@@ -0,0 +1,112 @@
1
+ import type { DurableObjectNamespace } from "./runtime";
2
+ import type { KVNamespace } from "./kv";
3
+ import type { WASI } from "./wasi";
4
+ /**
5
+ * Anything that can be resolved to a `WebAssembly.Module`:
6
+ * - `WebAssembly.Module` — already compiled (Cloudflare Workers, wrangler)
7
+ * - `ArrayBuffer` / `ArrayBufferView` — raw WASM bytes
8
+ * - `Response` — a fetch() response whose body is the WASM binary
9
+ * - `string` — an HTTP(S) URL or an absolute file path (Bun)
10
+ * - `URL` — a URL object
11
+ */
12
+ export type WasmInput = WebAssembly.Module | ArrayBuffer | ArrayBufferView | Response | string | URL;
13
+ /**
14
+ * Resolve any supported WASM input to a compiled `WebAssembly.Module`.
15
+ * The result is NOT cached here — cache it at the call site if needed.
16
+ */
17
+ export declare function resolveModule(input: WasmInput): Promise<WebAssembly.Module>;
18
+ /** Keys of `Env` whose value extends {@link KVNamespace}. */
19
+ type KVKey<Env> = {
20
+ [K in keyof Env]: Env[K] extends KVNamespace ? K : never;
21
+ }[keyof Env];
22
+ /** Keys of `Env` whose value extends {@link DurableObjectNamespace}. */
23
+ type DOKey<Env> = {
24
+ [K in keyof Env]: Env[K] extends DurableObjectNamespace ? K : never;
25
+ }[keyof Env];
26
+ type ZiexOptions<Env> = {
27
+ /** WASM module — accepts any {@link WasmInput}. Resolved and cached on first request. */
28
+ module: WasmInput;
29
+ /** Optional pre-configured WASI instance. */
30
+ wasi?: WASI;
31
+ /** Extra WASM import namespaces. */
32
+ imports?: (mem: () => WebAssembly.Memory) => Record<string, Record<string, unknown>>;
33
+ /**
34
+ * KV namespace bindings. Two forms are supported:
35
+ *
36
+ * - **Env key**: a single key from `Env` whose value is a `KVNamespace` — used as the `"default"` binding.
37
+ * - **Name map**: `{ [bindingName]: envKey }` — map namespace names to env keys.
38
+ *
39
+ * @example Single env key (becomes the "default" binding)
40
+ * ```ts
41
+ * kv: "MY_KV"
42
+ * ```
43
+ * @example Name map
44
+ * ```ts
45
+ * kv: { default: "MY_KV", users: "USERS_KV" }
46
+ * ```
47
+ */
48
+ kv?: KVKey<Env> | Record<string, KVKey<Env>>;
49
+ /**
50
+ * Env key whose value is a `DurableObjectNamespace` for WebSocket pub/sub.
51
+ * Requires `createWebSocketDO` export on the worker.
52
+ *
53
+ * @example
54
+ * ```ts
55
+ * websocket: "ChatRoom"
56
+ * ```
57
+ */
58
+ websocket?: DOKey<Env>;
59
+ };
60
+ /**
61
+ * Main Ziex application class. Mirrors the Hono API style — construct once,
62
+ * export as default, and the runtime calls `fetch` for you.
63
+ *
64
+ * Works on Cloudflare Workers, Bun, and Vercel Edge out of the box.
65
+ *
66
+ * @example Cloudflare Workers / wrangler
67
+ * ```ts
68
+ * import { Ziex } from "ziex";
69
+ * import module from "./app.wasm";
70
+ *
71
+ * const app = new Ziex<Env>({
72
+ * module,
73
+ * kv: (env) => ({ default: env.KV }),
74
+ * });
75
+ * export default app;
76
+ * ```
77
+ *
78
+ * @example Bun
79
+ * ```ts
80
+ * import { Ziex } from "ziex";
81
+ * import wasmPath from "./app.wasm" with { type: "wasm" };
82
+ *
83
+ * const app = new Ziex({ module: wasmPath });
84
+ * export default app;
85
+ * ```
86
+ *
87
+ * @example Vercel Edge
88
+ * ```ts
89
+ * import { Ziex } from "ziex";
90
+ * import { handle } from "ziex/vercel";
91
+ *
92
+ * const app = new Ziex({ module: "https://example.com/app.wasm" });
93
+ * export default handle(app);
94
+ * ```
95
+ */
96
+ export declare class Ziex<Env = Record<string, unknown>> {
97
+ private readonly options;
98
+ private resolved;
99
+ constructor(options: ZiexOptions<Env>);
100
+ private getModule;
101
+ private resolveKV;
102
+ /**
103
+ * Fetch handler called by the runtime on every request.
104
+ *
105
+ * Arrow function so `this` is always the class instance, even when the
106
+ * runtime extracts `fetch` from the exported object (e.g. Bun).
107
+ */
108
+ fetch: (request: Request, env: Env, ctx?: {
109
+ waitUntil(p: Promise<unknown>): void;
110
+ }) => Promise<Response>;
111
+ }
112
+ export {};
@@ -0,0 +1,96 @@
1
+ /**
2
+ * Ziex adapter for AWS Lambda (API Gateway v1, v2, and ALB).
3
+ *
4
+ * Based on Hono's AWS Lambda adapter implementation.
5
+ *
6
+ * @example API Gateway v2 (HTTP API)
7
+ * ```ts
8
+ * import { Ziex } from "ziex/cloudflare";
9
+ * import { handle } from "ziex/aws-lambda";
10
+ * import module from "./app.wasm";
11
+ *
12
+ * const app = new Ziex({ module });
13
+ * export const handler = handle(app);
14
+ * ```
15
+ */
16
+ type ApiGwV1Event = {
17
+ version?: "1.0";
18
+ httpMethod: string;
19
+ path: string;
20
+ headers: Record<string, string> | null;
21
+ multiValueHeaders: Record<string, string[]> | null;
22
+ queryStringParameters: Record<string, string> | null;
23
+ multiValueQueryStringParameters: Record<string, string[]> | null;
24
+ body: string | null;
25
+ isBase64Encoded: boolean;
26
+ requestContext: {
27
+ elb?: unknown;
28
+ };
29
+ };
30
+ type ApiGwV2Event = {
31
+ version: "2.0";
32
+ requestContext: {
33
+ http: {
34
+ method: string;
35
+ };
36
+ };
37
+ rawPath: string;
38
+ rawQueryString: string;
39
+ headers: Record<string, string>;
40
+ body?: string;
41
+ isBase64Encoded: boolean;
42
+ };
43
+ type AlbEvent = {
44
+ httpMethod: string;
45
+ path: string;
46
+ headers: Record<string, string> | null;
47
+ multiValueHeaders: Record<string, string[]> | null;
48
+ queryStringParameters: Record<string, string> | null;
49
+ multiValueQueryStringParameters: Record<string, string[]> | null;
50
+ body: string | null;
51
+ isBase64Encoded: boolean;
52
+ requestContext: {
53
+ elb: unknown;
54
+ };
55
+ };
56
+ export type LambdaEvent = ApiGwV1Event | ApiGwV2Event | AlbEvent;
57
+ export type LambdaContext = {
58
+ functionName: string;
59
+ functionVersion: string;
60
+ invokedFunctionArn: string;
61
+ memoryLimitInMB: string;
62
+ awsRequestId: string;
63
+ logGroupName: string;
64
+ logStreamName: string;
65
+ callbackWaitsForEmptyEventLoop: boolean;
66
+ getRemainingTimeInMillis(): number;
67
+ };
68
+ export type LambdaResult = {
69
+ statusCode: number;
70
+ headers: Record<string, string>;
71
+ multiValueHeaders: Record<string, string[]>;
72
+ body: string;
73
+ isBase64Encoded: boolean;
74
+ cookies?: string[];
75
+ };
76
+ type FetchApp = {
77
+ fetch(req: Request, env?: unknown, ctx?: unknown): Promise<Response>;
78
+ };
79
+ export type HandleOptions = {
80
+ /**
81
+ * Content types to encode as base64 in the Lambda response.
82
+ * By default, non-text content types are base64 encoded automatically.
83
+ */
84
+ binaryMediaTypes?: string[];
85
+ };
86
+ /**
87
+ * Wrap a Ziex app as an AWS Lambda handler.
88
+ *
89
+ * @example
90
+ * ```ts
91
+ * import { handle } from "ziex/aws-lambda";
92
+ * export const handler = handle(app);
93
+ * ```
94
+ */
95
+ export declare function handle(app: FetchApp, options?: HandleOptions): (event: LambdaEvent, _context?: LambdaContext) => Promise<LambdaResult>;
96
+ export {};
@@ -0,0 +1,126 @@
1
+ var __defProp = Object.defineProperty;
2
+ var __export = (target, all) => {
3
+ for (var name in all)
4
+ __defProp(target, name, {
5
+ get: all[name],
6
+ enumerable: true,
7
+ configurable: true,
8
+ set: (newValue) => all[name] = () => newValue
9
+ });
10
+ };
11
+
12
+ // src/aws-lambda/index.ts
13
+ function isV2(event) {
14
+ return "requestContext" in event && event.requestContext !== null && "http" in event.requestContext;
15
+ }
16
+ function getMethod(event) {
17
+ if (isV2(event))
18
+ return event.requestContext.http.method;
19
+ return event.httpMethod;
20
+ }
21
+ function getPath(event) {
22
+ if (isV2(event)) {
23
+ return event.rawPath + (event.rawQueryString ? `?${event.rawQueryString}` : "");
24
+ }
25
+ const e = event;
26
+ const mvqs = e.multiValueQueryStringParameters;
27
+ const qs = e.queryStringParameters;
28
+ let queryString = "";
29
+ if (mvqs) {
30
+ queryString = Object.entries(mvqs).flatMap(([k, vs]) => (vs ?? []).map((v) => `${encodeURIComponent(k)}=${encodeURIComponent(v)}`)).join("&");
31
+ } else if (qs) {
32
+ queryString = new URLSearchParams(qs).toString();
33
+ }
34
+ return e.path + (queryString ? `?${queryString}` : "");
35
+ }
36
+ function getHeaders(event) {
37
+ const headers = new Headers;
38
+ if (event.headers) {
39
+ for (const [k, v] of Object.entries(event.headers)) {
40
+ if (v != null)
41
+ headers.set(k, v);
42
+ }
43
+ }
44
+ if ("multiValueHeaders" in event && event.multiValueHeaders) {
45
+ for (const [k, vs] of Object.entries(event.multiValueHeaders)) {
46
+ if (!vs?.length)
47
+ continue;
48
+ headers.delete(k);
49
+ for (const v of vs)
50
+ headers.append(k, v);
51
+ }
52
+ }
53
+ return headers;
54
+ }
55
+ function getBody(event) {
56
+ if (!event.body)
57
+ return null;
58
+ if (event.isBase64Encoded)
59
+ return Buffer.from(event.body, "base64");
60
+ return event.body;
61
+ }
62
+ function toRequest(event, headers) {
63
+ const method = getMethod(event);
64
+ const host = headers.get("host") ?? "localhost";
65
+ const proto = headers.get("x-forwarded-proto") ?? "https";
66
+ const path = getPath(event);
67
+ const url = `${proto}://${host}${path}`;
68
+ const body = ["GET", "HEAD"].includes(method) ? null : getBody(event);
69
+ return new Request(url, { method, headers, body });
70
+ }
71
+ var TEXT_CONTENT_TYPES = [
72
+ "text/",
73
+ "application/json",
74
+ "application/xml",
75
+ "application/javascript",
76
+ "application/xhtml"
77
+ ];
78
+ function isBinaryContent(contentType, binaryMediaTypes) {
79
+ if (binaryMediaTypes.length > 0) {
80
+ return binaryMediaTypes.some((t) => contentType.includes(t));
81
+ }
82
+ return !TEXT_CONTENT_TYPES.some((t) => contentType.startsWith(t));
83
+ }
84
+ async function toLambdaResult(res, binaryMediaTypes) {
85
+ const responseHeaders = {};
86
+ const multiValueHeaders = {};
87
+ res.headers.forEach((value, key) => {
88
+ if (key in responseHeaders) {
89
+ multiValueHeaders[key] = [...multiValueHeaders[key] ?? [responseHeaders[key]], value];
90
+ delete responseHeaders[key];
91
+ } else if (key in multiValueHeaders) {
92
+ multiValueHeaders[key].push(value);
93
+ } else {
94
+ responseHeaders[key] = value;
95
+ }
96
+ });
97
+ const contentType = res.headers.get("content-type") ?? "";
98
+ const binary = isBinaryContent(contentType, binaryMediaTypes);
99
+ let body;
100
+ let isBase64Encoded = false;
101
+ if (binary) {
102
+ body = Buffer.from(await res.arrayBuffer()).toString("base64");
103
+ isBase64Encoded = true;
104
+ } else {
105
+ body = await res.text();
106
+ }
107
+ return {
108
+ statusCode: res.status,
109
+ headers: responseHeaders,
110
+ multiValueHeaders,
111
+ body,
112
+ isBase64Encoded
113
+ };
114
+ }
115
+ function handle(app, options = {}) {
116
+ const binaryMediaTypes = options.binaryMediaTypes ?? [];
117
+ return async (event, _context) => {
118
+ const headers = getHeaders(event);
119
+ const req = toRequest(event, headers);
120
+ const res = await app.fetch(req);
121
+ return toLambdaResult(res, binaryMediaTypes);
122
+ };
123
+ }
124
+ export {
125
+ handle
126
+ };
@@ -0,0 +1,2 @@
1
+ export { Ziex, resolveModule } from "../app";
2
+ export type { WasmInput } from "../app";
@@ -0,0 +1,48 @@
1
+ import type { WsState } from "../runtime";
2
+ import type { KVNamespace } from "../kv";
3
+ type ConnState = WsState & {
4
+ topics: Set<string>;
5
+ };
6
+ /**
7
+ * Create a Durable Object class that handles WebSocket connections for a ZX app.
8
+ *
9
+ * Each DO instance corresponds to one "room" (keyed by pathname). All clients
10
+ * connecting to the same route share a DO instance, enabling pub/sub via
11
+ * `ctx.socket.subscribe()` / `ctx.socket.publish()`.
12
+ *
13
+ * @example
14
+ * ```ts
15
+ * // worker.ts
16
+ * import { Ziex } from "ziex";
17
+ * import { createWebSocketDO } from "ziex/cloudflare";
18
+ * import module from "./app.wasm";
19
+ *
20
+ * export const ZxWS = createWebSocketDO(module);
21
+ *
22
+ * export default new Ziex({
23
+ * module,
24
+ * websocket: (env) => env.ZxWS,
25
+ * });
26
+ * ```
27
+ */
28
+ export declare function createWebSocketDO(module: WebAssembly.Module, options?: {
29
+ /**
30
+ * KV namespace bindings for the DO. Pass a factory that receives the DO's
31
+ * `env` so bindings are resolved at runtime:
32
+ *
33
+ * ```ts
34
+ * createWebSocketDO(module, { kv: (env) => ({ default: env.KV }) })
35
+ * ```
36
+ */
37
+ kv?: (env: any) => Record<string, KVNamespace>;
38
+ imports?: (mem: () => WebAssembly.Memory) => Record<string, Record<string, unknown>>;
39
+ }): {
40
+ new (state: any, env: any): {
41
+ readonly doState: any;
42
+ readonly env: any;
43
+ /** All active connections in this room, keyed by their server-side WebSocket. */
44
+ readonly connections: Map<WebSocket, ConnState>;
45
+ fetch(request: Request): Promise<Response>;
46
+ };
47
+ };
48
+ export {};
@@ -1,2 +1,4 @@
1
- export * as worker from "./worker";
2
- export * as kv from "./kv";
1
+ export * as worker from "../runtime";
2
+ export * as kv from "../kv";
3
+ export { Ziex } from "../app";
4
+ export { createWebSocketDO } from "./do";