format: prettify entire project
This commit is contained in:
205
node_modules/undici/lib/web/eventsource/eventsource-stream.js
generated
vendored
205
node_modules/undici/lib/web/eventsource/eventsource-stream.js
generated
vendored
@ -1,27 +1,27 @@
|
||||
'use strict'
|
||||
const { Transform } = require('node:stream')
|
||||
const { isASCIINumber, isValidLastEventId } = require('./util')
|
||||
'use strict';
|
||||
const { Transform } = require('node:stream');
|
||||
const { isASCIINumber, isValidLastEventId } = require('./util');
|
||||
|
||||
/**
|
||||
* @type {number[]} BOM
|
||||
*/
|
||||
const BOM = [0xEF, 0xBB, 0xBF]
|
||||
const BOM = [0xef, 0xbb, 0xbf];
|
||||
/**
|
||||
* @type {10} LF
|
||||
*/
|
||||
const LF = 0x0A
|
||||
const LF = 0x0a;
|
||||
/**
|
||||
* @type {13} CR
|
||||
*/
|
||||
const CR = 0x0D
|
||||
const CR = 0x0d;
|
||||
/**
|
||||
* @type {58} COLON
|
||||
*/
|
||||
const COLON = 0x3A
|
||||
const COLON = 0x3a;
|
||||
/**
|
||||
* @type {32} SPACE
|
||||
*/
|
||||
const SPACE = 0x20
|
||||
const SPACE = 0x20;
|
||||
|
||||
/**
|
||||
* @typedef {object} EventSourceStreamEvent
|
||||
@ -44,37 +44,37 @@ class EventSourceStream extends Transform {
|
||||
/**
|
||||
* @type {eventSourceSettings}
|
||||
*/
|
||||
state
|
||||
state;
|
||||
|
||||
/**
|
||||
* Leading byte-order-mark check.
|
||||
* @type {boolean}
|
||||
*/
|
||||
checkBOM = true
|
||||
checkBOM = true;
|
||||
|
||||
/**
|
||||
* @type {boolean}
|
||||
*/
|
||||
crlfCheck = false
|
||||
crlfCheck = false;
|
||||
|
||||
/**
|
||||
* @type {boolean}
|
||||
*/
|
||||
eventEndCheck = false
|
||||
eventEndCheck = false;
|
||||
|
||||
/**
|
||||
* @type {Buffer|null}
|
||||
*/
|
||||
buffer = null
|
||||
buffer = null;
|
||||
|
||||
pos = 0
|
||||
pos = 0;
|
||||
|
||||
event = {
|
||||
data: undefined,
|
||||
event: undefined,
|
||||
id: undefined,
|
||||
retry: undefined
|
||||
}
|
||||
retry: undefined,
|
||||
};
|
||||
|
||||
/**
|
||||
* @param {object} options
|
||||
@ -82,16 +82,16 @@ class EventSourceStream extends Transform {
|
||||
* @param {eventSourceSettings} [options.eventSourceSettings]
|
||||
* @param {(chunk: any, encoding?: BufferEncoding | undefined) => boolean} [options.push]
|
||||
*/
|
||||
constructor (options = {}) {
|
||||
constructor(options = {}) {
|
||||
// Enable object mode as EventSourceStream emits objects of shape
|
||||
// EventSourceStreamEvent
|
||||
options.readableObjectMode = true
|
||||
options.readableObjectMode = true;
|
||||
|
||||
super(options)
|
||||
super(options);
|
||||
|
||||
this.state = options.eventSourceSettings || {}
|
||||
this.state = options.eventSourceSettings || {};
|
||||
if (options.push) {
|
||||
this.push = options.push
|
||||
this.push = options.push;
|
||||
}
|
||||
}
|
||||
|
||||
@ -101,10 +101,10 @@ class EventSourceStream extends Transform {
|
||||
* @param {Function} callback
|
||||
* @returns {void}
|
||||
*/
|
||||
_transform (chunk, _encoding, callback) {
|
||||
_transform(chunk, _encoding, callback) {
|
||||
if (chunk.length === 0) {
|
||||
callback()
|
||||
return
|
||||
callback();
|
||||
return;
|
||||
}
|
||||
|
||||
// Cache the chunk in the buffer, as the data might not be complete while
|
||||
@ -113,9 +113,9 @@ class EventSourceStream extends Transform {
|
||||
// incoming chunks
|
||||
// see: https://github.com/nodejs/undici/issues/2630
|
||||
if (this.buffer) {
|
||||
this.buffer = Buffer.concat([this.buffer, chunk])
|
||||
this.buffer = Buffer.concat([this.buffer, chunk]);
|
||||
} else {
|
||||
this.buffer = chunk
|
||||
this.buffer = chunk;
|
||||
}
|
||||
|
||||
// Strip leading byte-order-mark if we opened the stream and started
|
||||
@ -126,33 +126,30 @@ class EventSourceStream extends Transform {
|
||||
// Check if the first byte is the same as the first byte of the BOM
|
||||
if (this.buffer[0] === BOM[0]) {
|
||||
// If it is, we need to wait for more data
|
||||
callback()
|
||||
return
|
||||
callback();
|
||||
return;
|
||||
}
|
||||
// Set the checkBOM flag to false as we don't need to check for the
|
||||
// BOM anymore
|
||||
this.checkBOM = false
|
||||
this.checkBOM = false;
|
||||
|
||||
// The buffer only contains one byte so we need to wait for more data
|
||||
callback()
|
||||
return
|
||||
callback();
|
||||
return;
|
||||
case 2:
|
||||
// Check if the first two bytes are the same as the first two bytes
|
||||
// of the BOM
|
||||
if (
|
||||
this.buffer[0] === BOM[0] &&
|
||||
this.buffer[1] === BOM[1]
|
||||
) {
|
||||
if (this.buffer[0] === BOM[0] && this.buffer[1] === BOM[1]) {
|
||||
// If it is, we need to wait for more data, because the third byte
|
||||
// is needed to determine if it is the BOM or not
|
||||
callback()
|
||||
return
|
||||
callback();
|
||||
return;
|
||||
}
|
||||
|
||||
// Set the checkBOM flag to false as we don't need to check for the
|
||||
// BOM anymore
|
||||
this.checkBOM = false
|
||||
break
|
||||
this.checkBOM = false;
|
||||
break;
|
||||
case 3:
|
||||
// Check if the first three bytes are the same as the first three
|
||||
// bytes of the BOM
|
||||
@ -162,18 +159,18 @@ class EventSourceStream extends Transform {
|
||||
this.buffer[2] === BOM[2]
|
||||
) {
|
||||
// If it is, we can drop the buffered data, as it is only the BOM
|
||||
this.buffer = Buffer.alloc(0)
|
||||
this.buffer = Buffer.alloc(0);
|
||||
// Set the checkBOM flag to false as we don't need to check for the
|
||||
// BOM anymore
|
||||
this.checkBOM = false
|
||||
this.checkBOM = false;
|
||||
|
||||
// Await more data
|
||||
callback()
|
||||
return
|
||||
callback();
|
||||
return;
|
||||
}
|
||||
// If it is not the BOM, we can start processing the data
|
||||
this.checkBOM = false
|
||||
break
|
||||
this.checkBOM = false;
|
||||
break;
|
||||
default:
|
||||
// The buffer is longer than 3 bytes, so we can drop the BOM if it is
|
||||
// present
|
||||
@ -183,12 +180,12 @@ class EventSourceStream extends Transform {
|
||||
this.buffer[2] === BOM[2]
|
||||
) {
|
||||
// Remove the BOM from the buffer
|
||||
this.buffer = this.buffer.subarray(3)
|
||||
this.buffer = this.buffer.subarray(3);
|
||||
}
|
||||
|
||||
// Set the checkBOM flag to false as we don't need to check for the
|
||||
this.checkBOM = false
|
||||
break
|
||||
this.checkBOM = false;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
@ -206,9 +203,9 @@ class EventSourceStream extends Transform {
|
||||
// If the current character is a line feed, we can remove it
|
||||
// from the buffer and reset the crlfCheck flag
|
||||
if (this.buffer[this.pos] === LF) {
|
||||
this.buffer = this.buffer.subarray(this.pos + 1)
|
||||
this.pos = 0
|
||||
this.crlfCheck = false
|
||||
this.buffer = this.buffer.subarray(this.pos + 1);
|
||||
this.pos = 0;
|
||||
this.crlfCheck = false;
|
||||
|
||||
// It is possible that the line feed is not the end of the
|
||||
// event. We need to check if the next character is an
|
||||
@ -219,9 +216,9 @@ class EventSourceStream extends Transform {
|
||||
// As we removed the line feed from the buffer and set the
|
||||
// crlfCheck flag to false, we basically don't make any
|
||||
// distinction between a line feed and a carriage return.
|
||||
continue
|
||||
continue;
|
||||
}
|
||||
this.crlfCheck = false
|
||||
this.crlfCheck = false;
|
||||
}
|
||||
|
||||
if (this.buffer[this.pos] === LF || this.buffer[this.pos] === CR) {
|
||||
@ -230,22 +227,26 @@ class EventSourceStream extends Transform {
|
||||
// next character is a line feed so we can remove it from the
|
||||
// buffer
|
||||
if (this.buffer[this.pos] === CR) {
|
||||
this.crlfCheck = true
|
||||
this.crlfCheck = true;
|
||||
}
|
||||
|
||||
this.buffer = this.buffer.subarray(this.pos + 1)
|
||||
this.pos = 0
|
||||
this.buffer = this.buffer.subarray(this.pos + 1);
|
||||
this.pos = 0;
|
||||
if (
|
||||
this.event.data !== undefined || this.event.event || this.event.id || this.event.retry) {
|
||||
this.processEvent(this.event)
|
||||
this.event.data !== undefined ||
|
||||
this.event.event ||
|
||||
this.event.id ||
|
||||
this.event.retry
|
||||
) {
|
||||
this.processEvent(this.event);
|
||||
}
|
||||
this.clearEvent()
|
||||
continue
|
||||
this.clearEvent();
|
||||
continue;
|
||||
}
|
||||
// If the current character is not an end-of-line, then the event
|
||||
// is not finished and we have to reset the eventEndCheck flag
|
||||
this.eventEndCheck = false
|
||||
continue
|
||||
this.eventEndCheck = false;
|
||||
continue;
|
||||
}
|
||||
|
||||
// If the current character is an end-of-line, we can process the
|
||||
@ -255,51 +256,51 @@ class EventSourceStream extends Transform {
|
||||
// set the crlfCheck flag to true, as we need to check if the
|
||||
// next character is a line feed
|
||||
if (this.buffer[this.pos] === CR) {
|
||||
this.crlfCheck = true
|
||||
this.crlfCheck = true;
|
||||
}
|
||||
|
||||
// In any case, we can process the line as we reached an
|
||||
// end-of-line character
|
||||
this.parseLine(this.buffer.subarray(0, this.pos), this.event)
|
||||
this.parseLine(this.buffer.subarray(0, this.pos), this.event);
|
||||
|
||||
// Remove the processed line from the buffer
|
||||
this.buffer = this.buffer.subarray(this.pos + 1)
|
||||
this.buffer = this.buffer.subarray(this.pos + 1);
|
||||
// Reset the position as we removed the processed line from the buffer
|
||||
this.pos = 0
|
||||
this.pos = 0;
|
||||
// A line was processed and this could be the end of the event. We need
|
||||
// to check if the next line is empty to determine if the event is
|
||||
// finished.
|
||||
this.eventEndCheck = true
|
||||
continue
|
||||
this.eventEndCheck = true;
|
||||
continue;
|
||||
}
|
||||
|
||||
this.pos++
|
||||
this.pos++;
|
||||
}
|
||||
|
||||
callback()
|
||||
callback();
|
||||
}
|
||||
|
||||
/**
|
||||
* @param {Buffer} line
|
||||
* @param {EventSourceStreamEvent} event
|
||||
*/
|
||||
parseLine (line, event) {
|
||||
parseLine(line, event) {
|
||||
// If the line is empty (a blank line)
|
||||
// Dispatch the event, as defined below.
|
||||
// This will be handled in the _transform method
|
||||
if (line.length === 0) {
|
||||
return
|
||||
return;
|
||||
}
|
||||
|
||||
// If the line starts with a U+003A COLON character (:)
|
||||
// Ignore the line.
|
||||
const colonPosition = line.indexOf(COLON)
|
||||
const colonPosition = line.indexOf(COLON);
|
||||
if (colonPosition === 0) {
|
||||
return
|
||||
return;
|
||||
}
|
||||
|
||||
let field = ''
|
||||
let value = ''
|
||||
let field = '';
|
||||
let value = '';
|
||||
|
||||
// If the line contains a U+003A COLON character (:)
|
||||
if (colonPosition !== -1) {
|
||||
@ -308,27 +309,27 @@ class EventSourceStream extends Transform {
|
||||
// TODO: Investigate if there is a more performant way to extract the
|
||||
// field
|
||||
// see: https://github.com/nodejs/undici/issues/2630
|
||||
field = line.subarray(0, colonPosition).toString('utf8')
|
||||
field = line.subarray(0, colonPosition).toString('utf8');
|
||||
|
||||
// Collect the characters on the line after the first U+003A COLON
|
||||
// character (:), and let value be that string.
|
||||
// If value starts with a U+0020 SPACE character, remove it from value.
|
||||
let valueStart = colonPosition + 1
|
||||
let valueStart = colonPosition + 1;
|
||||
if (line[valueStart] === SPACE) {
|
||||
++valueStart
|
||||
++valueStart;
|
||||
}
|
||||
// TODO: Investigate if there is a more performant way to extract the
|
||||
// value
|
||||
// see: https://github.com/nodejs/undici/issues/2630
|
||||
value = line.subarray(valueStart).toString('utf8')
|
||||
value = line.subarray(valueStart).toString('utf8');
|
||||
|
||||
// Otherwise, the string is not empty but does not contain a U+003A COLON
|
||||
// character (:)
|
||||
} else {
|
||||
// Process the field using the steps described below, using the whole
|
||||
// line as the field name, and the empty string as the field value.
|
||||
field = line.toString('utf8')
|
||||
value = ''
|
||||
field = line.toString('utf8');
|
||||
value = '';
|
||||
}
|
||||
|
||||
// Modify the event with the field name and value. The value is also
|
||||
@ -336,39 +337,39 @@ class EventSourceStream extends Transform {
|
||||
switch (field) {
|
||||
case 'data':
|
||||
if (event[field] === undefined) {
|
||||
event[field] = value
|
||||
event[field] = value;
|
||||
} else {
|
||||
event[field] += `\n${value}`
|
||||
event[field] += `\n${value}`;
|
||||
}
|
||||
break
|
||||
break;
|
||||
case 'retry':
|
||||
if (isASCIINumber(value)) {
|
||||
event[field] = value
|
||||
event[field] = value;
|
||||
}
|
||||
break
|
||||
break;
|
||||
case 'id':
|
||||
if (isValidLastEventId(value)) {
|
||||
event[field] = value
|
||||
event[field] = value;
|
||||
}
|
||||
break
|
||||
break;
|
||||
case 'event':
|
||||
if (value.length > 0) {
|
||||
event[field] = value
|
||||
event[field] = value;
|
||||
}
|
||||
break
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @param {EventSourceStreamEvent} event
|
||||
*/
|
||||
processEvent (event) {
|
||||
processEvent(event) {
|
||||
if (event.retry && isASCIINumber(event.retry)) {
|
||||
this.state.reconnectionTime = parseInt(event.retry, 10)
|
||||
this.state.reconnectionTime = parseInt(event.retry, 10);
|
||||
}
|
||||
|
||||
if (event.id && isValidLastEventId(event.id)) {
|
||||
this.state.lastEventId = event.id
|
||||
this.state.lastEventId = event.id;
|
||||
}
|
||||
|
||||
// only dispatch event, when data is provided
|
||||
@ -378,22 +379,22 @@ class EventSourceStream extends Transform {
|
||||
options: {
|
||||
data: event.data,
|
||||
lastEventId: this.state.lastEventId,
|
||||
origin: this.state.origin
|
||||
}
|
||||
})
|
||||
origin: this.state.origin,
|
||||
},
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
clearEvent () {
|
||||
clearEvent() {
|
||||
this.event = {
|
||||
data: undefined,
|
||||
event: undefined,
|
||||
id: undefined,
|
||||
retry: undefined
|
||||
}
|
||||
retry: undefined,
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
module.exports = {
|
||||
EventSourceStream
|
||||
}
|
||||
EventSourceStream,
|
||||
};
|
||||
|
333
node_modules/undici/lib/web/eventsource/eventsource.js
generated
vendored
333
node_modules/undici/lib/web/eventsource/eventsource.js
generated
vendored
@ -1,18 +1,18 @@
|
||||
'use strict'
|
||||
'use strict';
|
||||
|
||||
const { pipeline } = require('node:stream')
|
||||
const { fetching } = require('../fetch')
|
||||
const { makeRequest } = require('../fetch/request')
|
||||
const { webidl } = require('../fetch/webidl')
|
||||
const { EventSourceStream } = require('./eventsource-stream')
|
||||
const { parseMIMEType } = require('../fetch/data-url')
|
||||
const { createFastMessageEvent } = require('../websocket/events')
|
||||
const { isNetworkError } = require('../fetch/response')
|
||||
const { delay } = require('./util')
|
||||
const { kEnumerableProperty } = require('../../core/util')
|
||||
const { environmentSettingsObject } = require('../fetch/util')
|
||||
const { pipeline } = require('node:stream');
|
||||
const { fetching } = require('../fetch');
|
||||
const { makeRequest } = require('../fetch/request');
|
||||
const { webidl } = require('../fetch/webidl');
|
||||
const { EventSourceStream } = require('./eventsource-stream');
|
||||
const { parseMIMEType } = require('../fetch/data-url');
|
||||
const { createFastMessageEvent } = require('../websocket/events');
|
||||
const { isNetworkError } = require('../fetch/response');
|
||||
const { delay } = require('./util');
|
||||
const { kEnumerableProperty } = require('../../core/util');
|
||||
const { environmentSettingsObject } = require('../fetch/util');
|
||||
|
||||
let experimentalWarned = false
|
||||
let experimentalWarned = false;
|
||||
|
||||
/**
|
||||
* A reconnection time, in milliseconds. This must initially be an implementation-defined value,
|
||||
@ -24,7 +24,7 @@ let experimentalWarned = false
|
||||
*
|
||||
* @type {3000}
|
||||
*/
|
||||
const defaultReconnectionTime = 3000
|
||||
const defaultReconnectionTime = 3000;
|
||||
|
||||
/**
|
||||
* The readyState attribute represents the state of the connection.
|
||||
@ -39,32 +39,32 @@ const defaultReconnectionTime = 3000
|
||||
* agent is reconnecting.
|
||||
* @type {0}
|
||||
*/
|
||||
const CONNECTING = 0
|
||||
const CONNECTING = 0;
|
||||
|
||||
/**
|
||||
* The user agent has an open connection and is dispatching events as it
|
||||
* receives them.
|
||||
* @type {1}
|
||||
*/
|
||||
const OPEN = 1
|
||||
const OPEN = 1;
|
||||
|
||||
/**
|
||||
* The connection is not open, and the user agent is not trying to reconnect.
|
||||
* @type {2}
|
||||
*/
|
||||
const CLOSED = 2
|
||||
const CLOSED = 2;
|
||||
|
||||
/**
|
||||
* Requests for the element will have their mode set to "cors" and their credentials mode set to "same-origin".
|
||||
* @type {'anonymous'}
|
||||
*/
|
||||
const ANONYMOUS = 'anonymous'
|
||||
const ANONYMOUS = 'anonymous';
|
||||
|
||||
/**
|
||||
* Requests for the element will have their mode set to "cors" and their credentials mode set to "include".
|
||||
* @type {'use-credentials'}
|
||||
*/
|
||||
const USE_CREDENTIALS = 'use-credentials'
|
||||
const USE_CREDENTIALS = 'use-credentials';
|
||||
|
||||
/**
|
||||
* The EventSource interface is used to receive server-sent events. It
|
||||
@ -78,26 +78,26 @@ class EventSource extends EventTarget {
|
||||
#events = {
|
||||
open: null,
|
||||
error: null,
|
||||
message: null
|
||||
}
|
||||
message: null,
|
||||
};
|
||||
|
||||
#url
|
||||
#withCredentials = false
|
||||
#url;
|
||||
#withCredentials = false;
|
||||
|
||||
/**
|
||||
* @type {ReadyState}
|
||||
*/
|
||||
#readyState = CONNECTING
|
||||
#readyState = CONNECTING;
|
||||
|
||||
#request = null
|
||||
#controller = null
|
||||
#request = null;
|
||||
#controller = null;
|
||||
|
||||
#dispatcher
|
||||
#dispatcher;
|
||||
|
||||
/**
|
||||
* @type {import('./eventsource-stream').eventSourceSettings}
|
||||
*/
|
||||
#state
|
||||
#state;
|
||||
|
||||
/**
|
||||
* Creates a new EventSource object.
|
||||
@ -105,58 +105,65 @@ class EventSource extends EventTarget {
|
||||
* @param {EventSourceInit} [eventSourceInitDict={}]
|
||||
* @see https://html.spec.whatwg.org/multipage/server-sent-events.html#the-eventsource-interface
|
||||
*/
|
||||
constructor (url, eventSourceInitDict = {}) {
|
||||
constructor(url, eventSourceInitDict = {}) {
|
||||
// 1. Let ev be a new EventSource object.
|
||||
super()
|
||||
super();
|
||||
|
||||
webidl.util.markAsUncloneable(this)
|
||||
webidl.util.markAsUncloneable(this);
|
||||
|
||||
const prefix = 'EventSource constructor'
|
||||
webidl.argumentLengthCheck(arguments, 1, prefix)
|
||||
const prefix = 'EventSource constructor';
|
||||
webidl.argumentLengthCheck(arguments, 1, prefix);
|
||||
|
||||
if (!experimentalWarned) {
|
||||
experimentalWarned = true
|
||||
process.emitWarning('EventSource is experimental, expect them to change at any time.', {
|
||||
code: 'UNDICI-ES'
|
||||
})
|
||||
experimentalWarned = true;
|
||||
process.emitWarning(
|
||||
'EventSource is experimental, expect them to change at any time.',
|
||||
{
|
||||
code: 'UNDICI-ES',
|
||||
}
|
||||
);
|
||||
}
|
||||
|
||||
url = webidl.converters.USVString(url)
|
||||
eventSourceInitDict = webidl.converters.EventSourceInitDict(eventSourceInitDict, prefix, 'eventSourceInitDict')
|
||||
url = webidl.converters.USVString(url);
|
||||
eventSourceInitDict = webidl.converters.EventSourceInitDict(
|
||||
eventSourceInitDict,
|
||||
prefix,
|
||||
'eventSourceInitDict'
|
||||
);
|
||||
|
||||
this.#dispatcher = eventSourceInitDict.dispatcher
|
||||
this.#dispatcher = eventSourceInitDict.dispatcher;
|
||||
this.#state = {
|
||||
lastEventId: '',
|
||||
reconnectionTime: defaultReconnectionTime
|
||||
}
|
||||
reconnectionTime: defaultReconnectionTime,
|
||||
};
|
||||
|
||||
// 2. Let settings be ev's relevant settings object.
|
||||
// https://html.spec.whatwg.org/multipage/webappapis.html#environment-settings-object
|
||||
const settings = environmentSettingsObject
|
||||
const settings = environmentSettingsObject;
|
||||
|
||||
let urlRecord
|
||||
let urlRecord;
|
||||
|
||||
try {
|
||||
// 3. Let urlRecord be the result of encoding-parsing a URL given url, relative to settings.
|
||||
urlRecord = new URL(url, settings.settingsObject.baseUrl)
|
||||
this.#state.origin = urlRecord.origin
|
||||
urlRecord = new URL(url, settings.settingsObject.baseUrl);
|
||||
this.#state.origin = urlRecord.origin;
|
||||
} catch (e) {
|
||||
// 4. If urlRecord is failure, then throw a "SyntaxError" DOMException.
|
||||
throw new DOMException(e, 'SyntaxError')
|
||||
throw new DOMException(e, 'SyntaxError');
|
||||
}
|
||||
|
||||
// 5. Set ev's url to urlRecord.
|
||||
this.#url = urlRecord.href
|
||||
this.#url = urlRecord.href;
|
||||
|
||||
// 6. Let corsAttributeState be Anonymous.
|
||||
let corsAttributeState = ANONYMOUS
|
||||
let corsAttributeState = ANONYMOUS;
|
||||
|
||||
// 7. If the value of eventSourceInitDict's withCredentials member is true,
|
||||
// then set corsAttributeState to Use Credentials and set ev's
|
||||
// withCredentials attribute to true.
|
||||
if (eventSourceInitDict.withCredentials === true) {
|
||||
corsAttributeState = USE_CREDENTIALS
|
||||
this.#withCredentials = true
|
||||
corsAttributeState = USE_CREDENTIALS;
|
||||
this.#withCredentials = true;
|
||||
}
|
||||
|
||||
// 8. Let request be the result of creating a potential-CORS request given
|
||||
@ -166,30 +173,30 @@ class EventSource extends EventTarget {
|
||||
keepalive: true,
|
||||
// @see https://html.spec.whatwg.org/multipage/urls-and-fetching.html#cors-settings-attributes
|
||||
mode: 'cors',
|
||||
credentials: corsAttributeState === 'anonymous'
|
||||
? 'same-origin'
|
||||
: 'omit',
|
||||
referrer: 'no-referrer'
|
||||
}
|
||||
credentials: corsAttributeState === 'anonymous' ? 'same-origin' : 'omit',
|
||||
referrer: 'no-referrer',
|
||||
};
|
||||
|
||||
// 9. Set request's client to settings.
|
||||
initRequest.client = environmentSettingsObject.settingsObject
|
||||
initRequest.client = environmentSettingsObject.settingsObject;
|
||||
|
||||
// 10. User agents may set (`Accept`, `text/event-stream`) in request's header list.
|
||||
initRequest.headersList = [['accept', { name: 'accept', value: 'text/event-stream' }]]
|
||||
initRequest.headersList = [
|
||||
['accept', { name: 'accept', value: 'text/event-stream' }],
|
||||
];
|
||||
|
||||
// 11. Set request's cache mode to "no-store".
|
||||
initRequest.cache = 'no-store'
|
||||
initRequest.cache = 'no-store';
|
||||
|
||||
// 12. Set request's initiator type to "other".
|
||||
initRequest.initiator = 'other'
|
||||
initRequest.initiator = 'other';
|
||||
|
||||
initRequest.urlList = [new URL(this.#url)]
|
||||
initRequest.urlList = [new URL(this.#url)];
|
||||
|
||||
// 13. Set ev's request to request.
|
||||
this.#request = makeRequest(initRequest)
|
||||
this.#request = makeRequest(initRequest);
|
||||
|
||||
this.#connect()
|
||||
this.#connect();
|
||||
}
|
||||
|
||||
/**
|
||||
@ -198,8 +205,8 @@ class EventSource extends EventTarget {
|
||||
* @returns {ReadyState}
|
||||
* @readonly
|
||||
*/
|
||||
get readyState () {
|
||||
return this.#readyState
|
||||
get readyState() {
|
||||
return this.#readyState;
|
||||
}
|
||||
|
||||
/**
|
||||
@ -207,40 +214,40 @@ class EventSource extends EventTarget {
|
||||
* @readonly
|
||||
* @returns {string}
|
||||
*/
|
||||
get url () {
|
||||
return this.#url
|
||||
get url() {
|
||||
return this.#url;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a boolean indicating whether the EventSource object was
|
||||
* instantiated with CORS credentials set (true), or not (false, the default).
|
||||
*/
|
||||
get withCredentials () {
|
||||
return this.#withCredentials
|
||||
get withCredentials() {
|
||||
return this.#withCredentials;
|
||||
}
|
||||
|
||||
#connect () {
|
||||
if (this.#readyState === CLOSED) return
|
||||
#connect() {
|
||||
if (this.#readyState === CLOSED) return;
|
||||
|
||||
this.#readyState = CONNECTING
|
||||
this.#readyState = CONNECTING;
|
||||
|
||||
const fetchParams = {
|
||||
request: this.#request,
|
||||
dispatcher: this.#dispatcher
|
||||
}
|
||||
dispatcher: this.#dispatcher,
|
||||
};
|
||||
|
||||
// 14. Let processEventSourceEndOfBody given response res be the following step: if res is not a network error, then reestablish the connection.
|
||||
const processEventSourceEndOfBody = (response) => {
|
||||
if (isNetworkError(response)) {
|
||||
this.dispatchEvent(new Event('error'))
|
||||
this.close()
|
||||
this.dispatchEvent(new Event('error'));
|
||||
this.close();
|
||||
}
|
||||
|
||||
this.#reconnect()
|
||||
}
|
||||
this.#reconnect();
|
||||
};
|
||||
|
||||
// 15. Fetch request, with processResponseEndOfBody set to processEventSourceEndOfBody...
|
||||
fetchParams.processResponseEndOfBody = processEventSourceEndOfBody
|
||||
fetchParams.processResponseEndOfBody = processEventSourceEndOfBody;
|
||||
|
||||
// and processResponse set to the following steps given response res:
|
||||
fetchParams.processResponse = (response) => {
|
||||
@ -254,30 +261,29 @@ class EventSource extends EventTarget {
|
||||
// user agent has failed the connection, it does not attempt to
|
||||
// reconnect.
|
||||
if (response.aborted) {
|
||||
this.close()
|
||||
this.dispatchEvent(new Event('error'))
|
||||
return
|
||||
this.close();
|
||||
this.dispatchEvent(new Event('error'));
|
||||
return;
|
||||
// 2. Otherwise, if res is a network error, then reestablish the
|
||||
// connection, unless the user agent knows that to be futile, in
|
||||
// which case the user agent may fail the connection.
|
||||
} else {
|
||||
this.#reconnect()
|
||||
return
|
||||
this.#reconnect();
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
// 3. Otherwise, if res's status is not 200, or if res's `Content-Type`
|
||||
// is not `text/event-stream`, then fail the connection.
|
||||
const contentType = response.headersList.get('content-type', true)
|
||||
const mimeType = contentType !== null ? parseMIMEType(contentType) : 'failure'
|
||||
const contentTypeValid = mimeType !== 'failure' && mimeType.essence === 'text/event-stream'
|
||||
if (
|
||||
response.status !== 200 ||
|
||||
contentTypeValid === false
|
||||
) {
|
||||
this.close()
|
||||
this.dispatchEvent(new Event('error'))
|
||||
return
|
||||
const contentType = response.headersList.get('content-type', true);
|
||||
const mimeType =
|
||||
contentType !== null ? parseMIMEType(contentType) : 'failure';
|
||||
const contentTypeValid =
|
||||
mimeType !== 'failure' && mimeType.essence === 'text/event-stream';
|
||||
if (response.status !== 200 || contentTypeValid === false) {
|
||||
this.close();
|
||||
this.dispatchEvent(new Event('error'));
|
||||
return;
|
||||
}
|
||||
|
||||
// 4. Otherwise, announce the connection and interpret res's body
|
||||
@ -288,42 +294,35 @@ class EventSource extends EventTarget {
|
||||
// value other than CLOSED, sets the readyState attribute to OPEN
|
||||
// and fires an event named open at the EventSource object.
|
||||
// @see https://html.spec.whatwg.org/multipage/server-sent-events.html#sse-processing-model
|
||||
this.#readyState = OPEN
|
||||
this.dispatchEvent(new Event('open'))
|
||||
this.#readyState = OPEN;
|
||||
this.dispatchEvent(new Event('open'));
|
||||
|
||||
// If redirected to a different origin, set the origin to the new origin.
|
||||
this.#state.origin = response.urlList[response.urlList.length - 1].origin
|
||||
this.#state.origin = response.urlList[response.urlList.length - 1].origin;
|
||||
|
||||
const eventSourceStream = new EventSourceStream({
|
||||
eventSourceSettings: this.#state,
|
||||
push: (event) => {
|
||||
this.dispatchEvent(createFastMessageEvent(
|
||||
event.type,
|
||||
event.options
|
||||
))
|
||||
this.dispatchEvent(createFastMessageEvent(event.type, event.options));
|
||||
},
|
||||
});
|
||||
|
||||
pipeline(response.body.stream, eventSourceStream, (error) => {
|
||||
if (error?.aborted === false) {
|
||||
this.close();
|
||||
this.dispatchEvent(new Event('error'));
|
||||
}
|
||||
})
|
||||
});
|
||||
};
|
||||
|
||||
pipeline(response.body.stream,
|
||||
eventSourceStream,
|
||||
(error) => {
|
||||
if (
|
||||
error?.aborted === false
|
||||
) {
|
||||
this.close()
|
||||
this.dispatchEvent(new Event('error'))
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
this.#controller = fetching(fetchParams)
|
||||
this.#controller = fetching(fetchParams);
|
||||
}
|
||||
|
||||
/**
|
||||
* @see https://html.spec.whatwg.org/multipage/server-sent-events.html#sse-processing-model
|
||||
* @returns {Promise<void>}
|
||||
*/
|
||||
async #reconnect () {
|
||||
async #reconnect() {
|
||||
// When a user agent is to reestablish the connection, the user agent must
|
||||
// run the following steps. These steps are run in parallel, not as part of
|
||||
// a task. (The tasks that it queues, of course, are run like normal tasks
|
||||
@ -332,22 +331,22 @@ class EventSource extends EventTarget {
|
||||
// 1. Queue a task to run the following steps:
|
||||
|
||||
// 1. If the readyState attribute is set to CLOSED, abort the task.
|
||||
if (this.#readyState === CLOSED) return
|
||||
if (this.#readyState === CLOSED) return;
|
||||
|
||||
// 2. Set the readyState attribute to CONNECTING.
|
||||
this.#readyState = CONNECTING
|
||||
this.#readyState = CONNECTING;
|
||||
|
||||
// 3. Fire an event named error at the EventSource object.
|
||||
this.dispatchEvent(new Event('error'))
|
||||
this.dispatchEvent(new Event('error'));
|
||||
|
||||
// 2. Wait a delay equal to the reconnection time of the event source.
|
||||
await delay(this.#state.reconnectionTime)
|
||||
await delay(this.#state.reconnectionTime);
|
||||
|
||||
// 5. Queue a task to run the following steps:
|
||||
|
||||
// 1. If the EventSource object's readyState attribute is not set to
|
||||
// CONNECTING, then return.
|
||||
if (this.#readyState !== CONNECTING) return
|
||||
if (this.#readyState !== CONNECTING) return;
|
||||
|
||||
// 2. Let request be the EventSource object's request.
|
||||
// 3. If the EventSource object's last event ID string is not the empty
|
||||
@ -357,74 +356,78 @@ class EventSource extends EventTarget {
|
||||
// 2. Set (`Last-Event-ID`, lastEventIDValue) in request's header
|
||||
// list.
|
||||
if (this.#state.lastEventId.length) {
|
||||
this.#request.headersList.set('last-event-id', this.#state.lastEventId, true)
|
||||
this.#request.headersList.set(
|
||||
'last-event-id',
|
||||
this.#state.lastEventId,
|
||||
true
|
||||
);
|
||||
}
|
||||
|
||||
// 4. Fetch request and process the response obtained in this fashion, if any, as described earlier in this section.
|
||||
this.#connect()
|
||||
this.#connect();
|
||||
}
|
||||
|
||||
/**
|
||||
* Closes the connection, if any, and sets the readyState attribute to
|
||||
* CLOSED.
|
||||
*/
|
||||
close () {
|
||||
webidl.brandCheck(this, EventSource)
|
||||
close() {
|
||||
webidl.brandCheck(this, EventSource);
|
||||
|
||||
if (this.#readyState === CLOSED) return
|
||||
this.#readyState = CLOSED
|
||||
this.#controller.abort()
|
||||
this.#request = null
|
||||
if (this.#readyState === CLOSED) return;
|
||||
this.#readyState = CLOSED;
|
||||
this.#controller.abort();
|
||||
this.#request = null;
|
||||
}
|
||||
|
||||
get onopen () {
|
||||
return this.#events.open
|
||||
get onopen() {
|
||||
return this.#events.open;
|
||||
}
|
||||
|
||||
set onopen (fn) {
|
||||
set onopen(fn) {
|
||||
if (this.#events.open) {
|
||||
this.removeEventListener('open', this.#events.open)
|
||||
this.removeEventListener('open', this.#events.open);
|
||||
}
|
||||
|
||||
if (typeof fn === 'function') {
|
||||
this.#events.open = fn
|
||||
this.addEventListener('open', fn)
|
||||
this.#events.open = fn;
|
||||
this.addEventListener('open', fn);
|
||||
} else {
|
||||
this.#events.open = null
|
||||
this.#events.open = null;
|
||||
}
|
||||
}
|
||||
|
||||
get onmessage () {
|
||||
return this.#events.message
|
||||
get onmessage() {
|
||||
return this.#events.message;
|
||||
}
|
||||
|
||||
set onmessage (fn) {
|
||||
set onmessage(fn) {
|
||||
if (this.#events.message) {
|
||||
this.removeEventListener('message', this.#events.message)
|
||||
this.removeEventListener('message', this.#events.message);
|
||||
}
|
||||
|
||||
if (typeof fn === 'function') {
|
||||
this.#events.message = fn
|
||||
this.addEventListener('message', fn)
|
||||
this.#events.message = fn;
|
||||
this.addEventListener('message', fn);
|
||||
} else {
|
||||
this.#events.message = null
|
||||
this.#events.message = null;
|
||||
}
|
||||
}
|
||||
|
||||
get onerror () {
|
||||
return this.#events.error
|
||||
get onerror() {
|
||||
return this.#events.error;
|
||||
}
|
||||
|
||||
set onerror (fn) {
|
||||
set onerror(fn) {
|
||||
if (this.#events.error) {
|
||||
this.removeEventListener('error', this.#events.error)
|
||||
this.removeEventListener('error', this.#events.error);
|
||||
}
|
||||
|
||||
if (typeof fn === 'function') {
|
||||
this.#events.error = fn
|
||||
this.addEventListener('error', fn)
|
||||
this.#events.error = fn;
|
||||
this.addEventListener('error', fn);
|
||||
} else {
|
||||
this.#events.error = null
|
||||
this.#events.error = null;
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -435,26 +438,26 @@ const constantsPropertyDescriptors = {
|
||||
configurable: false,
|
||||
enumerable: true,
|
||||
value: CONNECTING,
|
||||
writable: false
|
||||
writable: false,
|
||||
},
|
||||
OPEN: {
|
||||
__proto__: null,
|
||||
configurable: false,
|
||||
enumerable: true,
|
||||
value: OPEN,
|
||||
writable: false
|
||||
writable: false,
|
||||
},
|
||||
CLOSED: {
|
||||
__proto__: null,
|
||||
configurable: false,
|
||||
enumerable: true,
|
||||
value: CLOSED,
|
||||
writable: false
|
||||
}
|
||||
}
|
||||
writable: false,
|
||||
},
|
||||
};
|
||||
|
||||
Object.defineProperties(EventSource, constantsPropertyDescriptors)
|
||||
Object.defineProperties(EventSource.prototype, constantsPropertyDescriptors)
|
||||
Object.defineProperties(EventSource, constantsPropertyDescriptors);
|
||||
Object.defineProperties(EventSource.prototype, constantsPropertyDescriptors);
|
||||
|
||||
Object.defineProperties(EventSource.prototype, {
|
||||
close: kEnumerableProperty,
|
||||
@ -463,22 +466,22 @@ Object.defineProperties(EventSource.prototype, {
|
||||
onopen: kEnumerableProperty,
|
||||
readyState: kEnumerableProperty,
|
||||
url: kEnumerableProperty,
|
||||
withCredentials: kEnumerableProperty
|
||||
})
|
||||
withCredentials: kEnumerableProperty,
|
||||
});
|
||||
|
||||
webidl.converters.EventSourceInitDict = webidl.dictionaryConverter([
|
||||
{
|
||||
key: 'withCredentials',
|
||||
converter: webidl.converters.boolean,
|
||||
defaultValue: () => false
|
||||
defaultValue: () => false,
|
||||
},
|
||||
{
|
||||
key: 'dispatcher', // undici only
|
||||
converter: webidl.converters.any
|
||||
}
|
||||
])
|
||||
converter: webidl.converters.any,
|
||||
},
|
||||
]);
|
||||
|
||||
module.exports = {
|
||||
EventSource,
|
||||
defaultReconnectionTime
|
||||
}
|
||||
defaultReconnectionTime,
|
||||
};
|
||||
|
24
node_modules/undici/lib/web/eventsource/util.js
generated
vendored
24
node_modules/undici/lib/web/eventsource/util.js
generated
vendored
@ -1,13 +1,13 @@
|
||||
'use strict'
|
||||
'use strict';
|
||||
|
||||
/**
|
||||
* Checks if the given value is a valid LastEventId.
|
||||
* @param {string} value
|
||||
* @returns {boolean}
|
||||
*/
|
||||
function isValidLastEventId (value) {
|
||||
function isValidLastEventId(value) {
|
||||
// LastEventId should not contain U+0000 NULL
|
||||
return value.indexOf('\u0000') === -1
|
||||
return value.indexOf('\u0000') === -1;
|
||||
}
|
||||
|
||||
/**
|
||||
@ -15,23 +15,23 @@ function isValidLastEventId (value) {
|
||||
* @param {string} value
|
||||
* @returns {boolean}
|
||||
*/
|
||||
function isASCIINumber (value) {
|
||||
if (value.length === 0) return false
|
||||
function isASCIINumber(value) {
|
||||
if (value.length === 0) return false;
|
||||
for (let i = 0; i < value.length; i++) {
|
||||
if (value.charCodeAt(i) < 0x30 || value.charCodeAt(i) > 0x39) return false
|
||||
if (value.charCodeAt(i) < 0x30 || value.charCodeAt(i) > 0x39) return false;
|
||||
}
|
||||
return true
|
||||
return true;
|
||||
}
|
||||
|
||||
// https://github.com/nodejs/undici/issues/2664
|
||||
function delay (ms) {
|
||||
function delay(ms) {
|
||||
return new Promise((resolve) => {
|
||||
setTimeout(resolve, ms).unref()
|
||||
})
|
||||
setTimeout(resolve, ms).unref();
|
||||
});
|
||||
}
|
||||
|
||||
module.exports = {
|
||||
isValidLastEventId,
|
||||
isASCIINumber,
|
||||
delay
|
||||
}
|
||||
delay,
|
||||
};
|
||||
|
Reference in New Issue
Block a user