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,323 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
|
|
3
|
+
require("core-js/modules/es.array.filter.js");
|
|
4
|
+
require("core-js/modules/es.object.get-own-property-descriptors.js");
|
|
5
|
+
require("core-js/modules/web.dom-collections.for-each.js");
|
|
6
|
+
var _interopRequireDefault = require("@babel/runtime/helpers/interopRequireDefault");
|
|
7
|
+
Object.defineProperty(exports, "__esModule", {
|
|
8
|
+
value: true
|
|
9
|
+
});
|
|
10
|
+
exports.ServerResponseImpl = void 0;
|
|
11
|
+
var _regenerator = _interopRequireDefault(require("@babel/runtime/regenerator"));
|
|
12
|
+
require("core-js/modules/es.array.includes.js");
|
|
13
|
+
require("core-js/modules/es.array.iterator.js");
|
|
14
|
+
require("core-js/modules/es.promise.js");
|
|
15
|
+
require("core-js/modules/es.string.includes.js");
|
|
16
|
+
require("core-js/modules/web.dom-collections.iterator.js");
|
|
17
|
+
var _asyncToGenerator2 = _interopRequireDefault(require("@babel/runtime/helpers/asyncToGenerator"));
|
|
18
|
+
var _defineProperty2 = _interopRequireDefault(require("@babel/runtime/helpers/defineProperty"));
|
|
19
|
+
var _utils = require("../utils");
|
|
20
|
+
var _constants = require("../constants");
|
|
21
|
+
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; }
|
|
22
|
+
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) { (0, _defineProperty2.default)(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; }
|
|
23
|
+
/**
|
|
24
|
+
* Callback waiting for client acknowledgment
|
|
25
|
+
*/
|
|
26
|
+
|
|
27
|
+
/**
|
|
28
|
+
* ServerResponse implementation
|
|
29
|
+
*/
|
|
30
|
+
class ServerResponseImpl {
|
|
31
|
+
constructor(requestId, path, secretKey, targetWindow, targetOrigin, channel) {
|
|
32
|
+
(0, _defineProperty2.default)(this, "statusCode", _constants.HttpStatus.OK);
|
|
33
|
+
(0, _defineProperty2.default)(this, "headers", {});
|
|
34
|
+
(0, _defineProperty2.default)(this, "_sent", false);
|
|
35
|
+
this.requestId = requestId;
|
|
36
|
+
this.path = path;
|
|
37
|
+
this.secretKey = secretKey;
|
|
38
|
+
this.targetWindow = targetWindow;
|
|
39
|
+
this.targetOrigin = targetOrigin;
|
|
40
|
+
this.channel = channel;
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
/**
|
|
44
|
+
* Send message via channel or direct postMessage
|
|
45
|
+
*/
|
|
46
|
+
sendMessage(message) {
|
|
47
|
+
if (this.channel) {
|
|
48
|
+
this.channel.send(this.targetWindow, message, this.targetOrigin);
|
|
49
|
+
} else {
|
|
50
|
+
this.targetWindow.postMessage(message, this.targetOrigin);
|
|
51
|
+
}
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
/**
|
|
55
|
+
* Set callback waiting for client acknowledgment
|
|
56
|
+
*/
|
|
57
|
+
_setOnAckCallback(callback) {
|
|
58
|
+
this.onAckCallback = callback;
|
|
59
|
+
}
|
|
60
|
+
|
|
61
|
+
/**
|
|
62
|
+
* Trigger client acknowledgment callback
|
|
63
|
+
*/
|
|
64
|
+
_triggerAck(received) {
|
|
65
|
+
if (this.onAckCallback) {
|
|
66
|
+
this.onAckCallback(received);
|
|
67
|
+
this.onAckCallback = undefined;
|
|
68
|
+
}
|
|
69
|
+
}
|
|
70
|
+
send(data, options) {
|
|
71
|
+
var _options$requireAck;
|
|
72
|
+
if (this._sent) return Promise.resolve(false);
|
|
73
|
+
this._sent = true;
|
|
74
|
+
var requireAck = (_options$requireAck = options === null || options === void 0 ? void 0 : options.requireAck) !== null && _options$requireAck !== void 0 ? _options$requireAck : false;
|
|
75
|
+
|
|
76
|
+
// If acknowledgment not required, send directly and return true
|
|
77
|
+
if (!requireAck) {
|
|
78
|
+
this.sendMessage((0, _utils.createPostMessage)(_constants.MessageType.RESPONSE, this.requestId, {
|
|
79
|
+
path: this.path,
|
|
80
|
+
secretKey: this.secretKey,
|
|
81
|
+
data,
|
|
82
|
+
status: this.statusCode,
|
|
83
|
+
statusText: (0, _constants.getStatusText)(this.statusCode),
|
|
84
|
+
headers: this.headers,
|
|
85
|
+
requireAck: false
|
|
86
|
+
}));
|
|
87
|
+
return Promise.resolve(true);
|
|
88
|
+
}
|
|
89
|
+
|
|
90
|
+
// Acknowledgment required, wait for client response
|
|
91
|
+
return new Promise(resolve => {
|
|
92
|
+
this._setOnAckCallback(resolve);
|
|
93
|
+
this.sendMessage((0, _utils.createPostMessage)(_constants.MessageType.RESPONSE, this.requestId, {
|
|
94
|
+
path: this.path,
|
|
95
|
+
secretKey: this.secretKey,
|
|
96
|
+
data,
|
|
97
|
+
status: this.statusCode,
|
|
98
|
+
statusText: (0, _constants.getStatusText)(this.statusCode),
|
|
99
|
+
headers: this.headers,
|
|
100
|
+
requireAck: true
|
|
101
|
+
}));
|
|
102
|
+
});
|
|
103
|
+
}
|
|
104
|
+
json(data, options) {
|
|
105
|
+
this.setHeader(_constants.HttpHeader.CONTENT_TYPE, 'application/json');
|
|
106
|
+
return this.send(data, options);
|
|
107
|
+
}
|
|
108
|
+
sendFile(content, options) {
|
|
109
|
+
var _this = this;
|
|
110
|
+
return (0, _asyncToGenerator2.default)(/*#__PURE__*/_regenerator.default.mark(function _callee() {
|
|
111
|
+
var _options$requireAck2;
|
|
112
|
+
var requireAck, base64Content, mimeType, fileName, fileHeaders, messageData;
|
|
113
|
+
return _regenerator.default.wrap(function (_context) {
|
|
114
|
+
while (1) switch (_context.prev = _context.next) {
|
|
115
|
+
case 0:
|
|
116
|
+
if (!_this._sent) {
|
|
117
|
+
_context.next = 1;
|
|
118
|
+
break;
|
|
119
|
+
}
|
|
120
|
+
return _context.abrupt("return", false);
|
|
121
|
+
case 1:
|
|
122
|
+
_this._sent = true;
|
|
123
|
+
requireAck = (_options$requireAck2 = options === null || options === void 0 ? void 0 : options.requireAck) !== null && _options$requireAck2 !== void 0 ? _options$requireAck2 : false;
|
|
124
|
+
mimeType = (options === null || options === void 0 ? void 0 : options.mimeType) || 'application/octet-stream';
|
|
125
|
+
fileName = options === null || options === void 0 ? void 0 : options.fileName;
|
|
126
|
+
if (!(typeof content === 'string')) {
|
|
127
|
+
_context.next = 2;
|
|
128
|
+
break;
|
|
129
|
+
}
|
|
130
|
+
// If it's a plain string, convert to base64
|
|
131
|
+
base64Content = btoa(unescape(encodeURIComponent(content)));
|
|
132
|
+
_context.next = 6;
|
|
133
|
+
break;
|
|
134
|
+
case 2:
|
|
135
|
+
if (!(content instanceof File)) {
|
|
136
|
+
_context.next = 4;
|
|
137
|
+
break;
|
|
138
|
+
}
|
|
139
|
+
mimeType = content.type || mimeType;
|
|
140
|
+
fileName = fileName || content.name;
|
|
141
|
+
_context.next = 3;
|
|
142
|
+
return _this.blobToBase64(content);
|
|
143
|
+
case 3:
|
|
144
|
+
base64Content = _context.sent;
|
|
145
|
+
_context.next = 6;
|
|
146
|
+
break;
|
|
147
|
+
case 4:
|
|
148
|
+
_context.next = 5;
|
|
149
|
+
return _this.blobToBase64(content);
|
|
150
|
+
case 5:
|
|
151
|
+
base64Content = _context.sent;
|
|
152
|
+
case 6:
|
|
153
|
+
// Merge file-related headers
|
|
154
|
+
fileHeaders = _objectSpread(_objectSpread({}, _this.headers), {}, {
|
|
155
|
+
[_constants.HttpHeader.CONTENT_TYPE]: mimeType,
|
|
156
|
+
[_constants.HttpHeader.CONTENT_DISPOSITION]: fileName ? `attachment; filename="${fileName}"` : 'attachment'
|
|
157
|
+
});
|
|
158
|
+
messageData = (0, _utils.createPostMessage)(_constants.MessageType.RESPONSE, _this.requestId, {
|
|
159
|
+
path: _this.path,
|
|
160
|
+
secretKey: _this.secretKey,
|
|
161
|
+
status: _this.statusCode,
|
|
162
|
+
statusText: (0, _constants.getStatusText)(_this.statusCode),
|
|
163
|
+
headers: fileHeaders,
|
|
164
|
+
fileData: {
|
|
165
|
+
content: base64Content,
|
|
166
|
+
mimeType,
|
|
167
|
+
fileName
|
|
168
|
+
},
|
|
169
|
+
requireAck
|
|
170
|
+
}); // If acknowledgment not required, send directly and return true
|
|
171
|
+
if (requireAck) {
|
|
172
|
+
_context.next = 7;
|
|
173
|
+
break;
|
|
174
|
+
}
|
|
175
|
+
_this.sendMessage(messageData);
|
|
176
|
+
return _context.abrupt("return", true);
|
|
177
|
+
case 7:
|
|
178
|
+
return _context.abrupt("return", new Promise(resolve => {
|
|
179
|
+
_this._setOnAckCallback(resolve);
|
|
180
|
+
_this.sendMessage(messageData);
|
|
181
|
+
}));
|
|
182
|
+
case 8:
|
|
183
|
+
case "end":
|
|
184
|
+
return _context.stop();
|
|
185
|
+
}
|
|
186
|
+
}, _callee);
|
|
187
|
+
}))();
|
|
188
|
+
}
|
|
189
|
+
|
|
190
|
+
/**
|
|
191
|
+
* Send stream response
|
|
192
|
+
* Bind stream to current request context and start stream transmission
|
|
193
|
+
*/
|
|
194
|
+
sendStream(stream) {
|
|
195
|
+
var _this2 = this;
|
|
196
|
+
return (0, _asyncToGenerator2.default)(/*#__PURE__*/_regenerator.default.mark(function _callee2() {
|
|
197
|
+
return _regenerator.default.wrap(function (_context2) {
|
|
198
|
+
while (1) switch (_context2.prev = _context2.next) {
|
|
199
|
+
case 0:
|
|
200
|
+
if (!_this2._sent) {
|
|
201
|
+
_context2.next = 1;
|
|
202
|
+
break;
|
|
203
|
+
}
|
|
204
|
+
return _context2.abrupt("return");
|
|
205
|
+
case 1:
|
|
206
|
+
_this2._sent = true;
|
|
207
|
+
|
|
208
|
+
// Bind stream to request context
|
|
209
|
+
stream._bind({
|
|
210
|
+
requestId: _this2.requestId,
|
|
211
|
+
targetWindow: _this2.targetWindow,
|
|
212
|
+
targetOrigin: _this2.targetOrigin,
|
|
213
|
+
secretKey: _this2.secretKey,
|
|
214
|
+
channel: _this2.channel
|
|
215
|
+
});
|
|
216
|
+
|
|
217
|
+
// Start stream transmission
|
|
218
|
+
_context2.next = 2;
|
|
219
|
+
return stream.start();
|
|
220
|
+
case 2:
|
|
221
|
+
case "end":
|
|
222
|
+
return _context2.stop();
|
|
223
|
+
}
|
|
224
|
+
}, _callee2);
|
|
225
|
+
}))();
|
|
226
|
+
}
|
|
227
|
+
status(code) {
|
|
228
|
+
this.statusCode = code;
|
|
229
|
+
return this;
|
|
230
|
+
}
|
|
231
|
+
setHeader(name, value) {
|
|
232
|
+
// Consistent with Express, returns void
|
|
233
|
+
// Special handling for Set-Cookie, keep as array
|
|
234
|
+
if (name.toLowerCase() === _constants.HttpHeader.SET_COOKIE.toLowerCase()) {
|
|
235
|
+
var existing = this.headers[_constants.HttpHeader.SET_COOKIE];
|
|
236
|
+
if (Array.isArray(value)) {
|
|
237
|
+
this.headers[_constants.HttpHeader.SET_COOKIE] = Array.isArray(existing) ? [...existing, ...value] : value;
|
|
238
|
+
} else {
|
|
239
|
+
var newValue = String(value);
|
|
240
|
+
if (Array.isArray(existing)) {
|
|
241
|
+
existing.push(newValue);
|
|
242
|
+
} else {
|
|
243
|
+
this.headers[_constants.HttpHeader.SET_COOKIE] = [newValue];
|
|
244
|
+
}
|
|
245
|
+
}
|
|
246
|
+
} else if (Array.isArray(value)) {
|
|
247
|
+
this.headers[name] = value.join(', ');
|
|
248
|
+
} else {
|
|
249
|
+
this.headers[name] = String(value);
|
|
250
|
+
}
|
|
251
|
+
}
|
|
252
|
+
set(name, value) {
|
|
253
|
+
// Chainable version, compatible with Express res.set
|
|
254
|
+
this.setHeader(name, value);
|
|
255
|
+
return this;
|
|
256
|
+
}
|
|
257
|
+
cookie(name, value, options) {
|
|
258
|
+
/**
|
|
259
|
+
* Set Cookie (similar to HTTP Set-Cookie)
|
|
260
|
+
* Generate Set-Cookie string and add to headers[HttpHeader.SET_COOKIE] array
|
|
261
|
+
* Client will parse and save to cookie storage upon receiving
|
|
262
|
+
*/
|
|
263
|
+
var setCookieStr = (0, _utils.createSetCookie)(name, value, {
|
|
264
|
+
path: options === null || options === void 0 ? void 0 : options.path,
|
|
265
|
+
expires: options === null || options === void 0 ? void 0 : options.expires,
|
|
266
|
+
maxAge: options === null || options === void 0 ? void 0 : options.maxAge,
|
|
267
|
+
httpOnly: options === null || options === void 0 ? void 0 : options.httpOnly,
|
|
268
|
+
secure: options === null || options === void 0 ? void 0 : options.secure,
|
|
269
|
+
sameSite: (options === null || options === void 0 ? void 0 : options.sameSite) === true ? 'Strict' : (options === null || options === void 0 ? void 0 : options.sameSite) === false ? undefined : options === null || options === void 0 ? void 0 : options.sameSite
|
|
270
|
+
});
|
|
271
|
+
|
|
272
|
+
// Add to Set-Cookie header array
|
|
273
|
+
var existing = this.headers[_constants.HttpHeader.SET_COOKIE];
|
|
274
|
+
if (Array.isArray(existing)) {
|
|
275
|
+
existing.push(setCookieStr);
|
|
276
|
+
} else {
|
|
277
|
+
this.headers[_constants.HttpHeader.SET_COOKIE] = [setCookieStr];
|
|
278
|
+
}
|
|
279
|
+
return this;
|
|
280
|
+
}
|
|
281
|
+
clearCookie(name, options) {
|
|
282
|
+
/**
|
|
283
|
+
* Clear specified Cookie
|
|
284
|
+
* Generate an expired Set-Cookie string, client will delete this cookie upon receiving
|
|
285
|
+
*/
|
|
286
|
+
var setCookieStr = (0, _utils.createClearCookie)(name, {
|
|
287
|
+
path: options === null || options === void 0 ? void 0 : options.path
|
|
288
|
+
});
|
|
289
|
+
|
|
290
|
+
// Add to Set-Cookie header array
|
|
291
|
+
var existing = this.headers[_constants.HttpHeader.SET_COOKIE];
|
|
292
|
+
if (Array.isArray(existing)) {
|
|
293
|
+
existing.push(setCookieStr);
|
|
294
|
+
} else {
|
|
295
|
+
this.headers[_constants.HttpHeader.SET_COOKIE] = [setCookieStr];
|
|
296
|
+
}
|
|
297
|
+
return this;
|
|
298
|
+
}
|
|
299
|
+
blobToBase64(blob) {
|
|
300
|
+
return (0, _asyncToGenerator2.default)(/*#__PURE__*/_regenerator.default.mark(function _callee3() {
|
|
301
|
+
return _regenerator.default.wrap(function (_context3) {
|
|
302
|
+
while (1) switch (_context3.prev = _context3.next) {
|
|
303
|
+
case 0:
|
|
304
|
+
return _context3.abrupt("return", new Promise((resolve, reject) => {
|
|
305
|
+
var reader = new FileReader();
|
|
306
|
+
reader.onloadend = () => {
|
|
307
|
+
var result = reader.result;
|
|
308
|
+
// Remove data URL prefix (e.g., "data:image/png;base64,")
|
|
309
|
+
var base64 = result.includes(',') ? result.split(',')[1] : result;
|
|
310
|
+
resolve(base64);
|
|
311
|
+
};
|
|
312
|
+
reader.onerror = reject;
|
|
313
|
+
reader.readAsDataURL(blob);
|
|
314
|
+
}));
|
|
315
|
+
case 1:
|
|
316
|
+
case "end":
|
|
317
|
+
return _context3.stop();
|
|
318
|
+
}
|
|
319
|
+
}, _callee3);
|
|
320
|
+
}))();
|
|
321
|
+
}
|
|
322
|
+
}
|
|
323
|
+
exports.ServerResponseImpl = ServerResponseImpl;
|
|
@@ -0,0 +1,86 @@
|
|
|
1
|
+
import { PostMessageData, ServerEventName } from '../types';
|
|
2
|
+
/**
|
|
3
|
+
* server 内部事件监听器集合
|
|
4
|
+
*/
|
|
5
|
+
type ServerListeners = Record<ServerEventName, Set<(payload: any, event?: MessageEvent) => void>>;
|
|
6
|
+
/**
|
|
7
|
+
* 等待客户端确认的响应
|
|
8
|
+
*/
|
|
9
|
+
interface PendingAck {
|
|
10
|
+
resolve: (received: boolean) => void;
|
|
11
|
+
reject: (error: Error) => void;
|
|
12
|
+
timeoutId: ReturnType<typeof setTimeout>;
|
|
13
|
+
}
|
|
14
|
+
/**
|
|
15
|
+
* RequestIframeBaseServer 基类(封装基本的请求交互逻辑)
|
|
16
|
+
*/
|
|
17
|
+
export declare abstract class RequestIframeBaseServer {
|
|
18
|
+
protected readonly uniqueKey?: string;
|
|
19
|
+
protected readonly ackTimeout: number;
|
|
20
|
+
protected readonly listeners: ServerListeners;
|
|
21
|
+
/** 等待客户端确认的响应 */
|
|
22
|
+
protected readonly pendingAcks: Map<string, PendingAck>;
|
|
23
|
+
/** 客户端等待响应的请求 */
|
|
24
|
+
protected readonly pendingClientRequests: Map<string, {
|
|
25
|
+
resolve: (data: PostMessageData) => void;
|
|
26
|
+
reject: (error: Error) => void;
|
|
27
|
+
origin?: string;
|
|
28
|
+
}>;
|
|
29
|
+
protected readonly onMessage: (event: MessageEvent) => void;
|
|
30
|
+
constructor(options?: {
|
|
31
|
+
uniqueKey?: string;
|
|
32
|
+
ackTimeout?: number;
|
|
33
|
+
});
|
|
34
|
+
/**
|
|
35
|
+
* 处理请求(由子类实现)
|
|
36
|
+
*/
|
|
37
|
+
protected abstract handleRequest(data: PostMessageData, event: MessageEvent): void;
|
|
38
|
+
/**
|
|
39
|
+
* 处理客户端响应(ack、async、response、error)
|
|
40
|
+
*/
|
|
41
|
+
protected handleClientResponse(data: PostMessageData, event: MessageEvent): void;
|
|
42
|
+
/**
|
|
43
|
+
* 处理客户端确认收到
|
|
44
|
+
*/
|
|
45
|
+
protected handleReceived(data: PostMessageData): void;
|
|
46
|
+
/**
|
|
47
|
+
* 处理 ping 请求(用于 isConnect)
|
|
48
|
+
*/
|
|
49
|
+
protected handlePing(data: PostMessageData, event: MessageEvent): void;
|
|
50
|
+
/**
|
|
51
|
+
* 处理 pong 响应(用于 isConnect)
|
|
52
|
+
*/
|
|
53
|
+
protected handlePong(data: PostMessageData, event: MessageEvent): void;
|
|
54
|
+
/**
|
|
55
|
+
* 注册等待客户端确认的响应
|
|
56
|
+
*/
|
|
57
|
+
_registerPendingAck(requestId: string, resolve: (received: boolean) => void, reject: (error: Error) => void): void;
|
|
58
|
+
/**
|
|
59
|
+
* 内部方法:监听底层事件
|
|
60
|
+
*/
|
|
61
|
+
_on(event: ServerEventName, fn: (payload: any, messageEvent?: MessageEvent) => void): void;
|
|
62
|
+
/**
|
|
63
|
+
* 内部方法:取消监听底层事件
|
|
64
|
+
*/
|
|
65
|
+
_off(event: ServerEventName, fn?: (payload: any, messageEvent?: MessageEvent) => void): void;
|
|
66
|
+
/**
|
|
67
|
+
* 内部方法:供 client 注册等待响应的 Promise
|
|
68
|
+
*/
|
|
69
|
+
_registerPendingRequest(requestId: string, resolve: (data: PostMessageData) => void, reject: (error: Error) => void, origin?: string): void;
|
|
70
|
+
/**
|
|
71
|
+
* 内部方法:供 client 取消等待
|
|
72
|
+
*/
|
|
73
|
+
_unregisterPendingRequest(requestId: string): void;
|
|
74
|
+
/**
|
|
75
|
+
* 销毁 server(移除 message 监听)
|
|
76
|
+
*/
|
|
77
|
+
destroy(): void;
|
|
78
|
+
protected emit(event: ServerEventName, payload: any, messageEvent?: MessageEvent): void;
|
|
79
|
+
protected prefixPath(path: string): string;
|
|
80
|
+
/**
|
|
81
|
+
* 发送协议版本不兼容错误(版本过低)
|
|
82
|
+
*/
|
|
83
|
+
protected sendProtocolError(data: PostMessageData, event: MessageEvent, remoteVersion: number): void;
|
|
84
|
+
}
|
|
85
|
+
export {};
|
|
86
|
+
//# sourceMappingURL=server-base.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"server-base.d.ts","sourceRoot":"","sources":["../../src/core/server-base.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,257 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
|
|
3
|
+
var _interopRequireDefault = require("@babel/runtime/helpers/interopRequireDefault");
|
|
4
|
+
Object.defineProperty(exports, "__esModule", {
|
|
5
|
+
value: true
|
|
6
|
+
});
|
|
7
|
+
exports.RequestIframeBaseServer = void 0;
|
|
8
|
+
require("core-js/modules/es.array.iterator.js");
|
|
9
|
+
require("core-js/modules/es.map.js");
|
|
10
|
+
require("core-js/modules/es.set.js");
|
|
11
|
+
require("core-js/modules/web.dom-collections.for-each.js");
|
|
12
|
+
require("core-js/modules/web.dom-collections.iterator.js");
|
|
13
|
+
var _defineProperty2 = _interopRequireDefault(require("@babel/runtime/helpers/defineProperty"));
|
|
14
|
+
var _utils = require("../utils");
|
|
15
|
+
var _constants = require("../constants");
|
|
16
|
+
/**
|
|
17
|
+
* server 内部事件监听器集合
|
|
18
|
+
*/
|
|
19
|
+
|
|
20
|
+
/**
|
|
21
|
+
* 等待客户端确认的响应
|
|
22
|
+
*/
|
|
23
|
+
|
|
24
|
+
/**
|
|
25
|
+
* RequestIframeBaseServer 基类(封装基本的请求交互逻辑)
|
|
26
|
+
*/
|
|
27
|
+
class RequestIframeBaseServer {
|
|
28
|
+
constructor(options) {
|
|
29
|
+
var _options$ackTimeout;
|
|
30
|
+
(0, _defineProperty2.default)(this, "listeners", {
|
|
31
|
+
request: new Set(),
|
|
32
|
+
ack: new Set(),
|
|
33
|
+
async: new Set(),
|
|
34
|
+
response: new Set(),
|
|
35
|
+
error: new Set(),
|
|
36
|
+
received: new Set(),
|
|
37
|
+
ping: new Set(),
|
|
38
|
+
pong: new Set()
|
|
39
|
+
});
|
|
40
|
+
/** 等待客户端确认的响应 */
|
|
41
|
+
(0, _defineProperty2.default)(this, "pendingAcks", new Map());
|
|
42
|
+
/** 客户端等待响应的请求 */
|
|
43
|
+
(0, _defineProperty2.default)(this, "pendingClientRequests", new Map());
|
|
44
|
+
(0, _defineProperty2.default)(this, "onMessage", event => {
|
|
45
|
+
var data = event.data;
|
|
46
|
+
|
|
47
|
+
// 检查是否是 request-iframe 框架的消息(基本格式验证)
|
|
48
|
+
if (!(0, _utils.isValidPostMessage)(data)) {
|
|
49
|
+
return;
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
// 检查协议版本兼容性
|
|
53
|
+
var version = (0, _utils.getProtocolVersion)(data);
|
|
54
|
+
if (version !== undefined && !(0, _utils.isCompatibleVersion)(version)) {
|
|
55
|
+
// 协议版本不兼容,通知对方
|
|
56
|
+
this.sendProtocolError(data, event, version);
|
|
57
|
+
return;
|
|
58
|
+
}
|
|
59
|
+
|
|
60
|
+
// uniqueKey 隔离:不匹配则忽略
|
|
61
|
+
if (this.uniqueKey) {
|
|
62
|
+
if (data.uniqueKey !== this.uniqueKey) return;
|
|
63
|
+
} else {
|
|
64
|
+
if (data.uniqueKey) return;
|
|
65
|
+
}
|
|
66
|
+
|
|
67
|
+
// 触发框架内部事件监听器
|
|
68
|
+
this.emit(data.type, data, event);
|
|
69
|
+
|
|
70
|
+
// 处理请求(由子类实现)
|
|
71
|
+
if (data.type === _constants.MessageType.REQUEST) {
|
|
72
|
+
this.handleRequest(data, event);
|
|
73
|
+
return;
|
|
74
|
+
}
|
|
75
|
+
|
|
76
|
+
// 处理响应和错误(供 client 使用)
|
|
77
|
+
if (data.type === _constants.MessageType.RESPONSE || data.type === _constants.MessageType.ERROR || data.type === _constants.MessageType.ACK || data.type === _constants.MessageType.ASYNC) {
|
|
78
|
+
this.handleClientResponse(data, event);
|
|
79
|
+
return;
|
|
80
|
+
}
|
|
81
|
+
|
|
82
|
+
// 处理客户端确认收到(received)
|
|
83
|
+
if (data.type === _constants.MessageType.RECEIVED) {
|
|
84
|
+
this.handleReceived(data);
|
|
85
|
+
return;
|
|
86
|
+
}
|
|
87
|
+
|
|
88
|
+
// 处理 ping(用于 isConnect)
|
|
89
|
+
if (data.type === _constants.MessageType.PING) {
|
|
90
|
+
this.handlePing(data, event);
|
|
91
|
+
return;
|
|
92
|
+
}
|
|
93
|
+
|
|
94
|
+
// 处理 pong(用于 isConnect)
|
|
95
|
+
if (data.type === _constants.MessageType.PONG) {
|
|
96
|
+
this.handlePong(data, event);
|
|
97
|
+
return;
|
|
98
|
+
}
|
|
99
|
+
});
|
|
100
|
+
this.uniqueKey = options === null || options === void 0 ? void 0 : options.uniqueKey;
|
|
101
|
+
this.ackTimeout = (_options$ackTimeout = options === null || options === void 0 ? void 0 : options.ackTimeout) !== null && _options$ackTimeout !== void 0 ? _options$ackTimeout : _constants.DefaultTimeout.SERVER_ACK;
|
|
102
|
+
window.addEventListener('message', this.onMessage);
|
|
103
|
+
}
|
|
104
|
+
|
|
105
|
+
/**
|
|
106
|
+
* 处理请求(由子类实现)
|
|
107
|
+
*/
|
|
108
|
+
|
|
109
|
+
/**
|
|
110
|
+
* 处理客户端响应(ack、async、response、error)
|
|
111
|
+
*/
|
|
112
|
+
handleClientResponse(data, event) {
|
|
113
|
+
var pending = this.pendingClientRequests.get(data.requestId);
|
|
114
|
+
if (pending) {
|
|
115
|
+
// 验证 origin(如果指定了)
|
|
116
|
+
if (pending.origin && pending.origin !== '*' && event.origin !== pending.origin) {
|
|
117
|
+
return;
|
|
118
|
+
}
|
|
119
|
+
// 对于 ack 和 async,不删除 pending,只触发回调
|
|
120
|
+
if (data.type === _constants.MessageType.ACK || data.type === _constants.MessageType.ASYNC) {
|
|
121
|
+
pending.resolve(data);
|
|
122
|
+
return;
|
|
123
|
+
}
|
|
124
|
+
// 对于 response 和 error,删除 pending 并触发回调
|
|
125
|
+
this.pendingClientRequests.delete(data.requestId);
|
|
126
|
+
pending.resolve(data);
|
|
127
|
+
}
|
|
128
|
+
}
|
|
129
|
+
|
|
130
|
+
/**
|
|
131
|
+
* 处理客户端确认收到
|
|
132
|
+
*/
|
|
133
|
+
handleReceived(data) {
|
|
134
|
+
var pending = this.pendingAcks.get(data.requestId);
|
|
135
|
+
if (pending) {
|
|
136
|
+
clearTimeout(pending.timeoutId);
|
|
137
|
+
this.pendingAcks.delete(data.requestId);
|
|
138
|
+
pending.resolve(true);
|
|
139
|
+
}
|
|
140
|
+
}
|
|
141
|
+
|
|
142
|
+
/**
|
|
143
|
+
* 处理 ping 请求(用于 isConnect)
|
|
144
|
+
*/
|
|
145
|
+
handlePing(data, event) {
|
|
146
|
+
if (!event.source) return;
|
|
147
|
+
event.source.postMessage((0, _utils.createPostMessage)(_constants.MessageType.PONG, data.requestId, {
|
|
148
|
+
uniqueKey: data.uniqueKey
|
|
149
|
+
}), event.origin);
|
|
150
|
+
}
|
|
151
|
+
|
|
152
|
+
/**
|
|
153
|
+
* 处理 pong 响应(用于 isConnect)
|
|
154
|
+
*/
|
|
155
|
+
handlePong(data, event) {
|
|
156
|
+
var pending = this.pendingClientRequests.get(data.requestId);
|
|
157
|
+
if (pending) {
|
|
158
|
+
if (pending.origin && pending.origin !== '*' && event.origin !== pending.origin) {
|
|
159
|
+
return;
|
|
160
|
+
}
|
|
161
|
+
this.pendingClientRequests.delete(data.requestId);
|
|
162
|
+
pending.resolve(data);
|
|
163
|
+
}
|
|
164
|
+
}
|
|
165
|
+
|
|
166
|
+
/**
|
|
167
|
+
* 注册等待客户端确认的响应
|
|
168
|
+
*/
|
|
169
|
+
_registerPendingAck(requestId, resolve, reject) {
|
|
170
|
+
var timeoutId = setTimeout(() => {
|
|
171
|
+
this.pendingAcks.delete(requestId);
|
|
172
|
+
resolve(false); // 超时未收到确认,但不报错
|
|
173
|
+
}, this.ackTimeout);
|
|
174
|
+
this.pendingAcks.set(requestId, {
|
|
175
|
+
resolve,
|
|
176
|
+
reject,
|
|
177
|
+
timeoutId
|
|
178
|
+
});
|
|
179
|
+
}
|
|
180
|
+
|
|
181
|
+
/**
|
|
182
|
+
* 内部方法:监听底层事件
|
|
183
|
+
*/
|
|
184
|
+
_on(event, fn) {
|
|
185
|
+
this.listeners[event].add(fn);
|
|
186
|
+
}
|
|
187
|
+
|
|
188
|
+
/**
|
|
189
|
+
* 内部方法:取消监听底层事件
|
|
190
|
+
*/
|
|
191
|
+
_off(event, fn) {
|
|
192
|
+
if (!fn) {
|
|
193
|
+
this.listeners[event].clear();
|
|
194
|
+
return;
|
|
195
|
+
}
|
|
196
|
+
this.listeners[event].delete(fn);
|
|
197
|
+
}
|
|
198
|
+
|
|
199
|
+
/**
|
|
200
|
+
* 内部方法:供 client 注册等待响应的 Promise
|
|
201
|
+
*/
|
|
202
|
+
_registerPendingRequest(requestId, resolve, reject, origin) {
|
|
203
|
+
this.pendingClientRequests.set(requestId, {
|
|
204
|
+
resolve,
|
|
205
|
+
reject,
|
|
206
|
+
origin
|
|
207
|
+
});
|
|
208
|
+
}
|
|
209
|
+
|
|
210
|
+
/**
|
|
211
|
+
* 内部方法:供 client 取消等待
|
|
212
|
+
*/
|
|
213
|
+
_unregisterPendingRequest(requestId) {
|
|
214
|
+
this.pendingClientRequests.delete(requestId);
|
|
215
|
+
}
|
|
216
|
+
|
|
217
|
+
/**
|
|
218
|
+
* 销毁 server(移除 message 监听)
|
|
219
|
+
*/
|
|
220
|
+
destroy() {
|
|
221
|
+
window.removeEventListener('message', this.onMessage);
|
|
222
|
+
this.pendingClientRequests.clear();
|
|
223
|
+
this.pendingAcks.forEach(pending => clearTimeout(pending.timeoutId));
|
|
224
|
+
this.pendingAcks.clear();
|
|
225
|
+
Object.keys(this.listeners).forEach(k => this.listeners[k].clear());
|
|
226
|
+
}
|
|
227
|
+
emit(event, payload, messageEvent) {
|
|
228
|
+
this.listeners[event].forEach(fn => {
|
|
229
|
+
try {
|
|
230
|
+
fn(payload, messageEvent);
|
|
231
|
+
} catch (e) {
|
|
232
|
+
// 忽略监听器异常
|
|
233
|
+
}
|
|
234
|
+
});
|
|
235
|
+
}
|
|
236
|
+
prefixPath(path) {
|
|
237
|
+
return this.uniqueKey ? `${this.uniqueKey}:${path}` : path;
|
|
238
|
+
}
|
|
239
|
+
|
|
240
|
+
/**
|
|
241
|
+
* 发送协议版本不兼容错误(版本过低)
|
|
242
|
+
*/
|
|
243
|
+
sendProtocolError(data, event, remoteVersion) {
|
|
244
|
+
if (!event.source) return;
|
|
245
|
+
event.source.postMessage((0, _utils.createPostMessage)(_constants.MessageType.ERROR, data.requestId, {
|
|
246
|
+
path: data.path,
|
|
247
|
+
uniqueKey: data.uniqueKey,
|
|
248
|
+
status: _constants.HttpStatus.BAD_REQUEST,
|
|
249
|
+
statusText: _constants.Messages.PROTOCOL_VERSION_UNSUPPORTED,
|
|
250
|
+
error: {
|
|
251
|
+
message: (0, _constants.formatMessage)(_constants.Messages.PROTOCOL_VERSION_TOO_LOW, remoteVersion, _constants.ProtocolVersion.MIN_SUPPORTED),
|
|
252
|
+
code: _constants.ErrorCode.PROTOCOL_UNSUPPORTED
|
|
253
|
+
}
|
|
254
|
+
}), event.origin);
|
|
255
|
+
}
|
|
256
|
+
}
|
|
257
|
+
exports.RequestIframeBaseServer = RequestIframeBaseServer;
|