/** * Read-only signal wrappers. */ import type { Signal } from './core'; const READONLY_SIGNAL_BRAND: unique symbol = Symbol('bquery.readonlySignal'); /** @internal */ type ReadonlySignalWrapper = ReadonlySignal & { readonly [READONLY_SIGNAL_BRAND]: true; }; /** * A readonly wrapper around a signal that prevents writes. * Provides read-only access to a signal's value while maintaining reactivity. * * @template T - The type of the wrapped value */ export interface ReadonlySignal { /** Gets the current value with dependency tracking. */ readonly value: T; /** Gets the current value without dependency tracking. */ peek(): T; } /** * Determines whether a value is a bQuery readonly signal wrapper. * * @internal */ export const isReadonlySignal = (value: unknown): value is ReturnType> => { return ( typeof value === 'object' && value !== null && Object.prototype.hasOwnProperty.call(value, READONLY_SIGNAL_BRAND) ); }; /** * Creates a read-only view of a signal. * Useful for exposing reactive state without allowing modifications. * * @template T - The type of the signal value * @param sig - The signal to wrap * @returns A readonly signal wrapper */ export const readonly = (sig: Signal): ReadonlySignalWrapper => Object.defineProperties( {}, { value: { get(): T { return sig.value; }, enumerable: true, }, peek: { value(): T { return sig.peek(); }, enumerable: true, }, [READONLY_SIGNAL_BRAND]: { value: true, enumerable: false, configurable: false, writable: false, }, } ) as ReadonlySignalWrapper; /** * Branded readonly wrapper type produced by {@link readonly}. * * Useful for APIs that compose additional behavior on top of a readonly signal * without widening to arbitrary structural `{ value, peek }` objects. */ export type ReadonlySignalHandle = ReturnType>;