request-iframe 0.0.6 → 0.1.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (95) hide show
  1. package/README.CN.md +220 -21
  2. package/README.md +221 -24
  3. package/esm/api/client.js +80 -0
  4. package/esm/api/server.js +61 -0
  5. package/esm/constants/index.js +289 -0
  6. package/esm/constants/messages.js +157 -0
  7. package/esm/core/client-server.js +294 -0
  8. package/esm/core/client.js +873 -0
  9. package/esm/core/request.js +27 -0
  10. package/esm/core/response.js +459 -0
  11. package/esm/core/server.js +776 -0
  12. package/esm/index.js +21 -0
  13. package/esm/interceptors/index.js +122 -0
  14. package/esm/message/channel.js +182 -0
  15. package/esm/message/dispatcher.js +418 -0
  16. package/esm/message/index.js +2 -0
  17. package/esm/stream/file-stream.js +289 -0
  18. package/esm/stream/index.js +44 -0
  19. package/esm/stream/readable-stream.js +539 -0
  20. package/esm/stream/stream-core.js +204 -0
  21. package/esm/stream/types.js +1 -0
  22. package/esm/stream/writable-stream.js +836 -0
  23. package/esm/types/index.js +1 -0
  24. package/esm/utils/ack.js +36 -0
  25. package/esm/utils/cache.js +147 -0
  26. package/esm/utils/cookie.js +352 -0
  27. package/esm/utils/debug.js +521 -0
  28. package/esm/utils/error.js +27 -0
  29. package/esm/utils/index.js +180 -0
  30. package/esm/utils/origin.js +30 -0
  31. package/esm/utils/path-match.js +148 -0
  32. package/esm/utils/protocol.js +157 -0
  33. package/library/api/client.d.ts.map +1 -1
  34. package/library/api/client.js +13 -5
  35. package/library/api/server.d.ts.map +1 -1
  36. package/library/api/server.js +6 -1
  37. package/library/constants/index.d.ts +59 -4
  38. package/library/constants/index.d.ts.map +1 -1
  39. package/library/constants/index.js +67 -9
  40. package/library/constants/messages.d.ts +8 -1
  41. package/library/constants/messages.d.ts.map +1 -1
  42. package/library/constants/messages.js +8 -1
  43. package/library/core/client-server.d.ts +7 -15
  44. package/library/core/client-server.d.ts.map +1 -1
  45. package/library/core/client-server.js +56 -44
  46. package/library/core/client.d.ts +4 -1
  47. package/library/core/client.d.ts.map +1 -1
  48. package/library/core/client.js +74 -31
  49. package/library/core/response.d.ts +21 -3
  50. package/library/core/response.d.ts.map +1 -1
  51. package/library/core/response.js +55 -7
  52. package/library/core/server.d.ts +34 -3
  53. package/library/core/server.d.ts.map +1 -1
  54. package/library/core/server.js +191 -21
  55. package/library/message/channel.d.ts +6 -0
  56. package/library/message/channel.d.ts.map +1 -1
  57. package/library/message/channel.js +2 -1
  58. package/library/message/dispatcher.d.ts +32 -0
  59. package/library/message/dispatcher.d.ts.map +1 -1
  60. package/library/message/dispatcher.js +131 -1
  61. package/library/stream/file-stream.d.ts +4 -0
  62. package/library/stream/file-stream.d.ts.map +1 -1
  63. package/library/stream/file-stream.js +61 -33
  64. package/library/stream/index.d.ts.map +1 -1
  65. package/library/stream/index.js +2 -0
  66. package/library/stream/readable-stream.d.ts +30 -11
  67. package/library/stream/readable-stream.d.ts.map +1 -1
  68. package/library/stream/readable-stream.js +368 -73
  69. package/library/stream/stream-core.d.ts +65 -0
  70. package/library/stream/stream-core.d.ts.map +1 -0
  71. package/library/stream/stream-core.js +211 -0
  72. package/library/stream/types.d.ts +203 -3
  73. package/library/stream/types.d.ts.map +1 -1
  74. package/library/stream/writable-stream.d.ts +59 -13
  75. package/library/stream/writable-stream.d.ts.map +1 -1
  76. package/library/stream/writable-stream.js +647 -197
  77. package/library/types/index.d.ts +70 -4
  78. package/library/types/index.d.ts.map +1 -1
  79. package/library/utils/ack.d.ts +2 -0
  80. package/library/utils/ack.d.ts.map +1 -0
  81. package/library/utils/ack.js +44 -0
  82. package/library/utils/debug.js +1 -1
  83. package/library/utils/index.d.ts +1 -0
  84. package/library/utils/index.d.ts.map +1 -1
  85. package/library/utils/index.js +19 -2
  86. package/library/utils/origin.d.ts +14 -0
  87. package/library/utils/origin.d.ts.map +1 -0
  88. package/library/utils/origin.js +35 -0
  89. package/package.json +30 -7
  90. package/react/README.md +16 -0
  91. package/react/esm/index.js +284 -0
  92. package/react/library/index.d.ts +1 -1
  93. package/react/library/index.d.ts.map +1 -1
  94. package/react/library/index.js +3 -3
  95. package/react/package.json +24 -2
@@ -27,6 +27,7 @@ var _slicedToArray2 = _interopRequireDefault(require("@babel/runtime/helpers/sli
27
27
  var _defineProperty2 = _interopRequireDefault(require("@babel/runtime/helpers/defineProperty"));
28
28
  var _utils = require("../utils");
29
29
  var _pathMatch = require("../utils/path-match");
30
+ var _origin = require("../utils/origin");
30
31
  var _request = require("./request");
31
32
  var _response = require("./response");
32
33
  var _message = require("../message");
@@ -58,12 +59,15 @@ function _objectSpread(e) { for (var r = 1; r < arguments.length; r++) { var t =
58
59
  */
59
60
  class RequestIframeServerImpl {
60
61
  constructor(options) {
61
- var _options$ackTimeout, _options$versionValid;
62
+ var _options$ackTimeout, _options$versionValid, _options$maxConcurren;
62
63
  /** Unique instance ID */
63
64
  (0, _defineProperty2.default)(this, "handlers", new Map());
64
65
  (0, _defineProperty2.default)(this, "middlewares", []);
66
+ (0, _defineProperty2.default)(this, "inFlightByClientKey", new Map());
65
67
  /** Responses waiting for client acknowledgment */
66
68
  (0, _defineProperty2.default)(this, "pendingAcks", new Map());
69
+ /** Pending pings waiting for client PONG (server -> client heartbeat) */
70
+ (0, _defineProperty2.default)(this, "pendingPongs", new Map());
67
71
  /** Pending requests waiting for client stream_start (streamId present) */
68
72
  (0, _defineProperty2.default)(this, "pendingStreamRequests", new Map());
69
73
  /** Stream message handlers (streamId -> handler) for client→server streams */
@@ -76,10 +80,23 @@ class RequestIframeServerImpl {
76
80
  this.id = (options === null || options === void 0 ? void 0 : options.id) || (0, _utils.generateInstanceId)();
77
81
  this.ackTimeout = (_options$ackTimeout = options === null || options === void 0 ? void 0 : options.ackTimeout) !== null && _options$ackTimeout !== void 0 ? _options$ackTimeout : _constants.DefaultTimeout.ACK;
78
82
  this.versionValidator = (_options$versionValid = options === null || options === void 0 ? void 0 : options.versionValidator) !== null && _options$versionValid !== void 0 ? _options$versionValid : _utils.isCompatibleVersion;
83
+ this.maxConcurrentRequestsPerClient = (_options$maxConcurren = options === null || options === void 0 ? void 0 : options.maxConcurrentRequestsPerClient) !== null && _options$maxConcurren !== void 0 ? _options$maxConcurren : Number.POSITIVE_INFINITY;
84
+
85
+ // Build origin validator (incoming messages)
86
+ if (options !== null && options !== void 0 && options.validateOrigin) {
87
+ this.originValidator = (origin, data, context) => options.validateOrigin(origin, data, context);
88
+ } else if (options !== null && options !== void 0 && options.allowedOrigins) {
89
+ var matcher = options.allowedOrigins;
90
+ this.originValidator = origin => (0, _origin.matchOrigin)(origin, matcher);
91
+ }
79
92
 
80
93
  // Get or create shared channel and create dispatcher
81
94
  var channel = (0, _cache.getOrCreateMessageChannel)(options === null || options === void 0 ? void 0 : options.secretKey);
82
95
  this.dispatcher = new _message.MessageDispatcher(channel, _constants.MessageRole.SERVER, this.id);
96
+ this.dispatcher.setAutoAckLimits({
97
+ maxMetaLength: options === null || options === void 0 ? void 0 : options.autoAckMaxMetaLength,
98
+ maxIdLength: options === null || options === void 0 ? void 0 : options.autoAckMaxIdLength
99
+ });
83
100
 
84
101
  // Auto-open by default (unless explicitly set to false)
85
102
  if ((options === null || options === void 0 ? void 0 : options.autoOpen) !== false) {
@@ -87,6 +104,39 @@ class RequestIframeServerImpl {
87
104
  }
88
105
  }
89
106
 
107
+ /**
108
+ * Check whether an incoming message origin is allowed.
109
+ */
110
+ isOriginAllowed(data, context) {
111
+ if (!this.originValidator) return true;
112
+ try {
113
+ return this.originValidator(context.origin, data, context);
114
+ } catch (_unused) {
115
+ return false;
116
+ }
117
+ }
118
+
119
+ /**
120
+ * Build a per-client key used for concurrency limiting.
121
+ * We intentionally include origin to prevent cross-origin collisions.
122
+ */
123
+ getClientKey(origin, creatorId) {
124
+ return `${origin}::${creatorId || 'unknown'}`;
125
+ }
126
+ incInFlight(clientKey) {
127
+ var current = this.inFlightByClientKey.get(clientKey) || 0;
128
+ this.inFlightByClientKey.set(clientKey, current + 1);
129
+ }
130
+ decInFlight(clientKey) {
131
+ var current = this.inFlightByClientKey.get(clientKey) || 0;
132
+ var next = current - 1;
133
+ if (next <= 0) {
134
+ this.inFlightByClientKey.delete(clientKey);
135
+ return;
136
+ }
137
+ this.inFlightByClientKey.set(clientKey, next);
138
+ }
139
+
90
140
  /**
91
141
  * Open message processing (register message handlers)
92
142
  */
@@ -130,22 +180,27 @@ class RequestIframeServerImpl {
130
180
  // Handle PING messages
131
181
  this.unregisterFns.push(this.dispatcher.registerHandler(_constants.MessageType.PING, (data, context) => this.handlePing(data, context), handlerOptions));
132
182
 
133
- // Handle RECEIVED messages (for confirming response delivery)
134
- this.unregisterFns.push(this.dispatcher.registerHandler(_constants.MessageType.RECEIVED, data => this.handleReceived(data), handlerOptions));
183
+ // Handle PONG messages (server -> client heartbeat)
184
+ this.unregisterFns.push(this.dispatcher.registerHandler(_constants.MessageType.PONG, (data, context) => this.handlePong(data, context), handlerOptions));
185
+
186
+ // Handle ACK messages (for confirming response delivery when requireAck === true)
187
+ this.unregisterFns.push(this.dispatcher.registerHandler(_constants.MessageType.ACK, (data, context) => this.handleAck(data, context), handlerOptions));
135
188
 
136
189
  // Handle stream_* messages (client→server stream)
137
190
  this.unregisterFns.push(this.dispatcher.registerHandler(_constants.MessageType.STREAM_START, (data, ctx) => this.handleStreamStart(data, ctx), handlerOptions));
138
- this.unregisterFns.push(this.dispatcher.registerHandler(type => type.startsWith('stream_') && type !== _constants.MessageType.STREAM_START, (data, _context) => this.dispatchStreamMessage(data), handlerOptions));
191
+ this.unregisterFns.push(this.dispatcher.registerHandler(type => type.startsWith('stream_') && type !== _constants.MessageType.STREAM_START, (data, context) => this.dispatchStreamMessage(data, context), handlerOptions));
139
192
  }
140
193
 
141
194
  /** Handle stream_start from client (stream request with streamId) */
142
- handleStreamStart(data, _context) {
195
+ handleStreamStart(data, context) {
143
196
  var _body$chunked;
144
197
  if (data.role !== _constants.MessageRole.CLIENT) return;
198
+ if (!this.isOriginAllowed(data, context)) return;
145
199
  var body = data.body;
146
200
  if (!(body !== null && body !== void 0 && body.streamId)) return;
147
201
  var pending = this.pendingStreamRequests.get(data.requestId);
148
202
  if (!pending || pending.streamId !== body.streamId) return;
203
+ clearTimeout(pending.timeoutId);
149
204
  this.pendingStreamRequests.delete(data.requestId);
150
205
  var targetWindow = pending.targetWindow,
151
206
  targetOrigin = pending.targetOrigin,
@@ -165,6 +220,7 @@ class RequestIframeServerImpl {
165
220
  }
166
221
  };
167
222
  var streamType = body.type || _constants.StreamType.DATA;
223
+ var streamMode = body.mode;
168
224
  var streamChunked = (_body$chunked = body.chunked) !== null && _body$chunked !== void 0 ? _body$chunked : true;
169
225
  var streamMetadata = body.metadata;
170
226
  var req = new _request.ServerRequestImpl(reqData, reqContext, res, pending.params);
@@ -175,6 +231,8 @@ class RequestIframeServerImpl {
175
231
  var fileStream = new _stream.IframeFileReadableStream(body.streamId, data.requestId, streamHandler, {
176
232
  chunked: streamChunked,
177
233
  metadata: streamMetadata,
234
+ secretKey: data.secretKey,
235
+ mode: streamMode,
178
236
  filename: streamMetadata === null || streamMetadata === void 0 ? void 0 : streamMetadata.filename,
179
237
  mimeType: streamMetadata === null || streamMetadata === void 0 ? void 0 : streamMetadata.mimeType,
180
238
  size: streamMetadata === null || streamMetadata === void 0 ? void 0 : streamMetadata.size
@@ -216,8 +274,10 @@ class RequestIframeServerImpl {
216
274
  // Non-file stream
217
275
  var readableStream = new _stream.IframeReadableStream(body.streamId, data.requestId, streamHandler, {
218
276
  type: streamType,
277
+ mode: streamMode,
219
278
  chunked: streamChunked,
220
- metadata: streamMetadata
279
+ metadata: streamMetadata,
280
+ secretKey: data.secretKey
221
281
  });
222
282
  req.body = undefined;
223
283
  req.stream = readableStream;
@@ -240,11 +300,17 @@ class RequestIframeServerImpl {
240
300
  }
241
301
  });
242
302
  }
243
- dispatchStreamMessage(data) {
303
+ dispatchStreamMessage(data, context) {
304
+ if (!this.isOriginAllowed(data, context)) return;
244
305
  var body = data.body;
245
306
  if (!(body !== null && body !== void 0 && body.streamId)) return;
246
307
  var handler = this.streamHandlers.get(body.streamId);
247
308
  if (handler) {
309
+ // Mark as accepted/handled so MessageDispatcher can auto-ack when requireAck === true
310
+ if (!context.handledBy) {
311
+ context.accepted = true;
312
+ context.handledBy = this.id;
313
+ }
248
314
  var messageType = data.type.replace('stream_', '');
249
315
  handler(_objectSpread(_objectSpread({}, body), {}, {
250
316
  type: messageType
@@ -276,20 +342,67 @@ class RequestIframeServerImpl {
276
342
  */
277
343
  handlePing(data, context) {
278
344
  if (!context.source) return;
345
+ if (!this.isOriginAllowed(data, context)) return;
346
+
347
+ /**
348
+ * Only allow one server instance to respond.
349
+ * This is important when multiple server instances share the same channel.
350
+ */
351
+ if (!context.handledBy) {
352
+ // Mark as accepted so MessageDispatcher can auto-send ACK when requireAck === true
353
+ context.accepted = true;
354
+ context.handledBy = this.id;
355
+ }
279
356
 
280
357
  // Window check is handled in MessageDispatcher
281
358
  this.dispatcher.sendMessage(context.source, context.origin, _constants.MessageType.PONG, data.requestId);
282
359
  }
360
+ handlePong(data, context) {
361
+ if (!this.isOriginAllowed(data, context)) return;
362
+ var pending = this.pendingPongs.get(data.requestId);
363
+ if (pending) {
364
+ if (!context.handledBy) {
365
+ context.accepted = true;
366
+ context.handledBy = this.id;
367
+ }
368
+ clearTimeout(pending.timeoutId);
369
+ this.pendingPongs.delete(data.requestId);
370
+ pending.resolve(true);
371
+ }
372
+ }
373
+ pingClient(targetWindow, targetOrigin, targetClientId) {
374
+ var requestId = (0, _utils.generateRequestId)();
375
+ return new Promise(resolve => {
376
+ var timeoutId = setTimeout(() => {
377
+ this.pendingPongs.delete(requestId);
378
+ resolve(false);
379
+ }, this.ackTimeout);
380
+ this.pendingPongs.set(requestId, {
381
+ resolve,
382
+ timeoutId
383
+ });
384
+ // Window check is handled in MessageDispatcher
385
+ this.dispatcher.sendMessage(targetWindow, targetOrigin, _constants.MessageType.PING, requestId, {
386
+ requireAck: true,
387
+ targetId: targetClientId
388
+ });
389
+ });
390
+ }
283
391
 
284
392
  /**
285
- * Handle received acknowledgment
393
+ * Handle ACK (receipt confirmation for responses when requireAck === true).
286
394
  */
287
- handleReceived(data) {
395
+ handleAck(data, context) {
396
+ if (!this.isOriginAllowed(data, context)) return;
288
397
  var pending = this.pendingAcks.get(data.requestId);
289
398
  if (pending) {
399
+ // Best-effort: prevent other server instances from also resolving
400
+ if (!context.handledBy) {
401
+ context.handledBy = this.id;
402
+ }
290
403
  clearTimeout(pending.timeoutId);
291
404
  this.pendingAcks.delete(data.requestId);
292
- pending.resolve(true);
405
+ pending.resolve(true, data.ack);
293
406
  }
294
407
  }
295
408
 
@@ -304,6 +417,7 @@ class RequestIframeServerImpl {
304
417
  }
305
418
  handleRequestError(res, targetWindow, targetOrigin, data, err) {
306
419
  if (!res._sent) {
420
+ res._markSent();
307
421
  /**
308
422
  * Use INTERNAL_SERVER_ERROR (500) for handler errors unless a different error status code was explicitly set.
309
423
  * If statusCode is still the default OK (200), override it to INTERNAL_SERVER_ERROR.
@@ -328,6 +442,7 @@ class RequestIframeServerImpl {
328
442
  if (!res._sent && result !== undefined) {
329
443
  res.send(result);
330
444
  } else if (!res._sent) {
445
+ res._markSent();
331
446
  this.dispatcher.sendMessage(targetWindow, targetOrigin, _constants.MessageType.ERROR, data.requestId, {
332
447
  path: data.path,
333
448
  error: {
@@ -392,6 +507,7 @@ class RequestIframeServerImpl {
392
507
  // If targetId is specified, only process if it matches this server's id
393
508
  if (!data.path || data.targetId && data.targetId !== this.id) return;
394
509
  if (!context.source) return;
510
+ if (!this.isOriginAllowed(data, context)) return;
395
511
 
396
512
  // If message has already been handled by another server instance, skip processing
397
513
  if (context.handledBy) {
@@ -425,25 +541,51 @@ class RequestIframeServerImpl {
425
541
  }
426
542
  var handlerFn = handlerMatch.handler,
427
543
  params = handlerMatch.params;
544
+ var clientKey = this.getClientKey(targetOrigin, data.creatorId);
545
+ if (Number.isFinite(this.maxConcurrentRequestsPerClient)) {
546
+ var inFlight = this.inFlightByClientKey.get(clientKey) || 0;
547
+ if (inFlight >= this.maxConcurrentRequestsPerClient) {
548
+ // Prevent other server instances from also responding
549
+ context.handledBy = this.id;
550
+ this.dispatcher.sendMessage(targetWindow, targetOrigin, _constants.MessageType.ERROR, data.requestId, {
551
+ path: data.path,
552
+ error: {
553
+ message: (0, _constants.formatMessage)(_constants.Messages.TOO_MANY_REQUESTS, this.maxConcurrentRequestsPerClient),
554
+ code: _constants.ErrorCode.TOO_MANY_REQUESTS
555
+ },
556
+ status: _constants.HttpStatus.TOO_MANY_REQUESTS,
557
+ statusText: _constants.HttpStatusText[_constants.HttpStatus.TOO_MANY_REQUESTS],
558
+ requireAck: data.requireAck,
559
+ ack: data.ack,
560
+ targetId: data.creatorId
561
+ });
562
+ return;
563
+ }
564
+ }
565
+ this.incInFlight(clientKey);
566
+
567
+ // Mark as accepted so MessageDispatcher can auto-send ACK (delivery confirmation)
568
+ context.accepted = true;
428
569
 
429
570
  // Mark message as handled by this server instance to prevent other server instances from processing it
430
571
  context.handledBy = this.id;
431
572
 
432
- // Send ACK immediately via dispatcher
433
- // Use request's creatorId as targetId to route back to the correct client
434
- // Window check is handled in MessageDispatcher
435
- this.dispatcher.sendMessage(targetWindow, targetOrigin, _constants.MessageType.ACK, data.requestId, {
436
- path: data.path,
437
- targetId: data.creatorId
438
- });
439
-
440
573
  // Create response object with channel reference
441
574
  // Pass request's creatorId as targetId so responses are routed back to the correct client
442
- var res = new _response.ServerResponseImpl(data.requestId, data.path || '', data.secretKey, targetWindow, targetOrigin, this.dispatcher.getChannel(), this.id, data.creatorId);
575
+ var res = new _response.ServerResponseImpl(data.requestId, data.path || '', data.secretKey, targetWindow, targetOrigin, this.dispatcher.getChannel(), this.id, data.creatorId, {
576
+ registerStreamHandler: (streamId, handler) => {
577
+ this.streamHandlers.set(streamId, handler);
578
+ },
579
+ unregisterStreamHandler: streamId => {
580
+ this.streamHandlers.delete(streamId);
581
+ },
582
+ heartbeat: () => this.pingClient(targetWindow, targetOrigin, data.creatorId),
583
+ onSent: () => this.decInFlight(clientKey)
584
+ });
443
585
 
444
586
  // Register callback waiting for client acknowledgment
445
- this.registerPendingAck(data.requestId, received => {
446
- res._triggerAck(received);
587
+ this.registerPendingAck(data.requestId, (received, ack) => {
588
+ res._triggerAck(received, ack);
447
589
  }, () => {
448
590
  res._triggerAck(false);
449
591
  });
@@ -452,10 +594,32 @@ class RequestIframeServerImpl {
452
594
  // If streamId is present, this is a stream request
453
595
  var streamId = data.streamId;
454
596
  if (streamId) {
597
+ var streamStartTimeout = this.ackTimeout;
598
+ var timeoutId = setTimeout(() => {
599
+ var pending = this.pendingStreamRequests.get(data.requestId);
600
+ if (!pending) return;
601
+ this.pendingStreamRequests.delete(data.requestId);
602
+ if (!pending.res._sent) {
603
+ pending.res._markSent();
604
+ this.dispatcher.sendMessage(pending.targetWindow, pending.targetOrigin, _constants.MessageType.ERROR, pending.requestId, {
605
+ path: pending.path,
606
+ error: {
607
+ message: (0, _constants.formatMessage)(_constants.Messages.STREAM_START_TIMEOUT, streamStartTimeout),
608
+ code: _constants.ErrorCode.STREAM_START_TIMEOUT
609
+ },
610
+ status: _constants.HttpStatus.REQUEST_TIMEOUT,
611
+ statusText: _constants.HttpStatusText[_constants.HttpStatus.REQUEST_TIMEOUT],
612
+ requireAck: pending.data.requireAck,
613
+ ack: pending.data.ack,
614
+ targetId: pending.data.creatorId
615
+ });
616
+ }
617
+ }, streamStartTimeout);
455
618
  this.pendingStreamRequests.set(data.requestId, {
456
619
  path: data.path || '',
457
620
  requestId: data.requestId,
458
621
  streamId,
622
+ timeoutId,
459
623
  handlerFn,
460
624
  targetWindow,
461
625
  targetOrigin,
@@ -598,10 +762,16 @@ class RequestIframeServerImpl {
598
762
  // Clean up pending
599
763
  this.pendingAcks.forEach(pending => clearTimeout(pending.timeoutId));
600
764
  this.pendingAcks.clear();
765
+ this.pendingPongs.forEach(pending => clearTimeout(pending.timeoutId));
766
+ this.pendingPongs.clear();
767
+ this.pendingStreamRequests.forEach(pending => clearTimeout(pending.timeoutId));
768
+ this.pendingStreamRequests.clear();
769
+ this.inFlightByClientKey.clear();
601
770
 
602
771
  // Clean up handlers
603
772
  this.handlers.clear();
604
773
  this.middlewares.length = 0;
774
+ this.streamHandlers.clear();
605
775
 
606
776
  // Destroy dispatcher and release channel reference
607
777
  this.dispatcher.destroy();
@@ -7,6 +7,12 @@ export interface MessageContext {
7
7
  source?: Window;
8
8
  /** Origin of the message */
9
9
  origin: string;
10
+ /**
11
+ * Whether the receiver accepted this message for processing.
12
+ * - Used by MessageDispatcher to decide whether it should send an ACK automatically.
13
+ * - Should be set by high-level handlers once they确定会处理该消息(例如:路由匹配到 handler,或找到 pending request)。
14
+ */
15
+ accepted?: boolean;
10
16
  /** ID of the instance that handled this message (if handled) */
11
17
  handledBy?: string;
12
18
  }
@@ -1 +1 @@
1
- {"version":3,"file":"channel.d.ts","sourceRoot":"","sources":["../../src/message/channel.ts"],"names":[],"mappings":"AAAA,OAAO,EACL,eAAe,EAChB,MAAM,UAAU,CAAC;AAGlB;;GAEG;AACH,MAAM,WAAW,cAAc;IAC7B,kDAAkD;IAClD,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,4BAA4B;IAC5B,MAAM,EAAE,MAAM,CAAC;IACf,gEAAgE;IAChE,SAAS,CAAC,EAAE,MAAM,CAAC;CACpB;AAED;;GAEG;AACH,MAAM,MAAM,eAAe,GAAG,CAAC,IAAI,EAAE,eAAe,EAAE,OAAO,EAAE,cAAc,KAAK,IAAI,CAAC;AAEvF;;GAEG;AACH,eAAO,MAAM,WAAW;IACtB,+BAA+B;;CAEvB,CAAC;AAEX;;GAEG;AACH,MAAM,MAAM,WAAW,GAAG,OAAO,WAAW,CAAC,MAAM,OAAO,WAAW,CAAC,CAAC;AAEvE;;;;;;;;;;;;GAYG;AACH,qBAAa,cAAc;IACzB,8CAA8C;IAC9C,SAAgB,IAAI,EAAE,WAAW,CAAC;IAElC,uCAAuC;IACvC,SAAgB,SAAS,CAAC,EAAE,MAAM,CAAC;IAEnC,8DAA8D;IAC9D,OAAO,CAAC,SAAS,CAAmC;IAEpD,gDAAgD;IAChD,OAAO,CAAC,QAAQ,CAAC,cAAc,CAAgC;IAE/D,6CAA6C;IAC7C,OAAO,CAAC,QAAQ,CAAK;gBAEF,SAAS,CAAC,EAAE,MAAM,EAAE,IAAI,GAAE,WAAsC;IAOnF;;;OAGG;IACI,WAAW,CAAC,QAAQ,EAAE,eAAe,GAAG,IAAI;IAInD;;OAEG;IACI,cAAc,CAAC,QAAQ,EAAE,eAAe,GAAG,IAAI;IAItD;;OAEG;IACI,MAAM,IAAI,IAAI;IAIrB;;;OAGG;IACI,OAAO,IAAI,MAAM;IAIxB;;OAEG;IACI,WAAW,IAAI,MAAM;IAI5B;;;OAGG;IACH,OAAO,CAAC,cAAc;IAOtB;;OAEG;IACH,OAAO,CAAC,SAAS;IA4BjB;;;;;OAKG;IACI,IAAI,CAAC,MAAM,EAAE,MAAM,EAAE,OAAO,EAAE,eAAe,EAAE,YAAY,GAAE,MAAY,GAAG,OAAO;IAQ1F;;;;;;;OAOG;IACI,WAAW,CAChB,MAAM,EAAE,MAAM,EACd,YAAY,EAAE,MAAM,EACpB,IAAI,EAAE,eAAe,CAAC,MAAM,CAAC,EAC7B,SAAS,EAAE,MAAM,EACjB,IAAI,CAAC,EAAE,OAAO,CAAC,IAAI,CAAC,eAAe,EAAE,mBAAmB,GAAG,MAAM,GAAG,WAAW,GAAG,WAAW,GAAG,MAAM,CAAC,CAAC,GACvG,OAAO;IAQV;;OAEG;IACI,UAAU,CAAC,IAAI,EAAE,MAAM,GAAG,MAAM;IAIvC;;OAEG;IACI,OAAO,IAAI,IAAI;CAIvB"}
1
+ {"version":3,"file":"channel.d.ts","sourceRoot":"","sources":["../../src/message/channel.ts"],"names":[],"mappings":"AAAA,OAAO,EACL,eAAe,EAChB,MAAM,UAAU,CAAC;AAIlB;;GAEG;AACH,MAAM,WAAW,cAAc;IAC7B,kDAAkD;IAClD,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,4BAA4B;IAC5B,MAAM,EAAE,MAAM,CAAC;IACf;;;;OAIG;IACH,QAAQ,CAAC,EAAE,OAAO,CAAC;IACnB,gEAAgE;IAChE,SAAS,CAAC,EAAE,MAAM,CAAC;CACpB;AAED;;GAEG;AACH,MAAM,MAAM,eAAe,GAAG,CAAC,IAAI,EAAE,eAAe,EAAE,OAAO,EAAE,cAAc,KAAK,IAAI,CAAC;AAEvF;;GAEG;AACH,eAAO,MAAM,WAAW;IACtB,+BAA+B;;CAEvB,CAAC;AAEX;;GAEG;AACH,MAAM,MAAM,WAAW,GAAG,OAAO,WAAW,CAAC,MAAM,OAAO,WAAW,CAAC,CAAC;AAEvE;;;;;;;;;;;;GAYG;AACH,qBAAa,cAAc;IACzB,8CAA8C;IAC9C,SAAgB,IAAI,EAAE,WAAW,CAAC;IAElC,uCAAuC;IACvC,SAAgB,SAAS,CAAC,EAAE,MAAM,CAAC;IAEnC,8DAA8D;IAC9D,OAAO,CAAC,SAAS,CAAmC;IAEpD,gDAAgD;IAChD,OAAO,CAAC,QAAQ,CAAC,cAAc,CAAgC;IAE/D,6CAA6C;IAC7C,OAAO,CAAC,QAAQ,CAAK;gBAEF,SAAS,CAAC,EAAE,MAAM,EAAE,IAAI,GAAE,WAAsC;IAOnF;;;OAGG;IACI,WAAW,CAAC,QAAQ,EAAE,eAAe,GAAG,IAAI;IAInD;;OAEG;IACI,cAAc,CAAC,QAAQ,EAAE,eAAe,GAAG,IAAI;IAItD;;OAEG;IACI,MAAM,IAAI,IAAI;IAIrB;;;OAGG;IACI,OAAO,IAAI,MAAM;IAIxB;;OAEG;IACI,WAAW,IAAI,MAAM;IAI5B;;;OAGG;IACH,OAAO,CAAC,cAAc;IAOtB;;OAEG;IACH,OAAO,CAAC,SAAS;IA4BjB;;;;;OAKG;IACI,IAAI,CAAC,MAAM,EAAE,MAAM,EAAE,OAAO,EAAE,eAAe,EAAE,YAAY,GAAE,MAA2B,GAAG,OAAO;IAQzG;;;;;;;OAOG;IACI,WAAW,CAChB,MAAM,EAAE,MAAM,EACd,YAAY,EAAE,MAAM,EACpB,IAAI,EAAE,eAAe,CAAC,MAAM,CAAC,EAC7B,SAAS,EAAE,MAAM,EACjB,IAAI,CAAC,EAAE,OAAO,CAAC,IAAI,CAAC,eAAe,EAAE,mBAAmB,GAAG,MAAM,GAAG,WAAW,GAAG,WAAW,GAAG,MAAM,CAAC,CAAC,GACvG,OAAO;IAQV;;OAEG;IACI,UAAU,CAAC,IAAI,EAAE,MAAM,GAAG,MAAM;IAIvC;;OAEG;IACI,OAAO,IAAI,IAAI;CAIvB"}
@@ -13,6 +13,7 @@ require("core-js/modules/web.dom-collections.for-each.js");
13
13
  require("core-js/modules/web.dom-collections.iterator.js");
14
14
  var _defineProperty2 = _interopRequireDefault(require("@babel/runtime/helpers/defineProperty"));
15
15
  var _utils = require("../utils");
16
+ var _constants = require("../constants");
16
17
  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; }
17
18
  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; }
18
19
  /**
@@ -147,7 +148,7 @@ class MessageChannel {
147
148
  * @param message message data (already formatted as PostMessageData)
148
149
  * @param targetOrigin target origin (defaults to '*')
149
150
  */
150
- send(target, message, targetOrigin = '*') {
151
+ send(target, message, targetOrigin = _constants.OriginConstant.ANY) {
151
152
  if (!(0, _utils.isWindowAvailable)(target)) {
152
153
  return false;
153
154
  }
@@ -52,6 +52,15 @@ export declare class MessageDispatcher {
52
52
  private readonly instanceId?;
53
53
  /** Underlying message channel */
54
54
  private readonly channel;
55
+ private autoAckMaxMetaLength;
56
+ private autoAckMaxIdLength;
57
+ /**
58
+ * Fallback target for sending auto-ack messages when MessageEvent.source is unavailable.
59
+ * - In real browser postMessage events, `source` should normally exist.
60
+ * - This is primarily used for unit tests or edge environments that synthesize MessageEvent without `source`.
61
+ */
62
+ private fallbackTargetWindow?;
63
+ private fallbackTargetOrigin;
55
64
  /** Message handler list */
56
65
  private readonly handlers;
57
66
  /** Message receiver callback (bound to this) */
@@ -59,6 +68,10 @@ export declare class MessageDispatcher {
59
68
  /** Reference count (for determining if can be destroyed when cached) */
60
69
  private refCount;
61
70
  constructor(channel: MessageChannel, role: MessageRoleValue, instanceId?: string);
71
+ /**
72
+ * Set fallback target for outgoing auto-ack messages.
73
+ */
74
+ setFallbackTarget(targetWindow: Window, targetOrigin?: string): void;
62
75
  /**
63
76
  * Increment reference count
64
77
  */
@@ -88,6 +101,25 @@ export declare class MessageDispatcher {
88
101
  * Dispatch message to matching handlers
89
102
  */
90
103
  private dispatchMessage;
104
+ /**
105
+ * Auto-ack logic (generalized requireAck workflow)
106
+ *
107
+ * Notes:
108
+ * - This is intentionally conservative: it only runs after the message is marked as handled
109
+ * (via `context.handledBy`) to avoid acknowledging messages that no consumer will process.
110
+ * - For backward compatibility:
111
+ * - REQUEST defaults to requiring ACK unless `requireAck === false`
112
+ * - Other message types only ack when `requireAck === true`
113
+ */
114
+ private tryAutoAck;
115
+ /**
116
+ * Limit echoed ack payload size for auto-ack replies.
117
+ *
118
+ * We only echo a fixed shape `{ id, meta?: string }`:
119
+ * - If meta is too long, we drop meta and only echo `{ id }`.
120
+ * - If id is missing or too long, omit `ack` field.
121
+ */
122
+ private getAutoAckEchoPayload;
91
123
  /**
92
124
  * Check if message type matches
93
125
  */
@@ -1 +1 @@
1
- {"version":3,"file":"dispatcher.d.ts","sourceRoot":"","sources":["../../src/message/dispatcher.ts"],"names":[],"mappings":"AAAA,OAAO,EAAe,gBAAgB,EAAE,MAAM,cAAc,CAAC;AAC7D,OAAO,EACL,eAAe,EAChB,MAAM,UAAU,CAAC;AAElB,OAAO,EAAE,cAAc,EAAE,KAAK,cAAc,EAAE,MAAM,WAAW,CAAC;AAEhE;;GAEG;AACH,MAAM,MAAM,gBAAgB,GAAG,CAAC,IAAI,EAAE,eAAe,EAAE,OAAO,EAAE,cAAc,KAAK,IAAI,CAAC;AAExF;;;;;GAKG;AACH,MAAM,MAAM,kBAAkB,GAAG,MAAM,GAAG,MAAM,GAAG,CAAC,CAAC,IAAI,EAAE,MAAM,KAAK,OAAO,CAAC,CAAC;AAE/E;;;;GAIG;AACH,MAAM,MAAM,gBAAgB,GAAG,CAAC,OAAO,EAAE,MAAM,KAAK,OAAO,CAAC;AAE5D;;GAEG;AACH,MAAM,WAAW,cAAc;IAC7B,4DAA4D;IAC5D,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,2EAA2E;IAC3E,gBAAgB,CAAC,EAAE,gBAAgB,CAAC;IACpC,4DAA4D;IAC5D,cAAc,CAAC,EAAE,CAAC,IAAI,EAAE,eAAe,EAAE,OAAO,EAAE,cAAc,EAAE,OAAO,EAAE,MAAM,KAAK,IAAI,CAAC;CAC5F;AAkBD;;;;;;;;;;;GAWG;AACH,qBAAa,iBAAiB;IAC5B,uCAAuC;IACvC,SAAgB,SAAS,CAAC,EAAE,MAAM,CAAC;IAEnC,mBAAmB;IACnB,SAAgB,IAAI,EAAE,cAAc,CAAC,MAAM,CAAC,CAAC;IAE7C,qDAAqD;IACrD,OAAO,CAAC,QAAQ,CAAC,IAAI,CAAmB;IAExC,iEAAiE;IACjE,OAAO,CAAC,QAAQ,CAAC,UAAU,CAAC,CAAS;IAErC,iCAAiC;IACjC,OAAO,CAAC,QAAQ,CAAC,OAAO,CAAiB;IAEzC,2BAA2B;IAC3B,OAAO,CAAC,QAAQ,CAAC,QAAQ,CAA6B;IAEtD,gDAAgD;IAChD,OAAO,CAAC,QAAQ,CAAC,aAAa,CAA2D;IAEzF,wEAAwE;IACxE,OAAO,CAAC,QAAQ,CAAK;gBAEF,OAAO,EAAE,cAAc,EAAE,IAAI,EAAE,gBAAgB,EAAE,UAAU,CAAC,EAAE,MAAM;IAkBvF;;OAEG;IACI,MAAM,IAAI,IAAI;IAIrB;;;OAGG;IACI,OAAO,IAAI,MAAM;IAIxB;;OAEG;IACI,WAAW,IAAI,MAAM;IAM5B;;;;;;OAMG;IACI,eAAe,CACpB,OAAO,EAAE,kBAAkB,EAC3B,OAAO,EAAE,gBAAgB,EACzB,OAAO,CAAC,EAAE,cAAc,GAAG,MAAM,GAChC,MAAM,IAAI;IAyBb;;OAEG;IACI,iBAAiB,CAAC,OAAO,EAAE,gBAAgB,GAAG,IAAI;IAOzD;;OAEG;IACH,OAAO,CAAC,eAAe;IAkDvB;;OAEG;IACH,OAAO,CAAC,SAAS;IAejB;;;;;OAKG;IACI,IAAI,CAAC,MAAM,EAAE,MAAM,EAAE,OAAO,EAAE,eAAe,EAAE,YAAY,GAAE,MAAY,GAAG,OAAO;IAW1F;;;;;;;OAOG;IACI,WAAW,CAChB,MAAM,EAAE,MAAM,EACd,YAAY,EAAE,MAAM,EACpB,IAAI,EAAE,eAAe,CAAC,MAAM,CAAC,EAC7B,SAAS,EAAE,MAAM,EACjB,IAAI,CAAC,EAAE,OAAO,CAAC,IAAI,CAAC,eAAe,EAAE,mBAAmB,GAAG,MAAM,GAAG,WAAW,GAAG,WAAW,GAAG,MAAM,GAAG,WAAW,CAAC,CAAC,GACrH,OAAO;IAcV;;OAEG;IACI,UAAU,CAAC,IAAI,EAAE,MAAM,GAAG,MAAM;IAIvC;;OAEG;IACI,UAAU,IAAI,cAAc;IAInC;;OAEG;IACI,OAAO,IAAI,IAAI;CAIvB"}
1
+ {"version":3,"file":"dispatcher.d.ts","sourceRoot":"","sources":["../../src/message/dispatcher.ts"],"names":[],"mappings":"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"}
@@ -22,6 +22,7 @@ require("core-js/modules/es.regexp.to-string.js");
22
22
  var _defineProperty2 = _interopRequireDefault(require("@babel/runtime/helpers/defineProperty"));
23
23
  var _constants = require("../constants");
24
24
  var _utils = require("../utils");
25
+ var _ack = require("../utils/ack");
25
26
  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; }
26
27
  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; }
27
28
  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; } } }; }
@@ -71,6 +72,9 @@ class MessageDispatcher {
71
72
  /** Role of this dispatcher ('client' or 'server') */
72
73
  /** Instance ID of the client/server that owns this dispatcher */
73
74
  /** Underlying message channel */
75
+ (0, _defineProperty2.default)(this, "autoAckMaxMetaLength", _constants.AutoAckConstant.MAX_META_LENGTH);
76
+ (0, _defineProperty2.default)(this, "autoAckMaxIdLength", _constants.AutoAckConstant.MAX_ID_LENGTH);
77
+ (0, _defineProperty2.default)(this, "fallbackTargetOrigin", _constants.OriginConstant.ANY);
74
78
  /** Message handler list */
75
79
  (0, _defineProperty2.default)(this, "handlers", []);
76
80
  /** Reference count (for determining if can be destroyed when cached) */
@@ -90,6 +94,29 @@ class MessageDispatcher {
90
94
  this.channel.addReceiver(this.boundReceiver);
91
95
  }
92
96
 
97
+ /**
98
+ * Set fallback target for outgoing auto-ack messages.
99
+ */
100
+ setFallbackTarget(targetWindow, targetOrigin = _constants.OriginConstant.ANY) {
101
+ this.fallbackTargetWindow = targetWindow;
102
+ this.fallbackTargetOrigin = targetOrigin;
103
+ }
104
+
105
+ /**
106
+ * Configure auto-ack echo limits (advanced/internal).
107
+ *
108
+ * @internal
109
+ */
110
+ setAutoAckLimits(limits) {
111
+ if (!limits || typeof limits !== 'object') return;
112
+ if (typeof limits.maxMetaLength === 'number' && Number.isFinite(limits.maxMetaLength) && limits.maxMetaLength >= 0) {
113
+ this.autoAckMaxMetaLength = limits.maxMetaLength;
114
+ }
115
+ if (typeof limits.maxIdLength === 'number' && Number.isFinite(limits.maxIdLength) && limits.maxIdLength >= 0) {
116
+ this.autoAckMaxIdLength = limits.maxIdLength;
117
+ }
118
+ }
119
+
93
120
  // ==================== Reference Counting ====================
94
121
 
95
122
  /**
@@ -177,6 +204,43 @@ class MessageDispatcher {
177
204
  }
178
205
  var type = data.type;
179
206
  var version = (0, _utils.getProtocolVersion)(data);
207
+
208
+ /**
209
+ * Auto-ack state for this incoming message.
210
+ * - We intentionally couple this to `context.handledBy` as the "accepted/handled" signal.
211
+ * - For some message types we only ack if they are truly handled (e.g. response requireAck),
212
+ * so we avoid incorrectly acknowledging messages when there is no pending consumer.
213
+ *
214
+ * Implementation note:
215
+ * We avoid using Proxy for compatibility and instead hook the `handledBy` property
216
+ * with a setter so handlers can trigger the ack immediately when they "accept" a message.
217
+ */
218
+ var autoAckState = {
219
+ sent: false
220
+ };
221
+ var originalHandledBy = context.handledBy;
222
+ var handledByValue = originalHandledBy;
223
+ try {
224
+ Object.defineProperty(context, 'handledBy', {
225
+ configurable: true,
226
+ enumerable: true,
227
+ get() {
228
+ return handledByValue;
229
+ },
230
+ set: value => {
231
+ handledByValue = value;
232
+ if (value && !autoAckState.sent) {
233
+ autoAckState.sent = true;
234
+ this.tryAutoAck(data, context);
235
+ }
236
+ }
237
+ });
238
+ } catch (_unused) {
239
+ /**
240
+ * In very rare cases `defineProperty` may fail (frozen object).
241
+ * We still proceed without auto-ack; handlers will continue to work as before.
242
+ */
243
+ }
180
244
  var _iterator = _createForOfIteratorHelper(this.handlers),
181
245
  _step;
182
246
  try {
@@ -214,6 +278,72 @@ class MessageDispatcher {
214
278
  }
215
279
  }
216
280
 
281
+ /**
282
+ * Auto-ack logic (generalized requireAck workflow)
283
+ *
284
+ * Notes:
285
+ * - This is intentionally conservative: it only runs after the message is marked as handled
286
+ * (via `context.handledBy`) to avoid acknowledging messages that no consumer will process.
287
+ * - For backward compatibility:
288
+ * - REQUEST defaults to requiring ACK unless `requireAck === false`
289
+ * - Other message types only ack when `requireAck === true`
290
+ */
291
+ tryAutoAck(data, context) {
292
+ var _context$source;
293
+ var targetWindow = (_context$source = context.source) !== null && _context$source !== void 0 ? _context$source : this.fallbackTargetWindow;
294
+ if (!targetWindow) return;
295
+ var targetOrigin = context.source ? context.origin : this.fallbackTargetOrigin || context.origin;
296
+ var type = data.type;
297
+
298
+ // Don't auto-ack ack messages (avoid loops)
299
+ if (type === _constants.MessageType.ACK) return;
300
+
301
+ /**
302
+ * ACK-only requireAck workflow (no compatibility guarantees):
303
+ * - For any message with `requireAck === true`, once the message is accepted/handled
304
+ * (via `context.accepted === true` + `context.handledBy` setter hook),
305
+ * we reply with `ack`.
306
+ *
307
+ * This unifies:
308
+ * - request delivery confirmation
309
+ * - response receipt confirmation
310
+ * - stream frame delivery confirmation (e.g. stream_data per-frame ack)
311
+ */
312
+ if (data.requireAck === true && context.accepted === true) {
313
+ var ack = this.getAutoAckEchoPayload(data.ack);
314
+ this.sendMessage(targetWindow, targetOrigin, _constants.MessageType.ACK, data.requestId, {
315
+ path: data.path,
316
+ targetId: data.creatorId,
317
+ ack
318
+ });
319
+ }
320
+ }
321
+
322
+ /**
323
+ * Limit echoed ack payload size for auto-ack replies.
324
+ *
325
+ * We only echo a fixed shape `{ id, meta?: string }`:
326
+ * - If meta is too long, we drop meta and only echo `{ id }`.
327
+ * - If id is missing or too long, omit `ack` field.
328
+ */
329
+ getAutoAckEchoPayload(rawAck) {
330
+ if (rawAck === undefined) return undefined;
331
+ var id = (0, _ack.getAckId)(rawAck);
332
+ if (id === undefined) return undefined;
333
+ if (typeof id === 'string' && id.length > this.autoAckMaxIdLength) return undefined;
334
+ var meta = (0, _ack.getAckMeta)(rawAck);
335
+ if (meta === undefined) return {
336
+ id
337
+ };
338
+ if (meta.length > this.autoAckMaxMetaLength) return {
339
+ id
340
+ };
341
+ return {
342
+ id,
343
+ meta
344
+ };
345
+ }
346
+
217
347
  /**
218
348
  * Check if message type matches
219
349
  */
@@ -238,7 +368,7 @@ class MessageDispatcher {
238
368
  * @param message message data (already formatted as PostMessageData)
239
369
  * @param targetOrigin target origin (defaults to '*')
240
370
  */
241
- send(target, message, targetOrigin = '*') {
371
+ send(target, message, targetOrigin = _constants.OriginConstant.ANY) {
242
372
  // Automatically set role and creatorId if not already set (for backward compatibility)
243
373
  if (message.role === undefined) {
244
374
  message.role = this.role;
@@ -32,6 +32,10 @@ export declare class IframeFileReadableStream extends IframeReadableStream<Uint8
32
32
  * Override merge method to merge all Uint8Array chunks
33
33
  */
34
34
  protected mergeChunks(): Uint8Array;
35
+ /**
36
+ * Read all data as a merged Uint8Array (file stream default behavior)
37
+ */
38
+ read(): Promise<Uint8Array>;
35
39
  /**
36
40
  * Read as Blob
37
41
  */