request-iframe 0.0.1
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/QUICKSTART.CN.md +269 -0
- package/QUICKSTART.md +269 -0
- package/README.CN.md +1369 -0
- package/README.md +1016 -0
- package/library/__tests__/interceptors.test.ts +124 -0
- package/library/__tests__/requestIframe.test.ts +2216 -0
- package/library/__tests__/stream.test.ts +650 -0
- package/library/__tests__/utils.test.ts +433 -0
- package/library/api/client.d.ts +16 -0
- package/library/api/client.d.ts.map +1 -0
- package/library/api/client.js +72 -0
- package/library/api/server.d.ts +16 -0
- package/library/api/server.d.ts.map +1 -0
- package/library/api/server.js +44 -0
- package/library/constants/index.d.ts +209 -0
- package/library/constants/index.d.ts.map +1 -0
- package/library/constants/index.js +260 -0
- package/library/constants/messages.d.ts +80 -0
- package/library/constants/messages.d.ts.map +1 -0
- package/library/constants/messages.js +123 -0
- package/library/core/client.d.ts +99 -0
- package/library/core/client.d.ts.map +1 -0
- package/library/core/client.js +440 -0
- package/library/core/message-handler.d.ts +110 -0
- package/library/core/message-handler.d.ts.map +1 -0
- package/library/core/message-handler.js +320 -0
- package/library/core/request-response.d.ts +59 -0
- package/library/core/request-response.d.ts.map +1 -0
- package/library/core/request-response.js +337 -0
- package/library/core/request.d.ts +17 -0
- package/library/core/request.d.ts.map +1 -0
- package/library/core/request.js +34 -0
- package/library/core/response.d.ts +51 -0
- package/library/core/response.d.ts.map +1 -0
- package/library/core/response.js +323 -0
- package/library/core/server-base.d.ts +86 -0
- package/library/core/server-base.d.ts.map +1 -0
- package/library/core/server-base.js +257 -0
- package/library/core/server-client.d.ts +99 -0
- package/library/core/server-client.d.ts.map +1 -0
- package/library/core/server-client.js +256 -0
- package/library/core/server.d.ts +82 -0
- package/library/core/server.d.ts.map +1 -0
- package/library/core/server.js +338 -0
- package/library/index.d.ts +16 -0
- package/library/index.d.ts.map +1 -0
- package/library/index.js +211 -0
- package/library/interceptors/index.d.ts +41 -0
- package/library/interceptors/index.d.ts.map +1 -0
- package/library/interceptors/index.js +126 -0
- package/library/message/channel.d.ts +107 -0
- package/library/message/channel.d.ts.map +1 -0
- package/library/message/channel.js +184 -0
- package/library/message/dispatcher.d.ts +119 -0
- package/library/message/dispatcher.d.ts.map +1 -0
- package/library/message/dispatcher.js +249 -0
- package/library/message/index.d.ts +5 -0
- package/library/message/index.d.ts.map +1 -0
- package/library/message/index.js +25 -0
- package/library/stream/file-stream.d.ts +48 -0
- package/library/stream/file-stream.d.ts.map +1 -0
- package/library/stream/file-stream.js +240 -0
- package/library/stream/index.d.ts +15 -0
- package/library/stream/index.d.ts.map +1 -0
- package/library/stream/index.js +83 -0
- package/library/stream/readable-stream.d.ts +83 -0
- package/library/stream/readable-stream.d.ts.map +1 -0
- package/library/stream/readable-stream.js +249 -0
- package/library/stream/types.d.ts +165 -0
- package/library/stream/types.d.ts.map +1 -0
- package/library/stream/types.js +5 -0
- package/library/stream/writable-stream.d.ts +60 -0
- package/library/stream/writable-stream.d.ts.map +1 -0
- package/library/stream/writable-stream.js +348 -0
- package/library/types/index.d.ts +408 -0
- package/library/types/index.d.ts.map +1 -0
- package/library/types/index.js +5 -0
- package/library/utils/cache.d.ts +19 -0
- package/library/utils/cache.d.ts.map +1 -0
- package/library/utils/cache.js +83 -0
- package/library/utils/cookie.d.ts +117 -0
- package/library/utils/cookie.d.ts.map +1 -0
- package/library/utils/cookie.js +365 -0
- package/library/utils/debug.d.ts +11 -0
- package/library/utils/debug.d.ts.map +1 -0
- package/library/utils/debug.js +162 -0
- package/library/utils/index.d.ts +13 -0
- package/library/utils/index.d.ts.map +1 -0
- package/library/utils/index.js +132 -0
- package/library/utils/path-match.d.ts +17 -0
- package/library/utils/path-match.d.ts.map +1 -0
- package/library/utils/path-match.js +90 -0
- package/library/utils/protocol.d.ts +61 -0
- package/library/utils/protocol.d.ts.map +1 -0
- package/library/utils/protocol.js +169 -0
- package/package.json +58 -0
|
@@ -0,0 +1,433 @@
|
|
|
1
|
+
import {
|
|
2
|
+
generateRequestId,
|
|
3
|
+
createPostMessage,
|
|
4
|
+
isValidPostMessage,
|
|
5
|
+
getIframeTargetOrigin,
|
|
6
|
+
parseSetCookie,
|
|
7
|
+
createSetCookie,
|
|
8
|
+
createClearCookie,
|
|
9
|
+
matchCookiePath,
|
|
10
|
+
CookieStore
|
|
11
|
+
} from '../utils';
|
|
12
|
+
import {
|
|
13
|
+
validateProtocolVersion,
|
|
14
|
+
validatePostMessage,
|
|
15
|
+
isRequestIframeMessage,
|
|
16
|
+
getProtocolVersion,
|
|
17
|
+
isCompatibleVersion
|
|
18
|
+
} from '../utils/protocol';
|
|
19
|
+
import { matchPath } from '../utils/path-match';
|
|
20
|
+
|
|
21
|
+
describe('utils', () => {
|
|
22
|
+
describe('generateRequestId', () => {
|
|
23
|
+
it('should generate unique request IDs', () => {
|
|
24
|
+
const id1 = generateRequestId();
|
|
25
|
+
const id2 = generateRequestId();
|
|
26
|
+
expect(id1).not.toBe(id2);
|
|
27
|
+
expect(id1).toMatch(/^req_\d+_[a-z0-9]+$/);
|
|
28
|
+
});
|
|
29
|
+
});
|
|
30
|
+
|
|
31
|
+
describe('createPostMessage', () => {
|
|
32
|
+
it('should create correct PostMessage data', () => {
|
|
33
|
+
const before = Date.now();
|
|
34
|
+
const message = createPostMessage('request', 'req123', {
|
|
35
|
+
path: 'test',
|
|
36
|
+
body: { param: 'value' }
|
|
37
|
+
});
|
|
38
|
+
const after = Date.now();
|
|
39
|
+
|
|
40
|
+
expect(message).toEqual({
|
|
41
|
+
__requestIframe__: 1,
|
|
42
|
+
timestamp: expect.any(Number),
|
|
43
|
+
type: 'request',
|
|
44
|
+
requestId: 'req123',
|
|
45
|
+
path: 'test',
|
|
46
|
+
body: { param: 'value' }
|
|
47
|
+
});
|
|
48
|
+
|
|
49
|
+
// Verify timestamp is within valid range
|
|
50
|
+
expect(message.timestamp).toBeGreaterThanOrEqual(before);
|
|
51
|
+
expect(message.timestamp).toBeLessThanOrEqual(after);
|
|
52
|
+
});
|
|
53
|
+
});
|
|
54
|
+
|
|
55
|
+
describe('isValidPostMessage', () => {
|
|
56
|
+
it('should validate correct PostMessage data', () => {
|
|
57
|
+
const valid = {
|
|
58
|
+
__requestIframe__: 1,
|
|
59
|
+
type: 'request',
|
|
60
|
+
requestId: 'req123'
|
|
61
|
+
};
|
|
62
|
+
expect(isValidPostMessage(valid)).toBe(true);
|
|
63
|
+
});
|
|
64
|
+
|
|
65
|
+
it('should reject invalid PostMessage data', () => {
|
|
66
|
+
expect(isValidPostMessage(null)).toBe(false);
|
|
67
|
+
expect(isValidPostMessage({})).toBe(false);
|
|
68
|
+
expect(isValidPostMessage({ __requestIframe__: 1, type: 'request' })).toBe(false);
|
|
69
|
+
expect(isValidPostMessage({ __requestIframe__: 1, requestId: 'req123' })).toBe(false);
|
|
70
|
+
expect(isValidPostMessage({ type: 'request', requestId: 'req123' })).toBe(false);
|
|
71
|
+
});
|
|
72
|
+
});
|
|
73
|
+
|
|
74
|
+
describe('getIframeTargetOrigin', () => {
|
|
75
|
+
beforeEach(() => {
|
|
76
|
+
document.querySelectorAll('iframe').forEach((iframe) => {
|
|
77
|
+
if (iframe.parentNode) {
|
|
78
|
+
iframe.parentNode.removeChild(iframe);
|
|
79
|
+
}
|
|
80
|
+
});
|
|
81
|
+
});
|
|
82
|
+
|
|
83
|
+
it('should parse origin from iframe.src', () => {
|
|
84
|
+
const iframe = document.createElement('iframe');
|
|
85
|
+
iframe.src = 'https://example.com/test.html';
|
|
86
|
+
document.body.appendChild(iframe);
|
|
87
|
+
|
|
88
|
+
const origin = getIframeTargetOrigin(iframe);
|
|
89
|
+
expect(origin).toBe('https://example.com');
|
|
90
|
+
});
|
|
91
|
+
|
|
92
|
+
it('should return * when iframe has no src', () => {
|
|
93
|
+
const iframe = document.createElement('iframe');
|
|
94
|
+
document.body.appendChild(iframe);
|
|
95
|
+
const origin = getIframeTargetOrigin(iframe);
|
|
96
|
+
expect(origin).toBe('*');
|
|
97
|
+
});
|
|
98
|
+
});
|
|
99
|
+
|
|
100
|
+
describe('Cookie utilities', () => {
|
|
101
|
+
describe('parseSetCookie', () => {
|
|
102
|
+
it('should parse basic Set-Cookie string', () => {
|
|
103
|
+
const cookie = parseSetCookie('token=abc123');
|
|
104
|
+
expect(cookie).toEqual({
|
|
105
|
+
name: 'token',
|
|
106
|
+
value: 'abc123',
|
|
107
|
+
path: '/'
|
|
108
|
+
});
|
|
109
|
+
});
|
|
110
|
+
|
|
111
|
+
it('should parse Set-Cookie string with Path', () => {
|
|
112
|
+
const cookie = parseSetCookie('token=abc123; Path=/api');
|
|
113
|
+
expect(cookie).toEqual({
|
|
114
|
+
name: 'token',
|
|
115
|
+
value: 'abc123',
|
|
116
|
+
path: '/api'
|
|
117
|
+
});
|
|
118
|
+
});
|
|
119
|
+
|
|
120
|
+
it('should parse Set-Cookie string with HttpOnly', () => {
|
|
121
|
+
const cookie = parseSetCookie('token=abc123; HttpOnly');
|
|
122
|
+
expect(cookie?.httpOnly).toBe(true);
|
|
123
|
+
});
|
|
124
|
+
|
|
125
|
+
it('should parse Set-Cookie string with Secure', () => {
|
|
126
|
+
const cookie = parseSetCookie('token=abc123; Secure');
|
|
127
|
+
expect(cookie?.secure).toBe(true);
|
|
128
|
+
});
|
|
129
|
+
|
|
130
|
+
it('should parse Set-Cookie string with Expires', () => {
|
|
131
|
+
const cookie = parseSetCookie('token=abc123; Expires=Thu, 01 Jan 2030 00:00:00 GMT');
|
|
132
|
+
expect(cookie?.expires).toBeDefined();
|
|
133
|
+
expect(cookie?.expires).toBeGreaterThan(Date.now());
|
|
134
|
+
});
|
|
135
|
+
|
|
136
|
+
it('should parse Set-Cookie string with Max-Age', () => {
|
|
137
|
+
const cookie = parseSetCookie('token=abc123; Max-Age=3600');
|
|
138
|
+
expect(cookie?.expires).toBeDefined();
|
|
139
|
+
expect(cookie?.expires).toBeGreaterThan(Date.now());
|
|
140
|
+
expect(cookie?.expires).toBeLessThan(Date.now() + 3600 * 1000 + 1000);
|
|
141
|
+
});
|
|
142
|
+
|
|
143
|
+
it('should parse Set-Cookie string with SameSite', () => {
|
|
144
|
+
const strict = parseSetCookie('token=abc123; SameSite=Strict');
|
|
145
|
+
expect(strict?.sameSite).toBe('Strict');
|
|
146
|
+
|
|
147
|
+
const lax = parseSetCookie('token=abc123; SameSite=Lax');
|
|
148
|
+
expect(lax?.sameSite).toBe('Lax');
|
|
149
|
+
|
|
150
|
+
const none = parseSetCookie('token=abc123; SameSite=None');
|
|
151
|
+
expect(none?.sameSite).toBe('None');
|
|
152
|
+
});
|
|
153
|
+
});
|
|
154
|
+
|
|
155
|
+
describe('createSetCookie', () => {
|
|
156
|
+
it('should create basic Set-Cookie string', () => {
|
|
157
|
+
const str = createSetCookie('token', 'abc123');
|
|
158
|
+
expect(str).toBe('token=abc123; Path=/');
|
|
159
|
+
});
|
|
160
|
+
|
|
161
|
+
it('should create Set-Cookie string with Path', () => {
|
|
162
|
+
const str = createSetCookie('token', 'abc123', { path: '/api' });
|
|
163
|
+
expect(str).toBe('token=abc123; Path=/api');
|
|
164
|
+
});
|
|
165
|
+
|
|
166
|
+
it('should create Set-Cookie string with HttpOnly', () => {
|
|
167
|
+
const str = createSetCookie('token', 'abc123', { httpOnly: true });
|
|
168
|
+
expect(str).toContain('HttpOnly');
|
|
169
|
+
});
|
|
170
|
+
});
|
|
171
|
+
|
|
172
|
+
describe('createClearCookie', () => {
|
|
173
|
+
it('should create Set-Cookie string to delete cookie', () => {
|
|
174
|
+
const str = createClearCookie('token');
|
|
175
|
+
expect(str).toContain('token=');
|
|
176
|
+
expect(str).toContain('Max-Age=0');
|
|
177
|
+
expect(str).toContain('Expires=');
|
|
178
|
+
});
|
|
179
|
+
});
|
|
180
|
+
|
|
181
|
+
describe('matchCookiePath', () => {
|
|
182
|
+
it('should return true for exact match', () => {
|
|
183
|
+
expect(matchCookiePath('/api', '/api')).toBe(true);
|
|
184
|
+
expect(matchCookiePath('/', '/')).toBe(true);
|
|
185
|
+
});
|
|
186
|
+
|
|
187
|
+
it('should return true when request path is sub-path of cookie path', () => {
|
|
188
|
+
expect(matchCookiePath('/api/users', '/api')).toBe(true);
|
|
189
|
+
expect(matchCookiePath('/api/users/123', '/api')).toBe(true);
|
|
190
|
+
expect(matchCookiePath('/api/users', '/')).toBe(true);
|
|
191
|
+
});
|
|
192
|
+
|
|
193
|
+
it('should return false for non-matching paths', () => {
|
|
194
|
+
expect(matchCookiePath('/api', '/admin')).toBe(false);
|
|
195
|
+
expect(matchCookiePath('/ap', '/api')).toBe(false);
|
|
196
|
+
expect(matchCookiePath('/apitest', '/api')).toBe(false);
|
|
197
|
+
});
|
|
198
|
+
});
|
|
199
|
+
|
|
200
|
+
describe('CookieStore', () => {
|
|
201
|
+
let store: CookieStore;
|
|
202
|
+
|
|
203
|
+
beforeEach(() => {
|
|
204
|
+
store = new CookieStore();
|
|
205
|
+
});
|
|
206
|
+
|
|
207
|
+
it('should set and get cookie', () => {
|
|
208
|
+
store.set({ name: 'token', value: 'abc', path: '/' });
|
|
209
|
+
expect(store.get('token')).toBe('abc');
|
|
210
|
+
});
|
|
211
|
+
|
|
212
|
+
it('should get cookies by path', () => {
|
|
213
|
+
store.set({ name: 'global', value: 'g', path: '/' });
|
|
214
|
+
store.set({ name: 'api', value: 'a', path: '/api' });
|
|
215
|
+
store.set({ name: 'admin', value: 'ad', path: '/admin' });
|
|
216
|
+
|
|
217
|
+
expect(store.getForPath('/')).toEqual({ global: 'g' });
|
|
218
|
+
expect(store.getForPath('/api')).toEqual({ global: 'g', api: 'a' });
|
|
219
|
+
expect(store.getForPath('/api/users')).toEqual({ global: 'g', api: 'a' });
|
|
220
|
+
expect(store.getForPath('/admin')).toEqual({ global: 'g', admin: 'ad' });
|
|
221
|
+
});
|
|
222
|
+
|
|
223
|
+
it('should remove cookie', () => {
|
|
224
|
+
store.set({ name: 'token', value: 'abc', path: '/' });
|
|
225
|
+
store.remove('token', '/');
|
|
226
|
+
expect(store.get('token')).toBeUndefined();
|
|
227
|
+
});
|
|
228
|
+
|
|
229
|
+
it('should set cookie from Set-Cookie string', () => {
|
|
230
|
+
store.setFromSetCookie('token=abc123; Path=/api');
|
|
231
|
+
expect(store.get('token', '/api')).toBe('abc123');
|
|
232
|
+
});
|
|
233
|
+
|
|
234
|
+
it('should remove expired cookie from Set-Cookie string', () => {
|
|
235
|
+
store.set({ name: 'token', value: 'old', path: '/' });
|
|
236
|
+
store.setFromSetCookie('token=; Path=/; Expires=Thu, 01 Jan 1970 00:00:00 GMT');
|
|
237
|
+
expect(store.get('token', '/')).toBeUndefined();
|
|
238
|
+
});
|
|
239
|
+
|
|
240
|
+
it('should clear all cookies', () => {
|
|
241
|
+
store.set({ name: 'a', value: '1', path: '/' });
|
|
242
|
+
store.set({ name: 'b', value: '2', path: '/api' });
|
|
243
|
+
store.clear();
|
|
244
|
+
expect(store.getAllSimple()).toEqual({});
|
|
245
|
+
});
|
|
246
|
+
|
|
247
|
+
it('should handle expired cookies in getForPath', () => {
|
|
248
|
+
store.set({ name: 'expired', value: 'old', path: '/', expires: Date.now() - 1000 });
|
|
249
|
+
expect(store.getForPath('/')).toEqual({});
|
|
250
|
+
});
|
|
251
|
+
|
|
252
|
+
it('should handle getAll method', () => {
|
|
253
|
+
store.set({ name: 'a', value: '1', path: '/' });
|
|
254
|
+
store.set({ name: 'b', value: '2', path: '/api' });
|
|
255
|
+
const all = store.getAll();
|
|
256
|
+
expect(all.length).toBe(2);
|
|
257
|
+
expect(all.some(c => c.name === 'a')).toBe(true);
|
|
258
|
+
expect(all.some(c => c.name === 'b')).toBe(true);
|
|
259
|
+
});
|
|
260
|
+
|
|
261
|
+
it('should handle cleanup method', () => {
|
|
262
|
+
store.set({ name: 'expired', value: 'old', path: '/', expires: Date.now() - 1000 });
|
|
263
|
+
store.set({ name: 'valid', value: 'new', path: '/' });
|
|
264
|
+
store.cleanup();
|
|
265
|
+
expect(store.get('expired')).toBeUndefined();
|
|
266
|
+
expect(store.get('valid')).toBe('new');
|
|
267
|
+
});
|
|
268
|
+
});
|
|
269
|
+
});
|
|
270
|
+
|
|
271
|
+
describe('Protocol utilities', () => {
|
|
272
|
+
describe('validateProtocolVersion', () => {
|
|
273
|
+
it('should validate compatible version', () => {
|
|
274
|
+
const result = validateProtocolVersion(1);
|
|
275
|
+
expect(result.valid).toBe(true);
|
|
276
|
+
expect(result.version).toBe(1);
|
|
277
|
+
});
|
|
278
|
+
|
|
279
|
+
it('should reject version too low', () => {
|
|
280
|
+
const result = validateProtocolVersion(0);
|
|
281
|
+
expect(result.valid).toBe(false);
|
|
282
|
+
expect(result.errorCode).toBe('VERSION_TOO_LOW');
|
|
283
|
+
});
|
|
284
|
+
|
|
285
|
+
it('should reject invalid format', () => {
|
|
286
|
+
const result1 = validateProtocolVersion('1' as any);
|
|
287
|
+
expect(result1.valid).toBe(false);
|
|
288
|
+
expect(result1.errorCode).toBe('INVALID_FORMAT');
|
|
289
|
+
|
|
290
|
+
const result2 = validateProtocolVersion(1.5);
|
|
291
|
+
expect(result2.valid).toBe(false);
|
|
292
|
+
expect(result2.errorCode).toBe('INVALID_FORMAT');
|
|
293
|
+
});
|
|
294
|
+
});
|
|
295
|
+
|
|
296
|
+
describe('validatePostMessage', () => {
|
|
297
|
+
it('should validate correct message', () => {
|
|
298
|
+
const result = validatePostMessage({
|
|
299
|
+
__requestIframe__: 1,
|
|
300
|
+
type: 'request',
|
|
301
|
+
requestId: 'req123'
|
|
302
|
+
});
|
|
303
|
+
expect(result.valid).toBe(true);
|
|
304
|
+
expect(result.data).toBeDefined();
|
|
305
|
+
});
|
|
306
|
+
|
|
307
|
+
it('should reject non-object', () => {
|
|
308
|
+
const result = validatePostMessage(null);
|
|
309
|
+
expect(result.valid).toBe(false);
|
|
310
|
+
expect(result.errorCode).toBe('INVALID_FORMAT');
|
|
311
|
+
});
|
|
312
|
+
|
|
313
|
+
it('should reject missing protocol identifier', () => {
|
|
314
|
+
const result = validatePostMessage({
|
|
315
|
+
type: 'request',
|
|
316
|
+
requestId: 'req123'
|
|
317
|
+
});
|
|
318
|
+
expect(result.valid).toBe(false);
|
|
319
|
+
expect(result.errorCode).toBe('INVALID_FORMAT');
|
|
320
|
+
});
|
|
321
|
+
|
|
322
|
+
it('should reject missing type', () => {
|
|
323
|
+
const result = validatePostMessage({
|
|
324
|
+
__requestIframe__: 1,
|
|
325
|
+
requestId: 'req123'
|
|
326
|
+
});
|
|
327
|
+
expect(result.valid).toBe(false);
|
|
328
|
+
expect(result.errorCode).toBe('INVALID_FORMAT');
|
|
329
|
+
});
|
|
330
|
+
|
|
331
|
+
it('should reject missing requestId', () => {
|
|
332
|
+
const result = validatePostMessage({
|
|
333
|
+
__requestIframe__: 1,
|
|
334
|
+
type: 'request'
|
|
335
|
+
});
|
|
336
|
+
expect(result.valid).toBe(false);
|
|
337
|
+
expect(result.errorCode).toBe('INVALID_FORMAT');
|
|
338
|
+
});
|
|
339
|
+
});
|
|
340
|
+
|
|
341
|
+
describe('isRequestIframeMessage', () => {
|
|
342
|
+
it('should return true for valid message', () => {
|
|
343
|
+
expect(isRequestIframeMessage({
|
|
344
|
+
__requestIframe__: 1,
|
|
345
|
+
type: 'request',
|
|
346
|
+
requestId: 'req123'
|
|
347
|
+
})).toBe(true);
|
|
348
|
+
});
|
|
349
|
+
|
|
350
|
+
it('should return false for invalid message', () => {
|
|
351
|
+
expect(isRequestIframeMessage(null)).toBe(false);
|
|
352
|
+
expect(isRequestIframeMessage({})).toBe(false);
|
|
353
|
+
expect(isRequestIframeMessage({
|
|
354
|
+
__requestIframe__: '1',
|
|
355
|
+
type: 'request',
|
|
356
|
+
requestId: 'req123'
|
|
357
|
+
})).toBe(false);
|
|
358
|
+
});
|
|
359
|
+
});
|
|
360
|
+
|
|
361
|
+
describe('getProtocolVersion', () => {
|
|
362
|
+
it('should extract version from message', () => {
|
|
363
|
+
expect(getProtocolVersion({
|
|
364
|
+
__requestIframe__: 1
|
|
365
|
+
})).toBe(1);
|
|
366
|
+
});
|
|
367
|
+
|
|
368
|
+
it('should return undefined for invalid message', () => {
|
|
369
|
+
expect(getProtocolVersion(null)).toBeUndefined();
|
|
370
|
+
expect(getProtocolVersion({})).toBeUndefined();
|
|
371
|
+
expect(getProtocolVersion({
|
|
372
|
+
__requestIframe__: '1'
|
|
373
|
+
})).toBeUndefined();
|
|
374
|
+
});
|
|
375
|
+
});
|
|
376
|
+
|
|
377
|
+
describe('isCompatibleVersion', () => {
|
|
378
|
+
it('should return true for compatible version', () => {
|
|
379
|
+
expect(isCompatibleVersion(1)).toBe(true);
|
|
380
|
+
expect(isCompatibleVersion(2)).toBe(true);
|
|
381
|
+
});
|
|
382
|
+
|
|
383
|
+
it('should return false for incompatible version', () => {
|
|
384
|
+
expect(isCompatibleVersion(0)).toBe(false);
|
|
385
|
+
});
|
|
386
|
+
});
|
|
387
|
+
});
|
|
388
|
+
|
|
389
|
+
describe('Path matching', () => {
|
|
390
|
+
describe('matchPath', () => {
|
|
391
|
+
it('should match exact string path', () => {
|
|
392
|
+
expect(matchPath('/api', '/api')).toBe(true);
|
|
393
|
+
expect(matchPath('/api/users', '/api/users')).toBe(true);
|
|
394
|
+
});
|
|
395
|
+
|
|
396
|
+
it('should match prefix path', () => {
|
|
397
|
+
expect(matchPath('/api/users', '/api')).toBe(true);
|
|
398
|
+
expect(matchPath('/api/users/123', '/api')).toBe(true);
|
|
399
|
+
});
|
|
400
|
+
|
|
401
|
+
it('should not match non-prefix path', () => {
|
|
402
|
+
expect(matchPath('/api2', '/api')).toBe(false);
|
|
403
|
+
expect(matchPath('/apitest', '/api')).toBe(false);
|
|
404
|
+
});
|
|
405
|
+
|
|
406
|
+
it('should match with trailing slash', () => {
|
|
407
|
+
expect(matchPath('/api/users', '/api/')).toBe(true);
|
|
408
|
+
});
|
|
409
|
+
|
|
410
|
+
it('should match RegExp', () => {
|
|
411
|
+
expect(matchPath('/api/users/123', /^\/api\/users\/\d+$/)).toBe(true);
|
|
412
|
+
expect(matchPath('/api/users/abc', /^\/api\/users\/\d+$/)).toBe(false);
|
|
413
|
+
});
|
|
414
|
+
|
|
415
|
+
it('should match array of matchers', () => {
|
|
416
|
+
expect(matchPath('/api/users', ['/admin', '/api'])).toBe(true);
|
|
417
|
+
expect(matchPath('/api/users', ['/admin', '/other'])).toBe(false);
|
|
418
|
+
});
|
|
419
|
+
|
|
420
|
+
it('should match wildcard patterns', () => {
|
|
421
|
+
expect(matchPath('/api/users/123', '/api/*')).toBe(true);
|
|
422
|
+
expect(matchPath('/api/users', '/api/*')).toBe(true);
|
|
423
|
+
expect(matchPath('/api/users/123/posts', '/api/*/posts')).toBe(true);
|
|
424
|
+
expect(matchPath('/other/users', '/api/*')).toBe(false);
|
|
425
|
+
});
|
|
426
|
+
|
|
427
|
+
it('should normalize paths', () => {
|
|
428
|
+
expect(matchPath('api', '/api')).toBe(true);
|
|
429
|
+
expect(matchPath('/api', 'api')).toBe(true);
|
|
430
|
+
});
|
|
431
|
+
});
|
|
432
|
+
});
|
|
433
|
+
});
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
import { RequestIframeClient, RequestIframeClientOptions } from '../types';
|
|
2
|
+
/**
|
|
3
|
+
* Create a client (for sending requests)
|
|
4
|
+
*
|
|
5
|
+
* Note:
|
|
6
|
+
* - MessageChannel is cached at the window level by secretKey (ensures unique message listener)
|
|
7
|
+
* - Client instances are not cached, a new instance is created on each call
|
|
8
|
+
* - This allows different versions of the library to coexist
|
|
9
|
+
*/
|
|
10
|
+
export declare function requestIframeClient(target: HTMLIFrameElement | Window, options?: RequestIframeClientOptions): RequestIframeClient;
|
|
11
|
+
/**
|
|
12
|
+
* Clear MessageChannel cache (for testing or reset)
|
|
13
|
+
* Note: This clears the shared message channel for the specified secretKey
|
|
14
|
+
*/
|
|
15
|
+
export declare function clearRequestIframeClientCache(secretKey?: string): void;
|
|
16
|
+
//# sourceMappingURL=client.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"client.d.ts","sourceRoot":"","sources":["../../src/api/client.ts"],"names":[],"mappings":"AAAA,OAAO,EAAiB,mBAAmB,EAAE,0BAA0B,EAAE,MAAM,UAAU,CAAC;AAO1F;;;;;;;GAOG;AACH,wBAAgB,mBAAmB,CACjC,MAAM,EAAE,iBAAiB,GAAG,MAAM,EAClC,OAAO,CAAC,EAAE,0BAA0B,GACnC,mBAAmB,CA0CrB;AAED;;;GAGG;AACH,wBAAgB,6BAA6B,CAAC,SAAS,CAAC,EAAE,MAAM,GAAG,IAAI,CAKtE"}
|
|
@@ -0,0 +1,72 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
|
|
3
|
+
Object.defineProperty(exports, "__esModule", {
|
|
4
|
+
value: true
|
|
5
|
+
});
|
|
6
|
+
exports.clearRequestIframeClientCache = clearRequestIframeClientCache;
|
|
7
|
+
exports.requestIframeClient = requestIframeClient;
|
|
8
|
+
var _utils = require("../utils");
|
|
9
|
+
var _serverClient = require("../core/server-client");
|
|
10
|
+
var _client = require("../core/client");
|
|
11
|
+
var _debug = require("../utils/debug");
|
|
12
|
+
var _constants = require("../constants");
|
|
13
|
+
/**
|
|
14
|
+
* Create a client (for sending requests)
|
|
15
|
+
*
|
|
16
|
+
* Note:
|
|
17
|
+
* - MessageChannel is cached at the window level by secretKey (ensures unique message listener)
|
|
18
|
+
* - Client instances are not cached, a new instance is created on each call
|
|
19
|
+
* - This allows different versions of the library to coexist
|
|
20
|
+
*/
|
|
21
|
+
function requestIframeClient(target, options) {
|
|
22
|
+
var targetWindow = null;
|
|
23
|
+
var targetOrigin = '*';
|
|
24
|
+
if (target.tagName === 'IFRAME') {
|
|
25
|
+
var iframe = target;
|
|
26
|
+
targetWindow = iframe.contentWindow;
|
|
27
|
+
targetOrigin = (0, _utils.getIframeTargetOrigin)(iframe);
|
|
28
|
+
if (!targetWindow) {
|
|
29
|
+
throw {
|
|
30
|
+
message: _constants.Messages.IFRAME_NOT_READY,
|
|
31
|
+
code: _constants.ErrorCode.IFRAME_NOT_READY
|
|
32
|
+
};
|
|
33
|
+
}
|
|
34
|
+
} else {
|
|
35
|
+
targetWindow = target;
|
|
36
|
+
targetOrigin = '*';
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
// Determine secretKey
|
|
40
|
+
var secretKey = options === null || options === void 0 ? void 0 : options.secretKey;
|
|
41
|
+
|
|
42
|
+
// Create ClientServer (internally obtains or creates a shared MessageChannel)
|
|
43
|
+
var server = new _serverClient.RequestIframeClientServer({
|
|
44
|
+
secretKey,
|
|
45
|
+
ackTimeout: options === null || options === void 0 ? void 0 : options.ackTimeout
|
|
46
|
+
});
|
|
47
|
+
|
|
48
|
+
// Create client instance
|
|
49
|
+
var client = new _client.RequestIframeClientImpl(targetWindow, targetOrigin, server, {
|
|
50
|
+
secretKey,
|
|
51
|
+
ackTimeout: options === null || options === void 0 ? void 0 : options.ackTimeout,
|
|
52
|
+
timeout: options === null || options === void 0 ? void 0 : options.timeout,
|
|
53
|
+
asyncTimeout: options === null || options === void 0 ? void 0 : options.asyncTimeout
|
|
54
|
+
});
|
|
55
|
+
|
|
56
|
+
// If trace mode is enabled, register debug interceptors
|
|
57
|
+
if (options !== null && options !== void 0 && options.trace) {
|
|
58
|
+
(0, _debug.setupClientDebugInterceptors)(client);
|
|
59
|
+
}
|
|
60
|
+
return client;
|
|
61
|
+
}
|
|
62
|
+
|
|
63
|
+
/**
|
|
64
|
+
* Clear MessageChannel cache (for testing or reset)
|
|
65
|
+
* Note: This clears the shared message channel for the specified secretKey
|
|
66
|
+
*/
|
|
67
|
+
function clearRequestIframeClientCache(secretKey) {
|
|
68
|
+
// Now client is no longer cached, only need to clear MessageChannel cache
|
|
69
|
+
// MessageChannel cleanup is handled by clearMessageChannelCache in cache.ts
|
|
70
|
+
// Empty implementation kept here to maintain API compatibility
|
|
71
|
+
void secretKey;
|
|
72
|
+
}
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
import { RequestIframeServer, RequestIframeServerOptions } from '../types';
|
|
2
|
+
/**
|
|
3
|
+
* Create a server (for receiving and handling requests)
|
|
4
|
+
*
|
|
5
|
+
* Note:
|
|
6
|
+
* - MessageChannel is cached at the window level by secretKey (ensures unique message listener)
|
|
7
|
+
* - Server instances are not cached, a new instance is created on each call
|
|
8
|
+
* - This allows different versions of the library to coexist
|
|
9
|
+
*/
|
|
10
|
+
export declare function requestIframeServer(options?: RequestIframeServerOptions): RequestIframeServer;
|
|
11
|
+
/**
|
|
12
|
+
* Clear MessageChannel cache (for testing or reset)
|
|
13
|
+
* Note: This clears the shared message channel for the specified secretKey
|
|
14
|
+
*/
|
|
15
|
+
export declare function clearRequestIframeServerCache(secretKey?: string): void;
|
|
16
|
+
//# sourceMappingURL=server.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"server.d.ts","sourceRoot":"","sources":["../../src/api/server.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,mBAAmB,EAAE,0BAA0B,EAAE,MAAM,UAAU,CAAC;AAI3E;;;;;;;GAOG;AACH,wBAAgB,mBAAmB,CACjC,OAAO,CAAC,EAAE,0BAA0B,GACnC,mBAAmB,CAgBrB;AAED;;;GAGG;AACH,wBAAgB,6BAA6B,CAAC,SAAS,CAAC,EAAE,MAAM,GAAG,IAAI,CAKtE"}
|
|
@@ -0,0 +1,44 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
|
|
3
|
+
Object.defineProperty(exports, "__esModule", {
|
|
4
|
+
value: true
|
|
5
|
+
});
|
|
6
|
+
exports.clearRequestIframeServerCache = clearRequestIframeServerCache;
|
|
7
|
+
exports.requestIframeServer = requestIframeServer;
|
|
8
|
+
var _server = require("../core/server");
|
|
9
|
+
var _debug = require("../utils/debug");
|
|
10
|
+
/**
|
|
11
|
+
* Create a server (for receiving and handling requests)
|
|
12
|
+
*
|
|
13
|
+
* Note:
|
|
14
|
+
* - MessageChannel is cached at the window level by secretKey (ensures unique message listener)
|
|
15
|
+
* - Server instances are not cached, a new instance is created on each call
|
|
16
|
+
* - This allows different versions of the library to coexist
|
|
17
|
+
*/
|
|
18
|
+
function requestIframeServer(options) {
|
|
19
|
+
// Determine secretKey
|
|
20
|
+
var secretKey = options === null || options === void 0 ? void 0 : options.secretKey;
|
|
21
|
+
|
|
22
|
+
// Create server (internally obtains or creates a shared MessageChannel)
|
|
23
|
+
var server = new _server.RequestIframeServerImpl({
|
|
24
|
+
secretKey,
|
|
25
|
+
ackTimeout: options === null || options === void 0 ? void 0 : options.ackTimeout
|
|
26
|
+
});
|
|
27
|
+
|
|
28
|
+
// If trace mode is enabled, register debug listeners
|
|
29
|
+
if (options !== null && options !== void 0 && options.trace) {
|
|
30
|
+
(0, _debug.setupServerDebugListeners)(server);
|
|
31
|
+
}
|
|
32
|
+
return server;
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
/**
|
|
36
|
+
* Clear MessageChannel cache (for testing or reset)
|
|
37
|
+
* Note: This clears the shared message channel for the specified secretKey
|
|
38
|
+
*/
|
|
39
|
+
function clearRequestIframeServerCache(secretKey) {
|
|
40
|
+
// Now server is no longer cached, only need to clear MessageChannel cache
|
|
41
|
+
// MessageChannel cleanup is handled by clearMessageChannelCache in cache.ts
|
|
42
|
+
// Empty implementation kept here to maintain API compatibility
|
|
43
|
+
void secretKey;
|
|
44
|
+
}
|