UNPKG

ngx-signal-hub

Version:

[![npm version](https://badge.fury.io/js/ngx-signal-hub.svg)](https://badge.fury.io/js/ngx-signal-hub) [![License: MIT](https://img.shields.io/badge/License-MIT-yellow.svg)](https://opensource.org/licenses/MIT) A lightweight, reactive signal hub service f

343 lines (342 loc) 13.5 kB
import { DestroyRef, Injector, Signal } from '@angular/core'; import * as i0 from "@angular/core"; /** * Represents an event in the signal hub with a key, data, and timestamp. */ export interface HubEvent<T = unknown> { key: string; data: T; timestamp: number; } /** * Represents the options for subscribing to a signal hub event. */ export interface HubEventOptions<T> { /** The key/query string to match events against (e.g., 'user:login', 'user:*'). */ key: string; /** The callback function to execute when an event matches the query. */ callback: (event: HubEvent<T>) => void | Promise<void>; /** Optional DestroyRef for auto-cleaning subscriptions. */ destroyRef?: DestroyRef; /** If true, replays the latest event for the key on subscription. */ replayLatest?: boolean; /** Optional error handler for callback errors. */ onError?: (error: unknown, event: HubEvent<T>) => void; } /** * Represents a subscription to the signal hub. */ export interface HubSubscription { unsubscribe: () => void; } /** * A hybrid signal hub service for publishing and observing events using Signals and callbacks. * Supports pub/sub with key-based routing, pattern matching, and Signal-based event observation. * * @example * ```typescript * @Component({...}) * export class MyComponent { * constructor(private signalHub: SignalHubService, private destroyRef: DestroyRef) { * // Synchronous subscription * this.signalHub.on({ * key: 'user:*', * callback: (event) => console.log(event.data), * destroyRef: this.destroyRef, * replayLatest: true, * }); * * // Asynchronous subscription * this.signalHub.onAsync({ * key: 'user:login', * callback: async (event) => { * await fetch('/log', { method: 'POST', body: JSON.stringify(event.data) }); * console.log(event.data); * }, * replayLatest: true, * onError: (err) => console.error('Event error:', err), * }); * * // Publish an event * this.signalHub.publish('user:login', { id: 123 }); * * // Clear a specific event * this.signalHub.clearEvent('user:login'); * * // Reset everything * this.signalHub.reset({ clearSubscribers: true }); * } * } * ``` */ export declare class SignalHubService { private readonly eventQueue; private readonly eventRegistry; private readonly subscribers; constructor(injector: Injector); /** * Publishes an event with the given key and data, triggering subscribers and updating the registry. * * @param key - The event key (e.g., 'user:login'). * @param data - The event data (must not be null or undefined). * @throws Error if key is empty or data is null/undefined. * * @example * ```typescript * signalHub.publish('user:login', { id: 123 }); * // Triggers subscribers to 'user:login' or 'user:*' * ``` */ publish<T>(key: string, data: T): void; /** * Publishes an event with the given key, triggering subscribers and updating the registry. * * @param key - The event key (e.g., 'user:login'). * @throws Error if key is empty. * * @example * ```typescript * signalHub.publish('user:login'); * // Triggers subscribers to 'user:login' or 'user:*' * ``` */ publishNoData(key: string): void; /** * Subscribes to events matching a query with a synchronous callback, optionally auto-cleaning with DestroyRef. * Supports pattern matching (e.g., 'user:*') and optional replay of the latest event. * * @param options - Subscription options including key, callback, and optional settings. * @returns A HubSubscription object with an unsubscribe method. * @throws Error if key is empty or callback is not a function. * * @example * ```typescript * signalHub.subscribe({ * key: 'user:*', * callback: (event) => console.log(event.data), * replayLatest: true, * destroyRef: inject(DestroyRef), * onError: (err) => console.error('Error:', err), * }); * ``` */ subscribe<T>({ key, callback, destroyRef, replayLatest, onError, }: HubEventOptions<T>): HubSubscription; /** * Subscribes to events matching a query with an asynchronous callback, optionally auto-cleaning with DestroyRef. * Supports pattern matching (e.g., 'user:*') and optional replay of the latest event. * * @param options - Subscription options including key, callback, and optional settings. * @returns A Promise resolving to a HubSubscription object with an unsubscribe method. * @throws Error if key is empty or callback is not a function. * * @example * ```typescript * await signalHub.subscribeAsync({ * key: 'user:*', * callback: async (event) => console.log(event.data), * replayLatest: true, * destroyRef: inject(DestroyRef), * onError: (err) => console.error('Error:', err), * }); * ``` */ subscribeAsync<T>({ key, callback, destroyRef, replayLatest, onError, }: HubEventOptions<T>): Promise<HubSubscription>; /** * A shorthand for subscribing to events with a synchronous callback, with optional replay and auto-cleanup. * * @param options - Options including key, callback, and optional replayLatest, destroyRef, and onError. * @returns A HubSubscription object with an unsubscribe method. * * @example * ```typescript * signalHub.on({ * key: 'user:login', * callback: (event) => console.log(event.data), * replayLatest: true, * destroyRef: inject(DestroyRef), * onError: (err) => console.error('Error:', err), * }); * ``` */ on<T>({ key, callback, replayLatest, destroyRef, onError }: HubEventOptions<T>): HubSubscription; /** * A shorthand for subscribing to events with an asynchronous callback, with optional replay and auto-cleanup. * * @param options - Options including key, callback, and optional replayLatest, destroyRef, and onError. * @returns A Promise resolving to a HubSubscription object with an unsubscribe method. * * @example * ```typescript * await signalHub.onAsync({ * key: 'user:login', * callback: async (event) => console.log(event.data), * replayLatest: true, * destroyRef: inject(DestroyRef), * onError: (err) => console.error('Error:', err), * }); * ``` */ onAsync<T>({ key, callback, replayLatest, destroyRef, onError, }: HubEventOptions<T>): Promise<HubSubscription>; /** * Subscribes to a single event matching the key with a synchronous callback, auto-unsubscribing after the first match. * * @param options - Options including key, callback, and optional replayLatest and onError. * @returns A HubSubscription object with an unsubscribe method. * * @example * ```typescript * signalHub.once({ * key: 'user:login', * callback: (event) => console.log('Logged in:', event.data), * replayLatest: true, * onError: (err) => console.error('Error:', err), * }); * ``` */ once<T>({ key, callback, replayLatest, onError }: HubEventOptions<T>): HubSubscription; /** * Subscribes to a single event matching the key with an asynchronous callback, auto-unsubscribing after the first match. * * @param options - Options including key, callback, and optional replayLatest and onError. * @returns A Promise resolving to a HubSubscription object with an unsubscribe method. * * @example * ```typescript * await signalHub.onceAsync({ * key: 'user:login', * callback: async (event) => console.log('Logged in:', event.data), * replayLatest: true, * onError: (err) => console.error('Error:', err), * }); * ``` */ onceAsync<T>({ key, callback, replayLatest, onError, }: HubEventOptions<T>): Promise<HubSubscription>; /** * Subscribes to the latest events from multiple keys, invoking the callback with an array of events * whenever any key emits a new event, provided all keys have emitted at least once. * * @param options - Options including keys, callback, and optional settings. * @returns A HubSubscription object with an unsubscribe method. * @throws Error if keys array is empty or contains invalid keys. * * @example * ```typescript * signalHub.onCombineLatest({ * keys: ['user:login', 'user:logout'], * callback: (events) => console.log(events.map(e => e.data)), * replayLatest: true, * destroyRef: inject(DestroyRef), * onError: (err, events) => console.error('Error:', err, events), * }); * ``` */ onCombineLatest<T>({ keys, callback, destroyRef, replayLatest, onError, }: { keys: string[]; callback: (events: HubEvent<T>[]) => void | Promise<void>; destroyRef?: DestroyRef; replayLatest?: boolean; onError?: (error: unknown, events: HubEvent<T>[]) => void; }): HubSubscription; /** * Subscribes to the latest events from multiple keys with an asynchronous callback, * invoking the callback with an array of events whenever any key emits a new event, * provided all keys have emitted at least once. * * @param options - Options including keys, callback, and optional settings. * @returns A Promise resolving to a HubSubscription object with an unsubscribe method. * @throws Error if keys array is empty or contains invalid keys. */ onCombineLatestAsync<T>({ keys, callback, destroyRef, replayLatest, onError, }: { keys: string[]; callback: (events: HubEvent<T>[]) => Promise<void>; destroyRef?: DestroyRef; replayLatest?: boolean; onError?: (error: unknown, events: HubEvent<T>[]) => void; }): Promise<HubSubscription>; /** * Returns a Signal for observing the latest event for a specific key, or null if none exists. * * @param key - The event key to observe (e.g., 'user:login'). * @returns A Signal emitting the latest HubEvent or null. * @throws Error if key is empty. * * @example * ```typescript * const userLogin = signalHub.toSignal('user:login'); * effect(() => console.log(userLogin()?.data)); * ``` */ toSignal<T>(key: string): Signal<HubEvent<T> | null>; /** * Returns a Signal for observing the latest events for multiple keys or wildcard patterns, * returning an array of matching events. * * @param keys - Array of event keys or wildcard patterns to observe (e.g., `['user:login', 'user:*']`). * @param options - Optional configuration for sorting the returned events. * @param options.sortBy - Sorts the events by `'timestamp'` (descending, latest first) or `'key'` (alphabetically). * @returns A Signal emitting an array of matching HubEvents, deduplicated by key. * @throws Error if the keys array is empty or contains invalid (empty) keys. * * @example * ```typescript * // Observe specific and wildcard keys * const events = signalHub.toSignalMultiple(['user:login', 'user:*'], { sortBy: 'timestamp' }); * effect(() => console.log(events().map(e => `${e.key}: ${e.data}`))); * * // Publish events * signalHub.publish('user:login', { id: 123 }); * signalHub.publish('user:logout', { id: 456 }); * * // Output might be: ["user:logout: {id: 456}", "user:login: {id: 123}"] (sorted by timestamp) * ``` */ toSignalMultiple<T>(keys: string[], options?: { sortBy?: 'timestamp' | 'key'; }): Signal<HubEvent<T>[]>; /** * Clears a specific event from the registry by its key. * * @param key - The event key to clear. * @throws Error if key is empty. * * @example * ```typescript * signalHub.clearEvent('user:login'); * // Removes 'user:login' from the registry, affecting replayLatest and signals * ``` */ clearEvent(key: string): void; /** * Resets the event registry, optionally clearing all subscribers. * * @param options - Optional settings for the reset operation. * @param options.clearSubscribers - If true, also clears all subscribers (default: false). * * @example * ```typescript * signalHub.reset(); // Clears event registry only * signalHub.reset({ clearSubscribers: true }); // Clears registry and subscribers * ``` */ reset(options?: { clearSubscribers?: boolean; }): void; /** * Unsubscribes all callbacks for a specific key or all subscribers if no key is provided. * * @param key - Optional key to unsubscribe all callbacks for. If omitted, all subscribers are removed. * * @example * ```typescript * signalHub.unsubscribeAll('user:login'); // Remove all 'user:login' subscribers * signalHub.unsubscribeAll(); // Remove all subscribers * ``` */ unsubscribeAll(key?: string): void; private internalSubscribe; private notifySubscribers; private unsubscribe; private matchQuery; static ɵfac: i0.ɵɵFactoryDeclaration<SignalHubService, never>; static ɵprov: i0.ɵɵInjectableDeclaration<SignalHubService>; }