request-iframe 0.0.6 → 0.1.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 (93) hide show
  1. package/README.CN.md +53 -6
  2. package/README.md +63 -10
  3. package/esm/api/client.js +79 -0
  4. package/esm/api/server.js +59 -0
  5. package/esm/constants/index.js +257 -0
  6. package/esm/constants/messages.js +155 -0
  7. package/esm/core/client-server.js +329 -0
  8. package/esm/core/client.js +873 -0
  9. package/esm/core/request.js +27 -0
  10. package/esm/core/response.js +451 -0
  11. package/esm/core/server.js +767 -0
  12. package/esm/index.js +21 -0
  13. package/esm/interceptors/index.js +122 -0
  14. package/esm/message/channel.js +181 -0
  15. package/esm/message/dispatcher.js +380 -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 +500 -0
  20. package/esm/stream/stream-core.js +91 -0
  21. package/esm/stream/types.js +1 -0
  22. package/esm/stream/writable-stream.js +582 -0
  23. package/esm/types/index.js +1 -0
  24. package/esm/utils/ack-meta.js +53 -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 +178 -0
  30. package/esm/utils/origin.js +28 -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 +8 -1
  35. package/library/api/server.d.ts.map +1 -1
  36. package/library/api/server.js +4 -1
  37. package/library/constants/index.d.ts +25 -1
  38. package/library/constants/index.d.ts.map +1 -1
  39. package/library/constants/index.js +30 -5
  40. package/library/constants/messages.d.ts +5 -0
  41. package/library/constants/messages.d.ts.map +1 -1
  42. package/library/constants/messages.js +5 -0
  43. package/library/core/client-server.d.ts +3 -2
  44. package/library/core/client-server.d.ts.map +1 -1
  45. package/library/core/client-server.js +51 -4
  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 +46 -6
  52. package/library/core/server.d.ts +28 -1
  53. package/library/core/server.d.ts.map +1 -1
  54. package/library/core/server.js +180 -19
  55. package/library/message/channel.d.ts +6 -0
  56. package/library/message/channel.d.ts.map +1 -1
  57. package/library/message/dispatcher.d.ts +22 -0
  58. package/library/message/dispatcher.d.ts.map +1 -1
  59. package/library/message/dispatcher.js +92 -0
  60. package/library/stream/file-stream.d.ts +4 -0
  61. package/library/stream/file-stream.d.ts.map +1 -1
  62. package/library/stream/file-stream.js +61 -33
  63. package/library/stream/index.d.ts.map +1 -1
  64. package/library/stream/index.js +2 -0
  65. package/library/stream/readable-stream.d.ts +30 -11
  66. package/library/stream/readable-stream.d.ts.map +1 -1
  67. package/library/stream/readable-stream.js +329 -73
  68. package/library/stream/stream-core.d.ts +44 -0
  69. package/library/stream/stream-core.d.ts.map +1 -0
  70. package/library/stream/stream-core.js +98 -0
  71. package/library/stream/types.d.ts +90 -3
  72. package/library/stream/types.d.ts.map +1 -1
  73. package/library/stream/writable-stream.d.ts +40 -12
  74. package/library/stream/writable-stream.d.ts.map +1 -1
  75. package/library/stream/writable-stream.js +391 -195
  76. package/library/types/index.d.ts +70 -3
  77. package/library/types/index.d.ts.map +1 -1
  78. package/library/utils/ack-meta.d.ts +2 -0
  79. package/library/utils/ack-meta.d.ts.map +1 -0
  80. package/library/utils/ack-meta.js +59 -0
  81. package/library/utils/index.d.ts +1 -0
  82. package/library/utils/index.d.ts.map +1 -1
  83. package/library/utils/index.js +16 -0
  84. package/library/utils/origin.d.ts +14 -0
  85. package/library/utils/origin.d.ts.map +1 -0
  86. package/library/utils/origin.js +34 -0
  87. package/package.json +30 -7
  88. package/react/README.md +16 -0
  89. package/react/esm/index.js +284 -0
  90. package/react/library/index.d.ts +1 -1
  91. package/react/library/index.d.ts.map +1 -1
  92. package/react/library/index.js +3 -3
  93. package/react/package.json +24 -2
@@ -17,6 +17,7 @@ var _defineProperty2 = _interopRequireDefault(require("@babel/runtime/helpers/de
17
17
  var _utils = require("../utils");
18
18
  var _constants = require("../constants");
19
19
  var _stream = require("../stream");
20
+ var _ackMeta = require("../utils/ack-meta");
20
21
  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; }
21
22
  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; }
22
23
  /**
@@ -27,7 +28,7 @@ function _objectSpread(e) { for (var r = 1; r < arguments.length; r++) { var t =
27
28
  * ServerResponse implementation
28
29
  */
29
30
  class ServerResponseImpl {
30
- constructor(requestId, path, secretKey, targetWindow, targetOrigin, channel, serverId, targetId) {
31
+ constructor(requestId, path, secretKey, targetWindow, targetOrigin, channel, serverId, targetId, options) {
31
32
  (0, _defineProperty2.default)(this, "statusCode", _constants.HttpStatus.OK);
32
33
  (0, _defineProperty2.default)(this, "headers", {});
33
34
  (0, _defineProperty2.default)(this, "_sent", false);
@@ -39,6 +40,10 @@ class ServerResponseImpl {
39
40
  this.channel = channel;
40
41
  this.serverId = serverId;
41
42
  this.targetId = targetId;
43
+ this.registerStreamHandler = options === null || options === void 0 ? void 0 : options.registerStreamHandler;
44
+ this.unregisterStreamHandler = options === null || options === void 0 ? void 0 : options.unregisterStreamHandler;
45
+ this.heartbeat = options === null || options === void 0 ? void 0 : options.heartbeat;
46
+ this.onSentCallback = options === null || options === void 0 ? void 0 : options.onSent;
42
47
  }
43
48
 
44
49
  /**
@@ -89,21 +94,42 @@ class ServerResponseImpl {
89
94
  /**
90
95
  * Trigger client acknowledgment callback
91
96
  */
92
- _triggerAck(received) {
97
+ _triggerAck(received, ackMeta) {
93
98
  if (this.onAckCallback) {
94
- this.onAckCallback(received);
99
+ this.onAckCallback(received, ackMeta);
95
100
  this.onAckCallback = undefined;
96
101
  }
97
102
  }
98
103
 
104
+ /**
105
+ * Mark response as sent (and trigger onSent callback once).
106
+ */
107
+ markSent() {
108
+ if (this._sent) return;
109
+ this._sent = true;
110
+ if (this.onSentCallback) {
111
+ var cb = this.onSentCallback;
112
+ this.onSentCallback = undefined;
113
+ cb();
114
+ }
115
+ }
116
+
117
+ /**
118
+ * Internal: mark as sent for manual error responses.
119
+ */
120
+ _markSent() {
121
+ this.markSent();
122
+ }
123
+
99
124
  /**
100
125
  * Internal method: send raw data (used by send after type detection)
101
126
  */
102
127
  _sendRaw(data, options) {
103
128
  var _options$requireAck;
104
129
  if (this._sent) return Promise.resolve(false);
105
- this._sent = true;
130
+ this.markSent();
106
131
  var requireAck = (_options$requireAck = options === null || options === void 0 ? void 0 : options.requireAck) !== null && _options$requireAck !== void 0 ? _options$requireAck : false;
132
+ var expectedAckMeta = options === null || options === void 0 ? void 0 : options.ackMeta;
107
133
  try {
108
134
  // If acknowledgment not required, send directly and return true
109
135
  if (!requireAck) {
@@ -125,7 +151,17 @@ class ServerResponseImpl {
125
151
  // Acknowledgment required, wait for client response
126
152
  return new Promise((resolve, reject) => {
127
153
  try {
128
- this._setOnAckCallback(resolve);
154
+ this._setOnAckCallback((received, receivedAckMeta) => {
155
+ if (!received) {
156
+ resolve(false);
157
+ return;
158
+ }
159
+ if (expectedAckMeta !== undefined && !(0, _ackMeta.isAckMetaEqual)(expectedAckMeta, receivedAckMeta)) {
160
+ resolve(false);
161
+ return;
162
+ }
163
+ resolve(true);
164
+ });
129
165
  this.sendMessage((0, _utils.createPostMessage)(_constants.MessageType.RESPONSE, this.requestId, {
130
166
  path: this.path,
131
167
  secretKey: this.secretKey,
@@ -134,6 +170,7 @@ class ServerResponseImpl {
134
170
  statusText: (0, _constants.getStatusText)(this.statusCode),
135
171
  headers: this.headers,
136
172
  requireAck: true,
173
+ ackMeta: expectedAckMeta,
137
174
  role: _constants.MessageRole.SERVER,
138
175
  creatorId: this.serverId,
139
176
  targetId: this.targetId
@@ -317,7 +354,7 @@ class ServerResponseImpl {
317
354
  }
318
355
  return _context4.abrupt("return");
319
356
  case 1:
320
- _this3._sent = true;
357
+ _this3.markSent();
321
358
 
322
359
  // Window check is handled in MessageDispatcher when stream sends messages
323
360
 
@@ -328,6 +365,9 @@ class ServerResponseImpl {
328
365
  targetOrigin: _this3.targetOrigin,
329
366
  secretKey: _this3.secretKey,
330
367
  channel: _this3.channel,
368
+ registerStreamHandler: _this3.registerStreamHandler,
369
+ unregisterStreamHandler: _this3.unregisterStreamHandler,
370
+ heartbeat: _this3.heartbeat,
331
371
  serverId: _this3.serverId,
332
372
  targetId: _this3.targetId
333
373
  });
@@ -1,4 +1,4 @@
1
- import { ServerHandler, RequestIframeServer, Middleware, PathMatcher } from '../types';
1
+ import type { ServerHandler, RequestIframeServer, Middleware, PathMatcher, OriginMatcher, OriginValidator } from '../types';
2
2
  import { MessageDispatcher, VersionValidator } from '../message';
3
3
  /**
4
4
  * Server configuration options
@@ -12,8 +12,17 @@ export interface ServerOptions {
12
12
  ackTimeout?: number;
13
13
  /** Protocol version validator (optional, uses built-in validator by default) */
14
14
  versionValidator?: VersionValidator;
15
+ /** Allowed origins for incoming messages */
16
+ allowedOrigins?: OriginMatcher;
17
+ /** Custom origin validator (higher priority than allowedOrigins) */
18
+ validateOrigin?: OriginValidator;
15
19
  /** Whether to automatically open when creating the server. Default is true. */
16
20
  autoOpen?: boolean;
21
+ /**
22
+ * Max concurrent in-flight requests per client (per origin + creatorId).
23
+ * Used to mitigate message explosion caused by abnormal code or attacks.
24
+ */
25
+ maxConcurrentRequestsPerClient?: number;
17
26
  }
18
27
  /**
19
28
  * RequestIframeServer implementation
@@ -27,8 +36,13 @@ export declare class RequestIframeServerImpl implements RequestIframeServer {
27
36
  private readonly versionValidator;
28
37
  private readonly handlers;
29
38
  private readonly middlewares;
39
+ private readonly originValidator?;
40
+ private readonly maxConcurrentRequestsPerClient;
41
+ private readonly inFlightByClientKey;
30
42
  /** Responses waiting for client acknowledgment */
31
43
  private readonly pendingAcks;
44
+ /** Pending pings waiting for client PONG (server -> client heartbeat) */
45
+ private readonly pendingPongs;
32
46
  /** Pending requests waiting for client stream_start (streamId present) */
33
47
  private readonly pendingStreamRequests;
34
48
  /** Stream message handlers (streamId -> handler) for client→server streams */
@@ -38,6 +52,17 @@ export declare class RequestIframeServerImpl implements RequestIframeServer {
38
52
  /** Whether it is open */
39
53
  private _isOpen;
40
54
  constructor(options?: ServerOptions);
55
+ /**
56
+ * Check whether an incoming message origin is allowed.
57
+ */
58
+ private isOriginAllowed;
59
+ /**
60
+ * Build a per-client key used for concurrency limiting.
61
+ * We intentionally include origin to prevent cross-origin collisions.
62
+ */
63
+ private getClientKey;
64
+ private incInFlight;
65
+ private decInFlight;
41
66
  /**
42
67
  * Open message processing (register message handlers)
43
68
  */
@@ -65,6 +90,8 @@ export declare class RequestIframeServerImpl implements RequestIframeServer {
65
90
  * Handle ping message
66
91
  */
67
92
  private handlePing;
93
+ private handlePong;
94
+ private pingClient;
68
95
  /**
69
96
  * Handle received acknowledgment
70
97
  */
@@ -1 +1 @@
1
- {"version":3,"file":"server.d.ts","sourceRoot":"","sources":["../../src/core/server.ts"],"names":[],"mappings":"AAAA,OAAO,EAEL,aAAa,EACb,mBAAmB,EACnB,UAAU,EACV,WAAW,EACZ,MAAM,UAAU,CAAC;AAKlB,OAAO,EAAE,iBAAiB,EAAE,gBAAgB,EAAkB,MAAM,YAAY,CAAC;AAiDjF;;GAEG;AACH,MAAM,WAAW,aAAa;IAC5B,mCAAmC;IACnC,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,kGAAkG;IAClG,EAAE,CAAC,EAAE,MAAM,CAAC;IACZ,2BAA2B;IAC3B,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,gFAAgF;IAChF,gBAAgB,CAAC,EAAE,gBAAgB,CAAC;IACpC,+EAA+E;IAC/E,QAAQ,CAAC,EAAE,OAAO,CAAC;CACpB;AAED;;;GAGG;AACH,qBAAa,uBAAwB,YAAW,mBAAmB;IACjE,yBAAyB;IACzB,SAAgB,EAAE,EAAE,MAAM,CAAC;IAE3B,OAAO,CAAC,QAAQ,CAAC,UAAU,CAAoB;IAC/C,OAAO,CAAC,QAAQ,CAAC,UAAU,CAAS;IACpC,OAAO,CAAC,QAAQ,CAAC,gBAAgB,CAAmB;IACpD,OAAO,CAAC,QAAQ,CAAC,QAAQ,CAAoC;IAC7D,OAAO,CAAC,QAAQ,CAAC,WAAW,CAAwB;IAEpD,kDAAkD;IAClD,OAAO,CAAC,QAAQ,CAAC,WAAW,CAAiC;IAE7D,0EAA0E;IAC1E,OAAO,CAAC,QAAQ,CAAC,qBAAqB,CAA2C;IAEjF,8EAA8E;IAC9E,OAAO,CAAC,QAAQ,CAAC,cAAc,CAAwD;IAEvF,+CAA+C;IAC/C,OAAO,CAAC,QAAQ,CAAC,aAAa,CAAyB;IAEvD,yBAAyB;IACzB,OAAO,CAAC,OAAO,CAAS;gBAEL,OAAO,CAAC,EAAE,aAAa;IAgB1C;;OAEG;IACI,IAAI,IAAI,IAAI;IAMnB;;OAEG;IACI,KAAK,IAAI,IAAI;IASpB;;OAEG;IACH,IAAW,MAAM,IAAI,OAAO,CAE3B;IAED;;OAEG;IACH,OAAO,CAAC,gBAAgB;IAkDxB,qEAAqE;IACrE,OAAO,CAAC,iBAAiB;IAkHzB,OAAO,CAAC,qBAAqB;IAU7B;;OAEG;IACH,OAAO,CAAC,kBAAkB;IAsB1B;;OAEG;IACH,OAAO,CAAC,UAAU;IAYlB;;OAEG;IACH,OAAO,CAAC,cAAc;IAStB,oBAAoB;IACpB,IAAW,SAAS,IAAI,MAAM,GAAG,SAAS,CAEzC;IAED,2CAA2C;IAC3C,IAAW,iBAAiB,IAAI,iBAAiB,CAEhD;IAED,OAAO,CAAC,kBAAkB;IAoC1B,OAAO,CAAC,mBAAmB;IA4B3B;;;;OAIG;IACH,OAAO,CAAC,WAAW;IAuBnB;;OAEG;IACH,OAAO,CAAC,aAAa;IA2IrB;;OAEG;IACH,OAAO,CAAC,kBAAkB;IAanB,GAAG,CAAC,UAAU,EAAE,UAAU,GAAG,IAAI;IACjC,GAAG,CAAC,IAAI,EAAE,WAAW,EAAE,UAAU,EAAE,UAAU,GAAG,IAAI;IAepD,EAAE,CAAC,IAAI,EAAE,MAAM,EAAE,OAAO,EAAE,aAAa,GAAG,MAAM,IAAI;IAU3D,OAAO,CAAC,cAAc;IA4Cf,GAAG,CAAC,IAAI,EAAE,MAAM,GAAG,MAAM,EAAE,GAAG,IAAI;IAYlC,GAAG,CAAC,QAAQ,EAAE,MAAM,CAAC,MAAM,EAAE,aAAa,CAAC,GAAG,CAAC,MAAM,IAAI,CAAC;IAUjE;;OAEG;IACI,OAAO,IAAI,IAAI;CAgBvB"}
1
+ {"version":3,"file":"server.d.ts","sourceRoot":"","sources":["../../src/core/server.ts"],"names":[],"mappings":"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"}
@@ -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,6 +80,15 @@ 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);
@@ -87,6 +100,39 @@ class RequestIframeServerImpl {
87
100
  }
88
101
  }
89
102
 
103
+ /**
104
+ * Check whether an incoming message origin is allowed.
105
+ */
106
+ isOriginAllowed(data, context) {
107
+ if (!this.originValidator) return true;
108
+ try {
109
+ return this.originValidator(context.origin, data, context);
110
+ } catch (_unused) {
111
+ return false;
112
+ }
113
+ }
114
+
115
+ /**
116
+ * Build a per-client key used for concurrency limiting.
117
+ * We intentionally include origin to prevent cross-origin collisions.
118
+ */
119
+ getClientKey(origin, creatorId) {
120
+ return `${origin}::${creatorId || 'unknown'}`;
121
+ }
122
+ incInFlight(clientKey) {
123
+ var current = this.inFlightByClientKey.get(clientKey) || 0;
124
+ this.inFlightByClientKey.set(clientKey, current + 1);
125
+ }
126
+ decInFlight(clientKey) {
127
+ var current = this.inFlightByClientKey.get(clientKey) || 0;
128
+ var next = current - 1;
129
+ if (next <= 0) {
130
+ this.inFlightByClientKey.delete(clientKey);
131
+ return;
132
+ }
133
+ this.inFlightByClientKey.set(clientKey, next);
134
+ }
135
+
90
136
  /**
91
137
  * Open message processing (register message handlers)
92
138
  */
@@ -130,22 +176,27 @@ class RequestIframeServerImpl {
130
176
  // Handle PING messages
131
177
  this.unregisterFns.push(this.dispatcher.registerHandler(_constants.MessageType.PING, (data, context) => this.handlePing(data, context), handlerOptions));
132
178
 
179
+ // Handle PONG messages (server -> client heartbeat)
180
+ this.unregisterFns.push(this.dispatcher.registerHandler(_constants.MessageType.PONG, (data, context) => this.handlePong(data, context), handlerOptions));
181
+
133
182
  // Handle RECEIVED messages (for confirming response delivery)
134
- this.unregisterFns.push(this.dispatcher.registerHandler(_constants.MessageType.RECEIVED, data => this.handleReceived(data), handlerOptions));
183
+ this.unregisterFns.push(this.dispatcher.registerHandler(_constants.MessageType.RECEIVED, (data, context) => this.handleReceived(data, context), handlerOptions));
135
184
 
136
185
  // Handle stream_* messages (client→server stream)
137
186
  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));
187
+ this.unregisterFns.push(this.dispatcher.registerHandler(type => type.startsWith('stream_') && type !== _constants.MessageType.STREAM_START, (data, context) => this.dispatchStreamMessage(data, context), handlerOptions));
139
188
  }
140
189
 
141
190
  /** Handle stream_start from client (stream request with streamId) */
142
- handleStreamStart(data, _context) {
191
+ handleStreamStart(data, context) {
143
192
  var _body$chunked;
144
193
  if (data.role !== _constants.MessageRole.CLIENT) return;
194
+ if (!this.isOriginAllowed(data, context)) return;
145
195
  var body = data.body;
146
196
  if (!(body !== null && body !== void 0 && body.streamId)) return;
147
197
  var pending = this.pendingStreamRequests.get(data.requestId);
148
198
  if (!pending || pending.streamId !== body.streamId) return;
199
+ clearTimeout(pending.timeoutId);
149
200
  this.pendingStreamRequests.delete(data.requestId);
150
201
  var targetWindow = pending.targetWindow,
151
202
  targetOrigin = pending.targetOrigin,
@@ -165,6 +216,7 @@ class RequestIframeServerImpl {
165
216
  }
166
217
  };
167
218
  var streamType = body.type || _constants.StreamType.DATA;
219
+ var streamMode = body.mode;
168
220
  var streamChunked = (_body$chunked = body.chunked) !== null && _body$chunked !== void 0 ? _body$chunked : true;
169
221
  var streamMetadata = body.metadata;
170
222
  var req = new _request.ServerRequestImpl(reqData, reqContext, res, pending.params);
@@ -175,6 +227,8 @@ class RequestIframeServerImpl {
175
227
  var fileStream = new _stream.IframeFileReadableStream(body.streamId, data.requestId, streamHandler, {
176
228
  chunked: streamChunked,
177
229
  metadata: streamMetadata,
230
+ secretKey: data.secretKey,
231
+ mode: streamMode,
178
232
  filename: streamMetadata === null || streamMetadata === void 0 ? void 0 : streamMetadata.filename,
179
233
  mimeType: streamMetadata === null || streamMetadata === void 0 ? void 0 : streamMetadata.mimeType,
180
234
  size: streamMetadata === null || streamMetadata === void 0 ? void 0 : streamMetadata.size
@@ -216,8 +270,10 @@ class RequestIframeServerImpl {
216
270
  // Non-file stream
217
271
  var readableStream = new _stream.IframeReadableStream(body.streamId, data.requestId, streamHandler, {
218
272
  type: streamType,
273
+ mode: streamMode,
219
274
  chunked: streamChunked,
220
- metadata: streamMetadata
275
+ metadata: streamMetadata,
276
+ secretKey: data.secretKey
221
277
  });
222
278
  req.body = undefined;
223
279
  req.stream = readableStream;
@@ -240,7 +296,8 @@ class RequestIframeServerImpl {
240
296
  }
241
297
  });
242
298
  }
243
- dispatchStreamMessage(data) {
299
+ dispatchStreamMessage(data, context) {
300
+ if (!this.isOriginAllowed(data, context)) return;
244
301
  var body = data.body;
245
302
  if (!(body !== null && body !== void 0 && body.streamId)) return;
246
303
  var handler = this.streamHandlers.get(body.streamId);
@@ -276,20 +333,67 @@ class RequestIframeServerImpl {
276
333
  */
277
334
  handlePing(data, context) {
278
335
  if (!context.source) return;
336
+ if (!this.isOriginAllowed(data, context)) return;
337
+
338
+ /**
339
+ * Only allow one server instance to respond.
340
+ * This is important when multiple server instances share the same channel.
341
+ */
342
+ if (!context.handledBy) {
343
+ // Mark as accepted so MessageDispatcher can auto-send ACK when requireAck === true
344
+ context.accepted = true;
345
+ context.handledBy = this.id;
346
+ }
279
347
 
280
348
  // Window check is handled in MessageDispatcher
281
349
  this.dispatcher.sendMessage(context.source, context.origin, _constants.MessageType.PONG, data.requestId);
282
350
  }
351
+ handlePong(data, context) {
352
+ if (!this.isOriginAllowed(data, context)) return;
353
+ var pending = this.pendingPongs.get(data.requestId);
354
+ if (pending) {
355
+ if (!context.handledBy) {
356
+ context.accepted = true;
357
+ context.handledBy = this.id;
358
+ }
359
+ clearTimeout(pending.timeoutId);
360
+ this.pendingPongs.delete(data.requestId);
361
+ pending.resolve(true);
362
+ }
363
+ }
364
+ pingClient(targetWindow, targetOrigin, targetClientId) {
365
+ var requestId = (0, _utils.generateRequestId)();
366
+ return new Promise(resolve => {
367
+ var timeoutId = setTimeout(() => {
368
+ this.pendingPongs.delete(requestId);
369
+ resolve(false);
370
+ }, this.ackTimeout);
371
+ this.pendingPongs.set(requestId, {
372
+ resolve,
373
+ timeoutId
374
+ });
375
+ // Window check is handled in MessageDispatcher
376
+ this.dispatcher.sendMessage(targetWindow, targetOrigin, _constants.MessageType.PING, requestId, {
377
+ requireAck: true,
378
+ targetId: targetClientId
379
+ });
380
+ });
381
+ }
283
382
 
284
383
  /**
285
384
  * Handle received acknowledgment
286
385
  */
287
- handleReceived(data) {
386
+ handleReceived(data, context) {
387
+ if (!this.isOriginAllowed(data, context)) return;
288
388
  var pending = this.pendingAcks.get(data.requestId);
289
389
  if (pending) {
390
+ // Best-effort: prevent other server instances from also resolving
391
+ if (!context.handledBy) {
392
+ context.handledBy = this.id;
393
+ }
290
394
  clearTimeout(pending.timeoutId);
291
395
  this.pendingAcks.delete(data.requestId);
292
- pending.resolve(true);
396
+ pending.resolve(true, data.ackMeta);
293
397
  }
294
398
  }
295
399
 
@@ -304,6 +408,7 @@ class RequestIframeServerImpl {
304
408
  }
305
409
  handleRequestError(res, targetWindow, targetOrigin, data, err) {
306
410
  if (!res._sent) {
411
+ res._markSent();
307
412
  /**
308
413
  * Use INTERNAL_SERVER_ERROR (500) for handler errors unless a different error status code was explicitly set.
309
414
  * If statusCode is still the default OK (200), override it to INTERNAL_SERVER_ERROR.
@@ -328,6 +433,7 @@ class RequestIframeServerImpl {
328
433
  if (!res._sent && result !== undefined) {
329
434
  res.send(result);
330
435
  } else if (!res._sent) {
436
+ res._markSent();
331
437
  this.dispatcher.sendMessage(targetWindow, targetOrigin, _constants.MessageType.ERROR, data.requestId, {
332
438
  path: data.path,
333
439
  error: {
@@ -392,6 +498,7 @@ class RequestIframeServerImpl {
392
498
  // If targetId is specified, only process if it matches this server's id
393
499
  if (!data.path || data.targetId && data.targetId !== this.id) return;
394
500
  if (!context.source) return;
501
+ if (!this.isOriginAllowed(data, context)) return;
395
502
 
396
503
  // If message has already been handled by another server instance, skip processing
397
504
  if (context.handledBy) {
@@ -425,25 +532,51 @@ class RequestIframeServerImpl {
425
532
  }
426
533
  var handlerFn = handlerMatch.handler,
427
534
  params = handlerMatch.params;
535
+ var clientKey = this.getClientKey(targetOrigin, data.creatorId);
536
+ if (Number.isFinite(this.maxConcurrentRequestsPerClient)) {
537
+ var inFlight = this.inFlightByClientKey.get(clientKey) || 0;
538
+ if (inFlight >= this.maxConcurrentRequestsPerClient) {
539
+ // Prevent other server instances from also responding
540
+ context.handledBy = this.id;
541
+ this.dispatcher.sendMessage(targetWindow, targetOrigin, _constants.MessageType.ERROR, data.requestId, {
542
+ path: data.path,
543
+ error: {
544
+ message: (0, _constants.formatMessage)(_constants.Messages.TOO_MANY_REQUESTS, this.maxConcurrentRequestsPerClient),
545
+ code: _constants.ErrorCode.TOO_MANY_REQUESTS
546
+ },
547
+ status: _constants.HttpStatus.TOO_MANY_REQUESTS,
548
+ statusText: _constants.HttpStatusText[_constants.HttpStatus.TOO_MANY_REQUESTS],
549
+ requireAck: data.requireAck,
550
+ ackMeta: data.ackMeta,
551
+ targetId: data.creatorId
552
+ });
553
+ return;
554
+ }
555
+ }
556
+ this.incInFlight(clientKey);
557
+
558
+ // Mark as accepted so MessageDispatcher can auto-send ACK (delivery confirmation)
559
+ context.accepted = true;
428
560
 
429
561
  // Mark message as handled by this server instance to prevent other server instances from processing it
430
562
  context.handledBy = this.id;
431
563
 
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
564
  // Create response object with channel reference
441
565
  // 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);
566
+ var res = new _response.ServerResponseImpl(data.requestId, data.path || '', data.secretKey, targetWindow, targetOrigin, this.dispatcher.getChannel(), this.id, data.creatorId, {
567
+ registerStreamHandler: (streamId, handler) => {
568
+ this.streamHandlers.set(streamId, handler);
569
+ },
570
+ unregisterStreamHandler: streamId => {
571
+ this.streamHandlers.delete(streamId);
572
+ },
573
+ heartbeat: () => this.pingClient(targetWindow, targetOrigin, data.creatorId),
574
+ onSent: () => this.decInFlight(clientKey)
575
+ });
443
576
 
444
577
  // Register callback waiting for client acknowledgment
445
- this.registerPendingAck(data.requestId, received => {
446
- res._triggerAck(received);
578
+ this.registerPendingAck(data.requestId, (received, ackMeta) => {
579
+ res._triggerAck(received, ackMeta);
447
580
  }, () => {
448
581
  res._triggerAck(false);
449
582
  });
@@ -452,10 +585,32 @@ class RequestIframeServerImpl {
452
585
  // If streamId is present, this is a stream request
453
586
  var streamId = data.streamId;
454
587
  if (streamId) {
588
+ var streamStartTimeout = this.ackTimeout;
589
+ var timeoutId = setTimeout(() => {
590
+ var pending = this.pendingStreamRequests.get(data.requestId);
591
+ if (!pending) return;
592
+ this.pendingStreamRequests.delete(data.requestId);
593
+ if (!pending.res._sent) {
594
+ pending.res._markSent();
595
+ this.dispatcher.sendMessage(pending.targetWindow, pending.targetOrigin, _constants.MessageType.ERROR, pending.requestId, {
596
+ path: pending.path,
597
+ error: {
598
+ message: (0, _constants.formatMessage)(_constants.Messages.STREAM_START_TIMEOUT, streamStartTimeout),
599
+ code: _constants.ErrorCode.STREAM_START_TIMEOUT
600
+ },
601
+ status: _constants.HttpStatus.REQUEST_TIMEOUT,
602
+ statusText: _constants.HttpStatusText[_constants.HttpStatus.REQUEST_TIMEOUT],
603
+ requireAck: pending.data.requireAck,
604
+ ackMeta: pending.data.ackMeta,
605
+ targetId: pending.data.creatorId
606
+ });
607
+ }
608
+ }, streamStartTimeout);
455
609
  this.pendingStreamRequests.set(data.requestId, {
456
610
  path: data.path || '',
457
611
  requestId: data.requestId,
458
612
  streamId,
613
+ timeoutId,
459
614
  handlerFn,
460
615
  targetWindow,
461
616
  targetOrigin,
@@ -598,10 +753,16 @@ class RequestIframeServerImpl {
598
753
  // Clean up pending
599
754
  this.pendingAcks.forEach(pending => clearTimeout(pending.timeoutId));
600
755
  this.pendingAcks.clear();
756
+ this.pendingPongs.forEach(pending => clearTimeout(pending.timeoutId));
757
+ this.pendingPongs.clear();
758
+ this.pendingStreamRequests.forEach(pending => clearTimeout(pending.timeoutId));
759
+ this.pendingStreamRequests.clear();
760
+ this.inFlightByClientKey.clear();
601
761
 
602
762
  // Clean up handlers
603
763
  this.handlers.clear();
604
764
  this.middlewares.length = 0;
765
+ this.streamHandlers.clear();
605
766
 
606
767
  // Destroy dispatcher and release channel reference
607
768
  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/RECEIVED 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;AAGlB;;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,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"}
@@ -52,6 +52,13 @@ export declare class MessageDispatcher {
52
52
  private readonly instanceId?;
53
53
  /** Underlying message channel */
54
54
  private readonly channel;
55
+ /**
56
+ * Fallback target for sending auto-ack messages when MessageEvent.source is unavailable.
57
+ * - In real browser postMessage events, `source` should normally exist.
58
+ * - This is primarily used for unit tests or edge environments that synthesize MessageEvent without `source`.
59
+ */
60
+ private fallbackTargetWindow?;
61
+ private fallbackTargetOrigin;
55
62
  /** Message handler list */
56
63
  private readonly handlers;
57
64
  /** Message receiver callback (bound to this) */
@@ -59,6 +66,10 @@ export declare class MessageDispatcher {
59
66
  /** Reference count (for determining if can be destroyed when cached) */
60
67
  private refCount;
61
68
  constructor(channel: MessageChannel, role: MessageRoleValue, instanceId?: string);
69
+ /**
70
+ * Set fallback target for outgoing auto-ack messages.
71
+ */
72
+ setFallbackTarget(targetWindow: Window, targetOrigin?: string): void;
62
73
  /**
63
74
  * Increment reference count
64
75
  */
@@ -88,6 +99,17 @@ export declare class MessageDispatcher {
88
99
  * Dispatch message to matching handlers
89
100
  */
90
101
  private dispatchMessage;
102
+ /**
103
+ * Auto-ack logic (generalized requireAck workflow)
104
+ *
105
+ * Notes:
106
+ * - This is intentionally conservative: it only runs after the message is marked as handled
107
+ * (via `context.handledBy`) to avoid acknowledging messages that no consumer will process.
108
+ * - For backward compatibility:
109
+ * - REQUEST defaults to requiring ACK unless `requireAck === false`
110
+ * - Other message types only ack when `requireAck === true`
111
+ */
112
+ private tryAutoAck;
91
113
  /**
92
114
  * Check if message type matches
93
115
  */
@@ -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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"}