@bagelink/sdk 1.7.101 → 1.8.3

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 CHANGED
@@ -6,6 +6,112 @@ function _interopDefaultCompat (e) { return e && typeof e === 'object' && 'defau
6
6
 
7
7
  const axios__default = /*#__PURE__*/_interopDefaultCompat(axios$1);
8
8
 
9
+ function isSSEStream(operation) {
10
+ const responses = operation.responses || {};
11
+ for (const [statusCode, response] of Object.entries(responses)) {
12
+ if (!statusCode.startsWith("2")) continue;
13
+ if ("$ref" in response) continue;
14
+ const content = response.content || {};
15
+ const contentTypes = Object.keys(content);
16
+ if (contentTypes.length > 0) {
17
+ if ("text/event-stream" in content) {
18
+ return true;
19
+ }
20
+ }
21
+ }
22
+ const hasDefinedContentTypes = Object.entries(responses).some(([statusCode, response]) => {
23
+ if (!statusCode.startsWith("2")) return false;
24
+ if ("$ref" in response) return false;
25
+ const content = response.content || {};
26
+ return Object.keys(content).length > 0;
27
+ });
28
+ if (hasDefinedContentTypes) {
29
+ return false;
30
+ }
31
+ const description = operation.description?.toLowerCase() || "";
32
+ const summary = operation.summary?.toLowerCase() || "";
33
+ const hasExplicitSSEMention = /\bsse\b/.test(description) || /server-sent events/i.test(description) || /text\/event-stream/i.test(description) || /\bsse\b/.test(summary);
34
+ return hasExplicitSSEMention;
35
+ }
36
+ function extractSSEEventTypes(operation) {
37
+ const description = operation.description || "";
38
+ const types = /* @__PURE__ */ new Set();
39
+ const markdownMatches = description.matchAll(/^\d+\.\s+\*\*([a-z_]+)\*\*/gm);
40
+ for (const match of markdownMatches) {
41
+ types.add(match[1]);
42
+ }
43
+ const typeMatches = description.matchAll(/type:\s*"([^"]+)"/g);
44
+ for (const match of typeMatches) {
45
+ types.add(match[1]);
46
+ }
47
+ const responses = operation.responses || {};
48
+ for (const response of Object.values(responses)) {
49
+ if ("content" in response) {
50
+ const content = response.content || {};
51
+ const eventStream = content["text/event-stream"];
52
+ if (eventStream?.example) {
53
+ const exampleMatches = eventStream.example.matchAll(/^event:\s*([a-z_]+)/gm);
54
+ for (const match of exampleMatches) {
55
+ types.add(match[1]);
56
+ }
57
+ }
58
+ }
59
+ }
60
+ return types.size > 0 ? Array.from(types).sort() : void 0;
61
+ }
62
+ function extractSSEEventInfo(operation) {
63
+ const description = operation.description || "";
64
+ const eventInfos = [];
65
+ const eventSections = description.split(/(?=^\d+\.\s+\*\*)/m);
66
+ for (const section of eventSections) {
67
+ const eventMatch = section.match(/^\d+\.\s+\*\*([a-z_]+)\*\*:\s*([^\n]+)/m);
68
+ if (!eventMatch) continue;
69
+ const [, eventName, eventDescription] = eventMatch;
70
+ const fields = [];
71
+ const fieldMatches = section.matchAll(/^\s+[-*]\s+`([^`]+)`:\s*([^\n]+)/gm);
72
+ for (const fieldMatch of fieldMatches) {
73
+ const [, fieldName, fieldDescription] = fieldMatch;
74
+ fields.push({
75
+ name: fieldName,
76
+ description: fieldDescription.trim()
77
+ });
78
+ }
79
+ eventInfos.push({
80
+ name: eventName,
81
+ description: eventDescription,
82
+ fields: fields.length > 0 ? fields : void 0
83
+ });
84
+ }
85
+ if (eventInfos.length === 0) {
86
+ const responses = operation.responses || {};
87
+ for (const response of Object.values(responses)) {
88
+ if ("content" in response) {
89
+ const content = response.content || {};
90
+ const eventStream = content["text/event-stream"];
91
+ if (eventStream?.example) {
92
+ const exampleMatches = eventStream.example.matchAll(/data:\s*(\{[^}]+\})/g);
93
+ const seenEvents = /* @__PURE__ */ new Set();
94
+ for (const match of exampleMatches) {
95
+ try {
96
+ const data = JSON.parse(match[1]);
97
+ if (data.type && !seenEvents.has(data.type)) {
98
+ seenEvents.add(data.type);
99
+ const fields = Object.keys(data).filter((key) => key !== "type" && key !== "sequence").map((key) => ({ name: key }));
100
+ eventInfos.push({
101
+ name: data.type,
102
+ fields: fields.length > 0 ? fields : void 0
103
+ });
104
+ }
105
+ } catch {
106
+ }
107
+ }
108
+ }
109
+ }
110
+ }
111
+ }
112
+ return eventInfos.length > 0 ? eventInfos : void 0;
113
+ }
114
+
9
115
  function getPath(pathsObject, path) {
10
116
  return pathsObject ? pathsObject[path] : void 0;
11
117
  }
@@ -284,6 +390,8 @@ const primitiveTypes = [
284
390
  ];
285
391
  const functionsInventory = {};
286
392
  const pathOperations = [];
393
+ const streamEventTypes = {};
394
+ const streamEventInfo = {};
287
395
  function collectTypeForImportStatement(typeName) {
288
396
  typeName = typeName.trim().replace("[]", "");
289
397
  if (typeName.includes("|")) {
@@ -447,6 +555,77 @@ function combineAllParams(parameters, requestBodyParam) {
447
555
  }).join(", ");
448
556
  return `{ ${destructuredNames} }: { ${typeDefinition} } = {}`;
449
557
  }
558
+ function generateStreamTypeName(path) {
559
+ return `${toPascalCase(
560
+ path.split("/").filter((p) => p && !/\{|\}/.test(p)).join("_")
561
+ )}StreamEvents`;
562
+ }
563
+ function generateStreamFunction(method, path, formattedPath, allParams, requestBodyPayload, eventTypes) {
564
+ if (allParams === "undefined") {
565
+ allParams = "";
566
+ }
567
+ const bodyVar = requestBodyPayload || "{}";
568
+ const baseUrlRef = 'axios.defaults.baseURL || ""';
569
+ const streamTypeName = generateStreamTypeName(path);
570
+ if (eventTypes?.length) {
571
+ streamEventTypes[streamTypeName] = eventTypes;
572
+ }
573
+ const eventTypesComment = eventTypes?.length ? `
574
+ * Event types: ${eventTypes.map((t) => `"${t}"`).join(", ")}` : "";
575
+ const eventTypesExample = eventTypes?.length ? eventTypes.map((t) => `
576
+ * .on('${t}', (data) => console.log(data))`).join("") : "\n * .on('message', (data) => console.log(data))";
577
+ const typeAnnotation = eventTypes?.length ? `StreamController<${streamTypeName}>` : "StreamController";
578
+ const pathForUrl = formattedPath.startsWith("`") ? formattedPath.slice(1, -1) : formattedPath.slice(1, -1);
579
+ if (method === "post") {
580
+ return `{
581
+ /**
582
+ * Stream SSE events from this endpoint (returns StreamController)${eventTypesComment}
583
+ *
584
+ * @example
585
+ * const stream = api.endpoint.stream(params)${eventTypesExample}
586
+ * .on('error', (err) => console.error(err))
587
+ * .on('complete', () => console.log('Done!'))
588
+ *
589
+ * // Close stream when needed
590
+ * stream.close()
591
+ */
592
+ stream: (${allParams}, options?: SSEStreamOptions): ${typeAnnotation} => {
593
+ const url = \`\${${baseUrlRef}}${pathForUrl}\`
594
+ return createSSEStreamPost<${streamTypeName}>(url, ${bodyVar}, options)
595
+ },
596
+ /**
597
+ * Regular POST request (non-streaming)
598
+ */
599
+ post: async (${allParams}): Promise<AxiosResponse<any>> => {
600
+ return axios.post(${formattedPath}, ${bodyVar})
601
+ }
602
+ }`;
603
+ } else {
604
+ return `{
605
+ /**
606
+ * Stream SSE events from this endpoint (returns StreamController)${eventTypesComment}
607
+ *
608
+ * @example
609
+ * const stream = api.endpoint.stream(params)${eventTypesExample}
610
+ * .on('error', (err) => console.error(err))
611
+ * .on('complete', () => console.log('Done!'))
612
+ *
613
+ * // Close stream when needed
614
+ * stream.close()
615
+ */
616
+ stream: (${allParams}, options?: SSEStreamOptions): ${typeAnnotation} => {
617
+ const url = \`\${${baseUrlRef}}${pathForUrl}\`
618
+ return createSSEStream<${streamTypeName}>(url, options)
619
+ },
620
+ /**
621
+ * Regular GET request (non-streaming)
622
+ */
623
+ get: async (${allParams}): Promise<AxiosResponse<any>> => {
624
+ return axios.get(${formattedPath})
625
+ }
626
+ }`;
627
+ }
628
+ }
450
629
  function generateAxiosFunction(method, formattedPath, allParams, responseTypeStr, parameters, requestBodyPayload) {
451
630
  if (allParams === "undefined") {
452
631
  allParams = "";
@@ -504,6 +683,7 @@ function generateFunctionForOperation(method, path, operation) {
504
683
  if (!operation) {
505
684
  return "";
506
685
  }
686
+ const isStream = isSSEStream(operation);
507
687
  const methodLower = method.toLowerCase();
508
688
  if (["get", "delete"].includes(methodLower) && operation.requestBody) {
509
689
  const requestBodyDeref = dereference(operation.requestBody);
@@ -532,6 +712,22 @@ function generateFunctionForOperation(method, path, operation) {
532
712
  const responseType = generateResponseType(operation.responses);
533
713
  const responseTypeStr = responseType ? `: Promise<AxiosResponse<${responseType}>>` : "";
534
714
  const functionComment = buildJSDocComment(operation, method, path);
715
+ if (isStream) {
716
+ const eventTypes = extractSSEEventTypes(operation);
717
+ const eventInfo = extractSSEEventInfo(operation);
718
+ const streamTypeName = generateStreamTypeName(path);
719
+ if (eventInfo?.length) {
720
+ streamEventInfo[streamTypeName] = eventInfo;
721
+ }
722
+ return functionComment + generateStreamFunction(
723
+ method,
724
+ path,
725
+ formatPathWithParams(path),
726
+ allParams,
727
+ requestBodyPayload,
728
+ eventTypes
729
+ );
730
+ }
535
731
  return functionComment + generateAxiosFunction(
536
732
  method,
537
733
  formatPathWithParams(path),
@@ -627,10 +823,79 @@ export const ${parent} = ${JSON.stringify(object, void 0, 2)};
627
823
  });
628
824
  return fileTemplate(tsString, allTypes, baseUrl);
629
825
  }
826
+ function generateStreamEventTypeDefinitions() {
827
+ if (Object.keys(streamEventTypes).length === 0) {
828
+ return "";
829
+ }
830
+ let typeDefs = "\n// ============================================================================\n";
831
+ typeDefs += "// Stream Event Type Definitions (Fully Typed!)\n";
832
+ typeDefs += "// ============================================================================\n\n";
833
+ for (const [typeName, events] of Object.entries(streamEventTypes)) {
834
+ const eventInfo = streamEventInfo[typeName];
835
+ typeDefs += `/**
836
+ * Event types for ${typeName.replace("StreamEvents", "")} stream
837
+ `;
838
+ typeDefs += ` * Events: ${events.map((e) => `"${e}"`).join(", ")}
839
+ `;
840
+ if (eventInfo?.length) {
841
+ typeDefs += ` *
842
+ `;
843
+ for (const info of eventInfo) {
844
+ typeDefs += ` * - **${info.name}**: ${info.description || "Event data"}
845
+ `;
846
+ }
847
+ }
848
+ typeDefs += ` */
849
+ `;
850
+ typeDefs += `export interface ${typeName} {
851
+ `;
852
+ if (eventInfo?.length) {
853
+ for (const info of eventInfo) {
854
+ typeDefs += ` /**
855
+ * ${info.description || info.name}
856
+ `;
857
+ if (info.fields?.length) {
858
+ info.fields.forEach((field) => {
859
+ typeDefs += ` * - \`${field.name}\`: ${field.description || "Field data"}
860
+ `;
861
+ });
862
+ }
863
+ typeDefs += ` */
864
+ `;
865
+ if (info.fields?.length) {
866
+ typeDefs += ` ${info.name}: {
867
+ `;
868
+ for (const field of info.fields) {
869
+ typeDefs += ` /** ${field.description || field.name} */
870
+ `;
871
+ typeDefs += ` ${field.name}: any
872
+ `;
873
+ }
874
+ typeDefs += ` }
875
+ `;
876
+ } else {
877
+ typeDefs += ` ${info.name}: any
878
+ `;
879
+ }
880
+ }
881
+ } else {
882
+ for (const event of events) {
883
+ typeDefs += ` /** ${event} event data */
884
+ `;
885
+ typeDefs += ` ${event}: any
886
+ `;
887
+ }
888
+ }
889
+ typeDefs += "}\n\n";
890
+ }
891
+ return typeDefs;
892
+ }
630
893
  function fileTemplate(tsString, typeForImport, baseURL) {
894
+ const streamTypeDefs = generateStreamEventTypeDefinitions();
631
895
  const templateCode = `import ax from 'axios';
632
896
  import type { AxiosResponse } from 'axios';
633
897
  import type { ${typeForImport.join(", ")} } from './types.d';
898
+ import { createSSEStream, createSSEStreamPost, StreamController, type SSEStreamOptions, type SSEEvent } from './streamClient';
634
899
 
635
900
  /**
636
901
  * Options for file upload operations
@@ -644,6 +909,24 @@ export interface UploadOptions {
644
909
  tags?: string[]
645
910
  }
646
911
 
912
+ /**
913
+ * Export SSE stream utilities for direct use
914
+ *
915
+ * @example Chainable event handlers
916
+ * const stream = createSSEStream(url)
917
+ * .on('token', (data) => console.log(data))
918
+ * .on('done', () => console.log('Complete!'))
919
+ *
920
+ * @example Async iteration
921
+ * for await (const event of createSSEStream(url)) {
922
+ * console.log(event.type, event.data)
923
+ * }
924
+ *
925
+ * @example Promise-based
926
+ * const result = await createSSEStream(url).toPromise()
927
+ */
928
+ export { createSSEStream, createSSEStreamPost, StreamController, type SSEStreamOptions, type SSEEvent } from './streamClient';
929
+ ${streamTypeDefs}
647
930
  /**
648
931
  * Configured axios instance for API requests
649
932
  * @example
@@ -697,6 +980,430 @@ function generateTypes(schemas) {
697
980
  }).join("\n");
698
981
  }
699
982
 
983
+ class StreamController {
984
+ constructor(streamFn) {
985
+ this.streamFn = streamFn;
986
+ this.abortController = new AbortController();
987
+ this.start();
988
+ }
989
+ handlers = /* @__PURE__ */ new Map();
990
+ errorHandlers = /* @__PURE__ */ new Set();
991
+ completeHandlers = /* @__PURE__ */ new Set();
992
+ abortController;
993
+ _closed = false;
994
+ _promise = null;
995
+ _resolvePromise = null;
996
+ _rejectPromise = null;
997
+ start() {
998
+ const cleanup = this.streamFn(
999
+ (event) => {
1000
+ this.emit(event.type, event.data);
1001
+ },
1002
+ (error) => {
1003
+ this.emitError(error);
1004
+ },
1005
+ () => {
1006
+ this.emitComplete();
1007
+ }
1008
+ );
1009
+ this.abortController.signal.addEventListener("abort", () => {
1010
+ cleanup();
1011
+ this._closed = true;
1012
+ });
1013
+ }
1014
+ /**
1015
+ * Register an event handler (fully typed!)
1016
+ * @param event - Event type to listen for
1017
+ * @param handler - Handler function (data type inferred from event)
1018
+ * @returns this (for chaining)
1019
+ */
1020
+ on(event, handler) {
1021
+ if (event === "error") {
1022
+ this.errorHandlers.add(handler);
1023
+ } else if (event === "complete") {
1024
+ this.completeHandlers.add(handler);
1025
+ } else {
1026
+ if (!this.handlers.has(event)) {
1027
+ this.handlers.set(event, /* @__PURE__ */ new Set());
1028
+ }
1029
+ this.handlers.get(event).add(handler);
1030
+ }
1031
+ return this;
1032
+ }
1033
+ /**
1034
+ * Register a one-time event handler (fully typed!)
1035
+ * @param event - Event type to listen for
1036
+ * @param handler - Handler function (called once then removed, data type inferred from event)
1037
+ * @returns this (for chaining)
1038
+ */
1039
+ once(event, handler) {
1040
+ const wrappedHandler = (data) => {
1041
+ handler(data);
1042
+ this.off(event, wrappedHandler);
1043
+ };
1044
+ return this.on(event, wrappedHandler);
1045
+ }
1046
+ /**
1047
+ * Remove an event handler (fully typed!)
1048
+ * @param event - Event type
1049
+ * @param handler - Handler to remove
1050
+ * @returns this (for chaining)
1051
+ */
1052
+ off(event, handler) {
1053
+ if (event === "error") {
1054
+ this.errorHandlers.delete(handler);
1055
+ } else if (event === "complete") {
1056
+ this.completeHandlers.delete(handler);
1057
+ } else {
1058
+ this.handlers.get(event)?.delete(handler);
1059
+ }
1060
+ return this;
1061
+ }
1062
+ /**
1063
+ * Remove all handlers for an event (or all events if no event specified)
1064
+ */
1065
+ removeAllListeners(event) {
1066
+ if (event === void 0) {
1067
+ this.handlers.clear();
1068
+ this.errorHandlers.clear();
1069
+ this.completeHandlers.clear();
1070
+ } else if (event === "error") {
1071
+ this.errorHandlers.clear();
1072
+ } else if (event === "complete") {
1073
+ this.completeHandlers.clear();
1074
+ } else {
1075
+ this.handlers.delete(event);
1076
+ }
1077
+ return this;
1078
+ }
1079
+ emit(event, data) {
1080
+ const handlers = this.handlers.get(event);
1081
+ if (handlers) {
1082
+ handlers.forEach((handler) => {
1083
+ try {
1084
+ handler(data);
1085
+ } catch (error) {
1086
+ console.error(`Error in handler for event "${event}":`, error);
1087
+ }
1088
+ });
1089
+ }
1090
+ if (event === "done" && this._resolvePromise) {
1091
+ this._resolvePromise(data);
1092
+ }
1093
+ }
1094
+ emitError(error) {
1095
+ this.errorHandlers.forEach((handler) => {
1096
+ try {
1097
+ handler(error);
1098
+ } catch (err) {
1099
+ console.error("Error in error handler:", err);
1100
+ }
1101
+ });
1102
+ if (this._rejectPromise) {
1103
+ this._rejectPromise(error);
1104
+ }
1105
+ }
1106
+ emitComplete() {
1107
+ this.completeHandlers.forEach((handler) => {
1108
+ try {
1109
+ handler();
1110
+ } catch (error) {
1111
+ console.error("Error in complete handler:", error);
1112
+ }
1113
+ });
1114
+ }
1115
+ /**
1116
+ * Close the stream
1117
+ */
1118
+ close() {
1119
+ if (!this._closed) {
1120
+ this.abortController.abort();
1121
+ this._closed = true;
1122
+ }
1123
+ }
1124
+ /**
1125
+ * Check if stream is closed
1126
+ */
1127
+ get closed() {
1128
+ return this._closed;
1129
+ }
1130
+ /**
1131
+ * Convert stream to a Promise that resolves when 'done' event fires
1132
+ * @returns Promise that resolves with the 'done' event data
1133
+ */
1134
+ toPromise() {
1135
+ if (!this._promise) {
1136
+ this._promise = new Promise((resolve, reject) => {
1137
+ this._resolvePromise = resolve;
1138
+ this._rejectPromise = reject;
1139
+ });
1140
+ }
1141
+ return this._promise;
1142
+ }
1143
+ /**
1144
+ * Make the stream async iterable
1145
+ * Usage: for await (const event of stream) { ... }
1146
+ */
1147
+ async *[Symbol.asyncIterator]() {
1148
+ const events = [];
1149
+ let resolveNext = null;
1150
+ let done = false;
1151
+ const eventHandler = (type) => (data) => {
1152
+ const event = { type, data };
1153
+ if (resolveNext) {
1154
+ resolveNext(event);
1155
+ resolveNext = null;
1156
+ } else {
1157
+ events.push(event);
1158
+ }
1159
+ };
1160
+ const originalEmit = this.emit.bind(this);
1161
+ const capturedEvents = [];
1162
+ this.emit = (event, data) => {
1163
+ if (!capturedEvents.includes(event)) {
1164
+ capturedEvents.push(event);
1165
+ this.on(event, eventHandler(event));
1166
+ }
1167
+ originalEmit(event, data);
1168
+ };
1169
+ this.on("complete", () => {
1170
+ done = true;
1171
+ if (resolveNext) {
1172
+ resolveNext(null);
1173
+ resolveNext = null;
1174
+ }
1175
+ });
1176
+ try {
1177
+ while (!done) {
1178
+ if (events.length > 0) {
1179
+ const event = events.shift();
1180
+ if (event) yield event;
1181
+ } else {
1182
+ const event = await new Promise((resolve) => {
1183
+ resolveNext = resolve;
1184
+ });
1185
+ if (event === null) break;
1186
+ yield event;
1187
+ }
1188
+ }
1189
+ } finally {
1190
+ this.close();
1191
+ }
1192
+ }
1193
+ /**
1194
+ * Collect all events into an array until stream completes
1195
+ * @returns Promise<SSEEvent[]>
1196
+ */
1197
+ async toArray() {
1198
+ const events = [];
1199
+ for await (const event of this) {
1200
+ events.push(event);
1201
+ }
1202
+ return events;
1203
+ }
1204
+ /**
1205
+ * Pipe stream events through a transform function
1206
+ */
1207
+ map(transform) {
1208
+ const mappedController = new StreamController(
1209
+ (onEvent, onError, onComplete) => {
1210
+ this.on("error", onError);
1211
+ this.on("complete", onComplete);
1212
+ this.handlers.forEach((_, eventType) => {
1213
+ this.on(eventType, (data) => {
1214
+ try {
1215
+ const transformed = transform({ type: eventType, data });
1216
+ onEvent({ type: eventType, data: transformed, raw: void 0 });
1217
+ } catch (error) {
1218
+ onError(error);
1219
+ }
1220
+ });
1221
+ });
1222
+ return () => {
1223
+ this.close();
1224
+ };
1225
+ }
1226
+ );
1227
+ return mappedController;
1228
+ }
1229
+ /**
1230
+ * Filter events based on a predicate
1231
+ */
1232
+ filter(predicate) {
1233
+ const filteredController = new StreamController(
1234
+ (onEvent, onError, onComplete) => {
1235
+ this.on("error", onError);
1236
+ this.on("complete", onComplete);
1237
+ this.handlers.forEach((_, eventType) => {
1238
+ this.on(eventType, (data) => {
1239
+ const event = { type: eventType, data };
1240
+ if (predicate(event)) {
1241
+ onEvent(event);
1242
+ }
1243
+ });
1244
+ });
1245
+ return () => {
1246
+ this.close();
1247
+ };
1248
+ }
1249
+ );
1250
+ return filteredController;
1251
+ }
1252
+ }
1253
+
1254
+ function createSSEStream(url, options = {}) {
1255
+ const { headers = {}, withCredentials = true } = options;
1256
+ return new StreamController((onEvent, onError, onComplete) => {
1257
+ const controller = new AbortController();
1258
+ const { signal } = controller;
1259
+ fetch(url, {
1260
+ method: "GET",
1261
+ headers: {
1262
+ Accept: "text/event-stream",
1263
+ ...headers
1264
+ },
1265
+ credentials: withCredentials ? "include" : "same-origin",
1266
+ signal
1267
+ }).then(async (response) => {
1268
+ if (!response.ok) {
1269
+ throw new Error(`HTTP ${response.status}: ${response.statusText}`);
1270
+ }
1271
+ if (!response.body) {
1272
+ throw new Error("Response body is null");
1273
+ }
1274
+ const reader = response.body.getReader();
1275
+ const decoder = new TextDecoder();
1276
+ let buffer = "";
1277
+ try {
1278
+ while (true) {
1279
+ const { done, value } = await reader.read();
1280
+ if (done) {
1281
+ onComplete();
1282
+ break;
1283
+ }
1284
+ buffer += decoder.decode(value, { stream: true });
1285
+ const lines = buffer.split("\n");
1286
+ buffer = lines.pop() || "";
1287
+ let eventType = "";
1288
+ let eventData = "";
1289
+ for (const line of lines) {
1290
+ if (line.startsWith("event:")) {
1291
+ eventType = line.slice(6).trim();
1292
+ } else if (line.startsWith("data:")) {
1293
+ eventData = line.slice(5).trim();
1294
+ } else if (line === "" && eventData) {
1295
+ try {
1296
+ const parsedData = JSON.parse(eventData);
1297
+ onEvent({
1298
+ type: eventType || "message",
1299
+ data: parsedData,
1300
+ raw: eventData
1301
+ });
1302
+ } catch {
1303
+ onEvent({
1304
+ type: eventType || "message",
1305
+ data: eventData,
1306
+ raw: eventData
1307
+ });
1308
+ }
1309
+ eventType = "";
1310
+ eventData = "";
1311
+ }
1312
+ }
1313
+ }
1314
+ } catch (error) {
1315
+ if (error instanceof Error && error.name !== "AbortError") {
1316
+ onError(error);
1317
+ }
1318
+ }
1319
+ }).catch((error) => {
1320
+ if (error.name !== "AbortError") {
1321
+ onError(error);
1322
+ }
1323
+ });
1324
+ return () => {
1325
+ controller.abort();
1326
+ };
1327
+ });
1328
+ }
1329
+ function createSSEStreamPost(url, body, options = {}) {
1330
+ const { headers = {}, withCredentials = true } = options;
1331
+ return new StreamController((onEvent, onError, onComplete) => {
1332
+ const controller = new AbortController();
1333
+ const { signal } = controller;
1334
+ fetch(url, {
1335
+ method: "POST",
1336
+ headers: {
1337
+ "Accept": "text/event-stream",
1338
+ "Content-Type": "application/json",
1339
+ ...headers
1340
+ },
1341
+ credentials: withCredentials ? "include" : "same-origin",
1342
+ body: JSON.stringify(body),
1343
+ signal
1344
+ }).then(async (response) => {
1345
+ if (!response.ok) {
1346
+ throw new Error(`HTTP ${response.status}: ${response.statusText}`);
1347
+ }
1348
+ if (!response.body) {
1349
+ throw new Error("Response body is null");
1350
+ }
1351
+ const reader = response.body.getReader();
1352
+ const decoder = new TextDecoder();
1353
+ let buffer = "";
1354
+ try {
1355
+ while (true) {
1356
+ const { done, value } = await reader.read();
1357
+ if (done) {
1358
+ onComplete();
1359
+ break;
1360
+ }
1361
+ buffer += decoder.decode(value, { stream: true });
1362
+ const lines = buffer.split("\n");
1363
+ buffer = lines.pop() || "";
1364
+ let eventType = "";
1365
+ let eventData = "";
1366
+ for (const line of lines) {
1367
+ if (line.startsWith("event:")) {
1368
+ eventType = line.slice(6).trim();
1369
+ } else if (line.startsWith("data:")) {
1370
+ eventData = line.slice(5).trim();
1371
+ } else if (line === "" && eventData) {
1372
+ try {
1373
+ const parsedData = JSON.parse(eventData);
1374
+ onEvent({
1375
+ type: eventType || "message",
1376
+ data: parsedData,
1377
+ raw: eventData
1378
+ });
1379
+ } catch {
1380
+ onEvent({
1381
+ type: eventType || "message",
1382
+ data: eventData,
1383
+ raw: eventData
1384
+ });
1385
+ }
1386
+ eventType = "";
1387
+ eventData = "";
1388
+ }
1389
+ }
1390
+ }
1391
+ } catch (error) {
1392
+ if (error instanceof Error && error.name !== "AbortError") {
1393
+ onError(error);
1394
+ }
1395
+ }
1396
+ }).catch((error) => {
1397
+ if (error.name !== "AbortError") {
1398
+ onError(error);
1399
+ }
1400
+ });
1401
+ return () => {
1402
+ controller.abort();
1403
+ };
1404
+ });
1405
+ }
1406
+
700
1407
  const basicAuthHeader = { Authorization: "Basic YmFnZWxfdXNlcm5hbWU6Tm90U2VjdXJlQGJhZ2Vs" };
701
1408
  const index = async (openApiUrl, baseUrl) => {
702
1409
  try {
@@ -1007,9 +1714,15 @@ class Bagel {
1007
1714
  }
1008
1715
 
1009
1716
  exports.Bagel = Bagel;
1717
+ exports.StreamController = StreamController;
1718
+ exports.createSSEStream = createSSEStream;
1719
+ exports.createSSEStreamPost = createSSEStreamPost;
1010
1720
  exports.dereference = dereference;
1721
+ exports.extractSSEEventInfo = extractSSEEventInfo;
1722
+ exports.extractSSEEventTypes = extractSSEEventTypes;
1011
1723
  exports.formatAPIErrorMessage = formatAPIErrorMessage;
1012
1724
  exports.getPath = getPath;
1013
1725
  exports.isReferenceObject = isReferenceObject;
1726
+ exports.isSSEStream = isSSEStream;
1014
1727
  exports.isSchemaObject = isSchemaObject;
1015
1728
  exports.openAPI = index;