seitu
Version:
70 lines (69 loc) • 1.67 kB
JavaScript
//#region src/core/subscription/index.ts
function createReadableSubscription(get, subscribe, notify, getServer) {
return {
get,
...getServer ? { getServer } : {},
subscribe(callback, options) {
return subscribe(() => callback(get()), options);
},
"~": {
output: null,
notify
}
};
}
/**
* Subscribe/notify primitive used by every reactive handle.
*
* - `onFirstSubscribe` attaches on first subscriber and cleans up on last.
* - `notify` calls every subscriber; the first throw is rethrown after the loop.
* - `size` is the subscriber count.
*
* @example
* ```ts twoslash
* import { createSubscription } from 'seitu'
*
* const { subscribe, notify, size } = createSubscription({
* onFirstSubscribe: () => {
* const id = setInterval(notify, 1000)
* return () => clearInterval(id)
* },
* })
* ```
*/
function createSubscription(options) {
const subscribers = /* @__PURE__ */ new Set();
let onEmpty;
const notify = () => {
let error;
for (const cb of [...subscribers]) {
if (!subscribers.has(cb)) continue;
try {
cb();
} catch (caught) {
error ??= { caught };
}
}
if (error) throw error.caught;
};
return {
subscribe(callback, opts) {
if (subscribers.size === 0 && options?.onFirstSubscribe) onEmpty = options.onFirstSubscribe() ?? void 0;
subscribers.add(callback);
if (opts?.immediate) callback();
return () => {
if (!subscribers.delete(callback)) return;
if (subscribers.size === 0) {
onEmpty?.();
onEmpty = void 0;
}
};
},
notify,
get size() {
return subscribers.size;
}
};
}
//#endregion
export { createReadableSubscription, createSubscription };