request-iframe 0.1.0 → 0.1.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.CN.md +174 -22
- package/README.md +166 -22
- package/esm/api/client.js +6 -5
- package/esm/api/server.js +3 -1
- package/esm/constants/index.js +38 -6
- package/esm/constants/messages.js +3 -1
- package/esm/core/client-server.js +8 -43
- package/esm/core/client.js +7 -7
- package/esm/core/response.js +16 -8
- package/esm/core/server.js +18 -9
- package/esm/message/channel.js +2 -1
- package/esm/message/dispatcher.js +63 -25
- package/esm/stream/readable-stream.js +57 -18
- package/esm/stream/stream-core.js +115 -2
- package/esm/stream/writable-stream.js +281 -27
- package/esm/utils/ack.js +36 -0
- package/esm/utils/debug.js +1 -1
- package/esm/utils/index.js +5 -3
- package/esm/utils/origin.js +3 -1
- package/library/api/client.d.ts.map +1 -1
- package/library/api/client.js +5 -4
- package/library/api/server.d.ts.map +1 -1
- package/library/api/server.js +3 -1
- package/library/constants/index.d.ts +36 -5
- package/library/constants/index.d.ts.map +1 -1
- package/library/constants/index.js +41 -8
- package/library/constants/messages.d.ts +3 -1
- package/library/constants/messages.d.ts.map +1 -1
- package/library/constants/messages.js +3 -1
- package/library/core/client-server.d.ts +4 -13
- package/library/core/client-server.d.ts.map +1 -1
- package/library/core/client-server.js +7 -42
- package/library/core/client.d.ts.map +1 -1
- package/library/core/client.js +6 -6
- package/library/core/response.d.ts +2 -2
- package/library/core/response.d.ts.map +1 -1
- package/library/core/response.js +15 -7
- package/library/core/server.d.ts +6 -2
- package/library/core/server.d.ts.map +1 -1
- package/library/core/server.js +18 -9
- package/library/message/channel.d.ts +1 -1
- package/library/message/channel.d.ts.map +1 -1
- package/library/message/channel.js +2 -1
- package/library/message/dispatcher.d.ts +10 -0
- package/library/message/dispatcher.d.ts.map +1 -1
- package/library/message/dispatcher.js +62 -24
- package/library/stream/readable-stream.d.ts.map +1 -1
- package/library/stream/readable-stream.js +56 -17
- package/library/stream/stream-core.d.ts +22 -1
- package/library/stream/stream-core.d.ts.map +1 -1
- package/library/stream/stream-core.js +114 -1
- package/library/stream/types.d.ts +115 -2
- package/library/stream/types.d.ts.map +1 -1
- package/library/stream/writable-stream.d.ts +20 -2
- package/library/stream/writable-stream.d.ts.map +1 -1
- package/library/stream/writable-stream.js +277 -23
- package/library/types/index.d.ts +3 -4
- package/library/types/index.d.ts.map +1 -1
- package/library/utils/ack.d.ts +2 -0
- package/library/utils/ack.d.ts.map +1 -0
- package/library/utils/ack.js +44 -0
- package/library/utils/debug.js +1 -1
- package/library/utils/index.d.ts.map +1 -1
- package/library/utils/index.js +4 -3
- package/library/utils/origin.d.ts.map +1 -1
- package/library/utils/origin.js +2 -1
- package/package.json +1 -1
- package/esm/utils/ack-meta.js +0 -53
- package/library/utils/ack-meta.d.ts +0 -2
- package/library/utils/ack-meta.d.ts.map +0 -1
- package/library/utils/ack-meta.js +0 -59
|
@@ -1,17 +1,20 @@
|
|
|
1
1
|
import _asyncToGenerator from "@babel/runtime/helpers/esm/asyncToGenerator";
|
|
2
2
|
import _defineProperty from "@babel/runtime/helpers/esm/defineProperty";
|
|
3
|
+
import _regeneratorRuntime from "@babel/runtime/regenerator";
|
|
3
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; }
|
|
4
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; }
|
|
5
|
-
import _regeneratorRuntime from "@babel/runtime/regenerator";
|
|
6
|
-
import "core-js/modules/es.array.slice.js";
|
|
7
6
|
import "core-js/modules/es.array.filter.js";
|
|
8
|
-
import "core-js/modules/es.
|
|
7
|
+
import "core-js/modules/es.array.iterator.js";
|
|
8
|
+
import "core-js/modules/es.array.slice.js";
|
|
9
|
+
import "core-js/modules/es.map.js";
|
|
9
10
|
import "core-js/modules/es.promise.js";
|
|
10
11
|
import "core-js/modules/es.promise.finally.js";
|
|
12
|
+
import "core-js/modules/es.object.get-own-property-descriptors.js";
|
|
11
13
|
import "core-js/modules/es.regexp.to-string.js";
|
|
12
14
|
import "core-js/modules/web.dom-collections.for-each.js";
|
|
13
|
-
import
|
|
14
|
-
import {
|
|
15
|
+
import "core-js/modules/web.dom-collections.iterator.js";
|
|
16
|
+
import { createPostMessage, generateRequestId } from '../utils';
|
|
17
|
+
import { MessageType, Messages, StreamType as StreamTypeConstant, StreamState as StreamStateConstant, StreamMode as StreamModeConstant, MessageRole, formatMessage, DefaultTimeout, StreamInternalMessageType, StreamEvent } from '../constants';
|
|
15
18
|
import { IframeStreamCore } from './stream-core';
|
|
16
19
|
|
|
17
20
|
/**
|
|
@@ -23,7 +26,11 @@ function generateStreamId() {
|
|
|
23
26
|
|
|
24
27
|
/**
|
|
25
28
|
* IframeWritableStream - Server-side writable stream
|
|
26
|
-
*
|
|
29
|
+
*
|
|
30
|
+
* Writer/producer stream.
|
|
31
|
+
* It can be created on either side:
|
|
32
|
+
* - Server → Client: used as response stream (via `res.sendStream(stream)`)
|
|
33
|
+
* - Client → Server: used as request body stream (via `client.sendStream(path, stream)`)
|
|
27
34
|
*/
|
|
28
35
|
export class IframeWritableStream extends IframeStreamCore {
|
|
29
36
|
constructor(options = {}) {
|
|
@@ -40,11 +47,14 @@ export class IframeWritableStream extends IframeStreamCore {
|
|
|
40
47
|
/** pull/ack protocol */
|
|
41
48
|
_defineProperty(this, "pullCredit", 0);
|
|
42
49
|
_defineProperty(this, "seq", 0);
|
|
50
|
+
_defineProperty(this, "pendingBytes", 0);
|
|
43
51
|
_defineProperty(this, "pendingQueue", []);
|
|
44
52
|
_defineProperty(this, "pumping", false);
|
|
45
53
|
_defineProperty(this, "completionPromise", null);
|
|
46
54
|
_defineProperty(this, "resolveCompletion", null);
|
|
47
55
|
_defineProperty(this, "rejectCompletion", null);
|
|
56
|
+
_defineProperty(this, "ackWaiters", new Map());
|
|
57
|
+
_defineProperty(this, "ackReceiverRegistered", false);
|
|
48
58
|
this.mode = (_options$mode = options.mode) !== null && _options$mode !== void 0 ? _options$mode : StreamModeConstant.PULL;
|
|
49
59
|
this.iterator = options.iterator;
|
|
50
60
|
this.nextFn = options.next;
|
|
@@ -52,6 +62,72 @@ export class IframeWritableStream extends IframeStreamCore {
|
|
|
52
62
|
// Default to async-timeout length to avoid leaking long-lived streams
|
|
53
63
|
this.expireTimeout = (_options$expireTimeou = options.expireTimeout) !== null && _options$expireTimeou !== void 0 ? _options$expireTimeou : DefaultTimeout.ASYNC;
|
|
54
64
|
this.streamTimeout = options.streamTimeout;
|
|
65
|
+
this.maxPendingChunks = options.maxPendingChunks;
|
|
66
|
+
this.maxPendingBytes = options.maxPendingBytes;
|
|
67
|
+
}
|
|
68
|
+
enqueue(item) {
|
|
69
|
+
var max = this.maxPendingChunks;
|
|
70
|
+
if (typeof max === 'number' && max > 0 && this.pendingQueue.length >= max) {
|
|
71
|
+
throw new Error(formatMessage(Messages.STREAM_PENDING_QUEUE_OVERFLOW, max));
|
|
72
|
+
}
|
|
73
|
+
var bytes = this.estimateChunkBytes(item.data);
|
|
74
|
+
var maxBytes = this.maxPendingBytes;
|
|
75
|
+
if (typeof maxBytes === 'number' && maxBytes > 0) {
|
|
76
|
+
var next = this.pendingBytes + bytes;
|
|
77
|
+
if (!Number.isFinite(next) || next > maxBytes) {
|
|
78
|
+
throw new Error(formatMessage(Messages.STREAM_PENDING_BYTES_OVERFLOW, maxBytes));
|
|
79
|
+
}
|
|
80
|
+
}
|
|
81
|
+
this.pendingQueue.push(_objectSpread(_objectSpread({}, item), {}, {
|
|
82
|
+
bytes
|
|
83
|
+
}));
|
|
84
|
+
this.pendingBytes += bytes;
|
|
85
|
+
}
|
|
86
|
+
estimateChunkBytes(data) {
|
|
87
|
+
if (data === null || data === undefined) return 0;
|
|
88
|
+
if (typeof data === 'string') return this.utf8ByteLength(data);
|
|
89
|
+
try {
|
|
90
|
+
// ArrayBuffer
|
|
91
|
+
if (typeof ArrayBuffer !== 'undefined' && data instanceof ArrayBuffer) {
|
|
92
|
+
return data.byteLength;
|
|
93
|
+
}
|
|
94
|
+
// TypedArray / DataView
|
|
95
|
+
if (typeof ArrayBuffer !== 'undefined' && ArrayBuffer.isView && ArrayBuffer.isView(data)) {
|
|
96
|
+
return data.byteLength;
|
|
97
|
+
}
|
|
98
|
+
} catch (_unused) {
|
|
99
|
+
/** ignore */
|
|
100
|
+
}
|
|
101
|
+
try {
|
|
102
|
+
// Blob / File
|
|
103
|
+
if (typeof Blob !== 'undefined' && data instanceof Blob) {
|
|
104
|
+
return data.size;
|
|
105
|
+
}
|
|
106
|
+
} catch (_unused2) {
|
|
107
|
+
/** ignore */
|
|
108
|
+
}
|
|
109
|
+
|
|
110
|
+
// Strategy C: only count well-defined types; other values are not counted.
|
|
111
|
+
return 0;
|
|
112
|
+
}
|
|
113
|
+
utf8ByteLength(text) {
|
|
114
|
+
try {
|
|
115
|
+
if (typeof TextEncoder !== 'undefined') {
|
|
116
|
+
return new TextEncoder().encode(text).length;
|
|
117
|
+
}
|
|
118
|
+
} catch (_unused3) {
|
|
119
|
+
/** ignore */
|
|
120
|
+
}
|
|
121
|
+
try {
|
|
122
|
+
// eslint-disable-next-line no-undef
|
|
123
|
+
if (typeof Buffer !== 'undefined') {
|
|
124
|
+
// eslint-disable-next-line no-undef
|
|
125
|
+
return Buffer.byteLength(text, 'utf8');
|
|
126
|
+
}
|
|
127
|
+
} catch (_unused4) {
|
|
128
|
+
/** ignore */
|
|
129
|
+
}
|
|
130
|
+
return text.length;
|
|
55
131
|
}
|
|
56
132
|
|
|
57
133
|
/** Get stream state */
|
|
@@ -84,14 +160,19 @@ export class IframeWritableStream extends IframeStreamCore {
|
|
|
84
160
|
{
|
|
85
161
|
var credit = typeof data.credit === 'number' && data.credit > 0 ? data.credit : 1;
|
|
86
162
|
this.pullCredit += credit;
|
|
163
|
+
this.emit(StreamEvent.PULL, {
|
|
164
|
+
credit,
|
|
165
|
+
totalCredit: this.pullCredit
|
|
166
|
+
});
|
|
87
167
|
// Try flushing buffered chunks or pumping generator
|
|
88
168
|
this.flush();
|
|
89
169
|
break;
|
|
90
170
|
}
|
|
91
|
-
case StreamInternalMessageType.ACK:
|
|
92
|
-
// Ack is treated as heartbeat; no further action required
|
|
93
|
-
break;
|
|
94
171
|
case StreamInternalMessageType.CANCEL:
|
|
172
|
+
this.emit(StreamEvent.CANCEL, {
|
|
173
|
+
reason: data.reason,
|
|
174
|
+
remote: true
|
|
175
|
+
});
|
|
95
176
|
this.cancel(data.reason);
|
|
96
177
|
break;
|
|
97
178
|
default:
|
|
@@ -166,8 +247,11 @@ export class IframeWritableStream extends IframeStreamCore {
|
|
|
166
247
|
return _context2.abrupt("return");
|
|
167
248
|
case 4:
|
|
168
249
|
try {
|
|
250
|
+
_this2.emit(StreamEvent.TIMEOUT, {
|
|
251
|
+
timeout
|
|
252
|
+
});
|
|
169
253
|
_this2.error(formatMessage(Messages.STREAM_TIMEOUT, timeout));
|
|
170
|
-
} catch (
|
|
254
|
+
} catch (_unused5) {
|
|
171
255
|
/** ignore */
|
|
172
256
|
}
|
|
173
257
|
case 5:
|
|
@@ -208,6 +292,54 @@ export class IframeWritableStream extends IframeStreamCore {
|
|
|
208
292
|
}
|
|
209
293
|
return true;
|
|
210
294
|
}
|
|
295
|
+
ensureAckReceiver() {
|
|
296
|
+
if (this.ackReceiverRegistered) return;
|
|
297
|
+
if (!this.context) return;
|
|
298
|
+
var ch = this.context.channel;
|
|
299
|
+
if (typeof ch.addReceiver !== 'function' || typeof ch.removeReceiver !== 'function') return;
|
|
300
|
+
this.ackReceiver = (data, context) => {
|
|
301
|
+
if (!data || data.type !== MessageType.ACK) return;
|
|
302
|
+
var pending = this.ackWaiters.get(data.requestId);
|
|
303
|
+
if (!pending) return;
|
|
304
|
+
if (context && !context.handledBy) {
|
|
305
|
+
context.handledBy = `stream:${this.streamId}`;
|
|
306
|
+
}
|
|
307
|
+
clearTimeout(pending.timeoutId);
|
|
308
|
+
this.ackWaiters.delete(data.requestId);
|
|
309
|
+
pending.resolve(true);
|
|
310
|
+
};
|
|
311
|
+
ch.addReceiver(this.ackReceiver);
|
|
312
|
+
this.ackReceiverRegistered = true;
|
|
313
|
+
}
|
|
314
|
+
cleanupAckWaiters() {
|
|
315
|
+
this.ackWaiters.forEach(p => {
|
|
316
|
+
clearTimeout(p.timeoutId);
|
|
317
|
+
p.resolve(false);
|
|
318
|
+
});
|
|
319
|
+
this.ackWaiters.clear();
|
|
320
|
+
if (this.ackReceiverRegistered && this.ackReceiver && this.context) {
|
|
321
|
+
var ch = this.context.channel;
|
|
322
|
+
if (typeof ch.removeReceiver === 'function') {
|
|
323
|
+
try {
|
|
324
|
+
ch.removeReceiver(this.ackReceiver);
|
|
325
|
+
} catch (_unused6) {
|
|
326
|
+
/** ignore */
|
|
327
|
+
}
|
|
328
|
+
}
|
|
329
|
+
}
|
|
330
|
+
this.ackReceiverRegistered = false;
|
|
331
|
+
this.ackReceiver = undefined;
|
|
332
|
+
}
|
|
333
|
+
registerAckWaiter(requestId, timeoutMs, resolve) {
|
|
334
|
+
var timeoutId = setTimeout(() => {
|
|
335
|
+
this.ackWaiters.delete(requestId);
|
|
336
|
+
resolve(false);
|
|
337
|
+
}, timeoutMs);
|
|
338
|
+
this.ackWaiters.set(requestId, {
|
|
339
|
+
resolve,
|
|
340
|
+
timeoutId
|
|
341
|
+
});
|
|
342
|
+
}
|
|
211
343
|
clearExpireTimer() {
|
|
212
344
|
if (this.expireTimer) {
|
|
213
345
|
clearTimeout(this.expireTimer);
|
|
@@ -221,8 +353,11 @@ export class IframeWritableStream extends IframeStreamCore {
|
|
|
221
353
|
this.expireTimer = setTimeout(() => {
|
|
222
354
|
if (this._state !== StreamStateConstant.STREAMING) return;
|
|
223
355
|
try {
|
|
356
|
+
this.emit(StreamEvent.EXPIRED, {
|
|
357
|
+
timeout: expireTimeout
|
|
358
|
+
});
|
|
224
359
|
this.error(formatMessage(Messages.STREAM_EXPIRED, expireTimeout));
|
|
225
|
-
} catch (
|
|
360
|
+
} catch (_unused7) {
|
|
226
361
|
/** ignore timer-triggered send failures */
|
|
227
362
|
}
|
|
228
363
|
}, expireTimeout);
|
|
@@ -268,6 +403,13 @@ export class IframeWritableStream extends IframeStreamCore {
|
|
|
268
403
|
metadata: _this3.metadata,
|
|
269
404
|
autoResolve: _this3.autoResolve
|
|
270
405
|
});
|
|
406
|
+
_this3.emit(StreamEvent.START, {
|
|
407
|
+
streamId: _this3.streamId,
|
|
408
|
+
type: _this3.type,
|
|
409
|
+
chunked: _this3.chunked,
|
|
410
|
+
mode: _this3.mode,
|
|
411
|
+
metadata: _this3.metadata
|
|
412
|
+
});
|
|
271
413
|
_context3.prev = 3;
|
|
272
414
|
if (!(_this3.mode === StreamModeConstant.PUSH)) {
|
|
273
415
|
_context3.next = 5;
|
|
@@ -310,7 +452,9 @@ export class IframeWritableStream extends IframeStreamCore {
|
|
|
310
452
|
/**
|
|
311
453
|
* Push a chunk manually (mode === 'push').
|
|
312
454
|
*/
|
|
313
|
-
|
|
455
|
+
|
|
456
|
+
write(data, doneOrOptions = false, options) {
|
|
457
|
+
var _opts$ackTimeout;
|
|
314
458
|
if (this.mode !== StreamModeConstant.PUSH) {
|
|
315
459
|
throw new Error(Messages.STREAM_WRITE_ONLY_IN_PUSH_MODE);
|
|
316
460
|
}
|
|
@@ -323,12 +467,39 @@ export class IframeWritableStream extends IframeStreamCore {
|
|
|
323
467
|
if (this._state !== StreamStateConstant.STREAMING) {
|
|
324
468
|
throw new Error(Messages.STREAM_ENDED);
|
|
325
469
|
}
|
|
326
|
-
|
|
327
|
-
|
|
328
|
-
|
|
329
|
-
|
|
470
|
+
var done = typeof doneOrOptions === 'boolean' ? doneOrOptions : false;
|
|
471
|
+
var opts = typeof doneOrOptions === 'object' ? doneOrOptions : options;
|
|
472
|
+
var requireAck = (opts === null || opts === void 0 ? void 0 : opts.requireAck) === true;
|
|
473
|
+
var ackTimeout = (_opts$ackTimeout = opts === null || opts === void 0 ? void 0 : opts.ackTimeout) !== null && _opts$ackTimeout !== void 0 ? _opts$ackTimeout : DefaultTimeout.ACK;
|
|
474
|
+
if (!requireAck) {
|
|
475
|
+
// push mode now buffers and sends based on pull credit
|
|
476
|
+
this.enqueue({
|
|
477
|
+
data,
|
|
478
|
+
done
|
|
479
|
+
});
|
|
480
|
+
this.emit(StreamEvent.WRITE, {
|
|
481
|
+
data,
|
|
482
|
+
done
|
|
483
|
+
});
|
|
484
|
+
this.flush();
|
|
485
|
+
return;
|
|
486
|
+
}
|
|
487
|
+
return new Promise(resolve => {
|
|
488
|
+
var ackRequestId = generateRequestId();
|
|
489
|
+
this.enqueue({
|
|
490
|
+
data,
|
|
491
|
+
done,
|
|
492
|
+
requireAck: true,
|
|
493
|
+
ackRequestId,
|
|
494
|
+
ackTimeout,
|
|
495
|
+
resolveAck: resolve
|
|
496
|
+
});
|
|
497
|
+
this.emit(StreamEvent.WRITE, {
|
|
498
|
+
data,
|
|
499
|
+
done
|
|
500
|
+
});
|
|
501
|
+
this.flush();
|
|
330
502
|
});
|
|
331
|
-
this.flush();
|
|
332
503
|
}
|
|
333
504
|
|
|
334
505
|
/**
|
|
@@ -343,7 +514,7 @@ export class IframeWritableStream extends IframeStreamCore {
|
|
|
343
514
|
// In push mode, end means enqueue a terminal marker if nothing queued
|
|
344
515
|
if (this.mode === StreamModeConstant.PUSH) {
|
|
345
516
|
if (this.pendingQueue.length === 0) {
|
|
346
|
-
this.
|
|
517
|
+
this.enqueue({
|
|
347
518
|
data: undefined,
|
|
348
519
|
done: true
|
|
349
520
|
});
|
|
@@ -403,7 +574,7 @@ export class IframeWritableStream extends IframeStreamCore {
|
|
|
403
574
|
_this4.endInternal();
|
|
404
575
|
return _context4.abrupt("continue", 7);
|
|
405
576
|
case 6:
|
|
406
|
-
_this4.
|
|
577
|
+
_this4.enqueue({
|
|
407
578
|
data: r.value,
|
|
408
579
|
done: false
|
|
409
580
|
});
|
|
@@ -433,7 +604,7 @@ export class IframeWritableStream extends IframeStreamCore {
|
|
|
433
604
|
return Promise.resolve(_this4.nextFn());
|
|
434
605
|
case 11:
|
|
435
606
|
result = _context4.sent;
|
|
436
|
-
_this4.
|
|
607
|
+
_this4.enqueue({
|
|
437
608
|
data: result.data,
|
|
438
609
|
done: result.done
|
|
439
610
|
});
|
|
@@ -478,11 +649,46 @@ export class IframeWritableStream extends IframeStreamCore {
|
|
|
478
649
|
/**
|
|
479
650
|
* Send data chunk
|
|
480
651
|
*/
|
|
481
|
-
sendData(data, done = false) {
|
|
482
|
-
|
|
483
|
-
|
|
484
|
-
|
|
485
|
-
|
|
652
|
+
sendData(data, done = false, options) {
|
|
653
|
+
var _this$context$serverI2, _options$requestId;
|
|
654
|
+
if (!this.context) {
|
|
655
|
+
throw new Error(Messages.STREAM_NOT_BOUND);
|
|
656
|
+
}
|
|
657
|
+
var seq = this.seq++;
|
|
658
|
+
var isClientStream = this.context.clientId !== undefined && this.context.serverId === undefined;
|
|
659
|
+
var role = isClientStream ? MessageRole.CLIENT : MessageRole.SERVER;
|
|
660
|
+
var creatorId = (_this$context$serverI2 = this.context.serverId) !== null && _this$context$serverI2 !== void 0 ? _this$context$serverI2 : this.context.clientId;
|
|
661
|
+
var message = createPostMessage(MessageType.STREAM_DATA, (_options$requestId = options === null || options === void 0 ? void 0 : options.requestId) !== null && _options$requestId !== void 0 ? _options$requestId : this.context.requestId, {
|
|
662
|
+
secretKey: this.context.secretKey,
|
|
663
|
+
requireAck: options === null || options === void 0 ? void 0 : options.requireAck,
|
|
664
|
+
/**
|
|
665
|
+
* When per-frame requireAck is enabled, include a unique identifier in ack.
|
|
666
|
+
* - seq is the stream frame sequence number.
|
|
667
|
+
*
|
|
668
|
+
* NOTE: ack is an internal reserved field (not part of public API).
|
|
669
|
+
*/
|
|
670
|
+
ack: options !== null && options !== void 0 && options.requireAck ? {
|
|
671
|
+
id: `${this.streamId}:${seq}`
|
|
672
|
+
} : undefined,
|
|
673
|
+
body: {
|
|
674
|
+
streamId: this.streamId,
|
|
675
|
+
data: this.encodeData(data),
|
|
676
|
+
done,
|
|
677
|
+
seq
|
|
678
|
+
},
|
|
679
|
+
role,
|
|
680
|
+
creatorId,
|
|
681
|
+
targetId: this.context.targetId
|
|
682
|
+
});
|
|
683
|
+
var ok = this.context.channel.send(this.context.targetWindow, message, this.context.targetOrigin);
|
|
684
|
+
if (!ok) {
|
|
685
|
+
this._state = StreamStateConstant.CANCELLED;
|
|
686
|
+
this.clearExpireTimer();
|
|
687
|
+
throw new Error(formatMessage(Messages.STREAM_CANCELLED, 'Target window closed'));
|
|
688
|
+
}
|
|
689
|
+
this.emit(StreamEvent.SEND, {
|
|
690
|
+
seq,
|
|
691
|
+
done
|
|
486
692
|
});
|
|
487
693
|
}
|
|
488
694
|
flush() {
|
|
@@ -494,9 +700,25 @@ export class IframeWritableStream extends IframeStreamCore {
|
|
|
494
700
|
}
|
|
495
701
|
while (this.pullCredit > 0 && this.pendingQueue.length > 0 && this._state === StreamStateConstant.STREAMING) {
|
|
496
702
|
var item = this.pendingQueue.shift();
|
|
703
|
+
this.pendingBytes -= item.bytes;
|
|
497
704
|
this.pullCredit--;
|
|
498
705
|
try {
|
|
499
|
-
|
|
706
|
+
if (item.requireAck && item.ackRequestId && item.resolveAck) {
|
|
707
|
+
this.ensureAckReceiver();
|
|
708
|
+
if (this.ackReceiverRegistered) {
|
|
709
|
+
var _item$ackTimeout;
|
|
710
|
+
this.registerAckWaiter(item.ackRequestId, (_item$ackTimeout = item.ackTimeout) !== null && _item$ackTimeout !== void 0 ? _item$ackTimeout : DefaultTimeout.ACK, item.resolveAck);
|
|
711
|
+
this.sendData(item.data, item.done, {
|
|
712
|
+
requestId: item.ackRequestId,
|
|
713
|
+
requireAck: true
|
|
714
|
+
});
|
|
715
|
+
} else {
|
|
716
|
+
item.resolveAck(false);
|
|
717
|
+
this.sendData(item.data, item.done);
|
|
718
|
+
}
|
|
719
|
+
} else {
|
|
720
|
+
this.sendData(item.data, item.done);
|
|
721
|
+
}
|
|
500
722
|
} catch (e) {
|
|
501
723
|
var _this$rejectCompletio;
|
|
502
724
|
// send failure treated as cancellation
|
|
@@ -504,6 +726,9 @@ export class IframeWritableStream extends IframeStreamCore {
|
|
|
504
726
|
this.clearExpireTimer();
|
|
505
727
|
this.clearIdleTimer();
|
|
506
728
|
this.unregisterControlHandler();
|
|
729
|
+
this.pendingQueue.length = 0;
|
|
730
|
+
this.pendingBytes = 0;
|
|
731
|
+
this.cleanupAckWaiters();
|
|
507
732
|
(_this$rejectCompletio = this.rejectCompletion) === null || _this$rejectCompletio === void 0 || _this$rejectCompletio.call(this, e instanceof Error ? e : new Error(String(e)));
|
|
508
733
|
throw e;
|
|
509
734
|
}
|
|
@@ -531,7 +756,15 @@ export class IframeWritableStream extends IframeStreamCore {
|
|
|
531
756
|
this.clearExpireTimer();
|
|
532
757
|
this.clearIdleTimer();
|
|
533
758
|
this.unregisterControlHandler();
|
|
759
|
+
this.pendingQueue.length = 0;
|
|
760
|
+
this.pendingBytes = 0;
|
|
534
761
|
this.sendMessage(MessageType.STREAM_END);
|
|
762
|
+
this.emit(StreamEvent.END);
|
|
763
|
+
this.emit(StreamEvent.STATE, {
|
|
764
|
+
state: this._state
|
|
765
|
+
});
|
|
766
|
+
this.cleanupAckWaiters();
|
|
767
|
+
this.clearAllListeners();
|
|
535
768
|
(_this$resolveCompleti = this.resolveCompletion) === null || _this$resolveCompleti === void 0 || _this$resolveCompleti.call(this);
|
|
536
769
|
}
|
|
537
770
|
|
|
@@ -545,9 +778,19 @@ export class IframeWritableStream extends IframeStreamCore {
|
|
|
545
778
|
this.clearExpireTimer();
|
|
546
779
|
this.clearIdleTimer();
|
|
547
780
|
this.unregisterControlHandler();
|
|
781
|
+
this.pendingQueue.length = 0;
|
|
782
|
+
this.pendingBytes = 0;
|
|
548
783
|
this.sendMessage(MessageType.STREAM_ERROR, {
|
|
549
784
|
error: message
|
|
550
785
|
});
|
|
786
|
+
this.emit(StreamEvent.ERROR, {
|
|
787
|
+
error: new Error(message)
|
|
788
|
+
});
|
|
789
|
+
this.emit(StreamEvent.STATE, {
|
|
790
|
+
state: this._state
|
|
791
|
+
});
|
|
792
|
+
this.cleanupAckWaiters();
|
|
793
|
+
this.clearAllListeners();
|
|
551
794
|
(_this$resolveCompleti2 = this.resolveCompletion) === null || _this$resolveCompleti2 === void 0 || _this$resolveCompleti2.call(this);
|
|
552
795
|
}
|
|
553
796
|
|
|
@@ -568,15 +811,26 @@ export class IframeWritableStream extends IframeStreamCore {
|
|
|
568
811
|
this.clearExpireTimer();
|
|
569
812
|
this.clearIdleTimer();
|
|
570
813
|
this.unregisterControlHandler();
|
|
814
|
+
this.pendingQueue.length = 0;
|
|
815
|
+
this.pendingBytes = 0;
|
|
816
|
+
this.emit(StreamEvent.CANCEL, {
|
|
817
|
+
reason,
|
|
818
|
+
remote: false
|
|
819
|
+
});
|
|
820
|
+
this.emit(StreamEvent.STATE, {
|
|
821
|
+
state: this._state
|
|
822
|
+
});
|
|
571
823
|
if (this.context) {
|
|
572
824
|
try {
|
|
573
825
|
this.sendMessage(MessageType.STREAM_CANCEL, {
|
|
574
826
|
reason
|
|
575
827
|
});
|
|
576
|
-
} catch (
|
|
828
|
+
} catch (_unused8) {
|
|
577
829
|
// ignore send failures on cancel
|
|
578
830
|
}
|
|
579
831
|
}
|
|
832
|
+
this.cleanupAckWaiters();
|
|
833
|
+
this.clearAllListeners();
|
|
580
834
|
(_this$resolveCompleti3 = this.resolveCompletion) === null || _this$resolveCompleti3 === void 0 || _this$resolveCompleti3.call(this);
|
|
581
835
|
}
|
|
582
836
|
}
|
package/esm/utils/ack.js
ADDED
|
@@ -0,0 +1,36 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* ack is an internal reserved protocol field (previously named ackMeta).
|
|
3
|
+
*
|
|
4
|
+
* Semantics (ACK-only workflow):
|
|
5
|
+
* - If `ack` exists, it should contain a required `id` (string|number) for matching.
|
|
6
|
+
* - Fixed shape: { id, meta?: string } (meta is optional and must be a string if present).
|
|
7
|
+
* - Matching is by `id` only; never deep-compare other fields.
|
|
8
|
+
*
|
|
9
|
+
* @internal
|
|
10
|
+
*/
|
|
11
|
+
export function getAckId(ack) {
|
|
12
|
+
if (!ack || typeof ack !== 'object') return undefined;
|
|
13
|
+
var id = ack.id;
|
|
14
|
+
return typeof id === 'string' || typeof id === 'number' ? id : undefined;
|
|
15
|
+
}
|
|
16
|
+
|
|
17
|
+
/**
|
|
18
|
+
* @internal
|
|
19
|
+
*/
|
|
20
|
+
export function getAckMeta(ack) {
|
|
21
|
+
if (!ack || typeof ack !== 'object') return undefined;
|
|
22
|
+
var meta = ack.meta;
|
|
23
|
+
return typeof meta === 'string' ? meta : undefined;
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
/**
|
|
27
|
+
* Match ack by `id` only.
|
|
28
|
+
* @internal
|
|
29
|
+
*/
|
|
30
|
+
export function isAckMatch(expected, received) {
|
|
31
|
+
if (expected === undefined) return true;
|
|
32
|
+
var expectedId = getAckId(expected);
|
|
33
|
+
var receivedId = getAckId(received);
|
|
34
|
+
if (expectedId === undefined || receivedId === undefined) return false;
|
|
35
|
+
return expectedId === receivedId;
|
|
36
|
+
}
|
package/esm/utils/debug.js
CHANGED
|
@@ -222,7 +222,7 @@ function setupClientMessageDebugging(clientImpl) {
|
|
|
222
222
|
log('info', Messages.DEBUG_CLIENT_SENDING_PING, {
|
|
223
223
|
requestId
|
|
224
224
|
});
|
|
225
|
-
} else if (type === MessageType.
|
|
225
|
+
} else if (type === MessageType.ACK) {
|
|
226
226
|
log('info', Messages.DEBUG_CLIENT_SENDING_RECEIVED_ACK, {
|
|
227
227
|
requestId
|
|
228
228
|
});
|
package/esm/utils/index.js
CHANGED
|
@@ -7,6 +7,8 @@ import "core-js/modules/web.dom-collections.iterator.js";
|
|
|
7
7
|
import "core-js/modules/web.url.js";
|
|
8
8
|
import "core-js/modules/web.url.to-json.js";
|
|
9
9
|
import "core-js/modules/web.url-search-params.js";
|
|
10
|
+
import { OriginConstant } from '../constants';
|
|
11
|
+
|
|
10
12
|
/**
|
|
11
13
|
* Generate unique request ID
|
|
12
14
|
*/
|
|
@@ -26,12 +28,12 @@ export function generateInstanceId() {
|
|
|
26
28
|
*/
|
|
27
29
|
export function getIframeTargetOrigin(iframe) {
|
|
28
30
|
if (!iframe.src) {
|
|
29
|
-
return
|
|
31
|
+
return OriginConstant.ANY;
|
|
30
32
|
}
|
|
31
33
|
try {
|
|
32
34
|
return new URL(iframe.src).origin;
|
|
33
35
|
} catch (e) {
|
|
34
|
-
return
|
|
36
|
+
return OriginConstant.ANY;
|
|
35
37
|
}
|
|
36
38
|
}
|
|
37
39
|
export function isPromise(value) {
|
|
@@ -78,7 +80,7 @@ export * from './path-match';
|
|
|
78
80
|
// Export origin matching functions
|
|
79
81
|
export * from './origin';
|
|
80
82
|
|
|
81
|
-
//
|
|
83
|
+
// ack is a reserved protocol field (internal). Do not export helpers publicly.
|
|
82
84
|
|
|
83
85
|
// Export Cookie-related functions
|
|
84
86
|
export * from './cookie';
|
package/esm/utils/origin.js
CHANGED
|
@@ -1,6 +1,8 @@
|
|
|
1
1
|
import "core-js/modules/es.regexp.constructor.js";
|
|
2
2
|
import "core-js/modules/es.regexp.exec.js";
|
|
3
3
|
import "core-js/modules/es.regexp.to-string.js";
|
|
4
|
+
import { OriginConstant } from '../constants';
|
|
5
|
+
|
|
4
6
|
/**
|
|
5
7
|
* Origin matcher type (supports string, RegExp, Array)
|
|
6
8
|
*/
|
|
@@ -14,7 +16,7 @@ import "core-js/modules/es.regexp.to-string.js";
|
|
|
14
16
|
* - Array: any item matches.
|
|
15
17
|
*/
|
|
16
18
|
export function matchOrigin(origin, matcher) {
|
|
17
|
-
if (matcher ===
|
|
19
|
+
if (matcher === OriginConstant.ANY) return true;
|
|
18
20
|
if (typeof matcher === 'string') {
|
|
19
21
|
return origin === matcher;
|
|
20
22
|
}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"client.d.ts","sourceRoot":"","sources":["../../src/api/client.ts"],"names":[],"mappings":"AAAA,OAAO,EAAiB,mBAAmB,EAAE,0BAA0B,EAAE,MAAM,UAAU,CAAC;AAO1F;;;;;;;GAOG;AACH,wBAAgB,mBAAmB,CACjC,MAAM,EAAE,iBAAiB,GAAG,MAAM,EAClC,OAAO,CAAC,EAAE,0BAA0B,GACnC,mBAAmB,
|
|
1
|
+
{"version":3,"file":"client.d.ts","sourceRoot":"","sources":["../../src/api/client.ts"],"names":[],"mappings":"AAAA,OAAO,EAAiB,mBAAmB,EAAE,0BAA0B,EAAE,MAAM,UAAU,CAAC;AAO1F;;;;;;;GAOG;AACH,wBAAgB,mBAAmB,CACjC,MAAM,EAAE,iBAAiB,GAAG,MAAM,EAClC,OAAO,CAAC,EAAE,0BAA0B,GACnC,mBAAmB,CAwDrB;AAED;;;GAGG;AACH,wBAAgB,6BAA6B,CAAC,SAAS,CAAC,EAAE,MAAM,GAAG,IAAI,CAKtE"}
|
package/library/api/client.js
CHANGED
|
@@ -20,7 +20,7 @@ var _constants = require("../constants");
|
|
|
20
20
|
*/
|
|
21
21
|
function requestIframeClient(target, options) {
|
|
22
22
|
var targetWindow = null;
|
|
23
|
-
var targetOrigin =
|
|
23
|
+
var targetOrigin = _constants.OriginConstant.ANY;
|
|
24
24
|
if (target.tagName === 'IFRAME') {
|
|
25
25
|
var iframe = target;
|
|
26
26
|
targetWindow = iframe.contentWindow;
|
|
@@ -33,7 +33,7 @@ function requestIframeClient(target, options) {
|
|
|
33
33
|
}
|
|
34
34
|
} else {
|
|
35
35
|
targetWindow = target;
|
|
36
|
-
targetOrigin =
|
|
36
|
+
targetOrigin = _constants.OriginConstant.ANY;
|
|
37
37
|
}
|
|
38
38
|
|
|
39
39
|
// Allow user to override targetOrigin explicitly
|
|
@@ -50,8 +50,9 @@ function requestIframeClient(target, options) {
|
|
|
50
50
|
// Create ClientServer (internally obtains or creates a shared MessageChannel)
|
|
51
51
|
var server = new _clientServer.RequestIframeClientServer({
|
|
52
52
|
secretKey,
|
|
53
|
-
|
|
54
|
-
|
|
53
|
+
autoOpen: options === null || options === void 0 ? void 0 : options.autoOpen,
|
|
54
|
+
autoAckMaxMetaLength: options === null || options === void 0 ? void 0 : options.autoAckMaxMetaLength,
|
|
55
|
+
autoAckMaxIdLength: options === null || options === void 0 ? void 0 : options.autoAckMaxIdLength
|
|
55
56
|
}, instanceId);
|
|
56
57
|
|
|
57
58
|
// Create client instance
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"server.d.ts","sourceRoot":"","sources":["../../src/api/server.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,mBAAmB,EAAE,0BAA0B,EAAE,MAAM,UAAU,CAAC;AAK3E;;;;;;;;GAQG;AACH,wBAAgB,mBAAmB,CACjC,OAAO,CAAC,EAAE,0BAA0B,GACnC,mBAAmB,
|
|
1
|
+
{"version":3,"file":"server.d.ts","sourceRoot":"","sources":["../../src/api/server.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,mBAAmB,EAAE,0BAA0B,EAAE,MAAM,UAAU,CAAC;AAK3E;;;;;;;;GAQG;AACH,wBAAgB,mBAAmB,CACjC,OAAO,CAAC,EAAE,0BAA0B,GACnC,mBAAmB,CAqCrB;AAED;;;GAGG;AACH,wBAAgB,6BAA6B,CAAC,SAAS,CAAC,EAAE,MAAM,GAAG,IAAI,CAKtE"}
|
package/library/api/server.js
CHANGED
|
@@ -38,7 +38,9 @@ function requestIframeServer(options) {
|
|
|
38
38
|
autoOpen: options === null || options === void 0 ? void 0 : options.autoOpen,
|
|
39
39
|
allowedOrigins: options === null || options === void 0 ? void 0 : options.allowedOrigins,
|
|
40
40
|
validateOrigin: options === null || options === void 0 ? void 0 : options.validateOrigin,
|
|
41
|
-
maxConcurrentRequestsPerClient: options === null || options === void 0 ? void 0 : options.maxConcurrentRequestsPerClient
|
|
41
|
+
maxConcurrentRequestsPerClient: options === null || options === void 0 ? void 0 : options.maxConcurrentRequestsPerClient,
|
|
42
|
+
autoAckMaxMetaLength: options === null || options === void 0 ? void 0 : options.autoAckMaxMetaLength,
|
|
43
|
+
autoAckMaxIdLength: options === null || options === void 0 ? void 0 : options.autoAckMaxIdLength
|
|
42
44
|
});
|
|
43
45
|
|
|
44
46
|
// If trace mode is enabled, register debug listeners
|