request-iframe 0.0.2 → 0.0.4

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (84) hide show
  1. package/QUICKSTART.CN.md +35 -8
  2. package/QUICKSTART.md +35 -8
  3. package/README.CN.md +439 -36
  4. package/README.md +496 -30
  5. package/library/__tests__/channel.test.ts +420 -0
  6. package/library/__tests__/coverage-branches.test.ts +356 -0
  7. package/library/__tests__/debug.test.ts +588 -0
  8. package/library/__tests__/dispatcher.test.ts +481 -0
  9. package/library/__tests__/requestIframe.test.ts +3163 -185
  10. package/library/__tests__/server.test.ts +738 -0
  11. package/library/__tests__/stream.test.ts +46 -15
  12. package/library/api/client.d.ts.map +1 -1
  13. package/library/api/client.js +12 -6
  14. package/library/api/server.d.ts +4 -3
  15. package/library/api/server.d.ts.map +1 -1
  16. package/library/api/server.js +25 -7
  17. package/library/constants/index.d.ts +14 -4
  18. package/library/constants/index.d.ts.map +1 -1
  19. package/library/constants/index.js +15 -7
  20. package/library/constants/messages.d.ts +37 -0
  21. package/library/constants/messages.d.ts.map +1 -1
  22. package/library/constants/messages.js +38 -1
  23. package/library/core/client-server.d.ts +105 -0
  24. package/library/core/client-server.d.ts.map +1 -0
  25. package/library/core/client-server.js +289 -0
  26. package/library/core/client.d.ts +53 -10
  27. package/library/core/client.d.ts.map +1 -1
  28. package/library/core/client.js +529 -207
  29. package/library/core/request.d.ts +3 -1
  30. package/library/core/request.d.ts.map +1 -1
  31. package/library/core/request.js +2 -1
  32. package/library/core/response.d.ts +30 -4
  33. package/library/core/response.d.ts.map +1 -1
  34. package/library/core/response.js +176 -100
  35. package/library/core/server-client.d.ts +3 -1
  36. package/library/core/server-client.d.ts.map +1 -1
  37. package/library/core/server-client.js +19 -9
  38. package/library/core/server.d.ts +22 -1
  39. package/library/core/server.d.ts.map +1 -1
  40. package/library/core/server.js +304 -55
  41. package/library/index.d.ts +3 -2
  42. package/library/index.d.ts.map +1 -1
  43. package/library/index.js +34 -5
  44. package/library/interceptors/index.d.ts.map +1 -1
  45. package/library/message/channel.d.ts +3 -1
  46. package/library/message/channel.d.ts.map +1 -1
  47. package/library/message/dispatcher.d.ts +7 -2
  48. package/library/message/dispatcher.d.ts.map +1 -1
  49. package/library/message/dispatcher.js +48 -2
  50. package/library/message/index.d.ts.map +1 -1
  51. package/library/stream/file-stream.d.ts +5 -0
  52. package/library/stream/file-stream.d.ts.map +1 -1
  53. package/library/stream/file-stream.js +41 -12
  54. package/library/stream/index.d.ts +11 -1
  55. package/library/stream/index.d.ts.map +1 -1
  56. package/library/stream/index.js +21 -3
  57. package/library/stream/readable-stream.d.ts.map +1 -1
  58. package/library/stream/readable-stream.js +32 -30
  59. package/library/stream/types.d.ts +20 -2
  60. package/library/stream/types.d.ts.map +1 -1
  61. package/library/stream/writable-stream.d.ts +2 -1
  62. package/library/stream/writable-stream.d.ts.map +1 -1
  63. package/library/stream/writable-stream.js +13 -10
  64. package/library/types/index.d.ts +106 -32
  65. package/library/types/index.d.ts.map +1 -1
  66. package/library/utils/cache.d.ts +24 -0
  67. package/library/utils/cache.d.ts.map +1 -1
  68. package/library/utils/cache.js +76 -0
  69. package/library/utils/cookie.d.ts.map +1 -1
  70. package/library/utils/debug.d.ts.map +1 -1
  71. package/library/utils/debug.js +382 -20
  72. package/library/utils/index.d.ts +19 -0
  73. package/library/utils/index.d.ts.map +1 -1
  74. package/library/utils/index.js +113 -2
  75. package/library/utils/path-match.d.ts +16 -0
  76. package/library/utils/path-match.d.ts.map +1 -1
  77. package/library/utils/path-match.js +65 -0
  78. package/library/utils/protocol.d.ts.map +1 -1
  79. package/package.json +4 -1
  80. package/react/library/__tests__/index.test.tsx +274 -281
  81. package/react/library/index.d.ts +4 -3
  82. package/react/library/index.d.ts.map +1 -1
  83. package/react/library/index.js +225 -158
  84. package/react/package.json +7 -0
@@ -6,7 +6,7 @@ require("core-js/modules/es.array.from.js");
6
6
  require("core-js/modules/es.array.slice.js");
7
7
  require("core-js/modules/es.object.get-own-property-descriptors.js");
8
8
  require("core-js/modules/es.regexp.to-string.js");
9
- require("core-js/modules/web.dom-collections.for-each.js");
9
+ require("core-js/modules/es.weak-map.js");
10
10
  var _interopRequireDefault = require("@babel/runtime/helpers/interopRequireDefault");
11
11
  Object.defineProperty(exports, "__esModule", {
12
12
  value: true
@@ -15,12 +15,16 @@ exports.RequestIframeClientImpl = void 0;
15
15
  var _regenerator = _interopRequireDefault(require("@babel/runtime/regenerator"));
16
16
  require("core-js/modules/es.array.iterator.js");
17
17
  require("core-js/modules/es.map.js");
18
+ require("core-js/modules/es.object.entries.js");
18
19
  require("core-js/modules/es.promise.js");
19
20
  require("core-js/modules/es.regexp.exec.js");
21
+ require("core-js/modules/es.string.match.js");
20
22
  require("core-js/modules/es.string.replace.js");
21
23
  require("core-js/modules/es.string.starts-with.js");
24
+ require("core-js/modules/web.dom-collections.for-each.js");
22
25
  require("core-js/modules/web.dom-collections.iterator.js");
23
26
  var _asyncToGenerator2 = _interopRequireDefault(require("@babel/runtime/helpers/asyncToGenerator"));
27
+ var _slicedToArray2 = _interopRequireDefault(require("@babel/runtime/helpers/slicedToArray"));
24
28
  var _defineProperty2 = _interopRequireDefault(require("@babel/runtime/helpers/defineProperty"));
25
29
  var _utils = require("../utils");
26
30
  var _interceptors = require("../interceptors");
@@ -29,6 +33,7 @@ var _stream = require("../stream");
29
33
  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; } } }; }
30
34
  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; } }
31
35
  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; }
36
+ function _interopRequireWildcard(e, t) { if ("function" == typeof WeakMap) var r = new WeakMap(), n = new WeakMap(); return (_interopRequireWildcard = function _interopRequireWildcard(e, t) { if (!t && e && e.__esModule) return e; var o, i, f = { __proto__: null, default: e }; if (null === e || "object" != typeof e && "function" != typeof e) return f; if (o = t ? n : r) { if (o.has(e)) return o.get(e); o.set(e, f); } for (var _t2 in e) "default" !== _t2 && {}.hasOwnProperty.call(e, _t2) && ((i = (o = Object.defineProperty) && Object.getOwnPropertyDescriptor(e, _t2)) && (i.get || i.set) ? o(f, _t2, i) : f[_t2] = e[_t2]); return f; })(e, t); }
32
37
  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; }
33
38
  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; }
34
39
  /**
@@ -39,8 +44,14 @@ function _objectSpread(e) { for (var r = 1; r < arguments.length; r++) { var t =
39
44
  * RequestIframeClient implementation (only responsible for initiating requests, reuses server's listener)
40
45
  */
41
46
  class RequestIframeClientImpl {
42
- constructor(targetWindow, targetOrigin, server, options) {
43
- var _options$ackTimeout, _options$timeout, _options$asyncTimeout;
47
+ /**
48
+ * Target server ID (remembered from responses)
49
+ * When a response is received, we remember the server's creatorId as the targetId for future requests
50
+ */
51
+
52
+ constructor(targetWindow, targetOrigin, server, options, instanceId) {
53
+ var _options$ackTimeout, _options$timeout, _options$asyncTimeout, _options$returnData;
54
+ /** Unique instance ID */
44
55
  (0, _defineProperty2.default)(this, "interceptors", {
45
56
  request: new _interceptors.RequestInterceptorManager(),
46
57
  response: new _interceptors.ResponseInterceptorManager()
@@ -57,6 +68,7 @@ class RequestIframeClientImpl {
57
68
  * value: stream message handler function
58
69
  */
59
70
  (0, _defineProperty2.default)(this, "streamHandlers", new Map());
71
+ this.id = instanceId || (0, _utils.generateInstanceId)();
60
72
  this.targetWindow = targetWindow;
61
73
  this.targetOrigin = targetOrigin;
62
74
  this.server = server;
@@ -67,6 +79,12 @@ class RequestIframeClientImpl {
67
79
  this.defaultTimeout = (_options$timeout = options === null || options === void 0 ? void 0 : options.timeout) !== null && _options$timeout !== void 0 ? _options$timeout : _constants.DefaultTimeout.REQUEST;
68
80
  this.defaultAsyncTimeout = (_options$asyncTimeout = options === null || options === void 0 ? void 0 : options.asyncTimeout) !== null && _options$asyncTimeout !== void 0 ? _options$asyncTimeout : _constants.DefaultTimeout.ASYNC;
69
81
 
82
+ // Set default returnData configuration
83
+ this.defaultReturnData = (_options$returnData = options === null || options === void 0 ? void 0 : options.returnData) !== null && _options$returnData !== void 0 ? _options$returnData : false;
84
+
85
+ // Save initial headers configuration
86
+ this.initialHeaders = options === null || options === void 0 ? void 0 : options.headers;
87
+
70
88
  // Register stream message processing callback
71
89
  this.server.setStreamCallback(data => {
72
90
  this.dispatchStreamMessage(data);
@@ -87,8 +105,8 @@ class RequestIframeClientImpl {
87
105
  this.streamHandlers.delete(streamId);
88
106
  }
89
107
 
90
- /**
91
- * Send message (StreamMessageHandler interface implementation)
108
+ /*
109
+ Send message (StreamMessageHandler interface implementation)
92
110
  */
93
111
  postMessage(message) {
94
112
  this.server.messageDispatcher.send(this.targetWindow, message, this.targetOrigin);
@@ -110,6 +128,71 @@ class RequestIframeClientImpl {
110
128
  }
111
129
  }
112
130
 
131
+ /**
132
+ * Resolve header value (handle function type headers)
133
+ */
134
+ resolveHeaderValue(value, config) {
135
+ if (typeof value === 'function') {
136
+ return value(config);
137
+ }
138
+ return value;
139
+ }
140
+
141
+ /**
142
+ * Detect Content-Type for request body
143
+ */
144
+ detectContentTypeForBody(body) {
145
+ return (0, _utils.detectContentType)(body, {
146
+ checkStream: false
147
+ });
148
+ }
149
+
150
+ /**
151
+ * Check if header exists (case-insensitive)
152
+ */
153
+ hasHeader(headers, name) {
154
+ var lower = name.toLowerCase();
155
+ return Object.keys(headers).some(k => k.toLowerCase() === lower);
156
+ }
157
+
158
+ /**
159
+ * Merge and resolve headers (initial headers + request headers)
160
+ * Request headers take precedence over initial headers
161
+ * Also auto-detects and sets Content-Type if not already set
162
+ */
163
+ mergeHeaders(config, body) {
164
+ var resolvedHeaders = {};
165
+
166
+ // First, resolve initial headers
167
+ if (this.initialHeaders) {
168
+ for (var _i = 0, _Object$entries = Object.entries(this.initialHeaders); _i < _Object$entries.length; _i++) {
169
+ var _Object$entries$_i = (0, _slicedToArray2.default)(_Object$entries[_i], 2),
170
+ key = _Object$entries$_i[0],
171
+ value = _Object$entries$_i[1];
172
+ resolvedHeaders[key] = this.resolveHeaderValue(value, config);
173
+ }
174
+ }
175
+
176
+ // Then, merge request headers (request headers take precedence)
177
+ if (config.headers) {
178
+ for (var _i2 = 0, _Object$entries2 = Object.entries(config.headers); _i2 < _Object$entries2.length; _i2++) {
179
+ var _Object$entries2$_i = (0, _slicedToArray2.default)(_Object$entries2[_i2], 2),
180
+ _key = _Object$entries2$_i[0],
181
+ _value = _Object$entries2$_i[1];
182
+ resolvedHeaders[_key] = this.resolveHeaderValue(_value, config);
183
+ }
184
+ }
185
+
186
+ // Auto-detect and set Content-Type if not already set and body is provided
187
+ if (body !== undefined && !this.hasHeader(resolvedHeaders, _constants.HttpHeader.CONTENT_TYPE)) {
188
+ var contentType = this.detectContentTypeForBody(body);
189
+ if (contentType) {
190
+ resolvedHeaders[_constants.HttpHeader.CONTENT_TYPE] = contentType;
191
+ }
192
+ }
193
+ return resolvedHeaders;
194
+ }
195
+
113
196
  /**
114
197
  * Check if server is reachable
115
198
  */
@@ -149,7 +232,7 @@ class RequestIframeClientImpl {
149
232
  send(path, body, options) {
150
233
  var _this = this;
151
234
  return (0, _asyncToGenerator2.default)(/*#__PURE__*/_regenerator.default.mark(function _callee() {
152
- var config, processedConfig, processedPath, processedBody, processedHeaders, processedCookies, _processedConfig$ackT, ackTimeout, _processedConfig$time, timeout, _processedConfig$asyn, asyncTimeout, _processedConfig$requ, requestId;
235
+ var config, processedConfig, processedBody, mergedHeaders, processedPath, processedCookies, userTargetId, _processedConfig$requ, requestId, targetId;
153
236
  return _regenerator.default.wrap(function (_context) {
154
237
  while (1) switch (_context.prev = _context.next) {
155
238
  case 0:
@@ -161,217 +244,456 @@ class RequestIframeClientImpl {
161
244
  return (0, _interceptors.runRequestInterceptors)(_this.interceptors.request, config);
162
245
  case 1:
163
246
  processedConfig = _context.sent;
164
- processedPath = processedConfig.path, processedBody = processedConfig.body, processedHeaders = processedConfig.headers, processedCookies = processedConfig.cookies, _processedConfig$ackT = processedConfig.ackTimeout, ackTimeout = _processedConfig$ackT === void 0 ? _this.defaultAckTimeout : _processedConfig$ackT, _processedConfig$time = processedConfig.timeout, timeout = _processedConfig$time === void 0 ? _this.defaultTimeout : _processedConfig$time, _processedConfig$asyn = processedConfig.asyncTimeout, asyncTimeout = _processedConfig$asyn === void 0 ? _this.defaultAsyncTimeout : _processedConfig$asyn, _processedConfig$requ = processedConfig.requestId, requestId = _processedConfig$requ === void 0 ? (0, _utils.generateRequestId)() : _processedConfig$requ;
165
- return _context.abrupt("return", new Promise((resolve, reject) => {
166
- var prefixedPath = _this.prefixPath(processedPath);
167
- var done = false;
168
- var timeoutId = null;
169
- var cleanup = () => {
170
- if (timeoutId) clearTimeout(timeoutId);
171
- _this.server._unregisterPendingRequest(requestId);
172
- };
173
- var fail = error => {
174
- if (done) return;
175
- done = true;
176
- cleanup();
177
- reject(error);
178
- };
179
- var setAckTimeout = () => {
180
- if (timeoutId) clearTimeout(timeoutId);
181
- timeoutId = setTimeout(() => {
182
- fail({
183
- message: (0, _constants.formatMessage)(_constants.Messages.ACK_TIMEOUT, ackTimeout),
184
- code: _constants.ErrorCode.ACK_TIMEOUT,
185
- config: processedConfig,
186
- requestId
187
- });
188
- }, ackTimeout);
189
- };
190
- var setRequestTimeout = () => {
191
- if (timeoutId) clearTimeout(timeoutId);
192
- timeoutId = setTimeout(() => {
193
- fail({
194
- message: (0, _constants.formatMessage)(_constants.Messages.REQUEST_TIMEOUT, timeout),
195
- code: _constants.ErrorCode.TIMEOUT,
196
- config: processedConfig,
197
- requestId
198
- });
199
- }, timeout);
200
- };
201
- var setAsyncTimeout = () => {
202
- if (timeoutId) clearTimeout(timeoutId);
203
- timeoutId = setTimeout(() => {
204
- fail({
205
- message: (0, _constants.formatMessage)(_constants.Messages.ASYNC_REQUEST_TIMEOUT, asyncTimeout),
206
- code: _constants.ErrorCode.ASYNC_TIMEOUT,
207
- config: processedConfig,
208
- requestId
209
- });
210
- }, asyncTimeout);
211
- };
212
-
213
- // Register to server's pending requests
214
- _this.server._registerPendingRequest(requestId, data => {
215
- if (done) return;
216
-
217
- // Received ACK: server has received request
218
- if (data.type === _constants.MessageType.ACK) {
219
- // Switch to request timeout
220
- setRequestTimeout();
221
- return;
222
- }
223
-
224
- // Received ASYNC notification: this is an async task
225
- if (data.type === _constants.MessageType.ASYNC) {
226
- // Switch to async timeout
227
- setAsyncTimeout();
228
- return;
229
- }
230
-
231
- // Received stream start message
232
- if (data.type === _constants.MessageType.STREAM_START) {
233
- var _streamBody$chunked;
234
- done = true;
235
- cleanup();
236
- var streamBody = data.body;
237
- var streamId = streamBody.streamId;
238
- var streamType = streamBody.type || _constants.StreamType.DATA;
239
- var streamChunked = (_streamBody$chunked = streamBody.chunked) !== null && _streamBody$chunked !== void 0 ? _streamBody$chunked : true;
240
- var streamMetadata = streamBody.metadata;
241
-
242
- // Create corresponding readable stream based on stream type
243
- var readableStream;
244
- if (streamType === _constants.StreamType.FILE) {
245
- readableStream = new _stream.IframeFileReadableStream(streamId, requestId, _this, {
246
- chunked: streamChunked,
247
- metadata: streamMetadata,
248
- filename: streamMetadata === null || streamMetadata === void 0 ? void 0 : streamMetadata.filename,
249
- mimeType: streamMetadata === null || streamMetadata === void 0 ? void 0 : streamMetadata.mimeType,
250
- size: streamMetadata === null || streamMetadata === void 0 ? void 0 : streamMetadata.size
251
- });
252
- } else {
253
- readableStream = new _stream.IframeReadableStream(streamId, requestId, _this, {
254
- type: streamType,
255
- chunked: streamChunked,
256
- metadata: streamMetadata
257
- });
258
- }
259
- var resp = {
260
- data: undefined,
261
- status: data.status || _constants.HttpStatus.OK,
262
- statusText: data.statusText || _constants.HttpStatusText[_constants.HttpStatus.OK],
263
- requestId,
264
- headers: data.headers,
265
- stream: readableStream
266
- };
267
- (0, _interceptors.runResponseInterceptors)(_this.interceptors.response, resp).then(resolve).catch(reject);
268
- return;
269
- }
270
-
271
- // Received stream data/end/error/cancel message - dispatch to stream handler
272
- if (data.type.startsWith('stream_')) {
273
- _this.dispatchStreamMessage(data);
274
- return;
275
- }
247
+ processedBody = processedConfig.body; // Universal send: dispatch by type (like response.send)
248
+ if (!(typeof File !== 'undefined' && processedBody instanceof File || typeof Blob !== 'undefined' && processedBody instanceof Blob)) {
249
+ _context.next = 2;
250
+ break;
251
+ }
252
+ return _context.abrupt("return", _this.sendFile(path, processedBody, options));
253
+ case 2:
254
+ if (!(0, _stream.isIframeWritableStream)(processedBody)) {
255
+ _context.next = 3;
256
+ break;
257
+ }
258
+ return _context.abrupt("return", _this.sendStream(path, processedBody, options));
259
+ case 3:
260
+ // Merge and resolve headers (initial headers + request headers)
261
+ mergedHeaders = _this.mergeHeaders(processedConfig, processedBody);
262
+ processedPath = processedConfig.path, processedCookies = processedConfig.cookies, userTargetId = processedConfig.targetId, _processedConfig$requ = processedConfig.requestId, requestId = _processedConfig$requ === void 0 ? (0, _utils.generateRequestId)() : _processedConfig$requ;
263
+ targetId = userTargetId || _this._targetServerId;
264
+ return _context.abrupt("return", _this._sendRequest(processedPath, processedBody, mergedHeaders, processedCookies, processedConfig, requestId, targetId));
265
+ case 4:
266
+ case "end":
267
+ return _context.stop();
268
+ }
269
+ }, _callee);
270
+ }))();
271
+ }
276
272
 
277
- // Received response
278
- if (data.type === _constants.MessageType.RESPONSE) {
279
- done = true;
280
- cleanup();
281
-
282
- // If server requires acknowledgment, send received message
283
- if (data.requireAck) {
284
- _this.server.messageDispatcher.sendMessage(_this.targetWindow, _this.targetOrigin, _constants.MessageType.RECEIVED, requestId, {
285
- path: prefixedPath
286
- });
287
- }
288
-
289
- // Parse and save server-set cookies (from Set-Cookie header)
290
- if (data.headers && data.headers[_constants.HttpHeader.SET_COOKIE]) {
291
- var setCookies = data.headers[_constants.HttpHeader.SET_COOKIE];
292
- var setCookieArray = Array.isArray(setCookies) ? setCookies : [setCookies];
293
- var _iterator = _createForOfIteratorHelper(setCookieArray),
294
- _step;
295
- try {
296
- for (_iterator.s(); !(_step = _iterator.n()).done;) {
297
- var setCookieStr = _step.value;
298
- _this._cookieStore.setFromSetCookie(setCookieStr);
299
- }
300
- } catch (err) {
301
- _iterator.e(err);
302
- } finally {
303
- _iterator.f();
273
+ /**
274
+ * Send file as request body (stream only; server receives stream or auto-resolved File/Blob via autoResolve).
275
+ */
276
+ sendFile(path, content, options) {
277
+ var _this2 = this;
278
+ return (0, _asyncToGenerator2.default)(/*#__PURE__*/_regenerator.default.mark(function _callee3() {
279
+ var _options$autoResolve;
280
+ var streamAutoResolve, mimeType, fileName, _yield$import, IframeFileWritableStream, fileStream;
281
+ return _regenerator.default.wrap(function (_context3) {
282
+ while (1) switch (_context3.prev = _context3.next) {
283
+ case 0:
284
+ streamAutoResolve = (_options$autoResolve = options === null || options === void 0 ? void 0 : options.autoResolve) !== null && _options$autoResolve !== void 0 ? _options$autoResolve : true;
285
+ mimeType = options === null || options === void 0 ? void 0 : options.mimeType;
286
+ fileName = options === null || options === void 0 ? void 0 : options.fileName;
287
+ _context3.next = 1;
288
+ return Promise.resolve().then(() => _interopRequireWildcard(require('../stream')));
289
+ case 1:
290
+ _yield$import = _context3.sent;
291
+ IframeFileWritableStream = _yield$import.IframeFileWritableStream;
292
+ fileStream = new IframeFileWritableStream({
293
+ filename: fileName || (typeof File !== 'undefined' && content instanceof File ? content.name : 'file'),
294
+ mimeType: mimeType || (typeof File !== 'undefined' && content instanceof File ? content.type : content === null || content === void 0 ? void 0 : content.type) || 'application/octet-stream',
295
+ chunked: false,
296
+ autoResolve: streamAutoResolve,
297
+ next: function () {
298
+ var _next = (0, _asyncToGenerator2.default)(/*#__PURE__*/_regenerator.default.mark(function _callee2() {
299
+ var data, _t;
300
+ return _regenerator.default.wrap(function (_context2) {
301
+ while (1) switch (_context2.prev = _context2.next) {
302
+ case 0:
303
+ if (!(typeof content === 'string')) {
304
+ _context2.next = 1;
305
+ break;
306
+ }
307
+ _t = btoa(unescape(encodeURIComponent(content)));
308
+ _context2.next = 3;
309
+ break;
310
+ case 1:
311
+ _context2.next = 2;
312
+ return (0, _utils.blobToBase64)(content);
313
+ case 2:
314
+ _t = _context2.sent;
315
+ case 3:
316
+ data = _t;
317
+ return _context2.abrupt("return", {
318
+ data,
319
+ done: true
320
+ });
321
+ case 4:
322
+ case "end":
323
+ return _context2.stop();
304
324
  }
305
- }
306
- var _resp = {
307
- data: data.data,
308
- status: data.status || _constants.HttpStatus.OK,
309
- statusText: data.statusText || _constants.HttpStatusText[_constants.HttpStatus.OK],
310
- requestId,
311
- headers: data.headers,
312
- fileData: data.fileData
313
- };
314
- (0, _interceptors.runResponseInterceptors)(_this.interceptors.response, _resp).then(resolve).catch(reject);
315
- return;
325
+ }, _callee2);
326
+ }));
327
+ function next() {
328
+ return _next.apply(this, arguments);
316
329
  }
317
-
318
- // Received error
319
- if (data.type === _constants.MessageType.ERROR) {
320
- var _data$error, _data$error2;
321
- // If server requires acknowledgment, send received message
322
- if (data.requireAck) {
323
- _this.server.messageDispatcher.sendMessage(_this.targetWindow, _this.targetOrigin, _constants.MessageType.RECEIVED, requestId, {
324
- path: prefixedPath
325
- });
326
- }
327
- var err = {
328
- message: ((_data$error = data.error) === null || _data$error === void 0 ? void 0 : _data$error.message) || _constants.Messages.REQUEST_FAILED,
329
- code: ((_data$error2 = data.error) === null || _data$error2 === void 0 ? void 0 : _data$error2.code) || _constants.ErrorCode.REQUEST_ERROR,
330
- config: processedConfig,
331
- response: data.status ? {
332
- data: data.data,
333
- status: data.status,
334
- statusText: data.statusText || _constants.Messages.ERROR
335
- } : undefined,
336
- requestId
337
- };
338
- fail(err);
339
- }
340
- }, error => {
341
- fail({
342
- message: error.message || _constants.Messages.REQUEST_FAILED,
343
- code: _constants.ErrorCode.REQUEST_ERROR,
344
- config: processedConfig,
345
- requestId
346
- });
347
- }, _this.targetOrigin);
348
-
349
- // Set ACK timeout
350
- setAckTimeout();
351
-
352
- // Get cookies matching request path and merge with user-provided cookies (user-provided takes precedence)
353
- var pathMatchedCookies = _this._cookieStore.getForPath(processedPath);
354
- var mergedCookies = _objectSpread(_objectSpread({}, pathMatchedCookies), processedCookies);
355
-
356
- // Send request via MessageDispatcher
357
- _this.server.messageDispatcher.sendMessage(_this.targetWindow, _this.targetOrigin, _constants.MessageType.REQUEST, requestId, {
358
- path: prefixedPath,
359
- body: processedBody,
360
- headers: processedHeaders,
361
- cookies: mergedCookies
362
- });
363
- }));
330
+ return next;
331
+ }()
332
+ });
333
+ return _context3.abrupt("return", _this2.sendStream(path, fileStream, options));
364
334
  case 2:
365
335
  case "end":
366
- return _context.stop();
336
+ return _context3.stop();
367
337
  }
368
- }, _callee);
338
+ }, _callee3);
369
339
  }))();
370
340
  }
371
- prefixPath(path) {
372
- return this.secretKey ? `${this.secretKey}:${path}` : path;
341
+
342
+ /**
343
+ * Send stream as request body (server receives readable stream).
344
+ * Sends REQUEST with streamId and stream: true, then starts the writable stream.
345
+ */
346
+ sendStream(path, stream, options) {
347
+ var _this3 = this;
348
+ return (0, _asyncToGenerator2.default)(/*#__PURE__*/_regenerator.default.mark(function _callee4() {
349
+ var _processedConfig$requ2, _processedConfig$targ;
350
+ var config, processedConfig, requestId, targetId, processedPath, mergedHeaders, pathMatchedCookies, mergedCookies, streamConfig, promise;
351
+ return _regenerator.default.wrap(function (_context4) {
352
+ while (1) switch (_context4.prev = _context4.next) {
353
+ case 0:
354
+ config = _objectSpread({
355
+ path,
356
+ body: undefined
357
+ }, options);
358
+ _context4.next = 1;
359
+ return (0, _interceptors.runRequestInterceptors)(_this3.interceptors.request, config);
360
+ case 1:
361
+ processedConfig = _context4.sent;
362
+ requestId = (_processedConfig$requ2 = processedConfig.requestId) !== null && _processedConfig$requ2 !== void 0 ? _processedConfig$requ2 : (0, _utils.generateRequestId)();
363
+ targetId = (_processedConfig$targ = processedConfig.targetId) !== null && _processedConfig$targ !== void 0 ? _processedConfig$targ : _this3._targetServerId;
364
+ processedPath = processedConfig.path;
365
+ stream._bind({
366
+ requestId,
367
+ targetWindow: _this3.targetWindow,
368
+ targetOrigin: _this3.targetOrigin,
369
+ secretKey: _this3.secretKey,
370
+ channel: _this3.server.messageDispatcher.getChannel(),
371
+ clientId: _this3.id,
372
+ targetId
373
+ });
374
+ mergedHeaders = _this3.mergeHeaders(processedConfig, undefined);
375
+ pathMatchedCookies = _this3._cookieStore.getForPath(processedPath);
376
+ mergedCookies = _objectSpread(_objectSpread({}, pathMatchedCookies), processedConfig.cookies);
377
+ streamConfig = _objectSpread(_objectSpread({}, processedConfig), {}, {
378
+ requestId
379
+ });
380
+ promise = _this3._sendRequest(processedPath, undefined, mergedHeaders, mergedCookies, streamConfig, requestId, targetId, {
381
+ streamId: stream.streamId
382
+ });
383
+ /** Start stream after REQUEST is sent (_sendRequest sends synchronously in executor) */
384
+ void stream.start();
385
+ return _context4.abrupt("return", promise);
386
+ case 2:
387
+ case "end":
388
+ return _context4.stop();
389
+ }
390
+ }, _callee4);
391
+ }))();
373
392
  }
374
393
 
394
+ /**
395
+ * Internal: send REQUEST and wait for response (used by send, sendFile, sendStream).
396
+ */
397
+ _sendRequest(requestPath, body, mergedHeaders, processedCookies, processedConfig, requestId, targetId, extraPayload) {
398
+ var _processedConfig$ackT = processedConfig.ackTimeout,
399
+ ackTimeout = _processedConfig$ackT === void 0 ? this.defaultAckTimeout : _processedConfig$ackT,
400
+ _processedConfig$time = processedConfig.timeout,
401
+ timeout = _processedConfig$time === void 0 ? this.defaultTimeout : _processedConfig$time,
402
+ _processedConfig$asyn = processedConfig.asyncTimeout,
403
+ asyncTimeout = _processedConfig$asyn === void 0 ? this.defaultAsyncTimeout : _processedConfig$asyn,
404
+ _processedConfig$retu = processedConfig.returnData,
405
+ returnData = _processedConfig$retu === void 0 ? this.defaultReturnData : _processedConfig$retu;
406
+ return new Promise((resolve, reject) => {
407
+ var done = false;
408
+ var timeoutId = null;
409
+ var cleanup = () => {
410
+ if (timeoutId) clearTimeout(timeoutId);
411
+ this.server._unregisterPendingRequest(requestId);
412
+ };
413
+ var fail = error => {
414
+ if (done) return;
415
+ done = true;
416
+ cleanup();
417
+ // Run response interceptors to allow error logging
418
+ Promise.reject(error).catch(err => {
419
+ // Run through response interceptors' rejected callbacks
420
+ var promise = Promise.reject(err);
421
+ this.interceptors.response.forEach(interceptor => {
422
+ promise = promise.catch(e => {
423
+ if (interceptor.rejected) {
424
+ return interceptor.rejected(e);
425
+ }
426
+ return Promise.reject(e);
427
+ });
428
+ });
429
+ return promise;
430
+ }).catch(() => {
431
+ // After interceptors, reject with original error
432
+ reject(error);
433
+ });
434
+ };
435
+ var setAckTimeout = () => {
436
+ if (timeoutId) clearTimeout(timeoutId);
437
+ timeoutId = setTimeout(() => {
438
+ fail({
439
+ message: (0, _constants.formatMessage)(_constants.Messages.ACK_TIMEOUT, ackTimeout),
440
+ code: _constants.ErrorCode.ACK_TIMEOUT,
441
+ config: processedConfig,
442
+ requestId
443
+ });
444
+ }, ackTimeout);
445
+ };
446
+ var setRequestTimeout = () => {
447
+ if (timeoutId) clearTimeout(timeoutId);
448
+ timeoutId = setTimeout(() => {
449
+ fail({
450
+ message: (0, _constants.formatMessage)(_constants.Messages.REQUEST_TIMEOUT, timeout),
451
+ code: _constants.ErrorCode.TIMEOUT,
452
+ config: processedConfig,
453
+ requestId
454
+ });
455
+ }, timeout);
456
+ };
457
+ var setAsyncTimeout = () => {
458
+ if (timeoutId) clearTimeout(timeoutId);
459
+ timeoutId = setTimeout(() => {
460
+ fail({
461
+ message: (0, _constants.formatMessage)(_constants.Messages.ASYNC_REQUEST_TIMEOUT, asyncTimeout),
462
+ code: _constants.ErrorCode.ASYNC_TIMEOUT,
463
+ config: processedConfig,
464
+ requestId
465
+ });
466
+ }, asyncTimeout);
467
+ };
468
+
469
+ // Register to server's pending requests
470
+ this.server._registerPendingRequest(requestId, data => {
471
+ if (done) return;
472
+
473
+ // Received ACK: server has received request
474
+ if (data.type === _constants.MessageType.ACK) {
475
+ // Remember server's creatorId as target server ID for future requests
476
+ if (data.creatorId && !this._targetServerId) {
477
+ this._targetServerId = data.creatorId;
478
+ }
479
+ // Switch to request timeout
480
+ setRequestTimeout();
481
+ return;
482
+ }
483
+
484
+ // Received ASYNC notification: this is an async task
485
+ if (data.type === _constants.MessageType.ASYNC) {
486
+ // Remember server's creatorId as target server ID for future requests
487
+ if (data.creatorId && !this._targetServerId) {
488
+ this._targetServerId = data.creatorId;
489
+ }
490
+ // Switch to async timeout
491
+ setAsyncTimeout();
492
+ return;
493
+ }
494
+
495
+ // Received stream start message
496
+ if (data.type === _constants.MessageType.STREAM_START) {
497
+ var _streamBody$chunked, _streamBody$autoResol;
498
+ done = true;
499
+ cleanup();
500
+ var streamBody = data.body;
501
+ var streamId = streamBody.streamId;
502
+ var streamType = streamBody.type || _constants.StreamType.DATA;
503
+ var streamChunked = (_streamBody$chunked = streamBody.chunked) !== null && _streamBody$chunked !== void 0 ? _streamBody$chunked : true;
504
+ var streamMetadata = streamBody.metadata;
505
+ var autoResolve = (_streamBody$autoResol = streamBody.autoResolve) !== null && _streamBody$autoResol !== void 0 ? _streamBody$autoResol : false;
506
+
507
+ // Create corresponding readable stream based on stream type
508
+ if (streamType === _constants.StreamType.FILE) {
509
+ var _readableStream = new _stream.IframeFileReadableStream(streamId, requestId, this, {
510
+ chunked: streamChunked,
511
+ metadata: streamMetadata,
512
+ filename: streamMetadata === null || streamMetadata === void 0 ? void 0 : streamMetadata.filename,
513
+ mimeType: streamMetadata === null || streamMetadata === void 0 ? void 0 : streamMetadata.mimeType,
514
+ size: streamMetadata === null || streamMetadata === void 0 ? void 0 : streamMetadata.size
515
+ });
516
+
517
+ // If autoResolve is enabled, automatically read and convert to File/Blob
518
+ if (autoResolve) {
519
+ var _data$headers;
520
+ // Extract fileName from headers if available
521
+ var contentDisposition = (_data$headers = data.headers) === null || _data$headers === void 0 ? void 0 : _data$headers[_constants.HttpHeader.CONTENT_DISPOSITION];
522
+ var fileName;
523
+ if (contentDisposition) {
524
+ var disposition = typeof contentDisposition === 'string' ? contentDisposition : contentDisposition[0];
525
+ var filenameMatch = disposition.match(/filename="?([^"]+)"?/i);
526
+ if (filenameMatch) {
527
+ fileName = filenameMatch[1];
528
+ }
529
+ }
530
+ // Fallback to stream metadata if not found in headers
531
+ fileName = fileName || (streamMetadata === null || streamMetadata === void 0 ? void 0 : streamMetadata.filename) || _readableStream.filename;
532
+
533
+ // Use stream's readAsFile or readAsBlob method
534
+ var fileDataPromise = fileName ? _readableStream.readAsFile(fileName) : _readableStream.readAsBlob();
535
+ fileDataPromise.then(fileData => {
536
+ var resp = {
537
+ data: fileData,
538
+ status: data.status || _constants.HttpStatus.OK,
539
+ statusText: data.statusText || _constants.HttpStatusText[_constants.HttpStatus.OK],
540
+ requestId,
541
+ headers: data.headers
542
+ };
543
+ return (0, _interceptors.runResponseInterceptors)(this.interceptors.response, resp);
544
+ }).then(response => {
545
+ resolve(returnData ? response.data : response);
546
+ }).catch(reject);
547
+ return;
548
+ }
549
+
550
+ // Non-autoResolve: return file stream directly
551
+ var _resp = {
552
+ data: undefined,
553
+ status: data.status || _constants.HttpStatus.OK,
554
+ statusText: data.statusText || _constants.HttpStatusText[_constants.HttpStatus.OK],
555
+ requestId,
556
+ headers: data.headers,
557
+ stream: _readableStream
558
+ };
559
+ (0, _interceptors.runResponseInterceptors)(this.interceptors.response, _resp).then(response => {
560
+ resolve(returnData ? response.data : response);
561
+ }).catch(reject);
562
+ return;
563
+ }
564
+
565
+ // Non-file stream: create regular readable stream
566
+ var readableStream = new _stream.IframeReadableStream(streamId, requestId, this, {
567
+ type: streamType,
568
+ chunked: streamChunked,
569
+ metadata: streamMetadata
570
+ });
571
+ var resp = {
572
+ data: undefined,
573
+ status: data.status || _constants.HttpStatus.OK,
574
+ statusText: data.statusText || _constants.HttpStatusText[_constants.HttpStatus.OK],
575
+ requestId,
576
+ headers: data.headers,
577
+ stream: readableStream
578
+ };
579
+ (0, _interceptors.runResponseInterceptors)(this.interceptors.response, resp).then(response => {
580
+ resolve(returnData ? response.data : response);
581
+ }).catch(reject);
582
+ return;
583
+ }
584
+
585
+ // Received stream data/end/error/cancel message - dispatch to stream handler
586
+ if (data.type.startsWith('stream_')) {
587
+ this.dispatchStreamMessage(data);
588
+ return;
589
+ }
590
+
591
+ // Received response
592
+ if (data.type === _constants.MessageType.RESPONSE) {
593
+ done = true;
594
+ cleanup();
595
+
596
+ // Remember server's creatorId as target server ID for future requests
597
+ if (data.creatorId && !this._targetServerId) {
598
+ this._targetServerId = data.creatorId;
599
+ }
600
+
601
+ // If server requires acknowledgment, send received message
602
+ if (data.requireAck) {
603
+ this.server.messageDispatcher.sendMessage(this.targetWindow, this.targetOrigin, _constants.MessageType.RECEIVED, requestId, {
604
+ path: requestPath,
605
+ targetId: data.creatorId
606
+ });
607
+ }
608
+
609
+ // Parse and save server-set cookies (from Set-Cookie header)
610
+ if (data.headers && data.headers[_constants.HttpHeader.SET_COOKIE]) {
611
+ var setCookies = data.headers[_constants.HttpHeader.SET_COOKIE];
612
+ var setCookieArray = Array.isArray(setCookies) ? setCookies : [setCookies];
613
+ var _iterator = _createForOfIteratorHelper(setCookieArray),
614
+ _step;
615
+ try {
616
+ for (_iterator.s(); !(_step = _iterator.n()).done;) {
617
+ var setCookieStr = _step.value;
618
+ this._cookieStore.setFromSetCookie(setCookieStr);
619
+ }
620
+ } catch (err) {
621
+ _iterator.e(err);
622
+ } finally {
623
+ _iterator.f();
624
+ }
625
+ }
626
+ var _resp2 = {
627
+ data: data.data,
628
+ status: data.status || _constants.HttpStatus.OK,
629
+ statusText: data.statusText || _constants.HttpStatusText[_constants.HttpStatus.OK],
630
+ requestId,
631
+ headers: data.headers
632
+ };
633
+ (0, _interceptors.runResponseInterceptors)(this.interceptors.response, _resp2).then(response => {
634
+ resolve(returnData ? response.data : response);
635
+ }).catch(reject);
636
+ return;
637
+ }
638
+
639
+ // Received error
640
+ if (data.type === _constants.MessageType.ERROR) {
641
+ var _data$error, _data$error2;
642
+ // Remember server's creatorId as target server ID for future requests
643
+ if (data.creatorId && !this._targetServerId) {
644
+ this._targetServerId = data.creatorId;
645
+ }
646
+
647
+ // If server requires acknowledgment, send received message
648
+ if (data.requireAck) {
649
+ this.server.messageDispatcher.sendMessage(this.targetWindow, this.targetOrigin, _constants.MessageType.RECEIVED, requestId, {
650
+ path: requestPath,
651
+ targetId: data.creatorId
652
+ });
653
+ }
654
+ var err = {
655
+ message: ((_data$error = data.error) === null || _data$error === void 0 ? void 0 : _data$error.message) || _constants.Messages.REQUEST_FAILED,
656
+ code: ((_data$error2 = data.error) === null || _data$error2 === void 0 ? void 0 : _data$error2.code) || _constants.ErrorCode.REQUEST_ERROR,
657
+ config: processedConfig,
658
+ response: data.status ? {
659
+ data: data.data,
660
+ status: data.status,
661
+ statusText: data.statusText || _constants.Messages.ERROR
662
+ } : undefined,
663
+ requestId
664
+ };
665
+ fail(err);
666
+ }
667
+ }, error => {
668
+ fail({
669
+ message: error.message || _constants.Messages.REQUEST_FAILED,
670
+ code: _constants.ErrorCode.REQUEST_ERROR,
671
+ config: processedConfig,
672
+ requestId
673
+ });
674
+ }, this.targetOrigin);
675
+
676
+ // Set ACK timeout
677
+ setAckTimeout();
678
+
679
+ // Get cookies matching request path and merge with user-provided cookies (user-provided takes precedence)
680
+ var pathMatchedCookies = this._cookieStore.getForPath(requestPath);
681
+ var mergedCookies = _objectSpread(_objectSpread({}, pathMatchedCookies), processedCookies);
682
+
683
+ // Send request via MessageDispatcher
684
+ var payload = {
685
+ path: requestPath,
686
+ body,
687
+ headers: mergedHeaders,
688
+ cookies: mergedCookies,
689
+ targetId
690
+ };
691
+ if (extraPayload !== null && extraPayload !== void 0 && extraPayload.streamId) {
692
+ payload.streamId = extraPayload.streamId;
693
+ }
694
+ this.server.messageDispatcher.sendMessage(this.targetWindow, this.targetOrigin, _constants.MessageType.REQUEST, requestId, payload);
695
+ });
696
+ }
375
697
  /**
376
698
  * Get internal server instance (for debugging)
377
699
  */