@zap-proto/web 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/LICENSE ADDED
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (C) 2025, Lux Industries Inc.
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
package/README.md ADDED
@@ -0,0 +1,142 @@
1
+ # @zap-proto/web
2
+
3
+ Browser-frontend RPC over **ZAP** — a drop-in tRPC replacement for Next.js /
4
+ Remix / SvelteKit. Native ZAP envelopes over WebSocket binary frames, layered
5
+ cleanly on [`@zap-proto/zap`](https://github.com/zap-proto/ts) (the ZAP wire
6
+ runtime). `v0.1.0` — pre-1.0 by policy; no version tags until the full chain
7
+ works end-to-end.
8
+
9
+ > **Note on naming.** The foundation runtime is `@zap-proto/zap` (the canonical
10
+ > TypeScript ZAP runtime, repo `zap-proto/ts`). This package — the WebSocket
11
+ > frontend layer — is `@zap-proto/web`, repo `zap-proto/web`. It is **not**
12
+ > Cap'n Proto; ZAP is a zero-copy, zero-dependency binary format byte-compatible
13
+ > with the Go runtime `github.com/zap-proto/go` and `github.com/luxfi/zap`.
14
+
15
+ ## What @zap-proto/web IS
16
+
17
+ - A **drop-in replacement for tRPC** across Hanzo's TS apps (esign, console,
18
+ platform), using native ZAP RPC over WebSocket instead of JSON-over-HTTP.
19
+ - An **isomorphic transport** — the same `WsTransport` works in Node (post
20
+ HTTP-upgrade, over the `ws` package) and in the browser (native `WebSocket`).
21
+ - A Node **`serve(httpServer, opts)`** harness that attaches to an existing
22
+ `http.Server`, so Next.js (`app.getRequestHandler()`) or a Remix Node server
23
+ share one port — integration is one line.
24
+ - A browser **`connect(url, opts)`** that opens the WS, waits for `open`, and
25
+ returns the bootstrap call surface typed by your generated bindings.
26
+ - A **`mintCap` boundary hook** at the WS upgrade so apps plug their own
27
+ bearer→context minting logic.
28
+
29
+ ## What @zap-proto/web is NOT
30
+
31
+ - ❌ **Not a Zod/procedure DSL** like tRPC. Service shape comes from `.zap`
32
+ schemas (`struct`s + method ordinals), codegen'd via
33
+ `zapgen --target=ts` from [`zap-proto/ts`](https://github.com/zap-proto/ts).
34
+ - ❌ **Not a JSON wrapper.** Wire format is ZAP envelopes over WS **binary**
35
+ messages. Text frames are a protocol violation and close the socket with WS
36
+ code `1003`.
37
+ - ❌ **Not Cap'n Proto.** ZAP is its own zero-copy format. The bootstrap is the
38
+ connection's call surface (`bootstrap.call(method, { payload })`), not a
39
+ Cap'n Proto capability object.
40
+ - ❌ **Not a bearer-JWT framework.** `mintCap` is a **slot** — apps provide a fn
41
+ `(upgradeReq) => Promise<Ctx | null>`. `v0` ships the slot; the canonical
42
+ ML-DSA-65 signed `Capability` mint (per
43
+ [`zap-spec/capabilities.zap`](https://github.com/zap-proto/spec) — the
44
+ 3408-byte signature footer, BLAKE3 identity, attenuable/revocable authority)
45
+ lands in a later version. Until then, whatever non-null value `mintCap`
46
+ returns becomes the per-connection `ctx`.
47
+
48
+ ## Install
49
+
50
+ ```sh
51
+ pnpm i @zap-proto/web @zap-proto/zap
52
+ ```
53
+
54
+ > `@zap-proto/zap` is not yet published to npm. The `dependencies` entry already
55
+ > ships plain semver (`^0.1.0`); until it lands on npm, local tests resolve the
56
+ > specifier to the sibling source tree (`../ts`, the `zap-proto/ts` repo) via the
57
+ > `vitest.config.ts` alias and the `tsconfig.json` path. No change needed once
58
+ > `@zap-proto/zap` ships — just drop the alias.
59
+
60
+ ## Quick start — Next.js (≈30 lines)
61
+
62
+ ```ts
63
+ // server.ts
64
+ import http from "node:http";
65
+ import next from "next";
66
+ import { serve } from "@zap-proto/web/server";
67
+ import { newGreeting, HelloArgs } from "./gen/hello_zap.js"; // zapgen --target=ts
68
+
69
+ const app = next({ dev: process.env.NODE_ENV !== "production" });
70
+ const handle = app.getRequestHandler();
71
+
72
+ await app.prepare();
73
+ const server = http.createServer((req, res) => handle(req, res));
74
+
75
+ serve(server, {
76
+ path: "/zap",
77
+ // mintCap SLOT: turn a bearer into your app's ctx. Return null → HTTP 401.
78
+ mintCap: async (req) => {
79
+ const auth = req.headers.authorization;
80
+ return auth ? { org: await orgFromBearer(auth) } : null;
81
+ },
82
+ // rootCap(ctx): dispatch every decoded ZAP Call for this connection.
83
+ rootCap: (ctx) => (call) => {
84
+ const args = HelloArgs.wrap(call.payload);
85
+ return {
86
+ status: 200,
87
+ promiseID: call.promiseID,
88
+ body: newGreeting({ text: `hi ${args.name} @ ${ctx.org}` }),
89
+ };
90
+ },
91
+ });
92
+
93
+ server.listen(3000);
94
+ ```
95
+
96
+ ```ts
97
+ // client.ts (browser)
98
+ import { connect } from "@zap-proto/web/client";
99
+ import { newHelloArgs, Greeting } from "./gen/hello_zap.js";
100
+
101
+ const { bootstrap, close } = await connect("wss://app.hanzo.ai/zap", {
102
+ bearer: sessionToken, // forwarded as Authorization on the upgrade (Node ws)
103
+ });
104
+
105
+ const resp = await bootstrap.call(/* method */ 0, {
106
+ payload: newHelloArgs({ name: "ada" }),
107
+ });
108
+ console.log(Greeting.wrap(resp.body).text); // "hi ada @ acme"
109
+ close();
110
+ ```
111
+
112
+ > **Browser bearer caveat.** The browser's native `WebSocket` cannot set an
113
+ > `Authorization` header. In the browser, `connect({ bearer })` falls back to a
114
+ > `?authorization=Bearer%20…` query param the server can read; prefer a cookie
115
+ > sent automatically on the upgrade for production. The header path applies to a
116
+ > header-capable `WebSocketImpl` (the `ws` package, used in Node/SSR/tests).
117
+
118
+ ## Schema → code
119
+
120
+ Service shape is `.zap` schemas compiled with the ZAP compiler from
121
+ [`zap-proto/ts`](https://github.com/zap-proto/ts):
122
+
123
+ ```sh
124
+ zapgen --target=ts -single hello.zap # → hello_zap.ts (views + builders)
125
+ ```
126
+
127
+ Method ordinals (the interface method `@n`) are the integers you pass to
128
+ `bootstrap.call(method, …)` and match in your `rootCap` dispatch.
129
+
130
+ ## API
131
+
132
+ | Export | Entry | Purpose |
133
+ | --- | --- | --- |
134
+ | `serve(httpServer, opts)` | `@zap-proto/web/server` | Attach a ZAP RPC endpoint to a Node `http.Server`. |
135
+ | `connect(url, opts?)` | `@zap-proto/web/client` | Open a ZAP RPC WebSocket; returns `{ bootstrap, close }`. |
136
+ | `nodeWsTransport(ws)` / `browserWsTransport(ws)` | `@zap-proto/web/transport` | Wrap a `ws`/native WebSocket as a `WsTransport`. |
137
+ | `MintCap<Ctx>` | `@zap-proto/web/auth` | The bearer→ctx slot. |
138
+ | `WebRpcError` | `@zap-proto/web` | Transport-level RPC failure (rejected upgrade, mid-call close, non-OK status). |
139
+
140
+ ## License
141
+
142
+ MIT © Lux Industries Inc.
package/dist/auth.d.ts ADDED
@@ -0,0 +1,22 @@
1
+ import type { IncomingMessage } from "node:http";
2
+ /**
3
+ * MintCap is the boundary where a bearer (cookie, header, session) becomes a
4
+ * typed Capability that downstream RPC methods are authorized against.
5
+ *
6
+ * v0 ships the SLOT — apps supply their own fn. The canonical ML-DSA-65 signed
7
+ * Capability mint (per zap-spec/capabilities.zap — the 3408-byte signature
8
+ * footer, BLAKE3 object identity, attenuable/revocable authority) lands in a
9
+ * later version. Until then you can return any object: whatever non-null value
10
+ * you return becomes the `ctx` threaded into your `rootCap(ctx)` factory and
11
+ * carried on every {@link import("@zap-proto/zap").Call} as its capability buffer.
12
+ *
13
+ * Return `null` to reject the connection with HTTP 401 before the WebSocket
14
+ * upgrade completes — no socket is opened for an unauthorized request.
15
+ *
16
+ * @typeParam Ctx - the minted authority/context type your handlers consume.
17
+ * @param req - the raw HTTP upgrade request (read `req.headers.authorization`,
18
+ * cookies, etc.).
19
+ * @returns the minted context, or `null` to reject with 401.
20
+ */
21
+ export type MintCap<Ctx> = (req: IncomingMessage) => Promise<Ctx | null>;
22
+ //# sourceMappingURL=auth.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"auth.d.ts","sourceRoot":"","sources":["../src/auth.ts"],"names":[],"mappings":"AAGA,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,WAAW,CAAC;AAEjD;;;;;;;;;;;;;;;;;;GAkBG;AACH,MAAM,MAAM,OAAO,CAAC,GAAG,IAAI,CAAC,GAAG,EAAE,eAAe,KAAK,OAAO,CAAC,GAAG,GAAG,IAAI,CAAC,CAAC"}
package/dist/auth.js ADDED
@@ -0,0 +1,4 @@
1
+ // Copyright (C) 2025, Lux Industries Inc. All rights reserved.
2
+ // See the file LICENSE for licensing terms.
3
+ export {};
4
+ //# sourceMappingURL=auth.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"auth.js","sourceRoot":"","sources":["../src/auth.ts"],"names":[],"mappings":"AAAA,+DAA+D;AAC/D,4CAA4C"}
@@ -0,0 +1,50 @@
1
+ /**
2
+ * client.ts — connect(url, opts): open a ZAP-over-WebSocket RPC connection from
3
+ * the browser (or Node, for tests) and return the bootstrap call surface.
4
+ *
5
+ * The transport is isomorphic: in the browser this uses the native WebSocket
6
+ * global; in Node you inject the `ws` package's WebSocket via
7
+ * {@link ConnectOptions.WebSocketImpl} (Node 22+ also has a built-in global
8
+ * WebSocket, but it cannot set request headers — see the bearer note below).
9
+ *
10
+ * Bearer note: the browser's native WebSocket constructor CANNOT set an
11
+ * Authorization header — the WS protocol gives JS no header control. So:
12
+ * - Node `ws` (tests, SSR): we pass `{ headers: { Authorization } }`, which
13
+ * `ws` forwards on the upgrade request, where serve()'s mintCap reads it.
14
+ * - browser: rely on a cookie sent automatically on the upgrade, or encode
15
+ * the bearer in a subprotocol; the Authorization-header path only applies
16
+ * to a header-capable WebSocketImpl. We feature-detect by arity and fall
17
+ * back to a query param (`?authorization=Bearer%20...`) the server can read.
18
+ */
19
+ import { Conn } from "./conn.js";
20
+ /** Options for {@link connect}. */
21
+ export interface ConnectOptions {
22
+ /** Bearer token; forwarded as `Authorization: Bearer <bearer>` on upgrade. */
23
+ bearer?: string;
24
+ /**
25
+ * WebSocket constructor to use. Defaults to globalThis.WebSocket (browser /
26
+ * Node 22+). Inject the `ws` package's WebSocket in Node tests/SSR so the
27
+ * bearer can ride an Authorization header.
28
+ */
29
+ WebSocketImpl?: typeof WebSocket;
30
+ }
31
+ /**
32
+ * The bootstrap call surface returned by {@link connect}. RootCap is the
33
+ * generated typed wrapper a consumer layers over the raw {@link Conn} call
34
+ * surface — `connect<MyRootCap>(...)` then exposes typed methods on `bootstrap`.
35
+ *
36
+ * On the real @zap-proto/zap foundation the bootstrap is the connection's call
37
+ * surface (method ordinal + ZAP payload), not a Cap'n Proto capability object.
38
+ * The default `RootCap = Conn` gives you raw `bootstrap.call(method, { payload })`;
39
+ * a zapgen-generated client wraps that into named, typed methods.
40
+ */
41
+ export interface Connection<RootCap = Conn> {
42
+ bootstrap: RootCap;
43
+ close(): void;
44
+ }
45
+ /**
46
+ * Open a ZAP RPC WebSocket to `url`, wait for the connection to open, and
47
+ * return the bootstrap call surface. The default RootCap is the raw {@link Conn}.
48
+ */
49
+ export declare function connect<RootCap = Conn>(url: string, opts?: ConnectOptions): Promise<Connection<RootCap>>;
50
+ //# sourceMappingURL=client.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"client.d.ts","sourceRoot":"","sources":["../src/client.ts"],"names":[],"mappings":"AAGA;;;;;;;;;;;;;;;;;GAiBG;AAEH,OAAO,EAAE,IAAI,EAAE,MAAM,WAAW,CAAC;AAIjC,mCAAmC;AACnC,MAAM,WAAW,cAAc;IAC7B,8EAA8E;IAC9E,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB;;;;OAIG;IACH,aAAa,CAAC,EAAE,OAAO,SAAS,CAAC;CAClC;AAED;;;;;;;;;GASG;AACH,MAAM,WAAW,UAAU,CAAC,OAAO,GAAG,IAAI;IACxC,SAAS,EAAE,OAAO,CAAC;IACnB,KAAK,IAAI,IAAI,CAAC;CACf;AAED;;;GAGG;AACH,wBAAsB,OAAO,CAAC,OAAO,GAAG,IAAI,EAC1C,GAAG,EAAE,MAAM,EACX,IAAI,GAAE,cAAmB,GACxB,OAAO,CAAC,UAAU,CAAC,OAAO,CAAC,CAAC,CAgD9B"}
package/dist/client.js ADDED
@@ -0,0 +1,105 @@
1
+ // Copyright (C) 2025, Lux Industries Inc. All rights reserved.
2
+ // See the file LICENSE for licensing terms.
3
+ /**
4
+ * client.ts — connect(url, opts): open a ZAP-over-WebSocket RPC connection from
5
+ * the browser (or Node, for tests) and return the bootstrap call surface.
6
+ *
7
+ * The transport is isomorphic: in the browser this uses the native WebSocket
8
+ * global; in Node you inject the `ws` package's WebSocket via
9
+ * {@link ConnectOptions.WebSocketImpl} (Node 22+ also has a built-in global
10
+ * WebSocket, but it cannot set request headers — see the bearer note below).
11
+ *
12
+ * Bearer note: the browser's native WebSocket constructor CANNOT set an
13
+ * Authorization header — the WS protocol gives JS no header control. So:
14
+ * - Node `ws` (tests, SSR): we pass `{ headers: { Authorization } }`, which
15
+ * `ws` forwards on the upgrade request, where serve()'s mintCap reads it.
16
+ * - browser: rely on a cookie sent automatically on the upgrade, or encode
17
+ * the bearer in a subprotocol; the Authorization-header path only applies
18
+ * to a header-capable WebSocketImpl. We feature-detect by arity and fall
19
+ * back to a query param (`?authorization=Bearer%20...`) the server can read.
20
+ */
21
+ import { Conn } from "./conn.js";
22
+ import { browserWsTransport } from "./transport.js";
23
+ import { WebRpcError } from "./errors.js";
24
+ /**
25
+ * Open a ZAP RPC WebSocket to `url`, wait for the connection to open, and
26
+ * return the bootstrap call surface. The default RootCap is the raw {@link Conn}.
27
+ */
28
+ export async function connect(url, opts = {}) {
29
+ const Impl = opts.WebSocketImpl ?? globalThis.WebSocket;
30
+ if (!Impl) {
31
+ throw new WebRpcError("zap-web: no WebSocket implementation (pass opts.WebSocketImpl)");
32
+ }
33
+ const ws = openSocket(Impl, url, opts.bearer);
34
+ await new Promise((resolve, reject) => {
35
+ const onOpen = () => {
36
+ cleanup();
37
+ resolve();
38
+ };
39
+ const onErr = () => {
40
+ cleanup();
41
+ reject(new WebRpcError(`zap-web: failed to connect to ${url}`));
42
+ };
43
+ const onClose = (ev) => {
44
+ cleanup();
45
+ const code = ev?.code;
46
+ reject(new WebRpcError(`zap-web: upgrade rejected by ${url}`, code === 1006 ? 401 : code));
47
+ };
48
+ const cleanup = () => {
49
+ remove(ws, "open", onOpen);
50
+ remove(ws, "error", onErr);
51
+ remove(ws, "close", onClose);
52
+ };
53
+ add(ws, "open", onOpen);
54
+ add(ws, "error", onErr);
55
+ add(ws, "close", onClose);
56
+ });
57
+ const transport = browserWsTransport(ws);
58
+ const conn = new Conn(transport);
59
+ return {
60
+ bootstrap: conn,
61
+ close() {
62
+ conn.close(1000, "client closed");
63
+ },
64
+ };
65
+ }
66
+ /**
67
+ * Construct a WebSocket, attaching the bearer the best way the impl allows.
68
+ * Node `ws` accepts a 3rd `options.headers` arg; the browser native WebSocket
69
+ * does not, so we fall back to a query param the server can read.
70
+ */
71
+ function openSocket(Impl, url, bearer) {
72
+ if (!bearer)
73
+ return new Impl(url);
74
+ // Node `ws` WebSocket: third constructor arg is options { headers }.
75
+ // We detect header support by the constructor's declared arity (>= 3).
76
+ if (Impl.length >= 3) {
77
+ return new Impl(url, undefined, {
78
+ headers: { Authorization: `Bearer ${bearer}` },
79
+ });
80
+ }
81
+ // Browser native WebSocket: no header control — encode on the URL instead.
82
+ const u = new URL(url);
83
+ u.searchParams.set("authorization", `Bearer ${bearer}`);
84
+ return new Impl(u.toString());
85
+ }
86
+ // --- isomorphic add/remove listener (browser EventTarget vs `ws` emitter) ---
87
+ function add(ws, type, fn) {
88
+ const anyWs = ws;
89
+ if (typeof anyWs.addEventListener === "function") {
90
+ anyWs.addEventListener(type, fn);
91
+ }
92
+ else if (typeof anyWs.on === "function") {
93
+ anyWs.on(type, fn);
94
+ }
95
+ }
96
+ function remove(ws, type, fn) {
97
+ const anyWs = ws;
98
+ if (typeof anyWs.removeEventListener === "function") {
99
+ anyWs.removeEventListener(type, fn);
100
+ }
101
+ else if (typeof anyWs.off === "function") {
102
+ anyWs.off(type, fn);
103
+ }
104
+ }
105
+ //# sourceMappingURL=client.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"client.js","sourceRoot":"","sources":["../src/client.ts"],"names":[],"mappings":"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"}
package/dist/conn.d.ts ADDED
@@ -0,0 +1,60 @@
1
+ /**
2
+ * conn.ts — a transport-agnostic ZAP RPC connection over a {@link WsTransport}.
3
+ *
4
+ * This is the shared core of both serve() and connect(). It mirrors the
5
+ * correlation logic of @zap-proto/zap's ZapClient (Node TCP), but rides a duplex
6
+ * WebSocket transport instead of a TCP socket and works in both directions:
7
+ *
8
+ * - client side: call() ships a request envelope and resolves its Response
9
+ * when the matching promiseID comes back.
10
+ * - server side: an inbound request envelope is decoded into a Call and
11
+ * handed to the registered handler, whose Response is shipped back.
12
+ *
13
+ * Each WS binary message is exactly one ZAP envelope (see transport.ts), so the
14
+ * envelope's own header tag (MSG_TYPE_ROUTER_BASE) distinguishes a request from
15
+ * a response and there is no extra framing. We disambiguate direction by trying
16
+ * the request decode first; a frame that parses as a request with a known
17
+ * method is dispatched as a server call, otherwise it is treated as a response
18
+ * to one of our outstanding promises.
19
+ */
20
+ import { type Call, type Response } from "@zap-proto/zap";
21
+ import type { WsTransport } from "./transport.js";
22
+ /** A server-side request handler: a decoded Call in, a Response out. */
23
+ export type CallHandler = (call: Call) => Promise<Response> | Response;
24
+ /** Options for an outbound {@link Conn.call}. */
25
+ export interface CallOptions {
26
+ /** Pipeline this call off an earlier call's promiseID (0 = root). */
27
+ target?: number;
28
+ /** Capability buffer to carry on the call (defaults to the conn's cap). */
29
+ cap?: Uint8Array;
30
+ /** Method params, ZAP-encoded. */
31
+ payload?: Uint8Array;
32
+ }
33
+ /**
34
+ * Conn correlates ZAP request/response envelopes over a single duplex
35
+ * WebSocket transport. One Conn is FIFO per direction on the wire, matching the
36
+ * Go node's per-connection dispatch.
37
+ */
38
+ export declare class Conn {
39
+ private readonly transport;
40
+ private readonly pending;
41
+ private promiseSeq;
42
+ private closed;
43
+ private handler;
44
+ private readonly cap;
45
+ constructor(transport: WsTransport, opts?: {
46
+ handler?: CallHandler;
47
+ cap?: Uint8Array;
48
+ });
49
+ /**
50
+ * Ship one Call and await its correlated Response. The promiseID is assigned
51
+ * here unless the caller pipelines via {@link CallOptions.target}.
52
+ */
53
+ call(method: number, opts?: CallOptions): Promise<Response>;
54
+ /** Close the connection and fail all in-flight calls. */
55
+ close(code?: number, reason?: string): void;
56
+ private onFrame;
57
+ private dispatch;
58
+ private fail;
59
+ }
60
+ //# sourceMappingURL=conn.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"conn.d.ts","sourceRoot":"","sources":["../src/conn.ts"],"names":[],"mappings":"AAGA;;;;;;;;;;;;;;;;;;GAkBG;AAEH,OAAO,EAOL,KAAK,IAAI,EACT,KAAK,QAAQ,EACd,MAAM,gBAAgB,CAAC;AACxB,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,gBAAgB,CAAC;AAGlD,wEAAwE;AACxE,MAAM,MAAM,WAAW,GAAG,CAAC,IAAI,EAAE,IAAI,KAAK,OAAO,CAAC,QAAQ,CAAC,GAAG,QAAQ,CAAC;AAEvE,iDAAiD;AACjD,MAAM,WAAW,WAAW;IAC1B,qEAAqE;IACrE,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,2EAA2E;IAC3E,GAAG,CAAC,EAAE,UAAU,CAAC;IACjB,kCAAkC;IAClC,OAAO,CAAC,EAAE,UAAU,CAAC;CACtB;AAID;;;;GAIG;AACH,qBAAa,IAAI;IAQb,OAAO,CAAC,QAAQ,CAAC,SAAS;IAP5B,OAAO,CAAC,QAAQ,CAAC,OAAO,CAA4C;IACpE,OAAO,CAAC,UAAU,CAAK;IACvB,OAAO,CAAC,MAAM,CAAS;IACvB,OAAO,CAAC,OAAO,CAA4B;IAC3C,OAAO,CAAC,QAAQ,CAAC,GAAG,CAAa;gBAGd,SAAS,EAAE,WAAW,EACvC,IAAI,GAAE;QAAE,OAAO,CAAC,EAAE,WAAW,CAAC;QAAC,GAAG,CAAC,EAAE,UAAU,CAAA;KAAO;IAQxD;;;OAGG;IACH,IAAI,CAAC,MAAM,EAAE,MAAM,EAAE,IAAI,GAAE,WAAgB,GAAG,OAAO,CAAC,QAAQ,CAAC;IAwB/D,yDAAyD;IACzD,KAAK,CAAC,IAAI,CAAC,EAAE,MAAM,EAAE,MAAM,CAAC,EAAE,MAAM,GAAG,IAAI;IAM3C,OAAO,CAAC,OAAO;YAmBD,QAAQ;IA8BtB,OAAO,CAAC,IAAI;CAcb"}
package/dist/conn.js ADDED
@@ -0,0 +1,145 @@
1
+ // Copyright (C) 2025, Lux Industries Inc. All rights reserved.
2
+ // See the file LICENSE for licensing terms.
3
+ /**
4
+ * conn.ts — a transport-agnostic ZAP RPC connection over a {@link WsTransport}.
5
+ *
6
+ * This is the shared core of both serve() and connect(). It mirrors the
7
+ * correlation logic of @zap-proto/zap's ZapClient (Node TCP), but rides a duplex
8
+ * WebSocket transport instead of a TCP socket and works in both directions:
9
+ *
10
+ * - client side: call() ships a request envelope and resolves its Response
11
+ * when the matching promiseID comes back.
12
+ * - server side: an inbound request envelope is decoded into a Call and
13
+ * handed to the registered handler, whose Response is shipped back.
14
+ *
15
+ * Each WS binary message is exactly one ZAP envelope (see transport.ts), so the
16
+ * envelope's own header tag (MSG_TYPE_ROUTER_BASE) distinguishes a request from
17
+ * a response and there is no extra framing. We disambiguate direction by trying
18
+ * the request decode first; a frame that parses as a request with a known
19
+ * method is dispatched as a server call, otherwise it is treated as a response
20
+ * to one of our outstanding promises.
21
+ */
22
+ import { buildRequest, buildResponse, parseRequest, parseResponse, NO_TARGET, Status, } from "@zap-proto/zap";
23
+ import { WebRpcError } from "./errors.js";
24
+ const EMPTY = new Uint8Array(0);
25
+ /**
26
+ * Conn correlates ZAP request/response envelopes over a single duplex
27
+ * WebSocket transport. One Conn is FIFO per direction on the wire, matching the
28
+ * Go node's per-connection dispatch.
29
+ */
30
+ export class Conn {
31
+ transport;
32
+ pending = new Map();
33
+ promiseSeq = 0;
34
+ closed = false;
35
+ handler = null;
36
+ cap;
37
+ constructor(transport, opts = {}) {
38
+ this.transport = transport;
39
+ this.handler = opts.handler ?? null;
40
+ this.cap = opts.cap ?? EMPTY;
41
+ transport.onMessage((bytes) => this.onFrame(bytes));
42
+ transport.onClose(() => this.fail());
43
+ }
44
+ /**
45
+ * Ship one Call and await its correlated Response. The promiseID is assigned
46
+ * here unless the caller pipelines via {@link CallOptions.target}.
47
+ */
48
+ call(method, opts = {}) {
49
+ if (this.closed) {
50
+ return Promise.reject(new WebRpcError("zap-web: connection closed"));
51
+ }
52
+ this.promiseSeq = (this.promiseSeq + 1) >>> 0 || 1;
53
+ const promiseID = this.promiseSeq;
54
+ const c = {
55
+ method,
56
+ promiseID,
57
+ target: opts.target ?? NO_TARGET,
58
+ cap: opts.cap ?? this.cap,
59
+ payload: opts.payload ?? EMPTY,
60
+ };
61
+ return new Promise((resolve, reject) => {
62
+ this.pending.set(promiseID, resolve);
63
+ try {
64
+ this.transport.send(buildRequest(c));
65
+ }
66
+ catch (err) {
67
+ this.pending.delete(promiseID);
68
+ reject(err instanceof Error ? err : new WebRpcError(String(err)));
69
+ }
70
+ });
71
+ }
72
+ /** Close the connection and fail all in-flight calls. */
73
+ close(code, reason) {
74
+ if (this.closed)
75
+ return;
76
+ this.transport.close(code, reason);
77
+ this.fail();
78
+ }
79
+ onFrame(bytes) {
80
+ if (this.handler) {
81
+ // Server side: every inbound frame is a request to dispatch.
82
+ this.dispatch(bytes);
83
+ return;
84
+ }
85
+ // Client side: every inbound frame is a response to one of our calls.
86
+ let resp;
87
+ try {
88
+ resp = parseResponse(bytes);
89
+ }
90
+ catch {
91
+ return; // malformed frame from peer — drop it.
92
+ }
93
+ const resolve = this.pending.get(resp.promiseID);
94
+ if (!resolve)
95
+ return;
96
+ this.pending.delete(resp.promiseID);
97
+ resolve(resp);
98
+ }
99
+ async dispatch(bytes) {
100
+ let call;
101
+ try {
102
+ call = parseRequest(bytes);
103
+ }
104
+ catch {
105
+ return; // unparseable request — drop it.
106
+ }
107
+ const handler = this.handler;
108
+ if (!handler)
109
+ return;
110
+ let resp;
111
+ try {
112
+ resp = await handler(call);
113
+ }
114
+ catch (err) {
115
+ const msg = err instanceof Error ? err.message : "internal handler error";
116
+ resp = {
117
+ status: Status.Internal,
118
+ promiseID: call.promiseID,
119
+ body: new TextEncoder().encode(JSON.stringify({ error: msg })),
120
+ };
121
+ }
122
+ if (this.closed)
123
+ return;
124
+ try {
125
+ this.transport.send(buildResponse(resp.status, call.promiseID, resp.body));
126
+ }
127
+ catch {
128
+ // peer went away mid-response — nothing to do.
129
+ }
130
+ }
131
+ fail() {
132
+ if (this.closed)
133
+ return;
134
+ this.closed = true;
135
+ for (const [, resolve] of this.pending) {
136
+ resolve({
137
+ status: 0,
138
+ promiseID: 0,
139
+ body: new TextEncoder().encode(JSON.stringify({ error: "connection closed" })),
140
+ });
141
+ }
142
+ this.pending.clear();
143
+ }
144
+ }
145
+ //# sourceMappingURL=conn.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"conn.js","sourceRoot":"","sources":["../src/conn.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,21 @@
1
+ /**
2
+ * errors.ts — error surface for the web RPC layer.
3
+ *
4
+ * Method/wire-level decode failures keep using @zap-proto/zap's ZapParseError (the
5
+ * runtime throws it on a bad magic/version/size); we re-export it so consumers
6
+ * have one import site. WebRpcError is new: it covers transport-level failures
7
+ * that only exist at the WebSocket boundary — a rejected upgrade, a socket that
8
+ * closes mid-call, or a non-OK RPC status surfaced to the caller.
9
+ */
10
+ export { ZapParseError } from "@zap-proto/zap";
11
+ /**
12
+ * WebRpcError is raised for WebSocket-transport-level failures: the upgrade was
13
+ * rejected (401/other), the socket closed while a call was in flight, or a
14
+ * call returned a non-OK ZAP status. `status` carries the ZAP/HTTP status when
15
+ * one is known (e.g. 401 for a rejected mint, or the response envelope status).
16
+ */
17
+ export declare class WebRpcError extends Error {
18
+ readonly status?: number;
19
+ constructor(message: string, status?: number);
20
+ }
21
+ //# sourceMappingURL=errors.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"errors.d.ts","sourceRoot":"","sources":["../src/errors.ts"],"names":[],"mappings":"AAGA;;;;;;;;GAQG;AAEH,OAAO,EAAE,aAAa,EAAE,MAAM,gBAAgB,CAAC;AAE/C;;;;;GAKG;AACH,qBAAa,WAAY,SAAQ,KAAK;IACpC,QAAQ,CAAC,MAAM,CAAC,EAAE,MAAM,CAAC;gBAEb,OAAO,EAAE,MAAM,EAAE,MAAM,CAAC,EAAE,MAAM;CAK7C"}
package/dist/errors.js ADDED
@@ -0,0 +1,27 @@
1
+ // Copyright (C) 2025, Lux Industries Inc. All rights reserved.
2
+ // See the file LICENSE for licensing terms.
3
+ /**
4
+ * errors.ts — error surface for the web RPC layer.
5
+ *
6
+ * Method/wire-level decode failures keep using @zap-proto/zap's ZapParseError (the
7
+ * runtime throws it on a bad magic/version/size); we re-export it so consumers
8
+ * have one import site. WebRpcError is new: it covers transport-level failures
9
+ * that only exist at the WebSocket boundary — a rejected upgrade, a socket that
10
+ * closes mid-call, or a non-OK RPC status surfaced to the caller.
11
+ */
12
+ export { ZapParseError } from "@zap-proto/zap";
13
+ /**
14
+ * WebRpcError is raised for WebSocket-transport-level failures: the upgrade was
15
+ * rejected (401/other), the socket closed while a call was in flight, or a
16
+ * call returned a non-OK ZAP status. `status` carries the ZAP/HTTP status when
17
+ * one is known (e.g. 401 for a rejected mint, or the response envelope status).
18
+ */
19
+ export class WebRpcError extends Error {
20
+ status;
21
+ constructor(message, status) {
22
+ super(message);
23
+ this.name = "WebRpcError";
24
+ this.status = status;
25
+ }
26
+ }
27
+ //# sourceMappingURL=errors.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"errors.js","sourceRoot":"","sources":["../src/errors.ts"],"names":[],"mappings":"AAAA,+DAA+D;AAC/D,4CAA4C;AAE5C;;;;;;;;GAQG;AAEH,OAAO,EAAE,aAAa,EAAE,MAAM,gBAAgB,CAAC;AAE/C;;;;;GAKG;AACH,MAAM,OAAO,WAAY,SAAQ,KAAK;IAC3B,MAAM,CAAU;IAEzB,YAAY,OAAe,EAAE,MAAe;QAC1C,KAAK,CAAC,OAAO,CAAC,CAAC;QACf,IAAI,CAAC,IAAI,GAAG,aAAa,CAAC;QAC1B,IAAI,CAAC,MAAM,GAAG,MAAM,CAAC;IACvB,CAAC;CACF"}