{"version":3,"file":"index.cjs","names":[],"sources":["../src/topicMatch.ts","../src/envelope.ts","../src/channel.ts","../src/transport.ts"],"sourcesContent":["/**\n * AMQP-style topic matching for postal's pub/sub system.\n *\n * Topics are dot-delimited strings (e.g., \"order.placed.domestic\").\n * Subscription patterns support two wildcards:\n *   - `*` matches exactly one segment\n *   - `#` matches zero or more segments (per AMQP standard)\n *\n * Match results are cached in a module-level Map for repeated lookups.\n * @module\n */\n\n/**\n * Recursively matches pattern segments against topic segments.\n *\n * Walks both arrays in lockstep. Literal segments must match exactly,\n * `*` consumes one topic segment, and `#` uses backtracking to try\n * consuming 0..N remaining topic segments until a full match is found.\n */\nconst matchSegments = (\n    patternSegments: string[],\n    topicSegments: string[],\n    patternIndex: number,\n    topicIndex: number\n): boolean => {\n    // Pattern fully consumed — only a match if topic is also fully consumed\n    if (patternIndex === patternSegments.length) {\n        return topicIndex === topicSegments.length;\n    }\n\n    const segment = patternSegments[patternIndex];\n\n    // # can consume zero segments, so it must run even when the topic is exhausted.\n    // This is what distinguishes # from * — it doesn't require remaining topic segments.\n    if (segment === \"#\") {\n        for (let consumed = 0; consumed <= topicSegments.length - topicIndex; consumed++) {\n            if (\n                matchSegments(\n                    patternSegments,\n                    topicSegments,\n                    patternIndex + 1,\n                    topicIndex + consumed\n                )\n            ) {\n                return true;\n            }\n        }\n        return false;\n    }\n\n    // Everything below (*, literals) requires at least one remaining topic segment\n    if (topicIndex === topicSegments.length) {\n        return false;\n    }\n\n    if (segment === \"*\") {\n        return matchSegments(patternSegments, topicSegments, patternIndex + 1, topicIndex + 1);\n    }\n\n    // Literal segment — must match exactly before continuing\n    return (\n        segment === topicSegments[topicIndex] &&\n        matchSegments(patternSegments, topicSegments, patternIndex + 1, topicIndex + 1)\n    );\n};\n\n/** Module-level cache for match results. Keyed by `pattern\\0topic`. */\nconst cache = new Map<string, boolean>();\n\n/**\n * Tests whether a subscription pattern matches a published topic.\n *\n * @param pattern - The subscription pattern, which may include `*` and `#` wildcards\n * @param topic - The published topic string (no wildcards)\n * @returns `true` if the pattern matches the topic\n *\n * @example\n * matchTopic(\"order.*\", \"order.placed\")        // true\n * matchTopic(\"order.#\", \"order.placed.rush\")    // true\n * matchTopic(\"order.#\", \"order\")                // true  (# matches zero segments)\n * matchTopic(\"order.*\", \"order.placed.rush\")    // false (* matches exactly one)\n */\nexport const matchTopic = (pattern: string, topic: string): boolean => {\n    // Fast path — identical strings don't need segment parsing\n    if (pattern === topic) {\n        return true;\n    }\n\n    // Null byte can't appear in topic strings, so it's a safe cache key delimiter\n    const key = `${pattern}\\0${topic}`;\n    const cached = cache.get(key);\n    if (cached !== undefined) {\n        return cached;\n    }\n\n    const result = matchSegments(pattern.split(\".\"), topic.split(\".\"), 0, 0);\n    cache.set(key, result);\n    return result;\n};\n\n/**\n * Clears the topic match result cache. Primarily useful for testing\n * and for cleanup when channels are disposed.\n */\nexport const clearMatchCache = (): void => {\n    cache.clear();\n};\n\n// --- Type-level topic matching ---\n\n/**\n * Given a channel map `TMap` and a subscription `Pattern`, resolves the union\n * of payload types for all topics in the map that the pattern would match.\n *\n * Handles common subscription patterns without recursive type gymnastics:\n *\n *   - Exact key: `\"order.placed\"` → specific payload type\n *   - Trailing `.*`: `\"order.*\"` → keys with exactly one segment after prefix\n *   - Trailing `.#`: `\"order.#\"` → prefix itself + keys with segments after prefix\n *   - Bare `#`: all values in the map\n *   - Bare `*`: single-segment keys only\n *   - Complex patterns: falls back to union of all values (safe but imprecise)\n *\n * @example\n * type Map = {\n *   \"order.placed\": { id: string };\n *   \"order.cancelled\": { id: string; reason: string };\n * };\n * type T = PayloadFor<Map, \"order.*\">;\n * // T = { id: string } | { id: string; reason: string }\n */\nexport type PayloadFor<TMap, Pattern extends string> =\n    // Exact match — pattern is a literal key in the map\n    Pattern extends keyof TMap\n        ? TMap[Pattern]\n        : // Trailing .# — prefix itself (zero segments) + keys starting with prefix (one or more)\n          Pattern extends `${infer Prefix}.#`\n          ? {\n                [K in Extract<keyof TMap, string>]: K extends Prefix\n                    ? TMap[K]\n                    : K extends `${Prefix}.${string}`\n                      ? TMap[K]\n                      : never;\n            }[Extract<keyof TMap, string>]\n          : // Trailing .* — only keys with exactly one segment after prefix.\n            // The nested conditional excludes keys with two+ segments (e.g., \"a.b.c\"\n            // is excluded when prefix is \"a\" because it extends \"a.${string}.${string}\")\n            Pattern extends `${infer Prefix}.*`\n            ? {\n                  [K in Extract<keyof TMap, string>]: K extends `${Prefix}.${string}`\n                      ? K extends `${Prefix}.${string}.${string}`\n                          ? never\n                          : TMap[K]\n                      : never;\n              }[Extract<keyof TMap, string>]\n            : // Bare # — matches everything, return union of all values\n              Pattern extends \"#\"\n              ? TMap[keyof TMap]\n              : // Bare * — only single-segment keys (no dots)\n                Pattern extends \"*\"\n                ? {\n                      [K in Extract<keyof TMap, string>]: K extends `${string}.${string}`\n                          ? never\n                          : TMap[K];\n                  }[Extract<keyof TMap, string>]\n                : // Complex/unrecognized wildcard pattern — union of all values as safe fallback\n                  TMap[keyof TMap];\n","/**\n * Types and factory for postal's message envelopes.\n *\n * Every message flowing through postal — publishes, requests, and replies —\n * is wrapped in an envelope that carries routing metadata alongside the payload.\n * @module\n */\n\n/** The kind of message this envelope carries. */\nexport type EnvelopeType = \"publish\" | \"request\" | \"reply\";\n\n/**\n * Standard message wrapper used internally and exposed to subscribers.\n *\n * Envelopes are the unit of communication in postal. Subscribers receive\n * the full envelope, and transports serialize/deserialize them when\n * bridging across execution boundaries.\n */\nexport type Envelope<TPayload = unknown> = {\n    /** Unique message identifier (UUID v4) */\n    id: string;\n    /** The kind of message */\n    type: EnvelopeType;\n    /** The channel this message was published on */\n    channel: string;\n    /** The dot-delimited topic string */\n    topic: string;\n    /** The message payload */\n    payload: TPayload;\n    /** When the envelope was created — Date.now() for serialization safety */\n    timestamp: number;\n    /** Originating context identifier, set by transports to track message origin */\n    source?: string;\n    /** Present on 'request' envelopes — the topic to send the reply to */\n    replyTo?: string;\n    /** Present on 'reply' envelopes — correlates back to the original request */\n    correlationId?: string;\n};\n\n/** Options for creating a new envelope. ID and timestamp are generated automatically. */\nexport type CreateEnvelopeOptions<TPayload = unknown> = {\n    type: EnvelopeType;\n    channel: string;\n    topic: string;\n    payload: TPayload;\n    source?: string;\n    replyTo?: string;\n    correlationId?: string;\n};\n\n/**\n * Creates a new envelope with a unique ID and current timestamp.\n *\n * Optional fields (`source`, `replyTo`, `correlationId`) are only included\n * on the envelope when explicitly provided — they won't appear as `undefined`\n * properties, which keeps serialized output clean.\n *\n * @param options - The envelope fields. `id` and `timestamp` are generated automatically.\n * @returns A fully formed envelope ready for delivery\n */\nexport const createEnvelope = <TPayload>({\n    type,\n    channel,\n    topic,\n    payload,\n    source,\n    replyTo,\n    correlationId,\n}: CreateEnvelopeOptions<TPayload>): Envelope<TPayload> => {\n    const envelope: Envelope<TPayload> = {\n        id: crypto.randomUUID(),\n        type,\n        channel,\n        topic,\n        payload,\n        timestamp: Date.now(),\n    };\n\n    if (source !== undefined) {\n        envelope.source = source;\n    }\n    if (replyTo !== undefined) {\n        envelope.replyTo = replyTo;\n    }\n    if (correlationId !== undefined) {\n        envelope.correlationId = correlationId;\n    }\n\n    return envelope;\n};\n","/**\n * Channel creation, pub/sub dispatch, request/handle RPC, and singleton registry.\n *\n * A channel is a named scope for messages. Subscribers register topic\n * patterns (with optional `*` and `#` wildcards), and publishes fan out\n * to every subscriber whose pattern matches the published topic.\n *\n * Channels also support request/handle — a correlation-based RPC pattern\n * where `request()` publishes a message through the channel and returns a\n * Promise, and `handle()` registers a specialized subscriber whose return\n * value is published as a reply on the internal system channel, resolving\n * the requester's Promise.\n *\n * Channels are singletons — `getChannel(\"orders\")` always returns the\n * same instance. The registry is module-level and can be reset for testing.\n * @module\n */\n\nimport { matchTopic, type PayloadFor } from \"./topicMatch\";\nimport { createEnvelope, type Envelope } from \"./envelope\";\n\n/**\n * Augmentable interface for global channel type registration.\n *\n * Users can declare their channel maps once via module augmentation\n * and get automatic payload inference on `getChannel()` without\n * passing a generic at every call site:\n *\n * ```ts\n * declare module 'postal' {\n *   interface ChannelRegistry {\n *     orders: { 'item.placed': { sku: string } };\n *   }\n * }\n *\n * const orders = getChannel('orders'); // Channel<{ 'item.placed': { sku: string } }>\n * ```\n *\n * Channels not in the registry fall back to `Record<string, unknown>` (untyped).\n */\n// eslint-disable-next-line @typescript-eslint/no-empty-object-type\nexport interface ChannelRegistry {}\n\n/** Resolves the TMap for a channel name — registry lookup with untyped fallback. */\ntype ResolveChannelMap<TName extends string> = TName extends keyof ChannelRegistry\n    ? ChannelRegistry[TName]\n    : Record<string, unknown>;\n\n// --- Type-level RPC utilities ---\n\n/** Detects whether a map entry is RPC-shaped ({ request, response }). */\ntype IsRpcTopic<T> = T extends { request: unknown; response: unknown } ? true : false;\n\n/**\n * Extracts pub/sub-only topic keys from a channel map.\n * For untyped maps (Record<string, unknown>), resolves to `string` so all topics are publishable.\n */\ntype PubSubTopics<TMap> = string extends keyof TMap\n    ? string\n    : { [K in keyof TMap]: IsRpcTopic<TMap[K]> extends true ? never : K }[keyof TMap];\n\n/**\n * Extracts RPC-capable topic keys from a channel map.\n * For untyped maps (Record<string, unknown>), resolves to `string` so all topics are requestable.\n */\ntype RpcTopics<TMap> = string extends keyof TMap\n    ? string\n    : { [K in keyof TMap]: IsRpcTopic<TMap[K]> extends true ? K : never }[keyof TMap];\n\n/** Extracts the request payload type from an RPC map entry. Falls back to T for non-RPC entries. */\ntype RequestPayload<T> = T extends { request: infer R } ? R : T;\n\n/** Extracts the response type from an RPC map entry. Falls back to unknown for non-RPC entries. */\ntype ResponsePayload<T> = T extends { response: infer S } ? S : unknown;\n\n/**\n * Unwraps RPC map entries to their request payload for subscriber type inference.\n * When a subscriber matches an RPC topic, they receive the request payload\n * (not the { request; response } map entry), because that's what flows on the channel.\n * Distributes over unions, so wildcard matches spanning both pub/sub and RPC topics work.\n */\ntype SubscribePayloadFor<T> = T extends { request: infer R } ? R : T;\n\n/** In-flight RPC response wrapper. Unpacked before resolving the caller's promise. */\ntype RpcResponse<T = unknown> =\n    | { success: true; payload: T }\n    | { success: false; payload: { message: string; code?: string } };\n\n/** Pending RPC entry in the correlation registry. */\ntype PendingRequest = {\n    resolve: (value: unknown) => void;\n    reject: (reason: unknown) => void;\n    timer: ReturnType<typeof setTimeout>;\n    onSettled?: () => void;\n};\n\n/** Default timeout for `request()` in milliseconds. */\nconst DEFAULT_REQUEST_TIMEOUT_MS = 5000;\n\n/**\n * Thrown when a `request()` call exceeds its timeout without receiving a response.\n *\n * Exposes `channel`, `topic`, and `timeout` so callers can inspect what timed out.\n */\nexport class PostalTimeoutError extends Error {\n    readonly channel: string;\n    readonly topic: string;\n    readonly timeout: number;\n\n    constructor(channel: string, topic: string, timeout: number) {\n        super(`Request to \"${channel}/${topic}\" timed out after ${timeout}ms`);\n        this.name = \"PostalTimeoutError\";\n        this.channel = channel;\n        this.topic = topic;\n        this.timeout = timeout;\n    }\n}\n\n/**\n * Thrown when an RPC handler throws and the error is relayed back to the requester.\n *\n * The original error's message is preserved. An optional `code` provides\n * machine-readable error classification for both in-memory and remote handlers.\n */\nexport class PostalRpcError extends Error {\n    readonly code?: string;\n\n    constructor(message: string, code?: string) {\n        super(message);\n        this.name = \"PostalRpcError\";\n        if (code !== undefined) {\n            this.code = code;\n        }\n    }\n}\n\n/**\n * Thrown when calling any method on a channel that has been disposed.\n *\n * Exposes the `channel` name so callers can identify which disposed\n * channel they're holding a stale reference to.\n */\nexport class PostalDisposedError extends Error {\n    readonly channel: string;\n\n    constructor(channel: string) {\n        super(`Channel \"${channel}\" has been disposed`);\n        this.name = \"PostalDisposedError\";\n        this.channel = channel;\n    }\n}\n\n/** Options for `channel.request()`. */\nexport type RequestOptions = {\n    /** Timeout in milliseconds. Defaults to 5000. */\n    timeout?: number;\n};\n\n/** Callback signature for message subscribers. Receives the full envelope. */\nexport type SubscriberCallback<TPayload = unknown> = (envelope: Envelope<TPayload>) => void;\n\n/** Internal record tracking a single subscription. */\ntype SubscriberRecord = {\n    pattern: string;\n    callback: SubscriberCallback<never>;\n};\n\n/**\n * A named, typed message channel.\n *\n * The optional `TMap` generic maps topic strings to their payload types.\n * Pub/sub topics use plain payload types. RPC topics use `{ request: X; response: Y }`.\n *\n * - `publish()` only accepts pub/sub topics (RPC topics excluded at compile time)\n * - `request()` and `handle()` only accept RPC topics\n * - `subscribe()` accepts any topic — RPC topics deliver the request payload\n *\n * Without a `TMap`, all payloads fall back to `unknown` and all methods accept any topic.\n */\nexport type Channel<TMap extends Record<string, unknown> = Record<string, unknown>> = {\n    /** The channel's name, as provided at creation time. Readable after dispose. */\n    readonly name: string;\n\n    /**\n     * Tear down this channel.\n     *\n     * Clears all subscribers and handlers, rejects pending RPC promises with\n     * `PostalDisposedError`, and removes this channel from the singleton registry.\n     * After disposal, calling `subscribe`, `publish`, `request`, or `handle`\n     * throws `PostalDisposedError`.\n     *\n     * Idempotent — calling dispose() on an already-disposed channel is a no-op.\n     * Unsubscribe/unhandle functions returned before disposal become silent no-ops.\n     */\n    dispose: () => void;\n\n    /**\n     * Subscribe to messages matching a topic pattern.\n     *\n     * The pattern can be an exact topic string or include AMQP-style\n     * wildcards (`*` for one segment, `#` for zero or more).\n     *\n     * @param pattern - Exact topic or wildcard pattern\n     * @param callback - Called with the full envelope for each matching publish or request\n     * @returns Unsubscribe function — safe to call multiple times\n     * @throws PostalDisposedError if the channel has been disposed\n     */\n    subscribe: <TPattern extends string>(\n        pattern: TPattern,\n        callback: SubscriberCallback<SubscribePayloadFor<PayloadFor<TMap, TPattern>>>\n    ) => () => void;\n\n    /**\n     * Publish a message to all subscribers whose patterns match the topic.\n     *\n     * Creates one envelope and delivers it to every matching subscriber.\n     * Subscribers run independently — if any throw, the rest still execute.\n     * Errors are collected and re-thrown as a single `AggregateError` after\n     * all subscribers have been called.\n     *\n     * RPC-shaped topics are excluded at compile time — use `request()` instead.\n     *\n     * @param topic - Exact topic string (no wildcards, no RPC topics)\n     * @param payload - Message payload, type-checked against TMap when provided\n     * @throws PostalDisposedError if the channel has been disposed\n     */\n    publish: <TTopic extends string & PubSubTopics<TMap>>(\n        topic: TTopic,\n        payload: TMap[TTopic]\n    ) => void;\n\n    /**\n     * Send a request and await a response from a registered handler.\n     *\n     * Creates a request envelope and publishes it through the channel like any\n     * other message. Regular subscribers see the request. A registered handler\n     * (via `handle()`) processes it and publishes a reply on the internal system\n     * channel. The reply resolves this Promise.\n     *\n     * Rejects with `PostalTimeoutError` if no response arrives in time.\n     * Rejects with `PostalRpcError` if the handler throws.\n     *\n     * @param topic - Exact topic string (must be an RPC-shaped topic in typed channels)\n     * @param payload - Request payload, extracted from the RPC map entry\n     * @param options - Request options (timeout, etc.)\n     * @returns Promise resolving with the handler's response\n     * @throws PostalDisposedError if the channel has been disposed\n     */\n    request: <TTopic extends string & RpcTopics<TMap>>(\n        topic: TTopic,\n        payload: RequestPayload<TMap[TTopic]>,\n        options?: RequestOptions\n    ) => Promise<ResponsePayload<TMap[TTopic]>>;\n\n    /**\n     * Register a responder for a request topic.\n     *\n     * The handler is registered as a specialized subscriber that only fires for\n     * `type: \"request\"` envelopes. Its return value (sync or async) is wrapped\n     * in a reply envelope and published on the internal system channel.\n     *\n     * If the handler throws, the error is wrapped in a `PostalRpcError` and\n     * relayed to the requester.\n     *\n     * Only one handler per topic per channel — registering a second handler\n     * for the same topic throws immediately.\n     *\n     * @param topic - Exact topic string (must be an RPC-shaped topic in typed channels)\n     * @param callback - Receives the request envelope, returns the response\n     * @returns Unhandle function — removes the handler, safe to call multiple times\n     * @throws PostalDisposedError if the channel has been disposed\n     */\n    handle: <TTopic extends string & RpcTopics<TMap>>(\n        topic: TTopic,\n        callback: (\n            envelope: Envelope<RequestPayload<TMap[TTopic]>>\n        ) => ResponsePayload<TMap[TTopic]> | Promise<ResponsePayload<TMap[TTopic]>>\n    ) => () => void;\n};\n\n/**\n * Extended channel type with internal dispatch method.\n * Not exported — used only for the system channel to deliver pre-built\n * reply envelopes without going through publish()'s envelope creation.\n */\ntype InternalChannel = Channel & {\n    dispatch: (envelope: Envelope) => void;\n};\n\n// --- Module-level RPC state ---\n\n/** Unique identifier for this postal instance. Used as the reply topic suffix. */\nlet instanceId = crypto.randomUUID();\n\n/**\n * Returns the current postal instance identifier.\n * Used by the transport layer to stamp outbound envelopes with their origin.\n * @internal\n */\nexport const getInstanceId = (): string => instanceId;\n\n/** Pending RPC promises keyed by correlationId. */\nlet pendingRequests = new Map<string, PendingRequest>();\n\n/** The internal system channel for RPC reply traffic. Not in the public registry. */\nlet systemChannel: InternalChannel;\n\n/** Unsubscribe function for the standing RPC reply subscription. */\nlet systemUnsub: (() => void) | null = null;\n\n// --- Outbound hook (transport integration) ---\n\n/** Called after every locally-originated dispatch so transports can broadcast. */\nlet outboundHook: ((envelope: Envelope) => void) | null = null;\n\n/**\n * Registers a callback that fires after every locally-originated dispatch.\n * Only one hook can be active — subsequent calls replace the previous.\n * Pass `null` to clear.\n * @internal Used by the transport layer.\n */\nexport const setOutboundHook = (hook: ((envelope: Envelope) => void) | null): void => {\n    outboundHook = hook;\n};\n\n// --- Wiretap (global bus observers) ---\n\n/** Registered wiretap callbacks. Cleared on resetChannels(). */\nconst wiretaps: ((envelope: Envelope) => void)[] = [];\n\n/** Notify all wiretaps. Errors are swallowed — observers must never affect dispatch. */\nconst notifyWiretaps = (envelope: Envelope): void => {\n    for (const tap of wiretaps) {\n        try {\n            tap(envelope);\n        } catch {\n            // Wiretaps are passive observers.\n        }\n    }\n};\n\n/**\n * Registers a global observer that sees every envelope flowing through the bus.\n *\n * Wiretaps fire for local publishes, requests, handler replies, and inbound\n * envelopes arriving from transports. Errors thrown by wiretaps are silently\n * swallowed — they must never affect message dispatch.\n *\n * @param callback - Called with the full envelope for every message\n * @returns Unsubscribe function (idempotent)\n */\nexport const addWiretap = (callback: (envelope: Envelope) => void): (() => void) => {\n    wiretaps.push(callback);\n\n    let removed = false;\n\n    return () => {\n        if (removed) {\n            return;\n        }\n        removed = true;\n\n        const index = wiretaps.indexOf(callback);\n        if (index !== -1) {\n            wiretaps.splice(index, 1);\n        }\n    };\n};\n\n/**\n * Removes all registered wiretaps.\n * Also called automatically during `resetChannels()`.\n */\nexport const resetWiretaps = (): void => {\n    wiretaps.splice(0, wiretaps.length);\n};\n\n// --- Reset hook (transport cleanup integration) ---\n\n/** Callbacks to invoke when resetChannels() is called. Persistent across resets. */\nconst resetCallbacks: (() => void)[] = [];\n\n/**\n * Registers a callback to run during resetChannels().\n * Returns a function that removes the callback.\n * @internal Used by the transport layer for cleanup.\n */\nexport const onReset = (callback: () => void): (() => void) => {\n    resetCallbacks.push(callback);\n    return () => {\n        const index = resetCallbacks.indexOf(callback);\n        if (index !== -1) {\n            resetCallbacks.splice(index, 1);\n        }\n    };\n};\n\n/**\n * Creates a new Channel instance.\n *\n * For singleton behavior (recommended), use `getChannel()` instead.\n * Not part of the public API — use `resetChannels()` for test isolation.\n *\n * @internal\n * @param name - The channel name\n * @returns A new Channel instance with no subscribers\n */\nexport const createChannel = <TMap extends Record<string, unknown> = Record<string, unknown>>(\n    name: string\n): Channel<TMap> => {\n    const subscribers: SubscriberRecord[] = [];\n    let disposed = false;\n\n    const ensureNotDisposed = (): void => {\n        if (disposed) {\n            throw new PostalDisposedError(name);\n        }\n    };\n\n    // Tracks correlation IDs from this channel's request() calls.\n    // Used during dispose to reject only this channel's pending RPCs.\n    const pendingCorrelationIds = new Set<string>();\n\n    // Shared dispatch core — delivers a pre-built envelope to matching subscribers.\n    // Returns collected errors so callers can decide how to handle them.\n    const dispatchEnvelope = (envelope: Envelope): unknown[] => {\n        const errors: unknown[] = [];\n\n        // Snapshot prevents mutation during iteration (e.g., unsubscribe-during-publish).\n        const snapshot = [...subscribers];\n\n        for (const sub of snapshot) {\n            if (matchTopic(sub.pattern, envelope.topic)) {\n                try {\n                    sub.callback(envelope as Envelope<never>);\n                } catch (err) {\n                    errors.push(err);\n                }\n            }\n        }\n\n        return errors;\n    };\n\n    const subscribe = <TPattern extends string>(\n        pattern: TPattern,\n        callback: SubscriberCallback<SubscribePayloadFor<PayloadFor<TMap, TPattern>>>\n    ): (() => void) => {\n        ensureNotDisposed();\n        const record: SubscriberRecord = {\n            pattern,\n            // The cast is safe — SubscriberRecord uses `never` as the payload type\n            // so it can hold callbacks of any payload type in the same array.\n            // The actual type safety comes from the Channel<TMap> generic on subscribe().\n            callback: callback as SubscriberCallback<never>,\n        };\n        subscribers.push(record);\n\n        // Unsubscribe by identity reference. indexOf returns -1 for an\n        // already-removed record, so calling this multiple times is a no-op.\n        return () => {\n            const index = subscribers.indexOf(record);\n            if (index !== -1) {\n                subscribers.splice(index, 1);\n            }\n        };\n    };\n\n    const publish = <TTopic extends string & PubSubTopics<TMap>>(\n        topic: TTopic,\n        payload: TMap[TTopic]\n    ): void => {\n        ensureNotDisposed();\n        const envelope = createEnvelope({\n            type: \"publish\",\n            channel: name,\n            topic,\n            payload,\n        });\n\n        const errors = dispatchEnvelope(envelope);\n        outboundHook?.(envelope);\n        notifyWiretaps(envelope);\n\n        if (errors.length > 0) {\n            throw new AggregateError(\n                errors,\n                `${errors.length} subscriber(s) threw during publish to \"${name}/${topic}\"`\n            );\n        }\n    };\n\n    // --- Request / Handle ---\n\n    // Tracks which topics have handlers registered. Enforces one handler per topic.\n    // The actual dispatch happens through the subscriber list via the wrapped callback.\n    const handlerTopics = new Set<string>();\n\n    const handle = <TTopic extends string & RpcTopics<TMap>>(\n        topic: TTopic,\n        callback: (\n            envelope: Envelope<RequestPayload<TMap[TTopic]>>\n        ) => ResponsePayload<TMap[TTopic]> | Promise<ResponsePayload<TMap[TTopic]>>\n    ): (() => void) => {\n        ensureNotDisposed();\n        if (handlerTopics.has(topic)) {\n            throw new Error(`Handler already registered for \"${topic}\" on channel \"${name}\"`);\n        }\n\n        handlerTopics.add(topic);\n\n        // Wrap the handler as a subscriber that only fires for request envelopes,\n        // captures the return value, and publishes a reply on the system channel.\n        const wrappedCallback: SubscriberCallback<never> = (envelope: Envelope<never>) => {\n            if (envelope.type !== \"request\") {\n                return;\n            }\n\n            const replyTo = envelope.replyTo;\n            const correlationId = envelope.correlationId;\n\n            if (!replyTo || !correlationId) {\n                return;\n            }\n\n            // Async IIFE — the handler may be sync or async, so we normalize.\n            // Errors are caught and published as RPC error responses rather than thrown.\n            (async () => {\n                try {\n                    const result = await (callback as (envelope: Envelope<never>) => unknown)(\n                        envelope\n                    );\n\n                    const replyEnvelope = createEnvelope({\n                        type: \"reply\" as const,\n                        channel: \"__postal__.system\",\n                        topic: replyTo,\n                        payload: { success: true, payload: result } as RpcResponse,\n                        correlationId,\n                    });\n\n                    systemChannel.dispatch(replyEnvelope);\n                    outboundHook?.(replyEnvelope);\n                    notifyWiretaps(replyEnvelope);\n                } catch (err) {\n                    const message = err instanceof Error ? err.message : String(err);\n                    const code = (err as { code?: string })?.code;\n\n                    const errorPayload: RpcResponse = {\n                        success: false,\n                        payload: code !== undefined ? { message, code } : { message },\n                    };\n\n                    const errorEnvelope = createEnvelope({\n                        type: \"reply\" as const,\n                        channel: \"__postal__.system\",\n                        topic: replyTo,\n                        payload: errorPayload,\n                        correlationId,\n                    });\n\n                    systemChannel.dispatch(errorEnvelope);\n                    outboundHook?.(errorEnvelope);\n                    notifyWiretaps(errorEnvelope);\n                }\n            })();\n        };\n\n        const record: SubscriberRecord = { pattern: topic, callback: wrappedCallback };\n        subscribers.push(record);\n\n        // Safe to call multiple times — delete/indexOf on missing entries are no-ops.\n        return () => {\n            handlerTopics.delete(topic);\n            const index = subscribers.indexOf(record);\n            if (index !== -1) {\n                subscribers.splice(index, 1);\n            }\n        };\n    };\n\n    const request = <TTopic extends string & RpcTopics<TMap>>(\n        topic: TTopic,\n        payload: RequestPayload<TMap[TTopic]>,\n        options: RequestOptions = {}\n    ): Promise<ResponsePayload<TMap[TTopic]>> => {\n        ensureNotDisposed();\n        const { timeout = DEFAULT_REQUEST_TIMEOUT_MS } = options;\n\n        const correlationId = crypto.randomUUID();\n        pendingCorrelationIds.add(correlationId);\n\n        const envelope = createEnvelope({\n            type: \"request\",\n            channel: name,\n            topic,\n            payload,\n            replyTo: `system.rpc.response.${instanceId}`,\n            correlationId,\n        });\n\n        return new Promise<ResponsePayload<TMap[TTopic]>>((resolve, reject) => {\n            const timer = setTimeout(() => {\n                pendingCorrelationIds.delete(correlationId);\n                pendingRequests.delete(correlationId);\n                reject(new PostalTimeoutError(name, topic, timeout));\n            }, timeout);\n\n            pendingRequests.set(correlationId, {\n                resolve: resolve as (value: unknown) => void,\n                reject,\n                timer,\n                onSettled: () => pendingCorrelationIds.delete(correlationId),\n            });\n\n            // Dispatch through the channel's subscriber list — regular subscribers\n            // AND the handler subscriber both see this envelope. Subscriber errors\n            // are collected but don't affect the RPC flow (the handler's reply is\n            // what resolves/rejects the promise).\n            dispatchEnvelope(envelope);\n            outboundHook?.(envelope);\n            notifyWiretaps(envelope);\n        });\n    };\n\n    const dispose = (): void => {\n        if (disposed) {\n            return;\n        }\n        disposed = true;\n\n        // Reject any pending RPC promises originating from this channel.\n        for (const correlationId of pendingCorrelationIds) {\n            const pending = pendingRequests.get(correlationId);\n            if (pending) {\n                clearTimeout(pending.timer);\n                pendingRequests.delete(correlationId);\n                pending.reject(new PostalDisposedError(name));\n            }\n        }\n        pendingCorrelationIds.clear();\n\n        subscribers.splice(0, subscribers.length);\n        handlerTopics.clear();\n\n        // Remove from the singleton registry if present.\n        // No-op for channels created directly via createChannel().\n        channels.delete(name);\n    };\n\n    // Internal dispatch — delivers a pre-built envelope to matching subscribers.\n    // Used by the system channel for RPC replies. Not exposed on the Channel type.\n    const dispatch = (envelope: Envelope): void => {\n        dispatchEnvelope(envelope);\n    };\n\n    // Extra `dispatch` and `dispose` properties are structurally invisible to\n    // the Channel<TMap> return type except for `dispose` which is declared.\n    // `dispatch` is accessible via InternalChannel for the system channel.\n    const channel = { name, dispose, subscribe, publish, request, handle, dispatch };\n    return channel;\n};\n\n// --- System Channel Initialization ---\n\n/**\n * Initializes (or re-initializes) the internal system channel for RPC reply traffic.\n * Called eagerly at module load and again after resetChannels().\n */\nconst initSystemChannel = (): void => {\n    // Cast is safe — createChannel() returns dispatch alongside other methods,\n    // but the Channel type doesn't declare it. InternalChannel adds it back.\n    systemChannel = createChannel(\"__postal__.system\") as unknown as InternalChannel;\n\n    systemUnsub = systemChannel.subscribe(\n        `system.rpc.response.${instanceId}`,\n        (envelope: Envelope) => {\n            const correlationId = envelope.correlationId;\n            if (!correlationId) {\n                return;\n            }\n\n            const pending = pendingRequests.get(correlationId);\n            if (!pending) {\n                // Reply for a request we don't know about — could be a duplicate\n                // or from a stale handler after reset. Safe to ignore.\n                return;\n            }\n\n            clearTimeout(pending.timer);\n            pending.onSettled?.();\n            pendingRequests.delete(correlationId);\n\n            const response = envelope.payload as RpcResponse;\n            if (response.success) {\n                pending.resolve(response.payload);\n            } else {\n                pending.reject(new PostalRpcError(response.payload.message, response.payload.code));\n            }\n        }\n    );\n};\n\n// Eager initialization — transports and cross-boundary audit subscriptions\n// need the system channel to exist before any RPC call happens.\ninitSystemChannel();\n\n// --- Channel Registry (singleton management) ---\n\n/** Module-level channel registry. Keyed by channel name. */\nconst channels = new Map<string, Channel>();\n\n/**\n * Gets or creates a singleton channel by name.\n *\n * The first call with a given name creates the channel. Subsequent calls\n * return the same instance. The type map generic is compile-time only —\n * all call sites referencing the same channel name should use the same map.\n *\n * Two ways to type a channel:\n *\n * 1. **Explicit type map** — pass `TMap` directly:\n *    ```ts\n *    const ch = getChannel<MyTopicMap>(\"orders\");\n *    ```\n *\n * 2. **Registry augmentation** — declare once, infer everywhere:\n *    ```ts\n *    declare module \"postal\" {\n *      interface ChannelRegistry { orders: MyTopicMap }\n *    }\n *    const ch = getChannel(\"orders\"); // MyTopicMap inferred\n *    ```\n *\n * @param name - The channel name (defaults to `\"__default__\"`)\n * @returns The singleton channel instance\n */\nexport function getChannel<TMap extends Record<string, unknown>>(name: string): Channel<TMap>;\nexport function getChannel<TName extends string = \"__default__\">(\n    name?: TName\n): Channel<ResolveChannelMap<TName>>;\nexport function getChannel(name: string = \"__default__\"): Channel {\n    let channel = channels.get(name);\n    if (!channel) {\n        channel = createChannel(name);\n        channels.set(name, channel);\n    }\n    return channel;\n}\n\n/**\n * Dispatches an externally-received envelope into the local bus.\n *\n * Routes by envelope type:\n * - `\"reply\"` → system channel (RPC reply resolution)\n * - `\"publish\"` / `\"request\"` → named channel in the registry\n *\n * Does NOT trigger the outbound hook — inbound envelopes stay local.\n * If the target channel doesn't exist locally, the envelope is silently dropped.\n *\n * @internal Used by the transport layer.\n */\nexport const dispatchInbound = (envelope: Envelope): void => {\n    if (envelope.type === \"reply\") {\n        systemChannel.dispatch(envelope);\n        return;\n    }\n\n    const channel = channels.get(envelope.channel) as InternalChannel | undefined;\n    if (channel) {\n        channel.dispatch(envelope);\n    }\n\n    notifyWiretaps(envelope);\n};\n\n/**\n * Clears the channel registry and all RPC state. Primarily useful for test isolation.\n *\n * Rejects pending RPC promises, tears down the system channel, regenerates the\n * instance GUID, and re-initializes a fresh system channel.\n */\nexport const resetChannels = (): void => {\n    // Notify reset listeners (e.g., transport layer cleanup) before\n    // tearing down channels they might reference.\n    // Snapshot prevents issues if a callback modifies the list during iteration.\n    const callbacks = [...resetCallbacks];\n    for (const cb of callbacks) {\n        cb();\n    }\n    outboundHook = null;\n    wiretaps.splice(0, wiretaps.length);\n\n    // Dispose each channel so stale references throw PostalDisposedError\n    // instead of silently working as detached orphans.\n    for (const channel of channels.values()) {\n        channel.dispose();\n    }\n    channels.clear();\n\n    // Safety sweep — reject any pending RPCs not owned by a registered channel.\n    // Shouldn't happen in practice, but prevents callers from hanging forever.\n    for (const [, pending] of pendingRequests) {\n        clearTimeout(pending.timer);\n        pending.reject(new Error(\"Channel registry reset while RPC request was pending\"));\n    }\n    pendingRequests = new Map();\n\n    // Tear down the old system channel subscription\n    if (systemUnsub) {\n        systemUnsub();\n        systemUnsub = null;\n    }\n\n    // Regenerate instance GUID so stale in-flight replies addressed\n    // to the old GUID are ignored by the new system channel.\n    instanceId = crypto.randomUUID();\n\n    // Re-initialize with the new GUID — system channel always exists.\n    initSystemChannel();\n};\n","/**\n * Global transport layer for bridging postal across execution boundaries.\n *\n * Transports are one-way pipes — postal publishes locally, transports\n * forward to remotes. Inbound envelopes are dispatched locally.\n * Echo prevention uses the Envelope `source` field: outbound stamps\n * `instanceId`, inbound skips if `source` matches the local instance.\n *\n * @module\n */\n\nimport type { Envelope } from \"./envelope\";\nimport { matchTopic } from \"./topicMatch\";\nimport { getInstanceId, setOutboundHook, dispatchInbound, onReset } from \"./channel\";\n\n// --- Public types ---\n\n/**\n * Metadata passed to `Transport.send()` by the core.\n *\n * Transports can use this to make send-time decisions that require context\n * the transport can't determine on its own. Currently carries `peerCount` so\n * a transport knows whether other transports are also receiving this envelope.\n *\n * Transports that don't need this can safely ignore it — the parameter is optional.\n */\nexport type TransportSendMeta = {\n    /**\n     * Number of transports that passed the filter for this envelope\n     * (including the current transport).\n     *\n     * A value of 1 means this transport is the sole recipient.\n     * A value > 1 means multiple transports are receiving the same envelope.\n     */\n    peerCount: number;\n};\n\n/**\n * A transport bridges postal across execution boundaries (iframes, workers, tabs).\n *\n * Implementers provide `send` (push envelopes to the remote) and `subscribe`\n * (receive envelopes from the remote). Postal handles the wiring — echo\n * prevention, filtering, and local dispatch are managed internally.\n */\nexport type Transport = {\n    /** Send an envelope to the remote side. */\n    send: (envelope: Envelope, meta?: TransportSendMeta) => void;\n    /** Listen for envelopes arriving from the remote side. Returns an unsubscribe function. */\n    subscribe: (callback: (envelope: Envelope) => void) => () => void;\n    /** Optional cleanup when the transport is removed or reset. */\n    dispose?: () => void;\n};\n\n/** Restricts which envelopes a transport forwards. */\nexport type TransportFilter = {\n    /** Only forward envelopes on these channels. Exact match. */\n    channels?: string[];\n    /** Only forward envelopes matching these topic patterns. Uses AMQP wildcard matching. */\n    topics?: string[];\n};\n\n/** Options when registering a transport. */\nexport type TransportOptions = {\n    /** Optional filter restricting which envelopes this transport forwards. */\n    filter?: TransportFilter;\n};\n\n// --- Internal state ---\n\ntype RegisteredTransport = {\n    transport: Transport;\n    filter?: TransportFilter;\n    unsubscribeInbound: () => void;\n};\n\nconst transports: RegisteredTransport[] = [];\n\n// --- Inbound deduplication (ring buffer) ---\n\nconst SEEN_CAPACITY = 500;\nlet seenIds: string[] = [];\nlet seenSet = new Set<string>();\nlet seenPtr = 0;\n\n/**\n * Returns `true` if this envelope ID was already seen (duplicate).\n * Tracks IDs in a fixed-size ring buffer — oldest entries are evicted\n * when the buffer is full, so they can be accepted again if they\n * somehow reappear (they won't — UUIDs don't repeat).\n */\nconst markSeen = (id: string): boolean => {\n    if (seenSet.has(id)) {\n        return true;\n    }\n\n    if (seenIds.length < SEEN_CAPACITY) {\n        seenIds.push(id);\n    } else {\n        seenSet.delete(seenIds[seenPtr]!);\n        seenIds[seenPtr] = id;\n    }\n\n    seenSet.add(id);\n    seenPtr = (seenPtr + 1) % SEEN_CAPACITY;\n\n    return false;\n};\n\nconst resetSeen = (): void => {\n    seenIds = [];\n    seenSet = new Set<string>();\n    seenPtr = 0;\n};\n\n// --- Filter ---\n\n/**\n * Tests whether an envelope passes a transport's filter.\n * Reply envelopes always pass — they complete an RPC round-trip\n * for a request that already matched on the way out.\n */\nconst passesFilter = (envelope: Envelope, filter?: TransportFilter): boolean => {\n    if (!filter) {\n        return true;\n    }\n\n    if (envelope.type === \"reply\") {\n        return true;\n    }\n\n    if (filter.channels && filter.channels.length > 0) {\n        if (!filter.channels.includes(envelope.channel)) {\n            return false;\n        }\n    }\n\n    if (filter.topics && filter.topics.length > 0) {\n        if (!filter.topics.some(pattern => matchTopic(pattern, envelope.topic))) {\n            return false;\n        }\n    }\n\n    return true;\n};\n\n// --- Outbound ---\n\n/**\n * Broadcasts an envelope to all registered transports that pass their filter.\n * Stamps each outbound copy with `source: instanceId` for echo prevention.\n *\n * Pre-filters into a list first so `peerCount` can be passed as meta —\n * some transports (e.g. MessagePort) use this to decide between zero-copy\n * transfer and structured clone when binary payloads are involved.\n */\nconst broadcastToTransports = (envelope: Envelope): void => {\n    if (transports.length === 0) {\n        return;\n    }\n\n    const source = getInstanceId();\n    const matching = transports.filter(entry => passesFilter(envelope, entry.filter));\n    const meta: TransportSendMeta = { peerCount: matching.length };\n\n    for (const entry of matching) {\n        // Shallow copy with source stamp — never mutate the original.\n        entry.transport.send({ ...envelope, source }, meta);\n    }\n};\n\n// --- Inbound ---\n\n/**\n * Creates an inbound handler for a transport subscription.\n * Performs echo prevention, then dispatches into the local bus.\n */\nconst createInboundHandler =\n    () =>\n    (envelope: Envelope): void => {\n        if (envelope.source === getInstanceId()) {\n            return;\n        }\n\n        if (markSeen(envelope.id)) {\n            return;\n        }\n\n        dispatchInbound(envelope);\n    };\n\n// --- Hook lifecycle ---\n\n/**\n * Wires or unwires the outbound hook based on whether any transports exist.\n * No overhead on publish when no transports are registered.\n */\nconst syncOutboundHook = (): void => {\n    setOutboundHook(transports.length > 0 ? broadcastToTransports : null);\n};\n\n// --- Public API ---\n\n/**\n * Registers a transport with postal.\n *\n * The transport will receive outbound envelopes (filtered by options) and\n * can inject inbound envelopes into the local bus. Returns a function\n * that removes this transport.\n *\n * @param transport - The transport to register\n * @param options - Optional filter configuration\n * @returns A remove function (idempotent)\n */\nexport const addTransport = (transport: Transport, options?: TransportOptions): (() => void) => {\n    const unsubscribeInbound = transport.subscribe(createInboundHandler());\n\n    const entry: RegisteredTransport = {\n        transport,\n        filter: options?.filter,\n        unsubscribeInbound,\n    };\n\n    transports.push(entry);\n    syncOutboundHook();\n\n    let removed = false;\n\n    return () => {\n        if (removed) {\n            return;\n        }\n        removed = true;\n\n        const index = transports.indexOf(entry);\n        if (index !== -1) {\n            transports.splice(index, 1);\n        }\n\n        unsubscribeInbound();\n        transport.dispose?.();\n        syncOutboundHook();\n    };\n};\n\n/**\n * Removes all registered transports and cleans up.\n * Called automatically during `resetChannels()` via the `onReset` hook.\n * Can also be called directly for transport-only teardown.\n */\nexport const resetTransports = (): void => {\n    const snapshot = [...transports];\n    transports.splice(0, transports.length);\n\n    for (const entry of snapshot) {\n        entry.unsubscribeInbound();\n        entry.transport.dispose?.();\n    }\n\n    resetSeen();\n    syncOutboundHook();\n};\n\n// Auto-cleanup when resetChannels() is called.\nonReset(resetTransports);\n"],"mappings":";;;;;;;;;;;;;;;;;;;;;AAmBA,MAAM,iBACF,iBACA,eACA,cACA,eACU;AAEV,KAAI,iBAAiB,gBAAgB,OACjC,QAAO,eAAe,cAAc;CAGxC,MAAM,UAAU,gBAAgB;AAIhC,KAAI,YAAY,KAAK;AACjB,OAAK,IAAI,WAAW,GAAG,YAAY,cAAc,SAAS,YAAY,WAClE,KACI,cACI,iBACA,eACA,eAAe,GACf,aAAa,SAChB,CAED,QAAO;AAGf,SAAO;;AAIX,KAAI,eAAe,cAAc,OAC7B,QAAO;AAGX,KAAI,YAAY,IACZ,QAAO,cAAc,iBAAiB,eAAe,eAAe,GAAG,aAAa,EAAE;AAI1F,QACI,YAAY,cAAc,eAC1B,cAAc,iBAAiB,eAAe,eAAe,GAAG,aAAa,EAAE;;;AAKvF,MAAM,wBAAQ,IAAI,KAAsB;;;;;;;;;;;;;;AAexC,MAAa,cAAc,SAAiB,UAA2B;AAEnE,KAAI,YAAY,MACZ,QAAO;CAIX,MAAM,MAAM,GAAG,QAAQ,IAAI;CAC3B,MAAM,SAAS,MAAM,IAAI,IAAI;AAC7B,KAAI,WAAW,OACX,QAAO;CAGX,MAAM,SAAS,cAAc,QAAQ,MAAM,IAAI,EAAE,MAAM,MAAM,IAAI,EAAE,GAAG,EAAE;AACxE,OAAM,IAAI,KAAK,OAAO;AACtB,QAAO;;;;;;;;;;;;;;;ACrCX,MAAa,kBAA4B,EACrC,MACA,SACA,OACA,SACA,QACA,SACA,oBACuD;CACvD,MAAM,WAA+B;EACjC,IAAI,OAAO,YAAY;EACvB;EACA;EACA;EACA;EACA,WAAW,KAAK,KAAK;EACxB;AAED,KAAI,WAAW,OACX,UAAS,SAAS;AAEtB,KAAI,YAAY,OACZ,UAAS,UAAU;AAEvB,KAAI,kBAAkB,OAClB,UAAS,gBAAgB;AAG7B,QAAO;;;;;;;;;;;;;;;;;;;;;;;ACSX,MAAM,6BAA6B;;;;;;AAOnC,IAAa,qBAAb,cAAwC,MAAM;CAC1C,AAAS;CACT,AAAS;CACT,AAAS;CAET,YAAY,SAAiB,OAAe,SAAiB;AACzD,QAAM,eAAe,QAAQ,GAAG,MAAM,oBAAoB,QAAQ,IAAI;AACtE,OAAK,OAAO;AACZ,OAAK,UAAU;AACf,OAAK,QAAQ;AACb,OAAK,UAAU;;;;;;;;;AAUvB,IAAa,iBAAb,cAAoC,MAAM;CACtC,AAAS;CAET,YAAY,SAAiB,MAAe;AACxC,QAAM,QAAQ;AACd,OAAK,OAAO;AACZ,MAAI,SAAS,OACT,MAAK,OAAO;;;;;;;;;AAWxB,IAAa,sBAAb,cAAyC,MAAM;CAC3C,AAAS;CAET,YAAY,SAAiB;AACzB,QAAM,YAAY,QAAQ,qBAAqB;AAC/C,OAAK,OAAO;AACZ,OAAK,UAAU;;;;AAgJvB,IAAI,aAAa,OAAO,YAAY;;;;;;AAOpC,MAAa,sBAA8B;;AAG3C,IAAI,kCAAkB,IAAI,KAA6B;;AAGvD,IAAI;;AAGJ,IAAI,cAAmC;;AAKvC,IAAI,eAAsD;;;;;;;AAQ1D,MAAa,mBAAmB,SAAsD;AAClF,gBAAe;;;AAMnB,MAAM,WAA6C,EAAE;;AAGrD,MAAM,kBAAkB,aAA6B;AACjD,MAAK,MAAM,OAAO,SACd,KAAI;AACA,MAAI,SAAS;SACT;;;;;;;;;;;;AAgBhB,MAAa,cAAc,aAAyD;AAChF,UAAS,KAAK,SAAS;CAEvB,IAAI,UAAU;AAEd,cAAa;AACT,MAAI,QACA;AAEJ,YAAU;EAEV,MAAM,QAAQ,SAAS,QAAQ,SAAS;AACxC,MAAI,UAAU,GACV,UAAS,OAAO,OAAO,EAAE;;;;;;;AASrC,MAAa,sBAA4B;AACrC,UAAS,OAAO,GAAG,SAAS,OAAO;;;AAMvC,MAAM,iBAAiC,EAAE;;;;;;AAOzC,MAAa,WAAW,aAAuC;AAC3D,gBAAe,KAAK,SAAS;AAC7B,cAAa;EACT,MAAM,QAAQ,eAAe,QAAQ,SAAS;AAC9C,MAAI,UAAU,GACV,gBAAe,OAAO,OAAO,EAAE;;;;;;;;;;;;;AAe3C,MAAa,iBACT,SACgB;CAChB,MAAM,cAAkC,EAAE;CAC1C,IAAI,WAAW;CAEf,MAAM,0BAAgC;AAClC,MAAI,SACA,OAAM,IAAI,oBAAoB,KAAK;;CAM3C,MAAM,wCAAwB,IAAI,KAAa;CAI/C,MAAM,oBAAoB,aAAkC;EACxD,MAAM,SAAoB,EAAE;EAG5B,MAAM,WAAW,CAAC,GAAG,YAAY;AAEjC,OAAK,MAAM,OAAO,SACd,KAAI,WAAW,IAAI,SAAS,SAAS,MAAM,CACvC,KAAI;AACA,OAAI,SAAS,SAA4B;WACpC,KAAK;AACV,UAAO,KAAK,IAAI;;AAK5B,SAAO;;CAGX,MAAM,aACF,SACA,aACe;AACf,qBAAmB;EACnB,MAAM,SAA2B;GAC7B;GAIU;GACb;AACD,cAAY,KAAK,OAAO;AAIxB,eAAa;GACT,MAAM,QAAQ,YAAY,QAAQ,OAAO;AACzC,OAAI,UAAU,GACV,aAAY,OAAO,OAAO,EAAE;;;CAKxC,MAAM,WACF,OACA,YACO;AACP,qBAAmB;EACnB,MAAM,WAAW,eAAe;GAC5B,MAAM;GACN,SAAS;GACT;GACA;GACH,CAAC;EAEF,MAAM,SAAS,iBAAiB,SAAS;AACzC,iBAAe,SAAS;AACxB,iBAAe,SAAS;AAExB,MAAI,OAAO,SAAS,EAChB,OAAM,IAAI,eACN,QACA,GAAG,OAAO,OAAO,0CAA0C,KAAK,GAAG,MAAM,GAC5E;;CAQT,MAAM,gCAAgB,IAAI,KAAa;CAEvC,MAAM,UACF,OACA,aAGe;AACf,qBAAmB;AACnB,MAAI,cAAc,IAAI,MAAM,CACxB,OAAM,IAAI,MAAM,mCAAmC,MAAM,gBAAgB,KAAK,GAAG;AAGrF,gBAAc,IAAI,MAAM;EAIxB,MAAM,mBAA8C,aAA8B;AAC9E,OAAI,SAAS,SAAS,UAClB;GAGJ,MAAM,UAAU,SAAS;GACzB,MAAM,gBAAgB,SAAS;AAE/B,OAAI,CAAC,WAAW,CAAC,cACb;AAKJ,IAAC,YAAY;AACT,QAAI;KAKA,MAAM,gBAAgB,eAAe;MACjC,MAAM;MACN,SAAS;MACT,OAAO;MACP,SAAS;OAAE,SAAS;OAAM,SARf,MAAO,SAClB,SACH;OAM8C;MAC3C;MACH,CAAC;AAEF,mBAAc,SAAS,cAAc;AACrC,oBAAe,cAAc;AAC7B,oBAAe,cAAc;aACxB,KAAK;KACV,MAAM,UAAU,eAAe,QAAQ,IAAI,UAAU,OAAO,IAAI;KAChE,MAAM,OAAQ,KAA2B;KAOzC,MAAM,gBAAgB,eAAe;MACjC,MAAM;MACN,SAAS;MACT,OAAO;MACP,SAT8B;OAC9B,SAAS;OACT,SAAS,SAAS,SAAY;QAAE;QAAS;QAAM,GAAG,EAAE,SAAS;OAChE;MAOG;MACH,CAAC;AAEF,mBAAc,SAAS,cAAc;AACrC,oBAAe,cAAc;AAC7B,oBAAe,cAAc;;OAEjC;;EAGR,MAAM,SAA2B;GAAE,SAAS;GAAO,UAAU;GAAiB;AAC9E,cAAY,KAAK,OAAO;AAGxB,eAAa;AACT,iBAAc,OAAO,MAAM;GAC3B,MAAM,QAAQ,YAAY,QAAQ,OAAO;AACzC,OAAI,UAAU,GACV,aAAY,OAAO,OAAO,EAAE;;;CAKxC,MAAM,WACF,OACA,SACA,UAA0B,EAAE,KACa;AACzC,qBAAmB;EACnB,MAAM,EAAE,UAAU,+BAA+B;EAEjD,MAAM,gBAAgB,OAAO,YAAY;AACzC,wBAAsB,IAAI,cAAc;EAExC,MAAM,WAAW,eAAe;GAC5B,MAAM;GACN,SAAS;GACT;GACA;GACA,SAAS,uBAAuB;GAChC;GACH,CAAC;AAEF,SAAO,IAAI,SAAwC,SAAS,WAAW;GACnE,MAAM,QAAQ,iBAAiB;AAC3B,0BAAsB,OAAO,cAAc;AAC3C,oBAAgB,OAAO,cAAc;AACrC,WAAO,IAAI,mBAAmB,MAAM,OAAO,QAAQ,CAAC;MACrD,QAAQ;AAEX,mBAAgB,IAAI,eAAe;IACtB;IACT;IACA;IACA,iBAAiB,sBAAsB,OAAO,cAAc;IAC/D,CAAC;AAMF,oBAAiB,SAAS;AAC1B,kBAAe,SAAS;AACxB,kBAAe,SAAS;IAC1B;;CAGN,MAAM,gBAAsB;AACxB,MAAI,SACA;AAEJ,aAAW;AAGX,OAAK,MAAM,iBAAiB,uBAAuB;GAC/C,MAAM,UAAU,gBAAgB,IAAI,cAAc;AAClD,OAAI,SAAS;AACT,iBAAa,QAAQ,MAAM;AAC3B,oBAAgB,OAAO,cAAc;AACrC,YAAQ,OAAO,IAAI,oBAAoB,KAAK,CAAC;;;AAGrD,wBAAsB,OAAO;AAE7B,cAAY,OAAO,GAAG,YAAY,OAAO;AACzC,gBAAc,OAAO;AAIrB,WAAS,OAAO,KAAK;;CAKzB,MAAM,YAAY,aAA6B;AAC3C,mBAAiB,SAAS;;AAO9B,QADgB;EAAE;EAAM;EAAS;EAAW;EAAS;EAAS;EAAQ;EAAU;;;;;;AAUpF,MAAM,0BAAgC;AAGlC,iBAAgB,cAAc,oBAAoB;AAElD,eAAc,cAAc,UACxB,uBAAuB,eACtB,aAAuB;EACpB,MAAM,gBAAgB,SAAS;AAC/B,MAAI,CAAC,cACD;EAGJ,MAAM,UAAU,gBAAgB,IAAI,cAAc;AAClD,MAAI,CAAC,QAGD;AAGJ,eAAa,QAAQ,MAAM;AAC3B,UAAQ,aAAa;AACrB,kBAAgB,OAAO,cAAc;EAErC,MAAM,WAAW,SAAS;AAC1B,MAAI,SAAS,QACT,SAAQ,QAAQ,SAAS,QAAQ;MAEjC,SAAQ,OAAO,IAAI,eAAe,SAAS,QAAQ,SAAS,SAAS,QAAQ,KAAK,CAAC;GAG9F;;AAKL,mBAAmB;;AAKnB,MAAM,2BAAW,IAAI,KAAsB;AA+B3C,SAAgB,WAAW,OAAe,eAAwB;CAC9D,IAAI,UAAU,SAAS,IAAI,KAAK;AAChC,KAAI,CAAC,SAAS;AACV,YAAU,cAAc,KAAK;AAC7B,WAAS,IAAI,MAAM,QAAQ;;AAE/B,QAAO;;;;;;;;;;;;;;AAeX,MAAa,mBAAmB,aAA6B;AACzD,KAAI,SAAS,SAAS,SAAS;AAC3B,gBAAc,SAAS,SAAS;AAChC;;CAGJ,MAAM,UAAU,SAAS,IAAI,SAAS,QAAQ;AAC9C,KAAI,QACA,SAAQ,SAAS,SAAS;AAG9B,gBAAe,SAAS;;;;;;;;AAS5B,MAAa,sBAA4B;CAIrC,MAAM,YAAY,CAAC,GAAG,eAAe;AACrC,MAAK,MAAM,MAAM,UACb,KAAI;AAER,gBAAe;AACf,UAAS,OAAO,GAAG,SAAS,OAAO;AAInC,MAAK,MAAM,WAAW,SAAS,QAAQ,CACnC,SAAQ,SAAS;AAErB,UAAS,OAAO;AAIhB,MAAK,MAAM,GAAG,YAAY,iBAAiB;AACvC,eAAa,QAAQ,MAAM;AAC3B,UAAQ,uBAAO,IAAI,MAAM,uDAAuD,CAAC;;AAErF,mCAAkB,IAAI,KAAK;AAG3B,KAAI,aAAa;AACb,eAAa;AACb,gBAAc;;AAKlB,cAAa,OAAO,YAAY;AAGhC,oBAAmB;;;;;ACxuBvB,MAAM,aAAoC,EAAE;AAI5C,MAAM,gBAAgB;AACtB,IAAI,UAAoB,EAAE;AAC1B,IAAI,0BAAU,IAAI,KAAa;AAC/B,IAAI,UAAU;;;;;;;AAQd,MAAM,YAAY,OAAwB;AACtC,KAAI,QAAQ,IAAI,GAAG,CACf,QAAO;AAGX,KAAI,QAAQ,SAAS,cACjB,SAAQ,KAAK,GAAG;MACb;AACH,UAAQ,OAAO,QAAQ,SAAU;AACjC,UAAQ,WAAW;;AAGvB,SAAQ,IAAI,GAAG;AACf,YAAW,UAAU,KAAK;AAE1B,QAAO;;AAGX,MAAM,kBAAwB;AAC1B,WAAU,EAAE;AACZ,2BAAU,IAAI,KAAa;AAC3B,WAAU;;;;;;;AAUd,MAAM,gBAAgB,UAAoB,WAAsC;AAC5E,KAAI,CAAC,OACD,QAAO;AAGX,KAAI,SAAS,SAAS,QAClB,QAAO;AAGX,KAAI,OAAO,YAAY,OAAO,SAAS,SAAS,GAC5C;MAAI,CAAC,OAAO,SAAS,SAAS,SAAS,QAAQ,CAC3C,QAAO;;AAIf,KAAI,OAAO,UAAU,OAAO,OAAO,SAAS,GACxC;MAAI,CAAC,OAAO,OAAO,MAAK,YAAW,WAAW,SAAS,SAAS,MAAM,CAAC,CACnE,QAAO;;AAIf,QAAO;;;;;;;;;;AAaX,MAAM,yBAAyB,aAA6B;AACxD,KAAI,WAAW,WAAW,EACtB;CAGJ,MAAM,SAAS,eAAe;CAC9B,MAAM,WAAW,WAAW,QAAO,UAAS,aAAa,UAAU,MAAM,OAAO,CAAC;CACjF,MAAM,OAA0B,EAAE,WAAW,SAAS,QAAQ;AAE9D,MAAK,MAAM,SAAS,SAEhB,OAAM,UAAU,KAAK;EAAE,GAAG;EAAU;EAAQ,EAAE,KAAK;;;;;;AAU3D,MAAM,8BAED,aAA6B;AAC1B,KAAI,SAAS,WAAW,eAAe,CACnC;AAGJ,KAAI,SAAS,SAAS,GAAG,CACrB;AAGJ,iBAAgB,SAAS;;;;;;AASjC,MAAM,yBAA+B;AACjC,iBAAgB,WAAW,SAAS,IAAI,wBAAwB,KAAK;;;;;;;;;;;;;AAgBzE,MAAa,gBAAgB,WAAsB,YAA6C;CAC5F,MAAM,qBAAqB,UAAU,UAAU,sBAAsB,CAAC;CAEtE,MAAM,QAA6B;EAC/B;EACA,QAAQ,SAAS;EACjB;EACH;AAED,YAAW,KAAK,MAAM;AACtB,mBAAkB;CAElB,IAAI,UAAU;AAEd,cAAa;AACT,MAAI,QACA;AAEJ,YAAU;EAEV,MAAM,QAAQ,WAAW,QAAQ,MAAM;AACvC,MAAI,UAAU,GACV,YAAW,OAAO,OAAO,EAAE;AAG/B,sBAAoB;AACpB,YAAU,WAAW;AACrB,oBAAkB;;;;;;;;AAS1B,MAAa,wBAA8B;CACvC,MAAM,WAAW,CAAC,GAAG,WAAW;AAChC,YAAW,OAAO,GAAG,WAAW,OAAO;AAEvC,MAAK,MAAM,SAAS,UAAU;AAC1B,QAAM,oBAAoB;AAC1B,QAAM,UAAU,WAAW;;AAG/B,YAAW;AACX,mBAAkB;;AAItB,QAAQ,gBAAgB"}