request-iframe 0.1.0 → 0.2.0

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 (223) hide show
  1. package/QUICKSTART.CN.md +4 -2
  2. package/QUICKSTART.md +4 -2
  3. package/README.CN.md +302 -54
  4. package/README.md +281 -36
  5. package/cdn/request-iframe-react.umd.js +3354 -0
  6. package/cdn/request-iframe-react.umd.js.map +1 -0
  7. package/cdn/request-iframe-react.umd.min.js +2 -0
  8. package/cdn/request-iframe-react.umd.min.js.map +1 -0
  9. package/cdn/request-iframe.umd.js +19735 -0
  10. package/cdn/request-iframe.umd.js.map +1 -0
  11. package/cdn/request-iframe.umd.min.js +4 -0
  12. package/cdn/request-iframe.umd.min.js.map +1 -0
  13. package/esm/api/client.js +31 -22
  14. package/esm/api/endpoint.js +229 -0
  15. package/esm/api/server.js +19 -9
  16. package/esm/constants/debug.js +17 -0
  17. package/esm/constants/index.js +115 -66
  18. package/esm/constants/log.js +11 -0
  19. package/esm/constants/messages.js +6 -1
  20. package/esm/constants/warn-once.js +15 -0
  21. package/esm/endpoint/facade.js +390 -0
  22. package/esm/endpoint/heartbeat/heartbeat.js +60 -0
  23. package/esm/endpoint/heartbeat/ping.js +20 -0
  24. package/esm/endpoint/index.js +13 -0
  25. package/esm/endpoint/infra/hub.js +316 -0
  26. package/esm/endpoint/infra/inbox.js +232 -0
  27. package/esm/endpoint/infra/outbox.js +408 -0
  28. package/esm/endpoint/stream/dispatcher.js +58 -0
  29. package/esm/endpoint/stream/errors.js +27 -0
  30. package/esm/endpoint/stream/factory.js +76 -0
  31. package/esm/endpoint/stream/file-auto-resolve.js +34 -0
  32. package/esm/endpoint/stream/file-writable.js +105 -0
  33. package/esm/endpoint/stream/handler.js +26 -0
  34. package/esm/{core → impl}/client.js +243 -320
  35. package/esm/{core → impl}/response.js +120 -154
  36. package/esm/impl/server.js +568 -0
  37. package/esm/index.js +13 -6
  38. package/esm/message/ack.js +27 -0
  39. package/esm/message/channel-cache.js +108 -0
  40. package/esm/message/channel.js +92 -5
  41. package/esm/message/dispatcher.js +149 -98
  42. package/esm/stream/error.js +22 -0
  43. package/esm/stream/index.js +3 -1
  44. package/esm/stream/readable-stream.js +101 -26
  45. package/esm/stream/stream-core.js +121 -3
  46. package/esm/stream/writable-stream.js +368 -43
  47. package/esm/utils/ack.js +36 -0
  48. package/esm/utils/blob.js +16 -0
  49. package/esm/utils/cache.js +25 -76
  50. package/esm/utils/content-type.js +81 -0
  51. package/esm/utils/debug.js +157 -180
  52. package/esm/utils/hooks.js +130 -0
  53. package/esm/utils/id.js +14 -0
  54. package/esm/utils/iframe.js +20 -0
  55. package/esm/utils/index.js +12 -162
  56. package/esm/utils/is.js +3 -0
  57. package/esm/utils/logger.js +55 -0
  58. package/esm/utils/origin.js +3 -1
  59. package/esm/utils/promise.js +3 -0
  60. package/esm/utils/window.js +31 -0
  61. package/library/api/client.d.ts.map +1 -1
  62. package/library/api/client.js +32 -23
  63. package/library/api/endpoint.d.ts +23 -0
  64. package/library/api/endpoint.d.ts.map +1 -0
  65. package/library/api/endpoint.js +235 -0
  66. package/library/api/server.d.ts +4 -1
  67. package/library/api/server.d.ts.map +1 -1
  68. package/library/api/server.js +19 -9
  69. package/library/constants/debug.d.ts +18 -0
  70. package/library/constants/debug.d.ts.map +1 -0
  71. package/library/constants/debug.js +23 -0
  72. package/library/constants/index.d.ts +58 -7
  73. package/library/constants/index.d.ts.map +1 -1
  74. package/library/constants/index.js +143 -67
  75. package/library/constants/log.d.ts +12 -0
  76. package/library/constants/log.d.ts.map +1 -0
  77. package/library/constants/log.js +17 -0
  78. package/library/constants/messages.d.ts +6 -1
  79. package/library/constants/messages.d.ts.map +1 -1
  80. package/library/constants/messages.js +6 -1
  81. package/library/constants/warn-once.d.ts +12 -0
  82. package/library/constants/warn-once.d.ts.map +1 -0
  83. package/library/constants/warn-once.js +22 -0
  84. package/library/endpoint/facade.d.ts +238 -0
  85. package/library/endpoint/facade.d.ts.map +1 -0
  86. package/library/endpoint/facade.js +398 -0
  87. package/library/endpoint/heartbeat/heartbeat.d.ts +34 -0
  88. package/library/endpoint/heartbeat/heartbeat.d.ts.map +1 -0
  89. package/library/endpoint/heartbeat/heartbeat.js +67 -0
  90. package/library/endpoint/heartbeat/ping.d.ts +18 -0
  91. package/library/endpoint/heartbeat/ping.d.ts.map +1 -0
  92. package/library/endpoint/heartbeat/ping.js +26 -0
  93. package/library/endpoint/index.d.ts +16 -0
  94. package/library/endpoint/index.d.ts.map +1 -0
  95. package/library/endpoint/index.js +114 -0
  96. package/library/endpoint/infra/hub.d.ts +170 -0
  97. package/library/endpoint/infra/hub.d.ts.map +1 -0
  98. package/library/endpoint/infra/hub.js +323 -0
  99. package/library/endpoint/infra/inbox.d.ts +73 -0
  100. package/library/endpoint/infra/inbox.d.ts.map +1 -0
  101. package/library/endpoint/infra/inbox.js +239 -0
  102. package/library/endpoint/infra/outbox.d.ts +149 -0
  103. package/library/endpoint/infra/outbox.d.ts.map +1 -0
  104. package/library/endpoint/infra/outbox.js +415 -0
  105. package/library/endpoint/stream/dispatcher.d.ts +33 -0
  106. package/library/endpoint/stream/dispatcher.d.ts.map +1 -0
  107. package/library/endpoint/stream/dispatcher.js +66 -0
  108. package/library/endpoint/stream/errors.d.ts +20 -0
  109. package/library/endpoint/stream/errors.d.ts.map +1 -0
  110. package/library/endpoint/stream/errors.js +32 -0
  111. package/library/endpoint/stream/factory.d.ts +44 -0
  112. package/library/endpoint/stream/factory.d.ts.map +1 -0
  113. package/library/endpoint/stream/factory.js +82 -0
  114. package/library/endpoint/stream/file-auto-resolve.d.ts +26 -0
  115. package/library/endpoint/stream/file-auto-resolve.d.ts.map +1 -0
  116. package/library/endpoint/stream/file-auto-resolve.js +41 -0
  117. package/library/endpoint/stream/file-writable.d.ts +33 -0
  118. package/library/endpoint/stream/file-writable.d.ts.map +1 -0
  119. package/library/endpoint/stream/file-writable.js +115 -0
  120. package/library/endpoint/stream/handler.d.ts +20 -0
  121. package/library/endpoint/stream/handler.d.ts.map +1 -0
  122. package/library/endpoint/stream/handler.js +32 -0
  123. package/library/{core → impl}/client.d.ts +16 -13
  124. package/library/impl/client.d.ts.map +1 -0
  125. package/library/{core → impl}/client.js +254 -333
  126. package/library/{core → impl}/request.d.ts.map +1 -1
  127. package/library/{core → impl}/response.d.ts +7 -12
  128. package/library/impl/response.d.ts.map +1 -0
  129. package/library/{core → impl}/response.js +120 -154
  130. package/library/{core → impl}/server.d.ts +26 -55
  131. package/library/impl/server.d.ts.map +1 -0
  132. package/library/impl/server.js +575 -0
  133. package/library/index.d.ts +13 -6
  134. package/library/index.d.ts.map +1 -1
  135. package/library/index.js +16 -16
  136. package/library/message/ack.d.ts +15 -0
  137. package/library/message/ack.d.ts.map +1 -0
  138. package/library/message/ack.js +33 -0
  139. package/library/message/channel-cache.d.ts +26 -0
  140. package/library/message/channel-cache.d.ts.map +1 -0
  141. package/library/message/channel-cache.js +115 -0
  142. package/library/message/channel.d.ts +53 -6
  143. package/library/message/channel.d.ts.map +1 -1
  144. package/library/message/channel.js +96 -9
  145. package/library/message/dispatcher.d.ts +17 -0
  146. package/library/message/dispatcher.d.ts.map +1 -1
  147. package/library/message/dispatcher.js +149 -98
  148. package/library/stream/error.d.ts +24 -0
  149. package/library/stream/error.d.ts.map +1 -0
  150. package/library/stream/error.js +29 -0
  151. package/library/stream/index.d.ts +4 -1
  152. package/library/stream/index.d.ts.map +1 -1
  153. package/library/stream/index.js +7 -4
  154. package/library/stream/readable-stream.d.ts.map +1 -1
  155. package/library/stream/readable-stream.js +102 -27
  156. package/library/stream/stream-core.d.ts +22 -1
  157. package/library/stream/stream-core.d.ts.map +1 -1
  158. package/library/stream/stream-core.js +120 -2
  159. package/library/stream/types.d.ts +115 -2
  160. package/library/stream/types.d.ts.map +1 -1
  161. package/library/stream/writable-stream.d.ts +20 -2
  162. package/library/stream/writable-stream.d.ts.map +1 -1
  163. package/library/stream/writable-stream.js +366 -41
  164. package/library/types/index.d.ts +17 -22
  165. package/library/types/index.d.ts.map +1 -1
  166. package/library/utils/ack.d.ts +2 -0
  167. package/library/utils/ack.d.ts.map +1 -0
  168. package/library/utils/ack.js +44 -0
  169. package/library/utils/blob.d.ts +3 -0
  170. package/library/utils/blob.d.ts.map +1 -0
  171. package/library/utils/blob.js +22 -0
  172. package/library/utils/cache.d.ts +10 -20
  173. package/library/utils/cache.d.ts.map +1 -1
  174. package/library/utils/cache.js +25 -79
  175. package/library/utils/content-type.d.ts +13 -0
  176. package/library/utils/content-type.d.ts.map +1 -0
  177. package/library/utils/content-type.js +87 -0
  178. package/library/utils/debug.d.ts.map +1 -1
  179. package/library/utils/debug.js +156 -178
  180. package/library/utils/hooks.d.ts +30 -0
  181. package/library/utils/hooks.d.ts.map +1 -0
  182. package/library/utils/hooks.js +139 -0
  183. package/library/utils/id.d.ts +9 -0
  184. package/library/utils/id.d.ts.map +1 -0
  185. package/library/utils/id.js +21 -0
  186. package/library/utils/iframe.d.ts +5 -0
  187. package/library/utils/iframe.d.ts.map +1 -0
  188. package/library/utils/iframe.js +25 -0
  189. package/library/utils/index.d.ts +7 -34
  190. package/library/utils/index.d.ts.map +1 -1
  191. package/library/utils/index.js +58 -193
  192. package/library/utils/is.d.ts +2 -0
  193. package/library/utils/is.d.ts.map +1 -0
  194. package/library/utils/is.js +9 -0
  195. package/library/utils/logger.d.ts +13 -0
  196. package/library/utils/logger.d.ts.map +1 -0
  197. package/library/utils/logger.js +63 -0
  198. package/library/utils/origin.d.ts.map +1 -1
  199. package/library/utils/origin.js +2 -1
  200. package/library/utils/promise.d.ts +2 -0
  201. package/library/utils/promise.d.ts.map +1 -0
  202. package/library/utils/promise.js +9 -0
  203. package/library/utils/window.d.ts +2 -0
  204. package/library/utils/window.d.ts.map +1 -0
  205. package/library/utils/window.js +38 -0
  206. package/package.json +49 -2
  207. package/react/package.json +2 -1
  208. package/esm/core/client-server.js +0 -329
  209. package/esm/core/server.js +0 -767
  210. package/esm/utils/ack-meta.js +0 -53
  211. package/library/core/client-server.d.ts +0 -106
  212. package/library/core/client-server.d.ts.map +0 -1
  213. package/library/core/client-server.js +0 -336
  214. package/library/core/client.d.ts.map +0 -1
  215. package/library/core/response.d.ts.map +0 -1
  216. package/library/core/server.d.ts.map +0 -1
  217. package/library/core/server.js +0 -772
  218. package/library/utils/ack-meta.d.ts +0 -2
  219. package/library/utils/ack-meta.d.ts.map +0 -1
  220. package/library/utils/ack-meta.js +0 -59
  221. /package/esm/{core → impl}/request.js +0 -0
  222. /package/library/{core → impl}/request.d.ts +0 -0
  223. /package/library/{core → impl}/request.js +0 -0
@@ -0,0 +1,108 @@
1
+ import "core-js/modules/es.array.iterator.js";
2
+ import "core-js/modules/es.map.js";
3
+ import "core-js/modules/esnext.global-this.js";
4
+ import "core-js/modules/web.dom-collections.for-each.js";
5
+ import "core-js/modules/web.dom-collections.iterator.js";
6
+ import { MessageChannel, ChannelType } from './channel';
7
+
8
+ /**
9
+ * Global cache Symbol (used to store MessageChannel instance cache on window/globalThis).
10
+ *
11
+ * NOTE:
12
+ * - We MUST use Symbol.for() so multiple library copies (different bundles/versions)
13
+ * can share the same cache.
14
+ * - Keep the symbol key stable for backward compatibility with older releases.
15
+ */
16
+ var MESSAGE_CHANNEL_CACHE_SYMBOL = Symbol.for('__requestIframeMessageChannelCache__');
17
+
18
+ /**
19
+ * Get the cache host object.
20
+ *
21
+ * We prefer `window` because MessageChannel itself is window-based (postMessage listener),
22
+ * and existing versions store the cache on window as well.
23
+ */
24
+ function getCacheHost() {
25
+ if (typeof window !== 'undefined') return window;
26
+ // Fallback for non-browser environments; creating MessageChannel will likely fail anyway.
27
+ return globalThis;
28
+ }
29
+
30
+ /**
31
+ * Get the MessageChannel cache Map from the host.
32
+ */
33
+ function getChannelCache() {
34
+ var host = getCacheHost();
35
+ if (!(MESSAGE_CHANNEL_CACHE_SYMBOL in host)) {
36
+ host[MESSAGE_CHANNEL_CACHE_SYMBOL] = new Map();
37
+ }
38
+ return host[MESSAGE_CHANNEL_CACHE_SYMBOL];
39
+ }
40
+
41
+ /**
42
+ * Generate cache key.
43
+ * Format: "type:secretKey" or "type:" when no secretKey.
44
+ */
45
+ function getCacheKey(type, secretKey) {
46
+ return `${type}:${secretKey !== null && secretKey !== void 0 ? secretKey : ''}`;
47
+ }
48
+
49
+ /**
50
+ * Get or create MessageChannel instance.
51
+ *
52
+ * - Within the same window, only one channel is created per type + secretKey.
53
+ * - Uses reference counting to manage lifecycle.
54
+ */
55
+ export function getOrCreateMessageChannel(secretKey, type = ChannelType.POST_MESSAGE) {
56
+ var cache = getChannelCache();
57
+ var key = getCacheKey(type, secretKey);
58
+ var channel = cache.get(key);
59
+ if (!channel) {
60
+ channel = new MessageChannel(secretKey, type);
61
+ cache.set(key, channel);
62
+ }
63
+ channel.addRef();
64
+ return channel;
65
+ }
66
+
67
+ /**
68
+ * Release MessageChannel reference.
69
+ *
70
+ * - When reference count reaches 0, destroy channel and remove from cache.
71
+ */
72
+ export function releaseMessageChannel(channel) {
73
+ var refCount = channel.release();
74
+ if (refCount > 0) return;
75
+ var cache = getChannelCache();
76
+ var key = getCacheKey(channel.type, channel.secretKey);
77
+ if (cache.get(key) === channel) {
78
+ cache.delete(key);
79
+ channel.destroy();
80
+ }
81
+ }
82
+
83
+ /**
84
+ * Clear MessageChannel cache (mainly for testing).
85
+ *
86
+ * - No args: clear all channels
87
+ * - string arg: treated as secretKey filter
88
+ * - params arg: filter by secretKey/type
89
+ */
90
+ export function clearMessageChannelCache(arg) {
91
+ var cache = getChannelCache();
92
+ if (!arg) {
93
+ cache.forEach(channel => {
94
+ channel.destroy();
95
+ });
96
+ cache.clear();
97
+ return;
98
+ }
99
+ var params = typeof arg === 'string' ? {
100
+ secretKey: arg
101
+ } : arg;
102
+ cache.forEach((channel, key) => {
103
+ if (params.type && channel.type !== params.type) return;
104
+ if (typeof params.secretKey === 'string' && channel.secretKey !== params.secretKey) return;
105
+ cache.delete(key);
106
+ channel.destroy();
107
+ });
108
+ }
@@ -7,11 +7,25 @@ import "core-js/modules/es.object.get-own-property-descriptors.js";
7
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
- import { isValidPostMessage, createPostMessage, isWindowAvailable } from '../utils';
10
+ import { isValidPostMessage, createPostMessage } from '../utils/protocol';
11
+ import { isWindowAvailable } from '../utils/window';
12
+ import { OriginConstant } from '../constants';
13
+ import { requestIframeLog } from '../utils/logger';
14
+ import { SyncHook } from '../utils/hooks';
11
15
 
12
16
  /**
13
17
  * Message context (extracted from MessageEvent, transport-agnostic)
14
18
  */
19
+ export var MessageContextStage = {
20
+ /** Message is not handled by any instance yet */
21
+ PENDING: 'pending',
22
+ /** Message is claimed/being handled (handledBy is set, but not accepted) */
23
+ HANDLING: 'handling',
24
+ /** Message is accepted for processing (acceptedBy is set) */
25
+ ACCEPTED: 'accepted',
26
+ /** Message handling finished (synchronous dispatch finished) */
27
+ DONE: 'done'
28
+ };
15
29
 
16
30
  /**
17
31
  * Message receiver callback
@@ -98,10 +112,83 @@ export class MessageChannel {
98
112
  * This encapsulates transport-specific details
99
113
  */
100
114
  extractContext(event) {
101
- return {
102
- source: event.source,
115
+ var _ref;
116
+ var context = {
117
+ source: (_ref = event.source) !== null && _ref !== void 0 ? _ref : undefined,
103
118
  origin: event.origin
104
119
  };
120
+ var stateChangeHook;
121
+ var ensureStateChangeHook = () => {
122
+ if (!stateChangeHook) {
123
+ stateChangeHook = new SyncHook();
124
+ }
125
+ return stateChangeHook;
126
+ };
127
+ var emitStateChange = (prev, next) => {
128
+ if (!stateChangeHook) return;
129
+ stateChangeHook.call(prev, next, context);
130
+ };
131
+
132
+ /**
133
+ * Attach stable internal helper methods.
134
+ *
135
+ * We intentionally make them non-enumerable so typical object inspection won't be polluted.
136
+ */
137
+ var markHandledBy = handledBy => {
138
+ var prev = getStage();
139
+ if (!context.handledBy) {
140
+ context.handledBy = handledBy;
141
+ }
142
+ var next = getStage();
143
+ if (prev !== next) emitStateChange(prev, next);
144
+ };
145
+ var markAcceptedBy = handledBy => {
146
+ var prev = getStage();
147
+ if (!context.acceptedBy) {
148
+ context.acceptedBy = handledBy;
149
+ }
150
+ markHandledBy(handledBy);
151
+ var next = getStage();
152
+ if (prev !== next) emitStateChange(prev, next);
153
+ };
154
+ var markDoneBy = doneBy => {
155
+ var prev = getStage();
156
+ if (!context.doneBy) {
157
+ context.doneBy = doneBy;
158
+ }
159
+ var next = getStage();
160
+ if (prev !== next) emitStateChange(prev, next);
161
+ };
162
+ var getStage = () => {
163
+ if (context.doneBy) return MessageContextStage.DONE;
164
+ if (context.acceptedBy) return MessageContextStage.ACCEPTED;
165
+ if (context.handledBy) return MessageContextStage.HANDLING;
166
+ return MessageContextStage.PENDING;
167
+ };
168
+ var onStateChange = (name, fn) => {
169
+ return ensureStateChangeHook().tap(name, fn);
170
+ };
171
+ Object.defineProperty(context, 'markHandledBy', {
172
+ value: markHandledBy,
173
+ enumerable: false
174
+ });
175
+ Object.defineProperty(context, 'markAcceptedBy', {
176
+ value: markAcceptedBy,
177
+ enumerable: false
178
+ });
179
+ Object.defineProperty(context, 'markDoneBy', {
180
+ value: markDoneBy,
181
+ enumerable: false
182
+ });
183
+ Object.defineProperty(context, 'getStage', {
184
+ value: getStage,
185
+ enumerable: false
186
+ });
187
+ Object.defineProperty(context, 'onStateChange', {
188
+ value: onStateChange,
189
+ enumerable: false
190
+ });
191
+ return context;
105
192
  }
106
193
 
107
194
  /**
@@ -130,7 +217,7 @@ export class MessageChannel {
130
217
  try {
131
218
  receiver(data, context);
132
219
  } catch (e) {
133
- console.error('[request-iframe] Receiver error:', e);
220
+ requestIframeLog('error', 'Receiver error', e);
134
221
  }
135
222
  });
136
223
  }
@@ -141,7 +228,7 @@ export class MessageChannel {
141
228
  * @param message message data (already formatted as PostMessageData)
142
229
  * @param targetOrigin target origin (defaults to '*')
143
230
  */
144
- send(target, message, targetOrigin = '*') {
231
+ send(target, message, targetOrigin = OriginConstant.ANY) {
145
232
  if (!isWindowAvailable(target)) {
146
233
  return false;
147
234
  }
@@ -18,8 +18,12 @@ 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';
22
- import { getProtocolVersion, createPostMessage } from '../utils';
21
+ import { AutoAckConstant, MessageRole, MessageType, OriginConstant } from '../constants';
22
+ import { getProtocolVersion, createPostMessage } from '../utils/protocol';
23
+ import { isFunction } from '../utils/is';
24
+ import { getAckId, getAckMeta } from '../utils/ack';
25
+ import { SyncHook } from '../utils/hooks';
26
+ import { requestIframeLog } from '../utils/logger';
23
27
 
24
28
  /**
25
29
  * Message handler function type
@@ -60,17 +64,15 @@ import { getProtocolVersion, createPostMessage } from '../utils';
60
64
  */
61
65
  export class MessageDispatcher {
62
66
  constructor(channel, role, instanceId) {
63
- /** Secret key for message isolation */
64
- /** Channel type */
65
- /** Role of this dispatcher ('client' or 'server') */
66
- /** Instance ID of the client/server that owns this dispatcher */
67
- /** 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", '*');
67
+ _defineProperty(this, "hooks", {
68
+ inbound: new SyncHook(),
69
+ beforeSend: new SyncHook(),
70
+ afterSend: new SyncHook(),
71
+ sendError: new SyncHook()
72
+ });
73
+ _defineProperty(this, "autoAckMaxMetaLength", AutoAckConstant.MAX_META_LENGTH);
74
+ _defineProperty(this, "autoAckMaxIdLength", AutoAckConstant.MAX_ID_LENGTH);
75
+ _defineProperty(this, "fallbackTargetOrigin", OriginConstant.ANY);
74
76
  /** Message handler list */
75
77
  _defineProperty(this, "handlers", []);
76
78
  /** Reference count (for determining if can be destroyed when cached) */
@@ -93,11 +95,26 @@ export class MessageDispatcher {
93
95
  /**
94
96
  * Set fallback target for outgoing auto-ack messages.
95
97
  */
96
- setFallbackTarget(targetWindow, targetOrigin = '*') {
98
+ setFallbackTarget(targetWindow, targetOrigin = OriginConstant.ANY) {
97
99
  this.fallbackTargetWindow = targetWindow;
98
100
  this.fallbackTargetOrigin = targetOrigin;
99
101
  }
100
102
 
103
+ /**
104
+ * Configure auto-ack echo limits (advanced/internal).
105
+ *
106
+ * @internal
107
+ */
108
+ setAutoAckLimits(limits) {
109
+ if (!limits || typeof limits !== 'object') return;
110
+ if (typeof limits.maxMetaLength === 'number' && Number.isFinite(limits.maxMetaLength) && limits.maxMetaLength >= 0) {
111
+ this.autoAckMaxMetaLength = limits.maxMetaLength;
112
+ }
113
+ if (typeof limits.maxIdLength === 'number' && Number.isFinite(limits.maxIdLength) && limits.maxIdLength >= 0) {
114
+ this.autoAckMaxIdLength = limits.maxIdLength;
115
+ }
116
+ }
117
+
101
118
  // ==================== Reference Counting ====================
102
119
 
103
120
  /**
@@ -183,79 +200,80 @@ export class MessageDispatcher {
183
200
  return;
184
201
  }
185
202
  }
186
- var type = data.type;
187
- var version = getProtocolVersion(data);
188
-
189
- /**
190
- * Auto-ack state for this incoming message.
191
- * - We intentionally couple this to `context.handledBy` as the "accepted/handled" signal.
192
- * - For some message types we only ack if they are truly handled (e.g. response requireAck),
193
- * so we avoid incorrectly acknowledging messages when there is no pending consumer.
194
- *
195
- * Implementation note:
196
- * We avoid using Proxy for compatibility and instead hook the `handledBy` property
197
- * with a setter so handlers can trigger the ack immediately when they "accept" a message.
198
- */
199
- var autoAckState = {
200
- sent: false
201
- };
202
- var originalHandledBy = context.handledBy;
203
- var handledByValue = originalHandledBy;
204
203
  try {
205
- Object.defineProperty(context, 'handledBy', {
206
- configurable: true,
207
- enumerable: true,
208
- get() {
209
- return handledByValue;
210
- },
211
- set: value => {
212
- handledByValue = value;
213
- if (value && !autoAckState.sent) {
214
- autoAckState.sent = true;
215
- this.tryAutoAck(data, context);
216
- }
217
- }
218
- });
219
- } catch (_unused) {
204
+ this.hooks.inbound.call(data, context);
205
+ var _type = data.type;
206
+ var _version = getProtocolVersion(data);
207
+
220
208
  /**
221
- * In very rare cases `defineProperty` may fail (frozen object).
222
- * We still proceed without auto-ack; handlers will continue to work as before.
209
+ * Auto-ack state for this incoming message.
210
+ *
211
+ * Design notes:
212
+ * - We only auto-ack after the message is truly handled (context.handledBy is set)
213
+ * AND accepted (context.acceptedBy is set).
214
+ * - This prevents incorrectly acknowledging messages when there is no pending consumer.
223
215
  */
224
- }
225
- var _iterator = _createForOfIteratorHelper(this.handlers),
226
- _step;
227
- try {
228
- for (_iterator.s(); !(_step = _iterator.n()).done;) {
229
- var entry = _step.value;
230
- if (this.matchType(type, entry.matcher)) {
231
- // If message has been handled by a previous handler, stop processing
232
- if (context.handledBy) {
233
- break;
234
- }
216
+ var autoAckState = {
217
+ sent: false
218
+ };
219
+ var maybeAutoAck = () => {
220
+ if (autoAckState.sent) return;
221
+ if (!context.handledBy) return;
222
+ if (!context.acceptedBy) return;
223
+ autoAckState.sent = true;
224
+ this.tryAutoAck(data, context);
225
+ };
226
+ var _iterator = _createForOfIteratorHelper(this.handlers),
227
+ _step;
228
+ try {
229
+ for (_iterator.s(); !(_step = _iterator.n()).done;) {
230
+ var entry = _step.value;
231
+ if (this.matchType(_type, entry.matcher)) {
232
+ // If message has been handled by a previous handler, stop processing
233
+ if (context.handledBy) {
234
+ break;
235
+ }
235
236
 
236
- // If handler specified version validation
237
- if (entry.versionValidator && version !== undefined) {
238
- if (!entry.versionValidator(version)) {
239
- var _entry$onVersionError;
240
- // Version incompatible, call error handler (if any)
241
- (_entry$onVersionError = entry.onVersionError) === null || _entry$onVersionError === void 0 || _entry$onVersionError.call(entry, data, context, version);
242
- continue; // Skip this handler, try other handlers
237
+ // If handler specified version validation
238
+ if (entry.versionValidator && _version !== undefined) {
239
+ if (!entry.versionValidator(_version)) {
240
+ var _entry$onVersionError;
241
+ // Version incompatible, call error handler (if any)
242
+ (_entry$onVersionError = entry.onVersionError) === null || _entry$onVersionError === void 0 || _entry$onVersionError.call(entry, data, context, _version);
243
+ continue; // Skip this handler, try other handlers
244
+ }
245
+ }
246
+ try {
247
+ entry.handler(data, context);
248
+ // After handler execution, check if it marked the message as handled
249
+ // If context.handledBy is set by the handler, subsequent handlers will be skipped
250
+ } catch (e) {
251
+ // Ignore handler exception, continue executing other handlers
252
+ requestIframeLog('error', 'Handler error', e);
253
+ } finally {
254
+ // Auto-ack once the message is accepted + handled.
255
+ maybeAutoAck();
243
256
  }
244
- }
245
- try {
246
- entry.handler(data, context);
247
- // After handler execution, check if it marked the message as handled
248
- // If context.handledBy is set by the handler, subsequent handlers will be skipped
249
- } catch (e) {
250
- // Ignore handler exception, continue executing other handlers
251
- console.error('[request-iframe] Handler error:', e);
252
257
  }
253
258
  }
259
+
260
+ // Fallback: if a handler accepted+handled without throwing, ensure we auto-ack.
261
+ // (This is safe due to autoAckState guard.)
262
+ } catch (err) {
263
+ _iterator.e(err);
264
+ } finally {
265
+ _iterator.f();
254
266
  }
255
- } catch (err) {
256
- _iterator.e(err);
267
+ maybeAutoAck();
257
268
  } finally {
258
- _iterator.f();
269
+ /**
270
+ * Mark as "done" only when this dispatcher actually claimed/handled this message.
271
+ * - If the message was never claimed (handledBy not set), we keep `doneBy` empty so another
272
+ * dispatcher/handler still has a chance to process it.
273
+ */
274
+ if (context.handledBy) {
275
+ context.markDoneBy(context.handledBy);
276
+ }
259
277
  }
260
278
  }
261
279
 
@@ -277,29 +295,54 @@ export class MessageDispatcher {
277
295
  var type = data.type;
278
296
 
279
297
  // 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
298
+ if (type === MessageType.ACK) return;
299
+
300
+ /**
301
+ * ACK-only requireAck workflow (no compatibility guarantees):
302
+ * - For any message with `requireAck === true`, once the message is accepted/handled
303
+ * (via `context.acceptedBy` + `context.handledBy`),
304
+ * we reply with `ack`.
305
+ *
306
+ * This unifies:
307
+ * - request delivery confirmation
308
+ * - response receipt confirmation
309
+ * - stream frame delivery confirmation (e.g. stream_data per-frame ack)
310
+ */
311
+ if (data.requireAck === true && !!context.acceptedBy) {
312
+ var ack = this.getAutoAckEchoPayload(data.ack);
286
313
  this.sendMessage(targetWindow, targetOrigin, MessageType.ACK, data.requestId, {
287
314
  path: data.path,
288
315
  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
316
+ ack
299
317
  });
300
318
  }
301
319
  }
302
320
 
321
+ /**
322
+ * Limit echoed ack payload size for auto-ack replies.
323
+ *
324
+ * We only echo a fixed shape `{ id, meta?: string }`:
325
+ * - If meta is too long, we drop meta and only echo `{ id }`.
326
+ * - If id is missing or too long, omit `ack` field.
327
+ */
328
+ getAutoAckEchoPayload(rawAck) {
329
+ if (rawAck === undefined) return undefined;
330
+ var id = getAckId(rawAck);
331
+ if (id === undefined) return undefined;
332
+ if (typeof id === 'string' && id.length > this.autoAckMaxIdLength) return undefined;
333
+ var meta = getAckMeta(rawAck);
334
+ if (meta === undefined) return {
335
+ id
336
+ };
337
+ if (meta.length > this.autoAckMaxMetaLength) return {
338
+ id
339
+ };
340
+ return {
341
+ id,
342
+ meta
343
+ };
344
+ }
345
+
303
346
  /**
304
347
  * Check if message type matches
305
348
  */
@@ -310,7 +353,7 @@ export class MessageDispatcher {
310
353
  if (matcher instanceof RegExp) {
311
354
  return matcher.test(type);
312
355
  }
313
- if (typeof matcher === 'function') {
356
+ if (isFunction(matcher)) {
314
357
  return matcher(type);
315
358
  }
316
359
  return false;
@@ -324,7 +367,7 @@ export class MessageDispatcher {
324
367
  * @param message message data (already formatted as PostMessageData)
325
368
  * @param targetOrigin target origin (defaults to '*')
326
369
  */
327
- send(target, message, targetOrigin = '*') {
370
+ send(target, message, targetOrigin = OriginConstant.ANY) {
328
371
  // Automatically set role and creatorId if not already set (for backward compatibility)
329
372
  if (message.role === undefined) {
330
373
  message.role = this.role;
@@ -332,7 +375,15 @@ export class MessageDispatcher {
332
375
  if (message.creatorId === undefined && this.instanceId) {
333
376
  message.creatorId = this.instanceId;
334
377
  }
335
- return this.channel.send(target, message, targetOrigin);
378
+ this.hooks.beforeSend.call(target, targetOrigin, message);
379
+ try {
380
+ var _ok = this.channel.send(target, message, targetOrigin);
381
+ this.hooks.afterSend.call(target, targetOrigin, message, _ok);
382
+ return _ok;
383
+ } catch (e) {
384
+ this.hooks.sendError.call(target, targetOrigin, message, e);
385
+ throw e;
386
+ }
336
387
  }
337
388
 
338
389
  /**
@@ -351,7 +402,7 @@ export class MessageDispatcher {
351
402
  creatorId: this.instanceId,
352
403
  secretKey: this.secretKey
353
404
  }));
354
- return this.channel.send(target, message, targetOrigin);
405
+ return this.send(target, message, targetOrigin);
355
406
  }
356
407
 
357
408
  // ==================== Utilities ====================
@@ -0,0 +1,22 @@
1
+ /**
2
+ * Stream-specific error type.
3
+ *
4
+ * Notes:
5
+ * - This is for stream lifecycle / protocol / binding errors (not request/response errors).
6
+ * - Use `RequestIframeError` for request/response level failures.
7
+ */
8
+ export class RequestIframeStreamError extends Error {
9
+ constructor(params) {
10
+ super(params.message);
11
+ this.name = 'RequestIframeStreamError';
12
+ this.code = params.code;
13
+ this.streamId = params.streamId;
14
+ this.requestId = params.requestId;
15
+ this.cause = params.cause;
16
+
17
+ // Maintain proper stack trace for where our error was thrown (only available on V8)
18
+ if (Error.captureStackTrace) {
19
+ Error.captureStackTrace(this, RequestIframeStreamError);
20
+ }
21
+ }
22
+ }
@@ -7,8 +7,10 @@ export * from './types';
7
7
  export { IframeWritableStream } from './writable-stream';
8
8
  export { IframeFileWritableStream } from './file-stream';
9
9
 
10
+ // Stream error
11
+ export { RequestIframeStreamError } from './error';
10
12
  // Readable stream (client-side)
11
- export { IframeReadableStream, StreamMessageHandler } from './readable-stream';
13
+ export { IframeReadableStream } from './readable-stream';
12
14
  export { IframeFileReadableStream } from './file-stream';
13
15
 
14
16
  // Type checking utility functions