/** * DevTools hook contract — single global object that every layer * (reactivity, runtime-core, store, router) emits into. * * The hook lives here in `@sigx/reactivity` because reactivity is at * the bottom of the dep stack — runtime-core depends on us, not the * other way around. Higher layers extend the event union with their * own variants and emit them through the same `hook.emit()`. * * Performance contract: every emission must short-circuit on the * `getDevtoolsHook()` null check. When no hook is installed (the * production-without-devtools case), an emission costs one global * read plus one null comparison. We do NOT try to make these * branches free at module load — Vite's tree-shaking and the JIT * handle the rest. */ /** * Base shape every devtools event satisfies. Layers extend with their * own `{ type: 'foo:bar'; …extra fields }` variants — the index * signature lets `hook.emit(layeredEvent)` typecheck without forcing * every layer's union into the base type. Consumers narrow on `type`. */ export interface DevtoolsEventBase { readonly type: string; readonly [key: string]: unknown; } export type DevtoolsListenerBase = (event: DevtoolsEventBase) => void; export declare const DEVTOOLS_HOOK_KEY = "__SIGX_DEVTOOLS_HOOK__"; export interface DevtoolsHook { /** Hook protocol version. Consumers should check compatibility. */ readonly version: 1; /** * Apps registered with the hook. Opaque at this layer — `runtime-core` * stores `AppContext` references here. Reactivity doesn't read it. */ readonly apps: Set; /** * Component id of the currently-mounting component, set by * `runtime-core` during setup. Reactivity reads this when a signal * or effect is created so the devtools can attribute ownership * without reactivity importing component types. */ currentOwner: number | null; /** Mint a fresh monotonic id. Shared id space across signals, effects, components, etc. */ nextId(): number; /** Push an event into the hook. */ emit(event: DevtoolsEventBase): void; /** Subscribe to events. Returns an unsubscribe. */ on(listener: DevtoolsListenerBase): () => void; /** * Events emitted before any listener attached. A late-attaching * client drains this on `on()`. */ readonly buffer: DevtoolsEventBase[]; } declare global { var __SIGX_DEVTOOLS_HOOK__: DevtoolsHook | undefined; } /** Get the installed devtools hook, or `null` if none is present. */ export declare function getDevtoolsHook(): DevtoolsHook | null; /** * Run a function with owner attribution suppressed. * * Used by the renderer to wrap framework-internal reactives (props * wrappers, slots) so they aren't blamed on whichever component's * render effect happens to be active. Without this, every remount * leaks fresh signals into the parent's "reactives" panel because * the parent's render effect is the one running while the child's * `reactiveProps = signal(...)` is set up. * * No-op when no hook is installed. */ export declare function withoutOwnerTracking(fn: () => T): T; /** * Centralized devtools "signal updated" emit. * * Called from every mutation path on a reactive signal — the proxy * `set` and `deleteProperty` traps in signal.ts, plus the Map/Set * instrumentations in collections.ts (`add`, `set`, `delete`, * `clear`). Routing every mutation through one function means the * panel sees every state change, not just object-property writes. * * `signalId === null` short-circuits — that's the "signal was created * before any devtools hook attached" case, which we deliberately * leave invisible (matching the rest of the surface). */ export declare function notifySignalUpdated(signalId: number | null, key: string | symbol): void; /** @internal */ export declare function registerReactiveProxy(id: number, proxy: object): void; /** * Resolve a reactive proxy by its devtools id, or `null` if it was * never registered or has been garbage-collected. * * @internal */ export declare function getReactiveById(id: number): object | null; /** * Install a hook if one is not already present. * * Idempotent: if a hook is already installed (e.g. a content script * injected a stub before sigx loaded), this returns the existing hook * unchanged. That lets clients race the runtime safely. */ export declare function ensureDevtoolsHook(): DevtoolsHook; //# sourceMappingURL=devtools-hook.d.ts.map