/**
 * @bobfrankston/mailx-bus
 *
 * Typed message bus that connects mailx's factors. Each factor (DB, sync,
 * UI, compose, calendar, …) is a peer that publishes/subscribes to events
 * and serves/calls request-reply methods over the same bus.
 *
 * **Why this exists.** mailx historically had one monolithic service on one
 * Node event loop: UI reads, IMAP sync, body parsing, OAuth refresh, prefetch,
 * calendar polling — all on the same thread. A 14-minute synchronous freeze
 * in any one path froze every other path. There was no separation between
 * "answer a click" and "wait for Dovecot." The bus is the mechanism that
 * makes those independent: a factor freezing is local; other factors keep
 * answering.
 *
 * **Shape.** A bus exposes two primitives:
 *   - `publish(topic, payload)` / `subscribe(topic, handler)` — fire-and-
 *     forget events. Many subscribers per topic.
 *   - `request(method, args) → Promise<result>` / `register(method, handler)`
 *     — RPC. One handler per method. Caller awaits the reply.
 *
 * No method-name dispatch on a god object. Each factor declares the topics
 * and methods it owns. Other factors hold a reference to the bus, not to
 * each other.
 *
 * **Two transports, one interface.**
 *   - `InProcessBus`: in-memory Map of handlers. Used in tests, in Android
 *     (single-threaded JS), and for the same-thread half of a bridge.
 *   - `WorkerBus`: connects to a peer via `worker_threads.MessagePort` (Node)
 *     or `MessagePort` (browser). Uses `postMessage`, with structured
 *     clone, so the two sides can live in different threads.
 *
 * Both implement `Bus`. Callers write against `Bus`. Where the peer lives is
 * a deploy decision, not an API decision.
 *
 * **Buffer/Uint8Array note (Node).** `worker_threads.postMessage` clones a
 * Node `Buffer` as a plain `Uint8Array`. Callers passing binary data through
 * the bus across a worker boundary must accept that the receiving side sees
 * `Uint8Array` — they should re-wrap with `Buffer.from(u.buffer, u.byteOffset,
 * u.byteLength)` before handing the value to APIs that test
 * `Buffer.isBuffer(x)`. The bus does not do this transparently; it is a
 * transport concern that varies by what the payload actually is.
 *
 * **Errors.** A handler that throws is converted to a rejection on the
 * caller's `request()` promise. The error's `message` survives the
 * structured-clone barrier; the stack trace does not (Node strips it).
 *
 * **Lifecycle.** Subscribers receive a `dispose()` function from `subscribe`.
 * Registered methods receive one from `register`. Dispose unhooks. A bus
 * itself has no global teardown — closing the underlying port (when using
 * `WorkerBus`) is the caller's responsibility.
 */
/** Method handler — receives the request payload, returns the response. May
 *  be async. A throw becomes a request() rejection on the caller. */
export type MethodHandler<A = any, R = any> = (args: A) => R | Promise<R>;
/** Topic handler — fire-and-forget; the return value is ignored. */
export type TopicHandler<P = any> = (payload: P) => void;
/** Unsubscribe / unregister token returned from `subscribe` / `register`. */
export type Dispose = () => void;
export interface Bus {
    /** Fire an event. Returns synchronously; subscribers are invoked
     *  asynchronously (next microtask) so a publisher doesn't observe its
     *  own re-entry. */
    publish<P = any>(topic: string, payload: P): void;
    /** Listen to events on `topic`. Returns a dispose function. */
    subscribe<P = any>(topic: string, handler: TopicHandler<P>): Dispose;
    /** Call `method` on its registered handler. The result Promise resolves
     *  with whatever the handler returned, or rejects with the error. */
    request<A = any, R = any>(method: string, args: A): Promise<R>;
    /** Register the handler for `method`. Only one handler per method —
     *  registering twice throws on the second call. Returns a dispose
     *  function that unregisters. */
    register<A = any, R = any>(method: string, handler: MethodHandler<A, R>): Dispose;
}
/** Single-process bus. Both sides of every call share a JavaScript heap.
 *  Used in tests, in Android (single-threaded JS), and on whichever side of
 *  a worker boundary is the host.
 *
 *  publish() defers subscriber dispatch to the next microtask so a
 *  publisher's stack doesn't deepen indefinitely if a handler republishes
 *  on the same topic. */
export declare class InProcessBus implements Bus {
    private topics;
    private methods;
    publish<P>(topic: string, payload: P): void;
    subscribe<P>(topic: string, handler: TopicHandler<P>): Dispose;
    request<A, R>(method: string, args: A): Promise<R>;
    register<A, R>(method: string, handler: MethodHandler<A, R>): Dispose;
}
/** Anything that quacks like a MessagePort — Node's `worker_threads.parentPort`
 *  and `Worker` instances, browser's `MessagePort`, etc. */
export interface MessagePortLike {
    postMessage(value: any): void;
    on?(event: "message", handler: (value: any) => void): void;
    addEventListener?(event: "message", handler: (e: MessageEvent) => void): void;
}
/** Cross-thread bus. Each side instantiates a `WorkerBus` over its end of a
 *  `MessageChannel`. The two sides are mirror images: subscribing on side A
 *  causes events published on side B to flow over the wire to A. Requests
 *  initiated on side A are served by whoever registered the method on side B.
 *
 *  Topology assumed by this implementation: exactly two endpoints. Multi-
 *  party busses (>2 peers) need a hub topology and aren't covered here. */
export declare class WorkerBus implements Bus {
    private port;
    private localSubs;
    /** Methods registered on THIS side. Requests arriving over the wire
     *  for these methods are dispatched locally. */
    private localMethods;
    /** Pending requests we sent to the peer, awaiting reply. */
    private pending;
    private nextId;
    constructor(port: MessagePortLike);
    publish<P>(topic: string, payload: P): void;
    subscribe<P>(topic: string, handler: TopicHandler<P>): Dispose;
    request<A, R>(method: string, args: A): Promise<R>;
    register<A, R>(method: string, handler: MethodHandler<A, R>): Dispose;
    private handleIncoming;
}
export { StoreBus, storeBus } from "./store-events.js";
export type { StoreEvent, StoreEventKind, StoreEventHandler } from "./store-events.js";
//# sourceMappingURL=index.d.ts.map