@bagelink/sdk 1.8.14 → 1.8.16
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/bin/index.ts +1 -22
- package/dist/index.cjs +125 -342
- package/dist/index.d.cts +20 -55
- package/dist/index.d.mts +20 -55
- package/dist/index.d.ts +20 -55
- package/dist/index.mjs +125 -342
- package/package.json +1 -1
- package/src/openAPITools/StreamController.ts +30 -246
- package/src/openAPITools/functionGenerator.ts +4 -11
- package/src/openAPITools/streamClient.ts +137 -167
package/bin/index.ts
CHANGED
|
@@ -23,28 +23,7 @@ export async function loadTypes() {
|
|
|
23
23
|
const apiPath = join(bagelinkDir, 'api.ts')
|
|
24
24
|
await formatAndWriteCode(apiPath, code)
|
|
25
25
|
|
|
26
|
-
|
|
27
|
-
const srcDir = join(__dirname, '..', 'src', 'openAPITools')
|
|
28
|
-
const streamClientSource = join(srcDir, 'streamClient.ts')
|
|
29
|
-
const streamControllerSource = join(srcDir, 'StreamController.ts')
|
|
30
|
-
|
|
31
|
-
if (fs.existsSync(streamClientSource)) {
|
|
32
|
-
const streamClientCode = fs.readFileSync(streamClientSource, 'utf-8')
|
|
33
|
-
const streamClientDest = join(bagelinkDir, 'streamClient.ts')
|
|
34
|
-
await formatAndWriteCode(streamClientDest, streamClientCode)
|
|
35
|
-
console.log('✅ Generated streamClient.ts')
|
|
36
|
-
} else {
|
|
37
|
-
console.warn('⚠️ streamClient.ts not found at:', streamClientSource)
|
|
38
|
-
}
|
|
39
|
-
|
|
40
|
-
if (fs.existsSync(streamControllerSource)) {
|
|
41
|
-
const streamControllerCode = fs.readFileSync(streamControllerSource, 'utf-8')
|
|
42
|
-
const streamControllerDest = join(bagelinkDir, 'StreamController.ts')
|
|
43
|
-
await formatAndWriteCode(streamControllerDest, streamControllerCode)
|
|
44
|
-
console.log('✅ Generated StreamController.ts')
|
|
45
|
-
} else {
|
|
46
|
-
console.warn('⚠️ StreamController.ts not found at:', streamControllerSource)
|
|
47
|
-
}
|
|
26
|
+
console.log('ℹ️ Stream utilities are imported from @bagelink/sdk (no need to copy)')
|
|
48
27
|
|
|
49
28
|
// Optionally split into organized files
|
|
50
29
|
if (shouldSplitFiles) {
|
package/dist/index.cjs
CHANGED
|
@@ -899,7 +899,7 @@ function fileTemplate(tsString, typeForImport, baseURL) {
|
|
|
899
899
|
const templateCode = `import ax from 'axios';
|
|
900
900
|
import type { AxiosResponse } from 'axios';
|
|
901
901
|
import type { ${typeForImport.join(", ")} } from './types.d';
|
|
902
|
-
import { createSSEStream, createSSEStreamPost, StreamController, type SSEStreamOptions, type SSEEvent } from '
|
|
902
|
+
import { createSSEStream, createSSEStreamPost, StreamController, type SSEStreamOptions, type SSEEvent } from '@bagelink/sdk';
|
|
903
903
|
|
|
904
904
|
/**
|
|
905
905
|
* Options for file upload operations
|
|
@@ -914,22 +914,15 @@ export interface UploadOptions {
|
|
|
914
914
|
}
|
|
915
915
|
|
|
916
916
|
/**
|
|
917
|
-
*
|
|
917
|
+
* Stream utilities are exported from @bagelink/sdk
|
|
918
918
|
*
|
|
919
919
|
* @example Chainable event handlers
|
|
920
|
+
* import { createSSEStream } from '@bagelink/sdk'
|
|
921
|
+
*
|
|
920
922
|
* const stream = createSSEStream(url)
|
|
921
923
|
* .on('token', (data) => console.log(data))
|
|
922
924
|
* .on('done', () => console.log('Complete!'))
|
|
923
|
-
*
|
|
924
|
-
* @example Async iteration
|
|
925
|
-
* for await (const event of createSSEStream(url)) {
|
|
926
|
-
* console.log(event.type, event.data)
|
|
927
|
-
* }
|
|
928
|
-
*
|
|
929
|
-
* @example Promise-based
|
|
930
|
-
* const result = await createSSEStream(url).toPromise()
|
|
931
925
|
*/
|
|
932
|
-
export { createSSEStream, createSSEStreamPost, StreamController, type SSEStreamOptions, type SSEEvent } from './streamClient';
|
|
933
926
|
${streamTypeDefs}
|
|
934
927
|
/**
|
|
935
928
|
* Configured axios instance for API requests
|
|
@@ -985,36 +978,13 @@ function generateTypes(schemas) {
|
|
|
985
978
|
}
|
|
986
979
|
|
|
987
980
|
class StreamController {
|
|
988
|
-
constructor(
|
|
989
|
-
this.
|
|
990
|
-
this.
|
|
991
|
-
this.start();
|
|
981
|
+
constructor(cleanup) {
|
|
982
|
+
this.cleanup = cleanup;
|
|
983
|
+
this.controller = new AbortController();
|
|
992
984
|
}
|
|
993
985
|
handlers = /* @__PURE__ */ new Map();
|
|
994
|
-
|
|
995
|
-
completeHandlers = /* @__PURE__ */ new Set();
|
|
996
|
-
abortController;
|
|
986
|
+
controller;
|
|
997
987
|
_closed = false;
|
|
998
|
-
_promise = null;
|
|
999
|
-
_resolvePromise = null;
|
|
1000
|
-
_rejectPromise = null;
|
|
1001
|
-
start() {
|
|
1002
|
-
const cleanup = this.streamFn(
|
|
1003
|
-
(event) => {
|
|
1004
|
-
this.emit(event.type, event.data);
|
|
1005
|
-
},
|
|
1006
|
-
(error) => {
|
|
1007
|
-
this.emitError(error);
|
|
1008
|
-
},
|
|
1009
|
-
() => {
|
|
1010
|
-
this.emitComplete();
|
|
1011
|
-
}
|
|
1012
|
-
);
|
|
1013
|
-
this.abortController.signal.addEventListener("abort", () => {
|
|
1014
|
-
cleanup();
|
|
1015
|
-
this._closed = true;
|
|
1016
|
-
});
|
|
1017
|
-
}
|
|
1018
988
|
/**
|
|
1019
989
|
* Register an event handler (fully typed!)
|
|
1020
990
|
* @param event - Event type to listen for
|
|
@@ -1022,22 +992,16 @@ class StreamController {
|
|
|
1022
992
|
* @returns this (for chaining)
|
|
1023
993
|
*/
|
|
1024
994
|
on(event, handler) {
|
|
1025
|
-
if (event
|
|
1026
|
-
this.
|
|
1027
|
-
} else if (event === "complete") {
|
|
1028
|
-
this.completeHandlers.add(handler);
|
|
1029
|
-
} else {
|
|
1030
|
-
if (!this.handlers.has(event)) {
|
|
1031
|
-
this.handlers.set(event, /* @__PURE__ */ new Set());
|
|
1032
|
-
}
|
|
1033
|
-
this.handlers.get(event).add(handler);
|
|
995
|
+
if (!this.handlers.has(event)) {
|
|
996
|
+
this.handlers.set(event, /* @__PURE__ */ new Set());
|
|
1034
997
|
}
|
|
998
|
+
this.handlers.get(event).add(handler);
|
|
1035
999
|
return this;
|
|
1036
1000
|
}
|
|
1037
1001
|
/**
|
|
1038
1002
|
* Register a one-time event handler (fully typed!)
|
|
1039
1003
|
* @param event - Event type to listen for
|
|
1040
|
-
* @param handler - Handler function (called once then removed
|
|
1004
|
+
* @param handler - Handler function (called once then removed)
|
|
1041
1005
|
* @returns this (for chaining)
|
|
1042
1006
|
*/
|
|
1043
1007
|
once(event, handler) {
|
|
@@ -1054,13 +1018,7 @@ class StreamController {
|
|
|
1054
1018
|
* @returns this (for chaining)
|
|
1055
1019
|
*/
|
|
1056
1020
|
off(event, handler) {
|
|
1057
|
-
|
|
1058
|
-
this.errorHandlers.delete(handler);
|
|
1059
|
-
} else if (event === "complete") {
|
|
1060
|
-
this.completeHandlers.delete(handler);
|
|
1061
|
-
} else {
|
|
1062
|
-
this.handlers.get(event)?.delete(handler);
|
|
1063
|
-
}
|
|
1021
|
+
this.handlers.get(event)?.delete(handler);
|
|
1064
1022
|
return this;
|
|
1065
1023
|
}
|
|
1066
1024
|
/**
|
|
@@ -1069,17 +1027,15 @@ class StreamController {
|
|
|
1069
1027
|
removeAllListeners(event) {
|
|
1070
1028
|
if (event === void 0) {
|
|
1071
1029
|
this.handlers.clear();
|
|
1072
|
-
this.errorHandlers.clear();
|
|
1073
|
-
this.completeHandlers.clear();
|
|
1074
|
-
} else if (event === "error") {
|
|
1075
|
-
this.errorHandlers.clear();
|
|
1076
|
-
} else if (event === "complete") {
|
|
1077
|
-
this.completeHandlers.clear();
|
|
1078
1030
|
} else {
|
|
1079
1031
|
this.handlers.delete(event);
|
|
1080
1032
|
}
|
|
1081
1033
|
return this;
|
|
1082
1034
|
}
|
|
1035
|
+
/**
|
|
1036
|
+
* Emit an event to all registered handlers
|
|
1037
|
+
* @internal
|
|
1038
|
+
*/
|
|
1083
1039
|
emit(event, data) {
|
|
1084
1040
|
const handlers = this.handlers.get(event);
|
|
1085
1041
|
if (handlers) {
|
|
@@ -1087,41 +1043,18 @@ class StreamController {
|
|
|
1087
1043
|
try {
|
|
1088
1044
|
handler(data);
|
|
1089
1045
|
} catch (error) {
|
|
1090
|
-
console.error(`Error in
|
|
1046
|
+
console.error(`Error in ${event} handler:`, error);
|
|
1091
1047
|
}
|
|
1092
1048
|
});
|
|
1093
1049
|
}
|
|
1094
|
-
if (event === "done" && this._resolvePromise) {
|
|
1095
|
-
this._resolvePromise(data);
|
|
1096
|
-
}
|
|
1097
|
-
}
|
|
1098
|
-
emitError(error) {
|
|
1099
|
-
this.errorHandlers.forEach((handler) => {
|
|
1100
|
-
try {
|
|
1101
|
-
handler(error);
|
|
1102
|
-
} catch (err) {
|
|
1103
|
-
console.error("Error in error handler:", err);
|
|
1104
|
-
}
|
|
1105
|
-
});
|
|
1106
|
-
if (this._rejectPromise) {
|
|
1107
|
-
this._rejectPromise(error);
|
|
1108
|
-
}
|
|
1109
|
-
}
|
|
1110
|
-
emitComplete() {
|
|
1111
|
-
this.completeHandlers.forEach((handler) => {
|
|
1112
|
-
try {
|
|
1113
|
-
handler();
|
|
1114
|
-
} catch (error) {
|
|
1115
|
-
console.error("Error in complete handler:", error);
|
|
1116
|
-
}
|
|
1117
|
-
});
|
|
1118
1050
|
}
|
|
1119
1051
|
/**
|
|
1120
1052
|
* Close the stream
|
|
1121
1053
|
*/
|
|
1122
1054
|
close() {
|
|
1123
1055
|
if (!this._closed) {
|
|
1124
|
-
this.
|
|
1056
|
+
this.controller.abort();
|
|
1057
|
+
this.cleanup();
|
|
1125
1058
|
this._closed = true;
|
|
1126
1059
|
}
|
|
1127
1060
|
}
|
|
@@ -1131,281 +1064,131 @@ class StreamController {
|
|
|
1131
1064
|
get closed() {
|
|
1132
1065
|
return this._closed;
|
|
1133
1066
|
}
|
|
1134
|
-
|
|
1135
|
-
|
|
1136
|
-
|
|
1137
|
-
|
|
1138
|
-
|
|
1139
|
-
|
|
1140
|
-
|
|
1141
|
-
|
|
1142
|
-
|
|
1143
|
-
|
|
1067
|
+
}
|
|
1068
|
+
|
|
1069
|
+
function createSSEStream(url, options = {}) {
|
|
1070
|
+
const { headers = {}, withCredentials = true } = options;
|
|
1071
|
+
const controller = new AbortController();
|
|
1072
|
+
const stream = new StreamController(() => {
|
|
1073
|
+
controller.abort();
|
|
1074
|
+
});
|
|
1075
|
+
fetch(url, {
|
|
1076
|
+
method: "GET",
|
|
1077
|
+
headers: {
|
|
1078
|
+
Accept: "text/event-stream",
|
|
1079
|
+
...headers
|
|
1080
|
+
},
|
|
1081
|
+
credentials: withCredentials ? "include" : "same-origin",
|
|
1082
|
+
signal: controller.signal
|
|
1083
|
+
}).then(async (response) => {
|
|
1084
|
+
if (!response.ok) {
|
|
1085
|
+
throw new Error(`HTTP ${response.status}: ${response.statusText}`);
|
|
1144
1086
|
}
|
|
1145
|
-
|
|
1146
|
-
|
|
1147
|
-
|
|
1148
|
-
|
|
1149
|
-
|
|
1150
|
-
|
|
1151
|
-
async *[Symbol.asyncIterator]() {
|
|
1152
|
-
const events = [];
|
|
1153
|
-
let resolveNext = null;
|
|
1154
|
-
let done = false;
|
|
1155
|
-
const eventHandler = (type) => (data) => {
|
|
1156
|
-
const event = { type, data };
|
|
1157
|
-
if (resolveNext) {
|
|
1158
|
-
resolveNext(event);
|
|
1159
|
-
resolveNext = null;
|
|
1160
|
-
} else {
|
|
1161
|
-
events.push(event);
|
|
1162
|
-
}
|
|
1163
|
-
};
|
|
1164
|
-
const originalEmit = this.emit.bind(this);
|
|
1165
|
-
const capturedEvents = [];
|
|
1166
|
-
this.emit = (event, data) => {
|
|
1167
|
-
if (!capturedEvents.includes(event)) {
|
|
1168
|
-
capturedEvents.push(event);
|
|
1169
|
-
this.on(event, eventHandler(event));
|
|
1170
|
-
}
|
|
1171
|
-
originalEmit(event, data);
|
|
1172
|
-
};
|
|
1173
|
-
this.on("complete", () => {
|
|
1174
|
-
done = true;
|
|
1175
|
-
if (resolveNext) {
|
|
1176
|
-
resolveNext(null);
|
|
1177
|
-
resolveNext = null;
|
|
1178
|
-
}
|
|
1179
|
-
});
|
|
1087
|
+
if (!response.body) {
|
|
1088
|
+
throw new Error("Response body is null");
|
|
1089
|
+
}
|
|
1090
|
+
const reader = response.body.getReader();
|
|
1091
|
+
const decoder = new TextDecoder();
|
|
1092
|
+
let buffer = "";
|
|
1180
1093
|
try {
|
|
1181
|
-
while (
|
|
1182
|
-
|
|
1183
|
-
|
|
1184
|
-
|
|
1185
|
-
|
|
1186
|
-
const event = await new Promise((resolve) => {
|
|
1187
|
-
resolveNext = resolve;
|
|
1188
|
-
});
|
|
1189
|
-
if (event === null) break;
|
|
1190
|
-
yield event;
|
|
1094
|
+
while (true) {
|
|
1095
|
+
const { done, value } = await reader.read();
|
|
1096
|
+
if (done) {
|
|
1097
|
+
stream.emit("complete", {});
|
|
1098
|
+
break;
|
|
1191
1099
|
}
|
|
1192
|
-
|
|
1193
|
-
|
|
1194
|
-
|
|
1195
|
-
|
|
1196
|
-
|
|
1197
|
-
|
|
1198
|
-
|
|
1199
|
-
|
|
1200
|
-
*/
|
|
1201
|
-
async toArray() {
|
|
1202
|
-
const events = [];
|
|
1203
|
-
for await (const event of this) {
|
|
1204
|
-
events.push(event);
|
|
1205
|
-
}
|
|
1206
|
-
return events;
|
|
1207
|
-
}
|
|
1208
|
-
/**
|
|
1209
|
-
* Pipe stream events through a transform function
|
|
1210
|
-
*/
|
|
1211
|
-
map(transform) {
|
|
1212
|
-
const mappedController = new StreamController(
|
|
1213
|
-
(onEvent, onError, onComplete) => {
|
|
1214
|
-
this.on("error", onError);
|
|
1215
|
-
this.on("complete", onComplete);
|
|
1216
|
-
this.handlers.forEach((_, eventType) => {
|
|
1217
|
-
this.on(eventType, (data) => {
|
|
1100
|
+
buffer += decoder.decode(value, { stream: true });
|
|
1101
|
+
const lines = buffer.split("\n");
|
|
1102
|
+
buffer = lines.pop() || "";
|
|
1103
|
+
let eventData = "";
|
|
1104
|
+
for (const line of lines) {
|
|
1105
|
+
if (line.startsWith("data:")) {
|
|
1106
|
+
eventData = line.slice(5).trim();
|
|
1107
|
+
} else if (line === "" && eventData) {
|
|
1218
1108
|
try {
|
|
1219
|
-
const
|
|
1220
|
-
|
|
1109
|
+
const data = JSON.parse(eventData);
|
|
1110
|
+
stream.emit(data.type || "message", data);
|
|
1221
1111
|
} catch (error) {
|
|
1222
|
-
|
|
1223
|
-
}
|
|
1224
|
-
});
|
|
1225
|
-
});
|
|
1226
|
-
return () => {
|
|
1227
|
-
this.close();
|
|
1228
|
-
};
|
|
1229
|
-
}
|
|
1230
|
-
);
|
|
1231
|
-
return mappedController;
|
|
1232
|
-
}
|
|
1233
|
-
/**
|
|
1234
|
-
* Filter events based on a predicate
|
|
1235
|
-
*/
|
|
1236
|
-
filter(predicate) {
|
|
1237
|
-
const filteredController = new StreamController(
|
|
1238
|
-
(onEvent, onError, onComplete) => {
|
|
1239
|
-
this.on("error", onError);
|
|
1240
|
-
this.on("complete", onComplete);
|
|
1241
|
-
this.handlers.forEach((_, eventType) => {
|
|
1242
|
-
this.on(eventType, (data) => {
|
|
1243
|
-
const event = { type: eventType, data };
|
|
1244
|
-
if (predicate(event)) {
|
|
1245
|
-
onEvent(event);
|
|
1246
|
-
}
|
|
1247
|
-
});
|
|
1248
|
-
});
|
|
1249
|
-
return () => {
|
|
1250
|
-
this.close();
|
|
1251
|
-
};
|
|
1252
|
-
}
|
|
1253
|
-
);
|
|
1254
|
-
return filteredController;
|
|
1255
|
-
}
|
|
1256
|
-
}
|
|
1257
|
-
|
|
1258
|
-
function createSSEStream(url, options = {}) {
|
|
1259
|
-
const { headers = {}, withCredentials = true } = options;
|
|
1260
|
-
return new StreamController((onEvent, onError, onComplete) => {
|
|
1261
|
-
const controller = new AbortController();
|
|
1262
|
-
const { signal } = controller;
|
|
1263
|
-
fetch(url, {
|
|
1264
|
-
method: "GET",
|
|
1265
|
-
headers: {
|
|
1266
|
-
Accept: "text/event-stream",
|
|
1267
|
-
...headers
|
|
1268
|
-
},
|
|
1269
|
-
credentials: withCredentials ? "include" : "same-origin",
|
|
1270
|
-
signal
|
|
1271
|
-
}).then(async (response) => {
|
|
1272
|
-
if (!response.ok) {
|
|
1273
|
-
throw new Error(`HTTP ${response.status}: ${response.statusText}`);
|
|
1274
|
-
}
|
|
1275
|
-
if (!response.body) {
|
|
1276
|
-
throw new Error("Response body is null");
|
|
1277
|
-
}
|
|
1278
|
-
const reader = response.body.getReader();
|
|
1279
|
-
const decoder = new TextDecoder();
|
|
1280
|
-
let buffer = "";
|
|
1281
|
-
try {
|
|
1282
|
-
while (true) {
|
|
1283
|
-
const { done, value } = await reader.read();
|
|
1284
|
-
if (done) {
|
|
1285
|
-
onComplete();
|
|
1286
|
-
break;
|
|
1287
|
-
}
|
|
1288
|
-
buffer += decoder.decode(value, { stream: true });
|
|
1289
|
-
const lines = buffer.split("\n");
|
|
1290
|
-
buffer = lines.pop() || "";
|
|
1291
|
-
let eventType = "";
|
|
1292
|
-
let eventData = "";
|
|
1293
|
-
for (const line of lines) {
|
|
1294
|
-
if (line.startsWith("event:")) {
|
|
1295
|
-
eventType = line.slice(6).trim();
|
|
1296
|
-
} else if (line.startsWith("data:")) {
|
|
1297
|
-
eventData = line.slice(5).trim();
|
|
1298
|
-
} else if (line === "" && eventData) {
|
|
1299
|
-
try {
|
|
1300
|
-
const parsedData = JSON.parse(eventData);
|
|
1301
|
-
onEvent({
|
|
1302
|
-
type: eventType || "message",
|
|
1303
|
-
data: parsedData,
|
|
1304
|
-
raw: eventData
|
|
1305
|
-
});
|
|
1306
|
-
} catch {
|
|
1307
|
-
onEvent({
|
|
1308
|
-
type: eventType || "message",
|
|
1309
|
-
data: eventData,
|
|
1310
|
-
raw: eventData
|
|
1311
|
-
});
|
|
1312
|
-
}
|
|
1313
|
-
eventType = "";
|
|
1314
|
-
eventData = "";
|
|
1112
|
+
console.error("Failed to parse SSE event:", error);
|
|
1315
1113
|
}
|
|
1114
|
+
eventData = "";
|
|
1316
1115
|
}
|
|
1317
1116
|
}
|
|
1318
|
-
} catch (error) {
|
|
1319
|
-
if (error instanceof Error && error.name !== "AbortError") {
|
|
1320
|
-
onError(error);
|
|
1321
|
-
}
|
|
1322
1117
|
}
|
|
1323
|
-
}
|
|
1324
|
-
if (error.name !== "AbortError") {
|
|
1325
|
-
|
|
1118
|
+
} catch (error) {
|
|
1119
|
+
if (error instanceof Error && error.name !== "AbortError") {
|
|
1120
|
+
stream.emit("error", error);
|
|
1326
1121
|
}
|
|
1327
|
-
}
|
|
1328
|
-
|
|
1329
|
-
|
|
1330
|
-
|
|
1122
|
+
}
|
|
1123
|
+
}).catch((error) => {
|
|
1124
|
+
if (error.name !== "AbortError") {
|
|
1125
|
+
stream.emit("error", error);
|
|
1126
|
+
}
|
|
1331
1127
|
});
|
|
1128
|
+
return stream;
|
|
1332
1129
|
}
|
|
1333
1130
|
function createSSEStreamPost(url, body, options = {}) {
|
|
1334
1131
|
const { headers = {}, withCredentials = true } = options;
|
|
1335
|
-
|
|
1336
|
-
|
|
1337
|
-
|
|
1338
|
-
|
|
1339
|
-
|
|
1340
|
-
|
|
1341
|
-
|
|
1342
|
-
|
|
1343
|
-
|
|
1344
|
-
|
|
1345
|
-
|
|
1346
|
-
|
|
1347
|
-
|
|
1348
|
-
|
|
1349
|
-
|
|
1350
|
-
|
|
1351
|
-
}
|
|
1352
|
-
|
|
1353
|
-
|
|
1354
|
-
|
|
1355
|
-
|
|
1356
|
-
|
|
1357
|
-
|
|
1358
|
-
|
|
1359
|
-
|
|
1360
|
-
|
|
1361
|
-
|
|
1362
|
-
|
|
1363
|
-
|
|
1364
|
-
|
|
1365
|
-
|
|
1366
|
-
|
|
1367
|
-
|
|
1368
|
-
|
|
1369
|
-
|
|
1370
|
-
|
|
1371
|
-
|
|
1372
|
-
|
|
1373
|
-
|
|
1374
|
-
|
|
1375
|
-
|
|
1376
|
-
|
|
1377
|
-
|
|
1378
|
-
|
|
1379
|
-
type: eventType || "message",
|
|
1380
|
-
data: parsedData,
|
|
1381
|
-
raw: eventData
|
|
1382
|
-
});
|
|
1383
|
-
} catch {
|
|
1384
|
-
onEvent({
|
|
1385
|
-
type: eventType || "message",
|
|
1386
|
-
data: eventData,
|
|
1387
|
-
raw: eventData
|
|
1388
|
-
});
|
|
1389
|
-
}
|
|
1390
|
-
eventType = "";
|
|
1391
|
-
eventData = "";
|
|
1132
|
+
const controller = new AbortController();
|
|
1133
|
+
const stream = new StreamController(() => {
|
|
1134
|
+
controller.abort();
|
|
1135
|
+
});
|
|
1136
|
+
fetch(url, {
|
|
1137
|
+
method: "POST",
|
|
1138
|
+
headers: {
|
|
1139
|
+
"Accept": "text/event-stream",
|
|
1140
|
+
"Content-Type": "application/json",
|
|
1141
|
+
...headers
|
|
1142
|
+
},
|
|
1143
|
+
credentials: withCredentials ? "include" : "same-origin",
|
|
1144
|
+
body: JSON.stringify(body),
|
|
1145
|
+
signal: controller.signal
|
|
1146
|
+
}).then(async (response) => {
|
|
1147
|
+
if (!response.ok) {
|
|
1148
|
+
throw new Error(`HTTP ${response.status}: ${response.statusText}`);
|
|
1149
|
+
}
|
|
1150
|
+
if (!response.body) {
|
|
1151
|
+
throw new Error("Response body is null");
|
|
1152
|
+
}
|
|
1153
|
+
const reader = response.body.getReader();
|
|
1154
|
+
const decoder = new TextDecoder();
|
|
1155
|
+
let buffer = "";
|
|
1156
|
+
try {
|
|
1157
|
+
while (true) {
|
|
1158
|
+
const { done, value } = await reader.read();
|
|
1159
|
+
if (done) {
|
|
1160
|
+
stream.emit("complete", {});
|
|
1161
|
+
break;
|
|
1162
|
+
}
|
|
1163
|
+
buffer += decoder.decode(value, { stream: true });
|
|
1164
|
+
const lines = buffer.split("\n");
|
|
1165
|
+
buffer = lines.pop() || "";
|
|
1166
|
+
let eventData = "";
|
|
1167
|
+
for (const line of lines) {
|
|
1168
|
+
if (line.startsWith("data:")) {
|
|
1169
|
+
eventData = line.slice(5).trim();
|
|
1170
|
+
} else if (line === "" && eventData) {
|
|
1171
|
+
try {
|
|
1172
|
+
const data = JSON.parse(eventData);
|
|
1173
|
+
stream.emit(data.type || "message", data);
|
|
1174
|
+
} catch (error) {
|
|
1175
|
+
console.error("Failed to parse SSE event:", error);
|
|
1392
1176
|
}
|
|
1177
|
+
eventData = "";
|
|
1393
1178
|
}
|
|
1394
1179
|
}
|
|
1395
|
-
} catch (error) {
|
|
1396
|
-
if (error instanceof Error && error.name !== "AbortError") {
|
|
1397
|
-
onError(error);
|
|
1398
|
-
}
|
|
1399
1180
|
}
|
|
1400
|
-
}
|
|
1401
|
-
if (error.name !== "AbortError") {
|
|
1402
|
-
|
|
1181
|
+
} catch (error) {
|
|
1182
|
+
if (error instanceof Error && error.name !== "AbortError") {
|
|
1183
|
+
stream.emit("error", error);
|
|
1403
1184
|
}
|
|
1404
|
-
}
|
|
1405
|
-
|
|
1406
|
-
|
|
1407
|
-
|
|
1185
|
+
}
|
|
1186
|
+
}).catch((error) => {
|
|
1187
|
+
if (error.name !== "AbortError") {
|
|
1188
|
+
stream.emit("error", error);
|
|
1189
|
+
}
|
|
1408
1190
|
});
|
|
1191
|
+
return stream;
|
|
1409
1192
|
}
|
|
1410
1193
|
|
|
1411
1194
|
const basicAuthHeader = { Authorization: "Basic YmFnZWxfdXNlcm5hbWU6Tm90U2VjdXJlQGJhZ2Vs" };
|