js-rpc2 1.0.2 → 1.0.4

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/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "js-rpc2",
3
- "version": "1.0.2",
3
+ "version": "1.0.4",
4
4
  "description": "js web websocket http rpc",
5
5
  "main": "index.js",
6
6
  "type": "module",
package/src/lib.js CHANGED
@@ -120,6 +120,19 @@ export async function parseBufferData(buffer, key, iv) {
120
120
  return [queue, remain]
121
121
  }
122
122
 
123
+ export function processPackets() {
124
+ let last = new Uint8Array(0)
125
+ return new TransformStream({
126
+ async transform(chunk, controller) {
127
+ let [queueReceive, remain] = await parseBufferData(Uint8Array_concat([last, chunk]), null, null)
128
+ last = remain
129
+ if (queueReceive.length > 0) {
130
+ let buffer = await buildBufferData(queueReceive, null, null)
131
+ controller.enqueue(buffer)
132
+ }
133
+ }
134
+ })
135
+ }
123
136
 
124
137
  /**
125
138
  * @param {Uint8Array} buffer
@@ -360,26 +373,26 @@ export const RPC_TYPE_ERROR = 0xa07c0f84
360
373
  */
361
374
 
362
375
  /**
363
- * @typedef {{type:RPC_DATA_AGR_TYPE;data:object}} RPC_DATA_ARG_ITEM
376
+ * @typedef {{type:RPC_DATA_ARG_TYPE;data:object}} RPC_DATA_ARG_ITEM
364
377
  * @typedef {{
365
378
  * id:number;
366
379
  * type:RPC_TYPES;
367
- * data:{type:RPC_DATA_AGR_TYPE;data:object}[];
380
+ * data:{type:RPC_DATA_ARG_TYPE;data:object}[];
368
381
  * }} RPC_DATA
369
382
  */
370
383
 
371
- export const RPC_DATA_AGR_TYPE_OBJECT = 0xa7f68c
372
- export const RPC_DATA_AGR_TYPE_FUNCTION = 0x7ff45f
373
- export const RPC_DATA_AGR_TYPE_UINT8ARRAY = 0xedb218
374
- export const RPC_DATA_AGR_TYPE_UNDEFINED = 0x7f77fe
375
- export const RPC_DATA_AGR_TYPE_NULL = 0x5794f9
384
+ export const RPC_DATA_ARG_TYPE_OBJECT = 0xa7f68c
385
+ export const RPC_DATA_ARG_TYPE_FUNCTION = 0x7ff45f
386
+ export const RPC_DATA_ARG_TYPE_UINT8ARRAY = 0xedb218
387
+ export const RPC_DATA_ARG_TYPE_UNDEFINED = 0x7f77fe
388
+ export const RPC_DATA_ARG_TYPE_NULL = 0x5794f9
376
389
 
377
390
  /**
378
- * @typedef {RPC_DATA_AGR_TYPE_OBJECT
379
- * |RPC_DATA_AGR_TYPE_FUNCTION
380
- * |RPC_DATA_AGR_TYPE_UINT8ARRAY
381
- * |RPC_DATA_AGR_TYPE_UNDEFINED
382
- * |RPC_DATA_AGR_TYPE_NULL} RPC_DATA_AGR_TYPE
391
+ * @typedef {RPC_DATA_ARG_TYPE_OBJECT
392
+ * |RPC_DATA_ARG_TYPE_FUNCTION
393
+ * |RPC_DATA_ARG_TYPE_UINT8ARRAY
394
+ * |RPC_DATA_ARG_TYPE_UNDEFINED
395
+ * |RPC_DATA_ARG_TYPE_NULL} RPC_DATA_ARG_TYPE
383
396
  */
384
397
 
385
398
  /**
@@ -392,23 +405,23 @@ export function buildRpcData(box) {
392
405
  buildBufferNumberUInt32LE(box.data.length),
393
406
  ]
394
407
  for (const o of box.data) {
395
- if (o.type == RPC_DATA_AGR_TYPE_UINT8ARRAY) {
408
+ if (o.type == RPC_DATA_ARG_TYPE_UINT8ARRAY) {
396
409
  buffers.push(buildBufferNumberUInt32LE(o.type))
397
410
  buffers.push(buildBufferNumberUInt32LE(o.data.length))
398
411
  buffers.push(o.data)
399
412
  }
400
- if (o.type == RPC_DATA_AGR_TYPE_FUNCTION) {
413
+ if (o.type == RPC_DATA_ARG_TYPE_FUNCTION) {
401
414
  buffers.push(buildBufferNumberUInt32LE(o.type))
402
415
  buffers.push(buildBufferSizeString(o.data))
403
416
  }
404
- if (o.type == RPC_DATA_AGR_TYPE_OBJECT) {
417
+ if (o.type == RPC_DATA_ARG_TYPE_OBJECT) {
405
418
  buffers.push(buildBufferNumberUInt32LE(o.type))
406
419
  buffers.push(buildBufferSizeString(JSON.stringify(o.data)))
407
420
  }
408
- if (o.type == RPC_DATA_AGR_TYPE_UNDEFINED) {
421
+ if (o.type == RPC_DATA_ARG_TYPE_UNDEFINED) {
409
422
  buffers.push(buildBufferNumberUInt32LE(o.type))
410
423
  }
411
- if (o.type == RPC_DATA_AGR_TYPE_NULL) {
424
+ if (o.type == RPC_DATA_ARG_TYPE_NULL) {
412
425
  buffers.push(buildBufferNumberUInt32LE(o.type))
413
426
  }
414
427
  }
@@ -432,28 +445,28 @@ export function parseRpcData(buffer) {
432
445
  for (let i = 0; i < dataLength; i++) {
433
446
  let type = readUInt32LE(buffer, offset)
434
447
  offset += 4
435
- if (type == RPC_DATA_AGR_TYPE_UINT8ARRAY) {
448
+ if (type == RPC_DATA_ARG_TYPE_UINT8ARRAY) {
436
449
  let size = readUInt32LE(buffer, offset)
437
450
  offset += 4
438
451
  let data = buffer.slice(offset, offset + size)
439
452
  offset += size
440
453
  args.push({ type: type, data })
441
454
  }
442
- if (type == RPC_DATA_AGR_TYPE_FUNCTION) {
455
+ if (type == RPC_DATA_ARG_TYPE_FUNCTION) {
443
456
  let o = readBufferSizeString(buffer, offset)
444
457
  offset += o.size
445
458
  args.push({ type: type, data: o.string })
446
459
  }
447
- if (type == RPC_DATA_AGR_TYPE_OBJECT) {
460
+ if (type == RPC_DATA_ARG_TYPE_OBJECT) {
448
461
  let o = readBufferSizeString(buffer, offset)
449
462
  offset += o.size
450
463
  let data = o.string
451
464
  args.push({ type: type, data: JSON.parse(data) })
452
465
  }
453
- if (type == RPC_DATA_AGR_TYPE_UNDEFINED) {
466
+ if (type == RPC_DATA_ARG_TYPE_UNDEFINED) {
454
467
  args.push({ type: type, data: undefined })
455
468
  }
456
- if (type == RPC_DATA_AGR_TYPE_NULL) {
469
+ if (type == RPC_DATA_ARG_TYPE_NULL) {
457
470
  args.push({ type: type, data: null })
458
471
  }
459
472
  }
@@ -469,23 +482,23 @@ export function buildRpcItemData(items) {
469
482
  /** @type{RPC_DATA_ARG_ITEM[]} */
470
483
  let arr = []
471
484
  for (const item of items) {
472
- /** @type{RPC_DATA_AGR_TYPE} */
485
+ /** @type{RPC_DATA_ARG_TYPE} */
473
486
  let type = null
474
487
  let data = null
475
488
  if (item === undefined) {
476
- type = RPC_DATA_AGR_TYPE_UNDEFINED
489
+ type = RPC_DATA_ARG_TYPE_UNDEFINED
477
490
  data = item
478
491
  } else if (item === null) {
479
- type = RPC_DATA_AGR_TYPE_NULL
492
+ type = RPC_DATA_ARG_TYPE_NULL
480
493
  data = item
481
494
  } else if (item instanceof Uint8Array) {
482
- type = RPC_DATA_AGR_TYPE_UINT8ARRAY
495
+ type = RPC_DATA_ARG_TYPE_UINT8ARRAY
483
496
  data = item
484
497
  } else if (typeof item == 'function') {
485
- type = RPC_DATA_AGR_TYPE_FUNCTION
498
+ type = RPC_DATA_ARG_TYPE_FUNCTION
486
499
  data = item()
487
500
  } else {
488
- type = RPC_DATA_AGR_TYPE_OBJECT
501
+ type = RPC_DATA_ARG_TYPE_OBJECT
489
502
  data = JSON.stringify(item)
490
503
  }
491
504
  arr.push({ type, data })
@@ -501,19 +514,19 @@ export function parseRpcItemData(array) {
501
514
  let items = []
502
515
  for (let i = 0; i < array.length; i++) {
503
516
  const o = array[i]
504
- if (o.type == RPC_DATA_AGR_TYPE_FUNCTION) {
517
+ if (o.type == RPC_DATA_ARG_TYPE_FUNCTION) {
505
518
  o.data = o.data
506
519
  }
507
- if (o.type == RPC_DATA_AGR_TYPE_NULL) {
520
+ if (o.type == RPC_DATA_ARG_TYPE_NULL) {
508
521
  o.data = null
509
522
  }
510
- if (o.type == RPC_DATA_AGR_TYPE_UNDEFINED) {
523
+ if (o.type == RPC_DATA_ARG_TYPE_UNDEFINED) {
511
524
  o.data = undefined
512
525
  }
513
- if (o.type == RPC_DATA_AGR_TYPE_UINT8ARRAY) {
526
+ if (o.type == RPC_DATA_ARG_TYPE_UINT8ARRAY) {
514
527
  o.data = o.data
515
528
  }
516
- if (o.type == RPC_DATA_AGR_TYPE_OBJECT) {
529
+ if (o.type == RPC_DATA_ARG_TYPE_OBJECT) {
517
530
  o.data = JSON.parse(o.data)
518
531
  }
519
532
  items.push(o)
@@ -539,7 +552,7 @@ export async function rpcRunServerDecodeBuffer(extension, writer, buffer) {
539
552
  let params = []
540
553
  for (let i = 0; i < args.length; i++) {
541
554
  const p = args[i]
542
- if (p.type == RPC_DATA_AGR_TYPE_FUNCTION) {
555
+ if (p.type == RPC_DATA_ARG_TYPE_FUNCTION) {
543
556
  const callback = async (/** @type {any[]} */ ...args) => {
544
557
  /** @type{RPC_DATA} */
545
558
  let box = { id: p.data, type: RPC_TYPE_CALLBACK, data: buildRpcItemData(args), }
@@ -561,7 +574,7 @@ export async function rpcRunServerDecodeBuffer(extension, writer, buffer) {
561
574
  box = {
562
575
  id: dataId,
563
576
  type: RPC_TYPE_ERROR,
564
- data: buildRpcItemData([`Error:${error.message}\n${error.stack}`]),
577
+ data: buildRpcItemData([error.message, error.stack]),
565
578
  }
566
579
  }
567
580
  await writer.write(buildRpcData(box))
@@ -580,7 +593,11 @@ export function createRPCProxy(apiInvoke) {
580
593
  }
581
594
  proxy = new Proxy(Function, {
582
595
  async apply(_target, _thisArg, argArray) {
583
- return await apiInvoke(String(p), argArray)
596
+ try {
597
+ return await apiInvoke(String(p), argArray)
598
+ } catch (error) {
599
+ throw new Error(error.message, { cause: error })
600
+ }
584
601
  }
585
602
  })
586
603
  map.set(p, proxy)
@@ -627,13 +644,24 @@ export function createRpcServerHelper(param) {
627
644
  * writable: WritableStream<Uint8Array>;
628
645
  * readable: ReadableStream<Uint8Array>;
629
646
  * apiInvoke: (fnName: string, args: object[]) => Promise<object>;
630
- * transform:()=>{
631
- * readable: ReadableStream<Uint8Array<ArrayBufferLike>>;
632
- * witeable: WritableStream<Uint8Array<ArrayBufferLike>>;
633
- * }
647
+ * reject: (error:object)=>void;
634
648
  * }} RPC_HELPER_CLIENT
635
649
  */
636
650
 
651
+ class RPCError extends Error {
652
+ /**
653
+ * @param {string} message
654
+ * @param {string} stack
655
+ * @param {ErrorOptions} [option]
656
+ */
657
+ constructor(message, stack, option) {
658
+ super(message, option)
659
+ if (stack) {
660
+ this.stack = stack
661
+ }
662
+ }
663
+ }
664
+
637
665
  /**
638
666
  * @param {{ rpcKey: string; }} param
639
667
  */
@@ -656,7 +684,7 @@ export function createRpcClientHelper(param) {
656
684
  if (callbackFunctionMap.has(data.id)) {
657
685
  let o = callbackFunctionMap.get(data.id)
658
686
  if (data.type == RPC_TYPE_ERROR) {
659
- o.promise.reject(new Error(items.at(0).data))
687
+ o.promise.reject(new RPCError(items.at(0).data, items.at(1).data))
660
688
  }
661
689
  if (data.type == RPC_TYPE_RETURN) {
662
690
  callbackFunctionMap.delete(data.id)
@@ -714,15 +742,18 @@ export function createRpcClientHelper(param) {
714
742
  }
715
743
  }
716
744
 
717
- function transform() {
718
- let decode = createDecodeStream(rpc_key_iv)
719
- let encode = createEncodeStream(rpc_key_iv)
720
- decode.readable.pipeTo(encode.writable)
721
- return { readable: encode.readable, witeable: decode.writable }
745
+ /**
746
+ * @param {object} error
747
+ */
748
+ function reject(error) {
749
+ callbackFunctionMap.forEach((o) => {
750
+ o.promise?.reject(error)
751
+ })
752
+ callbackFunctionMap.clear()
722
753
  }
723
754
 
724
755
  /** @type{RPC_HELPER_CLIENT} */
725
- let ret = { writable: decode.writable, readable: encode.readable, apiInvoke, transform }
756
+ let ret = { writable: decode.writable, readable: encode.readable, apiInvoke, reject }
726
757
  return ret
727
758
  }
728
759
 
@@ -810,15 +841,17 @@ export function createRpcClientHttp(param) {
810
841
  if (param.intercept) {
811
842
  param.intercept(res)
812
843
  }
813
- let transform = helper.transform()
814
- res.body.pipeTo(transform.witeable).catch(e => console.error(e))
815
- transform.readable.pipeTo(new WritableStream({
844
+ res.body.pipeThrough(processPackets()).pipeTo(new WritableStream({
816
845
  async write(chunk) {
817
846
  await writer.write(chunk)
818
847
  }
819
- })).catch((e) => console.error(e))
820
- }).catch(e => console.error(e))
848
+ })).catch((e) => {
849
+ helper.reject(e)
850
+ })
851
+ }).catch(e => {
852
+ helper.reject(e)
853
+ })
821
854
  }
822
- })).catch((err) => console.error('createRpcClientHttp', err.message))
855
+ })).catch((err) => helper.reject(err))
823
856
  return createRPCProxy(helper.apiInvoke)
824
857
  }
package/src/lib.test.js CHANGED
@@ -282,4 +282,48 @@ export async function runWithAbortController(func) {
282
282
  await func(ac)
283
283
  await sleep(1000)
284
284
  } finally { ac.abort() }
285
- }
285
+ }
286
+
287
+
288
+ test('error-stack', async () => {
289
+ // node --test-name-pattern="^error-stack$" src/lib.test.js
290
+
291
+ // server
292
+ const app = new Koa()
293
+ const router = new Router()
294
+ app.use(router.routes())
295
+ app.use(router.allowedMethods())
296
+ let server = createServer(app.callback()).listen(9000)
297
+
298
+ class RpcApi {
299
+ async hello() {
300
+ new URL('/')
301
+ }
302
+ }
303
+
304
+ const extension = new RpcApi()
305
+
306
+ createRpcServerKoaRouter({
307
+ path: '/rpc/abc',
308
+ router: router,
309
+ extension: extension,
310
+ })
311
+
312
+
313
+ // client
314
+
315
+ /** @type{RpcApi} */
316
+ const rpc = createRpcClientHttp({
317
+ // url: `/rpc/abc`, // in same site html page
318
+ url: `http://127.0.0.1:9000/rpc/abc`, // others
319
+ })
320
+
321
+ try {
322
+ let ret = await rpc.hello()
323
+ console.info(ret)
324
+ } catch (error) {
325
+ console.error(error)
326
+ }
327
+ server.close()
328
+
329
+ })