kkrpc 0.0.15 → 0.0.18

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/README.md CHANGED
@@ -12,6 +12,10 @@
12
12
  - [Documentation by JSR](https://jsr.io/@kunkun/kkrpc/doc)
13
13
  - [Typedoc Documentation](https://kunkunsh.github.io/kkrpc/)
14
14
 
15
+ ![](https://imgur.com/vR3Lmv0.png)
16
+ ![](https://imgur.com/u728aVv.png)
17
+ ![](https://imgur.com/2ycWgVQ.png)
18
+
15
19
  ## Supported Environments
16
20
 
17
21
  - stdio: RPC over stdio between any combinations of Node.js, Deno, Bun processes
@@ -47,7 +51,7 @@ class RPCChannel<
47
51
  > {}
48
52
  ```
49
53
 
50
- ## Examplesr
54
+ ## Examples
51
55
 
52
56
  Below are simple examples.
53
57
 
@@ -166,3 +170,51 @@ console.log("echoResponse", echoResponse)
166
170
  const sum = await clientAPI.add(2, 3)
167
171
  console.log("Sum: ", sum)
168
172
  ```
173
+
174
+ ### Chrome Extension Example
175
+
176
+ #### `background.ts`
177
+
178
+ ```ts
179
+ import { ChromeBackgroundIO, RPCChannel } from "kkrpc"
180
+ import type { API } from "./api"
181
+
182
+ // Store RPC channels for each tab
183
+ const rpcChannels = new Map<number, RPCChannel<API, {}>>()
184
+
185
+ // Listen for tab connections
186
+ chrome.runtime.onConnect.addListener((port) => {
187
+ if (port.sender?.tab?.id) {
188
+ const tabId = port.sender.tab.id
189
+ const io = new ChromeBackgroundIO(tabId)
190
+ const rpc = new RPCChannel(io, { expose: backgroundAPI })
191
+ rpcChannels.set(tabId, rpc)
192
+
193
+ port.onDisconnect.addListener(() => {
194
+ rpcChannels.delete(tabId)
195
+ })
196
+ }
197
+ })
198
+ ```
199
+
200
+ #### `content.ts`
201
+
202
+ ```ts
203
+ import { ChromeContentIO, RPCChannel } from "kkrpc"
204
+ import type { API } from "./api"
205
+
206
+ const io = new ChromeContentIO()
207
+ const rpc = new RPCChannel<API, API>(io, {
208
+ expose: {
209
+ updateUI: async (data) => {
210
+ document.body.innerHTML = data.message
211
+ return true
212
+ }
213
+ }
214
+ })
215
+
216
+ // Get API from background script
217
+ const api = rpc.getAPI()
218
+ const data = await api.getData()
219
+ console.log(data) // { message: "Hello from background!" }
220
+ ```
@@ -20,6 +20,8 @@ var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: tru
20
20
  // browser-mod.ts
21
21
  var browser_mod_exports = {};
22
22
  __export(browser_mod_exports, {
23
+ ChromeBackgroundIO: () => ChromeBackgroundIO,
24
+ ChromeContentIO: () => ChromeContentIO,
23
25
  IframeChildIO: () => IframeChildIO,
24
26
  IframeParentIO: () => IframeParentIO,
25
27
  RPCChannel: () => RPCChannel,
@@ -117,6 +119,220 @@ var WorkerChildIO = class {
117
119
  }
118
120
  };
119
121
 
122
+ // src/adapters/chrome.ts
123
+ var DESTROY_SIGNAL2 = "__DESTROY__";
124
+ var ChromeBackgroundIO = class {
125
+ name = "chrome-background-io";
126
+ messageQueue = [];
127
+ resolveRead = null;
128
+ tabId;
129
+ handleMessage = (message, sender, _sendResponse) => {
130
+ if (sender.tab?.id !== this.tabId) return;
131
+ if (message === DESTROY_SIGNAL2) {
132
+ this.destroy();
133
+ return;
134
+ }
135
+ if (this.resolveRead) {
136
+ this.resolveRead(message);
137
+ this.resolveRead = null;
138
+ } else {
139
+ this.messageQueue.push(message);
140
+ }
141
+ };
142
+ constructor(tabId) {
143
+ this.tabId = tabId;
144
+ chrome.runtime.onMessage.addListener(this.handleMessage);
145
+ }
146
+ async read() {
147
+ if (this.messageQueue.length > 0) {
148
+ return this.messageQueue.shift() ?? null;
149
+ }
150
+ return new Promise((resolve) => {
151
+ this.resolveRead = resolve;
152
+ });
153
+ }
154
+ async write(data) {
155
+ await chrome.tabs.sendMessage(this.tabId, data);
156
+ }
157
+ destroy() {
158
+ chrome.runtime.onMessage.removeListener(this.handleMessage);
159
+ }
160
+ signalDestroy() {
161
+ this.write(DESTROY_SIGNAL2);
162
+ }
163
+ };
164
+ var ChromeContentIO = class {
165
+ name = "chrome-content-io";
166
+ messageQueue = [];
167
+ resolveRead = null;
168
+ constructor() {
169
+ chrome.runtime.onMessage.addListener(this.handleMessage);
170
+ }
171
+ handleMessage = (message, _sender, _sendResponse) => {
172
+ if (message === DESTROY_SIGNAL2) {
173
+ this.destroy();
174
+ return;
175
+ }
176
+ if (this.resolveRead) {
177
+ this.resolveRead(message);
178
+ this.resolveRead = null;
179
+ } else {
180
+ this.messageQueue.push(message);
181
+ }
182
+ };
183
+ async read() {
184
+ if (this.messageQueue.length > 0) {
185
+ return this.messageQueue.shift() ?? null;
186
+ }
187
+ return new Promise((resolve) => {
188
+ this.resolveRead = resolve;
189
+ });
190
+ }
191
+ async write(data) {
192
+ await chrome.runtime.sendMessage(data);
193
+ }
194
+ destroy() {
195
+ chrome.runtime.onMessage.removeListener(this.handleMessage);
196
+ }
197
+ signalDestroy() {
198
+ this.write(DESTROY_SIGNAL2);
199
+ }
200
+ };
201
+
202
+ // src/adapters/iframe.ts
203
+ var DESTROY_SIGNAL3 = "__DESTROY__";
204
+ var PORT_INIT_SIGNAL = "__PORT_INIT__";
205
+ var IframeParentIO = class {
206
+ /**
207
+ * @example
208
+ * ```ts
209
+ * const io = new IframeParentIO(iframeRef.contentWindow);
210
+ * const rpc = new RPCChannel(io, {
211
+ * expose: {
212
+ * add: (a: number, b: number) => Promise.resolve(a + b),
213
+ * },
214
+ * });
215
+ * ```
216
+ */
217
+ constructor(targetWindow) {
218
+ this.targetWindow = targetWindow;
219
+ this.port = null;
220
+ window.addEventListener("message", (event) => {
221
+ if (event.source !== this.targetWindow) return;
222
+ if (event.data === PORT_INIT_SIGNAL && event.ports.length > 0) {
223
+ this.port = event.ports[0];
224
+ this.port.onmessage = this.handleMessage;
225
+ while (this.messageQueue.length > 0) {
226
+ const message = this.messageQueue.shift();
227
+ if (message) this.port.postMessage(message);
228
+ }
229
+ }
230
+ });
231
+ }
232
+ name = "iframe-parent-io";
233
+ messageQueue = [];
234
+ resolveRead = null;
235
+ port = null;
236
+ handleMessage = (event) => {
237
+ const message = event.data;
238
+ if (message === DESTROY_SIGNAL3) {
239
+ this.destroy();
240
+ return;
241
+ }
242
+ if (this.resolveRead) {
243
+ this.resolveRead(message);
244
+ this.resolveRead = null;
245
+ } else {
246
+ this.messageQueue.push(message);
247
+ }
248
+ };
249
+ async read() {
250
+ if (this.messageQueue.length > 0) {
251
+ return this.messageQueue.shift() ?? null;
252
+ }
253
+ return new Promise((resolve) => {
254
+ this.resolveRead = resolve;
255
+ });
256
+ }
257
+ async write(data) {
258
+ if (!this.port) {
259
+ this.messageQueue.push(data);
260
+ return;
261
+ }
262
+ this.port.postMessage(data);
263
+ }
264
+ destroy() {
265
+ if (this.port) {
266
+ this.port.postMessage(DESTROY_SIGNAL3);
267
+ this.port.close();
268
+ }
269
+ }
270
+ signalDestroy() {
271
+ if (this.port) {
272
+ this.port.postMessage(DESTROY_SIGNAL3);
273
+ }
274
+ }
275
+ };
276
+ var IframeChildIO = class {
277
+ name = "iframe-child-io";
278
+ messageQueue = [];
279
+ resolveRead = null;
280
+ port = null;
281
+ pendingMessages = [];
282
+ initialized;
283
+ channel;
284
+ constructor() {
285
+ this.channel = new MessageChannel();
286
+ this.port = this.channel.port1;
287
+ this.port.onmessage = this.handleMessage;
288
+ window.parent.postMessage(PORT_INIT_SIGNAL, "*", [this.channel.port2]);
289
+ this.initialized = Promise.resolve();
290
+ }
291
+ handleMessage = (event) => {
292
+ const message = event.data;
293
+ if (message === DESTROY_SIGNAL3) {
294
+ this.destroy();
295
+ return;
296
+ }
297
+ if (this.resolveRead) {
298
+ this.resolveRead(message);
299
+ this.resolveRead = null;
300
+ } else {
301
+ this.messageQueue.push(message);
302
+ }
303
+ };
304
+ async read() {
305
+ await this.initialized;
306
+ if (this.messageQueue.length > 0) {
307
+ return this.messageQueue.shift() ?? null;
308
+ }
309
+ return new Promise((resolve) => {
310
+ this.resolveRead = resolve;
311
+ });
312
+ }
313
+ async write(data) {
314
+ await this.initialized;
315
+ if (this.port) {
316
+ this.port.postMessage(data);
317
+ } else {
318
+ this.pendingMessages.push(data);
319
+ }
320
+ }
321
+ destroy() {
322
+ if (this.port) {
323
+ this.port.postMessage(DESTROY_SIGNAL3);
324
+ this.port.close();
325
+ }
326
+ }
327
+ signalDestroy() {
328
+ if (this.port) {
329
+ this.port.postMessage(DESTROY_SIGNAL3);
330
+ } else {
331
+ this.pendingMessages.push(DESTROY_SIGNAL3);
332
+ }
333
+ }
334
+ };
335
+
120
336
  // src/interface.ts
121
337
  var import_node_buffer = require("buffer");
122
338
 
@@ -356,142 +572,10 @@ var RPCChannel = class {
356
572
  this.callbackCache.clear();
357
573
  }
358
574
  };
359
-
360
- // src/adapters/iframe.ts
361
- var DESTROY_SIGNAL2 = "__DESTROY__";
362
- var PORT_INIT_SIGNAL = "__PORT_INIT__";
363
- var IframeParentIO = class {
364
- /**
365
- * @example
366
- * ```ts
367
- * const io = new IframeParentIO(iframeRef.contentWindow);
368
- * const rpc = new RPCChannel(io, {
369
- * expose: {
370
- * add: (a: number, b: number) => Promise.resolve(a + b),
371
- * },
372
- * });
373
- * ```
374
- */
375
- constructor(targetWindow) {
376
- this.targetWindow = targetWindow;
377
- this.port = null;
378
- window.addEventListener("message", (event) => {
379
- if (event.source !== this.targetWindow) return;
380
- if (event.data === PORT_INIT_SIGNAL && event.ports.length > 0) {
381
- this.port = event.ports[0];
382
- this.port.onmessage = this.handleMessage;
383
- while (this.messageQueue.length > 0) {
384
- const message = this.messageQueue.shift();
385
- if (message) this.port.postMessage(message);
386
- }
387
- }
388
- });
389
- }
390
- name = "iframe-parent-io";
391
- messageQueue = [];
392
- resolveRead = null;
393
- port = null;
394
- handleMessage = (event) => {
395
- const message = event.data;
396
- if (message === DESTROY_SIGNAL2) {
397
- this.destroy();
398
- return;
399
- }
400
- if (this.resolveRead) {
401
- this.resolveRead(message);
402
- this.resolveRead = null;
403
- } else {
404
- this.messageQueue.push(message);
405
- }
406
- };
407
- async read() {
408
- if (this.messageQueue.length > 0) {
409
- return this.messageQueue.shift() ?? null;
410
- }
411
- return new Promise((resolve) => {
412
- this.resolveRead = resolve;
413
- });
414
- }
415
- async write(data) {
416
- if (!this.port) {
417
- this.messageQueue.push(data);
418
- return;
419
- }
420
- this.port.postMessage(data);
421
- }
422
- destroy() {
423
- if (this.port) {
424
- this.port.postMessage(DESTROY_SIGNAL2);
425
- this.port.close();
426
- }
427
- }
428
- signalDestroy() {
429
- if (this.port) {
430
- this.port.postMessage(DESTROY_SIGNAL2);
431
- }
432
- }
433
- };
434
- var IframeChildIO = class {
435
- name = "iframe-child-io";
436
- messageQueue = [];
437
- resolveRead = null;
438
- port = null;
439
- pendingMessages = [];
440
- initialized;
441
- channel;
442
- constructor() {
443
- this.channel = new MessageChannel();
444
- this.port = this.channel.port1;
445
- this.port.onmessage = this.handleMessage;
446
- window.parent.postMessage(PORT_INIT_SIGNAL, "*", [this.channel.port2]);
447
- this.initialized = Promise.resolve();
448
- }
449
- handleMessage = (event) => {
450
- const message = event.data;
451
- if (message === DESTROY_SIGNAL2) {
452
- this.destroy();
453
- return;
454
- }
455
- if (this.resolveRead) {
456
- this.resolveRead(message);
457
- this.resolveRead = null;
458
- } else {
459
- this.messageQueue.push(message);
460
- }
461
- };
462
- async read() {
463
- await this.initialized;
464
- if (this.messageQueue.length > 0) {
465
- return this.messageQueue.shift() ?? null;
466
- }
467
- return new Promise((resolve) => {
468
- this.resolveRead = resolve;
469
- });
470
- }
471
- async write(data) {
472
- await this.initialized;
473
- if (this.port) {
474
- this.port.postMessage(data);
475
- } else {
476
- this.pendingMessages.push(data);
477
- }
478
- }
479
- destroy() {
480
- if (this.port) {
481
- this.port.postMessage(DESTROY_SIGNAL2);
482
- this.port.close();
483
- }
484
- }
485
- signalDestroy() {
486
- if (this.port) {
487
- this.port.postMessage(DESTROY_SIGNAL2);
488
- } else {
489
- this.pendingMessages.push(DESTROY_SIGNAL2);
490
- }
491
- }
492
- };
493
575
  // Annotate the CommonJS export names for ESM import in node:
494
576
  0 && (module.exports = {
577
+ ChromeBackgroundIO,
578
+ ChromeContentIO,
495
579
  IframeChildIO,
496
580
  IframeParentIO,
497
581
  RPCChannel,
@@ -1,4 +1,5 @@
1
- export { M as Message, R as Response, a as WorkerChildIO, W as WorkerParentIO, d as deserializeMessage, c as deserializeResponse, g as generateUUID, s as serializeMessage, b as serializeResponse } from './serialization-BrfKixNU.cjs';
1
+ export { a as WorkerChildIO, W as WorkerParentIO } from './worker-ByZFWF48.cjs';
2
+ export { ChromeBackgroundIO, ChromeContentIO, Message, Response, deserializeMessage, deserializeResponse, generateUUID, serializeMessage, serializeResponse } from './chrome.cjs';
2
3
  import { D as DestroyableIoInterface } from './channel-CGr_xSbe.cjs';
3
4
  export { I as IoInterface, R as RPCChannel } from './channel-CGr_xSbe.cjs';
4
5
  import 'node:buffer';
@@ -1,4 +1,5 @@
1
- export { M as Message, R as Response, a as WorkerChildIO, W as WorkerParentIO, d as deserializeMessage, c as deserializeResponse, g as generateUUID, s as serializeMessage, b as serializeResponse } from './serialization-C0yxGsSr.js';
1
+ export { a as WorkerChildIO, W as WorkerParentIO } from './worker-sUTyf1YL.js';
2
+ export { ChromeBackgroundIO, ChromeContentIO, Message, Response, deserializeMessage, deserializeResponse, generateUUID, serializeMessage, serializeResponse } from './chrome.js';
2
3
  import { D as DestroyableIoInterface } from './channel-CGr_xSbe.js';
3
4
  export { I as IoInterface, R as RPCChannel } from './channel-CGr_xSbe.js';
4
5
  import 'node:buffer';
@@ -2,6 +2,10 @@ import {
2
2
  WorkerChildIO,
3
3
  WorkerParentIO
4
4
  } from "./chunk-XU7DWWSJ.js";
5
+ import {
6
+ ChromeBackgroundIO,
7
+ ChromeContentIO
8
+ } from "./chunk-INKNKSKA.js";
5
9
  import {
6
10
  RPCChannel,
7
11
  deserializeMessage,
@@ -145,6 +149,8 @@ var IframeChildIO = class {
145
149
  }
146
150
  };
147
151
  export {
152
+ ChromeBackgroundIO,
153
+ ChromeContentIO,
148
154
  IframeChildIO,
149
155
  IframeParentIO,
150
156
  RPCChannel,