request-iframe 0.0.3 → 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 (53) hide show
  1. package/QUICKSTART.CN.md +35 -8
  2. package/QUICKSTART.md +35 -8
  3. package/README.CN.md +170 -24
  4. package/README.md +230 -19
  5. package/library/__tests__/coverage-branches.test.ts +356 -0
  6. package/library/__tests__/requestIframe.test.ts +1008 -58
  7. package/library/__tests__/stream.test.ts +46 -15
  8. package/library/api/client.d.ts.map +1 -1
  9. package/library/api/client.js +1 -0
  10. package/library/constants/messages.d.ts +2 -0
  11. package/library/constants/messages.d.ts.map +1 -1
  12. package/library/constants/messages.js +2 -0
  13. package/library/core/client-server.d.ts +4 -0
  14. package/library/core/client-server.d.ts.map +1 -1
  15. package/library/core/client-server.js +45 -22
  16. package/library/core/client.d.ts +31 -4
  17. package/library/core/client.d.ts.map +1 -1
  18. package/library/core/client.js +471 -284
  19. package/library/core/request.d.ts +3 -1
  20. package/library/core/request.d.ts.map +1 -1
  21. package/library/core/request.js +2 -1
  22. package/library/core/response.d.ts +26 -4
  23. package/library/core/response.d.ts.map +1 -1
  24. package/library/core/response.js +142 -81
  25. package/library/core/server.d.ts +13 -0
  26. package/library/core/server.d.ts.map +1 -1
  27. package/library/core/server.js +211 -6
  28. package/library/index.d.ts +2 -1
  29. package/library/index.d.ts.map +1 -1
  30. package/library/index.js +32 -3
  31. package/library/message/dispatcher.d.ts.map +1 -1
  32. package/library/message/dispatcher.js +4 -3
  33. package/library/stream/index.d.ts +11 -1
  34. package/library/stream/index.d.ts.map +1 -1
  35. package/library/stream/index.js +21 -3
  36. package/library/stream/types.d.ts +2 -2
  37. package/library/stream/types.d.ts.map +1 -1
  38. package/library/stream/writable-stream.d.ts +1 -1
  39. package/library/stream/writable-stream.d.ts.map +1 -1
  40. package/library/stream/writable-stream.js +8 -10
  41. package/library/types/index.d.ts +26 -4
  42. package/library/types/index.d.ts.map +1 -1
  43. package/library/utils/index.d.ts +14 -0
  44. package/library/utils/index.d.ts.map +1 -1
  45. package/library/utils/index.js +99 -1
  46. package/library/utils/path-match.d.ts +16 -0
  47. package/library/utils/path-match.d.ts.map +1 -1
  48. package/library/utils/path-match.js +65 -0
  49. package/package.json +2 -1
  50. package/react/library/__tests__/index.test.tsx +44 -22
  51. package/react/library/index.d.ts.map +1 -1
  52. package/react/library/index.js +81 -23
  53. package/react/package.json +7 -0
@@ -6,6 +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/es.weak-map.js");
9
10
  var _interopRequireDefault = require("@babel/runtime/helpers/interopRequireDefault");
10
11
  Object.defineProperty(exports, "__esModule", {
11
12
  value: true
@@ -32,6 +33,7 @@ var _stream = require("../stream");
32
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; } } }; }
33
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; } }
34
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); }
35
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; }
36
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; }
37
39
  /**
@@ -48,7 +50,7 @@ class RequestIframeClientImpl {
48
50
  */
49
51
 
50
52
  constructor(targetWindow, targetOrigin, server, options, instanceId) {
51
- var _options$ackTimeout, _options$timeout, _options$asyncTimeout;
53
+ var _options$ackTimeout, _options$timeout, _options$asyncTimeout, _options$returnData;
52
54
  /** Unique instance ID */
53
55
  (0, _defineProperty2.default)(this, "interceptors", {
54
56
  request: new _interceptors.RequestInterceptorManager(),
@@ -77,6 +79,9 @@ class RequestIframeClientImpl {
77
79
  this.defaultTimeout = (_options$timeout = options === null || options === void 0 ? void 0 : options.timeout) !== null && _options$timeout !== void 0 ? _options$timeout : _constants.DefaultTimeout.REQUEST;
78
80
  this.defaultAsyncTimeout = (_options$asyncTimeout = options === null || options === void 0 ? void 0 : options.asyncTimeout) !== null && _options$asyncTimeout !== void 0 ? _options$asyncTimeout : _constants.DefaultTimeout.ASYNC;
79
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
+
80
85
  // Save initial headers configuration
81
86
  this.initialHeaders = options === null || options === void 0 ? void 0 : options.headers;
82
87
 
@@ -133,11 +138,29 @@ class RequestIframeClientImpl {
133
138
  return value;
134
139
  }
135
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
+
136
158
  /**
137
159
  * Merge and resolve headers (initial headers + request headers)
138
160
  * Request headers take precedence over initial headers
161
+ * Also auto-detects and sets Content-Type if not already set
139
162
  */
140
- mergeHeaders(config) {
163
+ mergeHeaders(config, body) {
141
164
  var resolvedHeaders = {};
142
165
 
143
166
  // First, resolve initial headers
@@ -159,6 +182,14 @@ class RequestIframeClientImpl {
159
182
  resolvedHeaders[_key] = this.resolveHeaderValue(_value, config);
160
183
  }
161
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
+ }
162
193
  return resolvedHeaders;
163
194
  }
164
195
 
@@ -201,7 +232,7 @@ class RequestIframeClientImpl {
201
232
  send(path, body, options) {
202
233
  var _this = this;
203
234
  return (0, _asyncToGenerator2.default)(/*#__PURE__*/_regenerator.default.mark(function _callee() {
204
- var config, processedConfig, mergedHeaders, processedPath, processedBody, processedCookies, userTargetId, _processedConfig$ackT, ackTimeout, _processedConfig$time, timeout, _processedConfig$asyn, asyncTimeout, _processedConfig$requ, requestId, targetId;
235
+ var config, processedConfig, processedBody, mergedHeaders, processedPath, processedCookies, userTargetId, _processedConfig$requ, requestId, targetId;
205
236
  return _regenerator.default.wrap(function (_context) {
206
237
  while (1) switch (_context.prev = _context.next) {
207
238
  case 0:
@@ -213,300 +244,456 @@ class RequestIframeClientImpl {
213
244
  return (0, _interceptors.runRequestInterceptors)(_this.interceptors.request, config);
214
245
  case 1:
215
246
  processedConfig = _context.sent;
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:
216
260
  // Merge and resolve headers (initial headers + request headers)
217
- mergedHeaders = _this.mergeHeaders(processedConfig);
218
- processedPath = processedConfig.path, processedBody = processedConfig.body, processedCookies = processedConfig.cookies, userTargetId = processedConfig.targetId, _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; // Use user-specified targetId, or remembered target server ID, or undefined
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;
219
263
  targetId = userTargetId || _this._targetServerId;
220
- return _context.abrupt("return", new Promise((resolve, reject) => {
221
- var prefixedPath = _this.prefixPath(processedPath);
222
- var done = false;
223
- var timeoutId = null;
224
- var cleanup = () => {
225
- if (timeoutId) clearTimeout(timeoutId);
226
- _this.server._unregisterPendingRequest(requestId);
227
- };
228
- var fail = error => {
229
- if (done) return;
230
- done = true;
231
- cleanup();
232
- // Run response interceptors to allow error logging
233
- Promise.reject(error).catch(err => {
234
- // Run through response interceptors' rejected callbacks
235
- var promise = Promise.reject(err);
236
- _this.interceptors.response.forEach(interceptor => {
237
- promise = promise.catch(e => {
238
- if (interceptor.rejected) {
239
- return interceptor.rejected(e);
240
- }
241
- return Promise.reject(e);
242
- });
243
- });
244
- return promise;
245
- }).catch(() => {
246
- // After interceptors, reject with original error
247
- reject(error);
248
- });
249
- };
250
- var setAckTimeout = () => {
251
- if (timeoutId) clearTimeout(timeoutId);
252
- timeoutId = setTimeout(() => {
253
- fail({
254
- message: (0, _constants.formatMessage)(_constants.Messages.ACK_TIMEOUT, ackTimeout),
255
- code: _constants.ErrorCode.ACK_TIMEOUT,
256
- config: processedConfig,
257
- requestId
258
- });
259
- }, ackTimeout);
260
- };
261
- var setRequestTimeout = () => {
262
- if (timeoutId) clearTimeout(timeoutId);
263
- timeoutId = setTimeout(() => {
264
- fail({
265
- message: (0, _constants.formatMessage)(_constants.Messages.REQUEST_TIMEOUT, timeout),
266
- code: _constants.ErrorCode.TIMEOUT,
267
- config: processedConfig,
268
- requestId
269
- });
270
- }, timeout);
271
- };
272
- var setAsyncTimeout = () => {
273
- if (timeoutId) clearTimeout(timeoutId);
274
- timeoutId = setTimeout(() => {
275
- fail({
276
- message: (0, _constants.formatMessage)(_constants.Messages.ASYNC_REQUEST_TIMEOUT, asyncTimeout),
277
- code: _constants.ErrorCode.ASYNC_TIMEOUT,
278
- config: processedConfig,
279
- requestId
280
- });
281
- }, asyncTimeout);
282
- };
283
-
284
- // Register to server's pending requests
285
- _this.server._registerPendingRequest(requestId, data => {
286
- if (done) return;
287
-
288
- // Received ACK: server has received request
289
- if (data.type === _constants.MessageType.ACK) {
290
- // Remember server's creatorId as target server ID for future requests
291
- if (data.creatorId && !_this._targetServerId) {
292
- _this._targetServerId = data.creatorId;
293
- }
294
- // Switch to request timeout
295
- setRequestTimeout();
296
- return;
297
- }
298
-
299
- // Received ASYNC notification: this is an async task
300
- if (data.type === _constants.MessageType.ASYNC) {
301
- // Remember server's creatorId as target server ID for future requests
302
- if (data.creatorId && !_this._targetServerId) {
303
- _this._targetServerId = data.creatorId;
304
- }
305
- // Switch to async timeout
306
- setAsyncTimeout();
307
- return;
308
- }
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
+ }
309
272
 
310
- // Received stream start message
311
- if (data.type === _constants.MessageType.STREAM_START) {
312
- var _streamBody$chunked, _streamBody$autoResol;
313
- done = true;
314
- cleanup();
315
- var streamBody = data.body;
316
- var streamId = streamBody.streamId;
317
- var streamType = streamBody.type || _constants.StreamType.DATA;
318
- var streamChunked = (_streamBody$chunked = streamBody.chunked) !== null && _streamBody$chunked !== void 0 ? _streamBody$chunked : true;
319
- var streamMetadata = streamBody.metadata;
320
- var autoResolve = (_streamBody$autoResol = streamBody.autoResolve) !== null && _streamBody$autoResol !== void 0 ? _streamBody$autoResol : false;
321
-
322
- // Create corresponding readable stream based on stream type
323
- if (streamType === _constants.StreamType.FILE) {
324
- var _readableStream = new _stream.IframeFileReadableStream(streamId, requestId, _this, {
325
- chunked: streamChunked,
326
- metadata: streamMetadata,
327
- filename: streamMetadata === null || streamMetadata === void 0 ? void 0 : streamMetadata.filename,
328
- mimeType: streamMetadata === null || streamMetadata === void 0 ? void 0 : streamMetadata.mimeType,
329
- size: streamMetadata === null || streamMetadata === void 0 ? void 0 : streamMetadata.size
330
- });
331
-
332
- // If autoResolve is enabled, automatically read and convert to File/Blob
333
- if (autoResolve) {
334
- var _data$headers;
335
- // Extract fileName from headers if available
336
- var contentDisposition = (_data$headers = data.headers) === null || _data$headers === void 0 ? void 0 : _data$headers[_constants.HttpHeader.CONTENT_DISPOSITION];
337
- var fileName;
338
- if (contentDisposition) {
339
- var disposition = typeof contentDisposition === 'string' ? contentDisposition : contentDisposition[0];
340
- var filenameMatch = disposition.match(/filename="?([^"]+)"?/i);
341
- if (filenameMatch) {
342
- fileName = filenameMatch[1];
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;
343
306
  }
344
- }
345
- // Fallback to stream metadata if not found in headers
346
- fileName = fileName || (streamMetadata === null || streamMetadata === void 0 ? void 0 : streamMetadata.filename) || _readableStream.filename;
347
-
348
- // Use stream's readAsFile or readAsBlob method
349
- var fileDataPromise = fileName ? _readableStream.readAsFile(fileName) : _readableStream.readAsBlob();
350
- fileDataPromise.then(fileData => {
351
- var resp = {
352
- data: fileData,
353
- status: data.status || _constants.HttpStatus.OK,
354
- statusText: data.statusText || _constants.HttpStatusText[_constants.HttpStatus.OK],
355
- requestId,
356
- headers: data.headers
357
- };
358
- return (0, _interceptors.runResponseInterceptors)(_this.interceptors.response, resp);
359
- }).then(resolve).catch(reject);
360
- return;
361
- }
362
-
363
- // Non-autoResolve: return file stream directly
364
- var _resp = {
365
- data: undefined,
366
- status: data.status || _constants.HttpStatus.OK,
367
- statusText: data.statusText || _constants.HttpStatusText[_constants.HttpStatus.OK],
368
- requestId,
369
- headers: data.headers,
370
- stream: _readableStream
371
- };
372
- (0, _interceptors.runResponseInterceptors)(_this.interceptors.response, _resp).then(resolve).catch(reject);
373
- return;
374
- }
375
-
376
- // Non-file stream: create regular readable stream
377
- var readableStream = new _stream.IframeReadableStream(streamId, requestId, _this, {
378
- type: streamType,
379
- chunked: streamChunked,
380
- metadata: streamMetadata
381
- });
382
- var resp = {
383
- data: undefined,
384
- status: data.status || _constants.HttpStatus.OK,
385
- statusText: data.statusText || _constants.HttpStatusText[_constants.HttpStatus.OK],
386
- requestId,
387
- headers: data.headers,
388
- stream: readableStream
389
- };
390
- (0, _interceptors.runResponseInterceptors)(_this.interceptors.response, resp).then(resolve).catch(reject);
391
- return;
392
- }
393
-
394
- // Received stream data/end/error/cancel message - dispatch to stream handler
395
- if (data.type.startsWith('stream_')) {
396
- _this.dispatchStreamMessage(data);
397
- return;
398
- }
399
-
400
- // Received response
401
- if (data.type === _constants.MessageType.RESPONSE) {
402
- done = true;
403
- cleanup();
404
-
405
- // Remember server's creatorId as target server ID for future requests
406
- if (data.creatorId && !_this._targetServerId) {
407
- _this._targetServerId = data.creatorId;
408
- }
409
-
410
- // If server requires acknowledgment, send received message
411
- if (data.requireAck) {
412
- _this.server.messageDispatcher.sendMessage(_this.targetWindow, _this.targetOrigin, _constants.MessageType.RECEIVED, requestId, {
413
- path: prefixedPath,
414
- targetId: data.creatorId
415
- });
416
- }
417
-
418
- // Parse and save server-set cookies (from Set-Cookie header)
419
- if (data.headers && data.headers[_constants.HttpHeader.SET_COOKIE]) {
420
- var setCookies = data.headers[_constants.HttpHeader.SET_COOKIE];
421
- var setCookieArray = Array.isArray(setCookies) ? setCookies : [setCookies];
422
- var _iterator = _createForOfIteratorHelper(setCookieArray),
423
- _step;
424
- try {
425
- for (_iterator.s(); !(_step = _iterator.n()).done;) {
426
- var setCookieStr = _step.value;
427
- _this._cookieStore.setFromSetCookie(setCookieStr);
428
- }
429
- } catch (err) {
430
- _iterator.e(err);
431
- } finally {
432
- _iterator.f();
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();
433
324
  }
434
- }
435
- var _resp2 = {
436
- data: data.data,
437
- status: data.status || _constants.HttpStatus.OK,
438
- statusText: data.statusText || _constants.HttpStatusText[_constants.HttpStatus.OK],
439
- requestId,
440
- headers: data.headers
441
- };
442
- (0, _interceptors.runResponseInterceptors)(_this.interceptors.response, _resp2).then(resolve).catch(reject);
443
- return;
325
+ }, _callee2);
326
+ }));
327
+ function next() {
328
+ return _next.apply(this, arguments);
444
329
  }
445
-
446
- // Received error
447
- if (data.type === _constants.MessageType.ERROR) {
448
- var _data$error, _data$error2;
449
- // Remember server's creatorId as target server ID for future requests
450
- if (data.creatorId && !_this._targetServerId) {
451
- _this._targetServerId = data.creatorId;
452
- }
453
-
454
- // If server requires acknowledgment, send received message
455
- if (data.requireAck) {
456
- _this.server.messageDispatcher.sendMessage(_this.targetWindow, _this.targetOrigin, _constants.MessageType.RECEIVED, requestId, {
457
- path: prefixedPath,
458
- targetId: data.creatorId
459
- });
460
- }
461
- var err = {
462
- message: ((_data$error = data.error) === null || _data$error === void 0 ? void 0 : _data$error.message) || _constants.Messages.REQUEST_FAILED,
463
- code: ((_data$error2 = data.error) === null || _data$error2 === void 0 ? void 0 : _data$error2.code) || _constants.ErrorCode.REQUEST_ERROR,
464
- config: processedConfig,
465
- response: data.status ? {
466
- data: data.data,
467
- status: data.status,
468
- statusText: data.statusText || _constants.Messages.ERROR
469
- } : undefined,
470
- requestId
471
- };
472
- fail(err);
473
- }
474
- }, error => {
475
- fail({
476
- message: error.message || _constants.Messages.REQUEST_FAILED,
477
- code: _constants.ErrorCode.REQUEST_ERROR,
478
- config: processedConfig,
479
- requestId
480
- });
481
- }, _this.targetOrigin);
482
-
483
- // Set ACK timeout
484
- setAckTimeout();
485
-
486
- // Get cookies matching request path and merge with user-provided cookies (user-provided takes precedence)
487
- var pathMatchedCookies = _this._cookieStore.getForPath(processedPath);
488
- var mergedCookies = _objectSpread(_objectSpread({}, pathMatchedCookies), processedCookies);
489
-
490
- // Send request via MessageDispatcher
491
- _this.server.messageDispatcher.sendMessage(_this.targetWindow, _this.targetOrigin, _constants.MessageType.REQUEST, requestId, {
492
- path: prefixedPath,
493
- body: processedBody,
494
- headers: mergedHeaders,
495
- cookies: mergedCookies,
496
- targetId
497
- });
498
- }));
330
+ return next;
331
+ }()
332
+ });
333
+ return _context3.abrupt("return", _this2.sendStream(path, fileStream, options));
499
334
  case 2:
500
335
  case "end":
501
- return _context.stop();
336
+ return _context3.stop();
502
337
  }
503
- }, _callee);
338
+ }, _callee3);
504
339
  }))();
505
340
  }
506
- prefixPath(path) {
507
- 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
+ }))();
508
392
  }
509
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
+ }
510
697
  /**
511
698
  * Get internal server instance (for debugging)
512
699
  */