@bigmistqke/rpc 0.1.3 → 0.1.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/.claude/settings.local.json +7 -0
- package/dist/fetch-node.js +139 -0
- package/dist/fetch-node.js.map +1 -1
- package/dist/fetch.d.ts +1 -1
- package/dist/fetch.js +147 -6
- package/dist/fetch.js.map +1 -1
- package/dist/handle-18d6fe9b.d.ts +24 -0
- package/dist/messenger.d.ts +33 -11
- package/dist/messenger.js +149 -39
- package/dist/messenger.js.map +1 -1
- package/dist/stream.d.ts +1 -1
- package/dist/stream.js +69 -28
- package/dist/stream.js.map +1 -1
- package/dist/{types-a5ce9c9a.d.ts → types-9f54da43.d.ts} +5 -1
- package/dist/websocket.d.ts +50 -0
- package/dist/websocket.js +617 -0
- package/dist/websocket.js.map +1 -0
- package/package.json +13 -8
- package/src/core.ts +100 -0
- package/src/fetch/index.ts +2 -1
- package/src/fetch/node.ts +1 -1
- package/src/handle.ts +48 -0
- package/src/{messenger.ts → messenger/index.ts} +67 -25
- package/src/{message-protocol.ts → protocol.ts} +11 -1
- package/src/server-send-events/index.ts +3 -2
- package/src/stream/index.ts +3 -14
- package/src/types.ts +6 -1
- package/src/utils.ts +0 -32
- package/src/websocket/index.ts +142 -0
- package/test/messenger.test.ts +249 -35
- package/test/{message-protocol.test.ts → protocol.test.ts} +7 -7
- package/test/sse.test.ts +3 -3
- package/test/stream.test.ts +1 -5
- package/test/utils.test.ts +1 -2
- package/test/websocket.test.ts +514 -0
- package/tsup.config.ts +2 -1
- package/LICENSE +0 -21
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
/** Type for values returned by handle() - unwrapped to RPC<T> by RPC system */
|
|
2
|
+
type Handled<T extends object> = T & {
|
|
3
|
+
readonly ['__rpc_handled__']: T;
|
|
4
|
+
};
|
|
5
|
+
/**
|
|
6
|
+
* Mark methods to be returned as a sub-proxy from an RPC method.
|
|
7
|
+
* Use this when a method needs to return an object with callable methods.
|
|
8
|
+
*
|
|
9
|
+
* @example
|
|
10
|
+
* ```ts
|
|
11
|
+
* expose({
|
|
12
|
+
* init(canvas: OffscreenCanvas) {
|
|
13
|
+
* const renderer = createRenderer(canvas)
|
|
14
|
+
* return handle({
|
|
15
|
+
* render: () => renderer.render(),
|
|
16
|
+
* resize: (w, h) => renderer.resize(w, h),
|
|
17
|
+
* })
|
|
18
|
+
* }
|
|
19
|
+
* })
|
|
20
|
+
* ```
|
|
21
|
+
*/
|
|
22
|
+
declare function handle<T extends object>(methods: T): Handled<T>;
|
|
23
|
+
|
|
24
|
+
export { Handled as H, handle as h };
|
package/dist/messenger.d.ts
CHANGED
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import * as v from 'valibot';
|
|
2
|
-
import { R as RPC } from './types-
|
|
2
|
+
import { R as RPC } from './types-9f54da43.js';
|
|
3
|
+
export { H as Handled, h as handle } from './handle-18d6fe9b.js';
|
|
3
4
|
|
|
4
5
|
declare const requestSchema: v.ObjectSchema<{
|
|
5
6
|
readonly RPC_PROXY_REQUEST: v.NumberSchema<undefined>;
|
|
@@ -37,12 +38,32 @@ declare function createResponder(messenger: Messenger, callback: (data: RequestD
|
|
|
37
38
|
/**********************************************************************************/
|
|
38
39
|
/**********************************************************************************/
|
|
39
40
|
/**
|
|
40
|
-
* Exposes
|
|
41
|
+
* Exposes methods as an RPC endpoint over the given messenger.
|
|
41
42
|
*
|
|
42
|
-
* @param methods -
|
|
43
|
+
* @param methods - Object containing methods to expose
|
|
43
44
|
* @param options - Optional target Messenger and abort signal
|
|
45
|
+
*
|
|
46
|
+
* @example
|
|
47
|
+
* ```ts
|
|
48
|
+
* // Worker side - simple methods
|
|
49
|
+
* expose({
|
|
50
|
+
* add: (a, b) => a + b,
|
|
51
|
+
* multiply: (a, b) => a * b,
|
|
52
|
+
* })
|
|
53
|
+
*
|
|
54
|
+
* // Worker side - with initialization returning sub-proxy
|
|
55
|
+
* expose({
|
|
56
|
+
* init(canvas: OffscreenCanvas) {
|
|
57
|
+
* const renderer = createRenderer(canvas)
|
|
58
|
+
* return handle({
|
|
59
|
+
* render: () => renderer.render(),
|
|
60
|
+
* resize: (w, h) => renderer.resize(w, h),
|
|
61
|
+
* })
|
|
62
|
+
* }
|
|
63
|
+
* })
|
|
64
|
+
* ```
|
|
44
65
|
*/
|
|
45
|
-
declare function expose<
|
|
66
|
+
declare function expose<TMethods extends object>(methods: TMethods, { to, signal }?: {
|
|
46
67
|
to?: Messenger;
|
|
47
68
|
signal?: AbortSignal;
|
|
48
69
|
}): void;
|
|
@@ -51,18 +72,19 @@ declare function expose<T extends object>(methods: T, { to, signal }?: {
|
|
|
51
72
|
*
|
|
52
73
|
* @param messenger - The Messenger to communicate with (e.g. Worker or Window)
|
|
53
74
|
* @param options - Optional abort signal
|
|
54
|
-
* @returns A proxy object
|
|
75
|
+
* @returns A proxy object for calling remote methods
|
|
55
76
|
*
|
|
56
77
|
* @example
|
|
57
78
|
* ```ts
|
|
58
|
-
*
|
|
59
|
-
* const
|
|
79
|
+
* // Create RPC proxy (synchronous)
|
|
80
|
+
* const worker = rpc<WorkerMethods>(new Worker('worker.js'))
|
|
60
81
|
*
|
|
61
|
-
* // Call
|
|
62
|
-
* await
|
|
82
|
+
* // Call methods that return handle() get sub-proxies
|
|
83
|
+
* const renderer = await worker.init(transfer(canvas))
|
|
84
|
+
* await renderer.render()
|
|
63
85
|
*
|
|
64
86
|
* // Access underlying messenger
|
|
65
|
-
*
|
|
87
|
+
* worker[$MESSENGER].terminate()
|
|
66
88
|
* ```
|
|
67
89
|
*/
|
|
68
90
|
declare function rpc<T extends object>(messenger: Worker, options?: {
|
|
@@ -96,4 +118,4 @@ declare function rpc<T extends object, M extends Messenger = Messenger>(messenge
|
|
|
96
118
|
[$MESSENGER]: M;
|
|
97
119
|
};
|
|
98
120
|
|
|
99
|
-
export { $MESSENGER, $TRANSFER,
|
|
121
|
+
export { $MESSENGER, $TRANSFER, Transferred, createResponder, expose, rpc, transfer };
|
package/dist/messenger.js
CHANGED
|
@@ -1,3 +1,17 @@
|
|
|
1
|
+
// src/handle.ts
|
|
2
|
+
var $HANDLE_MARKER = Symbol("RPC-HANDLE-MARKER");
|
|
3
|
+
function handle(methods) {
|
|
4
|
+
return { [$HANDLE_MARKER]: true, methods };
|
|
5
|
+
}
|
|
6
|
+
function isHandleMarker(value) {
|
|
7
|
+
return !!value && typeof value === "object" && $HANDLE_MARKER in value;
|
|
8
|
+
}
|
|
9
|
+
var HANDLE_NAMESPACE_PREFIX = "__rpc_handle_";
|
|
10
|
+
var handleNamespaceCounter = 0;
|
|
11
|
+
function nextHandleNamespaceId() {
|
|
12
|
+
return `${HANDLE_NAMESPACE_PREFIX}${handleNamespaceCounter++}`;
|
|
13
|
+
}
|
|
14
|
+
|
|
1
15
|
// ../../node_modules/.pnpm/valibot@1.0.0_typescript@5.7.2/node_modules/valibot/dist/index.js
|
|
2
16
|
var store;
|
|
3
17
|
function getGlobalConfig(config2) {
|
|
@@ -292,6 +306,32 @@ function object(entries, message) {
|
|
|
292
306
|
}
|
|
293
307
|
};
|
|
294
308
|
}
|
|
309
|
+
function optional(wrapped, default_) {
|
|
310
|
+
return {
|
|
311
|
+
kind: "schema",
|
|
312
|
+
type: "optional",
|
|
313
|
+
reference: optional,
|
|
314
|
+
expects: `(${wrapped.expects} | undefined)`,
|
|
315
|
+
async: false,
|
|
316
|
+
wrapped,
|
|
317
|
+
default: default_,
|
|
318
|
+
get "~standard"() {
|
|
319
|
+
return _getStandardProps(this);
|
|
320
|
+
},
|
|
321
|
+
"~run"(dataset, config2) {
|
|
322
|
+
if (dataset.value === void 0) {
|
|
323
|
+
if (this.default !== void 0) {
|
|
324
|
+
dataset.value = getDefault(this, dataset, config2);
|
|
325
|
+
}
|
|
326
|
+
if (dataset.value === void 0) {
|
|
327
|
+
dataset.typed = true;
|
|
328
|
+
return dataset;
|
|
329
|
+
}
|
|
330
|
+
}
|
|
331
|
+
return this.wrapped["~run"](dataset, config2);
|
|
332
|
+
}
|
|
333
|
+
};
|
|
334
|
+
}
|
|
295
335
|
function string(message) {
|
|
296
336
|
return {
|
|
297
337
|
kind: "schema",
|
|
@@ -379,40 +419,14 @@ function defer() {
|
|
|
379
419
|
reject
|
|
380
420
|
};
|
|
381
421
|
}
|
|
382
|
-
function createCommander(apply) {
|
|
383
|
-
function _createCommander(topics, apply2) {
|
|
384
|
-
return new Proxy(function() {
|
|
385
|
-
}, {
|
|
386
|
-
get(target, topic) {
|
|
387
|
-
if (typeof topic === "symbol")
|
|
388
|
-
return target[topic];
|
|
389
|
-
return _createCommander([...topics, topic], apply2);
|
|
390
|
-
},
|
|
391
|
-
apply(_, __, args) {
|
|
392
|
-
return apply2(topics, args);
|
|
393
|
-
}
|
|
394
|
-
});
|
|
395
|
-
}
|
|
396
|
-
return _createCommander([], apply);
|
|
397
|
-
}
|
|
398
422
|
function createShape(schema, create) {
|
|
399
423
|
return {
|
|
400
424
|
validate: (value) => safeParse(schema, value).success,
|
|
401
425
|
create
|
|
402
426
|
};
|
|
403
427
|
}
|
|
404
|
-
function callMethod(methods, topics, args) {
|
|
405
|
-
const method = topics.reduce((acc, topic) => {
|
|
406
|
-
const result = acc?.[topic];
|
|
407
|
-
return result;
|
|
408
|
-
}, methods);
|
|
409
|
-
if (typeof method !== "function") {
|
|
410
|
-
throw new Error(`Topics did not resolve to a function: [${topics.join(",")}]`);
|
|
411
|
-
}
|
|
412
|
-
return method(...args);
|
|
413
|
-
}
|
|
414
428
|
|
|
415
|
-
// src/
|
|
429
|
+
// src/protocol.ts
|
|
416
430
|
var $MESSENGER_REQUEST = "RPC_PROXY_REQUEST";
|
|
417
431
|
var requestSchema = object({
|
|
418
432
|
[$MESSENGER_REQUEST]: number(),
|
|
@@ -426,7 +440,7 @@ var $MESSENGER_RESPONSE = "RPC_PROXY_RESPONSE";
|
|
|
426
440
|
var ResponseShape = createShape(
|
|
427
441
|
object({
|
|
428
442
|
[$MESSENGER_RESPONSE]: number(),
|
|
429
|
-
payload: unknown()
|
|
443
|
+
payload: optional(unknown())
|
|
430
444
|
}),
|
|
431
445
|
(request, payload) => ({
|
|
432
446
|
[$MESSENGER_RESPONSE]: request[$MESSENGER_REQUEST],
|
|
@@ -453,10 +467,89 @@ var RPCPayloadShape = createShape(
|
|
|
453
467
|
}),
|
|
454
468
|
(topics, args) => ({ [$MESSENGER_RPC_REQUEST]: true, topics, args })
|
|
455
469
|
);
|
|
470
|
+
var $MESSENGER_HANDLE = "RPC_PROXY_HANDLE";
|
|
471
|
+
var HandleResponseShape = createShape(
|
|
472
|
+
object({
|
|
473
|
+
[$MESSENGER_HANDLE]: string()
|
|
474
|
+
// namespace ID
|
|
475
|
+
}),
|
|
476
|
+
(namespaceId) => ({ [$MESSENGER_HANDLE]: namespaceId })
|
|
477
|
+
);
|
|
456
478
|
|
|
457
|
-
// src/
|
|
479
|
+
// src/core.ts
|
|
480
|
+
function createCommander(apply) {
|
|
481
|
+
function _createCommander(topics, apply2) {
|
|
482
|
+
return new Proxy(function() {
|
|
483
|
+
}, {
|
|
484
|
+
get(target, topic) {
|
|
485
|
+
if (typeof topic === "symbol")
|
|
486
|
+
return target[topic];
|
|
487
|
+
if (topic === "then")
|
|
488
|
+
return void 0;
|
|
489
|
+
return _createCommander([...topics, topic], apply2);
|
|
490
|
+
},
|
|
491
|
+
apply(_, __, args) {
|
|
492
|
+
return apply2(topics, args);
|
|
493
|
+
}
|
|
494
|
+
});
|
|
495
|
+
}
|
|
496
|
+
return _createCommander([], apply);
|
|
497
|
+
}
|
|
498
|
+
function callMethod(methods, topics, args) {
|
|
499
|
+
const method = topics.reduce((acc, topic) => {
|
|
500
|
+
const result = acc?.[topic];
|
|
501
|
+
return result;
|
|
502
|
+
}, methods);
|
|
503
|
+
if (typeof method !== "function") {
|
|
504
|
+
throw new Error(`Topics did not resolve to a function: [${topics.join(",")}]`);
|
|
505
|
+
}
|
|
506
|
+
return method(...args);
|
|
507
|
+
}
|
|
508
|
+
function isHandleResponse(value) {
|
|
509
|
+
return !!value && typeof value === "object" && $MESSENGER_HANDLE in value && typeof value[$MESSENGER_HANDLE] === "string";
|
|
510
|
+
}
|
|
511
|
+
function createExposeRequestHandler(methods) {
|
|
512
|
+
const namespaceHandlers = /* @__PURE__ */ new Map();
|
|
513
|
+
const processResult = (result) => {
|
|
514
|
+
if (isHandleMarker(result)) {
|
|
515
|
+
const namespaceId = nextHandleNamespaceId();
|
|
516
|
+
namespaceHandlers.set(namespaceId, result.methods);
|
|
517
|
+
return HandleResponseShape.create(namespaceId);
|
|
518
|
+
}
|
|
519
|
+
return result;
|
|
520
|
+
};
|
|
521
|
+
return async (topics, args) => {
|
|
522
|
+
const firstTopic = topics[0];
|
|
523
|
+
if (firstTopic && firstTopic.startsWith(HANDLE_NAMESPACE_PREFIX)) {
|
|
524
|
+
const handler = namespaceHandlers.get(firstTopic);
|
|
525
|
+
if (!handler) {
|
|
526
|
+
throw new Error(`Unknown namespace: ${firstTopic}`);
|
|
527
|
+
}
|
|
528
|
+
const result2 = await callMethod(handler, topics.slice(1), args);
|
|
529
|
+
return processResult(result2);
|
|
530
|
+
}
|
|
531
|
+
const result = await callMethod(methods, topics, args);
|
|
532
|
+
return processResult(result);
|
|
533
|
+
};
|
|
534
|
+
}
|
|
535
|
+
function createRpcCommander(request, topicPrefix = []) {
|
|
536
|
+
return createCommander((topics, methodArgs) => {
|
|
537
|
+
const fullTopics = [...topicPrefix, ...topics];
|
|
538
|
+
return request(fullTopics, methodArgs).then((result) => {
|
|
539
|
+
if (isHandleResponse(result)) {
|
|
540
|
+
return createRpcCommander(
|
|
541
|
+
request,
|
|
542
|
+
result[$MESSENGER_HANDLE] ? [result[$MESSENGER_HANDLE]] : []
|
|
543
|
+
);
|
|
544
|
+
}
|
|
545
|
+
return result;
|
|
546
|
+
});
|
|
547
|
+
});
|
|
548
|
+
}
|
|
549
|
+
|
|
550
|
+
// src/messenger/index.ts
|
|
458
551
|
var $TRANSFER = "RPC-TRANSFER";
|
|
459
|
-
var $MESSENGER = Symbol("RPC-MESSENGER");
|
|
552
|
+
var $MESSENGER = Symbol.for("RPC-MESSENGER");
|
|
460
553
|
function transfer(value) {
|
|
461
554
|
return Object.assign(value, { [$TRANSFER]: true });
|
|
462
555
|
}
|
|
@@ -529,7 +622,10 @@ function createResponder(messenger, callback, options = {}) {
|
|
|
529
622
|
if (RequestShape.validate(data)) {
|
|
530
623
|
try {
|
|
531
624
|
const result = await callback(data);
|
|
532
|
-
const {
|
|
625
|
+
const {
|
|
626
|
+
args: [processedResult],
|
|
627
|
+
transferables
|
|
628
|
+
} = extractTransferables([result]);
|
|
533
629
|
postMessage(ResponseShape.create(data, processedResult), transferables);
|
|
534
630
|
} catch (error) {
|
|
535
631
|
postMessage(ErrorShape.create(data, error));
|
|
@@ -543,24 +639,37 @@ function createResponder(messenger, callback, options = {}) {
|
|
|
543
639
|
}
|
|
544
640
|
}
|
|
545
641
|
function expose(methods, { to = self, signal } = {}) {
|
|
546
|
-
|
|
547
|
-
|
|
548
|
-
|
|
549
|
-
|
|
642
|
+
const postMessage = usePostMessage(to);
|
|
643
|
+
const handleRequest = createExposeRequestHandler(methods);
|
|
644
|
+
to.addEventListener(
|
|
645
|
+
"message",
|
|
646
|
+
async (event) => {
|
|
647
|
+
const data = event.data;
|
|
648
|
+
if (RequestShape.validate(data)) {
|
|
550
649
|
try {
|
|
551
|
-
|
|
552
|
-
|
|
650
|
+
if (RPCPayloadShape.validate(data.payload)) {
|
|
651
|
+
const result = await handleRequest(data.payload.topics, data.payload.args);
|
|
652
|
+
const {
|
|
653
|
+
args: [finalResult],
|
|
654
|
+
transferables
|
|
655
|
+
} = extractTransferables([result]);
|
|
656
|
+
postMessage(ResponseShape.create(data, finalResult), transferables);
|
|
657
|
+
}
|
|
553
658
|
} catch (error) {
|
|
554
|
-
console.error("Error while processing rpc request:", error, data.payload
|
|
659
|
+
console.error("Error while processing rpc request:", error, data.payload);
|
|
660
|
+
postMessage(ErrorShape.create(data, error));
|
|
555
661
|
}
|
|
556
662
|
}
|
|
557
663
|
},
|
|
558
664
|
{ signal }
|
|
559
665
|
);
|
|
666
|
+
if ("start" in to) {
|
|
667
|
+
to.start?.();
|
|
668
|
+
}
|
|
560
669
|
}
|
|
561
670
|
function rpc(messenger, options) {
|
|
562
671
|
const request = createRequester(messenger, options);
|
|
563
|
-
const proxy =
|
|
672
|
+
const proxy = createRpcCommander((topics, args) => {
|
|
564
673
|
const { args: processedArgs, transferables } = extractTransferables(args);
|
|
565
674
|
return request(RPCPayloadShape.create(topics, processedArgs), transferables);
|
|
566
675
|
});
|
|
@@ -571,6 +680,7 @@ export {
|
|
|
571
680
|
$TRANSFER,
|
|
572
681
|
createResponder,
|
|
573
682
|
expose,
|
|
683
|
+
handle,
|
|
574
684
|
rpc,
|
|
575
685
|
transfer
|
|
576
686
|
};
|