All files / blong-browser/src/lib eventBus.ts

0% Statements 0/69
0% Branches 0/1
0% Functions 0/1
0% Lines 0/69

Press n or j to go to the next uncovered block, b, p or k for the previous block.

1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70                                                                                                                                           
/**
 * blongEvents — typed event bus for blong-browser.
 *
 * A thin wrapper around the native browser `EventTarget` API, typed for the
 * events that blong-browser emits internally. Using `EventTarget` means zero extra
 * dependencies and native browser performance.
 *
 * ## Events
 *
 * | Type               | Fired when                                      |
 * |--------------------|-------------------------------------------------|
 * | `action:before`    | Before any dispatch call                        |
 * | `action:success`   | After a dispatch call resolves successfully     |
 * | `action:error`     | After a dispatch call rejects                   |
 *
 * ## Usage
 *
 * ```ts
 * import {blongEvents} from '@feasibleone/blong-browser';
 *
 * // Subscribe
 * const off = blongEvents.on('action:success', ({method, result}) => {
 *     console.log(method, result);
 * });
 *
 * // Unsubscribe
 * off();
 * ```
 */

/** All event payloads emitted by blong-browser */
export interface BlongEventMap {
    /** Emitted before every dispatch call */
    'action:before': {method: string; params: unknown};
    /** Emitted after a dispatch call resolves */
    'action:success': {method: string; params: unknown; result: unknown};
    /** Emitted after a dispatch call rejects */
    'action:error': {method: string; params: unknown; error: unknown};
}

type BlongEventType = keyof BlongEventMap;
type BlongListener<K extends BlongEventType> = (detail: BlongEventMap[K]) => void;

class BlongEventBus extends EventTarget {
    /**
     * Subscribe to an event. Returns an `off` function that removes the listener.
     *
     * @example
     * const off = blongEvents.on('action:success', ({method, result}) => { ... });
     * // later:
     * off();
     */
    on<K extends BlongEventType>(type: K, listener: BlongListener<K>): () => void {
        const handler = (e: Event) => listener((e as CustomEvent<BlongEventMap[K]>).detail);
        this.addEventListener(type, handler);
        return () => this.removeEventListener(type, handler);
    }

    /**
     * Emit an event with a typed payload. Called internally by blong-browser — user
     * code rarely needs to call this directly.
     */
    emit<K extends BlongEventType>(type: K, detail: BlongEventMap[K]): void {
        this.dispatchEvent(new CustomEvent(type, {detail}));
    }
}

/** Singleton event bus — import and subscribe from anywhere */
export const blongEvents = new BlongEventBus();