request-iframe 0.2.0 → 0.2.2

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 (93) hide show
  1. package/QUICKSTART.CN.md +33 -11
  2. package/QUICKSTART.md +33 -11
  3. package/README.CN.md +157 -44
  4. package/README.md +159 -41
  5. package/cdn/request-iframe.umd.js +4814 -4026
  6. package/cdn/request-iframe.umd.js.map +1 -1
  7. package/cdn/request-iframe.umd.min.js +2 -2
  8. package/cdn/request-iframe.umd.min.js.map +1 -1
  9. package/esm/api/client.js +45 -22
  10. package/esm/api/endpoint.js +30 -13
  11. package/esm/api/server.js +22 -13
  12. package/esm/constants/warn-once.js +7 -1
  13. package/esm/endpoint/index.js +1 -2
  14. package/esm/endpoint/infra/inbox.js +5 -4
  15. package/esm/endpoint/infra/outbox.js +8 -8
  16. package/esm/endpoint/stream/file-auto-resolve.js +9 -8
  17. package/esm/impl/client.js +3 -2
  18. package/esm/impl/response.js +4 -2
  19. package/esm/impl/server.js +8 -6
  20. package/esm/message/channel.js +15 -3
  21. package/esm/message/dispatcher.js +27 -0
  22. package/esm/stream/file-stream.js +311 -72
  23. package/esm/stream/writable-stream.js +21 -4
  24. package/esm/utils/blob.js +17 -0
  25. package/esm/utils/debug-lazy.js +76 -0
  26. package/esm/utils/logger.js +33 -1
  27. package/esm/utils/strict-mode.js +85 -0
  28. package/esm/utils/warn-once.js +30 -0
  29. package/esm/utils/warnings.js +47 -0
  30. package/library/api/client.d.ts.map +1 -1
  31. package/library/api/client.js +45 -22
  32. package/library/api/endpoint.d.ts.map +1 -1
  33. package/library/api/endpoint.js +30 -13
  34. package/library/api/server.d.ts.map +1 -1
  35. package/library/api/server.js +22 -13
  36. package/library/constants/warn-once.d.ts +6 -0
  37. package/library/constants/warn-once.d.ts.map +1 -1
  38. package/library/constants/warn-once.js +7 -1
  39. package/library/endpoint/index.d.ts +0 -1
  40. package/library/endpoint/index.d.ts.map +1 -1
  41. package/library/endpoint/index.js +1 -8
  42. package/library/endpoint/infra/inbox.d.ts.map +1 -1
  43. package/library/endpoint/infra/inbox.js +4 -3
  44. package/library/endpoint/infra/outbox.d.ts +2 -0
  45. package/library/endpoint/infra/outbox.d.ts.map +1 -1
  46. package/library/endpoint/infra/outbox.js +7 -7
  47. package/library/endpoint/stream/file-auto-resolve.d.ts +1 -1
  48. package/library/endpoint/stream/file-auto-resolve.d.ts.map +1 -1
  49. package/library/endpoint/stream/file-auto-resolve.js +8 -8
  50. package/library/impl/client.d.ts +2 -0
  51. package/library/impl/client.d.ts.map +1 -1
  52. package/library/impl/client.js +3 -2
  53. package/library/impl/response.d.ts.map +1 -1
  54. package/library/impl/response.js +4 -2
  55. package/library/impl/server.d.ts.map +1 -1
  56. package/library/impl/server.js +7 -5
  57. package/library/message/channel.d.ts +2 -2
  58. package/library/message/channel.d.ts.map +1 -1
  59. package/library/message/channel.js +15 -3
  60. package/library/message/dispatcher.d.ts.map +1 -1
  61. package/library/message/dispatcher.js +27 -0
  62. package/library/stream/file-stream.d.ts +70 -5
  63. package/library/stream/file-stream.d.ts.map +1 -1
  64. package/library/stream/file-stream.js +310 -70
  65. package/library/stream/types.d.ts +2 -0
  66. package/library/stream/types.d.ts.map +1 -1
  67. package/library/stream/writable-stream.d.ts.map +1 -1
  68. package/library/stream/writable-stream.js +21 -4
  69. package/library/types/index.d.ts +38 -0
  70. package/library/types/index.d.ts.map +1 -1
  71. package/library/utils/blob.d.ts +7 -0
  72. package/library/utils/blob.d.ts.map +1 -1
  73. package/library/utils/blob.js +18 -0
  74. package/library/utils/debug-lazy.d.ts +26 -0
  75. package/library/utils/debug-lazy.d.ts.map +1 -0
  76. package/library/utils/debug-lazy.js +85 -0
  77. package/library/utils/logger.d.ts +20 -0
  78. package/library/utils/logger.d.ts.map +1 -1
  79. package/library/utils/logger.js +34 -1
  80. package/library/utils/strict-mode.d.ts +37 -0
  81. package/library/utils/strict-mode.d.ts.map +1 -0
  82. package/library/utils/strict-mode.js +94 -0
  83. package/library/utils/warn-once.d.ts +9 -0
  84. package/library/utils/warn-once.d.ts.map +1 -0
  85. package/library/utils/warn-once.js +36 -0
  86. package/library/utils/warnings.d.ts +48 -0
  87. package/library/utils/warnings.d.ts.map +1 -0
  88. package/library/utils/warnings.js +54 -0
  89. package/package.json +1 -1
  90. package/esm/endpoint/stream/file-writable.js +0 -105
  91. package/library/endpoint/stream/file-writable.d.ts +0 -33
  92. package/library/endpoint/stream/file-writable.d.ts.map +0 -1
  93. package/library/endpoint/stream/file-writable.js +0 -115
@@ -1,20 +1,21 @@
1
- import _asyncToGenerator from "@babel/runtime/helpers/esm/asyncToGenerator";
2
1
  import _defineProperty from "@babel/runtime/helpers/esm/defineProperty";
3
- import _regeneratorRuntime from "@babel/runtime/regenerator";
2
+ import _asyncToGenerator from "@babel/runtime/helpers/esm/asyncToGenerator";
4
3
  function _createForOfIteratorHelper(r, e) { var t = "undefined" != typeof Symbol && r[Symbol.iterator] || r["@@iterator"]; if (!t) { if (Array.isArray(r) || (t = _unsupportedIterableToArray(r)) || e && r && "number" == typeof r.length) { t && (r = t); var _n = 0, F = function F() {}; return { s: F, n: function n() { return _n >= r.length ? { done: !0 } : { done: !1, value: r[_n++] }; }, e: function e(r) { throw r; }, f: F }; } throw new TypeError("Invalid attempt to iterate non-iterable instance.\nIn order to be iterable, non-array objects must have a [Symbol.iterator]() method."); } var o, a = !0, u = !1; return { s: function s() { t = t.call(r); }, n: function n() { var r = t.next(); return a = r.done, r; }, e: function e(r) { u = !0, o = r; }, f: function f() { try { a || null == t.return || t.return(); } finally { if (u) throw o; } } }; }
5
4
  function _unsupportedIterableToArray(r, a) { if (r) { if ("string" == typeof r) return _arrayLikeToArray(r, a); var t = {}.toString.call(r).slice(8, -1); return "Object" === t && r.constructor && (t = r.constructor.name), "Map" === t || "Set" === t ? Array.from(r) : "Arguments" === t || /^(?:Ui|I)nt(?:8|16|32)(?:Clamped)?Array$/.test(t) ? _arrayLikeToArray(r, a) : void 0; } }
6
5
  function _arrayLikeToArray(r, a) { (null == a || a > r.length) && (a = r.length); for (var e = 0, n = Array(a); e < a; e++) n[e] = r[e]; return n; }
7
6
  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; }
8
7
  function _objectSpread(e) { for (var r = 1; r < arguments.length; r++) { var t = null != arguments[r] ? arguments[r] : {}; r % 2 ? ownKeys(Object(t), !0).forEach(function (r) { _defineProperty(e, r, t[r]); }) : Object.getOwnPropertyDescriptors ? Object.defineProperties(e, Object.getOwnPropertyDescriptors(t)) : ownKeys(Object(t)).forEach(function (r) { Object.defineProperty(e, r, Object.getOwnPropertyDescriptor(t, r)); }); } return e; }
8
+ import _regeneratorRuntime from "@babel/runtime/regenerator";
9
9
  import "core-js/modules/es.array.iterator.js";
10
10
  import "core-js/modules/es.symbol.description.js";
11
11
  import "core-js/modules/es.array.from.js";
12
12
  import "core-js/modules/es.array.reduce.js";
13
- import "core-js/modules/es.array.slice.js";
14
13
  import "core-js/modules/es.array.filter.js";
15
- import "core-js/modules/es.object.get-own-property-descriptors.js";
14
+ import "core-js/modules/es.array.slice.js";
16
15
  import "core-js/modules/es.regexp.exec.js";
17
16
  import "core-js/modules/es.regexp.to-string.js";
17
+ import "core-js/modules/es.string.match.js";
18
+ import "core-js/modules/es.object.get-own-property-descriptors.js";
18
19
  import "core-js/modules/es.typed-array.uint8-array.js";
19
20
  import "core-js/modules/es.typed-array.fill.js";
20
21
  import "core-js/modules/es.typed-array.iterator.js";
@@ -26,6 +27,8 @@ import "core-js/modules/web.dom-collections.iterator.js";
26
27
  import { IframeWritableStream } from './writable-stream';
27
28
  import { IframeReadableStream } from './readable-stream';
28
29
  import { StreamType as StreamTypeConstant } from '../constants';
30
+ import { blobToArrayBuffer } from '../utils/blob';
31
+ var DEFAULT_FILE_CHUNK_SIZE = 256 * 1024; // 256KB
29
32
 
30
33
  /**
31
34
  * Convert Uint8Array to Base64 string
@@ -45,22 +48,208 @@ function uint8ArrayToBase64(uint8Array) {
45
48
  }
46
49
 
47
50
  /**
48
- * Convert Base64 string to Uint8Array
51
+ * Convert string to UTF-8 bytes.
52
+ *
53
+ * Notes:
54
+ * - We prefer TextEncoder when available.
55
+ * - Fallback uses `unescape(encodeURIComponent(...))` for broad browser compatibility.
49
56
  */
50
- function base64ToUint8Array(base64) {
51
- var binary = atob(base64);
52
- var uint8Array = new Uint8Array(binary.length);
53
- for (var i = 0; i < binary.length; i++) {
54
- uint8Array[i] = binary.charCodeAt(i);
57
+ function stringToUtf8Uint8Array(value) {
58
+ try {
59
+ if (typeof TextEncoder !== 'undefined') {
60
+ return new TextEncoder().encode(value);
61
+ }
62
+ } catch (_unused) {
63
+ /** ignore */
64
+ }
65
+ var latin1 = unescape(encodeURIComponent(value));
66
+ var arr = new Uint8Array(latin1.length);
67
+ for (var i = 0; i < latin1.length; i++) {
68
+ arr[i] = latin1.charCodeAt(i);
55
69
  }
56
- return uint8Array;
70
+ return arr;
71
+ }
72
+
73
+ /**
74
+ * Convert UTF-8 bytes to string.
75
+ *
76
+ * Notes:
77
+ * - We prefer TextDecoder when available.
78
+ * - Fallback uses `escape/decodeURIComponent` for broad browser compatibility.
79
+ */
80
+ function utf8Uint8ArrayToString(bytes) {
81
+ try {
82
+ if (typeof TextDecoder !== 'undefined') {
83
+ return new TextDecoder('utf-8').decode(bytes);
84
+ }
85
+ } catch (_unused2) {
86
+ /** ignore */
87
+ }
88
+ /**
89
+ * Fallback:
90
+ * - Build a latin1 string from bytes, then decode as UTF-8.
91
+ * - We chunk to avoid call stack / argument limits.
92
+ */
93
+ var chunkSize = 0x8000;
94
+ var parts = [];
95
+ for (var i = 0; i < bytes.length; i += chunkSize) {
96
+ var chunk = bytes.subarray(i, i + chunkSize);
97
+ parts.push(String.fromCharCode.apply(null, chunk));
98
+ }
99
+ return decodeURIComponent(escape(parts.join('')));
57
100
  }
58
101
 
59
102
  /**
60
103
  * IframeFileWritableStream - Server-side file writable stream
61
- * Automatically handles Base64 encoding of file content
104
+ *
105
+ * Notes:
106
+ * - This stream supports binary chunks (ArrayBuffer / Uint8Array), which can be transferred
107
+ * via postMessage transfer list for better performance.
62
108
  */
63
109
  export class IframeFileWritableStream extends IframeWritableStream {
110
+ /**
111
+ * Create a file writable stream from string/Blob/File.
112
+ *
113
+ * This is a stream-layer utility:
114
+ * - It does NOT depend on headers.
115
+ * - It produces binary chunks (ArrayBuffer) for better performance.
116
+ */
117
+ static from(params) {
118
+ return _asyncToGenerator(/*#__PURE__*/_regeneratorRuntime.mark(function _callee2() {
119
+ var _params$chunked, _params$autoResolve;
120
+ var mimeType, fileName, size, t, blob, streamFileName, chunked, chunkSize, offset, stream;
121
+ return _regeneratorRuntime.wrap(function (_context2) {
122
+ while (1) switch (_context2.prev = _context2.next) {
123
+ case 0:
124
+ mimeType = params.mimeType || params.defaultMimeType || 'application/octet-stream';
125
+ fileName = params.fileName;
126
+ try {
127
+ if (typeof File !== 'undefined' && params.content instanceof File) {
128
+ mimeType = params.content.type || mimeType;
129
+ fileName = fileName || params.content.name;
130
+ size = params.content.size;
131
+ }
132
+ } catch (_unused3) {
133
+ /** ignore */
134
+ }
135
+ try {
136
+ if (!fileName && typeof Blob !== 'undefined' && params.content instanceof Blob) {
137
+ t = params.content.type;
138
+ if (t) mimeType = t;
139
+ size = params.content.size;
140
+ }
141
+ } catch (_unused4) {
142
+ /** ignore */
143
+ }
144
+ blob = typeof params.content === 'string' ? new Blob([params.content], {
145
+ type: mimeType
146
+ }) : params.content;
147
+ size = size !== null && size !== void 0 ? size : blob === null || blob === void 0 ? void 0 : blob.size;
148
+ streamFileName = fileName || params.defaultFileName || 'file';
149
+ chunked = (_params$chunked = params.chunked) !== null && _params$chunked !== void 0 ? _params$chunked : false;
150
+ chunkSize = typeof params.chunkSize === 'number' && Number.isFinite(params.chunkSize) && params.chunkSize > 0 ? Math.floor(params.chunkSize) : DEFAULT_FILE_CHUNK_SIZE;
151
+ offset = 0;
152
+ stream = new IframeFileWritableStream({
153
+ filename: streamFileName,
154
+ mimeType,
155
+ size,
156
+ chunked,
157
+ autoResolve: (_params$autoResolve = params.autoResolve) !== null && _params$autoResolve !== void 0 ? _params$autoResolve : true,
158
+ next: function () {
159
+ var _next = _asyncToGenerator(/*#__PURE__*/_regeneratorRuntime.mark(function _callee() {
160
+ var _size;
161
+ var all, total, end, slice, buf;
162
+ return _regeneratorRuntime.wrap(function (_context) {
163
+ while (1) switch (_context.prev = _context.next) {
164
+ case 0:
165
+ if (chunked) {
166
+ _context.next = 2;
167
+ break;
168
+ }
169
+ _context.next = 1;
170
+ return blobToArrayBuffer(blob);
171
+ case 1:
172
+ all = _context.sent;
173
+ return _context.abrupt("return", {
174
+ data: all,
175
+ done: true
176
+ });
177
+ case 2:
178
+ total = (_size = blob.size) !== null && _size !== void 0 ? _size : 0;
179
+ if (!(offset >= total)) {
180
+ _context.next = 3;
181
+ break;
182
+ }
183
+ return _context.abrupt("return", {
184
+ data: new ArrayBuffer(0),
185
+ done: true
186
+ });
187
+ case 3:
188
+ end = Math.min(total, offset + chunkSize);
189
+ slice = blob.slice(offset, end);
190
+ _context.next = 4;
191
+ return blobToArrayBuffer(slice);
192
+ case 4:
193
+ buf = _context.sent;
194
+ offset = end;
195
+ return _context.abrupt("return", {
196
+ data: buf,
197
+ done: offset >= total
198
+ });
199
+ case 5:
200
+ case "end":
201
+ return _context.stop();
202
+ }
203
+ }, _callee);
204
+ }));
205
+ function next() {
206
+ return _next.apply(this, arguments);
207
+ }
208
+ return next;
209
+ }()
210
+ });
211
+ return _context2.abrupt("return", stream);
212
+ case 1:
213
+ case "end":
214
+ return _context2.stop();
215
+ }
216
+ }, _callee2);
217
+ }))();
218
+ }
219
+
220
+ /**
221
+ * Create a UTF-8 text file stream.
222
+ *
223
+ * This is a convenience wrapper around from({ content: string, ... }):
224
+ * - Makes "string -> UTF-8 bytes -> file stream" intent explicit.
225
+ * - Sets a more appropriate default mimeType for text files.
226
+ */
227
+ static fromText(params) {
228
+ return _asyncToGenerator(/*#__PURE__*/_regeneratorRuntime.mark(function _callee3() {
229
+ var _params$mimeType, _params$defaultFileNa;
230
+ return _regeneratorRuntime.wrap(function (_context3) {
231
+ while (1) switch (_context3.prev = _context3.next) {
232
+ case 0:
233
+ _context3.next = 1;
234
+ return IframeFileWritableStream.from({
235
+ content: params.text,
236
+ fileName: params.fileName,
237
+ mimeType: (_params$mimeType = params.mimeType) !== null && _params$mimeType !== void 0 ? _params$mimeType : 'text/plain; charset=utf-8',
238
+ chunked: params.chunked,
239
+ chunkSize: params.chunkSize,
240
+ autoResolve: params.autoResolve,
241
+ defaultFileName: (_params$defaultFileNa = params.defaultFileName) !== null && _params$defaultFileNa !== void 0 ? _params$defaultFileNa : 'file.txt',
242
+ defaultMimeType: 'text/plain; charset=utf-8'
243
+ });
244
+ case 1:
245
+ return _context3.abrupt("return", _context3.sent);
246
+ case 2:
247
+ case "end":
248
+ return _context3.stop();
249
+ }
250
+ }, _callee3);
251
+ }))();
252
+ }
64
253
  constructor(options) {
65
254
  super(_objectSpread(_objectSpread({}, options), {}, {
66
255
  type: StreamTypeConstant.FILE,
@@ -76,27 +265,32 @@ export class IframeFileWritableStream extends IframeWritableStream {
76
265
  }
77
266
 
78
267
  /**
79
- * Override encode method to convert Uint8Array to Base64
268
+ * Encode outbound chunk.
269
+ *
270
+ * - ArrayBuffer / TypedArray: keep as-is (binary chunks)
271
+ * - string: encoded as UTF-8 bytes
80
272
  */
81
273
  encodeData(data) {
82
- if (data instanceof Uint8Array) {
83
- return uint8ArrayToBase64(data);
84
- }
85
- if (data instanceof ArrayBuffer) {
86
- return uint8ArrayToBase64(new Uint8Array(data));
274
+ try {
275
+ if (typeof ArrayBuffer !== 'undefined' && data instanceof ArrayBuffer) {
276
+ return data;
277
+ }
278
+ if (typeof ArrayBuffer !== 'undefined' && ArrayBuffer.isView && ArrayBuffer.isView(data)) {
279
+ return data;
280
+ }
281
+ } catch (_unused5) {
282
+ /** ignore */
87
283
  }
88
284
  if (typeof data === 'string') {
89
- // Already a base64 string
90
- return data;
285
+ return stringToUtf8Uint8Array(data);
91
286
  }
92
- // Try to convert other types
93
- return String(data);
287
+ return stringToUtf8Uint8Array(String(data));
94
288
  }
95
289
  }
96
290
 
97
291
  /**
98
292
  * IframeFileReadableStream - Client-side file readable stream
99
- * Automatically handles Base64 decoding of file content
293
+ * Automatically normalizes inbound chunks to Uint8Array.
100
294
  */
101
295
  export class IframeFileReadableStream extends IframeReadableStream {
102
296
  constructor(streamId, requestId, messageHandler, options = {}) {
@@ -110,11 +304,11 @@ export class IframeFileReadableStream extends IframeReadableStream {
110
304
  }
111
305
 
112
306
  /**
113
- * Override decode method to convert Base64 to Uint8Array
307
+ * Override decode method to normalize chunk to Uint8Array.
114
308
  */
115
309
  decodeData(data) {
116
310
  if (typeof data === 'string') {
117
- return base64ToUint8Array(data);
311
+ return stringToUtf8Uint8Array(data);
118
312
  }
119
313
  if (data instanceof Uint8Array) {
120
314
  return data;
@@ -125,6 +319,24 @@ export class IframeFileReadableStream extends IframeReadableStream {
125
319
  return new Uint8Array();
126
320
  }
127
321
 
322
+ /**
323
+ * Parse filename from Content-Disposition header value.
324
+ */
325
+ static parseFilenameFromContentDisposition(value) {
326
+ if (!value) return undefined;
327
+ var disposition = typeof value === 'string' ? value : value[0];
328
+ if (!disposition) return undefined;
329
+ var match = disposition.match(/filename="?([^"]+)"?/i);
330
+ return match ? match[1] : undefined;
331
+ }
332
+
333
+ /**
334
+ * Resolve this file stream to File or Blob, depending on whether fileName is provided.
335
+ */
336
+ readAsFileOrBlob(fileName) {
337
+ return fileName ? this.readAsFile(fileName) : this.readAsBlob();
338
+ }
339
+
128
340
  /**
129
341
  * Override merge method to merge all Uint8Array chunks
130
342
  */
@@ -165,19 +377,19 @@ export class IframeFileReadableStream extends IframeReadableStream {
165
377
  read() {
166
378
  var _superprop_getRead = () => super.read,
167
379
  _this = this;
168
- return _asyncToGenerator(/*#__PURE__*/_regeneratorRuntime.mark(function _callee() {
169
- return _regeneratorRuntime.wrap(function (_context) {
170
- while (1) switch (_context.prev = _context.next) {
380
+ return _asyncToGenerator(/*#__PURE__*/_regeneratorRuntime.mark(function _callee4() {
381
+ return _regeneratorRuntime.wrap(function (_context4) {
382
+ while (1) switch (_context4.prev = _context4.next) {
171
383
  case 0:
172
- _context.next = 1;
384
+ _context4.next = 1;
173
385
  return _superprop_getRead().call(_this);
174
386
  case 1:
175
- return _context.abrupt("return", _context.sent);
387
+ return _context4.abrupt("return", _context4.sent);
176
388
  case 2:
177
389
  case "end":
178
- return _context.stop();
390
+ return _context4.stop();
179
391
  }
180
- }, _callee);
392
+ }, _callee4);
181
393
  }))();
182
394
  }
183
395
 
@@ -186,25 +398,52 @@ export class IframeFileReadableStream extends IframeReadableStream {
186
398
  */
187
399
  readAsBlob() {
188
400
  var _this2 = this;
189
- return _asyncToGenerator(/*#__PURE__*/_regeneratorRuntime.mark(function _callee2() {
401
+ return _asyncToGenerator(/*#__PURE__*/_regeneratorRuntime.mark(function _callee5() {
190
402
  var data, buffer;
191
- return _regeneratorRuntime.wrap(function (_context2) {
192
- while (1) switch (_context2.prev = _context2.next) {
403
+ return _regeneratorRuntime.wrap(function (_context5) {
404
+ while (1) switch (_context5.prev = _context5.next) {
193
405
  case 0:
194
- _context2.next = 1;
406
+ _context5.next = 1;
195
407
  return _this2.read();
196
408
  case 1:
197
- data = _context2.sent;
409
+ data = _context5.sent;
198
410
  // Use slice to create a pure ArrayBuffer copy to avoid type issues
199
411
  buffer = data.buffer.slice(data.byteOffset, data.byteOffset + data.byteLength);
200
- return _context2.abrupt("return", new Blob([buffer], {
412
+ return _context5.abrupt("return", new Blob([buffer], {
201
413
  type: _this2.mimeType || 'application/octet-stream'
202
414
  }));
203
415
  case 2:
204
416
  case "end":
205
- return _context2.stop();
417
+ return _context5.stop();
206
418
  }
207
- }, _callee2);
419
+ }, _callee5);
420
+ }))();
421
+ }
422
+
423
+ /**
424
+ * Read as UTF-8 text.
425
+ *
426
+ * Notes:
427
+ * - This is intended for "text file" use cases where file stream chunks represent UTF-8 bytes.
428
+ * - For non-UTF-8 binary files, use readAsBlob()/readAsArrayBuffer().
429
+ */
430
+ readAsText() {
431
+ var _this3 = this;
432
+ return _asyncToGenerator(/*#__PURE__*/_regeneratorRuntime.mark(function _callee6() {
433
+ var data;
434
+ return _regeneratorRuntime.wrap(function (_context6) {
435
+ while (1) switch (_context6.prev = _context6.next) {
436
+ case 0:
437
+ _context6.next = 1;
438
+ return _this3.read();
439
+ case 1:
440
+ data = _context6.sent;
441
+ return _context6.abrupt("return", utf8Uint8ArrayToString(data));
442
+ case 2:
443
+ case "end":
444
+ return _context6.stop();
445
+ }
446
+ }, _callee6);
208
447
  }))();
209
448
  }
210
449
 
@@ -213,27 +452,27 @@ export class IframeFileReadableStream extends IframeReadableStream {
213
452
  * @param fileName Optional file name (if not provided, uses stream's filename)
214
453
  */
215
454
  readAsFile(fileName) {
216
- var _this3 = this;
217
- return _asyncToGenerator(/*#__PURE__*/_regeneratorRuntime.mark(function _callee3() {
455
+ var _this4 = this;
456
+ return _asyncToGenerator(/*#__PURE__*/_regeneratorRuntime.mark(function _callee7() {
218
457
  var data, buffer, name;
219
- return _regeneratorRuntime.wrap(function (_context3) {
220
- while (1) switch (_context3.prev = _context3.next) {
458
+ return _regeneratorRuntime.wrap(function (_context7) {
459
+ while (1) switch (_context7.prev = _context7.next) {
221
460
  case 0:
222
- _context3.next = 1;
223
- return _this3.read();
461
+ _context7.next = 1;
462
+ return _this4.read();
224
463
  case 1:
225
- data = _context3.sent;
464
+ data = _context7.sent;
226
465
  // Use slice to create a pure ArrayBuffer copy to avoid type issues
227
466
  buffer = data.buffer.slice(data.byteOffset, data.byteOffset + data.byteLength);
228
- name = fileName || _this3.filename || 'file';
229
- return _context3.abrupt("return", new File([buffer], name, {
230
- type: _this3.mimeType || 'application/octet-stream'
467
+ name = fileName || _this4.filename || 'file';
468
+ return _context7.abrupt("return", new File([buffer], name, {
469
+ type: _this4.mimeType || 'application/octet-stream'
231
470
  }));
232
471
  case 2:
233
472
  case "end":
234
- return _context3.stop();
473
+ return _context7.stop();
235
474
  }
236
- }, _callee3);
475
+ }, _callee7);
237
476
  }))();
238
477
  }
239
478
 
@@ -241,25 +480,25 @@ export class IframeFileReadableStream extends IframeReadableStream {
241
480
  * Read as ArrayBuffer
242
481
  */
243
482
  readAsArrayBuffer() {
244
- var _this4 = this;
245
- return _asyncToGenerator(/*#__PURE__*/_regeneratorRuntime.mark(function _callee4() {
483
+ var _this5 = this;
484
+ return _asyncToGenerator(/*#__PURE__*/_regeneratorRuntime.mark(function _callee8() {
246
485
  var data, buffer;
247
- return _regeneratorRuntime.wrap(function (_context4) {
248
- while (1) switch (_context4.prev = _context4.next) {
486
+ return _regeneratorRuntime.wrap(function (_context8) {
487
+ while (1) switch (_context8.prev = _context8.next) {
249
488
  case 0:
250
- _context4.next = 1;
251
- return _this4.read();
489
+ _context8.next = 1;
490
+ return _this5.read();
252
491
  case 1:
253
- data = _context4.sent;
492
+ data = _context8.sent;
254
493
  // Create a new ArrayBuffer copy
255
494
  buffer = new ArrayBuffer(data.byteLength);
256
495
  new Uint8Array(buffer).set(data);
257
- return _context4.abrupt("return", buffer);
496
+ return _context8.abrupt("return", buffer);
258
497
  case 2:
259
498
  case "end":
260
- return _context4.stop();
499
+ return _context8.stop();
261
500
  }
262
- }, _callee4);
501
+ }, _callee8);
263
502
  }))();
264
503
  }
265
504
 
@@ -267,23 +506,23 @@ export class IframeFileReadableStream extends IframeReadableStream {
267
506
  * Read as Data URL
268
507
  */
269
508
  readAsDataURL() {
270
- var _this5 = this;
271
- return _asyncToGenerator(/*#__PURE__*/_regeneratorRuntime.mark(function _callee5() {
509
+ var _this6 = this;
510
+ return _asyncToGenerator(/*#__PURE__*/_regeneratorRuntime.mark(function _callee9() {
272
511
  var data, base64;
273
- return _regeneratorRuntime.wrap(function (_context5) {
274
- while (1) switch (_context5.prev = _context5.next) {
512
+ return _regeneratorRuntime.wrap(function (_context9) {
513
+ while (1) switch (_context9.prev = _context9.next) {
275
514
  case 0:
276
- _context5.next = 1;
277
- return _this5.read();
515
+ _context9.next = 1;
516
+ return _this6.read();
278
517
  case 1:
279
- data = _context5.sent;
518
+ data = _context9.sent;
280
519
  base64 = uint8ArrayToBase64(data);
281
- return _context5.abrupt("return", `data:${_this5.mimeType || 'application/octet-stream'};base64,${base64}`);
520
+ return _context9.abrupt("return", `data:${_this6.mimeType || 'application/octet-stream'};base64,${base64}`);
282
521
  case 2:
283
522
  case "end":
284
- return _context5.stop();
523
+ return _context9.stop();
285
524
  }
286
- }, _callee5);
525
+ }, _callee9);
287
526
  }))();
288
527
  }
289
528
  }
@@ -301,7 +301,24 @@ export class IframeWritableStream extends IframeStreamCore {
301
301
  creatorId,
302
302
  targetId: this.context.targetId
303
303
  });
304
- var ok = this.context.channel.send(this.context.targetWindow, message, this.context.targetOrigin);
304
+
305
+ /**
306
+ * Transferable optimization:
307
+ * - If payload contains ArrayBuffer/TypedArray, transfer its underlying buffer to avoid copy.
308
+ * - This helps large chunks (e.g. file streams) significantly.
309
+ */
310
+ var payloadData = data === null || data === void 0 ? void 0 : data.data;
311
+ var transfer;
312
+ try {
313
+ if (typeof ArrayBuffer !== 'undefined' && payloadData instanceof ArrayBuffer) {
314
+ transfer = [payloadData];
315
+ } else if (typeof ArrayBuffer !== 'undefined' && typeof ArrayBuffer.isView === 'function' && payloadData && ArrayBuffer.isView(payloadData) && payloadData.buffer instanceof ArrayBuffer) {
316
+ transfer = [payloadData.buffer];
317
+ }
318
+ } catch (_unused6) {
319
+ /** ignore */
320
+ }
321
+ var ok = this.context.channel.send(this.context.targetWindow, message, this.context.targetOrigin, transfer);
305
322
  if (!ok) {
306
323
  this._state = StreamStateConstant.CANCELLED;
307
324
  this.clearExpireTimer();
@@ -346,7 +363,7 @@ export class IframeWritableStream extends IframeStreamCore {
346
363
  if (isFunction(ch.removeReceiver)) {
347
364
  try {
348
365
  ch.removeReceiver(this.ackReceiver);
349
- } catch (_unused6) {
366
+ } catch (_unused7) {
350
367
  /** ignore */
351
368
  }
352
369
  }
@@ -381,7 +398,7 @@ export class IframeWritableStream extends IframeStreamCore {
381
398
  timeout: expireTimeout
382
399
  });
383
400
  this.error(formatMessage(Messages.STREAM_EXPIRED, expireTimeout));
384
- } catch (_unused7) {
401
+ } catch (_unused8) {
385
402
  /** ignore timer-triggered send failures */
386
403
  }
387
404
  }, expireTimeout);
@@ -896,7 +913,7 @@ export class IframeWritableStream extends IframeStreamCore {
896
913
  this.sendMessage(MessageType.STREAM_CANCEL, {
897
914
  reason
898
915
  });
899
- } catch (_unused8) {
916
+ } catch (_unused9) {
900
917
  // ignore send failures on cancel
901
918
  }
902
919
  }
package/esm/utils/blob.js CHANGED
@@ -13,4 +13,21 @@ export function blobToBase64(blob) {
13
13
  reader.onerror = reject;
14
14
  reader.readAsDataURL(blob);
15
15
  });
16
+ }
17
+
18
+ /**
19
+ * Convert Blob to ArrayBuffer.
20
+ *
21
+ * Notes:
22
+ * - Use FileReader for legacy browser support (e.g. Chrome 49).
23
+ */
24
+ export function blobToArrayBuffer(blob) {
25
+ return new Promise((resolve, reject) => {
26
+ var reader = new FileReader();
27
+ reader.onloadend = () => {
28
+ resolve(reader.result);
29
+ };
30
+ reader.onerror = reject;
31
+ reader.readAsArrayBuffer(blob);
32
+ });
16
33
  }
@@ -0,0 +1,76 @@
1
+ import "core-js/modules/es.array.iterator.js";
2
+ import "core-js/modules/es.promise.js";
3
+ import "core-js/modules/es.weak-map.js";
4
+ import "core-js/modules/web.dom-collections.iterator.js";
5
+ /**
6
+ * Lazy-load debug helpers (dynamic import) with shared caching.
7
+ *
8
+ * Why:
9
+ * - Avoid eagerly bundling debug wiring into the main bundle.
10
+ * - Keep one shared Promise so multiple entry points don't trigger multiple imports.
11
+ */
12
+
13
+ var debugModulePromise = null;
14
+ export function loadDebugModule() {
15
+ if (!debugModulePromise) {
16
+ debugModulePromise = import('./debug');
17
+ }
18
+ return debugModulePromise;
19
+ }
20
+ var CLIENT_DEBUG_STATE = new WeakMap();
21
+ var CLIENT_DEBUG_WRAPPED = Symbol.for('__requestIframeClientDebugWrapped__');
22
+
23
+ /**
24
+ * Ensure debug interceptors/listeners are attached to a client instance.
25
+ *
26
+ * Notes:
27
+ * - This returns a Promise that never rejects (best-effort).
28
+ * - It is safe to call multiple times; only attaches once per client instance.
29
+ */
30
+ export function ensureClientDebugInterceptors(client) {
31
+ var key = client;
32
+ var state = CLIENT_DEBUG_STATE.get(key);
33
+ if (!state) {
34
+ state = {
35
+ promise: null,
36
+ attached: false
37
+ };
38
+ CLIENT_DEBUG_STATE.set(key, state);
39
+ }
40
+ if (state.attached) return Promise.resolve();
41
+ if (!state.promise) {
42
+ state.promise = loadDebugModule().then(m => {
43
+ if (state.attached) return;
44
+ m.setupClientDebugInterceptors(client);
45
+ state.attached = true;
46
+ }).catch(() => {
47
+ /** ignore */
48
+ });
49
+ }
50
+ return state.promise;
51
+ }
52
+
53
+ /**
54
+ * Wrap client send methods so the first request in trace mode won't miss debug hooks.
55
+ *
56
+ * Why:
57
+ * - debug module is lazy-loaded via dynamic import, so it may not be ready immediately.
58
+ * - In trace mode, it's acceptable to delay the first send by a microtask or module-load time.
59
+ */
60
+ export function wrapClientMethodsForDebug(client) {
61
+ var c = client;
62
+ if (c[CLIENT_DEBUG_WRAPPED]) return;
63
+ c[CLIENT_DEBUG_WRAPPED] = true;
64
+ var wrapAsyncMethod = name => {
65
+ var original = c[name];
66
+ if (typeof original !== 'function') return;
67
+ var bound = original.bind(c);
68
+ c[name] = (...args) => {
69
+ return ensureClientDebugInterceptors(client).then(() => bound(...args));
70
+ };
71
+ };
72
+ wrapAsyncMethod('send');
73
+ wrapAsyncMethod('sendFile');
74
+ wrapAsyncMethod('sendStream');
75
+ wrapAsyncMethod('isConnect');
76
+ }