request-iframe 0.1.0 → 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 (71) hide show
  1. package/README.CN.md +174 -22
  2. package/README.md +166 -22
  3. package/esm/api/client.js +6 -5
  4. package/esm/api/server.js +3 -1
  5. package/esm/constants/index.js +38 -6
  6. package/esm/constants/messages.js +3 -1
  7. package/esm/core/client-server.js +8 -43
  8. package/esm/core/client.js +7 -7
  9. package/esm/core/response.js +16 -8
  10. package/esm/core/server.js +18 -9
  11. package/esm/message/channel.js +2 -1
  12. package/esm/message/dispatcher.js +63 -25
  13. package/esm/stream/readable-stream.js +57 -18
  14. package/esm/stream/stream-core.js +115 -2
  15. package/esm/stream/writable-stream.js +281 -27
  16. package/esm/utils/ack.js +36 -0
  17. package/esm/utils/debug.js +1 -1
  18. package/esm/utils/index.js +5 -3
  19. package/esm/utils/origin.js +3 -1
  20. package/library/api/client.d.ts.map +1 -1
  21. package/library/api/client.js +5 -4
  22. package/library/api/server.d.ts.map +1 -1
  23. package/library/api/server.js +3 -1
  24. package/library/constants/index.d.ts +36 -5
  25. package/library/constants/index.d.ts.map +1 -1
  26. package/library/constants/index.js +41 -8
  27. package/library/constants/messages.d.ts +3 -1
  28. package/library/constants/messages.d.ts.map +1 -1
  29. package/library/constants/messages.js +3 -1
  30. package/library/core/client-server.d.ts +4 -13
  31. package/library/core/client-server.d.ts.map +1 -1
  32. package/library/core/client-server.js +7 -42
  33. package/library/core/client.d.ts.map +1 -1
  34. package/library/core/client.js +6 -6
  35. package/library/core/response.d.ts +2 -2
  36. package/library/core/response.d.ts.map +1 -1
  37. package/library/core/response.js +15 -7
  38. package/library/core/server.d.ts +6 -2
  39. package/library/core/server.d.ts.map +1 -1
  40. package/library/core/server.js +18 -9
  41. package/library/message/channel.d.ts +1 -1
  42. package/library/message/channel.d.ts.map +1 -1
  43. package/library/message/channel.js +2 -1
  44. package/library/message/dispatcher.d.ts +10 -0
  45. package/library/message/dispatcher.d.ts.map +1 -1
  46. package/library/message/dispatcher.js +62 -24
  47. package/library/stream/readable-stream.d.ts.map +1 -1
  48. package/library/stream/readable-stream.js +56 -17
  49. package/library/stream/stream-core.d.ts +22 -1
  50. package/library/stream/stream-core.d.ts.map +1 -1
  51. package/library/stream/stream-core.js +114 -1
  52. package/library/stream/types.d.ts +115 -2
  53. package/library/stream/types.d.ts.map +1 -1
  54. package/library/stream/writable-stream.d.ts +20 -2
  55. package/library/stream/writable-stream.d.ts.map +1 -1
  56. package/library/stream/writable-stream.js +277 -23
  57. package/library/types/index.d.ts +3 -4
  58. package/library/types/index.d.ts.map +1 -1
  59. package/library/utils/ack.d.ts +2 -0
  60. package/library/utils/ack.d.ts.map +1 -0
  61. package/library/utils/ack.js +44 -0
  62. package/library/utils/debug.js +1 -1
  63. package/library/utils/index.d.ts.map +1 -1
  64. package/library/utils/index.js +4 -3
  65. package/library/utils/origin.d.ts.map +1 -1
  66. package/library/utils/origin.js +2 -1
  67. package/package.json +1 -1
  68. package/esm/utils/ack-meta.js +0 -53
  69. package/library/utils/ack-meta.d.ts +0 -2
  70. package/library/utils/ack-meta.d.ts.map +0 -1
  71. package/library/utils/ack-meta.js +0 -59
package/esm/api/server.js CHANGED
@@ -32,7 +32,9 @@ export function requestIframeServer(options) {
32
32
  autoOpen: options === null || options === void 0 ? void 0 : options.autoOpen,
33
33
  allowedOrigins: options === null || options === void 0 ? void 0 : options.allowedOrigins,
34
34
  validateOrigin: options === null || options === void 0 ? void 0 : options.validateOrigin,
35
- maxConcurrentRequestsPerClient: options === null || options === void 0 ? void 0 : options.maxConcurrentRequestsPerClient
35
+ maxConcurrentRequestsPerClient: options === null || options === void 0 ? void 0 : options.maxConcurrentRequestsPerClient,
36
+ autoAckMaxMetaLength: options === null || options === void 0 ? void 0 : options.autoAckMaxMetaLength,
37
+ autoAckMaxIdLength: options === null || options === void 0 ? void 0 : options.autoAckMaxIdLength
36
38
  });
37
39
 
38
40
  // If trace mode is enabled, register debug listeners
@@ -14,6 +14,24 @@ export var ProtocolVersion = {
14
14
  MIN_SUPPORTED: 1
15
15
  };
16
16
 
17
+ /**
18
+ * Special origin values
19
+ */
20
+ export var OriginConstant = {
21
+ /** Wildcard origin (postMessage targetOrigin = '*') */
22
+ ANY: '*'
23
+ };
24
+
25
+ /**
26
+ * Auto-ack (ACK-only) limits.
27
+ */
28
+ export var AutoAckConstant = {
29
+ /** Max length of ack.id to be echoed back in auto-ack */
30
+ MAX_ID_LENGTH: 1024,
31
+ /** Max length of ack.meta to be echoed back in auto-ack */
32
+ MAX_META_LENGTH: 5120
33
+ };
34
+
17
35
  /**
18
36
  * Protocol version type
19
37
  */
@@ -113,8 +131,6 @@ export var MessageType = {
113
131
  RESPONSE: 'response',
114
132
  /** Error message */
115
133
  ERROR: 'error',
116
- /** Client confirms response received */
117
- RECEIVED: 'received',
118
134
  /** Ping message (for connection detection) */
119
135
  PING: 'ping',
120
136
  /** Pong message (for connection detection) */
@@ -146,7 +162,7 @@ export var MessageRole = {
146
162
  export var DefaultTimeout = {
147
163
  /**
148
164
  * ACK confirmation timeout: 1000ms (1s)
149
- * Used for both client waiting for server ACK and server waiting for client RECEIVED.
165
+ * Used for requireAck confirmation (ACK-only).
150
166
  * Increased from 500ms to accommodate slower environments or busy browsers where postMessage
151
167
  * serialization/deserialization may take longer.
152
168
  */
@@ -218,9 +234,7 @@ export var StreamInternalMessageType = {
218
234
  /** Cancel message */
219
235
  CANCEL: 'cancel',
220
236
  /** Pull message */
221
- PULL: 'pull',
222
- /** Ack message */
223
- ACK: 'ack'
237
+ PULL: 'pull'
224
238
  };
225
239
 
226
240
  /**
@@ -251,6 +265,24 @@ export var StreamState = {
251
265
  * Stream state value type
252
266
  */
253
267
 
268
+ /**
269
+ * Stream event name constants (for stream.on / observability)
270
+ */
271
+ export var StreamEvent = {
272
+ START: 'start',
273
+ DATA: 'data',
274
+ READ: 'read',
275
+ WRITE: 'write',
276
+ SEND: 'send',
277
+ PULL: 'pull',
278
+ ACK: 'ack',
279
+ END: 'end',
280
+ CANCEL: 'cancel',
281
+ ERROR: 'error',
282
+ TIMEOUT: 'timeout',
283
+ EXPIRED: 'expired',
284
+ STATE: 'state'
285
+ };
254
286
  /**
255
287
  * Message constants (for multi-language support)
256
288
  */
@@ -57,6 +57,8 @@ var defaultMessages = {
57
57
  STREAM_ENDED: 'Stream has ended',
58
58
  STREAM_READ_ERROR: 'Failed to read stream data',
59
59
  STREAM_WRITE_ONLY_IN_PUSH_MODE: 'Stream write() is only available when mode is "push"',
60
+ STREAM_PENDING_QUEUE_OVERFLOW: 'Stream pending queue overflow (limit: {0})',
61
+ STREAM_PENDING_BYTES_OVERFLOW: 'Stream pending bytes overflow (limit: {0})',
60
62
  /** Debug messages - Client */
61
63
  DEBUG_CLIENT_REQUEST_START: '📤 [Client] Request Start',
62
64
  DEBUG_CLIENT_REQUEST_SUCCESS: '✅ [Client] Request Success',
@@ -73,7 +75,7 @@ var defaultMessages = {
73
75
  DEBUG_CLIENT_REQUEST_TIMEOUT: '⏱️ [Client] Request Timeout',
74
76
  DEBUG_CLIENT_SENDING_REQUEST: '📤 [Client] Sending Request',
75
77
  DEBUG_CLIENT_SENDING_PING: '📤 [Client] Sending Ping',
76
- DEBUG_CLIENT_SENDING_RECEIVED_ACK: '📤 [Client] Sending Received ACK',
78
+ DEBUG_CLIENT_SENDING_RECEIVED_ACK: '📤 [Client] Sending ACK',
77
79
  /** Debug messages - Server */
78
80
  DEBUG_SERVER_RECEIVED_REQUEST: '📥 [Server] Received Request',
79
81
  DEBUG_SERVER_SETTING_STATUS_CODE: '📝 [Server] Setting Status Code',
@@ -8,16 +8,12 @@ import "core-js/modules/web.dom-collections.iterator.js";
8
8
  import { MessageDispatcher } from '../message';
9
9
  import { getOrCreateMessageChannel, releaseMessageChannel } from '../utils/cache';
10
10
  import { isCompatibleVersion } from '../utils';
11
- import { MessageType, DefaultTimeout, ProtocolVersion, Messages, formatMessage, MessageRole } from '../constants';
11
+ import { MessageType, ProtocolVersion, Messages, formatMessage, MessageRole, OriginConstant } from '../constants';
12
12
 
13
13
  /**
14
14
  * Stream message handler callback
15
15
  */
16
16
 
17
- /**
18
- * Pending acknowledgment response
19
- */
20
-
21
17
  /**
22
18
  * Pending request awaiting response
23
19
  */
@@ -33,9 +29,7 @@ import { MessageType, DefaultTimeout, ProtocolVersion, Messages, formatMessage,
33
29
  */
34
30
  export class RequestIframeClientServer {
35
31
  constructor(options, instanceId) {
36
- var _options$ackTimeout, _options$versionValid;
37
- /** Pending responses awaiting client acknowledgment */
38
- _defineProperty(this, "pendingAcks", new Map());
32
+ var _options$versionValid;
39
33
  /** Pending requests awaiting response */
40
34
  _defineProperty(this, "pendingRequests", new Map());
41
35
  /**
@@ -46,12 +40,15 @@ export class RequestIframeClientServer {
46
40
  _defineProperty(this, "unregisterFns", []);
47
41
  /** Whether opened */
48
42
  _defineProperty(this, "_isOpen", false);
49
- this.ackTimeout = (_options$ackTimeout = options === null || options === void 0 ? void 0 : options.ackTimeout) !== null && _options$ackTimeout !== void 0 ? _options$ackTimeout : DefaultTimeout.ACK;
50
43
  this.versionValidator = (_options$versionValid = options === null || options === void 0 ? void 0 : options.versionValidator) !== null && _options$versionValid !== void 0 ? _options$versionValid : isCompatibleVersion;
51
44
 
52
45
  // Get or create shared channel and create dispatcher
53
46
  var channel = getOrCreateMessageChannel(options === null || options === void 0 ? void 0 : options.secretKey);
54
47
  this.dispatcher = new MessageDispatcher(channel, MessageRole.CLIENT, instanceId);
48
+ this.dispatcher.setAutoAckLimits({
49
+ maxMetaLength: options === null || options === void 0 ? void 0 : options.autoAckMaxMetaLength,
50
+ maxIdLength: options === null || options === void 0 ? void 0 : options.autoAckMaxIdLength
51
+ });
55
52
 
56
53
  // Auto-open by default (unless explicitly set to false)
57
54
  if ((options === null || options === void 0 ? void 0 : options.autoOpen) !== false) {
@@ -111,9 +108,6 @@ export class RequestIframeClientServer {
111
108
  // Handle ERROR messages
112
109
  this.unregisterFns.push(this.dispatcher.registerHandler(MessageType.ERROR, boundHandleClientResponse, handlerOptions));
113
110
 
114
- // Handle RECEIVED messages
115
- this.unregisterFns.push(this.dispatcher.registerHandler(MessageType.RECEIVED, this.handleReceived.bind(this), handlerOptions));
116
-
117
111
  // Handle PONG messages
118
112
  this.unregisterFns.push(this.dispatcher.registerHandler(MessageType.PONG, this.handlePong.bind(this), handlerOptions));
119
113
 
@@ -188,7 +182,7 @@ export class RequestIframeClientServer {
188
182
  // If validator throws, treat as disallowed
189
183
  return;
190
184
  }
191
- } else if (pending.origin && pending.origin !== '*' && context.origin !== pending.origin) {
185
+ } else if (pending.origin && pending.origin !== OriginConstant.ANY && context.origin !== pending.origin) {
192
186
  return;
193
187
  }
194
188
 
@@ -213,18 +207,6 @@ export class RequestIframeClientServer {
213
207
  pending.resolve(data);
214
208
  }
215
209
 
216
- /**
217
- * Handle received acknowledgment
218
- */
219
- handleReceived(data) {
220
- var pending = this.pendingAcks.get(data.requestId);
221
- if (pending) {
222
- clearTimeout(pending.timeoutId);
223
- this.pendingAcks.delete(data.requestId);
224
- pending.resolve(true);
225
- }
226
- }
227
-
228
210
  /**
229
211
  * Handle pong
230
212
  */
@@ -239,7 +221,7 @@ export class RequestIframeClientServer {
239
221
  } catch (_unused2) {
240
222
  return;
241
223
  }
242
- } else if (pending.origin && pending.origin !== '*' && context.origin !== pending.origin) {
224
+ } else if (pending.origin && pending.origin !== OriginConstant.ANY && context.origin !== pending.origin) {
243
225
  return;
244
226
  }
245
227
  if (!context.handledBy) {
@@ -268,21 +250,6 @@ export class RequestIframeClientServer {
268
250
  return this.dispatcher;
269
251
  }
270
252
 
271
- /**
272
- * Register pending acknowledgment response
273
- */
274
- _registerPendingAck(requestId, resolve, reject) {
275
- var timeoutId = setTimeout(() => {
276
- this.pendingAcks.delete(requestId);
277
- resolve(false);
278
- }, this.ackTimeout);
279
- this.pendingAcks.set(requestId, {
280
- resolve,
281
- reject,
282
- timeoutId
283
- });
284
- }
285
-
286
253
  /**
287
254
  * Register pending request awaiting response
288
255
  */
@@ -318,8 +285,6 @@ export class RequestIframeClientServer {
318
285
 
319
286
  // Clear pending
320
287
  this.pendingRequests.clear();
321
- this.pendingAcks.forEach(pending => clearTimeout(pending.timeoutId));
322
- this.pendingAcks.clear();
323
288
  this.warnedMissingPendingWhenClosed.clear();
324
289
 
325
290
  // Destroy dispatcher and release channel reference
@@ -24,11 +24,11 @@ import "core-js/modules/es.string.starts-with.js";
24
24
  import "core-js/modules/web.dom-collections.for-each.js";
25
25
  import "core-js/modules/web.dom-collections.iterator.js";
26
26
  import { RequestIframeError } from '../utils';
27
- import { isAckMetaEqual } from '../utils/ack-meta';
27
+ import { isAckMatch } from '../utils/ack';
28
28
  import { detectContentType, blobToBase64, isWindowAvailable, matchOrigin } from '../utils';
29
29
  import { generateRequestId, generateInstanceId, CookieStore } from '../utils';
30
30
  import { RequestInterceptorManager, ResponseInterceptorManager, runRequestInterceptors, runResponseInterceptors } from '../interceptors';
31
- import { DefaultTimeout, ErrorCode, MessageType, HttpStatus, HttpStatusText, HttpHeader, Messages, formatMessage, StreamType as StreamTypeConstant } from '../constants';
31
+ import { DefaultTimeout, ErrorCode, MessageType, OriginConstant, HttpStatus, HttpStatusText, HttpHeader, Messages, formatMessage, StreamType as StreamTypeConstant } from '../constants';
32
32
  import { IframeReadableStream, IframeFileReadableStream, isIframeWritableStream } from '../stream';
33
33
 
34
34
  /**
@@ -133,7 +133,7 @@ export class RequestIframeClientImpl {
133
133
  } catch (_unused) {
134
134
  return;
135
135
  }
136
- } else if (this.targetOrigin !== '*' && context.origin !== this.targetOrigin) {
136
+ } else if (this.targetOrigin !== OriginConstant.ANY && context.origin !== this.targetOrigin) {
137
137
  return;
138
138
  }
139
139
  }
@@ -450,7 +450,7 @@ export class RequestIframeClientImpl {
450
450
  _processedConfig$requ3 = processedConfig.requireAck,
451
451
  requireAck = _processedConfig$requ3 === void 0 ? true : _processedConfig$requ3,
452
452
  streamTimeout = processedConfig.streamTimeout,
453
- ackMeta = processedConfig.ackMeta,
453
+ ack = processedConfig.ack,
454
454
  _processedConfig$retu = processedConfig.returnData,
455
455
  returnData = _processedConfig$retu === void 0 ? this.defaultReturnData : _processedConfig$retu;
456
456
  return new Promise((resolve, reject) => {
@@ -524,8 +524,8 @@ export class RequestIframeClientImpl {
524
524
 
525
525
  // Received ACK: server has received request
526
526
  if (data.type === MessageType.ACK) {
527
- // Optional ackMeta match (ignore mismatched ACK)
528
- if (ackMeta !== undefined && !isAckMetaEqual(ackMeta, data.ackMeta)) {
527
+ // Optional ack match (ignore mismatched ACK)
528
+ if (ack !== undefined && !isAckMatch(ack, data.ack)) {
529
529
  return;
530
530
  }
531
531
  // Remember server's creatorId as target server ID for future requests
@@ -740,7 +740,7 @@ export class RequestIframeClientImpl {
740
740
  cookies: mergedCookies,
741
741
  targetId,
742
742
  requireAck,
743
- ackMeta
743
+ ack
744
744
  };
745
745
  if (extraPayload !== null && extraPayload !== void 0 && extraPayload.streamId) {
746
746
  payload.streamId = extraPayload.streamId;
@@ -9,10 +9,10 @@ import "core-js/modules/es.object.get-own-property-descriptors.js";
9
9
  import "core-js/modules/es.promise.js";
10
10
  import "core-js/modules/web.dom-collections.for-each.js";
11
11
  import "core-js/modules/web.dom-collections.iterator.js";
12
- import { createPostMessage, createSetCookie, createClearCookie, detectContentType, blobToBase64 } from '../utils';
12
+ import { createPostMessage, createSetCookie, createClearCookie, detectContentType, blobToBase64, generateRequestId } from '../utils';
13
13
  import { MessageType, HttpStatus, HttpHeader, getStatusText, MessageRole, ErrorCode } from '../constants';
14
14
  import { IframeFileWritableStream, isIframeWritableStream } from '../stream';
15
- import { isAckMetaEqual } from '../utils/ack-meta';
15
+ import { isAckMatch } from '../utils/ack';
16
16
 
17
17
  /**
18
18
  * Callback waiting for client acknowledgment
@@ -88,9 +88,9 @@ export class ServerResponseImpl {
88
88
  /**
89
89
  * Trigger client acknowledgment callback
90
90
  */
91
- _triggerAck(received, ackMeta) {
91
+ _triggerAck(received, ack) {
92
92
  if (this.onAckCallback) {
93
- this.onAckCallback(received, ackMeta);
93
+ this.onAckCallback(received, ack);
94
94
  this.onAckCallback = undefined;
95
95
  }
96
96
  }
@@ -119,11 +119,19 @@ export class ServerResponseImpl {
119
119
  * Internal method: send raw data (used by send after type detection)
120
120
  */
121
121
  _sendRaw(data, options) {
122
- var _options$requireAck;
122
+ var _options$requireAck, _ack;
123
123
  if (this._sent) return Promise.resolve(false);
124
124
  this.markSent();
125
125
  var requireAck = (_options$requireAck = options === null || options === void 0 ? void 0 : options.requireAck) !== null && _options$requireAck !== void 0 ? _options$requireAck : false;
126
- var expectedAckMeta = options === null || options === void 0 ? void 0 : options.ackMeta;
126
+ /**
127
+ * When requireAck is enabled, attach a unique ack payload by default so ACK can be
128
+ * unambiguously associated with this send.
129
+ *
130
+ * NOTE: ack is an internal reserved field (not part of public API).
131
+ */
132
+ var expectedAck = (_ack = options === null || options === void 0 ? void 0 : options.ack) !== null && _ack !== void 0 ? _ack : requireAck ? {
133
+ id: generateRequestId()
134
+ } : undefined;
127
135
  try {
128
136
  // If acknowledgment not required, send directly and return true
129
137
  if (!requireAck) {
@@ -150,7 +158,7 @@ export class ServerResponseImpl {
150
158
  resolve(false);
151
159
  return;
152
160
  }
153
- if (expectedAckMeta !== undefined && !isAckMetaEqual(expectedAckMeta, receivedAckMeta)) {
161
+ if (expectedAck !== undefined && !isAckMatch(expectedAck, receivedAckMeta)) {
154
162
  resolve(false);
155
163
  return;
156
164
  }
@@ -164,7 +172,7 @@ export class ServerResponseImpl {
164
172
  statusText: getStatusText(this.statusCode),
165
173
  headers: this.headers,
166
174
  requireAck: true,
167
- ackMeta: expectedAckMeta,
175
+ ack: expectedAck,
168
176
  role: MessageRole.SERVER,
169
177
  creatorId: this.serverId,
170
178
  targetId: this.targetId
@@ -89,6 +89,10 @@ export class RequestIframeServerImpl {
89
89
  // Get or create shared channel and create dispatcher
90
90
  var channel = getOrCreateMessageChannel(options === null || options === void 0 ? void 0 : options.secretKey);
91
91
  this.dispatcher = new MessageDispatcher(channel, MessageRole.SERVER, this.id);
92
+ this.dispatcher.setAutoAckLimits({
93
+ maxMetaLength: options === null || options === void 0 ? void 0 : options.autoAckMaxMetaLength,
94
+ maxIdLength: options === null || options === void 0 ? void 0 : options.autoAckMaxIdLength
95
+ });
92
96
 
93
97
  // Auto-open by default (unless explicitly set to false)
94
98
  if ((options === null || options === void 0 ? void 0 : options.autoOpen) !== false) {
@@ -175,8 +179,8 @@ export class RequestIframeServerImpl {
175
179
  // Handle PONG messages (server -> client heartbeat)
176
180
  this.unregisterFns.push(this.dispatcher.registerHandler(MessageType.PONG, (data, context) => this.handlePong(data, context), handlerOptions));
177
181
 
178
- // Handle RECEIVED messages (for confirming response delivery)
179
- this.unregisterFns.push(this.dispatcher.registerHandler(MessageType.RECEIVED, (data, context) => this.handleReceived(data, context), handlerOptions));
182
+ // Handle ACK messages (for confirming response delivery when requireAck === true)
183
+ this.unregisterFns.push(this.dispatcher.registerHandler(MessageType.ACK, (data, context) => this.handleAck(data, context), handlerOptions));
180
184
 
181
185
  // Handle stream_* messages (client→server stream)
182
186
  this.unregisterFns.push(this.dispatcher.registerHandler(MessageType.STREAM_START, (data, ctx) => this.handleStreamStart(data, ctx), handlerOptions));
@@ -298,6 +302,11 @@ export class RequestIframeServerImpl {
298
302
  if (!(body !== null && body !== void 0 && body.streamId)) return;
299
303
  var handler = this.streamHandlers.get(body.streamId);
300
304
  if (handler) {
305
+ // Mark as accepted/handled so MessageDispatcher can auto-ack when requireAck === true
306
+ if (!context.handledBy) {
307
+ context.accepted = true;
308
+ context.handledBy = this.id;
309
+ }
301
310
  var messageType = data.type.replace('stream_', '');
302
311
  handler(_objectSpread(_objectSpread({}, body), {}, {
303
312
  type: messageType
@@ -377,9 +386,9 @@ export class RequestIframeServerImpl {
377
386
  }
378
387
 
379
388
  /**
380
- * Handle received acknowledgment
389
+ * Handle ACK (receipt confirmation for responses when requireAck === true).
381
390
  */
382
- handleReceived(data, context) {
391
+ handleAck(data, context) {
383
392
  if (!this.isOriginAllowed(data, context)) return;
384
393
  var pending = this.pendingAcks.get(data.requestId);
385
394
  if (pending) {
@@ -389,7 +398,7 @@ export class RequestIframeServerImpl {
389
398
  }
390
399
  clearTimeout(pending.timeoutId);
391
400
  this.pendingAcks.delete(data.requestId);
392
- pending.resolve(true, data.ackMeta);
401
+ pending.resolve(true, data.ack);
393
402
  }
394
403
  }
395
404
 
@@ -543,7 +552,7 @@ export class RequestIframeServerImpl {
543
552
  status: HttpStatus.TOO_MANY_REQUESTS,
544
553
  statusText: HttpStatusText[HttpStatus.TOO_MANY_REQUESTS],
545
554
  requireAck: data.requireAck,
546
- ackMeta: data.ackMeta,
555
+ ack: data.ack,
547
556
  targetId: data.creatorId
548
557
  });
549
558
  return;
@@ -571,8 +580,8 @@ export class RequestIframeServerImpl {
571
580
  });
572
581
 
573
582
  // Register callback waiting for client acknowledgment
574
- this.registerPendingAck(data.requestId, (received, ackMeta) => {
575
- res._triggerAck(received, ackMeta);
583
+ this.registerPendingAck(data.requestId, (received, ack) => {
584
+ res._triggerAck(received, ack);
576
585
  }, () => {
577
586
  res._triggerAck(false);
578
587
  });
@@ -597,7 +606,7 @@ export class RequestIframeServerImpl {
597
606
  status: HttpStatus.REQUEST_TIMEOUT,
598
607
  statusText: HttpStatusText[HttpStatus.REQUEST_TIMEOUT],
599
608
  requireAck: pending.data.requireAck,
600
- ackMeta: pending.data.ackMeta,
609
+ ack: pending.data.ack,
601
610
  targetId: pending.data.creatorId
602
611
  });
603
612
  }
@@ -8,6 +8,7 @@ import "core-js/modules/es.set.js";
8
8
  import "core-js/modules/web.dom-collections.for-each.js";
9
9
  import "core-js/modules/web.dom-collections.iterator.js";
10
10
  import { isValidPostMessage, createPostMessage, isWindowAvailable } from '../utils';
11
+ import { OriginConstant } from '../constants';
11
12
 
12
13
  /**
13
14
  * Message context (extracted from MessageEvent, transport-agnostic)
@@ -141,7 +142,7 @@ export class MessageChannel {
141
142
  * @param message message data (already formatted as PostMessageData)
142
143
  * @param targetOrigin target origin (defaults to '*')
143
144
  */
144
- send(target, message, targetOrigin = '*') {
145
+ send(target, message, targetOrigin = OriginConstant.ANY) {
145
146
  if (!isWindowAvailable(target)) {
146
147
  return false;
147
148
  }
@@ -18,8 +18,9 @@ import "core-js/modules/es.object.get-own-property-descriptors.js";
18
18
  import "core-js/modules/es.regexp.constructor.js";
19
19
  import "core-js/modules/es.regexp.exec.js";
20
20
  import "core-js/modules/es.regexp.to-string.js";
21
- import { MessageRole, MessageType } from '../constants';
21
+ import { AutoAckConstant, MessageRole, MessageType, OriginConstant } from '../constants';
22
22
  import { getProtocolVersion, createPostMessage } from '../utils';
23
+ import { getAckId, getAckMeta } from '../utils/ack';
23
24
 
24
25
  /**
25
26
  * Message handler function type
@@ -65,12 +66,9 @@ export class MessageDispatcher {
65
66
  /** Role of this dispatcher ('client' or 'server') */
66
67
  /** Instance ID of the client/server that owns this dispatcher */
67
68
  /** Underlying message channel */
68
- /**
69
- * Fallback target for sending auto-ack messages when MessageEvent.source is unavailable.
70
- * - In real browser postMessage events, `source` should normally exist.
71
- * - This is primarily used for unit tests or edge environments that synthesize MessageEvent without `source`.
72
- */
73
- _defineProperty(this, "fallbackTargetOrigin", '*');
69
+ _defineProperty(this, "autoAckMaxMetaLength", AutoAckConstant.MAX_META_LENGTH);
70
+ _defineProperty(this, "autoAckMaxIdLength", AutoAckConstant.MAX_ID_LENGTH);
71
+ _defineProperty(this, "fallbackTargetOrigin", OriginConstant.ANY);
74
72
  /** Message handler list */
75
73
  _defineProperty(this, "handlers", []);
76
74
  /** Reference count (for determining if can be destroyed when cached) */
@@ -93,11 +91,26 @@ export class MessageDispatcher {
93
91
  /**
94
92
  * Set fallback target for outgoing auto-ack messages.
95
93
  */
96
- setFallbackTarget(targetWindow, targetOrigin = '*') {
94
+ setFallbackTarget(targetWindow, targetOrigin = OriginConstant.ANY) {
97
95
  this.fallbackTargetWindow = targetWindow;
98
96
  this.fallbackTargetOrigin = targetOrigin;
99
97
  }
100
98
 
99
+ /**
100
+ * Configure auto-ack echo limits (advanced/internal).
101
+ *
102
+ * @internal
103
+ */
104
+ setAutoAckLimits(limits) {
105
+ if (!limits || typeof limits !== 'object') return;
106
+ if (typeof limits.maxMetaLength === 'number' && Number.isFinite(limits.maxMetaLength) && limits.maxMetaLength >= 0) {
107
+ this.autoAckMaxMetaLength = limits.maxMetaLength;
108
+ }
109
+ if (typeof limits.maxIdLength === 'number' && Number.isFinite(limits.maxIdLength) && limits.maxIdLength >= 0) {
110
+ this.autoAckMaxIdLength = limits.maxIdLength;
111
+ }
112
+ }
113
+
101
114
  // ==================== Reference Counting ====================
102
115
 
103
116
  /**
@@ -277,29 +290,54 @@ export class MessageDispatcher {
277
290
  var type = data.type;
278
291
 
279
292
  // Don't auto-ack ack messages (avoid loops)
280
- if (type === MessageType.ACK || type === MessageType.RECEIVED) return;
281
- var shouldAckRequest = type === MessageType.REQUEST && data.requireAck !== false;
282
- var shouldAckPing = type === MessageType.PING && data.requireAck === true;
283
- var shouldAckResponse = (type === MessageType.RESPONSE || type === MessageType.ERROR) && data.requireAck === true;
284
- if ((shouldAckRequest || shouldAckPing) && context.accepted === true) {
285
- // Delivery acknowledgment for request/ping
293
+ if (type === MessageType.ACK) return;
294
+
295
+ /**
296
+ * ACK-only requireAck workflow (no compatibility guarantees):
297
+ * - For any message with `requireAck === true`, once the message is accepted/handled
298
+ * (via `context.accepted === true` + `context.handledBy` setter hook),
299
+ * we reply with `ack`.
300
+ *
301
+ * This unifies:
302
+ * - request delivery confirmation
303
+ * - response receipt confirmation
304
+ * - stream frame delivery confirmation (e.g. stream_data per-frame ack)
305
+ */
306
+ if (data.requireAck === true && context.accepted === true) {
307
+ var ack = this.getAutoAckEchoPayload(data.ack);
286
308
  this.sendMessage(targetWindow, targetOrigin, MessageType.ACK, data.requestId, {
287
309
  path: data.path,
288
310
  targetId: data.creatorId,
289
- ackMeta: data.ackMeta
290
- });
291
- return;
292
- }
293
- if (shouldAckResponse && context.accepted === true) {
294
- // Receipt acknowledgment for response/error
295
- this.sendMessage(targetWindow, targetOrigin, MessageType.RECEIVED, data.requestId, {
296
- path: data.path,
297
- targetId: data.creatorId,
298
- ackMeta: data.ackMeta
311
+ ack
299
312
  });
300
313
  }
301
314
  }
302
315
 
316
+ /**
317
+ * Limit echoed ack payload size for auto-ack replies.
318
+ *
319
+ * We only echo a fixed shape `{ id, meta?: string }`:
320
+ * - If meta is too long, we drop meta and only echo `{ id }`.
321
+ * - If id is missing or too long, omit `ack` field.
322
+ */
323
+ getAutoAckEchoPayload(rawAck) {
324
+ if (rawAck === undefined) return undefined;
325
+ var id = getAckId(rawAck);
326
+ if (id === undefined) return undefined;
327
+ if (typeof id === 'string' && id.length > this.autoAckMaxIdLength) return undefined;
328
+ var meta = getAckMeta(rawAck);
329
+ if (meta === undefined) return {
330
+ id
331
+ };
332
+ if (meta.length > this.autoAckMaxMetaLength) return {
333
+ id
334
+ };
335
+ return {
336
+ id,
337
+ meta
338
+ };
339
+ }
340
+
303
341
  /**
304
342
  * Check if message type matches
305
343
  */
@@ -324,7 +362,7 @@ export class MessageDispatcher {
324
362
  * @param message message data (already formatted as PostMessageData)
325
363
  * @param targetOrigin target origin (defaults to '*')
326
364
  */
327
- send(target, message, targetOrigin = '*') {
365
+ send(target, message, targetOrigin = OriginConstant.ANY) {
328
366
  // Automatically set role and creatorId if not already set (for backward compatibility)
329
367
  if (message.role === undefined) {
330
368
  message.role = this.role;