kkrpc 0.4.0 → 0.5.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.
Files changed (94) hide show
  1. package/README.md +290 -36
  2. package/dist/browser-mod.cjs +188 -839
  3. package/dist/browser-mod.d.cts +48 -46
  4. package/dist/browser-mod.d.cts.map +1 -0
  5. package/dist/browser-mod.d.ts +48 -46
  6. package/dist/browser-mod.d.ts.map +1 -0
  7. package/dist/browser-mod.js +170 -155
  8. package/dist/browser-mod.js.map +1 -0
  9. package/dist/channel-BYtPphRu.js +743 -0
  10. package/dist/channel-BYtPphRu.js.map +1 -0
  11. package/dist/channel-C92Q3vK-.d.ts +150 -0
  12. package/dist/channel-C92Q3vK-.d.ts.map +1 -0
  13. package/dist/channel-CgIjXyNX.cjs +839 -0
  14. package/dist/channel-QTVxXCE5.d.cts +150 -0
  15. package/dist/channel-QTVxXCE5.d.cts.map +1 -0
  16. package/dist/chrome-extension.cjs +79 -663
  17. package/dist/chrome-extension.d.cts +20 -23
  18. package/dist/chrome-extension.d.cts.map +1 -0
  19. package/dist/chrome-extension.d.ts +20 -23
  20. package/dist/chrome-extension.d.ts.map +1 -0
  21. package/dist/chrome-extension.js +70 -82
  22. package/dist/chrome-extension.js.map +1 -0
  23. package/dist/chunk-CUT6urMc.cjs +30 -0
  24. package/dist/deno-BzNLlX8S.d.ts +21 -0
  25. package/dist/deno-BzNLlX8S.d.ts.map +1 -0
  26. package/dist/deno-DAHG1vvV.js +33 -0
  27. package/dist/deno-DAHG1vvV.js.map +1 -0
  28. package/dist/deno-DyicMPIa.cjs +38 -0
  29. package/dist/deno-mod.cjs +10 -612
  30. package/dist/deno-mod.d.cts +5 -18
  31. package/dist/deno-mod.d.ts +5 -18
  32. package/dist/deno-mod.js +4 -10
  33. package/dist/deno-noilmrf7.d.cts +21 -0
  34. package/dist/deno-noilmrf7.d.cts.map +1 -0
  35. package/dist/http-5KkjLA6X.js +97 -0
  36. package/dist/http-5KkjLA6X.js.map +1 -0
  37. package/dist/http-Bq1OqmJP.cjs +109 -0
  38. package/dist/http-Cvnz7K2R.d.cts +37 -0
  39. package/dist/http-Cvnz7K2R.d.cts.map +1 -0
  40. package/dist/http-xFcyKRFw.d.ts +37 -0
  41. package/dist/http-xFcyKRFw.d.ts.map +1 -0
  42. package/dist/http.cjs +18 -692
  43. package/dist/http.d.cts +10 -7
  44. package/dist/http.d.cts.map +1 -0
  45. package/dist/http.d.ts +10 -7
  46. package/dist/http.d.ts.map +1 -0
  47. package/dist/http.js +15 -21
  48. package/dist/http.js.map +1 -0
  49. package/dist/interface-Bt8kzlyu.d.ts +102 -0
  50. package/dist/interface-Bt8kzlyu.d.ts.map +1 -0
  51. package/dist/interface-DIWzRMw1.d.cts +102 -0
  52. package/dist/interface-DIWzRMw1.d.cts.map +1 -0
  53. package/dist/mod.cjs +210 -992
  54. package/dist/mod.d.cts +56 -57
  55. package/dist/mod.d.cts.map +1 -0
  56. package/dist/mod.d.ts +56 -57
  57. package/dist/mod.d.ts.map +1 -0
  58. package/dist/mod.js +187 -197
  59. package/dist/mod.js.map +1 -0
  60. package/dist/socketio.cjs +123 -0
  61. package/dist/socketio.d.cts +44 -0
  62. package/dist/socketio.d.cts.map +1 -0
  63. package/dist/socketio.d.ts +44 -0
  64. package/dist/socketio.d.ts.map +1 -0
  65. package/dist/socketio.js +121 -0
  66. package/dist/socketio.js.map +1 -0
  67. package/dist/tauri-BAorUr9n.d.ts +47 -0
  68. package/dist/tauri-BAorUr9n.d.ts.map +1 -0
  69. package/dist/tauri-C7MVgjRt.js +160 -0
  70. package/dist/tauri-C7MVgjRt.js.map +1 -0
  71. package/dist/tauri-DwFX963h.d.cts +47 -0
  72. package/dist/tauri-DwFX963h.d.cts.map +1 -0
  73. package/dist/tauri-JjaZEH0s.cjs +177 -0
  74. package/dist/transfer-handlers-BbGAQoCs.d.ts +51 -0
  75. package/dist/transfer-handlers-BbGAQoCs.d.ts.map +1 -0
  76. package/dist/transfer-handlers-ZiPAV3RZ.d.cts +51 -0
  77. package/dist/transfer-handlers-ZiPAV3RZ.d.cts.map +1 -0
  78. package/dist/utils-BQ7rl7lY.d.ts +9 -0
  79. package/dist/utils-BQ7rl7lY.d.ts.map +1 -0
  80. package/dist/utils-DsPDtDlJ.d.cts +9 -0
  81. package/dist/utils-DsPDtDlJ.d.cts.map +1 -0
  82. package/package.json +55 -4
  83. package/dist/channel-B27IYR-w.d.cts +0 -218
  84. package/dist/channel-B27IYR-w.d.ts +0 -218
  85. package/dist/chunk-4HW5GG4Z.js +0 -26
  86. package/dist/chunk-H4MEJ5S3.js +0 -556
  87. package/dist/chunk-KZFPA2BM.js +0 -109
  88. package/dist/chunk-SZGZ2RBM.js +0 -94
  89. package/dist/http-Bmw5laGn.d.cts +0 -33
  90. package/dist/http-Oe0LUTM7.d.ts +0 -33
  91. package/dist/tauri-Dw5KiKI3.d.cts +0 -38
  92. package/dist/tauri-hhlO_PlO.d.ts +0 -38
  93. package/dist/utils-B1qZZBwh.d.cts +0 -7
  94. package/dist/utils-B1qZZBwh.d.ts +0 -7
package/README.md CHANGED
@@ -1,49 +1,107 @@
1
- # kkrpc
1
+ <div align="center">
2
2
 
3
- > This project is created for building extension system for a Tauri app (https://github.com/kunkunsh/kunkun).
3
+
4
+ # 🚀 kkrpc
5
+
6
+ ## TypeScript-First RPC Library
7
+
8
+ [![NPM Version](https://img.shields.io/npm/v/kkrpc?style=for-the-badge&logo=npm)](https://www.npmjs.com/package/kkrpc)
9
+ [![JSR Version](https://img.shields.io/jsr/v/@kunkun/kkrpc?style=for-the-badge&logo=deno)](https://jsr.io/@kunkun/kkrpc)
10
+ [![License](https://img.shields.io/npm/l/kkrpc?style=for-the-badge)](https://github.com/kunkunsh/kkrpc/blob/main/LICENSE)
11
+ [![Downloads](https://img.shields.io/npm/dm/kkrpc?style=for-the-badge&logo=npm)](https://www.npmjs.com/package/kkrpc)
12
+ [![GitHub stars](https://img.shields.io/github/stars/kunkunsh/kkrpc?style=for-the-badge&logo=github)](https://github.com/kunkunsh/kkrpc)
13
+ [![Typedoc Documentation](https://img.shields.io/badge/Docs-Typedoc-blue?style=for-the-badge&logo=typescript)](https://kunkunsh.github.io/kkrpc/)
14
+ [![Excalidraw Diagrams](https://img.shields.io/badge/Diagrams-Excalidraw-orange?style=for-the-badge&logo=drawio)](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
- [![NPM Version](https://img.shields.io/npm/v/kkrpc)](https://www.npmjs.com/package/kkrpc)
8
- [![JSR Version](https://jsr.io/badges/@kunkun/kkrpc)](https://jsr.io/@kunkun/kkrpc)
9
- ![GitHub last commit](https://img.shields.io/github/last-commit/kunkunsh/kkrpc)
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">
31
+
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;"/>
36
+
37
+ </div>
10
38
 
11
- > A TypeScript-first RPC library that enables seamless bi-directional communication between processes.
12
- > Call remote functions as if they were local, with full TypeScript type safety and autocompletion support.
39
+ ---
13
40
 
14
- - [JSR Package](https://jsr.io/@kunkun/kkrpc)
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/)
41
+ ## 🌟 Why kkrpc?
18
42
 
19
- [Excalidraw Diagrams](https://excalidraw.com/#json=xp6GbAJVAx3nU-h3PhaxW,oYBNvYmCRsQ2XR3MQo73Ug)
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.
20
44
 
21
- <img src="https://imgur.com/vR3Lmv0.png" style="max-height: 200px;"/>
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;"/>
45
+ ## Features
25
46
 
26
- ## Features
47
+ <div align="center">
27
48
 
28
- - **Cross-runtime compatibility**: Works seamlessly across Node.js, Deno, Bun, browsers, and more
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
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) |
38
62
 
39
- ## Supported Environments
63
+ </div>
40
64
 
41
- - stdio: RPC over stdio between any combinations of Node.js, Deno, Bun processes
42
- - web: RPC over `postMessage` API and message channel between browser main thread and web workers, or main thread and iframe
43
- - Web Worker API (web standard) is also supported in Deno and Bun, the main thread can call functions in worker and vice versa.
44
- - http: RPC over HTTP like tRPC
45
- - supports any HTTP server (e.g. hono, bun, nodejs http, express, fastify, deno, etc.)
46
- - WebSocket: RPC over WebSocket
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
+ ```
92
+
93
+ </div>
94
+
95
+ ### 📡 Transport Protocols
96
+
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
+ | **Socket.IO** | Enhanced real-time with rooms/namespaces | All runtimes |
104
+ | **Chrome Extension** | Extension component communication | Chrome Extension contexts |
47
105
 
48
106
  The core of **kkrpc** design is in `RPCChannel` and `IoInterface`.
49
107
 
@@ -99,9 +157,64 @@ const rpc = new RPCChannel(io, {
99
157
 
100
158
  For backward compatibility, the receiving side will automatically detect the serialization format so older clients can communicate with newer servers and vice versa.
101
159
 
102
- ## Examples
160
+ ## 🚀 Quick Start
161
+
162
+ ### Installation
163
+
164
+ <div align="center">
165
+
166
+ ```bash
167
+ # npm
168
+ npm install kkrpc
169
+
170
+ # yarn
171
+ yarn add kkrpc
103
172
 
104
- Below are simple examples.
173
+ # pnpm
174
+ pnpm add kkrpc
175
+
176
+ # deno
177
+ import { RPCChannel } from "jsr:@kunkun/kkrpc"
178
+ ```
179
+
180
+ </div>
181
+
182
+ ### Basic Example
183
+
184
+ <div align="center">
185
+
186
+ ```typescript
187
+ // server.ts
188
+ import { RPCChannel, NodeIo } from "kkrpc"
189
+
190
+ const api = {
191
+ greet: (name: string) => `Hello, ${name}!`,
192
+ add: (a: number, b: number) => a + b
193
+ }
194
+
195
+ const rpc = new RPCChannel(new NodeIo(process.stdin, process.stdout), {
196
+ expose: api
197
+ })
198
+ ```
199
+
200
+ ```typescript
201
+ // client.ts
202
+ import { RPCChannel, NodeIo } from "kkrpc"
203
+ import { spawn } from "child_process"
204
+
205
+ const worker = spawn("deno", ["run", "server.ts"])
206
+ const rpc = new RPCChannel(new NodeIo(worker.stdout, worker.stdin))
207
+ const api = rpc.getAPI<typeof api>()
208
+
209
+ console.log(await api.greet("World")) // "Hello, World!"
210
+ console.log(await api.add(5, 3)) // 8
211
+ ```
212
+
213
+ </div>
214
+
215
+ ## 📚 Examples
216
+
217
+ Below are simple examples to get you started quickly.
105
218
 
106
219
  ### Stdio Example
107
220
 
@@ -223,6 +336,51 @@ const sum = await api.add(1, 2)
223
336
  expect(sum).toBe(3)
224
337
  ```
225
338
 
339
+ ### Transferable Objects Example
340
+
341
+ 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.
342
+
343
+ ```ts
344
+ import { RPCChannel, WorkerParentIO, transfer } from "kkrpc/browser"
345
+
346
+ const worker = new Worker("worker.js")
347
+ const io = new WorkerParentIO(worker)
348
+ const rpc = new RPCChannel(io)
349
+ const api = rpc.getAPI<{
350
+ processBuffer(buffer: ArrayBuffer): Promise<number>
351
+ generateData(size: number): Promise<ArrayBuffer>
352
+ }>()
353
+
354
+ // Create a large buffer (10MB)
355
+ const buffer = new ArrayBuffer(10 * 1024 * 1024)
356
+ console.log("Before transfer:", buffer.byteLength) // 10485760
357
+
358
+ // Transfer buffer to worker (zero-copy)
359
+ const result = await api.processBuffer(transfer(buffer, [buffer]))
360
+ console.log("Worker processed:", result, "bytes")
361
+
362
+ // Buffer is now neutered (transferred ownership)
363
+ console.log("After transfer:", buffer.byteLength) // 0
364
+
365
+ // Get data back from worker (also transferred)
366
+ const newBuffer = await api.generateData(5 * 1024 * 1024)
367
+ console.log("Received from worker:", newBuffer.byteLength) // 5242880
368
+ ```
369
+
370
+ **Key Benefits:**
371
+ - **Zero-copy performance**: No serialization/deserialization overhead
372
+ - **Memory efficient**: Ownership transfers without copying
373
+ - **Automatic fallback**: Graceful degradation for non-transferable transports
374
+ - **Type-safe**: Full TypeScript support
375
+
376
+ **Supported Transferable Types:**
377
+ - `ArrayBuffer` - Binary data buffers
378
+ - `MessagePort` - Communication channels
379
+ - `ImageBitmap` - Decoded image data
380
+ - `OffscreenCanvas` - Off-screen canvas rendering
381
+ - `ReadableStream`/`WritableStream` - Streaming data
382
+ - And more... [See MDN](https://developer.mozilla.org/en-US/docs/Web/API/Web_Workers_API/Transferable_objects)
383
+
226
384
  ### HTTP Example
227
385
 
228
386
  Codesandbox: https://codesandbox.io/p/live/4a349334-0b04-4352-89f9-cf1955553ae7
@@ -419,3 +577,99 @@ async function spawnCmd(runtime: "deno" | "bun" | "node") {
419
577
  I provided a sample tauri app in `examples/tauri-demo`.
420
578
 
421
579
  ![Sample Tauri App](https://i.imgur.com/nkDwRHk.png)
580
+
581
+ ## 🆚 Comparison with Alternatives
582
+
583
+ <div align="center">
584
+
585
+ | Feature | kkrpc | tRPC | Comlink |
586
+ |---------|-------|------|---------|
587
+ | **Cross-runtime** | ✅ Node.js, Deno, Bun, Browser | ❌ Node.js/Browser only | ❌ Browser only |
588
+ | **Bidirectional** | ✅ Both sides can call APIs | ❌ Client calls server only | ✅ Both sides can call APIs |
589
+ | **Type Safety** | ✅ Full TypeScript support | ✅ Full TypeScript support | ✅ TypeScript support |
590
+ | **Transport Layers** | ✅ stdio, HTTP, WebSocket, postMessage, Chrome Extension | ❌ HTTP only | ❌ postMessage only |
591
+ | **Error Preservation** | ✅ Complete error objects | ⚠️ Limited error serialization | ⚠️ Limited error serialization |
592
+ | **Property Access** | ✅ Remote getters/setters | ❌ Methods only | ❌ Methods only |
593
+ | **Zero Config** | ✅ No code generation | ✅ No code generation | ✅ No code generation |
594
+ | **Callbacks** | ✅ Function parameters | ❌ No callbacks | ✅ Function parameters |
595
+ | **Transferable Objects** | ✅ Zero-copy transfers (40-100x faster) | ❌ Not supported | ✅ Basic support |
596
+
597
+ </div>
598
+
599
+ ### When to choose kkrpc
600
+
601
+ - **Cross-process communication**: Need to communicate between different runtimes (Node.js ↔ Deno, Browser ↔ Node.js, etc.)
602
+ - **Extension systems**: Building plugin architectures or extension systems
603
+ - **Tauri applications**: Communicating between Tauri frontend and backend processes
604
+ - **Chrome extensions**: Complex communication between content scripts, background pages, and popups
605
+ - **Multi-worker architectures**: Coordinating multiple web workers with different responsibilities
606
+ - **Desktop applications**: Electron/Tauri apps with multiple processes
607
+
608
+ ### When to choose tRPC
609
+
610
+ - **REST API replacement**: Building type-safe APIs for web applications
611
+ - **HTTP-only communication**: When you only need HTTP-based communication
612
+ - **React/Next.js integration**: When you need tight integration with React ecosystem
613
+ - **Database-driven APIs**: When building traditional client-server applications
614
+
615
+ ### When to choose Comlink
616
+
617
+ - **Browser-only applications**: Simple web worker communication in browsers
618
+ - **Lightweight needs**: When you only need basic postMessage abstraction
619
+ - **No cross-runtime requirements**: When all your code runs in browsers
620
+ - **Simple worker patterns**: When you don't need advanced features like property access
621
+
622
+ ## 🔍 Keywords & SEO
623
+
624
+ **Primary Keywords**: RPC, TypeScript, Remote Procedure Call, Type-safe, Bidirectional, Cross-runtime
625
+
626
+ **Secondary Keywords**: Node.js, Deno, Bun, Browser, Web Worker, Chrome Extension, Tauri, IPC, Inter-process Communication
627
+
628
+ **Use Cases**: Extension system, Plugin architecture, Microservices, Worker communication, Cross-context communication
629
+
630
+ ## 📦 Package Information
631
+
632
+ <div align="center">
633
+
634
+ | Platform | Package | Link |
635
+ |----------|---------|------|
636
+ | **NPM** | `kkrpc` | [![NPM](https://img.shields.io/badge/npm-kkrpc-red?style=flat-square&logo=npm)](https://www.npmjs.com/package/kkrpc) |
637
+ | **JSR** | `@kunkun/kkrpc` | [![JSR](https://img.shields.io/badge/jsr-@kunkun/kkrpc-blue?style=flat-square&logo=deno)](https://jsr.io/@kunkun/kkrpc) |
638
+ | **GitHub** | Repository | [![GitHub](https://img.shields.io/badge/github-kkrpc-black?style=flat-square&logo=github)](https://github.com/kunkunsh/kkrpc) |
639
+ | **Docs** | Typedoc | [![Docs](https://img.shields.io/badge/docs-typedoc-blue?style=flat-square&logo=typescript)](https://kunkunsh.github.io/kkrpc/) |
640
+ | **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) |
641
+
642
+ </div>
643
+
644
+ ## 🤝 Contributing
645
+
646
+ <div align="center">
647
+
648
+ **Contributions are welcome!** 🎉
649
+
650
+ Please feel free to submit a Pull Request. For major changes, please open an issue first to discuss what you would like to change.
651
+
652
+ [![GitHub issues](https://img.shields.io/github/issues/kunkunsh/kkrpc?style=flat-square&logo=github)](https://github.com/kunkunsh/kkrpc/issues)
653
+ [![GitHub pull requests](https://img.shields.io/github/issues-pr/kunkunsh/kkrpc?style=flat-square&logo=github)](https://github.com/kunkunsh/kkrpc/pulls)
654
+
655
+ </div>
656
+
657
+ ## 📄 License
658
+
659
+ <div align="center">
660
+
661
+ [![License](https://img.shields.io/npm/l/kkrpc?style=flat-square)](https://github.com/kunkunsh/kkrpc/blob/main/LICENSE)
662
+
663
+ MIT © [kunkunsh](https://github.com/kunkunsh)
664
+
665
+ </div>
666
+
667
+ ---
668
+
669
+ <div align="center">
670
+
671
+ **⭐ Star this repo if it helped you!**
672
+
673
+ Made with ❤️ by the kkrpc team
674
+
675
+ </div>