Skip to content

Instantly share code, notes, and snippets.

@mmyoji
Last active September 30, 2025 04:53
Show Gist options
  • Save mmyoji/bfccf32b67262b021415b27913de47e3 to your computer and use it in GitHub Desktop.
Save mmyoji/bfccf32b67262b021415b27913de47e3 to your computer and use it in GitHub Desktop.
Minimal local example of Cap'n Web
import { newWebSocketRpcSession } from "capnweb";
import type { MyApi } from "./server.ts";
const api = newWebSocketRpcSession<MyApi>("ws://localhost:8080/api");
const result = await api.hello("World");
console.log(result);
{
"name": "@mmyoji/capnweb-test",
"private": true,
"version": "1.0.0",
"main": "server.ts",
"type": "module",
"scripts": {
"start:client": "node --experimental-strip-types client.ts",
"start:server": "node --experimental-strip-types server.ts"
},
"author": "mmyoji",
"license": "ISC",
"dependencies": {
"capnweb": "^0.1.0",
"ws": "^8.18.3"
},
"devDependencies": {
"@types/node": "^22.18.7",
"@types/ws": "^8.18.1"
}
}
import http from "node:http";
import {
RpcTarget,
newWebSocketRpcSession,
nodeHttpBatchRpcResponse,
} from "capnweb";
import { WebSocketServer } from "ws";
export interface MyApi {
hello(name: string): string;
}
class MyApiServer extends RpcTarget implements MyApi {
hello(name: string) {
return `Hello, ${name}`;
}
}
const send = (
res: http.ServerResponse,
{ status, text }: { status: number; text: string }
) => {
res.writeHead(status, { "Content-Type": "text/plain" });
res.end(text);
};
const server = http.createServer(async (req, res) => {
if (req.headers.upgrade?.toLowerCase() === "websocket") {
return;
}
if (req.url === "/api") {
try {
await nodeHttpBatchRpcResponse(req, res, new MyApiServer(), {
headers: { "Access-Control-Allow-Origin": "*" },
});
} catch (err) {
send(res, { status: 500, text: String(err?.stack || err) });
}
return;
}
send(res, { status: 404, text: "Not Found" });
});
const wsServer = new WebSocketServer({ server });
wsServer.on("connection", (ws) => {
newWebSocketRpcSession(ws as any, new MyApiServer());
});
server.listen(8080);
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment