@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/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "@bagelink/sdk",
3
3
  "type": "module",
4
- "version": "1.7.101",
4
+ "version": "1.8.3",
5
5
  "description": "Bagel core sdk packages",
6
6
  "author": {
7
7
  "name": "Bagel Studio",
package/src/index.ts CHANGED
@@ -2,6 +2,7 @@ import ax from 'axios'
2
2
 
3
3
  export * from './openAPITools'
4
4
  export { default as openAPI } from './openAPITools'
5
+ export { createSSEStream, createSSEStreamPost, type SSEEvent, type SSEStreamOptions, StreamController, type StreamEventMap } from './openAPITools/streamClient'
5
6
 
6
7
  export type Tables = ''
7
8
  export type TableToTypeMapping = Record<Tables, any>
@@ -0,0 +1,372 @@
1
+ /* eslint-disable ts/no-non-null-assertion */
2
+ /* eslint-disable ts/no-unnecessary-condition */
3
+ /**
4
+ * StreamController - Elegant event-based SSE stream management
5
+ * Provides a beautiful, type-safe API for consuming Server-Sent Events
6
+ */
7
+
8
+ export interface SSEEvent<T = any> {
9
+ /** Event type (e.g., "token", "tool_call", "done") */
10
+ type: string
11
+ /** Event data payload */
12
+ data: T
13
+ /** Raw event string */
14
+ raw?: string
15
+ }
16
+
17
+ type EventHandler<T = any> = (data: T) => void
18
+ type ErrorHandler = (error: Error) => void
19
+ type VoidHandler = () => void
20
+
21
+ /**
22
+ * Type-safe event map for stream events
23
+ * Maps event names to their data types
24
+ */
25
+ export type StreamEventMap = Record<string, any>
26
+
27
+ /**
28
+ * StreamController - Chainable event emitter for SSE streams with full type safety
29
+ * @template TEventMap - Map of event names to their data types
30
+ *
31
+ * @example
32
+ * type ChatEvents = {
33
+ * token: { content: string }
34
+ * tool_call: { name: string, args: any }
35
+ * done: { message: string }
36
+ * }
37
+ *
38
+ * const stream: StreamController<ChatEvents> = ...
39
+ * stream.on('token', (data) => {
40
+ * // `data` is typed as { content: string }
41
+ * console.log(data.content)
42
+ * })
43
+ */
44
+ export class StreamController<TEventMap extends StreamEventMap = StreamEventMap> {
45
+ private handlers: Map<string, Set<EventHandler>> = new Map()
46
+ private errorHandlers: Set<ErrorHandler> = new Set()
47
+ private completeHandlers: Set<VoidHandler> = new Set()
48
+ private abortController: AbortController
49
+ private _closed = false
50
+ private _promise: Promise<any> | null = null
51
+ private _resolvePromise: ((value: any) => void) | null = null
52
+ private _rejectPromise: ((error: Error) => void) | null = null
53
+
54
+ constructor(
55
+ private streamFn: (
56
+ onEvent: (event: SSEEvent) => void,
57
+ onError: (error: Error) => void,
58
+ onComplete: () => void
59
+ ) => () => void
60
+ ) {
61
+ this.abortController = new AbortController()
62
+ this.start()
63
+ }
64
+
65
+ private start() {
66
+ const cleanup = this.streamFn(
67
+ (event) => { this.emit(event.type, event.data) },
68
+ (error) => { this.emitError(error) },
69
+ () => { this.emitComplete() }
70
+ )
71
+
72
+ // Store cleanup function
73
+ this.abortController.signal.addEventListener('abort', () => {
74
+ cleanup()
75
+ this._closed = true
76
+ })
77
+ }
78
+
79
+ /**
80
+ * Register an event handler (fully typed!)
81
+ * @param event - Event type to listen for
82
+ * @param handler - Handler function (data type inferred from event)
83
+ * @returns this (for chaining)
84
+ */
85
+ on<K extends keyof TEventMap | 'error' | 'complete'>(
86
+ event: K,
87
+ handler: K extends 'error'
88
+ ? ErrorHandler
89
+ : K extends 'complete'
90
+ ? VoidHandler
91
+ : K extends keyof TEventMap
92
+ ? (data: TEventMap[K]) => void
93
+ : EventHandler
94
+ ): this {
95
+ if (event === 'error') {
96
+ this.errorHandlers.add(handler as ErrorHandler)
97
+ } else if (event === 'complete') {
98
+ this.completeHandlers.add(handler as VoidHandler)
99
+ } else {
100
+ if (!this.handlers.has(event as string)) {
101
+ this.handlers.set(event as string, new Set())
102
+ }
103
+ this.handlers.get(event as string)!.add(handler as EventHandler)
104
+ }
105
+ return this
106
+ }
107
+
108
+ /**
109
+ * Register a one-time event handler (fully typed!)
110
+ * @param event - Event type to listen for
111
+ * @param handler - Handler function (called once then removed, data type inferred from event)
112
+ * @returns this (for chaining)
113
+ */
114
+ once<K extends keyof TEventMap | 'error' | 'complete'>(
115
+ event: K,
116
+ handler: K extends 'error'
117
+ ? ErrorHandler
118
+ : K extends 'complete'
119
+ ? VoidHandler
120
+ : K extends keyof TEventMap
121
+ ? (data: TEventMap[K]) => void
122
+ : EventHandler
123
+ ): this {
124
+ const wrappedHandler = (data: any) => {
125
+ (handler as any)(data)
126
+ this.off(event, wrappedHandler as any)
127
+ }
128
+ return this.on(event, wrappedHandler as any)
129
+ }
130
+
131
+ /**
132
+ * Remove an event handler (fully typed!)
133
+ * @param event - Event type
134
+ * @param handler - Handler to remove
135
+ * @returns this (for chaining)
136
+ */
137
+ off<K extends keyof TEventMap | 'error' | 'complete'>(
138
+ event: K,
139
+ handler: K extends 'error'
140
+ ? ErrorHandler
141
+ : K extends 'complete'
142
+ ? VoidHandler
143
+ : K extends keyof TEventMap
144
+ ? (data: TEventMap[K]) => void
145
+ : EventHandler
146
+ ): this {
147
+ if (event === 'error') {
148
+ this.errorHandlers.delete(handler as ErrorHandler)
149
+ } else if (event === 'complete') {
150
+ this.completeHandlers.delete(handler as VoidHandler)
151
+ } else {
152
+ this.handlers.get(event as string)?.delete(handler as EventHandler)
153
+ }
154
+ return this
155
+ }
156
+
157
+ /**
158
+ * Remove all handlers for an event (or all events if no event specified)
159
+ */
160
+ removeAllListeners(event?: keyof TEventMap | 'error' | 'complete'): this {
161
+ if (event === undefined) {
162
+ this.handlers.clear()
163
+ this.errorHandlers.clear()
164
+ this.completeHandlers.clear()
165
+ } else if (event === 'error') {
166
+ this.errorHandlers.clear()
167
+ } else if (event === 'complete') {
168
+ this.completeHandlers.clear()
169
+ } else {
170
+ this.handlers.delete(event as string)
171
+ }
172
+ return this
173
+ }
174
+
175
+ private emit(event: string, data: any) {
176
+ const handlers = this.handlers.get(event)
177
+ if (handlers) {
178
+ handlers.forEach((handler) => {
179
+ try {
180
+ handler(data)
181
+ } catch (error) {
182
+ console.error(`Error in handler for event "${event}":`, error)
183
+ }
184
+ })
185
+ }
186
+
187
+ // Resolve promise on 'done' event
188
+ if (event === 'done' && this._resolvePromise) {
189
+ this._resolvePromise(data)
190
+ }
191
+ }
192
+
193
+ private emitError(error: Error) {
194
+ this.errorHandlers.forEach((handler) => {
195
+ try {
196
+ handler(error)
197
+ } catch (err) {
198
+ console.error('Error in error handler:', err)
199
+ }
200
+ })
201
+
202
+ // Reject promise on error
203
+ if (this._rejectPromise) {
204
+ this._rejectPromise(error)
205
+ }
206
+ }
207
+
208
+ private emitComplete() {
209
+ this.completeHandlers.forEach((handler) => {
210
+ try {
211
+ handler()
212
+ } catch (error) {
213
+ console.error('Error in complete handler:', error)
214
+ }
215
+ })
216
+ }
217
+
218
+ /**
219
+ * Close the stream
220
+ */
221
+ close(): void {
222
+ if (!this._closed) {
223
+ this.abortController.abort()
224
+ this._closed = true
225
+ }
226
+ }
227
+
228
+ /**
229
+ * Check if stream is closed
230
+ */
231
+ get closed(): boolean {
232
+ return this._closed
233
+ }
234
+
235
+ /**
236
+ * Convert stream to a Promise that resolves when 'done' event fires
237
+ * @returns Promise that resolves with the 'done' event data
238
+ */
239
+ toPromise<T = any>(): Promise<T> {
240
+ if (!this._promise) {
241
+ this._promise = new Promise<T>((resolve, reject) => {
242
+ this._resolvePromise = resolve as any
243
+ this._rejectPromise = reject
244
+ })
245
+ }
246
+ return this._promise
247
+ }
248
+
249
+ /**
250
+ * Make the stream async iterable
251
+ * Usage: for await (const event of stream) { ... }
252
+ */
253
+ async* [Symbol.asyncIterator](): AsyncIterableIterator<SSEEvent> {
254
+ const events: SSEEvent[] = []
255
+ let resolveNext: ((event: SSEEvent | null) => void) | null = null
256
+ let done = false
257
+
258
+ // Capture all event types
259
+ const eventHandler = (type: string) => (data: any) => {
260
+ const event: SSEEvent = { type, data }
261
+ if (resolveNext) {
262
+ resolveNext(event)
263
+ resolveNext = null
264
+ } else {
265
+ events.push(event)
266
+ }
267
+ }
268
+
269
+ // Listen to all events by capturing them
270
+ const originalEmit = this.emit.bind(this)
271
+ const capturedEvents: string[] = []
272
+ this.emit = (event: string, data: any) => {
273
+ if (!capturedEvents.includes(event)) {
274
+ capturedEvents.push(event)
275
+
276
+ this.on(event as any, eventHandler(event))
277
+ }
278
+ originalEmit(event, data)
279
+ }
280
+
281
+ this.on('complete', () => {
282
+ done = true
283
+ if (resolveNext) {
284
+ resolveNext(null)
285
+ resolveNext = null
286
+ }
287
+ })
288
+
289
+ try {
290
+ // eslint-disable-next-line no-unmodified-loop-condition
291
+ while (!done) {
292
+ if (events.length > 0) {
293
+ const event = events.shift()
294
+ if (event) yield event
295
+ } else {
296
+ // eslint-disable-next-line no-await-in-loop
297
+ const event = await new Promise<SSEEvent | null>((resolve) => {
298
+ resolveNext = resolve
299
+ })
300
+ if (event === null) break
301
+ yield event
302
+ }
303
+ }
304
+ } finally {
305
+ this.close()
306
+ }
307
+ }
308
+
309
+ /**
310
+ * Collect all events into an array until stream completes
311
+ * @returns Promise<SSEEvent[]>
312
+ */
313
+ async toArray(): Promise<SSEEvent[]> {
314
+ const events: SSEEvent[] = []
315
+ for await (const event of this) {
316
+ events.push(event)
317
+ }
318
+ return events
319
+ }
320
+
321
+ /**
322
+ * Pipe stream events through a transform function
323
+ */
324
+ map<R>(transform: (event: SSEEvent) => R): StreamController<TEventMap> {
325
+ const mappedController = new StreamController<TEventMap>(
326
+ (onEvent, onError, onComplete) => {
327
+ this.on('error' as any, onError)
328
+ this.on('complete' as any, onComplete)
329
+
330
+ // Forward all events through transform
331
+ this.handlers.forEach((_, eventType) => {
332
+ this.on(eventType as any, (data: any) => {
333
+ try {
334
+ const transformed = transform({ type: eventType, data })
335
+ onEvent({ type: eventType, data: transformed, raw: undefined })
336
+ } catch (error) {
337
+ onError(error as Error)
338
+ }
339
+ })
340
+ })
341
+
342
+ return () => { this.close() }
343
+ }
344
+ )
345
+ return mappedController
346
+ }
347
+
348
+ /**
349
+ * Filter events based on a predicate
350
+ */
351
+ filter(predicate: (event: SSEEvent) => boolean): StreamController<TEventMap> {
352
+ const filteredController = new StreamController<TEventMap>(
353
+ (onEvent, onError, onComplete) => {
354
+ this.on('error' as any, onError)
355
+ this.on('complete' as any, onComplete)
356
+
357
+ // Forward filtered events
358
+ this.handlers.forEach((_, eventType) => {
359
+ this.on(eventType as any, (data: any) => {
360
+ const event = { type: eventType, data }
361
+ if (predicate(event)) {
362
+ onEvent(event)
363
+ }
364
+ })
365
+ })
366
+
367
+ return () => { this.close() }
368
+ }
369
+ )
370
+ return filteredController
371
+ }
372
+ }
@@ -1,3 +1,9 @@
1
+ /* eslint-disable ts/strict-boolean-expressions */
2
+ /* eslint-disable ts/no-unnecessary-condition */
3
+ /* eslint-disable jsdoc/check-param-names */
4
+ /* eslint-disable ts/no-non-null-assertion */
5
+ /* eslint-disable prefer-destructuring */
6
+ import type { SSEEventTypeInfo } from './streamDetector'
1
7
  import type {
2
8
  OperationObject as OpenAPIOperation,
3
9
  PathItemObject as OpenAPIPath,
@@ -8,8 +14,8 @@ import type {
8
14
  ReferenceObject,
9
15
  SchemaObject,
10
16
  } from './types'
17
+ import { isSSEStream, extractSSEEventTypes, extractSSEEventInfo } from './streamDetector'
11
18
  import { dereference, isReferenceObject } from './types/utils'
12
-
13
19
  import {
14
20
  cleanPath,
15
21
  formatType,
@@ -56,6 +62,8 @@ export interface PathOperation {
56
62
  // Tracking for function generation
57
63
  const functionsInventory: Record<string, string> = {}
58
64
  const pathOperations: PathOperation[] = []
65
+ const streamEventTypes: Record<string, string[]> = {} // Track stream endpoints and their event types
66
+ const streamEventInfo: Record<string, SSEEventTypeInfo[]> = {} // Track detailed event info for type generation
59
67
 
60
68
  /**
61
69
  * Collects non-primitive types for import statements
@@ -339,6 +347,121 @@ function combineAllParams(
339
347
  return `{ ${destructuredNames} }: { ${typeDefinition} } = {}`
340
348
  }
341
349
 
350
+ /**
351
+ * Generates a unique type name for a stream endpoint
352
+ */
353
+ function generateStreamTypeName(path: string): string {
354
+ return `${toPascalCase(
355
+ path
356
+ .split('/')
357
+ .filter(p => p && !/\{|\}/.test(p))
358
+ .join('_')
359
+ )}StreamEvents`
360
+ }
361
+
362
+ /**
363
+ * Generates a Stream function for SSE endpoints with full type safety
364
+ * @param method - The HTTP method
365
+ * @param path - The original API path
366
+ * @param formattedPath - The formatted API path
367
+ * @param allParams - The combined parameter string
368
+ * @param requestBodyPayload - The request body payload
369
+ * @param eventTypes - Array of SSE event types
370
+ * @returns A string with the SSE stream function
371
+ */
372
+ function generateStreamFunction(
373
+ method: string,
374
+ path: string,
375
+ formattedPath: string,
376
+ allParams: string,
377
+ requestBodyPayload: string,
378
+ eventTypes?: string[]
379
+ ): string {
380
+ if (allParams === 'undefined') { allParams = '' }
381
+
382
+ // Extract parameter names for the stream call (unused but kept for future use)
383
+ // const paramNames = allParams ? allParams.match(/\w+(?=\s*[?:])/g) || [] : []
384
+
385
+ const bodyVar = requestBodyPayload || '{}'
386
+ const baseUrlRef = 'axios.defaults.baseURL || ""'
387
+
388
+ // Generate type name for this stream
389
+ const streamTypeName = generateStreamTypeName(path)
390
+
391
+ // Store event types for later type generation
392
+ if (eventTypes?.length) {
393
+ streamEventTypes[streamTypeName] = eventTypes
394
+ }
395
+
396
+ const eventTypesComment = eventTypes?.length
397
+ ? `\n * Event types: ${eventTypes.map(t => `"${t}"`).join(', ')}`
398
+ : ''
399
+
400
+ const eventTypesExample = eventTypes?.length
401
+ ? eventTypes.map(t => `\n * .on('${t}', (data) => console.log(data))`).join('')
402
+ : '\n * .on(\'message\', (data) => console.log(data))'
403
+
404
+ const typeAnnotation = eventTypes?.length
405
+ ? `StreamController<${streamTypeName}>`
406
+ : 'StreamController'
407
+
408
+ // Convert formattedPath from string representation to actual path for URL construction
409
+ // formattedPath can be either 'path' or `path/${param}` (as strings)
410
+ const pathForUrl = formattedPath.startsWith('`')
411
+ ? formattedPath.slice(1, -1) // Remove backticks to get the content
412
+ : formattedPath.slice(1, -1) // Remove quotes to get the content
413
+
414
+ if (method === 'post') {
415
+ return `{
416
+ /**
417
+ * Stream SSE events from this endpoint (returns StreamController)${eventTypesComment}
418
+ *
419
+ * @example
420
+ * const stream = api.endpoint.stream(params)${eventTypesExample}
421
+ * .on('error', (err) => console.error(err))
422
+ * .on('complete', () => console.log('Done!'))
423
+ *
424
+ * // Close stream when needed
425
+ * stream.close()
426
+ */
427
+ stream: (${allParams}, options?: SSEStreamOptions): ${typeAnnotation} => {
428
+ const url = \`\${${baseUrlRef}}${pathForUrl}\`
429
+ return createSSEStreamPost<${streamTypeName}>(url, ${bodyVar}, options)
430
+ },
431
+ /**
432
+ * Regular POST request (non-streaming)
433
+ */
434
+ post: async (${allParams}): Promise<AxiosResponse<any>> => {
435
+ return axios.post(${formattedPath}, ${bodyVar})
436
+ }
437
+ }`
438
+ } else {
439
+ return `{
440
+ /**
441
+ * Stream SSE events from this endpoint (returns StreamController)${eventTypesComment}
442
+ *
443
+ * @example
444
+ * const stream = api.endpoint.stream(params)${eventTypesExample}
445
+ * .on('error', (err) => console.error(err))
446
+ * .on('complete', () => console.log('Done!'))
447
+ *
448
+ * // Close stream when needed
449
+ * stream.close()
450
+ */
451
+ stream: (${allParams}, options?: SSEStreamOptions): ${typeAnnotation} => {
452
+ const url = \`\${${baseUrlRef}}${pathForUrl}\`
453
+ return createSSEStream<${streamTypeName}>(url, options)
454
+ },
455
+ /**
456
+ * Regular GET request (non-streaming)
457
+ */
458
+ get: async (${allParams}): Promise<AxiosResponse<any>> => {
459
+ return axios.get(${formattedPath})
460
+ }
461
+ }`
462
+ }
463
+ }
464
+
342
465
  /**
343
466
  * Generates an Axios function call as a string
344
467
  * @param method - The HTTP method
@@ -444,6 +567,9 @@ function generateFunctionForOperation(
444
567
  ): string {
445
568
  if (!operation) { return '' }
446
569
 
570
+ // Check if this is an SSE stream endpoint
571
+ const isStream = isSSEStream(operation)
572
+
447
573
  // Validate: GET and DELETE requests should not have request bodies
448
574
  const methodLower = method.toLowerCase()
449
575
  if (['get', 'delete'].includes(methodLower) && operation.requestBody) {
@@ -493,6 +619,27 @@ function generateFunctionForOperation(
493
619
  // Create JSDoc comment with OpenAPI documentation
494
620
  const functionComment = buildJSDocComment(operation, method, path)
495
621
 
622
+ // Generate stream function for SSE endpoints
623
+ if (isStream) {
624
+ const eventTypes = extractSSEEventTypes(operation)
625
+ const eventInfo = extractSSEEventInfo(operation)
626
+
627
+ // Store detailed event info for type generation
628
+ const streamTypeName = generateStreamTypeName(path)
629
+ if (eventInfo?.length) {
630
+ streamEventInfo[streamTypeName] = eventInfo
631
+ }
632
+
633
+ return functionComment + generateStreamFunction(
634
+ method,
635
+ path,
636
+ formatPathWithParams(path),
637
+ allParams,
638
+ requestBodyPayload,
639
+ eventTypes
640
+ )
641
+ }
642
+
496
643
  return functionComment + generateAxiosFunction(
497
644
  method,
498
645
  formatPathWithParams(path),
@@ -667,6 +814,76 @@ export const ${parent} = ${JSON.stringify(object, undefined, 2)};\n`
667
814
  return fileTemplate(tsString, allTypes, baseUrl)
668
815
  }
669
816
 
817
+ /**
818
+ * Generates TypeScript type definitions for stream events
819
+ * Uses detailed event info if available, falls back to simple event list
820
+ * @returns TypeScript type definitions string
821
+ */
822
+ function generateStreamEventTypeDefinitions(): string {
823
+ if (Object.keys(streamEventTypes).length === 0) {
824
+ return ''
825
+ }
826
+
827
+ let typeDefs = '\n// ============================================================================\n'
828
+ typeDefs += '// Stream Event Type Definitions (Fully Typed!)\n'
829
+ typeDefs += '// ============================================================================\n\n'
830
+
831
+ for (const [typeName, events] of Object.entries(streamEventTypes)) {
832
+ const eventInfo = streamEventInfo[typeName]
833
+
834
+ typeDefs += `/**\n * Event types for ${typeName.replace('StreamEvents', '')} stream\n`
835
+ typeDefs += ` * Events: ${events.map(e => `"${e}"`).join(', ')}\n`
836
+
837
+ // Add event descriptions if available
838
+ if (eventInfo?.length) {
839
+ typeDefs += ` *\n`
840
+ for (const info of eventInfo) {
841
+ typeDefs += ` * - **${info.name}**: ${info.description || 'Event data'}\n`
842
+ }
843
+ }
844
+
845
+ typeDefs += ` */\n`
846
+ typeDefs += `export interface ${typeName} {\n`
847
+
848
+ // Generate event type definitions with field information if available
849
+ if (eventInfo?.length) {
850
+ for (const info of eventInfo) {
851
+ typeDefs += ` /**\n * ${info.description || info.name}\n`
852
+
853
+ if (info.fields?.length) {
854
+ info.fields.forEach((field) => {
855
+ typeDefs += ` * - \`${field.name}\`: ${field.description || 'Field data'}\n`
856
+ })
857
+ }
858
+
859
+ typeDefs += ` */\n`
860
+
861
+ // Generate interface for this event
862
+ if (info.fields?.length) {
863
+ typeDefs += ` ${info.name}: {\n`
864
+ for (const field of info.fields) {
865
+ typeDefs += ` /** ${field.description || field.name} */\n`
866
+ typeDefs += ` ${field.name}: any\n`
867
+ }
868
+ typeDefs += ` }\n`
869
+ } else {
870
+ typeDefs += ` ${info.name}: any\n`
871
+ }
872
+ }
873
+ } else {
874
+ // Fallback: simple event list without field info
875
+ for (const event of events) {
876
+ typeDefs += ` /** ${event} event data */\n`
877
+ typeDefs += ` ${event}: any\n`
878
+ }
879
+ }
880
+
881
+ typeDefs += '}\n\n'
882
+ }
883
+
884
+ return typeDefs
885
+ }
886
+
670
887
  /**
671
888
  * Generates the TypeScript file template
672
889
  * @param tsString - The generated TypeScript code
@@ -679,9 +896,12 @@ function fileTemplate(
679
896
  typeForImport: string[],
680
897
  baseURL: string
681
898
  ): string {
899
+ const streamTypeDefs = generateStreamEventTypeDefinitions()
900
+
682
901
  const templateCode = `import ax from 'axios';
683
902
  import type { AxiosResponse } from 'axios';
684
903
  import type { ${typeForImport.join(', ')} } from './types.d';
904
+ import { createSSEStream, createSSEStreamPost, StreamController, type SSEStreamOptions, type SSEEvent } from './streamClient';
685
905
 
686
906
  /**
687
907
  * Options for file upload operations
@@ -695,6 +915,24 @@ export interface UploadOptions {
695
915
  tags?: string[]
696
916
  }
697
917
 
918
+ /**
919
+ * Export SSE stream utilities for direct use
920
+ *
921
+ * @example Chainable event handlers
922
+ * const stream = createSSEStream(url)
923
+ * .on('token', (data) => console.log(data))
924
+ * .on('done', () => console.log('Complete!'))
925
+ *
926
+ * @example Async iteration
927
+ * for await (const event of createSSEStream(url)) {
928
+ * console.log(event.type, event.data)
929
+ * }
930
+ *
931
+ * @example Promise-based
932
+ * const result = await createSSEStream(url).toPromise()
933
+ */
934
+ export { createSSEStream, createSSEStreamPost, StreamController, type SSEStreamOptions, type SSEEvent } from './streamClient';
935
+ ${streamTypeDefs}
698
936
  /**
699
937
  * Configured axios instance for API requests
700
938
  * @example
@@ -35,4 +35,6 @@ export default async (openApiUrl: string, baseUrl: string): Promise<OpenAPIRespo
35
35
  }
36
36
  }
37
37
 
38
+ export * from './streamClient'
39
+ export * from './streamDetector'
38
40
  export * from './types'