fetch-sse
Advanced tools
Comparing version 1.0.17 to 1.0.18
@@ -14,3 +14,2 @@ "use strict"; | ||
try { | ||
const sse = new sse_1.SSEDecoder(); | ||
const res = await fetch(url, { | ||
@@ -31,3 +30,3 @@ method, | ||
break; | ||
const decoded = sse.decode(value); | ||
const decoded = (0, sse_1.parseServerSentEvent)(value); | ||
for (const event of decoded) { | ||
@@ -34,0 +33,0 @@ onMessage(event, done); |
import { Bytes, ServerSentEvent } from './interface'; | ||
export declare function parseServerSentEvent(chunk: Bytes): ServerSentEvent[] | []; | ||
/** | ||
* from openai sdk. | ||
* A re-implementation of http[s]'s `LineDecoder` that handles incrementally | ||
* reading lines from text. | ||
* | ||
* https://github.com/encode/httpx/blob/920333ea98118e9cf617f246905d7b202510941c/httpx/_decoders.py#L258 | ||
*/ | ||
export declare class LineDecoder { | ||
buffer: string[]; | ||
trailingCR: boolean; | ||
textDecoder: any; | ||
constructor(); | ||
decode(chunk: Bytes): string[]; | ||
decodeText(bytes: Bytes): string; | ||
flush(): string[]; | ||
} | ||
/** | ||
* decode string lines to ServerSentEvent | ||
*/ | ||
export declare class SSEDecoder { | ||
@@ -6,10 +26,4 @@ private data; | ||
private chunks; | ||
private lineDecoder; | ||
constructor(); | ||
/** | ||
* @description decode string from sse stream | ||
*/ | ||
decode(chunk: Bytes): ServerSentEvent[]; | ||
private parseTextLine; | ||
private clear; | ||
decode(line: string): ServerSentEvent | null; | ||
} |
"use strict"; | ||
Object.defineProperty(exports, "__esModule", { value: true }); | ||
exports.SSEDecoder = void 0; | ||
exports.SSEDecoder = exports.LineDecoder = exports.parseServerSentEvent = void 0; | ||
// prettier-ignore | ||
@@ -8,2 +8,24 @@ const NEWLINE_CHARS = new Set(['\n', '\r', '\x0b', '\x0c', '\x1c', '\x1d', '\x1e', '\x85', '\u2028', '\u2029']); | ||
const NEWLINE_REGEXP = /\r\n|[\n\r\x0b\x0c\x1c\x1d\x1e\x85\u2028\u2029]/g; | ||
function parseServerSentEvent(chunk) { | ||
if (!chunk) | ||
return []; | ||
const decoder = new SSEDecoder(); | ||
const lineDecoder = new LineDecoder(); | ||
// raw string lines | ||
const lines = lineDecoder.decode(chunk); | ||
const list = []; | ||
for (const line of lines) { | ||
const sseData = decoder.decode(line); | ||
if (sseData) { | ||
list.push(sseData); | ||
} | ||
} | ||
for (const line of lineDecoder.flush()) { | ||
const sseData = decoder.decode(line); | ||
if (sseData) | ||
list.push(sseData); | ||
} | ||
return list; | ||
} | ||
exports.parseServerSentEvent = parseServerSentEvent; | ||
/** | ||
@@ -86,2 +108,6 @@ * from openai sdk. | ||
} | ||
exports.LineDecoder = LineDecoder; | ||
/** | ||
* decode string lines to ServerSentEvent | ||
*/ | ||
class SSEDecoder { | ||
@@ -92,34 +118,4 @@ constructor() { | ||
this.chunks = []; | ||
const lindDecoder = new LineDecoder(); | ||
this.lineDecoder = lindDecoder; | ||
} | ||
/** | ||
* @description decode string from sse stream | ||
*/ | ||
decode(chunk) { | ||
if (!chunk) | ||
return []; | ||
try { | ||
const lines = this.lineDecoder.decode(chunk); | ||
const list = []; | ||
for (const line of lines) { | ||
const sseData = this.parseTextLine(line); | ||
if (sseData) { | ||
list.push(sseData); | ||
} | ||
} | ||
for (const line of this.lineDecoder.flush()) { | ||
const sseData = this.parseTextLine(line); | ||
if (sseData) | ||
list.push(sseData); | ||
} | ||
this.clear(); | ||
return list; | ||
} | ||
catch (error) { | ||
this.clear(); | ||
throw new Error(error); | ||
} | ||
} | ||
parseTextLine(line) { | ||
decode(line) { | ||
if (line.endsWith('\r')) { | ||
@@ -159,7 +155,2 @@ line = line.substring(0, line.length - 1); | ||
} | ||
clear() { | ||
this.event = null; | ||
this.chunks = []; | ||
this.data = []; | ||
} | ||
} | ||
@@ -166,0 +157,0 @@ exports.SSEDecoder = SSEDecoder; |
{ | ||
"name": "fetch-sse", | ||
"version": "1.0.17", | ||
"version": "1.0.18", | ||
"description": "An easy API for making Event Source requests, with all the features of fetch(), Supports browsers and node.", | ||
@@ -5,0 +5,0 @@ "main": "./build/index.js", |
import { IFetchOptions } from './interface'; | ||
import { SSEDecoder } from './sse'; | ||
import { parseServerSentEvent } from './sse'; | ||
import { checkOk } from './utils'; | ||
@@ -16,3 +16,2 @@ | ||
try { | ||
const sse = new SSEDecoder(); | ||
const res = await fetch(url, { | ||
@@ -32,3 +31,3 @@ method, | ||
if (done) break; | ||
const decoded = sse.decode(value); | ||
const decoded = parseServerSentEvent(value); | ||
for (const event of decoded) { | ||
@@ -35,0 +34,0 @@ onMessage(event, done); |
@@ -8,2 +8,25 @@ import { Bytes, ServerSentEvent } from './interface'; | ||
export function parseServerSentEvent(chunk: Bytes): ServerSentEvent[] | [] { | ||
if (!chunk) return []; | ||
const decoder = new SSEDecoder(); | ||
const lineDecoder = new LineDecoder(); | ||
// raw string lines | ||
const lines = lineDecoder.decode(chunk); | ||
const list: ServerSentEvent[] = []; | ||
for (const line of lines) { | ||
const sseData = decoder.decode(line); | ||
if (sseData) { | ||
list.push(sseData); | ||
} | ||
} | ||
for (const line of lineDecoder.flush()) { | ||
const sseData = decoder.decode(line); | ||
if (sseData) list.push(sseData); | ||
} | ||
return list; | ||
} | ||
/** | ||
@@ -16,3 +39,3 @@ * from openai sdk. | ||
*/ | ||
class LineDecoder { | ||
export class LineDecoder { | ||
buffer: string[]; | ||
@@ -114,2 +137,5 @@ trailingCR: boolean; | ||
/** | ||
* decode string lines to ServerSentEvent | ||
*/ | ||
export class SSEDecoder { | ||
@@ -119,3 +145,2 @@ private data: string[]; | ||
private chunks: string[]; | ||
private lineDecoder: LineDecoder; | ||
@@ -126,33 +151,6 @@ constructor() { | ||
this.chunks = []; | ||
const lindDecoder = new LineDecoder(); | ||
this.lineDecoder = lindDecoder; | ||
} | ||
/** | ||
* @description decode string from sse stream | ||
*/ | ||
public decode(chunk: Bytes) { | ||
if (!chunk) return []; | ||
try { | ||
const lines = this.lineDecoder.decode(chunk); | ||
const list: ServerSentEvent[] = []; | ||
for (const line of lines) { | ||
const sseData = this.parseTextLine(line); | ||
if (sseData) { | ||
list.push(sseData); | ||
} | ||
} | ||
for (const line of this.lineDecoder.flush()) { | ||
const sseData = this.parseTextLine(line); | ||
if (sseData) list.push(sseData); | ||
} | ||
this.clear(); | ||
return list; | ||
} catch(error: any) { | ||
this.clear(); | ||
throw new Error(error); | ||
} | ||
} | ||
private parseTextLine(line: string) { | ||
public decode(line: string) { | ||
if (line.endsWith('\r')) { | ||
@@ -197,7 +195,17 @@ line = line.substring(0, line.length - 1); | ||
private clear() { | ||
this.event = null; | ||
this.chunks = []; | ||
this.data = []; | ||
} | ||
// private decodeChunk(chunk: Bytes) { | ||
// const decoder = new LineDecoder(); | ||
// return decoder.decode(chunk); | ||
// } | ||
// private decodeChunks(chunks: string[]) { | ||
// const decoder = new LineDecoder(); | ||
// const lines: string[] = []; | ||
// for (const chunk of chunks) { | ||
// const decoded = decoder.decode(chunk); | ||
// lines.push(...decoded); | ||
// } | ||
// return lines; | ||
// } | ||
} | ||
@@ -204,0 +212,0 @@ |
@@ -1,34 +0,21 @@ | ||
import { SSEDecoder } from '../src/sse'; | ||
import { LineDecoder } from '../src/sse'; | ||
import { checkOk } from '../src/utils'; | ||
const decoder = new SSEDecoder(); | ||
describe('SSEDecoder', () => { | ||
test('should decode data-only messages', () => { | ||
const decoder = new LineDecoder(); | ||
const raw = '{"username": "bobby", "time": "02:33:46"}'; | ||
const line = `data: ${raw}`; | ||
const buf = Buffer.from(`${line}\n\n`, 'utf-8'); | ||
const data = decoder.decode(buf)[0]; | ||
expect(data).toEqual({ | ||
event: null, | ||
data: raw, | ||
raw: [line] | ||
}); | ||
const data = decoder.decode(buf); | ||
expect(data).toEqual([line, '', '']); | ||
}); | ||
test('should decode named events', () => { | ||
const decoder = new LineDecoder(); | ||
const raw = '{"username": "bobby", "time": "02:33:48"}'; | ||
const lines = `:HTTP 1.1\nid: 1\nevent: result\ndata: ${raw}`; | ||
const buf = Buffer.from(`${lines}\n\n`, 'utf-8'); | ||
const data = decoder.decode(buf)[0]; | ||
expect(data).toEqual({ | ||
event: 'result', | ||
data: raw, | ||
raw: [ | ||
':HTTP 1.1', | ||
'id: 1', | ||
'event: result', | ||
`data: ${raw}` | ||
] | ||
}); | ||
const data = decoder.decode(buf); | ||
expect(data).toEqual([':HTTP 1.1', 'id: 1', 'event: result', `data: ${raw}`, '', '']); | ||
}); | ||
@@ -35,0 +22,0 @@ |
26077
666