js-rpc2 2.1.0 → 2.2.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 CHANGED
@@ -312,4 +312,47 @@ export async function runWithAbortController(func) {
312
312
  await sleep(1000)
313
313
  } finally { ac.abort() }
314
314
  }
315
+ ```
316
+
317
+ ## Electron
318
+ ```js
319
+ // main.js
320
+ class AppApi {
321
+ asyncLocalStorage = new AsyncLocalStorage()
322
+
323
+ async hello(param) {
324
+ return 'wertyuioiuytre ' + param
325
+ }
326
+ }
327
+
328
+ import { ipcMain } from 'electron'
329
+ import { createRpcServerElectronMessagePort } from 'js-rpc2/src/lib.js'
330
+
331
+ ipcMain.on('port', (event) => {
332
+ const port = event.ports[0]
333
+ createRpcServerElectronMessagePort({ port, rpcKey: '', extension: new AppApi() })
334
+ port.start()
335
+ })
336
+
337
+ // preload.js
338
+ import { ipcRenderer } from 'electron/renderer'
339
+
340
+ window.onmessage = (/** @type {MessageEvent} */ event) => {
341
+ if (event.origin == location.origin && event.data != 'port') {
342
+ ipcRenderer.postMessage('port', null, [event.ports[0]])
343
+ }
344
+ }
345
+
346
+ // renderer.js
347
+ import { createRpcClientMessagePort } from 'js-rpc2/src/lib.js'
348
+
349
+ const channel = new MessageChannel();
350
+ window.postMessage("port", location.origin, [channel.port1]);
351
+ let rpc = createRpcClientMessagePort({ port: channel.port2, rpcKey: "" });
352
+
353
+ // uasge.js
354
+ async function postPortMessage() {
355
+ let ret = await rpc.hello('6667');
356
+ console.info("ret from rpc:", ret);
357
+ }
315
358
  ```
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "js-rpc2",
3
- "version": "2.1.0",
3
+ "version": "2.2.0",
4
4
  "description": "js web websocket http rpc",
5
5
  "main": "index.js",
6
6
  "type": "module",
@@ -26,10 +26,10 @@
26
26
  "author": "yuanliwei",
27
27
  "license": "MIT",
28
28
  "devDependencies": {
29
- "@koa/router": "^13.1.1",
30
- "@types/node": "^22.13.14",
31
- "koa": "^2.15.3",
32
- "ws": "^8.18.0"
29
+ "@koa/router": "^14.0.0",
30
+ "@types/node": "^24.2.1",
31
+ "koa": "^3.0.1",
32
+ "ws": "^8.18.3"
33
33
  },
34
34
  "dependencies": {
35
35
  "msgpackr": "^1.11.5"
package/src/lib.js CHANGED
@@ -23,8 +23,8 @@ export function Promise_withResolvers() {
23
23
  }
24
24
 
25
25
  /**
26
- * @param {Promise<[CryptoKey,Uint8Array]>} key_iv
27
- * @returns {TransformStream<Uint8Array, Uint8Array>}
26
+ * @param {Promise<[CryptoKey,Uint8Array<ArrayBuffer>]>} key_iv
27
+ * @returns {TransformStream<Uint8Array<ArrayBuffer>, Uint8Array<ArrayBuffer>>}
28
28
  */
29
29
  export function createEncodeStream(key_iv) {
30
30
  let key = null
@@ -41,8 +41,8 @@ export function createEncodeStream(key_iv) {
41
41
  }
42
42
 
43
43
  /**
44
- * @param {Promise<[CryptoKey,Uint8Array]>} key_iv
45
- * @returns {TransformStream<Uint8Array, Uint8Array>}
44
+ * @param {Promise<[CryptoKey,Uint8Array<ArrayBuffer>]>} key_iv
45
+ * @returns {TransformStream<Uint8Array<ArrayBuffer>, Uint8Array<ArrayBuffer>>}
46
46
  */
47
47
  export function createDecodeStream(key_iv) {
48
48
  let key = null
@@ -65,10 +65,10 @@ export function createDecodeStream(key_iv) {
65
65
  const HEADER_CHECK = 0xb1f7705f
66
66
 
67
67
  /**
68
- * @param {Uint8Array[]} queue
68
+ * @param {Uint8Array<ArrayBuffer>[]} queue
69
69
  * @param {CryptoKey} key
70
- * @param {Uint8Array} iv
71
- * @returns {Promise<Uint8Array>}
70
+ * @param {Uint8Array<ArrayBuffer>} iv
71
+ * @returns {Promise<Uint8Array<ArrayBuffer>>}
72
72
  */
73
73
  export async function buildBufferData(queue, key, iv) {
74
74
  let buffers = []
@@ -134,7 +134,7 @@ export function processPackets() {
134
134
  }
135
135
 
136
136
  /**
137
- * @param {Uint8Array} buffer
137
+ * @param {Uint8Array<ArrayBuffer>} buffer
138
138
  * @param {number} offset
139
139
  */
140
140
  export function readUInt32LE(buffer, offset) {
@@ -146,7 +146,7 @@ export function readUInt32LE(buffer, offset) {
146
146
  }
147
147
 
148
148
  /**
149
- * @param {Uint8Array} buffer
149
+ * @param {Uint8Array<ArrayBuffer>} buffer
150
150
  * @param {number} value
151
151
  * @param {number} offset
152
152
  */
@@ -159,7 +159,7 @@ export function writeUInt32LE(buffer, value, offset) {
159
159
  }
160
160
 
161
161
  /**
162
- * @param {Uint8Array[]} buffers
162
+ * @param {Uint8Array<ArrayBuffer>[]} buffers
163
163
  */
164
164
  export function Uint8Array_concat(buffers) {
165
165
  const totalLength = buffers.reduce((sum, buffer) => sum + buffer.length, 0)
@@ -196,7 +196,7 @@ export function Uint8Array_from(array, encoding) {
196
196
  }
197
197
 
198
198
  /**
199
- * @param {Uint8Array} buffer
199
+ * @param {Uint8Array<ArrayBuffer>} buffer
200
200
  * @param {'utf-8' | 'hex' | 'base64'} [encoding]
201
201
  */
202
202
  export function Uint8Array_toString(buffer, encoding = 'utf-8') {
@@ -231,7 +231,7 @@ function buildBufferSizeString(string) {
231
231
  }
232
232
 
233
233
  /**
234
- * @param {Uint8Array} buffer
234
+ * @param {Uint8Array<ArrayBuffer>} buffer
235
235
  * @param {number} offset
236
236
  */
237
237
  function readBufferSizeString(buffer, offset) {
@@ -258,7 +258,7 @@ export function guid() {
258
258
  *
259
259
  * @param {string} password
260
260
  * @param {number} iterations
261
- * @returns {Promise<[CryptoKey,Uint8Array]>}
261
+ * @returns {Promise<[CryptoKey,Uint8Array<ArrayBuffer>]>}
262
262
  */
263
263
  export async function buildKeyIv(password, iterations) {
264
264
  if (!JS_RPC_WITH_CRYPTO) return [null, null]
@@ -294,9 +294,9 @@ export async function buildKeyIv(password, iterations) {
294
294
 
295
295
  /**
296
296
  *
297
- * @param {Uint8Array} data
297
+ * @param {Uint8Array<ArrayBuffer>} data
298
298
  * @param {CryptoKey} key
299
- * @param {Uint8Array} iv
299
+ * @param {Uint8Array<ArrayBuffer>} iv
300
300
  * @returns
301
301
  */
302
302
  export async function encrypt(data, key, iv) {
@@ -311,7 +311,7 @@ export async function encrypt(data, key, iv) {
311
311
  /**
312
312
  * @param {Uint8Array<ArrayBuffer>} data
313
313
  * @param {CryptoKey} key
314
- * @param {Uint8Array} iv
314
+ * @param {Uint8Array<ArrayBuffer>} iv
315
315
  * @returns
316
316
  */
317
317
  export async function decrypt(data, key, iv) {
@@ -373,7 +373,7 @@ export function buildRpcData(box) {
373
373
  }
374
374
 
375
375
  /**
376
- * @param {Uint8Array} buffer
376
+ * @param {Uint8Array<ArrayBuffer>} buffer
377
377
  */
378
378
  export function parseRpcData(buffer) {
379
379
  let [id, type, data] = packr.unpack(buffer)
@@ -409,8 +409,8 @@ export function buildRpcItemData(items) {
409
409
  /**
410
410
  * @template T
411
411
  * @param {ExtensionApi<T>} extension
412
- * @param {WritableStreamDefaultWriter<Uint8Array>} writer
413
- * @param {Uint8Array} buffer
412
+ * @param {WritableStreamDefaultWriter<Uint8Array<ArrayBuffer>>} writer
413
+ * @param {Uint8Array<ArrayBuffer>} buffer
414
414
  * @param {(msg:string)=>void} logger
415
415
  */
416
416
  export async function rpcRunServerDecodeBuffer(extension, writer, buffer, logger) {
@@ -495,8 +495,8 @@ export function createRPCProxy(apiInvoke) {
495
495
 
496
496
  /**
497
497
  * @typedef {{
498
- * writable: WritableStream<Uint8Array>;
499
- * readable: ReadableStream<Uint8Array>;
498
+ * writable: WritableStream<Uint8Array<ArrayBuffer>>;
499
+ * readable: ReadableStream<Uint8Array<ArrayBuffer>>;
500
500
  * }} RPC_HELPER_SERVER
501
501
  */
502
502
 
@@ -537,8 +537,8 @@ export function createRpcServerHelper(param) {
537
537
 
538
538
  /**
539
539
  * @typedef {{
540
- * writable: WritableStream<Uint8Array>;
541
- * readable: ReadableStream<Uint8Array>;
540
+ * writable: WritableStream<Uint8Array<ArrayBuffer>>;
541
+ * readable: ReadableStream<Uint8Array<ArrayBuffer>>;
542
542
  * apiInvoke: (fnName: string, args: object[]) => Promise<object>;
543
543
  * reject: (error:object)=>void;
544
544
  * }} RPC_HELPER_CLIENT
@@ -671,7 +671,7 @@ export function createRpcClientWebSocket(param) {
671
671
  let helper = createRpcClientHelper({ rpcKey: param.rpcKey })
672
672
  let writer = helper.writable.getWriter()
673
673
  let signal = Promise_withResolvers()
674
- /** @type{WritableStreamDefaultWriter<Uint8Array>} */
674
+ /** @type{WritableStreamDefaultWriter<Uint8Array<ArrayBuffer>>} */
675
675
  let socketWriter = null
676
676
  helper.readable.pipeTo(new WritableStream({
677
677
  async write(chunk) {
@@ -761,3 +761,74 @@ export function createRpcClientHttp(param) {
761
761
  })).catch((err) => helper.reject(err))
762
762
  return createRPCProxy(helper.apiInvoke)
763
763
  }
764
+
765
+ /**
766
+ * @template T
767
+ * @param {{
768
+ * port:MessagePort;
769
+ * rpcKey:string;
770
+ * extension: ExtensionApi<T>;
771
+ * logger?:(msg:string)=>void;
772
+ * }} param
773
+ */
774
+ export function createRpcServerMessagePort(param) {
775
+ const port = param.port
776
+ let helper = createRpcServerHelper({
777
+ rpcKey: '', extension: param.extension, async: true, logger: param.logger,
778
+ })
779
+ let writer = helper.writable.getWriter()
780
+ port.onmessage = async (event) => {
781
+ await writer.write(event.data)
782
+ }
783
+ helper.readable.pipeTo(new WritableStream({
784
+ async write(chunk) {
785
+ port.postMessage(chunk)
786
+ }
787
+ }))
788
+ }
789
+
790
+ /**
791
+ * @import {Electron} from './types.js'
792
+ * @template T
793
+ * @param {{
794
+ * port:Electron.MessagePortMain;
795
+ * rpcKey:string;
796
+ * extension: ExtensionApi<T>;
797
+ * logger?:(msg:string)=>void;
798
+ * }} param
799
+ */
800
+ export function createRpcServerElectronMessagePort(param) {
801
+ const port = param.port
802
+ let helper = createRpcServerHelper({
803
+ rpcKey: '', extension: param.extension, async: true, logger: param.logger,
804
+ })
805
+ let writer = helper.writable.getWriter()
806
+ port.on('message', async (event) => {
807
+ await writer.write(event.data)
808
+ })
809
+ helper.readable.pipeTo(new WritableStream({
810
+ async write(chunk) {
811
+ port.postMessage(chunk)
812
+ }
813
+ }))
814
+ }
815
+
816
+ /**
817
+ * @param {{
818
+ * port:MessagePort;
819
+ * rpcKey:string;
820
+ * }} param
821
+ */
822
+ export function createRpcClientMessagePort(param) {
823
+ let helper = createRpcClientHelper({ rpcKey: param.rpcKey })
824
+ let writer = helper.writable.getWriter()
825
+ helper.readable.pipeTo(new WritableStream({
826
+ async write(chunk) {
827
+ param.port.postMessage(chunk)
828
+ }
829
+ }))
830
+ param.port.onmessage = async (event) => {
831
+ await writer.write(event.data)
832
+ }
833
+ return createRPCProxy(helper.apiInvoke)
834
+ }
package/src/server.js CHANGED
@@ -75,7 +75,6 @@ export function createRpcServerKoaRouter(param) {
75
75
  }
76
76
  param.router.post(param.path, async (ctx) => {
77
77
  let helper = createRpcServerHelper({ rpcKey: param.rpcKey, extension: param.extension, logger: param.logger, context: ctx })
78
- /** @type{ReadableStream} */
79
78
  let a = Readable.toWeb(ctx.req)
80
79
  await a.pipeTo(helper.writable)
81
80
  ctx.status = 200
package/src/types.ts CHANGED
@@ -46,4 +46,46 @@ export type RPC_DATA = {
46
46
  data: { message: string, stack: string };
47
47
  };
48
48
 
49
- export type RPC_DATA_ARG_TYPE = RPC_DATA_ARG_TYPE_OTHERS | RPC_DATA_ARG_TYPE_FUNCTION;
49
+ export type RPC_DATA_ARG_TYPE = RPC_DATA_ARG_TYPE_OTHERS | RPC_DATA_ARG_TYPE_FUNCTION;
50
+
51
+ export declare namespace Electron {
52
+
53
+ const NodeEventEmitter: typeof import('events').EventEmitter;
54
+
55
+ class MessagePortMain extends NodeEventEmitter {
56
+
57
+ // Docs: https://electronjs.org/docs/api/message-port-main
58
+
59
+ /**
60
+ * Emitted when the remote end of a MessagePortMain object becomes disconnected.
61
+ */
62
+ on(event: 'close', listener: () => void): this;
63
+ off(event: 'close', listener: () => void): this;
64
+ once(event: 'close', listener: () => void): this;
65
+ addListener(event: 'close', listener: () => void): this;
66
+ removeListener(event: 'close', listener: () => void): this;
67
+ /**
68
+ * Emitted when a MessagePortMain object receives a message.
69
+ */
70
+ on(event: 'message', listener: (messageEvent: MessageEvent) => void): this;
71
+ off(event: 'message', listener: (messageEvent: MessageEvent) => void): this;
72
+ once(event: 'message', listener: (messageEvent: MessageEvent) => void): this;
73
+ addListener(event: 'message', listener: (messageEvent: MessageEvent) => void): this;
74
+ removeListener(event: 'message', listener: (messageEvent: MessageEvent) => void): this;
75
+ /**
76
+ * Disconnects the port, so it is no longer active.
77
+ */
78
+ close(): void;
79
+ /**
80
+ * Sends a message from the port, and optionally, transfers ownership of objects to
81
+ * other browsing contexts.
82
+ */
83
+ postMessage(message: any, transfer?: MessagePortMain[]): void;
84
+ /**
85
+ * Starts the sending of messages queued on the port. Messages will be queued until
86
+ * this method is called.
87
+ */
88
+ start(): void;
89
+ }
90
+
91
+ }