request-iframe 0.0.5 → 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 +54 -7
- package/README.md +64 -11
- 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 +31 -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 +7 -4
- package/react/package.json +24 -2
- package/library/__tests__/channel.test.ts +0 -432
- package/library/__tests__/coverage-branches.test.ts +0 -356
- package/library/__tests__/debug.test.ts +0 -610
- package/library/__tests__/dispatcher.test.ts +0 -485
- package/library/__tests__/interceptors.test.ts +0 -146
- package/library/__tests__/requestIframe.test.ts +0 -5590
- package/library/__tests__/server.test.ts +0 -738
- package/library/__tests__/stream.test.ts +0 -726
- package/library/__tests__/utils.test.ts +0 -473
- package/library/api/client.d.js +0 -5
- package/library/api/server.d.js +0 -5
- package/library/constants/index.d.js +0 -36
- package/library/constants/messages.d.js +0 -5
- package/library/core/client.d.js +0 -5
- package/library/core/message-handler.d.ts +0 -110
- package/library/core/message-handler.d.ts.map +0 -1
- package/library/core/message-handler.js +0 -320
- package/library/core/request-response.d.ts +0 -59
- package/library/core/request-response.d.ts.map +0 -1
- package/library/core/request-response.js +0 -337
- package/library/core/request.d.js +0 -5
- package/library/core/response.d.js +0 -5
- package/library/core/server-base.d.ts +0 -86
- package/library/core/server-base.d.ts.map +0 -1
- package/library/core/server-base.js +0 -257
- package/library/core/server-client.d.js +0 -5
- package/library/core/server-client.d.ts +0 -101
- package/library/core/server-client.d.ts.map +0 -1
- package/library/core/server-client.js +0 -266
- package/library/core/server.d.js +0 -5
- package/library/interceptors/index.d.js +0 -5
- package/library/message/channel.d.js +0 -5
- package/library/message/dispatcher.d.js +0 -5
- package/library/message/index.d.js +0 -25
- package/library/stream/file-stream.d.js +0 -4
- package/library/stream/index.d.js +0 -58
- package/library/stream/readable-stream.d.js +0 -5
- package/library/stream/types.d.js +0 -5
- package/library/stream/writable-stream.d.js +0 -5
- package/library/types/index.d.js +0 -5
- package/library/utils/cache.d.js +0 -5
- package/library/utils/cookie.d.js +0 -5
- package/library/utils/debug.d.js +0 -5
- package/library/utils/index.d.js +0 -94
- package/library/utils/path-match.d.js +0 -5
- package/library/utils/protocol.d.js +0 -5
- package/react/library/__tests__/index.test.d.ts +0 -2
- package/react/library/__tests__/index.test.d.ts.map +0 -1
- package/react/library/__tests__/index.test.tsx +0 -792
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
import _slicedToArray from "@babel/runtime/helpers/esm/slicedToArray";
|
|
2
|
+
import "core-js/modules/es.object.entries.js";
|
|
3
|
+
/**
|
|
4
|
+
* ServerRequest implementation
|
|
5
|
+
*/
|
|
6
|
+
export class ServerRequestImpl {
|
|
7
|
+
constructor(data, context, response, params = {}) {
|
|
8
|
+
this.body = data.body;
|
|
9
|
+
// headers may contain array values (e.g., Set-Cookie), simplified to string here
|
|
10
|
+
this.headers = {};
|
|
11
|
+
if (data.headers) {
|
|
12
|
+
for (var _i = 0, _Object$entries = Object.entries(data.headers); _i < _Object$entries.length; _i++) {
|
|
13
|
+
var _Object$entries$_i = _slicedToArray(_Object$entries[_i], 2),
|
|
14
|
+
key = _Object$entries$_i[0],
|
|
15
|
+
value = _Object$entries$_i[1];
|
|
16
|
+
this.headers[key] = Array.isArray(value) ? value.join(', ') : value;
|
|
17
|
+
}
|
|
18
|
+
}
|
|
19
|
+
this.cookies = data.cookies || {};
|
|
20
|
+
this.path = data.path || '';
|
|
21
|
+
this.params = params;
|
|
22
|
+
this.requestId = data.requestId;
|
|
23
|
+
this.origin = context.origin;
|
|
24
|
+
this.source = context.source;
|
|
25
|
+
this.res = response;
|
|
26
|
+
}
|
|
27
|
+
}
|
|
@@ -0,0 +1,451 @@
|
|
|
1
|
+
import _asyncToGenerator from "@babel/runtime/helpers/esm/asyncToGenerator";
|
|
2
|
+
import _defineProperty from "@babel/runtime/helpers/esm/defineProperty";
|
|
3
|
+
import _regeneratorRuntime from "@babel/runtime/regenerator";
|
|
4
|
+
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; }
|
|
5
|
+
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) { _defineProperty(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; }
|
|
6
|
+
import "core-js/modules/es.array.iterator.js";
|
|
7
|
+
import "core-js/modules/es.array.filter.js";
|
|
8
|
+
import "core-js/modules/es.object.get-own-property-descriptors.js";
|
|
9
|
+
import "core-js/modules/es.promise.js";
|
|
10
|
+
import "core-js/modules/web.dom-collections.for-each.js";
|
|
11
|
+
import "core-js/modules/web.dom-collections.iterator.js";
|
|
12
|
+
import { createPostMessage, createSetCookie, createClearCookie, detectContentType, blobToBase64 } from '../utils';
|
|
13
|
+
import { MessageType, HttpStatus, HttpHeader, getStatusText, MessageRole, ErrorCode } from '../constants';
|
|
14
|
+
import { IframeFileWritableStream, isIframeWritableStream } from '../stream';
|
|
15
|
+
import { isAckMetaEqual } from '../utils/ack-meta';
|
|
16
|
+
|
|
17
|
+
/**
|
|
18
|
+
* Callback waiting for client acknowledgment
|
|
19
|
+
*/
|
|
20
|
+
|
|
21
|
+
/**
|
|
22
|
+
* ServerResponse implementation
|
|
23
|
+
*/
|
|
24
|
+
export class ServerResponseImpl {
|
|
25
|
+
constructor(requestId, path, secretKey, targetWindow, targetOrigin, channel, serverId, targetId, options) {
|
|
26
|
+
_defineProperty(this, "statusCode", HttpStatus.OK);
|
|
27
|
+
_defineProperty(this, "headers", {});
|
|
28
|
+
_defineProperty(this, "_sent", false);
|
|
29
|
+
this.requestId = requestId;
|
|
30
|
+
this.path = path;
|
|
31
|
+
this.secretKey = secretKey;
|
|
32
|
+
this.targetWindow = targetWindow;
|
|
33
|
+
this.targetOrigin = targetOrigin;
|
|
34
|
+
this.channel = channel;
|
|
35
|
+
this.serverId = serverId;
|
|
36
|
+
this.targetId = targetId;
|
|
37
|
+
this.registerStreamHandler = options === null || options === void 0 ? void 0 : options.registerStreamHandler;
|
|
38
|
+
this.unregisterStreamHandler = options === null || options === void 0 ? void 0 : options.unregisterStreamHandler;
|
|
39
|
+
this.heartbeat = options === null || options === void 0 ? void 0 : options.heartbeat;
|
|
40
|
+
this.onSentCallback = options === null || options === void 0 ? void 0 : options.onSent;
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
/**
|
|
44
|
+
* Send message via channel
|
|
45
|
+
*/
|
|
46
|
+
sendMessage(message) {
|
|
47
|
+
// Window check is handled in MessageDispatcher (via channel.send -> dispatcher.send)
|
|
48
|
+
this.channel.send(this.targetWindow, message, this.targetOrigin);
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
/**
|
|
52
|
+
* Check if header exists (case-insensitive)
|
|
53
|
+
*/
|
|
54
|
+
hasHeader(name) {
|
|
55
|
+
var lower = name.toLowerCase();
|
|
56
|
+
return Object.keys(this.headers).some(k => k.toLowerCase() === lower);
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
/**
|
|
60
|
+
* Detect data type and return appropriate Content-Type
|
|
61
|
+
* Returns null if Content-Type should not be auto-set
|
|
62
|
+
*/
|
|
63
|
+
detectContentType(data) {
|
|
64
|
+
return detectContentType(data, {
|
|
65
|
+
checkStream: true,
|
|
66
|
+
isIframeWritableStream
|
|
67
|
+
});
|
|
68
|
+
}
|
|
69
|
+
|
|
70
|
+
/**
|
|
71
|
+
* Auto set Content-Type based on data type (only if user not set)
|
|
72
|
+
*/
|
|
73
|
+
ensureContentTypeIfNeeded(data) {
|
|
74
|
+
if (this.hasHeader(HttpHeader.CONTENT_TYPE)) return;
|
|
75
|
+
var contentType = this.detectContentType(data);
|
|
76
|
+
if (contentType) {
|
|
77
|
+
this.setHeader(HttpHeader.CONTENT_TYPE, contentType);
|
|
78
|
+
}
|
|
79
|
+
}
|
|
80
|
+
|
|
81
|
+
/**
|
|
82
|
+
* Set callback waiting for client acknowledgment
|
|
83
|
+
*/
|
|
84
|
+
_setOnAckCallback(callback) {
|
|
85
|
+
this.onAckCallback = callback;
|
|
86
|
+
}
|
|
87
|
+
|
|
88
|
+
/**
|
|
89
|
+
* Trigger client acknowledgment callback
|
|
90
|
+
*/
|
|
91
|
+
_triggerAck(received, ackMeta) {
|
|
92
|
+
if (this.onAckCallback) {
|
|
93
|
+
this.onAckCallback(received, ackMeta);
|
|
94
|
+
this.onAckCallback = undefined;
|
|
95
|
+
}
|
|
96
|
+
}
|
|
97
|
+
|
|
98
|
+
/**
|
|
99
|
+
* Mark response as sent (and trigger onSent callback once).
|
|
100
|
+
*/
|
|
101
|
+
markSent() {
|
|
102
|
+
if (this._sent) return;
|
|
103
|
+
this._sent = true;
|
|
104
|
+
if (this.onSentCallback) {
|
|
105
|
+
var cb = this.onSentCallback;
|
|
106
|
+
this.onSentCallback = undefined;
|
|
107
|
+
cb();
|
|
108
|
+
}
|
|
109
|
+
}
|
|
110
|
+
|
|
111
|
+
/**
|
|
112
|
+
* Internal: mark as sent for manual error responses.
|
|
113
|
+
*/
|
|
114
|
+
_markSent() {
|
|
115
|
+
this.markSent();
|
|
116
|
+
}
|
|
117
|
+
|
|
118
|
+
/**
|
|
119
|
+
* Internal method: send raw data (used by send after type detection)
|
|
120
|
+
*/
|
|
121
|
+
_sendRaw(data, options) {
|
|
122
|
+
var _options$requireAck;
|
|
123
|
+
if (this._sent) return Promise.resolve(false);
|
|
124
|
+
this.markSent();
|
|
125
|
+
var requireAck = (_options$requireAck = options === null || options === void 0 ? void 0 : options.requireAck) !== null && _options$requireAck !== void 0 ? _options$requireAck : false;
|
|
126
|
+
var expectedAckMeta = options === null || options === void 0 ? void 0 : options.ackMeta;
|
|
127
|
+
try {
|
|
128
|
+
// If acknowledgment not required, send directly and return true
|
|
129
|
+
if (!requireAck) {
|
|
130
|
+
this.sendMessage(createPostMessage(MessageType.RESPONSE, this.requestId, {
|
|
131
|
+
path: this.path,
|
|
132
|
+
secretKey: this.secretKey,
|
|
133
|
+
data,
|
|
134
|
+
status: this.statusCode,
|
|
135
|
+
statusText: getStatusText(this.statusCode),
|
|
136
|
+
headers: this.headers,
|
|
137
|
+
requireAck: false,
|
|
138
|
+
role: MessageRole.SERVER,
|
|
139
|
+
creatorId: this.serverId,
|
|
140
|
+
targetId: this.targetId
|
|
141
|
+
}));
|
|
142
|
+
return Promise.resolve(true);
|
|
143
|
+
}
|
|
144
|
+
|
|
145
|
+
// Acknowledgment required, wait for client response
|
|
146
|
+
return new Promise((resolve, reject) => {
|
|
147
|
+
try {
|
|
148
|
+
this._setOnAckCallback((received, receivedAckMeta) => {
|
|
149
|
+
if (!received) {
|
|
150
|
+
resolve(false);
|
|
151
|
+
return;
|
|
152
|
+
}
|
|
153
|
+
if (expectedAckMeta !== undefined && !isAckMetaEqual(expectedAckMeta, receivedAckMeta)) {
|
|
154
|
+
resolve(false);
|
|
155
|
+
return;
|
|
156
|
+
}
|
|
157
|
+
resolve(true);
|
|
158
|
+
});
|
|
159
|
+
this.sendMessage(createPostMessage(MessageType.RESPONSE, this.requestId, {
|
|
160
|
+
path: this.path,
|
|
161
|
+
secretKey: this.secretKey,
|
|
162
|
+
data,
|
|
163
|
+
status: this.statusCode,
|
|
164
|
+
statusText: getStatusText(this.statusCode),
|
|
165
|
+
headers: this.headers,
|
|
166
|
+
requireAck: true,
|
|
167
|
+
ackMeta: expectedAckMeta,
|
|
168
|
+
role: MessageRole.SERVER,
|
|
169
|
+
creatorId: this.serverId,
|
|
170
|
+
targetId: this.targetId
|
|
171
|
+
}));
|
|
172
|
+
} catch (error) {
|
|
173
|
+
// If window is closed, reject immediately
|
|
174
|
+
if ((error === null || error === void 0 ? void 0 : error.code) === ErrorCode.TARGET_WINDOW_CLOSED) {
|
|
175
|
+
reject(error);
|
|
176
|
+
} else {
|
|
177
|
+
throw error;
|
|
178
|
+
}
|
|
179
|
+
}
|
|
180
|
+
});
|
|
181
|
+
} catch (error) {
|
|
182
|
+
// If window is closed, return rejected promise
|
|
183
|
+
if ((error === null || error === void 0 ? void 0 : error.code) === ErrorCode.TARGET_WINDOW_CLOSED) {
|
|
184
|
+
return Promise.reject(error);
|
|
185
|
+
}
|
|
186
|
+
throw error;
|
|
187
|
+
}
|
|
188
|
+
}
|
|
189
|
+
|
|
190
|
+
/**
|
|
191
|
+
* Universal send method - automatically detects data type and calls appropriate method
|
|
192
|
+
* - If data is IframeWritableStream, calls sendStream
|
|
193
|
+
* - If data is File/Blob, calls sendFile
|
|
194
|
+
* - Otherwise, sends as regular data with auto-detected Content-Type
|
|
195
|
+
*/
|
|
196
|
+
send(data, options) {
|
|
197
|
+
var _this = this;
|
|
198
|
+
return _asyncToGenerator(/*#__PURE__*/_regeneratorRuntime.mark(function _callee() {
|
|
199
|
+
var fileOptions;
|
|
200
|
+
return _regeneratorRuntime.wrap(function (_context) {
|
|
201
|
+
while (1) switch (_context.prev = _context.next) {
|
|
202
|
+
case 0:
|
|
203
|
+
if (!_this._sent) {
|
|
204
|
+
_context.next = 1;
|
|
205
|
+
break;
|
|
206
|
+
}
|
|
207
|
+
return _context.abrupt("return", Promise.resolve(false));
|
|
208
|
+
case 1:
|
|
209
|
+
if (!isIframeWritableStream(data)) {
|
|
210
|
+
_context.next = 3;
|
|
211
|
+
break;
|
|
212
|
+
}
|
|
213
|
+
_context.next = 2;
|
|
214
|
+
return _this.sendStream(data);
|
|
215
|
+
case 2:
|
|
216
|
+
return _context.abrupt("return", true);
|
|
217
|
+
case 3:
|
|
218
|
+
if (!(typeof File !== 'undefined' && data instanceof File || typeof Blob !== 'undefined' && data instanceof Blob)) {
|
|
219
|
+
_context.next = 4;
|
|
220
|
+
break;
|
|
221
|
+
}
|
|
222
|
+
// Extract options for sendFile
|
|
223
|
+
fileOptions = _objectSpread({
|
|
224
|
+
requireAck: options === null || options === void 0 ? void 0 : options.requireAck
|
|
225
|
+
}, typeof File !== 'undefined' && data instanceof File ? {
|
|
226
|
+
mimeType: data.type,
|
|
227
|
+
fileName: data.name
|
|
228
|
+
} : {});
|
|
229
|
+
return _context.abrupt("return", _this.sendFile(data, fileOptions));
|
|
230
|
+
case 4:
|
|
231
|
+
// For other types, auto-detect and set Content-Type, then send
|
|
232
|
+
_this.ensureContentTypeIfNeeded(data);
|
|
233
|
+
return _context.abrupt("return", _this._sendRaw(data, options));
|
|
234
|
+
case 5:
|
|
235
|
+
case "end":
|
|
236
|
+
return _context.stop();
|
|
237
|
+
}
|
|
238
|
+
}, _callee);
|
|
239
|
+
}))();
|
|
240
|
+
}
|
|
241
|
+
json(data, options) {
|
|
242
|
+
return this.send(data, options);
|
|
243
|
+
}
|
|
244
|
+
sendFile(content, options) {
|
|
245
|
+
var _this2 = this;
|
|
246
|
+
return _asyncToGenerator(/*#__PURE__*/_regeneratorRuntime.mark(function _callee3() {
|
|
247
|
+
var mimeType, fileName, fileContent, stream;
|
|
248
|
+
return _regeneratorRuntime.wrap(function (_context3) {
|
|
249
|
+
while (1) switch (_context3.prev = _context3.next) {
|
|
250
|
+
case 0:
|
|
251
|
+
if (!_this2._sent) {
|
|
252
|
+
_context3.next = 1;
|
|
253
|
+
break;
|
|
254
|
+
}
|
|
255
|
+
return _context3.abrupt("return", false);
|
|
256
|
+
case 1:
|
|
257
|
+
mimeType = (options === null || options === void 0 ? void 0 : options.mimeType) || 'application/octet-stream';
|
|
258
|
+
fileName = options === null || options === void 0 ? void 0 : options.fileName;
|
|
259
|
+
if (!(typeof content === 'string')) {
|
|
260
|
+
_context3.next = 2;
|
|
261
|
+
break;
|
|
262
|
+
}
|
|
263
|
+
// If it's a plain string, convert to base64
|
|
264
|
+
fileContent = btoa(unescape(encodeURIComponent(content)));
|
|
265
|
+
_context3.next = 6;
|
|
266
|
+
break;
|
|
267
|
+
case 2:
|
|
268
|
+
if (!(content instanceof File)) {
|
|
269
|
+
_context3.next = 4;
|
|
270
|
+
break;
|
|
271
|
+
}
|
|
272
|
+
mimeType = content.type || mimeType;
|
|
273
|
+
fileName = fileName || content.name;
|
|
274
|
+
_context3.next = 3;
|
|
275
|
+
return blobToBase64(content);
|
|
276
|
+
case 3:
|
|
277
|
+
fileContent = _context3.sent;
|
|
278
|
+
_context3.next = 6;
|
|
279
|
+
break;
|
|
280
|
+
case 4:
|
|
281
|
+
_context3.next = 5;
|
|
282
|
+
return blobToBase64(content);
|
|
283
|
+
case 5:
|
|
284
|
+
fileContent = _context3.sent;
|
|
285
|
+
case 6:
|
|
286
|
+
// Set file-related headers
|
|
287
|
+
_this2.setHeader(HttpHeader.CONTENT_TYPE, mimeType);
|
|
288
|
+
if (fileName) {
|
|
289
|
+
_this2.setHeader(HttpHeader.CONTENT_DISPOSITION, `attachment; filename="${fileName}"`);
|
|
290
|
+
} else {
|
|
291
|
+
_this2.setHeader(HttpHeader.CONTENT_DISPOSITION, 'attachment');
|
|
292
|
+
}
|
|
293
|
+
|
|
294
|
+
// Create file stream with autoResolve enabled
|
|
295
|
+
stream = new IframeFileWritableStream({
|
|
296
|
+
filename: fileName || 'file',
|
|
297
|
+
mimeType,
|
|
298
|
+
chunked: false,
|
|
299
|
+
// File is sent in one chunk
|
|
300
|
+
autoResolve: true,
|
|
301
|
+
// Client will automatically resolve to fileData
|
|
302
|
+
next: function () {
|
|
303
|
+
var _next = _asyncToGenerator(/*#__PURE__*/_regeneratorRuntime.mark(function _callee2() {
|
|
304
|
+
return _regeneratorRuntime.wrap(function (_context2) {
|
|
305
|
+
while (1) switch (_context2.prev = _context2.next) {
|
|
306
|
+
case 0:
|
|
307
|
+
return _context2.abrupt("return", {
|
|
308
|
+
data: fileContent,
|
|
309
|
+
done: true
|
|
310
|
+
});
|
|
311
|
+
case 1:
|
|
312
|
+
case "end":
|
|
313
|
+
return _context2.stop();
|
|
314
|
+
}
|
|
315
|
+
}, _callee2);
|
|
316
|
+
}));
|
|
317
|
+
function next() {
|
|
318
|
+
return _next.apply(this, arguments);
|
|
319
|
+
}
|
|
320
|
+
return next;
|
|
321
|
+
}()
|
|
322
|
+
}); // Send stream (this will handle the requireAck logic internally and set _sent)
|
|
323
|
+
_context3.next = 7;
|
|
324
|
+
return _this2.sendStream(stream);
|
|
325
|
+
case 7:
|
|
326
|
+
return _context3.abrupt("return", true);
|
|
327
|
+
case 8:
|
|
328
|
+
case "end":
|
|
329
|
+
return _context3.stop();
|
|
330
|
+
}
|
|
331
|
+
}, _callee3);
|
|
332
|
+
}))();
|
|
333
|
+
}
|
|
334
|
+
|
|
335
|
+
/**
|
|
336
|
+
* Send stream response
|
|
337
|
+
* Bind stream to current request context and start stream transmission
|
|
338
|
+
*/
|
|
339
|
+
sendStream(stream) {
|
|
340
|
+
var _this3 = this;
|
|
341
|
+
return _asyncToGenerator(/*#__PURE__*/_regeneratorRuntime.mark(function _callee4() {
|
|
342
|
+
return _regeneratorRuntime.wrap(function (_context4) {
|
|
343
|
+
while (1) switch (_context4.prev = _context4.next) {
|
|
344
|
+
case 0:
|
|
345
|
+
if (!_this3._sent) {
|
|
346
|
+
_context4.next = 1;
|
|
347
|
+
break;
|
|
348
|
+
}
|
|
349
|
+
return _context4.abrupt("return");
|
|
350
|
+
case 1:
|
|
351
|
+
_this3.markSent();
|
|
352
|
+
|
|
353
|
+
// Window check is handled in MessageDispatcher when stream sends messages
|
|
354
|
+
|
|
355
|
+
// Bind stream to request context
|
|
356
|
+
stream._bind({
|
|
357
|
+
requestId: _this3.requestId,
|
|
358
|
+
targetWindow: _this3.targetWindow,
|
|
359
|
+
targetOrigin: _this3.targetOrigin,
|
|
360
|
+
secretKey: _this3.secretKey,
|
|
361
|
+
channel: _this3.channel,
|
|
362
|
+
registerStreamHandler: _this3.registerStreamHandler,
|
|
363
|
+
unregisterStreamHandler: _this3.unregisterStreamHandler,
|
|
364
|
+
heartbeat: _this3.heartbeat,
|
|
365
|
+
serverId: _this3.serverId,
|
|
366
|
+
targetId: _this3.targetId
|
|
367
|
+
});
|
|
368
|
+
|
|
369
|
+
// Start stream transmission
|
|
370
|
+
_context4.next = 2;
|
|
371
|
+
return stream.start();
|
|
372
|
+
case 2:
|
|
373
|
+
case "end":
|
|
374
|
+
return _context4.stop();
|
|
375
|
+
}
|
|
376
|
+
}, _callee4);
|
|
377
|
+
}))();
|
|
378
|
+
}
|
|
379
|
+
status(code) {
|
|
380
|
+
this.statusCode = code;
|
|
381
|
+
return this;
|
|
382
|
+
}
|
|
383
|
+
setHeader(name, value) {
|
|
384
|
+
// Consistent with Express, returns void
|
|
385
|
+
// Special handling for Set-Cookie, keep as array
|
|
386
|
+
if (name.toLowerCase() === HttpHeader.SET_COOKIE.toLowerCase()) {
|
|
387
|
+
var existing = this.headers[HttpHeader.SET_COOKIE];
|
|
388
|
+
if (Array.isArray(value)) {
|
|
389
|
+
this.headers[HttpHeader.SET_COOKIE] = Array.isArray(existing) ? [...existing, ...value] : value;
|
|
390
|
+
} else {
|
|
391
|
+
var newValue = String(value);
|
|
392
|
+
if (Array.isArray(existing)) {
|
|
393
|
+
existing.push(newValue);
|
|
394
|
+
} else {
|
|
395
|
+
this.headers[HttpHeader.SET_COOKIE] = [newValue];
|
|
396
|
+
}
|
|
397
|
+
}
|
|
398
|
+
} else if (Array.isArray(value)) {
|
|
399
|
+
this.headers[name] = value.join(', ');
|
|
400
|
+
} else {
|
|
401
|
+
this.headers[name] = String(value);
|
|
402
|
+
}
|
|
403
|
+
}
|
|
404
|
+
set(name, value) {
|
|
405
|
+
// Chainable version, compatible with Express res.set
|
|
406
|
+
this.setHeader(name, value);
|
|
407
|
+
return this;
|
|
408
|
+
}
|
|
409
|
+
cookie(name, value, options) {
|
|
410
|
+
/**
|
|
411
|
+
* Set Cookie (similar to HTTP Set-Cookie)
|
|
412
|
+
* Generate Set-Cookie string and add to headers[HttpHeader.SET_COOKIE] array
|
|
413
|
+
* Client will parse and save to cookie storage upon receiving
|
|
414
|
+
*/
|
|
415
|
+
var setCookieStr = createSetCookie(name, value, {
|
|
416
|
+
path: options === null || options === void 0 ? void 0 : options.path,
|
|
417
|
+
expires: options === null || options === void 0 ? void 0 : options.expires,
|
|
418
|
+
maxAge: options === null || options === void 0 ? void 0 : options.maxAge,
|
|
419
|
+
httpOnly: options === null || options === void 0 ? void 0 : options.httpOnly,
|
|
420
|
+
secure: options === null || options === void 0 ? void 0 : options.secure,
|
|
421
|
+
sameSite: (options === null || options === void 0 ? void 0 : options.sameSite) === true ? 'Strict' : (options === null || options === void 0 ? void 0 : options.sameSite) === false ? undefined : options === null || options === void 0 ? void 0 : options.sameSite
|
|
422
|
+
});
|
|
423
|
+
|
|
424
|
+
// Add to Set-Cookie header array
|
|
425
|
+
var existing = this.headers[HttpHeader.SET_COOKIE];
|
|
426
|
+
if (Array.isArray(existing)) {
|
|
427
|
+
existing.push(setCookieStr);
|
|
428
|
+
} else {
|
|
429
|
+
this.headers[HttpHeader.SET_COOKIE] = [setCookieStr];
|
|
430
|
+
}
|
|
431
|
+
return this;
|
|
432
|
+
}
|
|
433
|
+
clearCookie(name, options) {
|
|
434
|
+
/**
|
|
435
|
+
* Clear specified Cookie
|
|
436
|
+
* Generate an expired Set-Cookie string, client will delete this cookie upon receiving
|
|
437
|
+
*/
|
|
438
|
+
var setCookieStr = createClearCookie(name, {
|
|
439
|
+
path: options === null || options === void 0 ? void 0 : options.path
|
|
440
|
+
});
|
|
441
|
+
|
|
442
|
+
// Add to Set-Cookie header array
|
|
443
|
+
var existing = this.headers[HttpHeader.SET_COOKIE];
|
|
444
|
+
if (Array.isArray(existing)) {
|
|
445
|
+
existing.push(setCookieStr);
|
|
446
|
+
} else {
|
|
447
|
+
this.headers[HttpHeader.SET_COOKIE] = [setCookieStr];
|
|
448
|
+
}
|
|
449
|
+
return this;
|
|
450
|
+
}
|
|
451
|
+
}
|