This package has been archived, and as such it is read-only.
@xan/broadcast-subject@0.1.0Built and signed on GitHub ActionsBuilt and signed on GitHub Actions
Built and signed on GitHub Actions
Works with
•JSR Score100%•This package works with Node.js, BrowsersIt is unknown whether this package works with Cloudflare Workers, Bun



Publisheda month ago (0.1.0)
A lightweight, RxJS-inspired library implementing the Observer pattern in JavaScript. Features BroadcastSubjects with AbortController-based unsubscription, supporting both synchronous and asynchronous producers.
1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677import { isObserver, type Observer } from "jsr:@xan/observer@^0.1.0"; import { Subject } from "jsr:@xan/subject@^0.1.0"; import type { BroadcastSubjectConstructor } from "./broadcast-subject-constructor.ts"; /** * Object type that acts as a variant of [`Subject`](https://jsr.io/@xan/subject/doc/~/Subject). */ export type BroadcastSubject<Value = unknown> = Subject<Value>; /** * A fixed UUID that is used to scope the name of the underlying {@linkcode BroadcastChannel}. This ensures that our * {@linkcode BroadcastSubject}'s only communicate with other {@linkcode BroadcastSubject}'s from this library * with _almost_ complete certainty. * * @internal Do NOT export. */ const namespace = "394068c9-9d2c-45cb-81d2-a09197594a9d"; export const BroadcastSubject: BroadcastSubjectConstructor = class { readonly [Symbol.toStringTag] = "BroadcastSubject"; readonly #subject = new Subject(); readonly signal = this.#subject.signal; readonly #channel: BroadcastChannel; constructor(name: string) { if (arguments.length === 0) { throw new TypeError("1 argument required but 0 present"); } if (typeof name !== "string") { throw new TypeError("Parameter 1 is not of type 'String'"); } Object.freeze(this); this.#channel = new BroadcastChannel(`${namespace}:${name}`); this.signal.addEventListener("abort", () => this.#channel.close(), { once: true, }); this.#channel.onmessage = (event) => this.#subject.next(event.data); this.#channel.onmessageerror = (event) => this.#subject.throw(event); } next(value: unknown): void { if (!(this instanceof BroadcastSubject)) { throw new TypeError("'this' is not instanceof 'BroadcastSubject'"); } try { this.#channel.postMessage(value); } catch (error) { this.#subject.throw(error); } } return(): void { if (this instanceof BroadcastSubject) this.#subject.return(); else throw new TypeError("'this' is not instanceof 'BroadcastSubject'"); } throw(value: unknown): void { if (this instanceof BroadcastSubject) this.#subject.throw(value); else throw new TypeError("'this' is not instanceof 'BroadcastSubject'"); } subscribe(observer: Observer): void { if (!(this instanceof BroadcastSubject)) { throw new TypeError("'this' is not instanceof 'BroadcastSubject'"); } if (arguments.length === 0) { throw new TypeError("1 argument required but 0 present"); } if (!isObserver(observer)) { throw new TypeError("Parameter 1 is not of type 'Observer'"); } this.#subject.subscribe(observer); } }; Object.freeze(BroadcastSubject); Object.freeze(BroadcastSubject.prototype);