kkrpc 0.6.0 → 0.6.1

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.
Files changed (153) hide show
  1. package/README.md +682 -166
  2. package/dist/browser-mod.cjs +1 -1
  3. package/dist/browser-mod.d.cts +14 -6
  4. package/dist/browser-mod.d.cts.map +1 -1
  5. package/dist/browser-mod.d.ts +16 -8
  6. package/dist/browser-mod.d.ts.map +1 -1
  7. package/dist/browser-mod.js +1 -1
  8. package/dist/browser-mod.js.map +1 -1
  9. package/dist/{channel-C92Q3vK-.d.ts → channel-ChGarSnI.d.cts} +6 -2
  10. package/dist/channel-ChGarSnI.d.cts.map +1 -0
  11. package/dist/{channel-QTVxXCE5.d.cts → channel-K9w_2vmv.d.ts} +6 -2
  12. package/dist/channel-K9w_2vmv.d.ts.map +1 -0
  13. package/dist/{channel-BYtPphRu.js → channel-LGw9tl8f.js} +3 -3
  14. package/dist/channel-LGw9tl8f.js.map +1 -0
  15. package/dist/{channel-D3yeLUXA.cjs → channel-OGNDLfsd.cjs} +2 -2
  16. package/dist/chrome-extension.cjs +1 -1
  17. package/dist/chrome-extension.d.cts +8 -4
  18. package/dist/chrome-extension.d.cts.map +1 -1
  19. package/dist/chrome-extension.d.ts +9 -5
  20. package/dist/chrome-extension.d.ts.map +1 -1
  21. package/dist/chrome-extension.js +1 -1
  22. package/dist/chrome-extension.js.map +1 -1
  23. package/dist/deno-B319Kxci.js +2 -0
  24. package/dist/deno-B319Kxci.js.map +1 -0
  25. package/dist/{deno-noilmrf7.d.cts → deno-BNN8LLrd.d.cts} +6 -2
  26. package/dist/deno-BNN8LLrd.d.cts.map +1 -0
  27. package/dist/deno-Cl_O9sLW.cjs +1 -0
  28. package/dist/{deno-BzNLlX8S.d.ts → deno-DS3TcO_u.d.ts} +6 -2
  29. package/dist/deno-DS3TcO_u.d.ts.map +1 -0
  30. package/dist/deno-mod.cjs +1 -1
  31. package/dist/deno-mod.d.cts +3 -3
  32. package/dist/deno-mod.d.ts +4 -4
  33. package/dist/deno-mod.js +1 -1
  34. package/dist/electron-ipc.cjs +1 -0
  35. package/dist/electron-ipc.d.cts +142 -0
  36. package/dist/electron-ipc.d.cts.map +1 -0
  37. package/dist/electron-ipc.d.ts +142 -0
  38. package/dist/electron-ipc.d.ts.map +1 -0
  39. package/dist/electron-ipc.js +2 -0
  40. package/dist/electron-ipc.js.map +1 -0
  41. package/dist/electron.cjs +1 -0
  42. package/dist/electron.d.cts +69 -0
  43. package/dist/electron.d.cts.map +1 -0
  44. package/dist/electron.d.ts +69 -0
  45. package/dist/electron.d.ts.map +1 -0
  46. package/dist/electron.js +2 -0
  47. package/dist/electron.js.map +1 -0
  48. package/dist/http-BEp3rEW8.js +2 -0
  49. package/dist/http-BEp3rEW8.js.map +1 -0
  50. package/dist/{http-Cvnz7K2R.d.cts → http-CcLOuQmc.d.ts} +12 -2
  51. package/dist/http-CcLOuQmc.d.ts.map +1 -0
  52. package/dist/{http-xFcyKRFw.d.ts → http-DWq6Ez_h.d.cts} +12 -2
  53. package/dist/http-DWq6Ez_h.d.cts.map +1 -0
  54. package/dist/http-DoUu8nzZ.cjs +1 -0
  55. package/dist/http.cjs +1 -1
  56. package/dist/http.d.cts +3 -3
  57. package/dist/http.d.ts +3 -3
  58. package/dist/http.js +1 -1
  59. package/dist/{interface-DIWzRMw1.d.cts → interface-DPtHJBBS.d.cts} +9 -10
  60. package/dist/interface-DPtHJBBS.d.cts.map +1 -0
  61. package/dist/{interface-Bt8kzlyu.d.ts → interface-DRqrAKo-.d.ts} +9 -10
  62. package/dist/interface-DRqrAKo-.d.ts.map +1 -0
  63. package/dist/kafka-BMOHF0lZ.d.ts +98 -0
  64. package/dist/kafka-BMOHF0lZ.d.ts.map +1 -0
  65. package/dist/kafka-DrhWN0Wx.js +2 -0
  66. package/dist/kafka-DrhWN0Wx.js.map +1 -0
  67. package/dist/kafka-_Fcc7erL.d.cts +98 -0
  68. package/dist/kafka-_Fcc7erL.d.cts.map +1 -0
  69. package/dist/kafka-x0zuIRyy.cjs +1 -0
  70. package/dist/kafka.cjs +1 -0
  71. package/dist/kafka.d.cts +3 -0
  72. package/dist/kafka.d.ts +3 -0
  73. package/dist/kafka.js +1 -0
  74. package/dist/mod.cjs +2 -2
  75. package/dist/mod.d.cts +82 -15
  76. package/dist/mod.d.cts.map +1 -1
  77. package/dist/mod.d.ts +84 -17
  78. package/dist/mod.d.ts.map +1 -1
  79. package/dist/mod.js +2 -2
  80. package/dist/mod.js.map +1 -1
  81. package/dist/nats-Ba4bXoY5.js +2 -0
  82. package/dist/nats-Ba4bXoY5.js.map +1 -0
  83. package/dist/nats-Bkr44tQB.d.cts +78 -0
  84. package/dist/nats-Bkr44tQB.d.cts.map +1 -0
  85. package/dist/nats-CMglzmZn.cjs +1 -0
  86. package/dist/nats-D3XOZAGl.d.ts +78 -0
  87. package/dist/nats-D3XOZAGl.d.ts.map +1 -0
  88. package/dist/nats.cjs +1 -0
  89. package/dist/nats.d.cts +3 -0
  90. package/dist/nats.d.ts +3 -0
  91. package/dist/nats.js +1 -0
  92. package/dist/rabbitmq-B5NVNJ3X.cjs +1 -0
  93. package/dist/rabbitmq-CpeO6XdQ.d.ts +61 -0
  94. package/dist/rabbitmq-CpeO6XdQ.d.ts.map +1 -0
  95. package/dist/rabbitmq-DAUXsuvL.d.cts +61 -0
  96. package/dist/rabbitmq-DAUXsuvL.d.cts.map +1 -0
  97. package/dist/rabbitmq-DbxfLKQj.js +2 -0
  98. package/dist/rabbitmq-DbxfLKQj.js.map +1 -0
  99. package/dist/rabbitmq.cjs +1 -0
  100. package/dist/rabbitmq.d.cts +5 -0
  101. package/dist/rabbitmq.d.ts +5 -0
  102. package/dist/rabbitmq.js +1 -0
  103. package/dist/redis-streams-BV472jY5.js +2 -0
  104. package/dist/redis-streams-BV472jY5.js.map +1 -0
  105. package/dist/redis-streams-CGnDQYMH.cjs +1 -0
  106. package/dist/redis-streams-DpbNc20y.d.cts +97 -0
  107. package/dist/redis-streams-DpbNc20y.d.cts.map +1 -0
  108. package/dist/redis-streams-avvO_U2r.d.ts +97 -0
  109. package/dist/redis-streams-avvO_U2r.d.ts.map +1 -0
  110. package/dist/redis-streams.cjs +1 -0
  111. package/dist/redis-streams.d.cts +3 -0
  112. package/dist/redis-streams.d.ts +3 -0
  113. package/dist/redis-streams.js +1 -0
  114. package/dist/socketio.cjs +1 -1
  115. package/dist/socketio.d.cts +12 -4
  116. package/dist/socketio.d.cts.map +1 -1
  117. package/dist/socketio.d.ts +12 -4
  118. package/dist/socketio.d.ts.map +1 -1
  119. package/dist/socketio.js +1 -1
  120. package/dist/socketio.js.map +1 -1
  121. package/dist/tauri-CSoj53la.js +2 -0
  122. package/dist/tauri-CSoj53la.js.map +1 -0
  123. package/dist/{tauri-BAorUr9n.d.ts → tauri-DIJzjZwG.d.ts} +16 -4
  124. package/dist/tauri-DIJzjZwG.d.ts.map +1 -0
  125. package/dist/tauri-DvS2Czwp.cjs +1 -0
  126. package/dist/{tauri-DwFX963h.d.cts → tauri-d0yDsUnV.d.cts} +16 -4
  127. package/dist/tauri-d0yDsUnV.d.cts.map +1 -0
  128. package/dist/{transfer-handlers-jwQTY0rF.d.ts → transfer-handlers-3wBZpi5F.d.ts} +1 -1
  129. package/dist/{transfer-handlers-jwQTY0rF.d.ts.map → transfer-handlers-3wBZpi5F.d.ts.map} +1 -1
  130. package/dist/{utils-BQ7rl7lY.d.ts → utils-BEgiHk89.d.ts} +1 -1
  131. package/dist/utils-BEgiHk89.d.ts.map +1 -0
  132. package/package.json +75 -5
  133. package/dist/channel-BYtPphRu.js.map +0 -1
  134. package/dist/channel-C92Q3vK-.d.ts.map +0 -1
  135. package/dist/channel-QTVxXCE5.d.cts.map +0 -1
  136. package/dist/deno-BzNLlX8S.d.ts.map +0 -1
  137. package/dist/deno-DAHG1vvV.js +0 -2
  138. package/dist/deno-DAHG1vvV.js.map +0 -1
  139. package/dist/deno-DjRflDaL.cjs +0 -1
  140. package/dist/deno-noilmrf7.d.cts.map +0 -1
  141. package/dist/http-5KkjLA6X.js +0 -2
  142. package/dist/http-5KkjLA6X.js.map +0 -1
  143. package/dist/http-Cvnz7K2R.d.cts.map +0 -1
  144. package/dist/http-DpCLmXI6.cjs +0 -1
  145. package/dist/http-xFcyKRFw.d.ts.map +0 -1
  146. package/dist/interface-Bt8kzlyu.d.ts.map +0 -1
  147. package/dist/interface-DIWzRMw1.d.cts.map +0 -1
  148. package/dist/tauri-BAorUr9n.d.ts.map +0 -1
  149. package/dist/tauri-C7MVgjRt.js +0 -2
  150. package/dist/tauri-C7MVgjRt.js.map +0 -1
  151. package/dist/tauri-DJegDPWN.cjs +0 -1
  152. package/dist/tauri-DwFX963h.d.cts.map +0 -1
  153. package/dist/utils-BQ7rl7lY.d.ts.map +0 -1
package/README.md CHANGED
@@ -1,10 +1,11 @@
1
1
  <div align="center">
2
2
 
3
-
4
3
  # 🚀 kkrpc
5
4
 
6
5
  ## TypeScript-First RPC Library
7
6
 
7
+ [![Ask DeepWiki](https://deepwiki.com/badge.svg)](https://deepwiki.com/kunkunsh/kkrpc)
8
+ [![zread](https://img.shields.io/badge/Ask_Zread-_.svg?style=for-the-badge&color=00b0aa&labelColor=000000&logo=data%3Aimage%2Fsvg%2Bxml%3Bbase64%2CPHN2ZyB3aWR0aD0iMTYiIGhlaWdodD0iMTYiIHZpZXdCb3g9IjAgMCAxNiAxNiIgZmlsbD0ibm9uZSIgeG1sbnM9Imh0dHA6Ly93d3cudzMub3JnLzIwMDAvc3ZnIj4KPHBhdGggZD0iTTQuOTYxNTYgMS42MDAxSDIuMjQxNTZDMS44ODgxIDEuNjAwMSAxLjYwMTU2IDEuODg2NjQgMS42MDE1NiAyLjI0MDFWNC45NjAxQzEuNjAxNTYgNS4zMTM1NiAxLjg4ODEgNS42MDAxIDIuMjQxNTYgNS42MDAxSDQuOTYxNTZDNS4zMTUwMiA1LjYwMDEgNS42MDE1NiA1LjMxMzU2IDUuNjAxNTYgNC45NjAxVjIuMjQwMUM1LjYwMTU2IDEuODg2NjQgNS4zMTUwMiAxLjYwMDEgNC45NjE1NiAxLjYwMDFaIiBmaWxsPSIjZmZmIi8%2BCjxwYXRoIGQ9Ik00Ljk2MTU2IDEwLjM5OTlIMi4yNDE1NkMxLjg4ODEgMTAuMzk5OSAxLjYwMTU2IDEwLjY4NjQgMS42MDE1NiAxMS4wMzk5VjEzLjc1OTlDMS42MDE1NiAxNC4xMTM0IDEuODg4MSAxNC4zOTk5IDIuMjQxNTYgMTQuMzk5OUg0Ljk2MTU2QzUuMzE1MDIgMTQuMzk5OSA1LjYwMTU2IDE0LjExMzQgNS42MDE1NiAxMy43NTk5VjExLjAzOTlDNS42MDE1NiAxMC42ODY0IDUuMzE1MDIgMTAuMzk5OSA0Ljk2MTU2IDEwLjM5OTlaIiBmaWxsPSIjZmZmIi8%2BCjxwYXRoIGQ9Ik0xMy43NTg0IDEuNjAwMUgxMS4wMzg0QzEwLjY4NSAxLjYwMDEgMTAuMzk4NCAxLjg4NjY0IDEwLjM5ODQgMi4yNDAxVjQuOTYwMUMxMC4zOTg0IDUuMzEzNTYgMTAuNjg1IDUuNjAwMSAxMS4wMzg0IDUuNjAwMUgxMy43NTg0QzE0LjExMTkgNS42MDAxIDE0LjM5ODQgNS4zMTM1NiAxNC4zOTg0IDQuOTYwMVYyLjI0MDFDMTQuMzk4NCAxLjg4NjY0IDE0LjExMTkgMS42MDAxIDEzLjc1ODQgMS42MDAxWiIgZmlsbD0iI2ZmZiIvPgo8cGF0aCBkPSJNNCAxMkwxMiA0TDQgMTJaIiBmaWxsPSIjZmZmIi8%2BCjxwYXRoIGQ9Ik00IDEyTDEyIDQiIHN0cm9rZT0iI2ZmZiIgc3Ryb2tlLXdpZHRoPSIxLjUiIHN0cm9rZS1saW5lY2FwPSJyb3VuZCIvPgo8L3N2Zz4K&logoColor=ffffff)](https://zread.ai/kunkunsh/kkrpc)
8
9
  [![NPM Version](https://img.shields.io/npm/v/kkrpc?style=for-the-badge&logo=npm)](https://www.npmjs.com/package/kkrpc)
9
10
  [![JSR Version](https://img.shields.io/jsr/v/@kunkun/kkrpc?style=for-the-badge&logo=deno)](https://jsr.io/@kunkun/kkrpc)
10
11
  [![License](https://img.shields.io/npm/l/kkrpc?style=for-the-badge)](https://github.com/kunkunsh/kkrpc/blob/main/LICENSE)
@@ -12,6 +13,7 @@
12
13
  [![GitHub stars](https://img.shields.io/github/stars/kunkunsh/kkrpc?style=for-the-badge&logo=github)](https://github.com/kunkunsh/kkrpc)
13
14
  [![Typedoc Documentation](https://img.shields.io/badge/Docs-Typedoc-blue?style=for-the-badge&logo=typescript)](https://kunkunsh.github.io/kkrpc/)
14
15
  [![Excalidraw Diagrams](https://img.shields.io/badge/Diagrams-Excalidraw-orange?style=for-the-badge&logo=drawio)](https://excalidraw.com/#json=xp6GbAJVAx3nU-h3PhaxW,oYBNvYmCRsQ2XR3MQo73Ug)
16
+ [![LLM Docs](https://img.shields.io/badge/LLM-Docs-green?style=for-the-badge&logo=openai)](https://docs.kkrpc.kunkun.sh/llms.txt)
15
17
 
16
18
  </div>
17
19
 
@@ -25,10 +27,11 @@ Call remote functions as if they were local, with full TypeScript type safety an
25
27
 
26
28
  **Similar to Comlink but with bidirectional communication** and support for multiple environments - both client and server can expose functions for the other to call across Node.js, Deno, Bun, and browser environments.
27
29
 
28
- [**Quick Start**](#-quick-start) • [**Documentation**](https://kunkunsh.github.io/kkrpc/) • [**Examples**](#-examples) • [**API Reference**](https://jsr.io/@kunkun/kkrpc/doc)
30
+ [**Quick Start**](#-quick-start) • [**Documentation**](https://kunkunsh.github.io/kkrpc/) • [**Examples**](#-examples) • [**API Reference**](https://jsr.io/@kunkun/kkrpc/doc) • [**LLM Docs**](https://docs.kkrpc.kunkun.sh/llms.txt) • [**中文文档**](./README.zh.md)
29
31
 
30
32
  <div align="center">
31
33
 
34
+ <img src="https://imgur.com/19XswxO.jpg" style="max-width: 800px; width: 100%; margin-bottom: 20px;"/>
32
35
  <img src="https://imgur.com/vR3Lmv0.png" style="max-height: 200px; margin: 10px;"/>
33
36
  <img src="https://i.imgur.com/zmOHNfu.png" style="max-height: 250px; margin: 10px;"/>
34
37
  <img src="https://imgur.com/u728aVv.png" style="max-height: 400px; margin: 10px;"/>
@@ -46,19 +49,19 @@ kkrpc stands out in the crowded RPC landscape by offering **true cross-runtime c
46
49
 
47
50
  <div align="center">
48
51
 
49
- | Feature | Description |
50
- |---------|-------------|
51
- | **🔄 Cross-runtime** | Works seamlessly across Node.js, Deno, Bun, browsers, and more |
52
- | **🛡️ Type-safe** | Full TypeScript inference and IDE autocompletion support |
53
- | **↔️ Bidirectional** | Both endpoints can expose and call APIs simultaneously |
54
- | **🏠 Property Access** | Remote getters/setters with dot notation (`await api.prop`) |
55
- | **💥 Error Preservation** | Complete error objects across RPC boundaries |
56
- | **🌐 Multiple Transports** | stdio, HTTP, WebSocket, postMessage, Chrome extensions |
57
- | **📞 Callback Support** | Remote functions can accept callback functions |
58
- | **🔗 Nested Calls** | Deep method chaining like `api.math.operations.calculate()` |
59
- | **📦 Auto Serialization** | Intelligent JSON/superjson detection |
60
- | **⚡ Zero Config** | No schema files or code generation required |
61
- | **🚀 Transferable Objects** | Zero-copy transfers for large data (40-100x faster) |
52
+ | Feature | Description |
53
+ | --------------------------- | -------------------------------------------------------------- |
54
+ | **🔄 Cross-runtime** | Works seamlessly across Node.js, Deno, Bun, browsers, and more |
55
+ | **🛡️ Type-safe** | Full TypeScript inference and IDE autocompletion support |
56
+ | **↔️ Bidirectional** | Both endpoints can expose and call APIs simultaneously |
57
+ | **🏠 Property Access** | Remote getters/setters with dot notation (`await api.prop`) |
58
+ | **💥 Error Preservation** | Complete error objects across RPC boundaries |
59
+ | **🌐 Multiple Transports** | stdio, HTTP, WebSocket, postMessage, Chrome extensions |
60
+ | **📞 Callback Support** | Remote functions can accept callback functions |
61
+ | **🔗 Nested Calls** | Deep method chaining like `api.math.operations.calculate()` |
62
+ | **📦 Auto Serialization** | Intelligent JSON/superjson detection |
63
+ | **⚡ Zero Config** | No schema files or code generation required |
64
+ | **🚀 Transferable Objects** | Zero-copy transfers for large data (40-100x faster) |
62
65
 
63
66
  </div>
64
67
 
@@ -68,42 +71,47 @@ kkrpc stands out in the crowded RPC landscape by offering **true cross-runtime c
68
71
 
69
72
  ```mermaid
70
73
  graph LR
71
- A[kkrpc] --> B[Node.js]
72
- A --> C[Deno]
73
- A --> D[Bun]
74
- A --> E[Browser]
75
- A --> F[Chrome Extension]
76
- A --> G[Tauri]
77
-
78
- B -.-> H[stdio]
79
- C -.-> H
80
- D -.-> H
81
-
82
- E -.-> I[postMessage]
83
- E -.-> J[Web Workers]
84
- E -.-> K[iframes]
85
-
86
- F -.-> L[Chrome Ports]
87
-
88
- G -.-> M[Shell Plugin]
89
-
90
- style A fill:#ff6b6b,stroke:#333,stroke-width:2px
74
+ A[kkrpc] --> B[Node.js]
75
+ A --> C[Deno]
76
+ A --> D[Bun]
77
+ A --> E[Browser]
78
+ A --> F[Chrome Extension]
79
+ A --> G[Tauri]
80
+
81
+ B -.-> H[stdio]
82
+ C -.-> H
83
+ D -.-> H
84
+
85
+ E -.-> I[postMessage]
86
+ E -.-> J[Web Workers]
87
+ E -.-> K[iframes]
88
+
89
+ F -.-> L[Chrome Ports]
90
+
91
+ G -.-> M[Shell Plugin]
92
+
93
+ style A fill:#ff6b6b,stroke:#333,stroke-width:2px
91
94
  ```
92
95
 
93
96
  </div>
94
97
 
95
98
  ### 📡 Transport Protocols
96
99
 
97
- | Transport | Use Case | Supported Runtimes |
98
- |-----------|----------|-------------------|
99
- | **stdio** | Process-to-process communication | Node.js ↔ Deno ↔ Bun |
100
- | **postMessage** | Browser context communication | Browser ↔ Web Workers ↔ iframes |
101
- | **HTTP** | Web API communication | All runtimes |
102
- | **WebSocket** | Real-time communication | All runtimes |
103
- | **Hono WebSocket** | High-performance WebSocket with Hono framework | Node.js, Deno, Bun, Cloudflare Workers |
104
- | **Socket.IO** | Enhanced real-time with rooms/namespaces | All runtimes |
105
- | **Elysia WebSocket** | Modern TypeScript framework WebSocket integration | Bun, Node.js, Deno |
106
- | **Chrome Extension** | Extension component communication | Chrome Extension contexts |
100
+ | Transport | Use Case | Supported Runtimes |
101
+ | -------------------- | ----------------------------------------------------- | -------------------------------------- |
102
+ | **stdio** | Process-to-process communication | Node.js ↔ Deno ↔ Bun |
103
+ | **postMessage** | Browser context communication | Browser ↔ Web Workers ↔ iframes |
104
+ | **HTTP** | Web API communication | All runtimes |
105
+ | **WebSocket** | Real-time communication | All runtimes |
106
+ | **Hono WebSocket** | High-performance WebSocket with Hono framework | Node.js, Deno, Bun, Cloudflare Workers |
107
+ | **Socket.IO** | Enhanced real-time with rooms/namespaces | All runtimes |
108
+ | **Elysia WebSocket** | Modern TypeScript framework WebSocket integration | Bun, Node.js, Deno |
109
+ | **Chrome Extension** | Extension component communication | Chrome Extension contexts |
110
+ | **RabbitMQ** | Message queue communication | Node.js, Deno, Bun |
111
+ | **Redis Streams** | Stream-based messaging with persistence | Node.js, Deno, Bun |
112
+ | **Kafka** | Distributed streaming platform | Node.js, Deno, Bun |
113
+ | **NATS** | High-performance messaging system | Node.js, Deno, Bun |
114
+ | **Electron** | Desktop app IPC (Renderer ↔ Main ↔ Utility Process) | Electron |
107
115
 
108
116
  The core of **kkrpc** design is in `RPCChannel` and `IoInterface`.
109
117
 
@@ -163,7 +171,7 @@ For backward compatibility, the receiving side will automatically detect the ser
163
171
 
164
172
  ### Installation
165
173
 
166
- <div align="center">
174
+
167
175
 
168
176
  ```bash
169
177
  # npm
@@ -179,41 +187,35 @@ pnpm add kkrpc
179
187
  import { RPCChannel } from "jsr:@kunkun/kkrpc"
180
188
  ```
181
189
 
182
- </div>
183
-
184
190
  ### Basic Example
185
191
 
186
- <div align="center">
187
-
188
192
  ```typescript
189
193
  // server.ts
190
- import { RPCChannel, NodeIo } from "kkrpc"
194
+ import { NodeIo, RPCChannel } from "kkrpc"
191
195
 
192
196
  const api = {
193
- greet: (name: string) => `Hello, ${name}!`,
194
- add: (a: number, b: number) => a + b
197
+ greet: (name: string) => `Hello, ${name}!`,
198
+ add: (a: number, b: number) => a + b
195
199
  }
196
200
 
197
201
  const rpc = new RPCChannel(new NodeIo(process.stdin, process.stdout), {
198
- expose: api
202
+ expose: api
199
203
  })
200
204
  ```
201
205
 
202
206
  ```typescript
203
207
  // client.ts
204
- import { RPCChannel, NodeIo } from "kkrpc"
205
208
  import { spawn } from "child_process"
209
+ import { NodeIo, RPCChannel } from "kkrpc"
206
210
 
207
211
  const worker = spawn("deno", ["run", "server.ts"])
208
212
  const rpc = new RPCChannel(new NodeIo(worker.stdout, worker.stdin))
209
213
  const api = rpc.getAPI<typeof api>()
210
214
 
211
215
  console.log(await api.greet("World")) // "Hello, World!"
212
- console.log(await api.add(5, 3)) // 8
216
+ console.log(await api.add(5, 3)) // 8
213
217
  ```
214
218
 
215
- </div>
216
-
217
219
  ## 📚 Examples
218
220
 
219
221
  Below are simple examples to get you started quickly.
@@ -280,9 +282,13 @@ kkrpc preserves complete error information across RPC boundaries:
280
282
  ```ts
281
283
  // Custom error class
282
284
  class DatabaseError extends Error {
283
- constructor(message: string, public code: number, public query: string) {
285
+ constructor(
286
+ message: string,
287
+ public code: number,
288
+ public query: string
289
+ ) {
284
290
  super(message)
285
- this.name = 'DatabaseError'
291
+ this.name = "DatabaseError"
286
292
  }
287
293
  }
288
294
 
@@ -304,11 +310,11 @@ try {
304
310
  await api.getUserById("")
305
311
  } catch (error) {
306
312
  // All error properties are preserved:
307
- console.log(error.name) // "DatabaseError"
308
- console.log(error.message) // "Invalid user ID"
309
- console.log(error.code) // 400
310
- console.log(error.query) // "SELECT * FROM users WHERE id = ?"
311
- console.log(error.stack) // Full stack trace
313
+ console.log(error.name) // "DatabaseError"
314
+ console.log(error.message) // "Invalid user ID"
315
+ console.log(error.code) // 400
316
+ console.log(error.query) // "SELECT * FROM users WHERE id = ?"
317
+ console.log(error.stack) // Full stack trace
312
318
  console.log(error.timestamp) // ISO timestamp
313
319
  console.log(error.requestId) // Request ID
314
320
  }
@@ -343,14 +349,14 @@ expect(sum).toBe(3)
343
349
  kkrpc supports zero-copy transfer of large data structures using browser's native transferable objects. This provides 40-100x performance improvement for large binary data transfers.
344
350
 
345
351
  ```ts
346
- import { RPCChannel, WorkerParentIO, transfer } from "kkrpc/browser"
352
+ import { RPCChannel, transfer, WorkerParentIO } from "kkrpc/browser"
347
353
 
348
354
  const worker = new Worker("worker.js")
349
355
  const io = new WorkerParentIO(worker)
350
356
  const rpc = new RPCChannel(io)
351
357
  const api = rpc.getAPI<{
352
- processBuffer(buffer: ArrayBuffer): Promise<number>
353
- generateData(size: number): Promise<ArrayBuffer>
358
+ processBuffer(buffer: ArrayBuffer): Promise<number>
359
+ generateData(size: number): Promise<ArrayBuffer>
354
360
  }>()
355
361
 
356
362
  // Create a large buffer (10MB)
@@ -376,23 +382,26 @@ Hono WebSocket adapter provides seamless integration with the Hono framework's h
376
382
  #### `server.ts`
377
383
 
378
384
  ```ts
379
- import { Hono } from 'hono'
380
- import { upgradeWebSocket, websocket } from 'hono/bun'
381
- import { createHonoWebSocketHandler } from 'kkrpc'
382
- import { apiMethods, type API } from './api'
385
+ import { Hono } from "hono"
386
+ import { upgradeWebSocket, websocket } from "hono/bun"
387
+ import { createHonoWebSocketHandler } from "kkrpc"
388
+ import { apiMethods, type API } from "./api"
383
389
 
384
390
  const app = new Hono()
385
391
 
386
- app.get('/ws', upgradeWebSocket(() => {
387
- return createHonoWebSocketHandler<API>({
388
- expose: apiMethods
389
- })
390
- }))
392
+ app.get(
393
+ "/ws",
394
+ upgradeWebSocket(() => {
395
+ return createHonoWebSocketHandler<API>({
396
+ expose: apiMethods
397
+ })
398
+ })
399
+ )
391
400
 
392
401
  const server = Bun.serve({
393
- port: 3000,
394
- fetch: app.fetch,
395
- websocket
402
+ port: 3000,
403
+ fetch: app.fetch,
404
+ websocket
396
405
  })
397
406
 
398
407
  console.log(`Server running on port ${server.port}`)
@@ -401,15 +410,15 @@ console.log(`Server running on port ${server.port}`)
401
410
  #### `client.ts`
402
411
 
403
412
  ```ts
404
- import { WebSocketClientIO, RPCChannel } from 'kkrpc'
405
- import { apiMethods, type API } from './api'
413
+ import { RPCChannel, WebSocketClientIO } from "kkrpc"
414
+ import { apiMethods, type API } from "./api"
406
415
 
407
416
  const clientIO = new WebSocketClientIO({
408
- url: 'ws://localhost:3000/ws'
417
+ url: "ws://localhost:3000/ws"
409
418
  })
410
419
 
411
420
  const clientRPC = new RPCChannel<API, API>(clientIO, {
412
- expose: apiMethods
421
+ expose: apiMethods
413
422
  })
414
423
 
415
424
  const api = clientRPC.getAPI()
@@ -429,6 +438,7 @@ clientIO.destroy()
429
438
  ```
430
439
 
431
440
  **Hono WebSocket Features:**
441
+
432
442
  - **High Performance**: Built on Hono's ultra-fast WebSocket implementation
433
443
  - **Cross-runtime**: Works across Bun, Deno, Node.js, and Cloudflare Workers
434
444
  - **Type-safe**: Full TypeScript support with Hono integration
@@ -444,54 +454,54 @@ Elysia WebSocket adapter provides seamless integration with the modern TypeScrip
444
454
  #### `server.ts`
445
455
 
446
456
  ```ts
447
- import { Elysia } from 'elysia'
448
- import { ElysiaWebSocketServerIO, RPCChannel } from 'kkrpc'
449
- import { apiMethods, type API } from './api'
457
+ import { Elysia } from "elysia"
458
+ import { ElysiaWebSocketServerIO, RPCChannel } from "kkrpc"
459
+ import { apiMethods, type API } from "./api"
450
460
 
451
461
  // Extend API for Elysia-specific features
452
462
  interface ElysiaAPI extends API {
453
- getConnectionInfo(): Promise<{
454
- remoteAddress: string | undefined
455
- query: Record<string, string>
456
- headers: Record<string, string>
457
- }>
463
+ getConnectionInfo(): Promise<{
464
+ remoteAddress: string | undefined
465
+ query: Record<string, string>
466
+ headers: Record<string, string>
467
+ }>
458
468
  }
459
469
 
460
470
  const app = new Elysia()
461
- .ws('/rpc', {
462
- open(ws) {
463
- const io = new ElysiaWebSocketServerIO(ws)
464
- const elysiaApiMethods: ElysiaAPI = {
465
- ...apiMethods,
466
- getConnectionInfo: async () => ({
467
- remoteAddress: io.getRemoteAddress(),
468
- query: io.getQuery(),
469
- headers: io.getHeaders()
470
- })
471
- }
472
-
473
- const rpc = new RPCChannel<ElysiaAPI, ElysiaAPI>(io, {
474
- expose: elysiaApiMethods
475
- })
476
- },
477
- message(ws, message) {
478
- ElysiaWebSocketServerIO.feedMessage(ws, message)
479
- }
480
- })
481
- .listen(3000)
482
-
483
- console.log('Elysia server running on port 3000')
471
+ .ws("/rpc", {
472
+ open(ws) {
473
+ const io = new ElysiaWebSocketServerIO(ws)
474
+ const elysiaApiMethods: ElysiaAPI = {
475
+ ...apiMethods,
476
+ getConnectionInfo: async () => ({
477
+ remoteAddress: io.getRemoteAddress(),
478
+ query: io.getQuery(),
479
+ headers: io.getHeaders()
480
+ })
481
+ }
482
+
483
+ const rpc = new RPCChannel<ElysiaAPI, ElysiaAPI>(io, {
484
+ expose: elysiaApiMethods
485
+ })
486
+ },
487
+ message(ws, message) {
488
+ ElysiaWebSocketServerIO.feedMessage(ws, message)
489
+ }
490
+ })
491
+ .listen(3000)
492
+
493
+ console.log("Elysia server running on port 3000")
484
494
  ```
485
495
 
486
496
  #### `client.ts`
487
497
 
488
498
  ```ts
489
- import { ElysiaWebSocketClientIO, RPCChannel } from 'kkrpc'
490
- import { apiMethods, type API } from './api'
499
+ import { ElysiaWebSocketClientIO, RPCChannel } from "kkrpc"
500
+ import { apiMethods, type API } from "./api"
491
501
 
492
- const clientIO = new ElysiaWebSocketClientIO('ws://localhost:3000/rpc')
502
+ const clientIO = new ElysiaWebSocketClientIO("ws://localhost:3000/rpc")
493
503
  const clientRPC = new RPCChannel<API, any>(clientIO, {
494
- expose: apiMethods
504
+ expose: apiMethods
495
505
  })
496
506
 
497
507
  const api = clientRPC.getAPI()
@@ -506,14 +516,15 @@ console.log(await api.math.grade3.divide(20, 4)) // 5
506
516
 
507
517
  // Test Elysia-specific features
508
518
  const connInfo = await api.getConnectionInfo()
509
- console.log('Connected from:', connInfo.remoteAddress)
510
- console.log('Query params:', connInfo.query)
511
- console.log('Headers:', connInfo.headers)
519
+ console.log("Connected from:", connInfo.remoteAddress)
520
+ console.log("Query params:", connInfo.query)
521
+ console.log("Headers:", connInfo.headers)
512
522
 
513
523
  clientIO.destroy()
514
524
  ```
515
525
 
516
526
  **Elysia WebSocket Features:**
527
+
517
528
  - **Modern Framework**: Built on Elysia's TypeScript-first design
518
529
  - **Ultra-fast**: Powered by uWebSocket for maximum performance
519
530
  - **Rich Metadata**: Access to connection info, query params, and headers
@@ -524,12 +535,14 @@ clientIO.destroy()
524
535
  **Learn more:** [Elysia WebSocket Documentation](https://elysiajs.com/patterns/websocket)
525
536
 
526
537
  **Key Benefits:**
538
+
527
539
  - **Zero-copy performance**: No serialization/deserialization overhead
528
540
  - **Memory efficient**: Ownership transfers without copying
529
541
  - **Automatic fallback**: Graceful degradation for non-transferable transports
530
542
  - **Type-safe**: Full TypeScript support
531
543
 
532
544
  **Supported Transferable Types:**
545
+
533
546
  - `ArrayBuffer` - Binary data buffers
534
547
  - `MessagePort` - Communication channels
535
548
  - `ImageBitmap` - Decoded image data
@@ -615,55 +628,334 @@ For Chrome extensions, use the dedicated `ChromePortIO` adapter for reliable, po
615
628
  #### `background.ts`
616
629
 
617
630
  ```ts
618
- import { ChromePortIO, RPCChannel } from "kkrpc/chrome-extension";
619
- import type { BackgroundAPI, ContentAPI } from "./types";
631
+ import { ChromePortIO, RPCChannel } from "kkrpc/chrome-extension"
632
+ import type { BackgroundAPI, ContentAPI } from "./types"
620
633
 
621
634
  const backgroundAPI: BackgroundAPI = {
622
- async getExtensionVersion() {
623
- return chrome.runtime.getManifest().version;
624
- },
625
- };
635
+ async getExtensionVersion() {
636
+ return chrome.runtime.getManifest().version
637
+ }
638
+ }
626
639
 
627
640
  chrome.runtime.onConnect.addListener((port) => {
628
- if (port.name === "content-to-background") {
629
- const io = new ChromePortIO(port);
630
- const rpc = new RPCChannel(io, { expose: backgroundAPI });
631
- // Handle disconnect
632
- port.onDisconnect.addListener(() => io.destroy());
633
- }
634
- });
641
+ if (port.name === "content-to-background") {
642
+ const io = new ChromePortIO(port)
643
+ const rpc = new RPCChannel(io, { expose: backgroundAPI })
644
+ // Handle disconnect
645
+ port.onDisconnect.addListener(() => io.destroy())
646
+ }
647
+ })
635
648
  ```
636
649
 
637
650
  #### `content.ts`
638
651
 
639
652
  ```ts
640
- import { ChromePortIO, RPCChannel } from "kkrpc/chrome-extension";
641
- import type { BackgroundAPI, ContentAPI } from "./types";
653
+ import { ChromePortIO, RPCChannel } from "kkrpc/chrome-extension"
654
+ import type { BackgroundAPI, ContentAPI } from "./types"
642
655
 
643
656
  const contentAPI: ContentAPI = {
644
- async getPageTitle() {
645
- return document.title;
646
- },
647
- };
657
+ async getPageTitle() {
658
+ return document.title
659
+ }
660
+ }
648
661
 
649
- const port = chrome.runtime.connect({ name: "content-to-background" });
650
- const io = new ChromePortIO(port);
651
- const rpc = new RPCChannel<ContentAPI, BackgroundAPI>(io, { expose: contentAPI });
662
+ const port = chrome.runtime.connect({ name: "content-to-background" })
663
+ const io = new ChromePortIO(port)
664
+ const rpc = new RPCChannel<ContentAPI, BackgroundAPI>(io, { expose: contentAPI })
652
665
 
653
- const backgroundAPI = rpc.getAPI();
666
+ const backgroundAPI = rpc.getAPI()
654
667
 
655
668
  // Example call
656
- backgroundAPI.getExtensionVersion().then(version => {
657
- console.log("Extension version:", version);
658
- });
669
+ backgroundAPI.getExtensionVersion().then((version) => {
670
+ console.log("Extension version:", version)
671
+ })
659
672
  ```
660
673
 
661
674
  **Chrome Extension Features:**
675
+
662
676
  - **Port-based**: Uses `chrome.runtime.Port` for stable, long-lived connections.
663
677
  - **Bidirectional**: Both sides can expose and call APIs.
664
678
  - **Type-safe**: Full TypeScript support for your APIs.
665
679
  - **Reliable**: Handles connection lifecycle and cleanup.
666
680
 
681
+ ### RabbitMQ Example
682
+
683
+ RabbitMQ adapter provides reliable message queue communication with support for topic exchanges and durable messaging.
684
+
685
+ #### `producer.ts`
686
+
687
+ ```ts
688
+ import { RabbitMQIO, RPCChannel } from "kkrpc"
689
+ import { apiMethods, type API } from "./api"
690
+
691
+ const rabbitmqIO = new RabbitMQIO({
692
+ url: "amqp://localhost",
693
+ exchange: "kkrpc-exchange",
694
+ exchangeType: "topic",
695
+ durable: true
696
+ })
697
+
698
+ const producerRPC = new RPCChannel<API, API>(rabbitmqIO, {
699
+ expose: apiMethods
700
+ })
701
+
702
+ const api = producerRPC.getAPI()
703
+
704
+ // Test basic RPC calls
705
+ console.log(await api.add(5, 3)) // 8
706
+ console.log(await api.echo("Hello from RabbitMQ!")) // "Hello from RabbitMQ!"
707
+
708
+ rabbitmqIO.destroy()
709
+ ```
710
+
711
+ #### `consumer.ts`
712
+
713
+ ```ts
714
+ import { RabbitMQIO, RPCChannel } from "kkrpc"
715
+ import { apiMethods, type API } from "./api"
716
+
717
+ const rabbitmqIO = new RabbitMQIO({
718
+ url: "amqp://localhost",
719
+ exchange: "kkrpc-exchange",
720
+ exchangeType: "topic",
721
+ durable: true,
722
+ sessionId: "consumer-session"
723
+ })
724
+
725
+ const consumerRPC = new RPCChannel<API, API>(rabbitmqIO, {
726
+ expose: apiMethods
727
+ })
728
+
729
+ const api = consumerRPC.getAPI()
730
+
731
+ // Process messages from producer
732
+ console.log(await api.add(10, 20)) // 30
733
+ console.log(await api.echo("Hello from consumer!")) // "Hello from consumer!"
734
+
735
+ rabbitmqIO.destroy()
736
+ ```
737
+
738
+ **RabbitMQ Features:**
739
+
740
+ - **Topic Exchange**: Flexible routing with wildcard patterns
741
+ - **Durable Messaging**: Messages survive broker restarts
742
+ - **Load Balancing**: Multiple consumers can share workload
743
+ - **Reliable Delivery**: Acknowledgments and redelivery support
744
+ - **Session Management**: Unique sessions prevent message conflicts
745
+
746
+ ### Redis Streams Example
747
+
748
+ Redis Streams adapter provides high-performance stream-based messaging with persistence and consumer group support.
749
+
750
+ #### `publisher.ts`
751
+
752
+ ```ts
753
+ import { RedisStreamsIO, RPCChannel } from "kkrpc"
754
+ import { apiMethods, type API } from "./api"
755
+
756
+ const redisIO = new RedisStreamsIO({
757
+ url: "redis://localhost:6379",
758
+ stream: "kkrpc-stream",
759
+ maxLen: 10000, // Keep only last 10k messages
760
+ maxQueueSize: 1000
761
+ })
762
+
763
+ const publisherRPC = new RPCChannel<API, API>(redisIO, {
764
+ expose: apiMethods
765
+ })
766
+
767
+ const api = publisherRPC.getAPI()
768
+
769
+ // Test basic RPC calls
770
+ console.log(await api.add(7, 8)) // 15
771
+ console.log(await api.echo("Hello from Redis Streams!")) // "Hello from Redis Streams!"
772
+
773
+ // Get stream information
774
+ const streamInfo = await redisIO.getStreamInfo()
775
+ console.log("Stream length:", streamInfo.length)
776
+
777
+ redisIO.destroy()
778
+ ```
779
+
780
+ #### `subscriber.ts`
781
+
782
+ ```ts
783
+ import { RedisStreamsIO, RPCChannel } from "kkrpc"
784
+ import { apiMethods, type API } from "./api"
785
+
786
+ // Using consumer group for load balancing
787
+ const redisIO = new RedisStreamsIO({
788
+ url: "redis://localhost:6379",
789
+ stream: "kkrpc-stream",
790
+ consumerGroup: "kkrpc-group",
791
+ consumerName: "worker-1",
792
+ useConsumerGroup: true, // Enable load balancing
793
+ maxQueueSize: 1000
794
+ })
795
+
796
+ const subscriberRPC = new RPCChannel<API, API>(redisIO, {
797
+ expose: apiMethods
798
+ })
799
+
800
+ const api = subscriberRPC.getAPI()
801
+
802
+ // Process messages with load balancing
803
+ console.log(await api.multiply(4, 6)) // 24
804
+ console.log(await api.echo("Hello from subscriber!")) // "Hello from subscriber!"
805
+
806
+ redisIO.destroy()
807
+ ```
808
+
809
+ **Redis Streams Features:**
810
+
811
+ - **Two Modes**: Pub/Sub (all consumers) or Consumer Groups (load balancing)
812
+ - **Persistence**: Messages stored in Redis with configurable retention
813
+ - **Memory Protection**: Queue size limits prevent memory issues
814
+ - **Consumer Groups**: Load balancing with message acknowledgment
815
+ - **Stream Management**: Built-in tools for monitoring and trimming streams
816
+
817
+ ### Kafka Example
818
+
819
+ Kafka adapter provides distributed streaming with high throughput and fault tolerance for large-scale systems.
820
+
821
+ #### `producer.ts`
822
+
823
+ ```ts
824
+ import { KafkaIO, RPCChannel } from "kkrpc"
825
+ import { apiMethods, type API } from "./api"
826
+
827
+ const kafkaIO = new KafkaIO({
828
+ brokers: ["localhost:9092"],
829
+ topic: "kkrpc-topic",
830
+ clientId: "kkrpc-producer",
831
+ numPartitions: 3,
832
+ replicationFactor: 1,
833
+ maxQueueSize: 1000
834
+ })
835
+
836
+ const producerRPC = new RPCChannel<API, API>(kafkaIO, {
837
+ expose: apiMethods
838
+ })
839
+
840
+ const api = producerRPC.getAPI()
841
+
842
+ // Test basic RPC calls
843
+ console.log(await api.add(12, 18)) // 30
844
+ console.log(await api.echo("Hello from Kafka!")) // "Hello from Kafka!"
845
+
846
+ console.log("Topic:", kafkaIO.getTopic())
847
+ console.log("Session ID:", kafkaIO.getSessionId())
848
+
849
+ kafkaIO.destroy()
850
+ ```
851
+
852
+ #### `consumer.ts`
853
+
854
+ ```ts
855
+ import { KafkaIO, RPCChannel } from "kkrpc"
856
+ import { apiMethods, type API } from "./api"
857
+
858
+ const kafkaIO = new KafkaIO({
859
+ brokers: ["localhost:9092"],
860
+ topic: "kkrpc-topic",
861
+ clientId: "kkrpc-consumer",
862
+ groupId: "kkrpc-consumer-group",
863
+ fromBeginning: false, // Only read new messages
864
+ maxQueueSize: 1000
865
+ })
866
+
867
+ const consumerRPC = new RPCChannel<API, API>(kafkaIO, {
868
+ expose: apiMethods
869
+ })
870
+
871
+ const api = consumerRPC.getAPI()
872
+
873
+ // Process messages from Kafka
874
+ console.log(await api.divide(100, 4)) // 25
875
+ console.log(await api.echo("Hello from Kafka consumer!")) // "Hello from Kafka consumer!"
876
+
877
+ console.log("Topic:", kafkaIO.getTopic())
878
+ console.log("Group ID:", kafkaIO.getGroupId())
879
+
880
+ kafkaIO.destroy()
881
+ ```
882
+
883
+ **Kafka Features:**
884
+
885
+ - **Distributed**: Built-in replication and partitioning
886
+ - **High Throughput**: Optimized for high-volume message streaming
887
+ - **Fault Tolerant**: Replication and automatic failover
888
+ - **Scalable**: Horizontal scaling with partitions
889
+ - **Persistent**: Durable message storage with configurable retention
890
+ - **Consumer Groups**: Load balancing across consumer instances
891
+
892
+ ### NATS Example
893
+
894
+ NATS adapter provides high-performance messaging with publish/subscribe patterns and optional queue groups for load balancing.
895
+
896
+ #### `publisher.ts`
897
+
898
+ ```ts
899
+ import { NatsIO, RPCChannel } from "kkrpc"
900
+ import { apiMethods, type API } from "./api"
901
+
902
+ const natsIO = new NatsIO({
903
+ servers: "nats://localhost:4222",
904
+ subject: "kkrpc-messages",
905
+ queueGroup: "kkrpc-group" // Optional: enables load balancing
906
+ })
907
+
908
+ const publisherRPC = new RPCChannel<API, API>(natsIO, {
909
+ expose: apiMethods
910
+ })
911
+
912
+ const api = publisherRPC.getAPI()
913
+
914
+ // Test basic RPC calls
915
+ console.log(await api.add(5, 3)) // 8
916
+ console.log(await api.echo("Hello from NATS!")) // "Hello from NATS!"
917
+
918
+ console.log("Subject:", natsIO.getSubject())
919
+ console.log("Session ID:", natsIO.getSessionId())
920
+
921
+ natsIO.destroy()
922
+ ```
923
+
924
+ #### `subscriber.ts`
925
+
926
+ ```ts
927
+ import { NatsIO, RPCChannel } from "kkrpc"
928
+ import { apiMethods, type API } from "./api"
929
+
930
+ const natsIO = new NatsIO({
931
+ servers: "nats://localhost:4222",
932
+ subject: "kkrpc-messages",
933
+ queueGroup: "kkrpc-group", // Optional: enables load balancing
934
+ sessionId: "subscriber-session"
935
+ })
936
+
937
+ const subscriberRPC = new RPCChannel<API, API>(natsIO, {
938
+ expose: apiMethods
939
+ })
940
+
941
+ const api = subscriberRPC.getAPI()
942
+
943
+ // Process messages from publisher
944
+ console.log(await api.add(10, 20)) // 30
945
+ console.log(await api.echo("Hello from subscriber!")) // "Hello from subscriber!"
946
+
947
+ natsIO.destroy()
948
+ ```
949
+
950
+ **NATS Features:**
951
+
952
+ - **High Performance**: Ultra-low latency messaging system
953
+ - **Subject-Based**: Flexible subject hierarchy for routing
954
+ - **Queue Groups**: Optional load balancing across subscribers
955
+ - **Simple Model**: Pub/Sub with request/reply support
956
+ - **Cross-Platform**: Works across Node.js, Deno, and Bun
957
+ - **No Schema Required**: Dynamic message routing without upfront configuration
958
+
667
959
  ### Tauri Example
668
960
 
669
961
  Call functions in bun/node/deno processes from Tauri app with JS/TS.
@@ -734,21 +1026,245 @@ I provided a sample tauri app in `examples/tauri-demo`.
734
1026
 
735
1027
  ![Sample Tauri App](https://i.imgur.com/nkDwRHk.png)
736
1028
 
1029
+ ### Electron Example
1030
+
1031
+ Electron adapter provides type-safe bidirectional RPC communication between Renderer process, Main process, and Utility Process.
1032
+
1033
+ There are two sets of adapters for Electron:
1034
+
1035
+ 1. **Renderer ↔ Main IPC**: `ElectronIpcMainIO` (Main side) + `ElectronIpcRendererIO` (Renderer side)
1036
+ 2. **Main ↔ Utility Process**: `ElectronUtilityProcessIO` (Main side) + `ElectronUtilityProcessChildIO` (Utility Process side)
1037
+
1038
+ #### Preload Script Setup
1039
+
1040
+ Use `createSecureIpcBridge` to create a secured `ipcRenderer` with channel whitelisting:
1041
+
1042
+ ```ts title="preload.ts"
1043
+ import { contextBridge, ipcRenderer } from "electron"
1044
+ import { createSecureIpcBridge } from "kkrpc/electron-ipc"
1045
+
1046
+ const securedIpcRenderer = createSecureIpcBridge({
1047
+ ipcRenderer,
1048
+ channelPrefix: "kkrpc-"
1049
+ })
1050
+
1051
+ contextBridge.exposeInMainWorld("electron", {
1052
+ ipcRenderer: securedIpcRenderer
1053
+ })
1054
+ ```
1055
+
1056
+ This automatically whitelists only channels starting with `"kkrpc-"`. You can also whitelist specific channels:
1057
+
1058
+ ```ts title="preload.ts"
1059
+ import { contextBridge, ipcRenderer } from "electron"
1060
+ import { createSecureIpcBridge } from "kkrpc/electron-ipc"
1061
+
1062
+ const securedIpcRenderer = createSecureIpcBridge({
1063
+ ipcRenderer,
1064
+ allowedChannels: ["kkrpc-ipc", "kkrpc-worker-relay"]
1065
+ })
1066
+
1067
+ contextBridge.exposeInMainWorld("electron", {
1068
+ ipcRenderer: securedIpcRenderer
1069
+ })
1070
+ ```
1071
+
1072
+ This approach avoids direct Electron dependencies in kkrpc, making it compatible with any Electron version.
1073
+
1074
+ #### Main Process
1075
+
1076
+ ```ts title="main.ts"
1077
+ import { app, BrowserWindow, ipcMain, utilityProcess } from "electron"
1078
+ import { ElectronUtilityProcessIO, RPCChannel } from "kkrpc/electron"
1079
+ import { ElectronIpcMainIO } from "kkrpc/electron-ipc"
1080
+
1081
+ interface MainAPI {
1082
+ showNotification(message: string): Promise<void>
1083
+ getAppVersion(): Promise<string>
1084
+ }
1085
+
1086
+ interface WorkerAPI {
1087
+ add(a: number, b: number): Promise<number>
1088
+ multiply(a: number, b: number): Promise<number>
1089
+ }
1090
+
1091
+ const mainAPI: MainAPI = {
1092
+ showNotification: async (message: string) => {
1093
+ console.log(`[Main] Notification: ${message}`)
1094
+ },
1095
+ getAppVersion: async () => app.getVersion()
1096
+ }
1097
+
1098
+ // 1. Setup Renderer ↔ Main IPC
1099
+ const win = new BrowserWindow({
1100
+ webPreferences: {
1101
+ preload: path.join(__dirname, "preload.js"),
1102
+ contextIsolation: true,
1103
+ nodeIntegration: false
1104
+ }
1105
+ })
1106
+
1107
+ const ipcIO = new ElectronIpcMainIO(ipcMain, win.webContents)
1108
+ const ipcRPC = new RPCChannel<MainAPI, object>(ipcIO, { expose: mainAPI })
1109
+
1110
+ // 2. Setup Main ↔ Utility Process
1111
+ const workerPath = path.join(__dirname, "./worker.js")
1112
+ const workerProcess = utilityProcess.fork(workerPath)
1113
+ const workerIO = new ElectronUtilityProcessIO(workerProcess)
1114
+ const workerRPC = new RPCChannel<MainAPI, WorkerAPI>(workerIO, { expose: mainAPI })
1115
+ const workerAPI = workerRPC.getAPI()
1116
+
1117
+ // Now you can call worker methods from main
1118
+ const result = await workerAPI.add(2, 3) // 5
1119
+ ```
1120
+
1121
+ #### Renderer Process
1122
+
1123
+ ```ts title="renderer.ts"
1124
+ import { ElectronIpcRendererIO, RPCChannel } from "kkrpc/electron-ipc"
1125
+
1126
+ interface MainAPI {
1127
+ showNotification(message: string): Promise<void>
1128
+ getAppVersion(): Promise<string>
1129
+ }
1130
+
1131
+ const ipcIO = new ElectronIpcRendererIO()
1132
+ const ipcRPC = new RPCChannel<object, MainAPI>(ipcIO, { expose: {} })
1133
+ const mainAPI = ipcRPC.getAPI()
1134
+
1135
+ // Call main process methods from renderer
1136
+ await mainAPI.showNotification("Hello from renderer!")
1137
+ const version = await mainAPI.getAppVersion()
1138
+ ```
1139
+
1140
+ #### Utility Process (Worker)
1141
+
1142
+ ```ts title="worker.ts"
1143
+ import { ElectronUtilityProcessChildIO, RPCChannel } from "kkrpc/electron"
1144
+
1145
+ interface MainAPI {
1146
+ showNotification(message: string): Promise<void>
1147
+ }
1148
+
1149
+ const io = new ElectronUtilityProcessChildIO()
1150
+
1151
+ const workerMethods = {
1152
+ add: async (a: number, b: number) => a + b,
1153
+ multiply: async (a: number, b: number) => a * b
1154
+ }
1155
+
1156
+ const rpc = new RPCChannel<typeof workerMethods, MainAPI>(io, {
1157
+ expose: workerMethods
1158
+ })
1159
+
1160
+ const mainAPI = rpc.getAPI()
1161
+
1162
+ // Call back to main process
1163
+ await mainAPI.showNotification("Hello from worker!")
1164
+ ```
1165
+
1166
+ **Electron Features:**
1167
+
1168
+ - **Type-safe IPC**: Full TypeScript support across Renderer ↔ Main ↔ Utility Process
1169
+ - **Bidirectional**: All processes can expose and call APIs
1170
+ - **Secure**: Works with `contextIsolation: true` (recommended)
1171
+ - **Multiple Patterns**: Supports both IPC and Utility Process communication
1172
+ - **Nested API Support**: Full support for nested method calls like `api.math.add()`
1173
+
1174
+ **Learn more:** [Electron Documentation](https://www.electronjs.org/docs/latest/)
1175
+
1176
+ ### Relay Example
1177
+
1178
+ The `createRelay` function creates a transparent bidirectional relay between two IoInterfaces. This is useful when you want to connect two different transport layers without the intermediary process knowing the API details.
1179
+
1180
+ A common use case is connecting a Renderer process to an external Node.js process through Electron's Main process:
1181
+
1182
+ ```
1183
+ Renderer (IPC) → Main (relay) → External Node Process (stdio)
1184
+ ```
1185
+
1186
+ With relay, Main acts as a transparent byte pipe - it forwards messages without parsing them.
1187
+
1188
+ #### Main Process (with relay)
1189
+
1190
+ ```ts title="main.ts"
1191
+ import { spawn } from "child_process"
1192
+ import { createRelay, NodeIo } from "kkrpc"
1193
+ import { ElectronIpcMainIO } from "kkrpc/electron-ipc"
1194
+
1195
+ // Spawn external Node.js process
1196
+ const worker = spawn("node", ["./worker.js"])
1197
+
1198
+ // Create relay: IPC channel "worker-relay" <-> stdio
1199
+ const relay = createRelay(
1200
+ new ElectronIpcMainIO(ipcMain, webContents, "worker-relay"),
1201
+ new NodeIo(worker.stdout, worker.stdin)
1202
+ )
1203
+
1204
+ // Cleanup when done
1205
+ app.on("window-all-closed", () => {
1206
+ relay.destroy()
1207
+ worker.kill()
1208
+ })
1209
+ ```
1210
+
1211
+ #### Renderer Process
1212
+
1213
+ ```ts title="renderer.ts"
1214
+ import { ElectronIpcRendererIO, RPCChannel } from "kkrpc/electron-ipc"
1215
+
1216
+ // Connect via the relay channel (not the default "kkrpc-ipc" channel)
1217
+ const io = new ElectronIpcRendererIO("worker-relay")
1218
+ const rpc = new RPCChannel<{}, WorkerAPI>(io)
1219
+ const workerAPI = rpc.getAPI()
1220
+
1221
+ // Calls go directly to the external worker process
1222
+ const result = await workerAPI.calculate(42)
1223
+ ```
1224
+
1225
+ #### External Worker Process
1226
+
1227
+ ```ts title="worker.ts"
1228
+ import { NodeIo, RPCChannel } from "kkrpc"
1229
+
1230
+ const io = new NodeIo(process.stdin, process.stdout)
1231
+ const rpc = new RPCChannel<WorkerAPI, {}>(io, {
1232
+ expose: {
1233
+ calculate: async (n: number) => n * 2
1234
+ }
1235
+ })
1236
+ ```
1237
+
1238
+ **Relay Scenarios:**
1239
+
1240
+ | Scenario | From | Through | To | Use Case |
1241
+ | ------------------------------- | ----------------------- | ---------------------- | -------- | -------------------------------------- |
1242
+ | **Renderer → External Process** | `ElectronIpcRendererIO` | Main (`createRelay`) | `NodeIo` | Call external Node.js/Bun/Deno scripts |
1243
+ | **Browser → Server Process** | `WebSocketClientIO` | Server (`createRelay`) | `NodeIo` | Browser to shell process via WebSocket |
1244
+ | **Worker → External Process** | `WorkerChildIO` | Main (`createRelay`) | `NodeIo` | Web Worker to external script |
1245
+
1246
+ **Benefits:**
1247
+
1248
+ - **Transparent**: Intermediary doesn't need to know the API
1249
+ - **Clean separation**: Main doesn't expose worker methods
1250
+ - **Multiple channels**: Can create multiple relays on different IPC channels
1251
+ - **Composable**: Can chain relays through multiple processes
1252
+
737
1253
  ## 🆚 Comparison with Alternatives
738
1254
 
739
1255
  <div align="center">
740
1256
 
741
- | Feature | kkrpc | tRPC | Comlink |
742
- |---------|-------|------|---------|
743
- | **Cross-runtime** | ✅ Node.js, Deno, Bun, Browser | ❌ Node.js/Browser only | ❌ Browser only |
744
- | **Bidirectional** | ✅ Both sides can call APIs | ❌ Client calls server only | ✅ Both sides can call APIs |
745
- | **Type Safety** | ✅ Full TypeScript support | ✅ Full TypeScript support | ✅ TypeScript support |
746
- | **Transport Layers** | ✅ stdio, HTTP, WebSocket, postMessage, Chrome Extension | ❌ HTTP only | ❌ postMessage only |
747
- | **Error Preservation** | ✅ Complete error objects | ⚠️ Limited error serialization | ⚠️ Limited error serialization |
748
- | **Property Access** | ✅ Remote getters/setters | ❌ Methods only | ❌ Methods only |
749
- | **Zero Config** | ✅ No code generation | ✅ No code generation | ✅ No code generation |
750
- | **Callbacks** | ✅ Function parameters | ❌ No callbacks | ✅ Function parameters |
751
- | **Transferable Objects** | ✅ Zero-copy transfers (40-100x faster) | ❌ Not supported | ✅ Basic support |
1257
+ | Feature | kkrpc | tRPC | Comlink |
1258
+ | ------------------------ | ------------------------------------------------------------------ | ------------------------------ | ------------------------------ |
1259
+ | **Cross-runtime** | ✅ Node.js, Deno, Bun, Browser | ❌ Node.js/Browser only | ❌ Browser only |
1260
+ | **Bidirectional** | ✅ Both sides can call APIs | ❌ Client calls server only | ✅ Both sides can call APIs |
1261
+ | **Type Safety** | ✅ Full TypeScript support | ✅ Full TypeScript support | ✅ TypeScript support |
1262
+ | **Transport Layers** | ✅ stdio, HTTP, WebSocket, postMessage, Chrome Extension, Electron | ❌ HTTP only | ❌ postMessage only |
1263
+ | **Error Preservation** | ✅ Complete error objects | ⚠️ Limited error serialization | ⚠️ Limited error serialization |
1264
+ | **Property Access** | ✅ Remote getters/setters | ❌ Methods only | ❌ Methods only |
1265
+ | **Zero Config** | ✅ No code generation | ✅ No code generation | ✅ No code generation |
1266
+ | **Callbacks** | ✅ Function parameters | ❌ No callbacks | ✅ Function parameters |
1267
+ | **Transferable Objects** | ✅ Zero-copy transfers (40-100x faster) | ❌ Not supported | ✅ Basic support |
752
1268
 
753
1269
  </div>
754
1270
 
@@ -787,13 +1303,13 @@ I provided a sample tauri app in `examples/tauri-demo`.
787
1303
 
788
1304
  <div align="center">
789
1305
 
790
- | Platform | Package | Link |
791
- |----------|---------|------|
792
- | **NPM** | `kkrpc` | [![NPM](https://img.shields.io/badge/npm-kkrpc-red?style=flat-square&logo=npm)](https://www.npmjs.com/package/kkrpc) |
793
- | **JSR** | `@kunkun/kkrpc` | [![JSR](https://img.shields.io/badge/jsr-@kunkun/kkrpc-blue?style=flat-square&logo=deno)](https://jsr.io/@kunkun/kkrpc) |
794
- | **GitHub** | Repository | [![GitHub](https://img.shields.io/badge/github-kkrpc-black?style=flat-square&logo=github)](https://github.com/kunkunsh/kkrpc) |
795
- | **Docs** | Typedoc | [![Docs](https://img.shields.io/badge/docs-typedoc-blue?style=flat-square&logo=typescript)](https://kunkunsh.github.io/kkrpc/) |
796
- | **Examples** | Code Samples | [![Examples](https://img.shields.io/badge/examples-code-green?style=flat-square&logo=github)](https://github.com/kunkunsh/kkrpc/tree/main/examples) |
1306
+ | Platform | Package | Link |
1307
+ | ------------ | --------------- | --------------------------------------------------------------------------------------------------------------------------------------------------- |
1308
+ | **NPM** | `kkrpc` | [![NPM](https://img.shields.io/badge/npm-kkrpc-red?style=flat-square&logo=npm)](https://www.npmjs.com/package/kkrpc) |
1309
+ | **JSR** | `@kunkun/kkrpc` | [![JSR](https://img.shields.io/badge/jsr-@kunkun/kkrpc-blue?style=flat-square&logo=deno)](https://jsr.io/@kunkun/kkrpc) |
1310
+ | **GitHub** | Repository | [![GitHub](https://img.shields.io/badge/github-kkrpc-black?style=flat-square&logo=github)](https://github.com/kunkunsh/kkrpc) |
1311
+ | **Docs** | Typedoc | [![Docs](https://img.shields.io/badge/docs-typedoc-blue?style=flat-square&logo=typescript)](https://kunkunsh.github.io/kkrpc/) |
1312
+ | **Examples** | Code Samples | [![Examples](https://img.shields.io/badge/examples-code-green?style=flat-square&logo=github)](https://github.com/kunkunsh/kkrpc/tree/main/examples) |
797
1313
 
798
1314
  </div>
799
1315