| 54 | } |
| 55 | |
| 56 | export function fetchEventSource(input: RequestInfo, { |
| 57 | signal: inputSignal, |
| 58 | headers: inputHeaders, |
| 59 | onopen: inputOnOpen, |
| 60 | onmessage, |
| 61 | onclose, |
| 62 | onerror, |
| 63 | openWhenHidden, |
| 64 | fetch: inputFetch, |
| 65 | ...rest |
| 66 | }: FetchEventSourceInit) { |
| 67 | return new Promise<void>((resolve, reject) => { |
| 68 | // make a copy of the input headers since we may modify it below: |
| 69 | const headers = { ...inputHeaders }; |
| 70 | if (!headers.accept) { |
| 71 | headers.accept = EventStreamContentType; |
| 72 | } |
| 73 | |
| 74 | let curRequestController: AbortController; |
| 75 | function onVisibilityChange() { |
| 76 | curRequestController.abort(); // close existing request on every visibility change |
| 77 | if (!document.hidden) { |
| 78 | create(); // page is now visible again, recreate request. |
| 79 | } |
| 80 | } |
| 81 | |
| 82 | if (!openWhenHidden) { |
| 83 | document.addEventListener('visibilitychange', onVisibilityChange); |
| 84 | } |
| 85 | |
| 86 | let retryInterval = DefaultRetryInterval; |
| 87 | let retryTimer = 0; |
| 88 | function dispose() { |
| 89 | document.removeEventListener('visibilitychange', onVisibilityChange); |
| 90 | window.clearTimeout(retryTimer); |
| 91 | curRequestController.abort(); |
| 92 | } |
| 93 | |
| 94 | // if the incoming signal aborts, dispose resources and resolve: |
| 95 | inputSignal?.addEventListener('abort', () => { |
| 96 | dispose(); |
| 97 | resolve(); // don't waste time constructing/logging errors |
| 98 | }); |
| 99 | |
| 100 | const fetch = inputFetch ?? window.fetch; |
| 101 | const onopen = inputOnOpen ?? defaultOnOpen; |
| 102 | async function create() { |
| 103 | curRequestController = new AbortController(); |
| 104 | try { |
| 105 | const response = await fetch(input, { |
| 106 | ...rest, |
| 107 | headers, |
| 108 | signal: curRequestController.signal, |
| 109 | }); |
| 110 | |
| 111 | await onopen(response); |
| 112 | |
| 113 | await getBytes(response.body, getLines(getMessages(id => { |