@x-oasis/async-call-rpc 0.1.38

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 (104) hide show
  1. package/README.md +48 -0
  2. package/dist/async-call-rpc.cjs.development.js +1275 -0
  3. package/dist/async-call-rpc.cjs.development.js.map +1 -0
  4. package/dist/async-call-rpc.cjs.production.min.js +2 -0
  5. package/dist/async-call-rpc.cjs.production.min.js.map +1 -0
  6. package/dist/async-call-rpc.esm.js +1559 -0
  7. package/dist/async-call-rpc.esm.js.map +1 -0
  8. package/dist/buffer/BufferFactory.d.ts +12 -0
  9. package/dist/buffer/DataBuffer.d.ts +2 -0
  10. package/dist/buffer/MessagePackBuffer.d.ts +10 -0
  11. package/dist/buffer/ReadBaseBuffer.d.ts +5 -0
  12. package/dist/buffer/ReadBuffer.d.ts +14 -0
  13. package/dist/buffer/SerializationFormat.d.ts +16 -0
  14. package/dist/buffer/WriteBaseBuffer.d.ts +5 -0
  15. package/dist/buffer/WriteBuffer.d.ts +5 -0
  16. package/dist/buffer/examples.d.ts +10 -0
  17. package/dist/buffer/index.d.ts +8 -0
  18. package/dist/common.d.ts +4 -0
  19. package/dist/endpoint/ProxyRPCClient.d.ts +12 -0
  20. package/dist/endpoint/RPCClientHost.d.ts +12 -0
  21. package/dist/endpoint/RPCService.d.ts +20 -0
  22. package/dist/endpoint/RPCServiceHost.d.ts +10 -0
  23. package/dist/error.d.ts +21 -0
  24. package/dist/index.d.ts +11 -0
  25. package/dist/index.js +8 -0
  26. package/dist/middlewares/buffer.d.ts +18 -0
  27. package/dist/middlewares/handleDisconnectedRequest.d.ts +7 -0
  28. package/dist/middlewares/handlePortRequest.d.ts +3 -0
  29. package/dist/middlewares/handleRequest.d.ts +3 -0
  30. package/dist/middlewares/handleRequestUtils.d.ts +10 -0
  31. package/dist/middlewares/handleResponse.d.ts +3 -0
  32. package/dist/middlewares/index.d.ts +7 -0
  33. package/dist/middlewares/logger.d.ts +4 -0
  34. package/dist/middlewares/normalize.d.ts +14 -0
  35. package/dist/middlewares/prepareRequestData.d.ts +28 -0
  36. package/dist/middlewares/sendRequest.d.ts +6 -0
  37. package/dist/middlewares/updateSeqInfo.d.ts +6 -0
  38. package/dist/middlewares/utils.d.ts +3 -0
  39. package/dist/protocol/AbstractChannelProtocol.d.ts +55 -0
  40. package/dist/protocol/MessageChannel.d.ts +18 -0
  41. package/dist/protocol/WebSocketChannel.d.ts +23 -0
  42. package/dist/protocol/WorkerChannel.d.ts +11 -0
  43. package/dist/types/buffer.d.ts +4 -0
  44. package/dist/types/channel.d.ts +27 -0
  45. package/dist/types/index.d.ts +7 -0
  46. package/dist/types/middleware.d.ts +44 -0
  47. package/dist/types/proxyChannel.d.ts +3 -0
  48. package/dist/types/proxyService.d.ts +11 -0
  49. package/dist/types/rpc.d.ts +25 -0
  50. package/dist/types/rpcProtocol.d.ts +22 -0
  51. package/dist/utils/constants.d.ts +5 -0
  52. package/dist/utils/index.d.ts +2 -0
  53. package/dist/utils/jsonrpc.d.ts +36 -0
  54. package/package.json +36 -0
  55. package/src/buffer/ARCHITECTURE.md +298 -0
  56. package/src/buffer/BufferFactory.ts +124 -0
  57. package/src/buffer/CHANGELOG.md +207 -0
  58. package/src/buffer/DataBuffer.ts +1 -0
  59. package/src/buffer/MessagePackBuffer.ts +79 -0
  60. package/src/buffer/OPTIMIZATION.md +258 -0
  61. package/src/buffer/README.md +147 -0
  62. package/src/buffer/ReadBaseBuffer.ts +20 -0
  63. package/src/buffer/ReadBuffer.ts +58 -0
  64. package/src/buffer/SerializationFormat.ts +81 -0
  65. package/src/buffer/WriteBaseBuffer.ts +20 -0
  66. package/src/buffer/WriteBuffer.ts +15 -0
  67. package/src/buffer/examples.ts +242 -0
  68. package/src/buffer/index.ts +15 -0
  69. package/src/common.ts +20 -0
  70. package/src/endpoint/ProxyRPCClient.ts +64 -0
  71. package/src/endpoint/RPCClientHost.ts +45 -0
  72. package/src/endpoint/RPCService.ts +54 -0
  73. package/src/endpoint/RPCServiceHost.ts +18 -0
  74. package/src/error.ts +98 -0
  75. package/src/index.ts +16 -0
  76. package/src/middlewares/buffer.ts +33 -0
  77. package/src/middlewares/handleDisconnectedRequest.ts +30 -0
  78. package/src/middlewares/handlePortRequest.ts +141 -0
  79. package/src/middlewares/handleRequest.ts +128 -0
  80. package/src/middlewares/handleRequestUtils.ts +43 -0
  81. package/src/middlewares/handleResponse.ts +36 -0
  82. package/src/middlewares/index.ts +11 -0
  83. package/src/middlewares/logger.ts +22 -0
  84. package/src/middlewares/normalize.ts +167 -0
  85. package/src/middlewares/prepareRequestData.ts +137 -0
  86. package/src/middlewares/sendRequest.ts +15 -0
  87. package/src/middlewares/updateSeqInfo.ts +34 -0
  88. package/src/middlewares/utils.ts +67 -0
  89. package/src/protocol/AbstractChannelProtocol.ts +343 -0
  90. package/src/protocol/MessageChannel.ts +80 -0
  91. package/src/protocol/WebSocketChannel.ts +179 -0
  92. package/src/protocol/WorkerChannel.ts +36 -0
  93. package/src/types/buffer.ts +5 -0
  94. package/src/types/channel.ts +50 -0
  95. package/src/types/index.ts +9 -0
  96. package/src/types/messageChannel.ts +133 -0
  97. package/src/types/middleware.ts +54 -0
  98. package/src/types/proxyChannel.ts +3 -0
  99. package/src/types/proxyService.ts +18 -0
  100. package/src/types/rpc.ts +61 -0
  101. package/src/types/rpcProtocol.ts +24 -0
  102. package/src/utils/constants.ts +17 -0
  103. package/src/utils/index.ts +5 -0
  104. package/src/utils/jsonrpc.ts +242 -0
@@ -0,0 +1,167 @@
1
+ import { NormalizedRawMessageOutput } from '../types';
2
+
3
+ export const normalizeMessageChannelRawMessage =
4
+ () =>
5
+ (event: MessageEvent): NormalizedRawMessageOutput => {
6
+ return {
7
+ event,
8
+ data: event.data,
9
+ ports: event.ports || [],
10
+ };
11
+ };
12
+
13
+ export const normalizeIPCChannelRawMessage =
14
+ () => (event: MessageEvent, data: string) => {
15
+ return {
16
+ event,
17
+ data,
18
+ ports: event.ports || [],
19
+ };
20
+ };
21
+
22
+ export const processClientRawMessage = () => (data: string) => {
23
+ return {
24
+ event: null,
25
+ data,
26
+ ports: [],
27
+ };
28
+ };
29
+
30
+ /**
31
+ * Helper function to check if Buffer is available (Node.js environment)
32
+ */
33
+ function isBufferAvailable(): boolean {
34
+ return typeof Buffer !== 'undefined' && Buffer.isBuffer !== undefined;
35
+ }
36
+
37
+ /**
38
+ * Helper function to check if value is a Buffer (works in both browser and Node.js)
39
+ */
40
+ function isBuffer(value: any): boolean {
41
+ if (!isBufferAvailable()) {
42
+ return false;
43
+ }
44
+ return Buffer.isBuffer(value);
45
+ }
46
+
47
+ /**
48
+ * Helper function to convert ArrayBuffer to string (works in both browser and Node.js)
49
+ */
50
+ function arrayBufferToString(buffer: ArrayBuffer): string {
51
+ if (isBufferAvailable()) {
52
+ return Buffer.from(buffer).toString('utf8');
53
+ } else {
54
+ // Browser environment: use TextDecoder
55
+ try {
56
+ return new TextDecoder('utf-8').decode(buffer);
57
+ } catch (e) {
58
+ // Fallback: convert Uint8Array to string
59
+ const uint8Array = new Uint8Array(buffer);
60
+ return String.fromCharCode.apply(null, Array.from(uint8Array));
61
+ }
62
+ }
63
+ }
64
+
65
+ /**
66
+ * Helper function to convert Buffer to string (Node.js only)
67
+ */
68
+ function bufferToString(buffer: any): string {
69
+ if (isBufferAvailable() && Buffer.isBuffer(buffer)) {
70
+ return buffer.toString('utf8');
71
+ }
72
+ return String(buffer);
73
+ }
74
+
75
+ /**
76
+ * Normalize WebSocket raw message
77
+ * Handles both browser MessageEvent and Node.js ws library format
78
+ */
79
+ export const normalizeWebSocketRawMessage =
80
+ () =>
81
+ (
82
+ eventOrData: MessageEvent | Buffer | string | any,
83
+ ...args: any[]
84
+ ): NormalizedRawMessageOutput => {
85
+ // Handle undefined or null
86
+ if (eventOrData === undefined || eventOrData === null) {
87
+ console.warn(
88
+ '[normalizeWebSocketRawMessage] Received undefined or null data'
89
+ );
90
+ return {
91
+ event: null,
92
+ data: '',
93
+ ports: [],
94
+ };
95
+ }
96
+
97
+ let normalizedData = '';
98
+ let event: MessageEvent | null = null;
99
+ let ports: MessagePort[] = [];
100
+
101
+ // Check if this is a MessageEvent (browser or ws library with EventTarget)
102
+ if (
103
+ eventOrData &&
104
+ typeof eventOrData === 'object' &&
105
+ 'data' in eventOrData
106
+ ) {
107
+ event = eventOrData as MessageEvent;
108
+ const data = event.data;
109
+ // Create a new array to avoid readonly type issues
110
+ ports = event.ports ? [...event.ports] : [];
111
+
112
+ // Handle different data types in MessageEvent
113
+ if (data === undefined || data === null) {
114
+ normalizedData = '';
115
+ } else if (typeof data === 'string') {
116
+ normalizedData = data;
117
+ } else if (isBuffer(data)) {
118
+ normalizedData = bufferToString(data);
119
+ } else if (data instanceof ArrayBuffer) {
120
+ normalizedData = arrayBufferToString(data);
121
+ } else if (data instanceof Blob) {
122
+ // For Blob, we'd need async handling, but for now return empty
123
+ // In practice, WebSocket text frames should be strings
124
+ normalizedData = '';
125
+ } else {
126
+ normalizedData = String(data);
127
+ }
128
+ } else {
129
+ // Node.js ws library: direct data (Buffer or string)
130
+ // The ws library may pass data directly, or as (data, isBinary) tuple
131
+ // If args[0] exists and eventOrData is not an object with 'data',
132
+ // then args might contain the actual data
133
+ let actualData = eventOrData;
134
+
135
+ // Check if this might be a tuple (data, isBinary) from ws library
136
+ if (
137
+ args.length > 0 &&
138
+ (typeof eventOrData === 'string' || isBuffer(eventOrData))
139
+ ) {
140
+ // This is likely (data, isBinary) format, use eventOrData as data
141
+ actualData = eventOrData;
142
+ }
143
+
144
+ // Convert Buffer to string if needed
145
+ if (isBuffer(actualData)) {
146
+ normalizedData = bufferToString(actualData);
147
+ } else if (typeof actualData === 'string') {
148
+ normalizedData = actualData;
149
+ } else if (actualData instanceof ArrayBuffer) {
150
+ normalizedData = arrayBufferToString(actualData);
151
+ } else {
152
+ // Fallback: try to stringify
153
+ normalizedData = String(actualData);
154
+ }
155
+ }
156
+
157
+ // Ensure normalizedData is never undefined or null
158
+ if (normalizedData === undefined || normalizedData === null) {
159
+ normalizedData = '';
160
+ }
161
+
162
+ return {
163
+ event,
164
+ data: normalizedData,
165
+ ports,
166
+ };
167
+ };
@@ -0,0 +1,137 @@
1
+ import AbstractChannelProtocol from '../protocol/AbstractChannelProtocol';
2
+ import {
3
+ SendingProps,
4
+ RequestEntryHeader,
5
+ HostRequestEntryHeader,
6
+ RequestType,
7
+ SendMiddlewareLifecycle,
8
+ } from '../types';
9
+
10
+ export const preparePortData = (channel: AbstractChannelProtocol) => {
11
+ const fn = (props: string | SendingProps, ...args: any[]) => {
12
+ let requestPath = '';
13
+ let methodName = '';
14
+ let params = [] as any[];
15
+ let transfer = [];
16
+ let isOptionsRequest = false;
17
+
18
+ const seqId = channel.seqId;
19
+
20
+ if (typeof props === 'string') {
21
+ requestPath = props;
22
+ methodName = args[0];
23
+ params = args.slice(1);
24
+ } else {
25
+ requestPath = props.requestPath;
26
+ methodName = props.methodName;
27
+ isOptionsRequest = props.isOptionsRequest;
28
+ // args will convert to array on default
29
+ params = [].concat(props.args);
30
+ transfer = args[0] ? args[0] : [];
31
+ }
32
+
33
+ const header: RequestEntryHeader = [
34
+ RequestType.PromiseRequest,
35
+ seqId,
36
+ requestPath,
37
+ methodName,
38
+ ];
39
+
40
+ const body = params;
41
+ return {
42
+ seqId,
43
+ transfer,
44
+ isOptionsRequest,
45
+ data: [header, body],
46
+ };
47
+ };
48
+
49
+ fn.lifecycle = SendMiddlewareLifecycle.Prepare;
50
+ return fn;
51
+ };
52
+
53
+ export const prepareHostPortData = (channel: AbstractChannelProtocol) => {
54
+ const fn = (props: string | SendingProps, ...args: any[]) => {
55
+ let requestPath = '';
56
+ let methodName = '';
57
+ let params = [] as any[];
58
+ let transfer = [];
59
+ const seqId = channel.seqId;
60
+ let isOptionsRequest = false;
61
+
62
+ if (typeof props === 'string') {
63
+ requestPath = props;
64
+ methodName = args[0];
65
+ params = args.slice(1);
66
+ } else {
67
+ requestPath = props.requestPath;
68
+ methodName = props.methodName;
69
+ isOptionsRequest = props.isOptionsRequest;
70
+ // args will convert to array on default
71
+ params = [].concat(props.args);
72
+ transfer = args[0] ? args[0] : [];
73
+ }
74
+
75
+ const header: HostRequestEntryHeader = [
76
+ RequestType.PromiseRequest,
77
+ seqId,
78
+ requestPath,
79
+ methodName,
80
+ // @ts-ignore
81
+ channel.channelName,
82
+ ];
83
+
84
+ const body = params;
85
+
86
+ return {
87
+ seqId,
88
+ transfer,
89
+ isOptionsRequest,
90
+ data: [header, body],
91
+ };
92
+ };
93
+
94
+ fn.lifecycle = SendMiddlewareLifecycle.Prepare;
95
+ return fn;
96
+ };
97
+
98
+ export const prepareNormalData = (channel: AbstractChannelProtocol) => {
99
+ const fn = (props: string | SendingProps, ...args: any[]) => {
100
+ let requestPath = '';
101
+ let methodName = '';
102
+ let params = [] as any[];
103
+ const seqId = channel.seqId;
104
+ let isOptionsRequest = false;
105
+
106
+ if (typeof props === 'string') {
107
+ requestPath = props;
108
+ methodName = args[0];
109
+ params = args.slice(1);
110
+ } else {
111
+ requestPath = props.requestPath;
112
+ methodName = props.methodName;
113
+ isOptionsRequest = props.isOptionsRequest;
114
+ // args will convert to array on default
115
+ params = [].concat(props.args);
116
+ }
117
+
118
+ const header: RequestEntryHeader = [
119
+ RequestType.PromiseRequest,
120
+ seqId,
121
+ requestPath,
122
+ methodName,
123
+ ];
124
+
125
+ const body = params;
126
+
127
+ return {
128
+ seqId,
129
+ isOptionsRequest,
130
+ data: [header, body],
131
+ };
132
+ };
133
+
134
+ fn.lifecycle = SendMiddlewareLifecycle.Prepare;
135
+
136
+ return fn;
137
+ };
@@ -0,0 +1,15 @@
1
+ import { SenderMiddlewareOutput, SendMiddlewareLifecycle } from '../types';
2
+ import AbstractChannelProtocol from '../protocol/AbstractChannelProtocol';
3
+
4
+ export const sendRequest = (channelProtocol: AbstractChannelProtocol) => {
5
+ const fn = (value: SenderMiddlewareOutput) => {
6
+ const { data, transfer } = value;
7
+ if (transfer) channelProtocol.send(data, transfer);
8
+ else channelProtocol.send(data);
9
+
10
+ return value;
11
+ };
12
+
13
+ fn.lifecycle = SendMiddlewareLifecycle.Send;
14
+ return fn;
15
+ };
@@ -0,0 +1,34 @@
1
+ import { createDeferred } from '@x-oasis/deferred';
2
+ import { isEventMethod } from '../common';
3
+ import { SenderMiddlewareOutput, SendMiddlewareLifecycle } from '../types';
4
+ import AbstractChannelProtocol from '../protocol/AbstractChannelProtocol';
5
+
6
+ /**
7
+ *
8
+ * @param channelProtocol
9
+ * @returns
10
+ *
11
+ * Add how to handle the request and response
12
+ */
13
+ export const updateSeqInfo = (channelProtocol: AbstractChannelProtocol) => {
14
+ const fn = (value: SenderMiddlewareOutput) => {
15
+ const { data, seqId } = value;
16
+ const header = data[0];
17
+ const body = data[1];
18
+ const methodName = header[3];
19
+
20
+ // 如果说是event method的话,需要将body重制一下
21
+ if (methodName && isEventMethod(methodName)) {
22
+ channelProtocol.requestEvents.set(`${seqId}`, body[0]);
23
+ data[1] = [];
24
+ } else {
25
+ const returnValue = createDeferred();
26
+ channelProtocol.ongoingRequests.set(`${seqId}`, returnValue);
27
+ value.returnValue = returnValue;
28
+ }
29
+ return value;
30
+ };
31
+
32
+ fn.lifecycle = SendMiddlewareLifecycle.Transform;
33
+ return fn;
34
+ };
@@ -0,0 +1,67 @@
1
+ import {
2
+ MiddlewareContext,
3
+ PendingSendEntry,
4
+ MiddlewareFunction,
5
+ SendMiddlewareLifecycle,
6
+ } from '../types';
7
+
8
+ export const resumeMiddlewares = (
9
+ middlewares: any,
10
+ entry: PendingSendEntry
11
+ ) => {
12
+ let start = false;
13
+
14
+ return middlewares.reduce((a: any, b: MiddlewareFunction) => {
15
+ if (!b.lifecycle) return a;
16
+ if (a.lifecycle >= b.lifecycle && b.displayName === a.methodName) {
17
+ start = true;
18
+ }
19
+ if (!start) return a;
20
+
21
+ const targetLifecycle = a?.middlewareContext?.minLifecycle;
22
+ const currentLifecycle = b?.lifecycle;
23
+
24
+ // @ts-ignore
25
+ if (
26
+ targetLifecycle &&
27
+ currentLifecycle &&
28
+ currentLifecycle < targetLifecycle
29
+ ) {
30
+ return a;
31
+ }
32
+
33
+ return b(a);
34
+ }, entry);
35
+ };
36
+
37
+ export const runMiddlewares = (
38
+ middlewares: any,
39
+ args: any[],
40
+ _context?: MiddlewareContext
41
+ ) => {
42
+ const context = {
43
+ isResumed: false,
44
+ startLifecycle: SendMiddlewareLifecycle.Initial,
45
+ minLifecycle: SendMiddlewareLifecycle.Initial,
46
+ ...(_context || {}),
47
+ };
48
+
49
+ return middlewares.reduce((a: any, b: MiddlewareFunction, index: number) => {
50
+ if (!index) return b(...a);
51
+ if (index === 1) {
52
+ a.middlewareContext = context;
53
+ }
54
+
55
+ const targetLifecycle = a?.middlewareContext?.minLifecycle;
56
+ const currentLifecycle = b?.lifecycle;
57
+
58
+ if (
59
+ targetLifecycle &&
60
+ currentLifecycle &&
61
+ currentLifecycle < targetLifecycle
62
+ ) {
63
+ return a;
64
+ }
65
+ return b(a);
66
+ }, args);
67
+ };