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.
- package/README.CN.md +53 -6
- package/README.md +63 -10
- package/esm/api/client.js +79 -0
- package/esm/api/server.js +59 -0
- package/esm/constants/index.js +257 -0
- package/esm/constants/messages.js +155 -0
- package/esm/core/client-server.js +329 -0
- package/esm/core/client.js +873 -0
- package/esm/core/request.js +27 -0
- package/esm/core/response.js +451 -0
- package/esm/core/server.js +767 -0
- package/esm/index.js +21 -0
- package/esm/interceptors/index.js +122 -0
- package/esm/message/channel.js +181 -0
- package/esm/message/dispatcher.js +380 -0
- package/esm/message/index.js +2 -0
- package/esm/stream/file-stream.js +289 -0
- package/esm/stream/index.js +44 -0
- package/esm/stream/readable-stream.js +500 -0
- package/esm/stream/stream-core.js +91 -0
- package/esm/stream/types.js +1 -0
- package/esm/stream/writable-stream.js +582 -0
- package/esm/types/index.js +1 -0
- package/esm/utils/ack-meta.js +53 -0
- package/esm/utils/cache.js +147 -0
- package/esm/utils/cookie.js +352 -0
- package/esm/utils/debug.js +521 -0
- package/esm/utils/error.js +27 -0
- package/esm/utils/index.js +178 -0
- package/esm/utils/origin.js +28 -0
- package/esm/utils/path-match.js +148 -0
- package/esm/utils/protocol.js +157 -0
- package/library/api/client.d.ts.map +1 -1
- package/library/api/client.js +8 -1
- package/library/api/server.d.ts.map +1 -1
- package/library/api/server.js +4 -1
- package/library/constants/index.d.ts +25 -1
- package/library/constants/index.d.ts.map +1 -1
- package/library/constants/index.js +30 -5
- package/library/constants/messages.d.ts +5 -0
- package/library/constants/messages.d.ts.map +1 -1
- package/library/constants/messages.js +5 -0
- package/library/core/client-server.d.ts +3 -2
- package/library/core/client-server.d.ts.map +1 -1
- package/library/core/client-server.js +51 -4
- package/library/core/client.d.ts +4 -1
- package/library/core/client.d.ts.map +1 -1
- package/library/core/client.js +74 -31
- package/library/core/response.d.ts +21 -3
- package/library/core/response.d.ts.map +1 -1
- package/library/core/response.js +46 -6
- package/library/core/server.d.ts +28 -1
- package/library/core/server.d.ts.map +1 -1
- package/library/core/server.js +180 -19
- package/library/message/channel.d.ts +6 -0
- package/library/message/channel.d.ts.map +1 -1
- package/library/message/dispatcher.d.ts +22 -0
- package/library/message/dispatcher.d.ts.map +1 -1
- package/library/message/dispatcher.js +92 -0
- package/library/stream/file-stream.d.ts +4 -0
- package/library/stream/file-stream.d.ts.map +1 -1
- package/library/stream/file-stream.js +61 -33
- package/library/stream/index.d.ts.map +1 -1
- package/library/stream/index.js +2 -0
- package/library/stream/readable-stream.d.ts +30 -11
- package/library/stream/readable-stream.d.ts.map +1 -1
- package/library/stream/readable-stream.js +329 -73
- package/library/stream/stream-core.d.ts +44 -0
- package/library/stream/stream-core.d.ts.map +1 -0
- package/library/stream/stream-core.js +98 -0
- package/library/stream/types.d.ts +90 -3
- package/library/stream/types.d.ts.map +1 -1
- package/library/stream/writable-stream.d.ts +40 -12
- package/library/stream/writable-stream.d.ts.map +1 -1
- package/library/stream/writable-stream.js +391 -195
- package/library/types/index.d.ts +70 -3
- package/library/types/index.d.ts.map +1 -1
- package/library/utils/ack-meta.d.ts +2 -0
- package/library/utils/ack-meta.d.ts.map +1 -0
- package/library/utils/ack-meta.js +59 -0
- package/library/utils/index.d.ts +1 -0
- package/library/utils/index.d.ts.map +1 -1
- package/library/utils/index.js +16 -0
- package/library/utils/origin.d.ts +14 -0
- package/library/utils/origin.d.ts.map +1 -0
- package/library/utils/origin.js +34 -0
- package/package.json +30 -7
- package/react/README.md +16 -0
- package/react/esm/index.js +284 -0
- package/react/library/index.d.ts +1 -1
- package/react/library/index.d.ts.map +1 -1
- package/react/library/index.js +3 -3
- package/react/package.json +24 -2
package/library/core/response.js
CHANGED
|
@@ -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.
|
|
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(
|
|
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.
|
|
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
|
});
|
package/library/core/server.d.ts
CHANGED
|
@@ -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,
|
|
1
|
+
{"version":3,"file":"server.d.ts","sourceRoot":"","sources":["../../src/core/server.ts"],"names":[],"mappings":"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"}
|
package/library/core/server.js
CHANGED
|
@@ -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,
|
|
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,
|
|
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,
|
|
1
|
+
{"version":3,"file":"dispatcher.d.ts","sourceRoot":"","sources":["../../src/message/dispatcher.ts"],"names":[],"mappings":"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"}
|