capnweb 0.0.0-03c82e8 → 0.0.0-0b20ec6

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/README.md CHANGED
@@ -6,7 +6,7 @@ Cap'n Web is a spiritual sibling to [Cap'n Proto](https://capnproto.org) (and is
6
6
  * That said, it integrates nicely with TypeScript.
7
7
  * Also unlike Cap'n Proto, Cap'n Web's underlying serialization is human-readable. In fact, it's just JSON, with a little pre-/post-processing.
8
8
  * It works over HTTP, WebSocket, and postMessage() out-of-the-box, with the ability to extend it to other transports easily.
9
- * It works in all major browsers, Cloudflare Workers, Node.js, and other modern JavaScript runtimes.
9
+ * It works in all major browsers, Cloudflare Workers, Node.js, Bun, Deno, and other modern JavaScript runtimes.
10
10
  The whole thing compresses (minify+gzip) to under 10kB with no dependencies.
11
11
 
12
12
  Cap'n Web is more expressive than almost every other RPC system, because it implements an object-capability RPC model. That means it:
@@ -201,6 +201,7 @@ The following types can be passed over RPC (in arguments or return values), and
201
201
  * `Date`
202
202
  * `Uint8Array`
203
203
  * `Error` and its well-known subclasses
204
+ * `Blob`
204
205
  * `ReadableStream` and `WritableStream`, with automatic flow control.
205
206
  * `Headers`, `Request`, and `Response` from the Fetch API.
206
207
 
@@ -404,6 +405,8 @@ If anything happens to the stub that would cause all further method calls and pr
404
405
 
405
406
  * Cap'n Web's pipelining can make it easy for a malicious client to enqueue a large amount of work to occur on a server. To mitigate this, we recommend implementing rate limits on expensive operations. If using Cloudflare Workers, you may also consider configuring [per-request CPU limits](https://developers.cloudflare.com/workers/wrangler/configuration/#limits) to be lower than the default 30s. Note that in stateless Workers (i.e. not Durable Objects), the system considers an entire WebSocket session to be one "request" for CPU limits purposes.
406
407
 
408
+ * Cap'n Web applies receiver-side resource limits before expensive message processing, including a maximum incoming message size before `JSON.parse`. If your app is exposed to untrusted peers, also configure native transport or socket payload limits where available, such as `ws`'s `maxPayload`, Bun's `maxPayloadLength`, or the runtime's built-in WebSocket cap. Cap'n Web's own check runs after `RpcTransport.receive()` has returned a complete message string, so transport-level limits are still the first line of defense against buffering very large frames.
409
+
407
410
  * Cap'n Web currently does not provide any runtime type checking. When using TypeScript, keep in mind that types are checked only at compile time. A malicious client can send types you did not expect, and this could cause you application to behave in unexpected ways. For example, MongoDB uses special property names to express queries; placing attacker-provided values directly into queries can result in query injection vulnerabilities (similar to SQL injection). Of course, JSON has always had the same problem, and there exists tooling to solve it. You might consider using a runtime type-checking framework like Zod to check your inputs. In the future, we hope to explore auto-generating type-checking code based on TypeScript types.
408
411
 
409
412
  ## Setting up a session
@@ -630,6 +633,45 @@ Deno.serve(async (req) => {
630
633
  });
631
634
  ```
632
635
 
636
+ ### HTTP server on Bun
637
+
638
+ Bun's server-side WebSocket API uses [callback-based handlers](https://bun.sh/docs/runtime/http/websockets) instead of the standard `addEventListener` interface. Cap'n Web provides `newBunWebSocketRpcHandler()` which returns a handler object you can pass directly to `Bun.serve()`.
639
+
640
+ ```ts
641
+ import { RpcTarget, newBunWebSocketRpcHandler, newHttpBatchRpcResponse } from "capnweb";
642
+
643
+ class MyApiImpl extends RpcTarget implements MyApi {
644
+ // ... define API, same as above ...
645
+ }
646
+
647
+ // Create a WebSocket handler that manages RPC sessions automatically.
648
+ // The callback is invoked once per connection to create a fresh API instance.
649
+ let rpcHandler = newBunWebSocketRpcHandler(() => new MyApiImpl());
650
+
651
+ Bun.serve({
652
+ async fetch(req, server) {
653
+ let url = new URL(req.url);
654
+ if (url.pathname === "/api") {
655
+ // Upgrade WebSocket requests.
656
+ if (req.headers.get("upgrade")?.toLowerCase() === "websocket") {
657
+ if (server.upgrade(req)) return;
658
+ return new Response("WebSocket upgrade failed", { status: 500 });
659
+ }
660
+
661
+ // Handle HTTP batch requests.
662
+ let response = await newHttpBatchRpcResponse(req, new MyApiImpl());
663
+ response.headers.set("Access-Control-Allow-Origin", "*");
664
+ return response;
665
+ }
666
+
667
+ return new Response("Not Found", { status: 404 });
668
+ },
669
+
670
+ // Pass the handler directly — no manual wiring needed.
671
+ websocket: rpcHandler,
672
+ });
673
+ ```
674
+
633
675
  ### HTTP server on other runtimes
634
676
 
635
677
  Every runtime does HTTP handling and WebSockets a little differently, although most modern runtimes use the standard `Request` and `Response` types from the Fetch API, as well as the standard `WebSocket` API. You should be able to use these two functions (exported by `capnweb`) to implement both HTTP batch and WebSocket handling on all platforms:
@@ -736,3 +778,10 @@ let stub: RemoteMainInterface = session.getRemoteMain();
736
778
  ```
737
779
 
738
780
  Note that sessions are entirely symmetric: neither side is defined as the "client" nor the "server". Each side can optionally expose a "main interface" to the other. In typical scenarios with a logical client and server, the server exposes a main interface but the client does not.
781
+
782
+ By default, `send()` accepts a string, and `receive()` returns a string, with Cap'n Web handling the encoding all the way to and from strings. However, transports that want more control over the serialization can declare the property `encodingLevel` to control how much encoding Cap'n Web does before passing off the message:
783
+
784
+ * `"string"` (default): Full JSON round-trip. The transport deals in strings only. Cap'n Web handles all encoding/decoding. This is what HTTP batch and WebSocket transports use.
785
+ * `"jsonCompatible"`: The transport works with JavaScript value trees, but they must be JSON-compatible. Cap'n Web still encodes special types, but skips the final `JSON.stringify`. The transport is responsible for serialization (e.g. to CBOR, MessagePack).
786
+ * `"jsonCompatibleWithBytes"`: Like `"jsonCompatible"` except that byte arrays are left as `Uint8Array` instead of base64-encoded, avoiding the ~33% base64 size overhead and the encode/decode CPU cost. Handy for use with serializations like CBOR or MessagePack that support this efficiently.
787
+ * `"structuredClonable"`: Messages are structured-clonable values. Cap'n Web passes through native structured-clone types where possible, while still handling RPC-specific values such as stubs. This is useful when the transport is a `MessagePort` or similar.