request-iframe 0.0.6 → 0.1.0
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/README.CN.md +53 -6
- package/README.md +63 -10
- package/esm/api/client.js +79 -0
- package/esm/api/server.js +59 -0
- package/esm/constants/index.js +257 -0
- package/esm/constants/messages.js +155 -0
- package/esm/core/client-server.js +329 -0
- package/esm/core/client.js +873 -0
- package/esm/core/request.js +27 -0
- package/esm/core/response.js +451 -0
- package/esm/core/server.js +767 -0
- package/esm/index.js +21 -0
- package/esm/interceptors/index.js +122 -0
- package/esm/message/channel.js +181 -0
- package/esm/message/dispatcher.js +380 -0
- package/esm/message/index.js +2 -0
- package/esm/stream/file-stream.js +289 -0
- package/esm/stream/index.js +44 -0
- package/esm/stream/readable-stream.js +500 -0
- package/esm/stream/stream-core.js +91 -0
- package/esm/stream/types.js +1 -0
- package/esm/stream/writable-stream.js +582 -0
- package/esm/types/index.js +1 -0
- package/esm/utils/ack-meta.js +53 -0
- package/esm/utils/cache.js +147 -0
- package/esm/utils/cookie.js +352 -0
- package/esm/utils/debug.js +521 -0
- package/esm/utils/error.js +27 -0
- package/esm/utils/index.js +178 -0
- package/esm/utils/origin.js +28 -0
- package/esm/utils/path-match.js +148 -0
- package/esm/utils/protocol.js +157 -0
- package/library/api/client.d.ts.map +1 -1
- package/library/api/client.js +8 -1
- package/library/api/server.d.ts.map +1 -1
- package/library/api/server.js +4 -1
- package/library/constants/index.d.ts +25 -1
- package/library/constants/index.d.ts.map +1 -1
- package/library/constants/index.js +30 -5
- package/library/constants/messages.d.ts +5 -0
- package/library/constants/messages.d.ts.map +1 -1
- package/library/constants/messages.js +5 -0
- package/library/core/client-server.d.ts +3 -2
- package/library/core/client-server.d.ts.map +1 -1
- package/library/core/client-server.js +51 -4
- package/library/core/client.d.ts +4 -1
- package/library/core/client.d.ts.map +1 -1
- package/library/core/client.js +74 -31
- package/library/core/response.d.ts +21 -3
- package/library/core/response.d.ts.map +1 -1
- package/library/core/response.js +46 -6
- package/library/core/server.d.ts +28 -1
- package/library/core/server.d.ts.map +1 -1
- package/library/core/server.js +180 -19
- package/library/message/channel.d.ts +6 -0
- package/library/message/channel.d.ts.map +1 -1
- package/library/message/dispatcher.d.ts +22 -0
- package/library/message/dispatcher.d.ts.map +1 -1
- package/library/message/dispatcher.js +92 -0
- package/library/stream/file-stream.d.ts +4 -0
- package/library/stream/file-stream.d.ts.map +1 -1
- package/library/stream/file-stream.js +61 -33
- package/library/stream/index.d.ts.map +1 -1
- package/library/stream/index.js +2 -0
- package/library/stream/readable-stream.d.ts +30 -11
- package/library/stream/readable-stream.d.ts.map +1 -1
- package/library/stream/readable-stream.js +329 -73
- package/library/stream/stream-core.d.ts +44 -0
- package/library/stream/stream-core.d.ts.map +1 -0
- package/library/stream/stream-core.js +98 -0
- package/library/stream/types.d.ts +90 -3
- package/library/stream/types.d.ts.map +1 -1
- package/library/stream/writable-stream.d.ts +40 -12
- package/library/stream/writable-stream.d.ts.map +1 -1
- package/library/stream/writable-stream.js +391 -195
- package/library/types/index.d.ts +70 -3
- package/library/types/index.d.ts.map +1 -1
- package/library/utils/ack-meta.d.ts +2 -0
- package/library/utils/ack-meta.d.ts.map +1 -0
- package/library/utils/ack-meta.js +59 -0
- package/library/utils/index.d.ts +1 -0
- package/library/utils/index.d.ts.map +1 -1
- package/library/utils/index.js +16 -0
- package/library/utils/origin.d.ts +14 -0
- package/library/utils/origin.d.ts.map +1 -0
- package/library/utils/origin.js +34 -0
- package/package.json +30 -7
- package/react/README.md +16 -0
- package/react/esm/index.js +284 -0
- package/react/library/index.d.ts +1 -1
- package/react/library/index.d.ts.map +1 -1
- package/react/library/index.js +3 -3
- package/react/package.json +24 -2
package/esm/index.js
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
// API
|
|
2
|
+
export { requestIframeClient, clearRequestIframeClientCache } from './api/client';
|
|
3
|
+
export { requestIframeServer, clearRequestIframeServerCache } from './api/server';
|
|
4
|
+
// Implementation classes
|
|
5
|
+
export { RequestIframeClientImpl } from './core/client';
|
|
6
|
+
export { RequestIframeServerImpl } from './core/server';
|
|
7
|
+
export { RequestIframeClientServer } from './core/client-server';
|
|
8
|
+
// MessageChannel and MessageDispatcher
|
|
9
|
+
export { MessageChannel, ChannelType, MessageDispatcher } from './message';
|
|
10
|
+
// Cache utilities
|
|
11
|
+
export { getOrCreateMessageChannel, releaseMessageChannel, clearMessageChannelCache } from './utils/cache';
|
|
12
|
+
export { ServerRequestImpl } from './core/request';
|
|
13
|
+
export { ServerResponseImpl } from './core/response';
|
|
14
|
+
// Stream
|
|
15
|
+
export { IframeWritableStream, IframeReadableStream, IframeFileWritableStream, IframeFileReadableStream, isIframeReadableStream, isIframeFileReadableStream, isIframeFileWritableStream, isIframeWritableStream } from './stream';
|
|
16
|
+
// Types and utilities
|
|
17
|
+
export * from './types';
|
|
18
|
+
export { detectContentType, blobToBase64, RequestIframeError } from './utils';
|
|
19
|
+
export { InterceptorManager, RequestInterceptorManager, ResponseInterceptorManager } from './interceptors';
|
|
20
|
+
// Constants
|
|
21
|
+
export * from './constants';
|
|
@@ -0,0 +1,122 @@
|
|
|
1
|
+
import _asyncToGenerator from "@babel/runtime/helpers/esm/asyncToGenerator";
|
|
2
|
+
import _defineProperty from "@babel/runtime/helpers/esm/defineProperty";
|
|
3
|
+
import _regeneratorRuntime from "@babel/runtime/regenerator";
|
|
4
|
+
import "core-js/modules/es.promise.js";
|
|
5
|
+
import "core-js/modules/web.dom-collections.for-each.js";
|
|
6
|
+
/**
|
|
7
|
+
* Interceptor manager
|
|
8
|
+
*/
|
|
9
|
+
export class InterceptorManager {
|
|
10
|
+
constructor() {
|
|
11
|
+
_defineProperty(this, "handlers", []);
|
|
12
|
+
}
|
|
13
|
+
/**
|
|
14
|
+
* Add interceptor
|
|
15
|
+
*/
|
|
16
|
+
use(fulfilled, rejected) {
|
|
17
|
+
this.handlers.push({
|
|
18
|
+
fulfilled,
|
|
19
|
+
rejected
|
|
20
|
+
});
|
|
21
|
+
return this.handlers.length - 1;
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
/**
|
|
25
|
+
* Remove interceptor
|
|
26
|
+
*/
|
|
27
|
+
eject(id) {
|
|
28
|
+
if (this.handlers[id]) {
|
|
29
|
+
this.handlers[id] = null;
|
|
30
|
+
}
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
/**
|
|
34
|
+
* Clear all interceptors
|
|
35
|
+
*/
|
|
36
|
+
clear() {
|
|
37
|
+
this.handlers.length = 0;
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
/**
|
|
41
|
+
* Iterate over all interceptors
|
|
42
|
+
*/
|
|
43
|
+
forEach(fn) {
|
|
44
|
+
this.handlers.forEach(h => {
|
|
45
|
+
if (h !== null) {
|
|
46
|
+
fn(h);
|
|
47
|
+
}
|
|
48
|
+
});
|
|
49
|
+
}
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
/**
|
|
53
|
+
* Request interceptor manager
|
|
54
|
+
*/
|
|
55
|
+
export class RequestInterceptorManager extends InterceptorManager {}
|
|
56
|
+
|
|
57
|
+
/**
|
|
58
|
+
* Response interceptor manager
|
|
59
|
+
*/
|
|
60
|
+
export class ResponseInterceptorManager extends InterceptorManager {}
|
|
61
|
+
|
|
62
|
+
/**
|
|
63
|
+
* Execute request interceptor chain
|
|
64
|
+
*/
|
|
65
|
+
export function runRequestInterceptors(_x, _x2) {
|
|
66
|
+
return _runRequestInterceptors.apply(this, arguments);
|
|
67
|
+
}
|
|
68
|
+
|
|
69
|
+
/**
|
|
70
|
+
* Execute response interceptor chain
|
|
71
|
+
*/
|
|
72
|
+
function _runRequestInterceptors() {
|
|
73
|
+
_runRequestInterceptors = _asyncToGenerator(/*#__PURE__*/_regeneratorRuntime.mark(function _callee(interceptors, config) {
|
|
74
|
+
var promise;
|
|
75
|
+
return _regeneratorRuntime.wrap(function (_context) {
|
|
76
|
+
while (1) switch (_context.prev = _context.next) {
|
|
77
|
+
case 0:
|
|
78
|
+
promise = Promise.resolve(config);
|
|
79
|
+
interceptors.forEach(interceptor => {
|
|
80
|
+
promise = promise.then(config => interceptor.fulfilled(config), error => {
|
|
81
|
+
if (interceptor.rejected) {
|
|
82
|
+
return interceptor.rejected(error);
|
|
83
|
+
}
|
|
84
|
+
return Promise.reject(error);
|
|
85
|
+
});
|
|
86
|
+
});
|
|
87
|
+
return _context.abrupt("return", promise);
|
|
88
|
+
case 1:
|
|
89
|
+
case "end":
|
|
90
|
+
return _context.stop();
|
|
91
|
+
}
|
|
92
|
+
}, _callee);
|
|
93
|
+
}));
|
|
94
|
+
return _runRequestInterceptors.apply(this, arguments);
|
|
95
|
+
}
|
|
96
|
+
export function runResponseInterceptors(_x3, _x4) {
|
|
97
|
+
return _runResponseInterceptors.apply(this, arguments);
|
|
98
|
+
}
|
|
99
|
+
function _runResponseInterceptors() {
|
|
100
|
+
_runResponseInterceptors = _asyncToGenerator(/*#__PURE__*/_regeneratorRuntime.mark(function _callee2(interceptors, response) {
|
|
101
|
+
var promise;
|
|
102
|
+
return _regeneratorRuntime.wrap(function (_context2) {
|
|
103
|
+
while (1) switch (_context2.prev = _context2.next) {
|
|
104
|
+
case 0:
|
|
105
|
+
promise = Promise.resolve(response);
|
|
106
|
+
interceptors.forEach(interceptor => {
|
|
107
|
+
promise = promise.then(response => interceptor.fulfilled(response), error => {
|
|
108
|
+
if (interceptor.rejected) {
|
|
109
|
+
return interceptor.rejected(error);
|
|
110
|
+
}
|
|
111
|
+
return Promise.reject(error);
|
|
112
|
+
});
|
|
113
|
+
});
|
|
114
|
+
return _context2.abrupt("return", promise);
|
|
115
|
+
case 1:
|
|
116
|
+
case "end":
|
|
117
|
+
return _context2.stop();
|
|
118
|
+
}
|
|
119
|
+
}, _callee2);
|
|
120
|
+
}));
|
|
121
|
+
return _runResponseInterceptors.apply(this, arguments);
|
|
122
|
+
}
|
|
@@ -0,0 +1,181 @@
|
|
|
1
|
+
import _defineProperty from "@babel/runtime/helpers/esm/defineProperty";
|
|
2
|
+
function ownKeys(e, r) { var t = Object.keys(e); if (Object.getOwnPropertySymbols) { var o = Object.getOwnPropertySymbols(e); r && (o = o.filter(function (r) { return Object.getOwnPropertyDescriptor(e, r).enumerable; })), t.push.apply(t, o); } return t; }
|
|
3
|
+
function _objectSpread(e) { for (var r = 1; r < arguments.length; r++) { var t = null != arguments[r] ? arguments[r] : {}; r % 2 ? ownKeys(Object(t), !0).forEach(function (r) { _defineProperty(e, r, t[r]); }) : Object.getOwnPropertyDescriptors ? Object.defineProperties(e, Object.getOwnPropertyDescriptors(t)) : ownKeys(Object(t)).forEach(function (r) { Object.defineProperty(e, r, Object.getOwnPropertyDescriptor(t, r)); }); } return e; }
|
|
4
|
+
import "core-js/modules/es.array.filter.js";
|
|
5
|
+
import "core-js/modules/es.array.iterator.js";
|
|
6
|
+
import "core-js/modules/es.object.get-own-property-descriptors.js";
|
|
7
|
+
import "core-js/modules/es.set.js";
|
|
8
|
+
import "core-js/modules/web.dom-collections.for-each.js";
|
|
9
|
+
import "core-js/modules/web.dom-collections.iterator.js";
|
|
10
|
+
import { isValidPostMessage, createPostMessage, isWindowAvailable } from '../utils';
|
|
11
|
+
|
|
12
|
+
/**
|
|
13
|
+
* Message context (extracted from MessageEvent, transport-agnostic)
|
|
14
|
+
*/
|
|
15
|
+
|
|
16
|
+
/**
|
|
17
|
+
* Message receiver callback
|
|
18
|
+
*/
|
|
19
|
+
|
|
20
|
+
/**
|
|
21
|
+
* Channel type constants
|
|
22
|
+
*/
|
|
23
|
+
export var ChannelType = {
|
|
24
|
+
/** postMessage channel type */
|
|
25
|
+
POST_MESSAGE: 'postMessage'
|
|
26
|
+
};
|
|
27
|
+
|
|
28
|
+
/**
|
|
29
|
+
* Channel type
|
|
30
|
+
*/
|
|
31
|
+
|
|
32
|
+
/**
|
|
33
|
+
* MessageChannel - Low-level communication channel for postMessage
|
|
34
|
+
*
|
|
35
|
+
* Responsibilities:
|
|
36
|
+
* - Listening to window.postMessage events
|
|
37
|
+
* - Filtering messages by secretKey
|
|
38
|
+
* - Extracting transport-specific information (MessageEvent) into generic MessageContext
|
|
39
|
+
* - Forwarding received messages to registered receivers
|
|
40
|
+
* - Sending messages to target windows
|
|
41
|
+
*
|
|
42
|
+
* This is the low-level communication layer that handles postMessage directly.
|
|
43
|
+
* All transport-specific details (like MessageEvent) are encapsulated here.
|
|
44
|
+
*/
|
|
45
|
+
export class MessageChannel {
|
|
46
|
+
constructor(secretKey, type = ChannelType.POST_MESSAGE) {
|
|
47
|
+
/** Channel type (used for cache isolation) */
|
|
48
|
+
/** Secret key for message isolation */
|
|
49
|
+
/** Message receiver callbacks (support multiple receivers) */
|
|
50
|
+
_defineProperty(this, "receivers", new Set());
|
|
51
|
+
/** Reference count (for cache management) */
|
|
52
|
+
_defineProperty(this, "refCount", 0);
|
|
53
|
+
this.type = type;
|
|
54
|
+
this.secretKey = secretKey;
|
|
55
|
+
this.boundOnMessage = this.onMessage.bind(this);
|
|
56
|
+
window.addEventListener('message', this.boundOnMessage);
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
/**
|
|
60
|
+
* Add message receiver callback
|
|
61
|
+
* When a message is received, it will be forwarded to all registered receivers
|
|
62
|
+
*/
|
|
63
|
+
addReceiver(receiver) {
|
|
64
|
+
this.receivers.add(receiver);
|
|
65
|
+
}
|
|
66
|
+
|
|
67
|
+
/**
|
|
68
|
+
* Remove message receiver callback
|
|
69
|
+
*/
|
|
70
|
+
removeReceiver(receiver) {
|
|
71
|
+
this.receivers.delete(receiver);
|
|
72
|
+
}
|
|
73
|
+
|
|
74
|
+
/**
|
|
75
|
+
* Increment reference count (for cache management)
|
|
76
|
+
*/
|
|
77
|
+
addRef() {
|
|
78
|
+
this.refCount++;
|
|
79
|
+
}
|
|
80
|
+
|
|
81
|
+
/**
|
|
82
|
+
* Decrement reference count (for cache management)
|
|
83
|
+
* @returns current reference count
|
|
84
|
+
*/
|
|
85
|
+
release() {
|
|
86
|
+
return --this.refCount;
|
|
87
|
+
}
|
|
88
|
+
|
|
89
|
+
/**
|
|
90
|
+
* Get reference count (for cache management)
|
|
91
|
+
*/
|
|
92
|
+
getRefCount() {
|
|
93
|
+
return this.refCount;
|
|
94
|
+
}
|
|
95
|
+
|
|
96
|
+
/**
|
|
97
|
+
* Extract MessageContext from MessageEvent
|
|
98
|
+
* This encapsulates transport-specific details
|
|
99
|
+
*/
|
|
100
|
+
extractContext(event) {
|
|
101
|
+
return {
|
|
102
|
+
source: event.source,
|
|
103
|
+
origin: event.origin
|
|
104
|
+
};
|
|
105
|
+
}
|
|
106
|
+
|
|
107
|
+
/**
|
|
108
|
+
* Message handling entry point
|
|
109
|
+
*/
|
|
110
|
+
onMessage(event) {
|
|
111
|
+
var data = event.data;
|
|
112
|
+
|
|
113
|
+
// Check if this is a request-iframe framework message (basic format validation)
|
|
114
|
+
if (!isValidPostMessage(data)) {
|
|
115
|
+
return;
|
|
116
|
+
}
|
|
117
|
+
|
|
118
|
+
// secretKey isolation
|
|
119
|
+
if (this.secretKey) {
|
|
120
|
+
if (data.secretKey !== this.secretKey) return;
|
|
121
|
+
} else {
|
|
122
|
+
if (data.secretKey) return;
|
|
123
|
+
}
|
|
124
|
+
|
|
125
|
+
// Extract context from transport-specific event
|
|
126
|
+
var context = this.extractContext(event);
|
|
127
|
+
|
|
128
|
+
// Forward to all registered receivers
|
|
129
|
+
this.receivers.forEach(receiver => {
|
|
130
|
+
try {
|
|
131
|
+
receiver(data, context);
|
|
132
|
+
} catch (e) {
|
|
133
|
+
console.error('[request-iframe] Receiver error:', e);
|
|
134
|
+
}
|
|
135
|
+
});
|
|
136
|
+
}
|
|
137
|
+
|
|
138
|
+
/**
|
|
139
|
+
* Send raw message to target window
|
|
140
|
+
* @param target target window
|
|
141
|
+
* @param message message data (already formatted as PostMessageData)
|
|
142
|
+
* @param targetOrigin target origin (defaults to '*')
|
|
143
|
+
*/
|
|
144
|
+
send(target, message, targetOrigin = '*') {
|
|
145
|
+
if (!isWindowAvailable(target)) {
|
|
146
|
+
return false;
|
|
147
|
+
}
|
|
148
|
+
target.postMessage(message, targetOrigin);
|
|
149
|
+
return true;
|
|
150
|
+
}
|
|
151
|
+
|
|
152
|
+
/**
|
|
153
|
+
* Send typed message to target window (creates PostMessageData automatically)
|
|
154
|
+
* @param target target window
|
|
155
|
+
* @param targetOrigin target origin
|
|
156
|
+
* @param type message type
|
|
157
|
+
* @param requestId request ID
|
|
158
|
+
* @param data additional data
|
|
159
|
+
*/
|
|
160
|
+
sendMessage(target, targetOrigin, type, requestId, data) {
|
|
161
|
+
var message = createPostMessage(type, requestId, _objectSpread(_objectSpread({}, data), {}, {
|
|
162
|
+
secretKey: this.secretKey
|
|
163
|
+
}));
|
|
164
|
+
return this.send(target, message, targetOrigin);
|
|
165
|
+
}
|
|
166
|
+
|
|
167
|
+
/**
|
|
168
|
+
* Add path prefix (for secretKey isolation)
|
|
169
|
+
*/
|
|
170
|
+
prefixPath(path) {
|
|
171
|
+
return this.secretKey ? `${this.secretKey}:${path}` : path;
|
|
172
|
+
}
|
|
173
|
+
|
|
174
|
+
/**
|
|
175
|
+
* Destroy channel (remove event listener)
|
|
176
|
+
*/
|
|
177
|
+
destroy() {
|
|
178
|
+
window.removeEventListener('message', this.boundOnMessage);
|
|
179
|
+
this.receivers.clear();
|
|
180
|
+
}
|
|
181
|
+
}
|
|
@@ -0,0 +1,380 @@
|
|
|
1
|
+
import _defineProperty from "@babel/runtime/helpers/esm/defineProperty";
|
|
2
|
+
function ownKeys(e, r) { var t = Object.keys(e); if (Object.getOwnPropertySymbols) { var o = Object.getOwnPropertySymbols(e); r && (o = o.filter(function (r) { return Object.getOwnPropertyDescriptor(e, r).enumerable; })), t.push.apply(t, o); } return t; }
|
|
3
|
+
function _objectSpread(e) { for (var r = 1; r < arguments.length; r++) { var t = null != arguments[r] ? arguments[r] : {}; r % 2 ? ownKeys(Object(t), !0).forEach(function (r) { _defineProperty(e, r, t[r]); }) : Object.getOwnPropertyDescriptors ? Object.defineProperties(e, Object.getOwnPropertyDescriptors(t)) : ownKeys(Object(t)).forEach(function (r) { Object.defineProperty(e, r, Object.getOwnPropertyDescriptor(t, r)); }); } return e; }
|
|
4
|
+
function _createForOfIteratorHelper(r, e) { var t = "undefined" != typeof Symbol && r[Symbol.iterator] || r["@@iterator"]; if (!t) { if (Array.isArray(r) || (t = _unsupportedIterableToArray(r)) || e && r && "number" == typeof r.length) { t && (r = t); var _n = 0, F = function F() {}; return { s: F, n: function n() { return _n >= r.length ? { done: !0 } : { done: !1, value: r[_n++] }; }, e: function e(r) { throw r; }, f: F }; } throw new TypeError("Invalid attempt to iterate non-iterable instance.\nIn order to be iterable, non-array objects must have a [Symbol.iterator]() method."); } var o, a = !0, u = !1; return { s: function s() { t = t.call(r); }, n: function n() { var r = t.next(); return a = r.done, r; }, e: function e(r) { u = !0, o = r; }, f: function f() { try { a || null == t.return || t.return(); } finally { if (u) throw o; } } }; }
|
|
5
|
+
function _unsupportedIterableToArray(r, a) { if (r) { if ("string" == typeof r) return _arrayLikeToArray(r, a); var t = {}.toString.call(r).slice(8, -1); return "Object" === t && r.constructor && (t = r.constructor.name), "Map" === t || "Set" === t ? Array.from(r) : "Arguments" === t || /^(?:Ui|I)nt(?:8|16|32)(?:Clamped)?Array$/.test(t) ? _arrayLikeToArray(r, a) : void 0; } }
|
|
6
|
+
function _arrayLikeToArray(r, a) { (null == a || a > r.length) && (a = r.length); for (var e = 0, n = Array(a); e < a; e++) n[e] = r[e]; return n; }
|
|
7
|
+
import "core-js/modules/es.symbol.description.js";
|
|
8
|
+
import "core-js/modules/es.array.filter.js";
|
|
9
|
+
import "core-js/modules/es.array.from.js";
|
|
10
|
+
import "core-js/modules/es.array.index-of.js";
|
|
11
|
+
import "core-js/modules/es.array.iterator.js";
|
|
12
|
+
import "core-js/modules/es.array.slice.js";
|
|
13
|
+
import "core-js/modules/es.array.sort.js";
|
|
14
|
+
import "core-js/modules/es.array.splice.js";
|
|
15
|
+
import "core-js/modules/web.dom-collections.for-each.js";
|
|
16
|
+
import "core-js/modules/web.dom-collections.iterator.js";
|
|
17
|
+
import "core-js/modules/es.object.get-own-property-descriptors.js";
|
|
18
|
+
import "core-js/modules/es.regexp.constructor.js";
|
|
19
|
+
import "core-js/modules/es.regexp.exec.js";
|
|
20
|
+
import "core-js/modules/es.regexp.to-string.js";
|
|
21
|
+
import { MessageRole, MessageType } from '../constants';
|
|
22
|
+
import { getProtocolVersion, createPostMessage } from '../utils';
|
|
23
|
+
|
|
24
|
+
/**
|
|
25
|
+
* Message handler function type
|
|
26
|
+
*/
|
|
27
|
+
|
|
28
|
+
/**
|
|
29
|
+
* Message type matcher
|
|
30
|
+
* - string: exact match message type
|
|
31
|
+
* - RegExp: regex match message type
|
|
32
|
+
* - function: custom match function
|
|
33
|
+
*/
|
|
34
|
+
|
|
35
|
+
/**
|
|
36
|
+
* Protocol version validator function
|
|
37
|
+
* @param version protocol version in message
|
|
38
|
+
* @returns true if version is compatible, false otherwise
|
|
39
|
+
*/
|
|
40
|
+
|
|
41
|
+
/**
|
|
42
|
+
* Message handler registration options
|
|
43
|
+
*/
|
|
44
|
+
|
|
45
|
+
/**
|
|
46
|
+
* Message handler entry
|
|
47
|
+
*/
|
|
48
|
+
|
|
49
|
+
/**
|
|
50
|
+
* MessageDispatcher - Message dispatcher for client/server interaction
|
|
51
|
+
*
|
|
52
|
+
* Responsibilities:
|
|
53
|
+
* - Using MessageChannel for receiving and sending messages
|
|
54
|
+
* - Dispatching received messages to registered handlers
|
|
55
|
+
* - Managing handler registration/unregistration
|
|
56
|
+
* - Protocol version validation
|
|
57
|
+
*
|
|
58
|
+
* This is the high-level interface used by client and server implementations.
|
|
59
|
+
* It works with transport-agnostic MessageContext instead of transport-specific MessageEvent.
|
|
60
|
+
*/
|
|
61
|
+
export class MessageDispatcher {
|
|
62
|
+
constructor(channel, role, instanceId) {
|
|
63
|
+
/** Secret key for message isolation */
|
|
64
|
+
/** Channel type */
|
|
65
|
+
/** Role of this dispatcher ('client' or 'server') */
|
|
66
|
+
/** Instance ID of the client/server that owns this dispatcher */
|
|
67
|
+
/** Underlying message channel */
|
|
68
|
+
/**
|
|
69
|
+
* Fallback target for sending auto-ack messages when MessageEvent.source is unavailable.
|
|
70
|
+
* - In real browser postMessage events, `source` should normally exist.
|
|
71
|
+
* - This is primarily used for unit tests or edge environments that synthesize MessageEvent without `source`.
|
|
72
|
+
*/
|
|
73
|
+
_defineProperty(this, "fallbackTargetOrigin", '*');
|
|
74
|
+
/** Message handler list */
|
|
75
|
+
_defineProperty(this, "handlers", []);
|
|
76
|
+
/** Reference count (for determining if can be destroyed when cached) */
|
|
77
|
+
_defineProperty(this, "refCount", 0);
|
|
78
|
+
this.channel = channel;
|
|
79
|
+
this.secretKey = channel.secretKey;
|
|
80
|
+
this.type = channel.type;
|
|
81
|
+
this.role = role;
|
|
82
|
+
this.instanceId = instanceId;
|
|
83
|
+
|
|
84
|
+
// Create bound receiver callback
|
|
85
|
+
this.boundReceiver = (data, context) => {
|
|
86
|
+
this.dispatchMessage(data, context);
|
|
87
|
+
};
|
|
88
|
+
|
|
89
|
+
// Add receiver callback to handle incoming messages
|
|
90
|
+
this.channel.addReceiver(this.boundReceiver);
|
|
91
|
+
}
|
|
92
|
+
|
|
93
|
+
/**
|
|
94
|
+
* Set fallback target for outgoing auto-ack messages.
|
|
95
|
+
*/
|
|
96
|
+
setFallbackTarget(targetWindow, targetOrigin = '*') {
|
|
97
|
+
this.fallbackTargetWindow = targetWindow;
|
|
98
|
+
this.fallbackTargetOrigin = targetOrigin;
|
|
99
|
+
}
|
|
100
|
+
|
|
101
|
+
// ==================== Reference Counting ====================
|
|
102
|
+
|
|
103
|
+
/**
|
|
104
|
+
* Increment reference count
|
|
105
|
+
*/
|
|
106
|
+
addRef() {
|
|
107
|
+
this.refCount++;
|
|
108
|
+
}
|
|
109
|
+
|
|
110
|
+
/**
|
|
111
|
+
* Decrement reference count
|
|
112
|
+
* @returns current reference count
|
|
113
|
+
*/
|
|
114
|
+
release() {
|
|
115
|
+
return --this.refCount;
|
|
116
|
+
}
|
|
117
|
+
|
|
118
|
+
/**
|
|
119
|
+
* Get reference count
|
|
120
|
+
*/
|
|
121
|
+
getRefCount() {
|
|
122
|
+
return this.refCount;
|
|
123
|
+
}
|
|
124
|
+
|
|
125
|
+
// ==================== Message Handling ====================
|
|
126
|
+
|
|
127
|
+
/**
|
|
128
|
+
* Register message handler
|
|
129
|
+
* @param matcher message type matcher
|
|
130
|
+
* @param handler handler function
|
|
131
|
+
* @param options registration options (priority, version validation, etc.)
|
|
132
|
+
* @returns function to unregister
|
|
133
|
+
*/
|
|
134
|
+
registerHandler(matcher, handler, options) {
|
|
135
|
+
var _opts$priority;
|
|
136
|
+
var opts = typeof options === 'number' ? {
|
|
137
|
+
priority: options
|
|
138
|
+
} : options || {};
|
|
139
|
+
var entry = {
|
|
140
|
+
matcher,
|
|
141
|
+
handler,
|
|
142
|
+
priority: (_opts$priority = opts.priority) !== null && _opts$priority !== void 0 ? _opts$priority : 0,
|
|
143
|
+
versionValidator: opts.versionValidator,
|
|
144
|
+
onVersionError: opts.onVersionError
|
|
145
|
+
};
|
|
146
|
+
this.handlers.push(entry);
|
|
147
|
+
// Sort by priority in descending order
|
|
148
|
+
this.handlers.sort((a, b) => b.priority - a.priority);
|
|
149
|
+
return () => {
|
|
150
|
+
var index = this.handlers.indexOf(entry);
|
|
151
|
+
if (index >= 0) {
|
|
152
|
+
this.handlers.splice(index, 1);
|
|
153
|
+
}
|
|
154
|
+
};
|
|
155
|
+
}
|
|
156
|
+
|
|
157
|
+
/**
|
|
158
|
+
* Unregister message handler
|
|
159
|
+
*/
|
|
160
|
+
unregisterHandler(handler) {
|
|
161
|
+
var index = this.handlers.findIndex(entry => entry.handler === handler);
|
|
162
|
+
if (index >= 0) {
|
|
163
|
+
this.handlers.splice(index, 1);
|
|
164
|
+
}
|
|
165
|
+
}
|
|
166
|
+
|
|
167
|
+
/**
|
|
168
|
+
* Dispatch message to matching handlers
|
|
169
|
+
*/
|
|
170
|
+
dispatchMessage(data, context) {
|
|
171
|
+
// If message has already been handled by another dispatcher, skip processing
|
|
172
|
+
if (context.handledBy) {
|
|
173
|
+
return;
|
|
174
|
+
}
|
|
175
|
+
|
|
176
|
+
// Role-based message filtering: only process messages from the opposite role
|
|
177
|
+
// - Server only processes messages from client (role === 'client')
|
|
178
|
+
// - Client only processes messages from server (role === 'server')
|
|
179
|
+
if (data.role !== undefined) {
|
|
180
|
+
var expectedRole = this.role === MessageRole.CLIENT ? MessageRole.SERVER : MessageRole.CLIENT;
|
|
181
|
+
if (data.role !== expectedRole) {
|
|
182
|
+
// Message is from the same role, ignore it to prevent routing confusion
|
|
183
|
+
return;
|
|
184
|
+
}
|
|
185
|
+
}
|
|
186
|
+
var type = data.type;
|
|
187
|
+
var version = getProtocolVersion(data);
|
|
188
|
+
|
|
189
|
+
/**
|
|
190
|
+
* Auto-ack state for this incoming message.
|
|
191
|
+
* - We intentionally couple this to `context.handledBy` as the "accepted/handled" signal.
|
|
192
|
+
* - For some message types we only ack if they are truly handled (e.g. response requireAck),
|
|
193
|
+
* so we avoid incorrectly acknowledging messages when there is no pending consumer.
|
|
194
|
+
*
|
|
195
|
+
* Implementation note:
|
|
196
|
+
* We avoid using Proxy for compatibility and instead hook the `handledBy` property
|
|
197
|
+
* with a setter so handlers can trigger the ack immediately when they "accept" a message.
|
|
198
|
+
*/
|
|
199
|
+
var autoAckState = {
|
|
200
|
+
sent: false
|
|
201
|
+
};
|
|
202
|
+
var originalHandledBy = context.handledBy;
|
|
203
|
+
var handledByValue = originalHandledBy;
|
|
204
|
+
try {
|
|
205
|
+
Object.defineProperty(context, 'handledBy', {
|
|
206
|
+
configurable: true,
|
|
207
|
+
enumerable: true,
|
|
208
|
+
get() {
|
|
209
|
+
return handledByValue;
|
|
210
|
+
},
|
|
211
|
+
set: value => {
|
|
212
|
+
handledByValue = value;
|
|
213
|
+
if (value && !autoAckState.sent) {
|
|
214
|
+
autoAckState.sent = true;
|
|
215
|
+
this.tryAutoAck(data, context);
|
|
216
|
+
}
|
|
217
|
+
}
|
|
218
|
+
});
|
|
219
|
+
} catch (_unused) {
|
|
220
|
+
/**
|
|
221
|
+
* In very rare cases `defineProperty` may fail (frozen object).
|
|
222
|
+
* We still proceed without auto-ack; handlers will continue to work as before.
|
|
223
|
+
*/
|
|
224
|
+
}
|
|
225
|
+
var _iterator = _createForOfIteratorHelper(this.handlers),
|
|
226
|
+
_step;
|
|
227
|
+
try {
|
|
228
|
+
for (_iterator.s(); !(_step = _iterator.n()).done;) {
|
|
229
|
+
var entry = _step.value;
|
|
230
|
+
if (this.matchType(type, entry.matcher)) {
|
|
231
|
+
// If message has been handled by a previous handler, stop processing
|
|
232
|
+
if (context.handledBy) {
|
|
233
|
+
break;
|
|
234
|
+
}
|
|
235
|
+
|
|
236
|
+
// If handler specified version validation
|
|
237
|
+
if (entry.versionValidator && version !== undefined) {
|
|
238
|
+
if (!entry.versionValidator(version)) {
|
|
239
|
+
var _entry$onVersionError;
|
|
240
|
+
// Version incompatible, call error handler (if any)
|
|
241
|
+
(_entry$onVersionError = entry.onVersionError) === null || _entry$onVersionError === void 0 || _entry$onVersionError.call(entry, data, context, version);
|
|
242
|
+
continue; // Skip this handler, try other handlers
|
|
243
|
+
}
|
|
244
|
+
}
|
|
245
|
+
try {
|
|
246
|
+
entry.handler(data, context);
|
|
247
|
+
// After handler execution, check if it marked the message as handled
|
|
248
|
+
// If context.handledBy is set by the handler, subsequent handlers will be skipped
|
|
249
|
+
} catch (e) {
|
|
250
|
+
// Ignore handler exception, continue executing other handlers
|
|
251
|
+
console.error('[request-iframe] Handler error:', e);
|
|
252
|
+
}
|
|
253
|
+
}
|
|
254
|
+
}
|
|
255
|
+
} catch (err) {
|
|
256
|
+
_iterator.e(err);
|
|
257
|
+
} finally {
|
|
258
|
+
_iterator.f();
|
|
259
|
+
}
|
|
260
|
+
}
|
|
261
|
+
|
|
262
|
+
/**
|
|
263
|
+
* Auto-ack logic (generalized requireAck workflow)
|
|
264
|
+
*
|
|
265
|
+
* Notes:
|
|
266
|
+
* - This is intentionally conservative: it only runs after the message is marked as handled
|
|
267
|
+
* (via `context.handledBy`) to avoid acknowledging messages that no consumer will process.
|
|
268
|
+
* - For backward compatibility:
|
|
269
|
+
* - REQUEST defaults to requiring ACK unless `requireAck === false`
|
|
270
|
+
* - Other message types only ack when `requireAck === true`
|
|
271
|
+
*/
|
|
272
|
+
tryAutoAck(data, context) {
|
|
273
|
+
var _context$source;
|
|
274
|
+
var targetWindow = (_context$source = context.source) !== null && _context$source !== void 0 ? _context$source : this.fallbackTargetWindow;
|
|
275
|
+
if (!targetWindow) return;
|
|
276
|
+
var targetOrigin = context.source ? context.origin : this.fallbackTargetOrigin || context.origin;
|
|
277
|
+
var type = data.type;
|
|
278
|
+
|
|
279
|
+
// Don't auto-ack ack messages (avoid loops)
|
|
280
|
+
if (type === MessageType.ACK || type === MessageType.RECEIVED) return;
|
|
281
|
+
var shouldAckRequest = type === MessageType.REQUEST && data.requireAck !== false;
|
|
282
|
+
var shouldAckPing = type === MessageType.PING && data.requireAck === true;
|
|
283
|
+
var shouldAckResponse = (type === MessageType.RESPONSE || type === MessageType.ERROR) && data.requireAck === true;
|
|
284
|
+
if ((shouldAckRequest || shouldAckPing) && context.accepted === true) {
|
|
285
|
+
// Delivery acknowledgment for request/ping
|
|
286
|
+
this.sendMessage(targetWindow, targetOrigin, MessageType.ACK, data.requestId, {
|
|
287
|
+
path: data.path,
|
|
288
|
+
targetId: data.creatorId,
|
|
289
|
+
ackMeta: data.ackMeta
|
|
290
|
+
});
|
|
291
|
+
return;
|
|
292
|
+
}
|
|
293
|
+
if (shouldAckResponse && context.accepted === true) {
|
|
294
|
+
// Receipt acknowledgment for response/error
|
|
295
|
+
this.sendMessage(targetWindow, targetOrigin, MessageType.RECEIVED, data.requestId, {
|
|
296
|
+
path: data.path,
|
|
297
|
+
targetId: data.creatorId,
|
|
298
|
+
ackMeta: data.ackMeta
|
|
299
|
+
});
|
|
300
|
+
}
|
|
301
|
+
}
|
|
302
|
+
|
|
303
|
+
/**
|
|
304
|
+
* Check if message type matches
|
|
305
|
+
*/
|
|
306
|
+
matchType(type, matcher) {
|
|
307
|
+
if (typeof matcher === 'string') {
|
|
308
|
+
return type === matcher;
|
|
309
|
+
}
|
|
310
|
+
if (matcher instanceof RegExp) {
|
|
311
|
+
return matcher.test(type);
|
|
312
|
+
}
|
|
313
|
+
if (typeof matcher === 'function') {
|
|
314
|
+
return matcher(type);
|
|
315
|
+
}
|
|
316
|
+
return false;
|
|
317
|
+
}
|
|
318
|
+
|
|
319
|
+
// ==================== Sending (Delegated to Channel) ====================
|
|
320
|
+
|
|
321
|
+
/**
|
|
322
|
+
* Send raw message to target window
|
|
323
|
+
* @param target target window
|
|
324
|
+
* @param message message data (already formatted as PostMessageData)
|
|
325
|
+
* @param targetOrigin target origin (defaults to '*')
|
|
326
|
+
*/
|
|
327
|
+
send(target, message, targetOrigin = '*') {
|
|
328
|
+
// Automatically set role and creatorId if not already set (for backward compatibility)
|
|
329
|
+
if (message.role === undefined) {
|
|
330
|
+
message.role = this.role;
|
|
331
|
+
}
|
|
332
|
+
if (message.creatorId === undefined && this.instanceId) {
|
|
333
|
+
message.creatorId = this.instanceId;
|
|
334
|
+
}
|
|
335
|
+
return this.channel.send(target, message, targetOrigin);
|
|
336
|
+
}
|
|
337
|
+
|
|
338
|
+
/**
|
|
339
|
+
* Send typed message to target window (creates PostMessageData automatically)
|
|
340
|
+
* @param target target window
|
|
341
|
+
* @param targetOrigin target origin
|
|
342
|
+
* @param type message type
|
|
343
|
+
* @param requestId request ID
|
|
344
|
+
* @param data additional data
|
|
345
|
+
*/
|
|
346
|
+
sendMessage(target, targetOrigin, type, requestId, data) {
|
|
347
|
+
// Automatically set role, creatorId, and secretKey based on dispatcher's properties
|
|
348
|
+
// Create message with role, creatorId, and secretKey using createPostMessage directly
|
|
349
|
+
var message = createPostMessage(type, requestId, _objectSpread(_objectSpread({}, data), {}, {
|
|
350
|
+
role: this.role,
|
|
351
|
+
creatorId: this.instanceId,
|
|
352
|
+
secretKey: this.secretKey
|
|
353
|
+
}));
|
|
354
|
+
return this.channel.send(target, message, targetOrigin);
|
|
355
|
+
}
|
|
356
|
+
|
|
357
|
+
// ==================== Utilities ====================
|
|
358
|
+
|
|
359
|
+
/**
|
|
360
|
+
* Add path prefix
|
|
361
|
+
*/
|
|
362
|
+
prefixPath(path) {
|
|
363
|
+
return this.channel.prefixPath(path);
|
|
364
|
+
}
|
|
365
|
+
|
|
366
|
+
/**
|
|
367
|
+
* Get the underlying message channel
|
|
368
|
+
*/
|
|
369
|
+
getChannel() {
|
|
370
|
+
return this.channel;
|
|
371
|
+
}
|
|
372
|
+
|
|
373
|
+
/**
|
|
374
|
+
* Destroy dispatcher (clear handlers, but don't destroy channel as it may be shared)
|
|
375
|
+
*/
|
|
376
|
+
destroy() {
|
|
377
|
+
this.handlers.length = 0;
|
|
378
|
+
this.channel.removeReceiver(this.boundReceiver);
|
|
379
|
+
}
|
|
380
|
+
}
|