kkrpc 0.4.0 → 0.6.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +446 -36
- package/dist/browser-mod.cjs +1 -845
- package/dist/browser-mod.d.cts +48 -46
- package/dist/browser-mod.d.cts.map +1 -0
- package/dist/browser-mod.d.ts +48 -46
- package/dist/browser-mod.d.ts.map +1 -0
- package/dist/browser-mod.js +2 -160
- package/dist/browser-mod.js.map +1 -0
- package/dist/channel-BYtPphRu.js +7 -0
- package/dist/channel-BYtPphRu.js.map +1 -0
- package/dist/channel-C92Q3vK-.d.ts +150 -0
- package/dist/channel-C92Q3vK-.d.ts.map +1 -0
- package/dist/channel-D3yeLUXA.cjs +6 -0
- package/dist/channel-QTVxXCE5.d.cts +150 -0
- package/dist/channel-QTVxXCE5.d.cts.map +1 -0
- package/dist/chrome-extension.cjs +1 -667
- package/dist/chrome-extension.d.cts +20 -23
- package/dist/chrome-extension.d.cts.map +1 -0
- package/dist/chrome-extension.d.ts +20 -23
- package/dist/chrome-extension.d.ts.map +1 -0
- package/dist/chrome-extension.js +2 -85
- package/dist/chrome-extension.js.map +1 -0
- package/dist/chunk-DjWAcSYV.cjs +1 -0
- package/dist/deno-BzNLlX8S.d.ts +21 -0
- package/dist/deno-BzNLlX8S.d.ts.map +1 -0
- package/dist/deno-DAHG1vvV.js +2 -0
- package/dist/deno-DAHG1vvV.js.map +1 -0
- package/dist/deno-DjRflDaL.cjs +1 -0
- package/dist/deno-mod.cjs +1 -612
- package/dist/deno-mod.d.cts +5 -18
- package/dist/deno-mod.d.ts +5 -18
- package/dist/deno-mod.js +1 -10
- package/dist/deno-noilmrf7.d.cts +21 -0
- package/dist/deno-noilmrf7.d.cts.map +1 -0
- package/dist/http-5KkjLA6X.js +2 -0
- package/dist/http-5KkjLA6X.js.map +1 -0
- package/dist/http-Cvnz7K2R.d.cts +37 -0
- package/dist/http-Cvnz7K2R.d.cts.map +1 -0
- package/dist/http-DpCLmXI6.cjs +1 -0
- package/dist/http-xFcyKRFw.d.ts +37 -0
- package/dist/http-xFcyKRFw.d.ts.map +1 -0
- package/dist/http.cjs +1 -697
- package/dist/http.d.cts +10 -7
- package/dist/http.d.cts.map +1 -0
- package/dist/http.d.ts +10 -7
- package/dist/http.d.ts.map +1 -0
- package/dist/http.js +2 -26
- package/dist/http.js.map +1 -0
- package/dist/interface-Bt8kzlyu.d.ts +102 -0
- package/dist/interface-Bt8kzlyu.d.ts.map +1 -0
- package/dist/interface-DIWzRMw1.d.cts +102 -0
- package/dist/interface-DIWzRMw1.d.cts.map +1 -0
- package/dist/mod.cjs +3 -1004
- package/dist/mod.d.cts +267 -57
- package/dist/mod.d.cts.map +1 -0
- package/dist/mod.d.ts +267 -57
- package/dist/mod.d.ts.map +1 -0
- package/dist/mod.js +4 -208
- package/dist/mod.js.map +1 -0
- package/dist/socketio.cjs +1 -0
- package/dist/socketio.d.cts +44 -0
- package/dist/socketio.d.cts.map +1 -0
- package/dist/socketio.d.ts +44 -0
- package/dist/socketio.d.ts.map +1 -0
- package/dist/socketio.js +2 -0
- package/dist/socketio.js.map +1 -0
- package/dist/tauri-BAorUr9n.d.ts +47 -0
- package/dist/tauri-BAorUr9n.d.ts.map +1 -0
- package/dist/tauri-C7MVgjRt.js +2 -0
- package/dist/tauri-C7MVgjRt.js.map +1 -0
- package/dist/tauri-DJegDPWN.cjs +1 -0
- package/dist/tauri-DwFX963h.d.cts +47 -0
- package/dist/tauri-DwFX963h.d.cts.map +1 -0
- package/dist/transfer-handlers-jwQTY0rF.d.ts +51 -0
- package/dist/transfer-handlers-jwQTY0rF.d.ts.map +1 -0
- package/dist/transfer-handlers-zy5mMRny.d.cts +51 -0
- package/dist/transfer-handlers-zy5mMRny.d.cts.map +1 -0
- package/dist/utils-BQ7rl7lY.d.ts +9 -0
- package/dist/utils-BQ7rl7lY.d.ts.map +1 -0
- package/dist/utils-DsPDtDlJ.d.cts +9 -0
- package/dist/utils-DsPDtDlJ.d.cts.map +1 -0
- package/package.json +65 -4
- package/dist/channel-B27IYR-w.d.cts +0 -218
- package/dist/channel-B27IYR-w.d.ts +0 -218
- package/dist/chunk-4HW5GG4Z.js +0 -26
- package/dist/chunk-H4MEJ5S3.js +0 -556
- package/dist/chunk-KZFPA2BM.js +0 -109
- package/dist/chunk-SZGZ2RBM.js +0 -94
- package/dist/http-Bmw5laGn.d.cts +0 -33
- package/dist/http-Oe0LUTM7.d.ts +0 -33
- package/dist/tauri-Dw5KiKI3.d.cts +0 -38
- package/dist/tauri-hhlO_PlO.d.ts +0 -38
- package/dist/utils-B1qZZBwh.d.cts +0 -7
- package/dist/utils-B1qZZBwh.d.ts +0 -7
package/README.md
CHANGED
|
@@ -1,49 +1,109 @@
|
|
|
1
|
-
|
|
1
|
+
<div align="center">
|
|
2
2
|
|
|
3
|
-
|
|
3
|
+
|
|
4
|
+
# 🚀 kkrpc
|
|
5
|
+
|
|
6
|
+
## TypeScript-First RPC Library
|
|
7
|
+
|
|
8
|
+
[](https://www.npmjs.com/package/kkrpc)
|
|
9
|
+
[](https://jsr.io/@kunkun/kkrpc)
|
|
10
|
+
[](https://github.com/kunkunsh/kkrpc/blob/main/LICENSE)
|
|
11
|
+
[](https://www.npmjs.com/package/kkrpc)
|
|
12
|
+
[](https://github.com/kunkunsh/kkrpc)
|
|
13
|
+
[](https://kunkunsh.github.io/kkrpc/)
|
|
14
|
+
[](https://excalidraw.com/#json=xp6GbAJVAx3nU-h3PhaxW,oYBNvYmCRsQ2XR3MQo73Ug)
|
|
15
|
+
|
|
16
|
+
</div>
|
|
17
|
+
|
|
18
|
+
> This project was created for building extension system for a Tauri app ([kunkun](https://github.com/kunkunsh/kunkun)).
|
|
4
19
|
>
|
|
5
20
|
> It can potentially be used in other types of apps, so I open sourced it as a standalone package.
|
|
6
21
|
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
22
|
+
**Seamless bi-directional communication between processes, workers, and contexts**
|
|
23
|
+
|
|
24
|
+
Call remote functions as if they were local, with full TypeScript type safety and autocompletion support.
|
|
25
|
+
|
|
26
|
+
**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
|
+
|
|
28
|
+
[**Quick Start**](#-quick-start) • [**Documentation**](https://kunkunsh.github.io/kkrpc/) • [**Examples**](#-examples) • [**API Reference**](https://jsr.io/@kunkun/kkrpc/doc)
|
|
29
|
+
|
|
30
|
+
<div align="center">
|
|
10
31
|
|
|
11
|
-
|
|
12
|
-
|
|
32
|
+
<img src="https://imgur.com/vR3Lmv0.png" style="max-height: 200px; margin: 10px;"/>
|
|
33
|
+
<img src="https://i.imgur.com/zmOHNfu.png" style="max-height: 250px; margin: 10px;"/>
|
|
34
|
+
<img src="https://imgur.com/u728aVv.png" style="max-height: 400px; margin: 10px;"/>
|
|
35
|
+
<img src="https://i.imgur.com/Gu7jH1v.png" style="max-height: 300px; margin: 10px;"/>
|
|
13
36
|
|
|
14
|
-
|
|
15
|
-
- [NPM Package](https://www.npmjs.com/package/kkrpc)
|
|
16
|
-
- [Documentation by JSR](https://jsr.io/@kunkun/kkrpc/doc)
|
|
17
|
-
- [Typedoc Documentation](https://kunkunsh.github.io/kkrpc/)
|
|
37
|
+
</div>
|
|
18
38
|
|
|
19
|
-
|
|
39
|
+
---
|
|
20
40
|
|
|
21
|
-
|
|
22
|
-
<img src="https://i.imgur.com/zmOHNfu.png" style="max-height: 250px;"/>
|
|
23
|
-
<img src="https://imgur.com/u728aVv.png" style="max-height: 400px;"/>
|
|
24
|
-
<img src="https://i.imgur.com/Gu7jH1v.png" style="max-height: 300px;"/>
|
|
41
|
+
## 🌟 Why kkrpc?
|
|
25
42
|
|
|
26
|
-
|
|
43
|
+
kkrpc stands out in the crowded RPC landscape by offering **true cross-runtime compatibility** without sacrificing type safety or developer experience. Unlike tRPC (HTTP-only) or Comlink (browser-only), kkrpc enables seamless communication across Node.js, Deno, Bun, and browser environments.
|
|
44
|
+
|
|
45
|
+
## ✨ Features
|
|
46
|
+
|
|
47
|
+
<div align="center">
|
|
48
|
+
|
|
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) |
|
|
62
|
+
|
|
63
|
+
</div>
|
|
64
|
+
|
|
65
|
+
## 🌍 Supported Environments
|
|
66
|
+
|
|
67
|
+
<div align="center">
|
|
68
|
+
|
|
69
|
+
```mermaid
|
|
70
|
+
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
|
|
91
|
+
```
|
|
27
92
|
|
|
28
|
-
|
|
29
|
-
- **Type-safe remote calls**: Full TypeScript inference and IDE autocompletion support
|
|
30
|
-
- **Bidirectional communication**: Both endpoints can expose and call APIs simultaneously
|
|
31
|
-
- **Property access**: Remote property getters and setters with dot notation (`await api.prop`, `api.prop = value`)
|
|
32
|
-
- **Enhanced error preservation**: Complete error object preservation across RPC boundaries including stack traces, causes, and custom properties
|
|
33
|
-
- **Multiple transport protocols**: stdio, HTTP, WebSocket, postMessage, Chrome extensions
|
|
34
|
-
- **Callback support**: Remote functions can accept callback functions as parameters
|
|
35
|
-
- **Nested object calls**: Deep method chaining like `api.math.operations.calculate()`
|
|
36
|
-
- **Automatic serialization**: Intelligent detection between JSON and superjson formats
|
|
37
|
-
- **Zero configuration**: No schema files or code generation required
|
|
93
|
+
</div>
|
|
38
94
|
|
|
39
|
-
|
|
95
|
+
### 📡 Transport Protocols
|
|
40
96
|
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
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 |
|
|
47
107
|
|
|
48
108
|
The core of **kkrpc** design is in `RPCChannel` and `IoInterface`.
|
|
49
109
|
|
|
@@ -99,9 +159,64 @@ const rpc = new RPCChannel(io, {
|
|
|
99
159
|
|
|
100
160
|
For backward compatibility, the receiving side will automatically detect the serialization format so older clients can communicate with newer servers and vice versa.
|
|
101
161
|
|
|
102
|
-
##
|
|
162
|
+
## 🚀 Quick Start
|
|
163
|
+
|
|
164
|
+
### Installation
|
|
165
|
+
|
|
166
|
+
<div align="center">
|
|
167
|
+
|
|
168
|
+
```bash
|
|
169
|
+
# npm
|
|
170
|
+
npm install kkrpc
|
|
171
|
+
|
|
172
|
+
# yarn
|
|
173
|
+
yarn add kkrpc
|
|
174
|
+
|
|
175
|
+
# pnpm
|
|
176
|
+
pnpm add kkrpc
|
|
177
|
+
|
|
178
|
+
# deno
|
|
179
|
+
import { RPCChannel } from "jsr:@kunkun/kkrpc"
|
|
180
|
+
```
|
|
181
|
+
|
|
182
|
+
</div>
|
|
183
|
+
|
|
184
|
+
### Basic Example
|
|
185
|
+
|
|
186
|
+
<div align="center">
|
|
187
|
+
|
|
188
|
+
```typescript
|
|
189
|
+
// server.ts
|
|
190
|
+
import { RPCChannel, NodeIo } from "kkrpc"
|
|
191
|
+
|
|
192
|
+
const api = {
|
|
193
|
+
greet: (name: string) => `Hello, ${name}!`,
|
|
194
|
+
add: (a: number, b: number) => a + b
|
|
195
|
+
}
|
|
196
|
+
|
|
197
|
+
const rpc = new RPCChannel(new NodeIo(process.stdin, process.stdout), {
|
|
198
|
+
expose: api
|
|
199
|
+
})
|
|
200
|
+
```
|
|
201
|
+
|
|
202
|
+
```typescript
|
|
203
|
+
// client.ts
|
|
204
|
+
import { RPCChannel, NodeIo } from "kkrpc"
|
|
205
|
+
import { spawn } from "child_process"
|
|
206
|
+
|
|
207
|
+
const worker = spawn("deno", ["run", "server.ts"])
|
|
208
|
+
const rpc = new RPCChannel(new NodeIo(worker.stdout, worker.stdin))
|
|
209
|
+
const api = rpc.getAPI<typeof api>()
|
|
210
|
+
|
|
211
|
+
console.log(await api.greet("World")) // "Hello, World!"
|
|
212
|
+
console.log(await api.add(5, 3)) // 8
|
|
213
|
+
```
|
|
103
214
|
|
|
104
|
-
|
|
215
|
+
</div>
|
|
216
|
+
|
|
217
|
+
## 📚 Examples
|
|
218
|
+
|
|
219
|
+
Below are simple examples to get you started quickly.
|
|
105
220
|
|
|
106
221
|
### Stdio Example
|
|
107
222
|
|
|
@@ -223,6 +338,205 @@ const sum = await api.add(1, 2)
|
|
|
223
338
|
expect(sum).toBe(3)
|
|
224
339
|
```
|
|
225
340
|
|
|
341
|
+
### Transferable Objects Example
|
|
342
|
+
|
|
343
|
+
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
|
+
|
|
345
|
+
```ts
|
|
346
|
+
import { RPCChannel, WorkerParentIO, transfer } from "kkrpc/browser"
|
|
347
|
+
|
|
348
|
+
const worker = new Worker("worker.js")
|
|
349
|
+
const io = new WorkerParentIO(worker)
|
|
350
|
+
const rpc = new RPCChannel(io)
|
|
351
|
+
const api = rpc.getAPI<{
|
|
352
|
+
processBuffer(buffer: ArrayBuffer): Promise<number>
|
|
353
|
+
generateData(size: number): Promise<ArrayBuffer>
|
|
354
|
+
}>()
|
|
355
|
+
|
|
356
|
+
// Create a large buffer (10MB)
|
|
357
|
+
const buffer = new ArrayBuffer(10 * 1024 * 1024)
|
|
358
|
+
console.log("Before transfer:", buffer.byteLength) // 10485760
|
|
359
|
+
|
|
360
|
+
// Transfer buffer to worker (zero-copy)
|
|
361
|
+
const result = await api.processBuffer(transfer(buffer, [buffer]))
|
|
362
|
+
console.log("Worker processed:", result, "bytes")
|
|
363
|
+
|
|
364
|
+
// Buffer is now neutered (transferred ownership)
|
|
365
|
+
console.log("After transfer:", buffer.byteLength) // 0
|
|
366
|
+
|
|
367
|
+
// Get data back from worker (also transferred)
|
|
368
|
+
const newBuffer = await api.generateData(5 * 1024 * 1024)
|
|
369
|
+
console.log("Received from worker:", newBuffer.byteLength) // 5242880
|
|
370
|
+
```
|
|
371
|
+
|
|
372
|
+
### Hono WebSocket Example
|
|
373
|
+
|
|
374
|
+
Hono WebSocket adapter provides seamless integration with the Hono framework's high-performance WebSocket support.
|
|
375
|
+
|
|
376
|
+
#### `server.ts`
|
|
377
|
+
|
|
378
|
+
```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'
|
|
383
|
+
|
|
384
|
+
const app = new Hono()
|
|
385
|
+
|
|
386
|
+
app.get('/ws', upgradeWebSocket(() => {
|
|
387
|
+
return createHonoWebSocketHandler<API>({
|
|
388
|
+
expose: apiMethods
|
|
389
|
+
})
|
|
390
|
+
}))
|
|
391
|
+
|
|
392
|
+
const server = Bun.serve({
|
|
393
|
+
port: 3000,
|
|
394
|
+
fetch: app.fetch,
|
|
395
|
+
websocket
|
|
396
|
+
})
|
|
397
|
+
|
|
398
|
+
console.log(`Server running on port ${server.port}`)
|
|
399
|
+
```
|
|
400
|
+
|
|
401
|
+
#### `client.ts`
|
|
402
|
+
|
|
403
|
+
```ts
|
|
404
|
+
import { WebSocketClientIO, RPCChannel } from 'kkrpc'
|
|
405
|
+
import { apiMethods, type API } from './api'
|
|
406
|
+
|
|
407
|
+
const clientIO = new WebSocketClientIO({
|
|
408
|
+
url: 'ws://localhost:3000/ws'
|
|
409
|
+
})
|
|
410
|
+
|
|
411
|
+
const clientRPC = new RPCChannel<API, API>(clientIO, {
|
|
412
|
+
expose: apiMethods
|
|
413
|
+
})
|
|
414
|
+
|
|
415
|
+
const api = clientRPC.getAPI()
|
|
416
|
+
|
|
417
|
+
// Test basic RPC calls
|
|
418
|
+
console.log(await api.add(5, 3)) // 8
|
|
419
|
+
console.log(await api.echo("Hello from Hono!")) // "Hello from Hono!"
|
|
420
|
+
|
|
421
|
+
// Test nested API calls
|
|
422
|
+
console.log(await api.math.grade2.multiply(4, 6)) // 24
|
|
423
|
+
|
|
424
|
+
// Test property access
|
|
425
|
+
console.log(await api.counter) // 42
|
|
426
|
+
console.log(await api.nested.value) // "hello world"
|
|
427
|
+
|
|
428
|
+
clientIO.destroy()
|
|
429
|
+
```
|
|
430
|
+
|
|
431
|
+
**Hono WebSocket Features:**
|
|
432
|
+
- **High Performance**: Built on Hono's ultra-fast WebSocket implementation
|
|
433
|
+
- **Cross-runtime**: Works across Bun, Deno, Node.js, and Cloudflare Workers
|
|
434
|
+
- **Type-safe**: Full TypeScript support with Hono integration
|
|
435
|
+
- **Bidirectional**: Both client and server can expose APIs
|
|
436
|
+
- **Framework Integration**: Seamless integration with Hono's middleware ecosystem
|
|
437
|
+
|
|
438
|
+
**Learn more:** [Hono WebSocket Documentation](https://hono.dev/docs/helpers/websocket)
|
|
439
|
+
|
|
440
|
+
### Elysia WebSocket Example
|
|
441
|
+
|
|
442
|
+
Elysia WebSocket adapter provides seamless integration with the modern TypeScript-first Elysia framework and its uWebSocket-powered WebSocket support.
|
|
443
|
+
|
|
444
|
+
#### `server.ts`
|
|
445
|
+
|
|
446
|
+
```ts
|
|
447
|
+
import { Elysia } from 'elysia'
|
|
448
|
+
import { ElysiaWebSocketServerIO, RPCChannel } from 'kkrpc'
|
|
449
|
+
import { apiMethods, type API } from './api'
|
|
450
|
+
|
|
451
|
+
// Extend API for Elysia-specific features
|
|
452
|
+
interface ElysiaAPI extends API {
|
|
453
|
+
getConnectionInfo(): Promise<{
|
|
454
|
+
remoteAddress: string | undefined
|
|
455
|
+
query: Record<string, string>
|
|
456
|
+
headers: Record<string, string>
|
|
457
|
+
}>
|
|
458
|
+
}
|
|
459
|
+
|
|
460
|
+
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')
|
|
484
|
+
```
|
|
485
|
+
|
|
486
|
+
#### `client.ts`
|
|
487
|
+
|
|
488
|
+
```ts
|
|
489
|
+
import { ElysiaWebSocketClientIO, RPCChannel } from 'kkrpc'
|
|
490
|
+
import { apiMethods, type API } from './api'
|
|
491
|
+
|
|
492
|
+
const clientIO = new ElysiaWebSocketClientIO('ws://localhost:3000/rpc')
|
|
493
|
+
const clientRPC = new RPCChannel<API, any>(clientIO, {
|
|
494
|
+
expose: apiMethods
|
|
495
|
+
})
|
|
496
|
+
|
|
497
|
+
const api = clientRPC.getAPI()
|
|
498
|
+
|
|
499
|
+
// Test basic RPC calls
|
|
500
|
+
console.log(await api.add(5, 3)) // 8
|
|
501
|
+
console.log(await api.echo("Hello from Elysia!")) // "Hello from Elysia!"
|
|
502
|
+
|
|
503
|
+
// Test nested API calls
|
|
504
|
+
console.log(await api.math.grade1.add(10, 20)) // 30
|
|
505
|
+
console.log(await api.math.grade3.divide(20, 4)) // 5
|
|
506
|
+
|
|
507
|
+
// Test Elysia-specific features
|
|
508
|
+
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)
|
|
512
|
+
|
|
513
|
+
clientIO.destroy()
|
|
514
|
+
```
|
|
515
|
+
|
|
516
|
+
**Elysia WebSocket Features:**
|
|
517
|
+
- **Modern Framework**: Built on Elysia's TypeScript-first design
|
|
518
|
+
- **Ultra-fast**: Powered by uWebSocket for maximum performance
|
|
519
|
+
- **Rich Metadata**: Access to connection info, query params, and headers
|
|
520
|
+
- **Type-safe**: Full TypeScript inference and autocompletion
|
|
521
|
+
- **Runtime Flexible**: Works across Bun, Node.js, and Deno
|
|
522
|
+
- **Developer Experience**: Clean API with factory functions
|
|
523
|
+
|
|
524
|
+
**Learn more:** [Elysia WebSocket Documentation](https://elysiajs.com/patterns/websocket)
|
|
525
|
+
|
|
526
|
+
**Key Benefits:**
|
|
527
|
+
- **Zero-copy performance**: No serialization/deserialization overhead
|
|
528
|
+
- **Memory efficient**: Ownership transfers without copying
|
|
529
|
+
- **Automatic fallback**: Graceful degradation for non-transferable transports
|
|
530
|
+
- **Type-safe**: Full TypeScript support
|
|
531
|
+
|
|
532
|
+
**Supported Transferable Types:**
|
|
533
|
+
- `ArrayBuffer` - Binary data buffers
|
|
534
|
+
- `MessagePort` - Communication channels
|
|
535
|
+
- `ImageBitmap` - Decoded image data
|
|
536
|
+
- `OffscreenCanvas` - Off-screen canvas rendering
|
|
537
|
+
- `ReadableStream`/`WritableStream` - Streaming data
|
|
538
|
+
- And more... [See MDN](https://developer.mozilla.org/en-US/docs/Web/API/Web_Workers_API/Transferable_objects)
|
|
539
|
+
|
|
226
540
|
### HTTP Example
|
|
227
541
|
|
|
228
542
|
Codesandbox: https://codesandbox.io/p/live/4a349334-0b04-4352-89f9-cf1955553ae7
|
|
@@ -419,3 +733,99 @@ async function spawnCmd(runtime: "deno" | "bun" | "node") {
|
|
|
419
733
|
I provided a sample tauri app in `examples/tauri-demo`.
|
|
420
734
|
|
|
421
735
|

|
|
736
|
+
|
|
737
|
+
## 🆚 Comparison with Alternatives
|
|
738
|
+
|
|
739
|
+
<div align="center">
|
|
740
|
+
|
|
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 |
|
|
752
|
+
|
|
753
|
+
</div>
|
|
754
|
+
|
|
755
|
+
### When to choose kkrpc
|
|
756
|
+
|
|
757
|
+
- **Cross-process communication**: Need to communicate between different runtimes (Node.js ↔ Deno, Browser ↔ Node.js, etc.)
|
|
758
|
+
- **Extension systems**: Building plugin architectures or extension systems
|
|
759
|
+
- **Tauri applications**: Communicating between Tauri frontend and backend processes
|
|
760
|
+
- **Chrome extensions**: Complex communication between content scripts, background pages, and popups
|
|
761
|
+
- **Multi-worker architectures**: Coordinating multiple web workers with different responsibilities
|
|
762
|
+
- **Desktop applications**: Electron/Tauri apps with multiple processes
|
|
763
|
+
|
|
764
|
+
### When to choose tRPC
|
|
765
|
+
|
|
766
|
+
- **REST API replacement**: Building type-safe APIs for web applications
|
|
767
|
+
- **HTTP-only communication**: When you only need HTTP-based communication
|
|
768
|
+
- **React/Next.js integration**: When you need tight integration with React ecosystem
|
|
769
|
+
- **Database-driven APIs**: When building traditional client-server applications
|
|
770
|
+
|
|
771
|
+
### When to choose Comlink
|
|
772
|
+
|
|
773
|
+
- **Browser-only applications**: Simple web worker communication in browsers
|
|
774
|
+
- **Lightweight needs**: When you only need basic postMessage abstraction
|
|
775
|
+
- **No cross-runtime requirements**: When all your code runs in browsers
|
|
776
|
+
- **Simple worker patterns**: When you don't need advanced features like property access
|
|
777
|
+
|
|
778
|
+
## 🔍 Keywords & SEO
|
|
779
|
+
|
|
780
|
+
**Primary Keywords**: RPC, TypeScript, Remote Procedure Call, Type-safe, Bidirectional, Cross-runtime
|
|
781
|
+
|
|
782
|
+
**Secondary Keywords**: Node.js, Deno, Bun, Browser, Web Worker, Chrome Extension, Tauri, IPC, Inter-process Communication
|
|
783
|
+
|
|
784
|
+
**Use Cases**: Extension system, Plugin architecture, Microservices, Worker communication, Cross-context communication
|
|
785
|
+
|
|
786
|
+
## 📦 Package Information
|
|
787
|
+
|
|
788
|
+
<div align="center">
|
|
789
|
+
|
|
790
|
+
| Platform | Package | Link |
|
|
791
|
+
|----------|---------|------|
|
|
792
|
+
| **NPM** | `kkrpc` | [](https://www.npmjs.com/package/kkrpc) |
|
|
793
|
+
| **JSR** | `@kunkun/kkrpc` | [](https://jsr.io/@kunkun/kkrpc) |
|
|
794
|
+
| **GitHub** | Repository | [](https://github.com/kunkunsh/kkrpc) |
|
|
795
|
+
| **Docs** | Typedoc | [](https://kunkunsh.github.io/kkrpc/) |
|
|
796
|
+
| **Examples** | Code Samples | [](https://github.com/kunkunsh/kkrpc/tree/main/examples) |
|
|
797
|
+
|
|
798
|
+
</div>
|
|
799
|
+
|
|
800
|
+
## 🤝 Contributing
|
|
801
|
+
|
|
802
|
+
<div align="center">
|
|
803
|
+
|
|
804
|
+
**Contributions are welcome!** 🎉
|
|
805
|
+
|
|
806
|
+
Please feel free to submit a Pull Request. For major changes, please open an issue first to discuss what you would like to change.
|
|
807
|
+
|
|
808
|
+
[](https://github.com/kunkunsh/kkrpc/issues)
|
|
809
|
+
[](https://github.com/kunkunsh/kkrpc/pulls)
|
|
810
|
+
|
|
811
|
+
</div>
|
|
812
|
+
|
|
813
|
+
## 📄 License
|
|
814
|
+
|
|
815
|
+
<div align="center">
|
|
816
|
+
|
|
817
|
+
[](https://github.com/kunkunsh/kkrpc/blob/main/LICENSE)
|
|
818
|
+
|
|
819
|
+
MIT © [kunkunsh](https://github.com/kunkunsh)
|
|
820
|
+
|
|
821
|
+
</div>
|
|
822
|
+
|
|
823
|
+
---
|
|
824
|
+
|
|
825
|
+
<div align="center">
|
|
826
|
+
|
|
827
|
+
**⭐ Star this repo if it helped you!**
|
|
828
|
+
|
|
829
|
+
Made with ❤️ by the kkrpc team
|
|
830
|
+
|
|
831
|
+
</div>
|