UNPKG

svelte-streamable

Version:

Super tiny, simple to use SvelteJS store for real-time updates from server via SSE.

147 lines (125 loc) 3.64 kB
function noop$1() { } function safe_not_equal(a, b) { return a != a ? b == b : a !== b || ((a && typeof a === 'object') || typeof a === 'function'); } Promise.resolve(); const subscriber_queue = []; /** * Creates a `Readable` store that allows reading by subscription. * @param value initial value * @param {StartStopNotifier}start start and stop notifications for subscriptions */ function readable(value, start) { return { subscribe: writable(value, start).subscribe }; } /** * Create a `Writable` store that allows both updating and reading by subscription. * @param {*=}value initial value * @param {StartStopNotifier=}start start and stop notifications for subscriptions */ function writable(value, start = noop$1) { let stop; const subscribers = new Set(); function set(new_value) { if (safe_not_equal(value, new_value)) { value = new_value; if (stop) { // store is ready const run_queue = !subscriber_queue.length; for (const subscriber of subscribers) { subscriber[1](); subscriber_queue.push(subscriber, value); } if (run_queue) { for (let i = 0; i < subscriber_queue.length; i += 2) { subscriber_queue[i][0](subscriber_queue[i + 1]); } subscriber_queue.length = 0; } } } } function update(fn) { set(fn(value)); } function subscribe(run, invalidate = noop$1) { const subscriber = [run, invalidate]; subscribers.add(subscriber); if (subscribers.size === 1) { stop = start(set) || noop$1; } run(value); return () => { subscribers.delete(subscriber); if (subscribers.size === 0) { stop(); stop = null; } }; } return { set, update, subscribe }; } const esx = {}; function streamable( { url, event = 'message', format = 'json', ...options }, callback, defaultValue ) { const auto = !callback || callback.length < 2; const initial = defaultValue ? Promise.resolve(defaultValue) : new Promise(noop); return readable(initial, (set) => { let cleanup = noop; function resolve(value) { set(typeof value !== 'undefined' ? Promise.resolve(value) : initial); } function update(e) { cleanup(false); let data; if (e && e.data) { if (format === 'json') { data = JSON.parse(e.data); } else if (format === 'base64') { data = atob(e.data); } else if (format === 'urlencoded') { data = Object.fromEntries(new URLSearchParams(e.data)); } else { data = e.data; } } const result = callback ? callback(data, resolve) : data; if (auto) { resolve(result); } else { cleanup = typeof result === 'function' ? result : noop; } } function error(e) { set(Promise.reject(e)); } const keypath = Object.entries(options) .sort() .reduce((k, [, v]) => `${k}/${v}`, url); let es = esx[keypath]; if (!es) { es = new EventSource(url, options); es.subscribers = 0; esx[keypath] = es; } es.addEventListener('error', error); es.addEventListener(event, update); callback && setTimeout(update); es.subscribers++; return () => { es.removeEventListener('error', error); es.removeEventListener(event, update); if (!--es.subscribers) { es.close(); delete esx[keypath]; } cleanup(true); }; }); } function noop() {} export { streamable };