(options)
| 358 | const streamsCreatingAsyncIterator = new WeakSet(); |
| 359 | |
| 360 | function createFetchStreamObserver(options) { |
| 361 | const { connectionId, isSSE, isNDJSON, getNextMessageId } = options; |
| 362 | const decoder = new TextDecoder(); |
| 363 | let buffer = ''; |
| 364 | let closed = false; |
| 365 | let activeStream = null; |
| 366 | |
| 367 | const emitMessage = (eventType, data, lastEventId = '') => { |
| 368 | postToContentScript({ |
| 369 | type: 'stream-message', |
| 370 | connectionId: connectionId, |
| 371 | messageId: getNextMessageId(), |
| 372 | eventType: eventType, |
| 373 | data: data, |
| 374 | lastEventId: lastEventId, |
| 375 | timestamp: Date.now() |
| 376 | }); |
| 377 | }; |
| 378 | |
| 379 | const reportError = (error) => { |
| 380 | postToContentScript({ |
| 381 | type: 'stream-error', |
| 382 | connectionId: connectionId, |
| 383 | timestamp: Date.now(), |
| 384 | error: error?.message || String(error) |
| 385 | }); |
| 386 | }; |
| 387 | |
| 388 | const flushBuffer = () => { |
| 389 | if (!buffer.trim()) { |
| 390 | buffer = ''; |
| 391 | return; |
| 392 | } |
| 393 | |
| 394 | if (isSSE) { |
| 395 | const events = parseSSEEvents(buffer + '\n\n'); |
| 396 | for (const event of events) { |
| 397 | emitMessage(event.event, event.data, event.id); |
| 398 | } |
| 399 | } else if (isNDJSON) { |
| 400 | const lines = buffer.split(/\r?\n/).filter(line => line.trim()); |
| 401 | for (const line of lines) { |
| 402 | emitMessage('message', line); |
| 403 | } |
| 404 | } |
| 405 | buffer = ''; |
| 406 | }; |
| 407 | |
| 408 | const shouldObserveStream = (stream) => { |
| 409 | if (!activeStream) { |
| 410 | activeStream = stream; |
| 411 | return true; |
| 412 | } |
| 413 | return activeStream === stream; |
| 414 | }; |
| 415 | |
| 416 | const closeConnection = (stream) => { |
| 417 | if (activeStream && activeStream !== stream) return; |
no outgoing calls
no test coverage detected