/** * Stable bridge protocol between a bQuery app and the DevTools browser * extension (1.15+). * * The protocol is a small, versioned message contract carried over any * request/response transport. In the browser it rides on `window.postMessage` * (page ⇄ content-script ⇄ extension panel); the core * {@link createBridgeServer} is transport-agnostic so it can be unit-tested * without a DOM. * * Message envelopes always carry `source: 'bquery-devtools'` and the protocol * version `v`. The panel sends `hello` / `request`; the page replies with * `init` / `response` and streams `event` messages as the timeline grows. * * @module bquery/devtools */ import type { TimelineEntry } from './types'; /** Current bridge protocol version. Bumped only on breaking protocol changes. */ export declare const BRIDGE_PROTOCOL_VERSION = 1; /** Shared `source` discriminator on every bridge message. */ export declare const BRIDGE_SOURCE = "bquery-devtools"; /** Capabilities advertised by the page in its `init` handshake. */ export declare const BRIDGE_CAPABILITIES: readonly ["signals", "stores", "components", "timeline", "time-travel"]; /** A serialized node in the component tree. */ export interface ComponentTreeNode { /** Custom-element tag name (always contains a hyphen). */ tag: string; /** A stable-ish id derived from tree position. */ id: string; /** Selected attributes, for display in the panel. */ attrs: Record; /** Nested custom-element descendants. */ children: ComponentTreeNode[]; } /** Panel → page messages. */ export type BridgeInboundMessage = { source: typeof BRIDGE_SOURCE; channel: 'panel'; v: number; kind: 'hello'; } | { source: typeof BRIDGE_SOURCE; channel: 'panel'; v: number; kind: 'request'; id: number; method: string; params?: unknown; }; /** Page → panel messages. */ export type BridgeOutboundMessage = { source: typeof BRIDGE_SOURCE; channel: 'page'; v: number; kind: 'init'; capabilities: readonly string[]; } | { source: typeof BRIDGE_SOURCE; channel: 'page'; v: number; kind: 'response'; id: number; result?: unknown; error?: string; } | { source: typeof BRIDGE_SOURCE; channel: 'page'; v: number; kind: 'event'; entry: TimelineEntry; }; /** A request handler registered on the bridge server. */ export type BridgeMethod = (params: unknown) => unknown; /** Options for {@link createBridgeServer}. */ export interface BridgeServerOptions { /** Transport sink — called with each outbound (page → panel) message. */ post: (message: BridgeOutboundMessage) => void; /** Extra/override methods merged over the built-in read methods. */ methods?: Record; } /** Handle returned by {@link createBridgeServer}. */ export interface BridgeServer { /** Feed one inbound (panel → page) message in. Ignores foreign messages. */ handleMessage: (data: unknown) => void; /** Stream a timeline entry to the panel as an `event` message. */ pushEvent: (entry: TimelineEntry) => void; /** Send the `init` handshake (also sent automatically on `hello`). */ announce: () => void; /** Registered method names (built-ins + overrides). */ methods: readonly string[]; } /** * Walks the DOM from `root` and serializes the tree of custom elements * (tag names containing a hyphen) for the panel's component tree. */ export declare const serializeComponentTree: (root?: ParentNode) => ComponentTreeNode[]; /** * Creates a transport-agnostic bridge server. Feed inbound panel messages to * {@link BridgeServer.handleMessage} and call {@link BridgeServer.pushEvent} * for timeline updates; outbound messages go to `options.post`. * * @example * ```ts * const sent: unknown[] = []; * const server = createBridgeServer({ post: (m) => sent.push(m) }); * server.handleMessage({ source: 'bquery-devtools', channel: 'panel', v: 1, kind: 'hello' }); * // sent[0] is the `init` handshake * ``` */ export declare const createBridgeServer: (options: BridgeServerOptions) => BridgeServer; /** Options for {@link connectDevtoolsBridge}. */ export interface ConnectBridgeOptions { /** Extra/override request methods. */ methods?: Record; /** Window to attach to. Defaults to the global `window`. */ target?: Window; } /** Handle returned by {@link connectDevtoolsBridge}. */ export interface BridgeConnection { /** Tears down the message listener and timeline subscription. */ disconnect: () => void; /** The underlying transport-agnostic server. */ server: BridgeServer; } /** * Connects the bridge protocol to `window.postMessage`, announces the `init` * handshake, answers panel `request`s, and forwards timeline events to the * extension. No-op (returns an inert handle) outside a DOM environment. * * This is the stabilized contract the DevTools extension connects to. * * @returns A {@link BridgeConnection} with `disconnect()`. */ export declare const connectDevtoolsBridge: (options?: ConnectBridgeOptions) => BridgeConnection; //# sourceMappingURL=bridge.d.ts.map