// https://www.npmjs.com/package/eventsource-parser/v/1.1.1 function createParser(onParse) { let isFirstChunk let bytes let buffer let startingPosition let startingFieldLength let eventId let eventName let data reset() return { feed, reset, } function reset() { isFirstChunk = true bytes = [] buffer = '' startingPosition = 0 startingFieldLength = -1 eventId = void 0 eventName = void 0 data = '' } function feed(chunk) { bytes = bytes.concat(Array.from(chunk)) buffer = new TextDecoder().decode(new Uint8Array(bytes)) if (isFirstChunk && hasBom(buffer)) { buffer = buffer.slice(BOM.length) } isFirstChunk = false const length = buffer.length let position = 0 let discardTrailingNewline = false while (position < length) { if (discardTrailingNewline) { if (buffer[position] === '\n') { ++position } discardTrailingNewline = false } let lineLength = -1 let fieldLength = startingFieldLength let character for (let index = startingPosition; lineLength < 0 && index < length; ++index) { character = buffer[index] if (character === ':' && fieldLength < 0) { fieldLength = index - position } else if (character === '\r') { discardTrailingNewline = true lineLength = index - position } else if (character === '\n') { lineLength = index - position } } if (lineLength < 0) { startingPosition = length - position startingFieldLength = fieldLength break } else { startingPosition = 0 startingFieldLength = -1 } parseEventStreamLine(buffer, position, fieldLength, lineLength) position += lineLength + 1 } if (position === length) { bytes = [] buffer = '' } else if (position > 0) { bytes = bytes.slice(new TextEncoder().encode(buffer.slice(0, position)).length) buffer = buffer.slice(position) } } function parseEventStreamLine(lineBuffer, index, fieldLength, lineLength) { if (lineLength === 0) { if (data.length > 0) { onParse({ type: 'event', id: eventId, event: eventName || void 0, data: data.slice(0, -1), // remove trailing newline }) data = '' eventId = void 0 } eventName = void 0 return } const noValue = fieldLength < 0 const field = lineBuffer.slice(index, index + (noValue ? lineLength : fieldLength)) let step = 0 if (noValue) { step = lineLength } else if (lineBuffer[index + fieldLength + 1] === ' ') { step = fieldLength + 2 } else { step = fieldLength + 1 } const position = index + step const valueLength = lineLength - step const value = lineBuffer.slice(position, position + valueLength).toString() if (field === 'data') { data += value ? ''.concat(value, '\n') : '\n' } else if (field === 'event') { eventName = value } else if (field === 'id' && !value.includes('\0')) { eventId = value } else if (field === 'retry') { const retry = parseInt(value, 10) if (!Number.isNaN(retry)) { onParse({ type: 'reconnect-interval', value: retry, }) } } } } const BOM = [239, 187, 191] function hasBom(buffer) { return BOM.every((charCode, index) => buffer.charCodeAt(index) === charCode) } export { createParser }