### Full RpcSession Example Source: https://github.com/cloudflare/capnweb/blob/main/_autodocs/core-types.md Demonstrates the complete setup and usage of RpcSession with a custom transport implementation, exposing a local API, and interacting with the remote peer's interface. ```typescript import { RpcSession, RpcTransport, RpcTarget } from "capnweb"; // Implement a custom transport class MyTransport implements RpcTransport { async send(message: string): Promise { // Send to peer... } async receive(): Promise { // Receive from peer... } } class MyApi extends RpcTarget { hello() { return "Hello!"; } } // Create a session with custom transport const transport = new MyTransport(); const session = new RpcSession(transport, new MyApi()); // Get stub for peer's main interface const stub = session.getRemoteMain(); // Get session stats const stats = session.getStats(); console.log(`Exports: ${stats.exports}, Imports: ${stats.imports}`); // Wait for processing to complete await session.drain(); ``` -------------------------------- ### Setting up an RpcSession with a Custom Transport Source: https://github.com/cloudflare/capnweb/blob/main/README.md Demonstrates how to instantiate a custom transport, define a local interface, and start an RpcSession. This session can then be used to get a stub for the remote interface. ```typescript // Create the transport. let transport: RpcTransport = new MyTransport(); // Create the main interface we will expose to the other end. let localMain: RpcTarget = new MyMainInterface(); // Start the session. let session = new RpcSession(transport, localMain); // Get a stub for the other end's main interface. let stub: RemoteMainInterface = session.getRemoteMain(); // Now we can call methods on the stub. ``` -------------------------------- ### Bun WebSocket Handler Setup (Recommended) Source: https://github.com/cloudflare/capnweb/blob/main/_autodocs/bun-websocket-sessions.md Shows the recommended one-liner setup for a Bun WebSocket RPC handler. ```typescript const handler = newBunWebSocketRpcHandler(() => new MyApi()); Bun.serve({ websocket: handler, fetch: handleRoute }); ``` -------------------------------- ### Bun WebSocket RPC Server with Client Callbacks Source: https://github.com/cloudflare/capnweb/blob/main/_autodocs/bun-websocket-sessions.md An example demonstrating a Bun WebSocket RPC server that can call back to clients using `RpcStub`. This setup requires custom connection tracking. ```typescript import { RpcTarget, newBunWebSocketRpcHandler } from "capnweb"; interface ClientCallbacks { onServerBroadcast(message: string): void; } class ServerApi extends RpcTarget { constructor(public clientStub: RpcStub) {} async request(data: string): string { // Call back to client await this.clientStub.onServerBroadcast(`Echo: ${data}`); return `Processed: ${data}`; } } class ClientApi extends RpcTarget { onServerBroadcast(message: string) { console.log("Server broadcast:", message); } } const clients = new Map(); const wsHandler = newBunWebSocketRpcHandler(() => { // Create server API bound to a client stub // You'll need to link the client to the server after the connection is established return new ServerApi(null as any); }); Bun.serve({ port: 3000, fetch(req, server) { const url = new URL(req.url); if (url.pathname === "/api" && req.headers.get("upgrade")?.toLowerCase() === "websocket") { return server.upgrade(req) ? undefined : new Response("Upgrade failed", { status: 500 }); } return new Response("Not found", { status: 404 }); }, websocket: { ...wsHandler, // Note: This pattern requires custom setup; for simplicity, consider using // newBunWebSocketRpcSession directly with manual connection tracking }, }); ``` -------------------------------- ### Typical Bun WebSocket Server Setup Source: https://github.com/cloudflare/capnweb/blob/main/_autodocs/bun-websocket-sessions.md Illustrates a common setup for a Bun WebSocket server using a handler. ```typescript const wsHandler = newBunWebSocketRpcHandler(() => new MyApi()); Bun.serve({ websocket: wsHandler, fetch(req, server) { return server.upgrade(req); } }); ``` -------------------------------- ### Install Cap'n Web with npm Source: https://github.com/cloudflare/capnweb/blob/main/README.md Install the Cap'n Web package using npm. This is the first step before using the library. ```bash npm i capnweb ``` -------------------------------- ### Install Capnweb Package Source: https://github.com/cloudflare/capnweb/blob/main/_autodocs/README.md Install the Capnweb library using npm. This is the first step before using any of its features. ```bash npm install capnweb ``` -------------------------------- ### WebSocketRpcSession Basic Example Source: https://github.com/cloudflare/capnweb/blob/main/_autodocs/MANIFEST.txt A basic example of establishing and using a WebSocket RPC session. ```typescript const session = newWebSocketRpcSession(transport); const result = await session.call("myMethod", [arg1]); ``` -------------------------------- ### HttpBatchRpcSession Basic Example Source: https://github.com/cloudflare/capnweb/blob/main/_autodocs/MANIFEST.txt A basic example of creating and using an HTTP Batch RPC session. ```typescript const session = newHttpBatchRpcSession(transport); const result = await session.call("myMethod", [arg1, arg2]); ``` -------------------------------- ### Bun WebSocket Session Setup (Custom) Source: https://github.com/cloudflare/capnweb/blob/main/_autodocs/bun-websocket-sessions.md Demonstrates a custom setup for a Bun WebSocket server using the session approach, providing more control over connection management. ```typescript Bun.serve({ websocket: { open(ws) { const { transport } = newBunWebSocketRpcSession(ws, new MyApi()); ws.data = { transport }; }, message(ws, msg) { ws.data.transport.dispatchMessage(msg); }, close(ws, code, reason) { ws.data.transport.dispatchClose(code, reason); }, error(ws, err) { ws.data.transport.dispatchError(err); } }, fetch: handleRoute }); ``` -------------------------------- ### Browser Client Setup for Cloudflare Workers Source: https://github.com/cloudflare/capnweb/blob/main/_autodocs/examples.md Set up a Cap'n Web client in the browser to communicate with a Cloudflare Worker RPC endpoint. This example shows how to establish a session and make RPC calls to the defined API. ```typescript import { newHttpBatchRpcSession } from "capnweb"; interface Api { greet(name: string): string; add(a: number, b: number): number; } // One-time setup const api = newHttpBatchRpcSession("https://my-worker.dev/api"); // Make calls const greeting = await api.greet("World"); const sum = await api.add(5, 3); console.log(greeting); // "Hello, World!" console.log(sum); // 8 ``` -------------------------------- ### Cap'n Web RPC Client Example Source: https://github.com/cloudflare/capnweb/blob/main/README.md Example of setting up an RPC client using Cap'n Web. This client connects to a WebSocket endpoint and calls a remote method. ```javascript import { newWebSocketRpcSession } from "capnweb"; // One-line setup. let api = newWebSocketRpcSession("wss://example.com/api"); // Call a method on the server! let result = await api.hello("World"); console.log(result); ``` -------------------------------- ### newBunWebSocketRpcHandler() Zero-Boilerplate Example Source: https://github.com/cloudflare/capnweb/blob/main/_autodocs/MANIFEST.txt A zero-boilerplate example of setting up a Bun WebSocket RPC server using newBunWebSocketRpcHandler. ```typescript import { newBunWebSocketRpcHandler } from "@capnweb/bun-websocket-sessions"; Bun.serve({ fetch: newBunWebSocketRpcHandler(async (method, args) => { // Handle RPC call }), // ... other server options }); ``` -------------------------------- ### Deno Example for newHttpBatchRpcResponse Source: https://github.com/cloudflare/capnweb/blob/main/_autodocs/http-batch-sessions.md Illustrates how to implement batch RPC request handling in a Deno environment using `newHttpBatchRpcResponse`. This example sets up a Deno server to expose an RPC interface. ```typescript import { RpcTarget, newHttpBatchRpcResponse } from "npm:capnweb"; class MyApiServer extends RpcTarget { greet(name: string): string { return `Hello, ${name}`; } } Deno.serve(async (req) => { const url = new URL(req.url); if (url.pathname === "/api") { const response = await newHttpBatchRpcResponse( req, new MyApiServer() ); response.headers.set("Access-Control-Allow-Origin", "*"); return response; } return new Response("Not found", { status: 404 }); }); ``` -------------------------------- ### MessagePortRpcSession Parent-to-Iframe Example Source: https://github.com/cloudflare/capnweb/blob/main/_autodocs/MANIFEST.txt Example of setting up a MessagePort RPC session for communication between a parent window and an iframe. ```typescript const session = newMessagePortRpcSession(port, { // ... options ... }); ``` -------------------------------- ### Basic Setup: Browser to Cloudflare Workers Source: https://github.com/cloudflare/capnweb/blob/main/_autodocs/MANIFEST.txt Provides the server and client code for a basic RPC setup between a browser and Cloudflare Workers. ```typescript // --- Server (Cloudflare Worker) --- import { newWorkersRpcResponse } from '@capnp/rpc-web'; export default { async fetch(request: Request): Promise { return newWorkersRpcResponse(request, { // Implement your RPC methods here greet: async (name: string) => `Hello, ${name}!` }); } }; // --- Client (Browser) --- import { newWebSocketRpcSession } from '@capnp/rpc-web'; async function main() { const session = await newWebSocketRpcSession<{ greet: (name: string) => Promise }>(new WebSocket('wss://your-worker-url.workers.dev')); const greeting = await session.greet('World'); console.log(greeting); } ``` -------------------------------- ### WebSocketRpcSession Server Callback Example Source: https://github.com/cloudflare/capnweb/blob/main/_autodocs/MANIFEST.txt Example showing server-side callbacks initiated through a WebSocket RPC session. ```typescript const session = newWebSocketRpcSession(transport, { onServerCallback: (method, args) => { console.log(`Server callback: ${method}(${args.join(', ')})`); } }); ``` -------------------------------- ### Cap'n Web RPC Server Example (Cloudflare Workers) Source: https://github.com/cloudflare/capnweb/blob/main/README.md Example of an RPC server implementation using Cap'n Web for Cloudflare Workers. It defines an API and handles incoming requests. ```javascript import { RpcTarget, newWorkersRpcResponse } from "capnweb"; // This is the server implementation. class MyApiServer extends RpcTarget { hello(name) { return `Hello, ${name}!` } } // Standard Cloudflare Workers HTTP handler. // // (Node and other runtimes are supported too; see below.) export default { fetch(request, env, ctx) { // Parse URL for routing. let url = new URL(request.url); // Serve API at `/api`. if (url.pathname === "/api") { return newWorkersRpcResponse(request, new MyApiServer()); } // You could serve other endpoints here... return new Response("Not found", {status: 404}); } } ``` -------------------------------- ### newBunWebSocketRpcHandler() Server Callback Example Source: https://github.com/cloudflare/capnweb/blob/main/_autodocs/MANIFEST.txt Example of a Bun WebSocket RPC server that can initiate callbacks to clients. ```typescript const handler = newBunWebSocketRpcHandler(async (method, args, ws) => { // Handle RPC call if (method === "requestCallback") { ws.send("callback", ["data"]) } }); ``` -------------------------------- ### WebSocketRpcSession Pipelining Example Source: https://github.com/cloudflare/capnweb/blob/main/_autodocs/MANIFEST.txt Demonstrates how to use promise pipelining with a WebSocket RPC session. ```typescript const session = newWebSocketRpcSession(transport); const data = await session.call("fetchData").then(d => session.call("processData", [d])); ``` -------------------------------- ### Install capnweb-validate Source: https://github.com/cloudflare/capnweb/blob/main/packages/capnweb-validate/README.md Install the necessary packages for capnweb-validate. Workers RPC users can install only capnweb-validate. ```sh npm install capnweb capnweb-validate ``` -------------------------------- ### Cloudflare Worker Server Setup Source: https://github.com/cloudflare/capnweb/blob/main/_autodocs/examples.md Implement the server-side logic for Cap'n Web RPC endpoints using Cloudflare Workers. This example defines an API interface and its implementation, handling incoming requests and returning RPC responses. ```typescript import { RpcTarget, newWorkersRpcResponse } from "capnweb"; interface Api { greet(name: string): string; add(a: number, b: number): number; } class ApiImpl extends RpcTarget implements Api { greet(name: string): string { return `Hello, ${name}!`; } add(a: number, b: number): number { return a + b; } } export default { async fetch(request: Request) { const url = new URL(request.url); if (url.pathname === "/api") { return await newWorkersRpcResponse(request, new ApiImpl()); } return new Response("Not found", { status: 404 }); } }; ``` -------------------------------- ### Promise Pipelining Basic Example Source: https://github.com/cloudflare/capnweb/blob/main/_autodocs/MANIFEST.txt A fundamental example of promise pipelining, chaining RPC calls where the result of one is used as input for the next. ```typescript const result = await session.call("fetchUser", [userId]).then(user => session.call("getUserPosts", [user.id])); ``` -------------------------------- ### Manual WebSocket RPC Session Wiring Example Source: https://github.com/cloudflare/capnweb/blob/main/_autodocs/bun-websocket-sessions.md Demonstrates how to manually set up and manage an RPC session using newBunWebSocketRpcSession within Bun's WebSocket server handlers. ```typescript import { RpcTarget, newBunWebSocketRpcSession } from "capnweb"; class MyApi extends RpcTarget { greet(name: string): string { return `Hello, ${name} அளிக்க!`; } } Bun.serve({ port: 3000, fetch(req, server) { const url = new URL(req.url); if (url.pathname === "/api" && req.headers.get("upgrade")?.toLowerCase() === "websocket") { if (server.upgrade(req)) return; return new Response("Upgrade failed", { status: 500 }); } return new Response("Not found", { status: 404 }); }, websocket: { open(ws) { // Manually setup RPC session const { stub, transport } = newBunWebSocketRpcSession(ws, new MyApi()); ws.data = { transport, stub }; }, message(ws, message) { // Manually dispatch message ws.data.transport.dispatchMessage(message); }, close(ws, code, reason) { // Manually dispatch close ws.data.transport.dispatchClose(code, reason); }, error(ws, error) { // Manually dispatch error ws.data.transport.dispatchError(error); }, }, }); ``` -------------------------------- ### Express-like Server Example with nodeHttpBatchRpcResponse Source: https://github.com/cloudflare/capnweb/blob/main/_autodocs/http-batch-sessions.md An example demonstrating how to use `nodeHttpBatchRpcResponse` within a Node.js HTTP server, similar to Express, to handle batch RPC requests on a specific endpoint. ```typescript import http from "node:http"; import { RpcTarget, nodeHttpBatchRpcResponse } from "capnweb"; class MyApiServer extends RpcTarget { greet(name: string): string { return `Hello, ${name}!`; } } const server = http.createServer(async (request, response) => { const url = new URL(request.url, `http://${request.headers.host}`); if (url.pathname === "/api" && request.method === "POST") { try { await nodeHttpBatchRpcResponse(request, response, new MyApiServer(), { headers: { "Access-Control-Allow-Origin": "*" } }); } catch (err) { response.writeHead(500, { "content-type": "text/plain" }); response.end(`Error: ${err}`); } return; } response.writeHead(404, { "content-type": "text/plain" }); response.end("Not found"); }); server.listen(3000, () => { console.log("Server running on port 3000"); }); ``` -------------------------------- ### Example Usage of RpcStub Source: https://github.com/cloudflare/capnweb/blob/main/_autodocs/core-types.md Demonstrates creating, duplicating, monitoring, and disposing RpcStubs. Includes defining an interface and implementation for remote API calls. ```typescript import { RpcStub, RpcTarget } from "capnweb"; interface ApiInterface { greet(name: string): string; } class ApiImpl extends RpcTarget implements ApiInterface { greet(name: string) { return `Hello, ${name}`; } } // Create a local stub for local testing const localStub = new RpcStub(new ApiImpl()); console.log(await localStub.greet("Alice")); // "Hello, Alice!" // Duplicate a stub to keep for later use const stub1 = remoteStub.dup(); const stub2 = remoteStub.dup(); // stub1 and stub2 will both be disposed when both are disposed // Monitor a stub for disconnection remoteStub.onRpcBroken((error) => { console.error("Connection lost:", error); }); // Use with explicit resource management { using stub = remoteStub.dup(); await stub.greet("Bob"); // stub is automatically disposed at end of block } ``` -------------------------------- ### RpcTarget Class Example Source: https://github.com/cloudflare/capnweb/blob/main/_autodocs/MANIFEST.txt Demonstrates the usage of the RpcTarget class, including its constructor and common use cases. ```typescript const target = new RpcTarget("my-target"); console.log(target.id); ``` -------------------------------- ### RpcStub Monitoring Example Source: https://github.com/cloudflare/capnweb/blob/main/_autodocs/MANIFEST.txt Illustrates how to monitor an RpcStub for connection breaks using the onRpcBroken method. ```typescript stub.onRpcBroken(err => { console.error("RPC broken:", err); }); ``` -------------------------------- ### HttpBatchRpcSession Pipelining Example Source: https://github.com/cloudflare/capnweb/blob/main/_autodocs/MANIFEST.txt Demonstrates message pipelining within an HTTP Batch RPC session. ```typescript const session = newHttpBatchRpcSession(transport); const result = await session.call("methodA").then(resA => session.call("methodB", [resA])); ``` -------------------------------- ### Cloudflare Workers Example for newHttpBatchRpcResponse Source: https://github.com/cloudflare/capnweb/blob/main/_autodocs/http-batch-sessions.md Demonstrates how to set up a Cloudflare Worker to handle batch RPC requests using `newHttpBatchRpcResponse`. This example shows defining an RPC interface and routing requests to it. ```typescript import { RpcTarget, newHttpBatchRpcResponse } from "capnweb"; class MyApiServer extends RpcTarget { greet(name: string): string { return `Hello, ${name}`; } add(a: number, b: number): number { return a + b; } } export default { async fetch(request: Request) { const url = new URL(request.url); if (url.pathname === "/api") { const response = await newHttpBatchRpcResponse( request, new MyApiServer() ); // Optionally set CORS headers response.headers.set("Access-Control-Allow-Origin", "*"); return response; } return new Response("Not found", { status: 404 }); } }; ``` -------------------------------- ### Database Operations: User Repository with Batch Queries Source: https://github.com/cloudflare/capnweb/blob/main/_autodocs/MANIFEST.txt Example of implementing a user repository that utilizes batch queries for efficient database operations. ```typescript // Assume 'dbClient' is an RPC client connected to a database service. interface User { id: number; name: string; email: string; } class UserRepository { constructor(private dbClient: any) {} async getUsersByIds(ids: number[]): Promise { // The database service would need to support batch operations. // This is a conceptual example of calling a batched RPC method. return this.dbClient.executeBatch({ queries: ids.map(id => ({ type: 'getUser', params: { id } })) }); } async createUser(user: Omit): Promise { // Standard single RPC call for creating a user. return this.dbClient.createUser(user); } } ``` -------------------------------- ### Workers RPC Endpoint Example Source: https://github.com/cloudflare/capnweb/blob/main/_autodocs/websocket-sessions.md This example demonstrates how to set up a Cloudflare Worker to handle incoming requests, distinguishing between standard HTTP requests and WebSocket upgrade requests for RPC communication. ```typescript import { RpcTarget, newWorkersWebSocketRpcResponse } from "capnweb"; class ApiServer extends RpcTarget { greet(name: string): string { return `Hello, ${name}!`; } getStatus(): { ready: boolean } { return { ready: true }; } } export default { fetch(request: Request) { const url = new URL(request.url); if (url.pathname === "/api") { // Handles both HTTP batch (POST) and WebSocket (upgrade) if (request.headers.get("Upgrade")?.toLowerCase() === "websocket") { return newWorkersWebSocketRpcResponse(request, new ApiServer()); } } return new Response("Not found", { status: 404 }); } }; ``` -------------------------------- ### Cap'nweb RPC Example with Pipelining and Map Source: https://github.com/cloudflare/capnweb/blob/main/_autodocs/core-types.md Demonstrates using RpcPromise for pipelined RPC calls, property access, method invocation, and the map() function for server-side array transformations. ```typescript import { newHttpBatchRpcSession } from "capnweb"; interface UserApi { authenticate(token: string): AuthedApi; getUserProfile(id: number): UserProfile; } interface AuthedApi { getUserId(): number; getFriendIds(): number[]; } type UserProfile = { name: string }; // HTTP Batch: Make pipelined calls in one round trip const api = newHttpBatchRpcSession("https://api.example.com"); // Authenticate but don't await (pipelining) const authedPromise = api.authenticate("token123"); // Use the promise in another call before it's resolved const userIdPromise = authedPromise.getUserId(); const profilePromise = api.getUserProfile(userIdPromise); // Batch is sent here, all results received in one round trip const profile = await profilePromise; console.log(`Hello, ${profile.name}! `); // Using map() for arrays const friendIds = await authedPromise.getFriendIds(); const friendProfiles = await friendIds.map(id => api.getUserProfile(id) ); // All profiles fetched in one round trip! // With explicit resource management { using stub = api.authenticate("token"); console.log(await stub.getUserId()); // Promise is automatically disposed at block end } ``` -------------------------------- ### MessagePortRpcSession Web Worker Example Source: https://github.com/cloudflare/capnweb/blob/main/_autodocs/MANIFEST.txt Illustrates using MessagePort RPC for communication with a web worker. ```typescript const worker = new Worker("worker.js"); const session = newMessagePortRpcSession(worker.port, { // ... options ... }); ``` -------------------------------- ### Unstubify Type Transformation Example Source: https://github.com/cloudflare/capnweb/blob/main/_autodocs/MANIFEST.txt Shows the Unstubify type utility for reversing the Stubify transformation. ```typescript interface MyApiStub { add(a: number, b: number): RpcPromise; } type MyApi = Unstubify; // { add(a: number, b: number): number } ``` -------------------------------- ### newBunWebSocketRpcSession() Custom Handler Example Source: https://github.com/cloudflare/capnweb/blob/main/_autodocs/MANIFEST.txt Using the lower-level newBunWebSocketRpcSession API with custom handlers for more control. ```typescript const session = newBunWebSocketRpcSession(ws, { onMessage: async (message) => { /* handle message */ }, onClose: async () => { /* handle close */ } }); ``` -------------------------------- ### Real-time Updates: Server Callbacks (Chat Application) Source: https://github.com/cloudflare/capnweb/blob/main/_autodocs/MANIFEST.txt Example of implementing real-time updates using server callbacks, suitable for a chat application. ```typescript // Assume 'chatService' is an RPC client connected to a chat service. interface ChatService { joinRoom(roomId: string): Promise; sendMessage(roomId: string, message: string): Promise; // Server-side callback definition onMessage(callback: (roomId: string, message: string) => void): void; } async function setupChatClient(chatService: ChatService) { await chatService.joinRoom('general'); chatService.onMessage((roomId, message) => { console.log(`[${roomId}] New message: ${message}`); }); // Simulate sending a message after a delay setTimeout(() => { chatService.sendMessage('general', 'Hello everyone!'); }, 2000); } ``` -------------------------------- ### Promise Pipelining Example Source: https://github.com/cloudflare/capnweb/blob/main/_autodocs/promise-pipelining.md Illustrates how un-awaited promises are handled in property paths for sequential API calls. This pseudocode shows the client-side calls and the server's execution flow. ```typescript // Python-like pseudocode showing what gets sent: api.authenticate("token") // ["call", 1, [], ["authenticate", ["token"]]] .getUserId() // ["call", 2, [1], ["getUserId", []]] .then(id => api.getProfile(id) // ["call", 3, [], ["getProfile", [["ref", 2]]]] ) // Server processes: // 1. execute call 1: authenticate("token") -> returns stub // 2. execute call 2: call getUserId on result of 1 -> returns ID // 3. execute call 3: getProfile(ID) -> returns profile // 4. return profile ``` -------------------------------- ### HttpBatchRpcSession Disposal Example Source: https://github.com/cloudflare/capnweb/blob/main/_autodocs/MANIFEST.txt Shows how to properly dispose of an HTTP Batch RPC session to release resources. ```typescript const session = newHttpBatchRpcSession(transport); // ... use session ... session[Symbol.dispose](); ``` -------------------------------- ### Stream Transport Usage Example Source: https://github.com/cloudflare/capnweb/blob/main/_autodocs/custom-transports.md Demonstrates how to use the StreamRpcTransport with a pipe pair for client and server communication. Sets up a simple RPC API and makes a remote call. ```typescript // Usage with pipe pair const { PassThrough } = require("stream"); const serverInput = new PassThrough(); const serverOutput = new PassThrough(); const clientInput = serverOutput; const clientOutput = serverInput; class MyApi extends RpcTarget { hello(): string { return "Hello from server!"; } } // Server side const serverTransport = new StreamRpcTransport(serverInput, serverOutput); const serverSession = new RpcSession(serverTransport, new MyApi()); // Client side const clientTransport = new StreamRpcTransport(clientInput, clientOutput); const clientSession = new RpcSession(clientTransport); const stub = clientSession.getRemoteMain(); // Make call stub.hello().then(result => { console.log(result); }); ``` -------------------------------- ### Promise Pipelining Nested Access Example Source: https://github.com/cloudflare/capnweb/blob/main/_autodocs/MANIFEST.txt Demonstrates accessing nested properties through promise pipelining in RPC calls. ```typescript const postTitle = await session.call("getUser", [userId]).user.profile.name; ``` -------------------------------- ### Implementing RpcTarget for RPC Source: https://github.com/cloudflare/capnweb/blob/main/_autodocs/core-types.md Example of creating a class that extends RpcTarget to expose methods over RPC. Private methods using '#' are not exposed. ```typescript import { RpcTarget } from "capnweb"; class MyApi extends RpcTarget { greeting(name: string): string { return `Hello, ${name}`; } // This method will be exposed over RPC getStatus(): { ready: boolean } { return { ready: true }; } // Private methods (use # prefix to hide from RPC) #secretMethod() { // Not accessible via RPC } // Optional: Clean up when disposed [Symbol.dispose]() { console.log("Stub was disposed"); } } ``` -------------------------------- ### Unstubify Examples Source: https://github.com/cloudflare/capnweb/blob/main/_autodocs/types-and-compatibility.md Demonstrates how Unstubify unwraps different stubbed types. It handles direct stubs, arrays of stubs, and promises containing stubs. ```typescript // Stub unwraps to original type Unstubified = Unstubify>; // Result: MyClass // Arrays recursively unwrapped type UnstubifiedArray = Unstubify[]>; // Result: MyClass[] // Promises accepted or unwrapped type UnstubifiedPromise = Unstubify>>; // Result: MyClass ``` -------------------------------- ### Zero-Boilerplate Bun WebSocket RPC Server Source: https://github.com/cloudflare/capnweb/blob/main/_autodocs/bun-websocket-sessions.md An example of a basic Bun WebSocket RPC server using `newBunWebSocketRpcHandler`. It handles both WebSocket upgrades and HTTP batch requests. ```typescript import { RpcTarget, newBunWebSocketRpcHandler, newHttpBatchRpcResponse } from "capnweb"; class MyApiImpl extends RpcTarget { greet(name: string): string { return `Hello, ${name}`; } getStatus(): { ready: boolean } { return { ready: true }; } } // Create WebSocket handler (new instance per connection) const wsHandler = newBunWebSocketRpcHandler(() => new MyApiImpl()); Bun.serve({ port: 3000, async fetch(req, server) { const url = new URL(req.url); if (url.pathname === "/api") { // Handle WebSocket upgrade if (req.headers.get("upgrade")?.toLowerCase() === "websocket") { if (server.upgrade(req)) return; return new Response("WebSocket upgrade failed", { status: 500 }); } // Handle HTTP batch const response = await newHttpBatchRpcResponse(req, new MyApiImpl()); response.headers.set("Access-Control-Allow-Origin", "*"); return response; } return new Response("Not found", { status: 404 }); }, // Pass the handler directly websocket: wsHandler, }); ``` -------------------------------- ### Server Usage with @validateRpc Source: https://github.com/cloudflare/capnweb/blob/main/packages/capnweb-validate/README.md Example of using the @validateRpc decorator on a service class for runtime validation. This setup is compatible with Cap'n Web, Workers WorkerEntrypoint, and DurableObject services. ```ts import { newWorkersRpcResponse, RpcTarget } from "capnweb"; import { validateRpc } from "capnweb-validate"; type User = { id: string; name: string }; @validateRpc() export class Api extends RpcTarget { async authenticate(sessionToken: string): Promise { // ... } } export default { async fetch(request: Request, env: Env) { return newWorkersRpcResponse(request, new Api()); }, }; ``` -------------------------------- ### Client-Side WebSocket Session Example Source: https://github.com/cloudflare/capnweb/blob/main/_autodocs/websocket-sessions.md Demonstrates connecting to a WebSocket RPC server, making independent calls, and handling callbacks. The session is automatically closed when the 'using' scope ends. ```typescript import { newWebSocketRpcSession } from "capnweb"; interface ServerApi { greet(name: string): string; getStatus(): { ready: boolean }; subscribe(onUpdate: (data: string) => void): () => void; } // Connect to WebSocket server using api = newWebSocketRpcSession("wss://api.example.com/rpc"); // Make calls independently const greeting = await api.greet("Alice"); console.log(greeting); // Make another call later const status = await api.getStatus(); console.log(status); // Server can call back to client (if client exposes main interface) // Connection is automatically closed when `api` goes out of scope (using declaration) ``` -------------------------------- ### newWorkersWebSocketRpcResponse() Example Source: https://github.com/cloudflare/capnweb/blob/main/_autodocs/MANIFEST.txt Example for handling WebSocket RPC requests in Cloudflare Workers using newWorkersWebSocketRpcResponse. ```typescript export const onRequest = [newWorkersWebSocketRpcResponse(async (ws) => { // Handle WebSocket connection })]; ``` -------------------------------- ### Server Calling Client Example Source: https://github.com/cloudflare/capnweb/blob/main/_autodocs/websocket-sessions.md Shows how a server can initiate calls back to the client by exposing a main interface from the client. The client's exposed interface methods can be invoked by the server. ```typescript // Client-side import { RpcTarget, newWebSocketRpcSession } from "capnweb"; class ClientCallbacks extends RpcTarget { onServerUpdate(message: string) { console.log("Server says:", message); } } using api = newWebSocketRpcSession( "wss://api.example.com/rpc", new ClientCallbacks() // Expose this to server ); // Server can now call methods on ClientCallbacks const greeting = await api.greet("Alice"); ``` -------------------------------- ### Testing: Mock Server for Unit Tests Source: https://github.com/cloudflare/capnweb/blob/main/_autodocs/MANIFEST.txt Shows how to create a mock RPC server for unit testing client logic. ```typescript import { RpcTransport, RpcSession } from '@capnp/core'; // Mock Transport implementation class MockTransport implements RpcTransport { private receivedMessages: Uint8Array[] = []; private sentMessages: Uint8Array[] = []; async send(message: Uint8Array): Promise { this.sentMessages.push(message); } async receive(): Promise { if (this.receivedMessages.length === 0) { throw new Error('No message available'); } return this.receivedMessages.shift()!; } async abort(): Promise {} // Helper methods for testing addIncomingMessage(message: Uint8Array) { this.receivedMessages.push(message); } getSentMessages(): Uint8Array[] { return this.sentMessages; } } // --- Test Code --- async function testClientMethod() { const mockTransport = new MockTransport(); const session = new RpcSession(mockTransport, {}); // Use appropriate options // Mock the server's response const mockResponse = new Uint8Array(/* serialized mock response */); mockTransport.addIncomingMessage(mockResponse); // Call a method on the client stub // const result = await session.callMethod(...); // Assertions // expect(mockTransport.getSentMessages()).toEqual([...]); // expect(result).toEqual(...); } ``` -------------------------------- ### Implement RPC Interface on Server Source: https://github.com/cloudflare/capnweb/blob/main/README.md Shows how to implement the defined RPC interface on the server-side using Cap'n'Web's RpcTarget. This example includes the basic structure for a server that can handle RPC requests. ```typescript import { newWorkersRpcResponse, RpcTarget } from "capnweb"; class ApiServer extends RpcTarget implements PublicApi { // ... implement PublicApi ... } export default { async fetch(req, env, ctx) { // ... same as previous example ... } } ``` -------------------------------- ### Example: Transport-Specific Timeout Option Source: https://github.com/cloudflare/capnweb/blob/main/_autodocs/http-batch-sessions.md Illustrates how a transport implementation might accept custom options, such as a timeout, when creating an HttpBatchRpcSession. Note that this specific option is an example and not part of the standard interface. ```typescript // Example: Some transport might accept timeout options const session = newHttpBatchRpcSession(url, { // timeout: 30000, // Example, not standard }); ``` -------------------------------- ### Parent Window with Single Iframe RPC Setup Source: https://github.com/cloudflare/capnweb/blob/main/_autodocs/messageport-sessions.md Sets up a MessagePort RPC session between a parent window and a single iframe. The parent creates a MessageChannel and sends one port to the iframe, retaining the other for communication. ```typescript // Parent const channel = new MessageChannel(); const iframe = document.querySelector("iframe"); iframe.contentWindow.postMessage({ port: channel.port2 }, "*", [channel.port2]); using api = newMessagePortRpcSession(channel.port1, parentApi); // Iframe window.addEventListener("message", (e) => { if (e.data.port) { using api = newMessagePortRpcSession(e.data.port, iframeApi); } }); ``` -------------------------------- ### Type Injection Attack Example Source: https://github.com/cloudflare/capnweb/blob/main/_autodocs/MANIFEST.txt Illustrates a type injection vulnerability and its mitigation. ```typescript // Vulnerable code example (simplified): function processRequest(data: any) { // If 'data.type' can be controlled by an attacker, they might inject // malicious types or functions. const handler = getHandlerForType(data.type); handler(data.payload); } // Mitigation: Use a strict mapping or allowlist for types. const allowedHandlers: { [key: string]: Function } = { 'user_data': handleUserData, 'system_log': handleSystemLog }; function processRequestMitigated(data: { type: string, payload: any }) { const handler = allowedHandlers[data.type]; if (!handler) { throw new Error('Invalid type specified'); } handler(data.payload); } ``` -------------------------------- ### Classes and Interfaces Source: https://github.com/cloudflare/capnweb/blob/main/_autodocs/MANIFEST.txt Detailed documentation for key classes and interfaces within the Cap'n Proto RPC system, including their constructors and methods. ```APIDOC ## Classes and Interfaces Detailed documentation for key classes and interfaces within the Cap'n Proto RPC system, including their constructors and methods. ### `RpcTarget` class Represents a remote endpoint for RPC communication. Provides methods for interacting with remote services. ### `RpcStub` class Represents a client-side proxy for a remote service. Its constructor and methods allow for invoking remote procedures. ### `RpcPromise` (thenable, properties) An object that conforms to the thenable protocol, representing the eventual result of an RPC operation. It includes properties for managing the RPC call's state and lifecycle. ### `RpcSession` class Manages the lifecycle and communication for an RPC session. Handles connection management, message routing, and error propagation. ### `RpcTransport` interface Defines the contract for transport mechanisms used by `RpcSession`. Implementations handle the low-level sending and receiving of data. ### `BunWebSocketTransport` class An implementation of `RpcTransport` specifically for WebSocket connections using the Bun runtime. ### `WebSocketTransport` class An implementation of `RpcTransport` for standard WebSocket connections. ### `MessagePortTransport` class An implementation of `RpcTransport` utilizing `MessagePort` for inter-process or inter-worker communication. ### `BatchClientTransport` class Handles batched RPC requests on the client side, typically over HTTP. ### `BatchServerTransport` class Handles batched RPC requests on the server side, typically over HTTP. ``` -------------------------------- ### Automatic Stub Disposal Source: https://github.com/cloudflare/capnweb/blob/main/_autodocs/MANIFEST.txt Explains automatic stub disposal rules with examples. ```typescript import { RpcTarget } from '@capnp/core'; // Assume 'rpcTarget' is an instance of RpcTarget // Rule 1: Stubs are automatically disposed when the parent RpcTarget is disposed. const parentTarget = new RpcTarget(); const childStub = parentTarget.createStub(); // When parentTarget is disposed, childStub will also be disposed. parentTarget[Symbol.dispose](); // Rule 2: RpcPromises are automatically disposed when they resolve or reject. const promise = new RpcPromise(async (resolve) => { setTimeout(() => resolve(42), 100); }); promise.then(result => { // promise is now disposed }); // Rule 3: Stubs created from RpcPromises are disposed when the promise settles. const stubFromPromise = parentTarget.createStub(promise); promise.then(() => { // stubFromPromise is now disposed }); ``` -------------------------------- ### Download with Progress Source: https://github.com/cloudflare/capnweb/blob/main/_autodocs/MANIFEST.txt Demonstrates how to download a file with a progress indicator using streams. ```typescript async function downloadWithProgress(url: string, destination: string) { const response = await fetch(url); if (!response.ok) { throw new Error(`HTTP error! status: ${response.status}`); } const totalBytes = response.headers.get('content-length'); if (!totalBytes) { console.warn('Content-Length header missing, progress cannot be shown.'); } const fileStream = fs.createWriteStream(destination); const reader = response.body!.getReader(); let receivedBytes = 0; while (true) { const { done, value } = await reader.read(); if (done) { break; } fileStream.write(value); receivedBytes += value.length; if (totalBytes) { const percentComplete = Math.round((receivedBytes / parseInt(totalBytes)) * 100); console.log(`Downloaded: ${percentComplete}%`); } else { console.log(`Downloaded: ${receivedBytes} bytes`); } } fileStream.end(); console.log('Download complete!'); } ``` -------------------------------- ### Pipelining Over WebSocket Example Source: https://github.com/cloudflare/capnweb/blob/main/_autodocs/websocket-sessions.md Illustrates making multiple RPC calls in a single round trip using promise pipelining over a WebSocket connection. Subsequent calls can be made on new round trips. ```typescript import { newWebSocketRpcSession } from "capnweb"; interface UserApi { authenticate(token: string): AuthedApi; } interface AuthedApi { getUserId(): number; getFriendIds(): number[]; } using api = newWebSocketRpcSession("wss://api.example.com/rpc"); // Make pipelined calls in one round trip using authed = api.authenticate("token123"); const userId = await authed.getUserId(); const friendIds = await authed.getFriendIds(); console.log(`User ID: ${userId}`); console.log(`Friend IDs: ${friendIds}`); // Make more calls on new round trip (WebSocket allows this anytime) const status = await api.authenticate("token456").getStatus?.(); ``` -------------------------------- ### RpcPromise map() Example Source: https://github.com/cloudflare/capnweb/blob/main/_autodocs/MANIFEST.txt Demonstrates using the map() method on an RpcPromise to transform array results. ```typescript const promise = RpcPromise.resolve([1, 2, 3]); const mappedPromise = promise.map(x => x * 2); mappedPromise.then(result => console.log(result)); // [2, 4, 6] ``` -------------------------------- ### Denial of Service Vector: Stream Amplification Source: https://github.com/cloudflare/capnweb/blob/main/_autodocs/MANIFEST.txt Example of a stream amplification DoS vector and mitigation strategy. ```typescript // Vulnerable scenario: A small initial stream message causes the server // to send a much larger stream of data back. // Mitigation: Limit the amount of data that can be sent in response to a // specific stream initiation or control message. Monitor stream sizes. ``` -------------------------------- ### Deno HTTP Server with WebSockets Source: https://github.com/cloudflare/capnweb/blob/main/README.md Implement an HTTP server on Deno that handles both batch HTTP and WebSocket requests using `newHttpBatchRpcResponse` and `newWebSocketRpcSession`. This example leverages Deno's built-in `Deno.serve` and `Deno.upgradeWebSocket`. ```typescript import { newHttpBatchRpcResponse, newWebSocketRpcSession, RpcTarget, } from "npm:capnweb"; // This is the server implementation. class MyApiImpl extends RpcTarget implements MyApi { // ... define API, same as above ... } Deno.serve(async (req) => { const url = new URL(req.url); if (url.pathname === "/api") { if (req.headers.get("upgrade") === "websocket") { const { socket, response } = Deno.upgradeWebSocket(req); socket.addEventListener("open", () => { newWebSocketRpcSession(socket, new MyApiImpl()); }); return response; } else { const response = await newHttpBatchRpcResponse(req, new MyApiImpl()); // If you are accepting WebSockets, then you might as well accept cross-origin HTTP, since // WebSockets always permit cross-origin request anyway. But, see security considerations // for further discussion. response.headers.set("Access-Control-Allow-Origin", "*"); return response; } } return new Response("Not Found", { status: 404 }); }); ``` -------------------------------- ### Denial of Service Vector: Request Amplification Source: https://github.com/cloudflare/capnweb/blob/main/_autodocs/MANIFEST.txt Example of a request amplification DoS vector and mitigation strategy. ```typescript // Vulnerable scenario: A small request triggers a large response. // Attacker sends many small requests to overwhelm the server with large responses. // Mitigation: Implement rate limiting on incoming requests and potentially // limit the size of responses that can be triggered by a single request. ``` -------------------------------- ### Basic HTTP Batch Session Usage Source: https://github.com/cloudflare/capnweb/blob/main/_autodocs/http-batch-sessions.md Demonstrates how to create an HTTP batch session and make multiple RPC calls. The calls are buffered and sent in a single batch when results are awaited. ```typescript import { newHttpBatchRpcSession } from "capnweb"; interface MyApi { greet(name: string): string; add(a: number, b: number): number; } // Create a batch session const stub = newHttpBatchRpcSession("https://api.example.com/rpc"); // Make calls (they are buffered) const greetPromise = stub.greet("Alice"); const sumPromise = stub.add(5, 3); // Await results (triggers batch send) const greeting = await greetPromise; const sum = await sumPromise; console.log(greeting); // "Hello, Alice!" console.log(sum); // 8 ``` -------------------------------- ### Real-time Pipeline Source: https://github.com/cloudflare/capnweb/blob/main/_autodocs/MANIFEST.txt Demonstrates creating a real-time data processing pipeline using streams. ```typescript async function realTimePipeline(sourceUrl: string, sinkUrl: string) { const sourceResponse = await fetch(sourceUrl); if (!sourceResponse.ok) { throw new Error(`Source HTTP error! status: ${sourceResponse.ok}`); } const sinkResponse = await fetch(sinkUrl, { method: 'POST', headers: { 'Content-Type': 'application/octet-stream' } }); if (!sinkResponse.ok) { throw new Error(`Sink HTTP error! status: ${sinkResponse.ok}`); } const sourceReader = sourceResponse.body!.getReader(); const sinkWriter = sinkResponse.getWriter(); while (true) { const { done, value } = await sourceReader.read(); if (done) { break; } // Process the data chunk (e.g., transform, filter) const processedChunk = processData(value); await sinkWriter.write(processedChunk); } sinkWriter.close(); console.log('Pipeline finished.'); } function processData(chunk: Uint8Array): Uint8Array { // Placeholder for data processing logic return chunk; } ``` -------------------------------- ### Stubify Type Transformation Example Source: https://github.com/cloudflare/capnweb/blob/main/_autodocs/MANIFEST.txt Demonstrates the Stubify type utility for transforming an API into a stub interface. ```typescript interface MyApi { add(a: number, b: number): number; } type MyApiStub = Stubify; // { add: (a: number, b: number) => RpcPromise } ``` -------------------------------- ### newWorkersRpcResponse() Unified Handler Example Source: https://github.com/cloudflare/capnweb/blob/main/_autodocs/MANIFEST.txt Demonstrates a unified handler for both HTTP and WebSocket RPC in Cloudflare Workers. ```typescript export const onRequest = newWorkersRpcResponse(async (requestOrWs) => { // Handle request or WebSocket }); ``` -------------------------------- ### Mock Server for Unit Tests Source: https://github.com/cloudflare/capnweb/blob/main/_autodocs/examples.md Set up a mock server using `MessageChannel` for unit testing Capnweb RPC services. This allows testing client-side logic without a live server. ```typescript import { newMessagePortRpcSession, RpcTarget, RpcStub } from "capnweb"; interface Api extends RpcTarget { greet(name: string): string; add(a: number, b: number): number; } class MockApi extends RpcTarget implements Api { greet(name: string): string { return `Hello, ${name}!`; } add(a: number, b: number): number { return a + b; } } describe("MyComponent", () => { let api: RpcStub; beforeEach(() => { const channel = new MessageChannel(); // Server side newMessagePortRpcSession(channel.port1, new MockApi()); // Client side api = newMessagePortRpcSession(channel.port2); }); it("calls greet correctly", async () => { const result = await api.greet("World"); expect(result).toBe("Hello, World!"); }); it("calls add correctly", async () => { const result = await api.add(5, 3); expect(result).toBe(8); }); }); ```