@waylaidwanderer/fetch-event-source
Version:
A better API for making Event Source requests, with all the features of fetch()
91 lines • 4.1 kB
JavaScript
var __rest = (this && this.__rest) || function (s, e) {
var t = {};
for (var p in s) if (Object.prototype.hasOwnProperty.call(s, p) && e.indexOf(p) < 0)
t[p] = s[p];
if (s != null && typeof Object.getOwnPropertySymbols === "function")
for (var i = 0, p = Object.getOwnPropertySymbols(s); i < p.length; i++) {
if (e.indexOf(p[i]) < 0 && Object.prototype.propertyIsEnumerable.call(s, p[i]))
t[p[i]] = s[p[i]];
}
return t;
};
import { getBytes, getLines, getMessages } from './parse.js';
export const EventStreamContentType = 'text/event-stream';
const DefaultRetryInterval = 1000;
const LastEventId = 'last-event-id';
export function fetchEventSource(input, _a) {
var { signal: inputSignal, headers: inputHeaders, onopen: inputOnOpen, onmessage, onclose, onerror, openWhenHidden, fetch: inputFetch } = _a, rest = __rest(_a, ["signal", "headers", "onopen", "onmessage", "onclose", "onerror", "openWhenHidden", "fetch"]);
return new Promise((resolve, reject) => {
const headers = Object.assign({}, inputHeaders);
if (!headers.accept) {
headers.accept = EventStreamContentType;
}
let curRequestController;
function onVisibilityChange() {
curRequestController.abort();
if (!document.hidden) {
create();
}
}
if (typeof document !== 'undefined' && !openWhenHidden) {
document.addEventListener('visibilitychange', onVisibilityChange);
}
let retryInterval = DefaultRetryInterval;
let retryTimer = 0;
function dispose() {
if (typeof document !== 'undefined' && !openWhenHidden) {
document.removeEventListener('visibilitychange', onVisibilityChange);
}
clearTimeout(retryTimer);
curRequestController.abort();
}
inputSignal === null || inputSignal === void 0 ? void 0 : inputSignal.addEventListener('abort', () => {
dispose();
resolve();
});
const fetchFn = inputFetch !== null && inputFetch !== void 0 ? inputFetch : fetch;
const onopen = inputOnOpen !== null && inputOnOpen !== void 0 ? inputOnOpen : defaultOnOpen;
async function create() {
var _a;
curRequestController = new AbortController();
try {
const response = await fetchFn(input, Object.assign(Object.assign({}, rest), { headers, signal: curRequestController.signal }));
await onopen(response);
await getBytes(response.body, getLines(getMessages(onmessage, id => {
if (id) {
headers[LastEventId] = id;
}
else {
delete headers[LastEventId];
}
}, retry => {
retryInterval = retry;
})));
onclose === null || onclose === void 0 ? void 0 : onclose();
dispose();
resolve();
}
catch (err) {
if (!curRequestController.signal.aborted) {
try {
const interval = (_a = onerror === null || onerror === void 0 ? void 0 : onerror(err)) !== null && _a !== void 0 ? _a : retryInterval;
clearTimeout(retryTimer);
retryTimer = setTimeout(create, interval);
}
catch (innerErr) {
dispose();
reject(innerErr);
}
}
}
}
create();
});
}
function defaultOnOpen(response) {
const contentType = response.headers.get('content-type');
if (!(contentType === null || contentType === void 0 ? void 0 : contentType.startsWith(EventStreamContentType))) {
throw new Error(`Expected content-type to be ${EventStreamContentType}, Actual: ${contentType}`);
}
}
//# sourceMappingURL=fetch.js.map