@bagelink/sdk 1.15.543 → 1.15.549
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/dist/index.cjs +15 -6
- package/dist/index.mjs +15 -6
- package/package.json +1 -1
- package/src/openAPITools/streamClient.ts +12 -9
package/dist/index.cjs
CHANGED
|
@@ -1312,6 +1312,7 @@ function createSSEStream(url, options = {}) {
|
|
|
1312
1312
|
let lastEventId = initialLastEventId;
|
|
1313
1313
|
let reconnectAttempts = 0;
|
|
1314
1314
|
async function connect() {
|
|
1315
|
+
if (controller.signal.aborted) return;
|
|
1315
1316
|
const requestHeaders = {
|
|
1316
1317
|
"Accept": "text/event-stream",
|
|
1317
1318
|
"Cache-Control": "no-cache",
|
|
@@ -1341,10 +1342,10 @@ function createSSEStream(url, options = {}) {
|
|
|
1341
1342
|
stream.emit("error", new Error("Response body is null"));
|
|
1342
1343
|
return;
|
|
1343
1344
|
}
|
|
1344
|
-
reconnectAttempts = 0;
|
|
1345
1345
|
const reader = response.body.getReader();
|
|
1346
1346
|
const decoder = new TextDecoder();
|
|
1347
1347
|
let buffer = "";
|
|
1348
|
+
let terminalEventReceived = false;
|
|
1348
1349
|
let currentEvent = "message";
|
|
1349
1350
|
let currentData = "";
|
|
1350
1351
|
let currentId;
|
|
@@ -1352,11 +1353,10 @@ function createSSEStream(url, options = {}) {
|
|
|
1352
1353
|
while (true) {
|
|
1353
1354
|
const { done, value } = await reader.read();
|
|
1354
1355
|
if (done) {
|
|
1355
|
-
if (!controller.signal.aborted) {
|
|
1356
|
-
|
|
1357
|
-
stream.emit("complete", {});
|
|
1356
|
+
if (!controller.signal.aborted && !terminalEventReceived) {
|
|
1357
|
+
return handleDisconnect(new Error("Stream ended before a terminal event"));
|
|
1358
1358
|
}
|
|
1359
|
-
|
|
1359
|
+
return;
|
|
1360
1360
|
}
|
|
1361
1361
|
buffer += decoder.decode(value, { stream: true });
|
|
1362
1362
|
const lines = buffer.split("\n");
|
|
@@ -1370,12 +1370,21 @@ function createSSEStream(url, options = {}) {
|
|
|
1370
1370
|
currentData = currentData ? `${currentData}
|
|
1371
1371
|
${line.slice(5).trim()}` : line.slice(5).trim();
|
|
1372
1372
|
} else if (line === "" && currentData) {
|
|
1373
|
-
if (currentId !== void 0)
|
|
1373
|
+
if (currentId !== void 0) {
|
|
1374
|
+
if (currentId !== lastEventId) reconnectAttempts = 0;
|
|
1375
|
+
lastEventId = currentId;
|
|
1376
|
+
}
|
|
1374
1377
|
try {
|
|
1375
1378
|
const parsed = JSON.parse(currentData);
|
|
1376
1379
|
stream.emit(currentEvent, parsed);
|
|
1377
1380
|
if (currentEvent === "done" || currentEvent === "error") {
|
|
1381
|
+
terminalEventReceived = true;
|
|
1378
1382
|
stream.emit("complete", {});
|
|
1383
|
+
controller.abort();
|
|
1384
|
+
try {
|
|
1385
|
+
await reader.cancel();
|
|
1386
|
+
} catch {
|
|
1387
|
+
}
|
|
1379
1388
|
return;
|
|
1380
1389
|
}
|
|
1381
1390
|
} catch {
|
package/dist/index.mjs
CHANGED
|
@@ -1306,6 +1306,7 @@ function createSSEStream(url, options = {}) {
|
|
|
1306
1306
|
let lastEventId = initialLastEventId;
|
|
1307
1307
|
let reconnectAttempts = 0;
|
|
1308
1308
|
async function connect() {
|
|
1309
|
+
if (controller.signal.aborted) return;
|
|
1309
1310
|
const requestHeaders = {
|
|
1310
1311
|
"Accept": "text/event-stream",
|
|
1311
1312
|
"Cache-Control": "no-cache",
|
|
@@ -1335,10 +1336,10 @@ function createSSEStream(url, options = {}) {
|
|
|
1335
1336
|
stream.emit("error", new Error("Response body is null"));
|
|
1336
1337
|
return;
|
|
1337
1338
|
}
|
|
1338
|
-
reconnectAttempts = 0;
|
|
1339
1339
|
const reader = response.body.getReader();
|
|
1340
1340
|
const decoder = new TextDecoder();
|
|
1341
1341
|
let buffer = "";
|
|
1342
|
+
let terminalEventReceived = false;
|
|
1342
1343
|
let currentEvent = "message";
|
|
1343
1344
|
let currentData = "";
|
|
1344
1345
|
let currentId;
|
|
@@ -1346,11 +1347,10 @@ function createSSEStream(url, options = {}) {
|
|
|
1346
1347
|
while (true) {
|
|
1347
1348
|
const { done, value } = await reader.read();
|
|
1348
1349
|
if (done) {
|
|
1349
|
-
if (!controller.signal.aborted) {
|
|
1350
|
-
|
|
1351
|
-
stream.emit("complete", {});
|
|
1350
|
+
if (!controller.signal.aborted && !terminalEventReceived) {
|
|
1351
|
+
return handleDisconnect(new Error("Stream ended before a terminal event"));
|
|
1352
1352
|
}
|
|
1353
|
-
|
|
1353
|
+
return;
|
|
1354
1354
|
}
|
|
1355
1355
|
buffer += decoder.decode(value, { stream: true });
|
|
1356
1356
|
const lines = buffer.split("\n");
|
|
@@ -1364,12 +1364,21 @@ function createSSEStream(url, options = {}) {
|
|
|
1364
1364
|
currentData = currentData ? `${currentData}
|
|
1365
1365
|
${line.slice(5).trim()}` : line.slice(5).trim();
|
|
1366
1366
|
} else if (line === "" && currentData) {
|
|
1367
|
-
if (currentId !== void 0)
|
|
1367
|
+
if (currentId !== void 0) {
|
|
1368
|
+
if (currentId !== lastEventId) reconnectAttempts = 0;
|
|
1369
|
+
lastEventId = currentId;
|
|
1370
|
+
}
|
|
1368
1371
|
try {
|
|
1369
1372
|
const parsed = JSON.parse(currentData);
|
|
1370
1373
|
stream.emit(currentEvent, parsed);
|
|
1371
1374
|
if (currentEvent === "done" || currentEvent === "error") {
|
|
1375
|
+
terminalEventReceived = true;
|
|
1372
1376
|
stream.emit("complete", {});
|
|
1377
|
+
controller.abort();
|
|
1378
|
+
try {
|
|
1379
|
+
await reader.cancel();
|
|
1380
|
+
} catch {
|
|
1381
|
+
}
|
|
1373
1382
|
return;
|
|
1374
1383
|
}
|
|
1375
1384
|
} catch {
|
package/package.json
CHANGED
|
@@ -66,6 +66,7 @@ export function createSSEStream<TEventMap extends StreamEventMap = StreamEventMa
|
|
|
66
66
|
let reconnectAttempts = 0
|
|
67
67
|
|
|
68
68
|
async function connect(): Promise<void> {
|
|
69
|
+
if (controller.signal.aborted) return
|
|
69
70
|
const requestHeaders: Record<string, string> = {
|
|
70
71
|
'Accept': 'text/event-stream',
|
|
71
72
|
'Cache-Control': 'no-cache',
|
|
@@ -98,12 +99,10 @@ export function createSSEStream<TEventMap extends StreamEventMap = StreamEventMa
|
|
|
98
99
|
return
|
|
99
100
|
}
|
|
100
101
|
|
|
101
|
-
// Successful connection — reset reconnect counter
|
|
102
|
-
reconnectAttempts = 0
|
|
103
|
-
|
|
104
102
|
const reader = response.body.getReader()
|
|
105
103
|
const decoder = new TextDecoder()
|
|
106
104
|
let buffer = ''
|
|
105
|
+
let terminalEventReceived = false
|
|
107
106
|
|
|
108
107
|
// SSE parser state MUST live across read() chunks: a single event's
|
|
109
108
|
// `event:`/`data:` lines and its terminating blank line can be split over
|
|
@@ -120,12 +119,10 @@ export function createSSEStream<TEventMap extends StreamEventMap = StreamEventMa
|
|
|
120
119
|
const { done, value } = await reader.read()
|
|
121
120
|
|
|
122
121
|
if (done) {
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
stream.emit('done', {})
|
|
126
|
-
stream.emit('complete', {})
|
|
122
|
+
if (!controller.signal.aborted && !terminalEventReceived) {
|
|
123
|
+
return handleDisconnect(new Error('Stream ended before a terminal event'))
|
|
127
124
|
}
|
|
128
|
-
|
|
125
|
+
return
|
|
129
126
|
}
|
|
130
127
|
|
|
131
128
|
buffer += decoder.decode(value, { stream: true })
|
|
@@ -143,7 +140,10 @@ export function createSSEStream<TEventMap extends StreamEventMap = StreamEventMa
|
|
|
143
140
|
currentData = currentData ? `${currentData}\n${line.slice(5).trim()}` : line.slice(5).trim()
|
|
144
141
|
} else if (line === '' && currentData) {
|
|
145
142
|
// Track last seen ID for reconnect
|
|
146
|
-
if (currentId !== undefined)
|
|
143
|
+
if (currentId !== undefined) {
|
|
144
|
+
if (currentId !== lastEventId) reconnectAttempts = 0
|
|
145
|
+
lastEventId = currentId
|
|
146
|
+
}
|
|
147
147
|
|
|
148
148
|
try {
|
|
149
149
|
const parsed = JSON.parse(currentData)
|
|
@@ -151,7 +151,10 @@ export function createSSEStream<TEventMap extends StreamEventMap = StreamEventMa
|
|
|
151
151
|
|
|
152
152
|
// Auto-close stream on terminal events
|
|
153
153
|
if (currentEvent === 'done' || currentEvent === 'error') {
|
|
154
|
+
terminalEventReceived = true
|
|
154
155
|
stream.emit('complete', {})
|
|
156
|
+
controller.abort()
|
|
157
|
+
try { await reader.cancel() } catch { /* already closed */ }
|
|
155
158
|
return
|
|
156
159
|
}
|
|
157
160
|
} catch {
|