request-iframe 0.0.1 → 0.0.3

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 (96) hide show
  1. package/README.CN.md +271 -12
  2. package/README.md +268 -11
  3. package/library/__tests__/channel.test.ts +420 -0
  4. package/library/__tests__/debug.test.ts +588 -0
  5. package/library/__tests__/dispatcher.test.ts +481 -0
  6. package/library/__tests__/interceptors.test.ts +22 -0
  7. package/library/__tests__/requestIframe.test.ts +2317 -99
  8. package/library/__tests__/server.test.ts +738 -0
  9. package/library/api/client.d.js +5 -0
  10. package/library/api/client.d.ts.map +1 -1
  11. package/library/api/client.js +11 -6
  12. package/library/api/server.d.js +5 -0
  13. package/library/api/server.d.ts +4 -3
  14. package/library/api/server.d.ts.map +1 -1
  15. package/library/api/server.js +25 -7
  16. package/library/constants/index.d.js +36 -0
  17. package/library/constants/index.d.ts +14 -4
  18. package/library/constants/index.d.ts.map +1 -1
  19. package/library/constants/index.js +15 -7
  20. package/library/constants/messages.d.js +5 -0
  21. package/library/constants/messages.d.ts +35 -0
  22. package/library/constants/messages.d.ts.map +1 -1
  23. package/library/constants/messages.js +36 -1
  24. package/library/core/client-server.d.ts +101 -0
  25. package/library/core/client-server.d.ts.map +1 -0
  26. package/library/core/client-server.js +266 -0
  27. package/library/core/client.d.js +5 -0
  28. package/library/core/client.d.ts +38 -6
  29. package/library/core/client.d.ts.map +1 -1
  30. package/library/core/client.js +198 -24
  31. package/library/core/request.d.js +5 -0
  32. package/library/core/response.d.js +5 -0
  33. package/library/core/response.d.ts +5 -1
  34. package/library/core/response.d.ts.map +1 -1
  35. package/library/core/response.js +85 -70
  36. package/library/core/server-client.d.js +5 -0
  37. package/library/core/server-client.d.ts +3 -1
  38. package/library/core/server-client.d.ts.map +1 -1
  39. package/library/core/server-client.js +19 -9
  40. package/library/core/server.d.js +5 -0
  41. package/library/core/server.d.ts +11 -3
  42. package/library/core/server.d.ts.map +1 -1
  43. package/library/core/server.js +112 -54
  44. package/library/index.d.ts +1 -1
  45. package/library/index.js +2 -2
  46. package/library/interceptors/index.d.js +5 -0
  47. package/library/interceptors/index.d.ts +4 -0
  48. package/library/interceptors/index.d.ts.map +1 -1
  49. package/library/interceptors/index.js +7 -0
  50. package/library/message/channel.d.js +5 -0
  51. package/library/message/channel.d.ts +3 -1
  52. package/library/message/channel.d.ts.map +1 -1
  53. package/library/message/dispatcher.d.js +5 -0
  54. package/library/message/dispatcher.d.ts +7 -2
  55. package/library/message/dispatcher.d.ts.map +1 -1
  56. package/library/message/dispatcher.js +47 -2
  57. package/library/message/index.d.js +25 -0
  58. package/library/stream/file-stream.d.js +4 -0
  59. package/library/stream/file-stream.d.ts +5 -0
  60. package/library/stream/file-stream.d.ts.map +1 -1
  61. package/library/stream/file-stream.js +41 -12
  62. package/library/stream/index.d.js +58 -0
  63. package/library/stream/readable-stream.d.js +5 -0
  64. package/library/stream/readable-stream.d.ts.map +1 -1
  65. package/library/stream/readable-stream.js +32 -30
  66. package/library/stream/types.d.js +5 -0
  67. package/library/stream/types.d.ts +18 -0
  68. package/library/stream/types.d.ts.map +1 -1
  69. package/library/stream/writable-stream.d.js +5 -0
  70. package/library/stream/writable-stream.d.ts +1 -0
  71. package/library/stream/writable-stream.d.ts.map +1 -1
  72. package/library/stream/writable-stream.js +7 -2
  73. package/library/types/index.d.js +5 -0
  74. package/library/types/index.d.ts +79 -19
  75. package/library/types/index.d.ts.map +1 -1
  76. package/library/utils/cache.d.js +5 -0
  77. package/library/utils/cache.d.ts +24 -0
  78. package/library/utils/cache.d.ts.map +1 -1
  79. package/library/utils/cache.js +76 -0
  80. package/library/utils/cookie.d.js +5 -0
  81. package/library/utils/debug.d.js +5 -0
  82. package/library/utils/debug.d.ts.map +1 -1
  83. package/library/utils/debug.js +382 -20
  84. package/library/utils/index.d.js +94 -0
  85. package/library/utils/index.d.ts +5 -0
  86. package/library/utils/index.d.ts.map +1 -1
  87. package/library/utils/index.js +14 -1
  88. package/library/utils/path-match.d.js +5 -0
  89. package/library/utils/protocol.d.js +5 -0
  90. package/package.json +16 -2
  91. package/react/library/__tests__/index.test.d.ts +2 -0
  92. package/react/library/__tests__/index.test.d.ts.map +1 -0
  93. package/react/library/__tests__/index.test.tsx +770 -0
  94. package/react/library/index.d.ts +118 -0
  95. package/react/library/index.d.ts.map +1 -0
  96. package/react/library/index.js +232 -0
@@ -0,0 +1,420 @@
1
+ import { MessageChannel, ChannelType, MessageContext } from '../message/channel';
2
+ import { createPostMessage } from '../utils';
3
+ import { MessageType, MessageRole } from '../constants';
4
+
5
+ describe('MessageChannel', () => {
6
+ let channel: MessageChannel;
7
+ let mockReceiver: jest.Mock;
8
+
9
+ beforeEach(() => {
10
+ mockReceiver = jest.fn();
11
+ channel = new MessageChannel();
12
+ });
13
+
14
+ afterEach(() => {
15
+ channel.destroy();
16
+ });
17
+
18
+ describe('constructor', () => {
19
+ it('should create channel with default type', () => {
20
+ expect(channel.type).toBe(ChannelType.POST_MESSAGE);
21
+ });
22
+
23
+ it('should create channel with secretKey', () => {
24
+ const channelWithKey = new MessageChannel('test-key');
25
+ expect(channelWithKey.secretKey).toBe('test-key');
26
+ channelWithKey.destroy();
27
+ });
28
+
29
+ it('should add message event listener', () => {
30
+ const addEventListenerSpy = jest.spyOn(window, 'addEventListener');
31
+ const testChannel = new MessageChannel();
32
+ expect(addEventListenerSpy).toHaveBeenCalledWith('message', expect.any(Function));
33
+ testChannel.destroy();
34
+ addEventListenerSpy.mockRestore();
35
+ });
36
+ });
37
+
38
+ describe('addReceiver and removeReceiver', () => {
39
+ it('should add receiver callback', () => {
40
+ channel.addReceiver(mockReceiver);
41
+
42
+ const message = createPostMessage(MessageType.REQUEST, 'req123', {
43
+ path: 'test'
44
+ });
45
+
46
+ window.dispatchEvent(
47
+ new MessageEvent('message', {
48
+ data: message,
49
+ origin: 'https://example.com'
50
+ })
51
+ );
52
+
53
+ // Wait for async message handling
54
+ setTimeout(() => {
55
+ expect(mockReceiver).toHaveBeenCalled();
56
+ }, 10);
57
+ });
58
+
59
+ it('should remove receiver callback', () => {
60
+ channel.addReceiver(mockReceiver);
61
+ channel.removeReceiver(mockReceiver);
62
+
63
+ const message = createPostMessage(MessageType.REQUEST, 'req123', {
64
+ path: 'test'
65
+ });
66
+
67
+ window.dispatchEvent(
68
+ new MessageEvent('message', {
69
+ data: message,
70
+ origin: 'https://example.com'
71
+ })
72
+ );
73
+
74
+ // Wait for async message handling
75
+ setTimeout(() => {
76
+ expect(mockReceiver).not.toHaveBeenCalled();
77
+ }, 10);
78
+ });
79
+
80
+ it('should support multiple receivers', () => {
81
+ const receiver1 = jest.fn();
82
+ const receiver2 = jest.fn();
83
+
84
+ channel.addReceiver(receiver1);
85
+ channel.addReceiver(receiver2);
86
+
87
+ const message = createPostMessage(MessageType.REQUEST, 'req123', {
88
+ path: 'test'
89
+ });
90
+
91
+ window.dispatchEvent(
92
+ new MessageEvent('message', {
93
+ data: message,
94
+ origin: 'https://example.com'
95
+ })
96
+ );
97
+
98
+ // Wait for async message handling
99
+ setTimeout(() => {
100
+ expect(receiver1).toHaveBeenCalled();
101
+ expect(receiver2).toHaveBeenCalled();
102
+ }, 10);
103
+ });
104
+ });
105
+
106
+ describe('reference counting', () => {
107
+ it('should increment reference count', () => {
108
+ expect(channel.getRefCount()).toBe(0);
109
+ channel.addRef();
110
+ expect(channel.getRefCount()).toBe(1);
111
+ channel.addRef();
112
+ expect(channel.getRefCount()).toBe(2);
113
+ });
114
+
115
+ it('should decrement reference count', () => {
116
+ channel.addRef();
117
+ channel.addRef();
118
+ expect(channel.release()).toBe(1);
119
+ expect(channel.release()).toBe(0);
120
+ });
121
+ });
122
+
123
+ describe('message filtering', () => {
124
+ it('should filter messages by secretKey', () => {
125
+ const channelWithKey = new MessageChannel('test-key');
126
+ channelWithKey.addReceiver(mockReceiver);
127
+
128
+ // Message with matching secretKey
129
+ const validMessage = createPostMessage(MessageType.REQUEST, 'req123', {
130
+ path: 'test',
131
+ secretKey: 'test-key'
132
+ });
133
+
134
+ window.dispatchEvent(
135
+ new MessageEvent('message', {
136
+ data: validMessage,
137
+ origin: 'https://example.com'
138
+ })
139
+ );
140
+
141
+ // Message with different secretKey
142
+ const invalidMessage = createPostMessage(MessageType.REQUEST, 'req124', {
143
+ path: 'test',
144
+ secretKey: 'other-key'
145
+ });
146
+
147
+ window.dispatchEvent(
148
+ new MessageEvent('message', {
149
+ data: invalidMessage,
150
+ origin: 'https://example.com'
151
+ })
152
+ );
153
+
154
+ setTimeout(() => {
155
+ expect(mockReceiver).toHaveBeenCalledTimes(1);
156
+ expect(mockReceiver).toHaveBeenCalledWith(
157
+ validMessage,
158
+ expect.objectContaining({
159
+ origin: 'https://example.com'
160
+ })
161
+ );
162
+ }, 10);
163
+
164
+ channelWithKey.destroy();
165
+ });
166
+
167
+ it('should filter messages without secretKey when channel has secretKey', () => {
168
+ const channelWithKey = new MessageChannel('test-key');
169
+ channelWithKey.addReceiver(mockReceiver);
170
+
171
+ // Message without secretKey
172
+ const message = createPostMessage(MessageType.REQUEST, 'req123', {
173
+ path: 'test'
174
+ });
175
+ delete (message as any).secretKey;
176
+
177
+ window.dispatchEvent(
178
+ new MessageEvent('message', {
179
+ data: message,
180
+ origin: 'https://example.com'
181
+ })
182
+ );
183
+
184
+ setTimeout(() => {
185
+ expect(mockReceiver).not.toHaveBeenCalled();
186
+ }, 10);
187
+
188
+ channelWithKey.destroy();
189
+ });
190
+
191
+ it('should accept messages without secretKey when channel has no secretKey', () => {
192
+ channel.addReceiver(mockReceiver);
193
+
194
+ const message = createPostMessage(MessageType.REQUEST, 'req123', {
195
+ path: 'test'
196
+ });
197
+ delete (message as any).secretKey;
198
+
199
+ window.dispatchEvent(
200
+ new MessageEvent('message', {
201
+ data: message,
202
+ origin: 'https://example.com'
203
+ })
204
+ );
205
+
206
+ setTimeout(() => {
207
+ expect(mockReceiver).toHaveBeenCalled();
208
+ }, 10);
209
+ });
210
+
211
+ it('should ignore invalid postMessage format', () => {
212
+ channel.addReceiver(mockReceiver);
213
+
214
+ window.dispatchEvent(
215
+ new MessageEvent('message', {
216
+ data: { invalid: 'message' },
217
+ origin: 'https://example.com'
218
+ })
219
+ );
220
+
221
+ setTimeout(() => {
222
+ expect(mockReceiver).not.toHaveBeenCalled();
223
+ }, 10);
224
+ });
225
+ });
226
+
227
+ describe('send', () => {
228
+ it('should send message to target window', () => {
229
+ const targetWindow = {
230
+ postMessage: jest.fn()
231
+ } as any;
232
+
233
+ const message = createPostMessage(MessageType.REQUEST, 'req123', {
234
+ path: 'test'
235
+ });
236
+
237
+ channel.send(targetWindow, message, 'https://example.com');
238
+
239
+ expect(targetWindow.postMessage).toHaveBeenCalledWith(
240
+ message,
241
+ 'https://example.com'
242
+ );
243
+ });
244
+
245
+ it('should use default origin * when not specified', () => {
246
+ const targetWindow = {
247
+ postMessage: jest.fn()
248
+ } as any;
249
+
250
+ const message = createPostMessage(MessageType.REQUEST, 'req123', {
251
+ path: 'test'
252
+ });
253
+
254
+ channel.send(targetWindow, message);
255
+
256
+ expect(targetWindow.postMessage).toHaveBeenCalledWith(
257
+ message,
258
+ '*'
259
+ );
260
+ });
261
+ });
262
+
263
+ describe('sendMessage', () => {
264
+ it('should create and send message', () => {
265
+ const targetWindow = {
266
+ postMessage: jest.fn()
267
+ } as any;
268
+
269
+ channel.sendMessage(
270
+ targetWindow,
271
+ 'https://example.com',
272
+ MessageType.REQUEST,
273
+ 'req123',
274
+ {
275
+ path: 'test',
276
+ body: { param: 'value' }
277
+ }
278
+ );
279
+
280
+ expect(targetWindow.postMessage).toHaveBeenCalledWith(
281
+ expect.objectContaining({
282
+ __requestIframe__: 1,
283
+ type: 'request',
284
+ requestId: 'req123',
285
+ path: 'test',
286
+ body: { param: 'value' },
287
+ secretKey: undefined
288
+ }),
289
+ 'https://example.com'
290
+ );
291
+ });
292
+
293
+ it('should include secretKey in message', () => {
294
+ const channelWithKey = new MessageChannel('test-key');
295
+ const targetWindow = {
296
+ postMessage: jest.fn()
297
+ } as any;
298
+
299
+ channelWithKey.sendMessage(
300
+ targetWindow,
301
+ 'https://example.com',
302
+ MessageType.REQUEST,
303
+ 'req123',
304
+ { path: 'test' }
305
+ );
306
+
307
+ expect(targetWindow.postMessage).toHaveBeenCalledWith(
308
+ expect.objectContaining({
309
+ secretKey: 'test-key'
310
+ }),
311
+ 'https://example.com'
312
+ );
313
+
314
+ channelWithKey.destroy();
315
+ });
316
+ });
317
+
318
+ describe('prefixPath', () => {
319
+ it('should add secretKey prefix when secretKey exists', () => {
320
+ const channelWithKey = new MessageChannel('test-key');
321
+ expect(channelWithKey.prefixPath('test')).toBe('test-key:test');
322
+ channelWithKey.destroy();
323
+ });
324
+
325
+ it('should return path as-is when no secretKey', () => {
326
+ expect(channel.prefixPath('test')).toBe('test');
327
+ });
328
+ });
329
+
330
+ describe('extractContext', () => {
331
+ it('should extract context from MessageEvent', () => {
332
+ channel.addReceiver(mockReceiver);
333
+
334
+ const sourceWindow = window;
335
+ const message = createPostMessage(MessageType.REQUEST, 'req123', {
336
+ path: 'test'
337
+ });
338
+
339
+ window.dispatchEvent(
340
+ new MessageEvent('message', {
341
+ data: message,
342
+ origin: 'https://example.com',
343
+ source: sourceWindow
344
+ })
345
+ );
346
+
347
+ setTimeout(() => {
348
+ expect(mockReceiver).toHaveBeenCalledWith(
349
+ message,
350
+ expect.objectContaining({
351
+ source: sourceWindow,
352
+ origin: 'https://example.com'
353
+ })
354
+ );
355
+ }, 10);
356
+ });
357
+ });
358
+
359
+ describe('error handling', () => {
360
+ it('should handle receiver errors gracefully', () => {
361
+ const errorReceiver = jest.fn(() => {
362
+ throw new Error('Receiver error');
363
+ });
364
+ const consoleErrorSpy = jest.spyOn(console, 'error').mockImplementation();
365
+
366
+ channel.addReceiver(errorReceiver);
367
+ channel.addReceiver(mockReceiver);
368
+
369
+ const message = createPostMessage(MessageType.REQUEST, 'req123', {
370
+ path: 'test'
371
+ });
372
+
373
+ window.dispatchEvent(
374
+ new MessageEvent('message', {
375
+ data: message,
376
+ origin: 'https://example.com'
377
+ })
378
+ );
379
+
380
+ setTimeout(() => {
381
+ expect(errorReceiver).toHaveBeenCalled();
382
+ expect(mockReceiver).toHaveBeenCalled(); // Other receivers should still be called
383
+ expect(consoleErrorSpy).toHaveBeenCalledWith(
384
+ '[request-iframe] Receiver error:',
385
+ expect.any(Error)
386
+ );
387
+ consoleErrorSpy.mockRestore();
388
+ }, 10);
389
+ });
390
+ });
391
+
392
+ describe('destroy', () => {
393
+ it('should remove event listener', () => {
394
+ const removeEventListenerSpy = jest.spyOn(window, 'removeEventListener');
395
+ channel.destroy();
396
+ expect(removeEventListenerSpy).toHaveBeenCalledWith('message', expect.any(Function));
397
+ removeEventListenerSpy.mockRestore();
398
+ });
399
+
400
+ it('should clear receivers', () => {
401
+ channel.addReceiver(mockReceiver);
402
+ channel.destroy();
403
+
404
+ const message = createPostMessage(MessageType.REQUEST, 'req123', {
405
+ path: 'test'
406
+ });
407
+
408
+ window.dispatchEvent(
409
+ new MessageEvent('message', {
410
+ data: message,
411
+ origin: 'https://example.com'
412
+ })
413
+ );
414
+
415
+ setTimeout(() => {
416
+ expect(mockReceiver).not.toHaveBeenCalled();
417
+ }, 10);
418
+ });
419
+ });
420
+ });