{"version":3,"sources":["../src/domain/errors.ts","../src/application/message-dispatcher.ts","../src/utils/async.ts","../src/domain/chat.ts","../src/domain/timestamp.ts","../src/domain/chat-id.ts","../src/infra/db/contract.ts","../src/infra/db/macos26.ts","../src/domain/attachment.ts","../src/domain/message.ts","../src/domain/reaction.ts","../src/domain/service.ts","../src/infra/db/body-decoder.ts","../src/infra/db/mapper.ts","../src/infra/db/sqlite-adapter.ts","../src/infra/db/reader.ts","../src/infra/db/watcher.ts","../src/domain/routing.ts","../src/domain/validate.ts","../src/infra/platform.ts","../src/domain/messages-app.ts","../src/infra/outgoing/applescript-builder.ts","../src/infra/outgoing/applescript-transport.ts","../src/infra/outgoing/sender.ts","../src/infra/outgoing/temp-files.ts","../src/infra/plugin.ts","../src/sdk-bounds.ts","../src/sdk.ts","../src/infra/attachments.ts"],"names":["resolve","release","Unarchiver","NSAttributedString","homedir","join","basename","require","createRequire","watch","dirname","statSync","promisify","execFile","spawn","path","existsSync","readdirSync","lstatSync","rmSync","access","extname"],"mappings":"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","file":"index.cjs","sourcesContent":["/**\n * Unified error type, factory functions, and normalization utilities.\n *\n * Prefer factory functions over `new IMessageError` so the error code\n * always matches the intent.\n */\n\n// -----------------------------------------------\n// Types\n// -----------------------------------------------\n\nexport type ErrorCode = 'PLATFORM' | 'DATABASE' | 'SEND' | 'CONFIG'\n\n// -----------------------------------------------\n// Error class\n// -----------------------------------------------\n\nexport class IMessageError extends Error {\n    readonly code: ErrorCode\n\n    constructor(code: ErrorCode, message: string, options?: ErrorOptions) {\n        super(message, options)\n        this.code = code\n        this.name = 'IMessageError'\n\n        if (Error.captureStackTrace) {\n            Error.captureStackTrace(this, IMessageError)\n        }\n    }\n}\n\n// -----------------------------------------------\n// Factory functions\n// -----------------------------------------------\n\nexport function PlatformError(message = 'Only macOS is supported', cause?: unknown): IMessageError {\n    return new IMessageError('PLATFORM', message, { cause })\n}\n\nexport function DatabaseError(message: string, cause?: unknown): IMessageError {\n    return new IMessageError('DATABASE', message, { cause })\n}\n\nexport function SendError(message: string, cause?: unknown): IMessageError {\n    return new IMessageError('SEND', message, { cause })\n}\n\nexport function ConfigError(message: string, cause?: unknown): IMessageError {\n    return new IMessageError('CONFIG', message, { cause })\n}\n\n// -----------------------------------------------\n// Normalization utilities\n// -----------------------------------------------\n\n/** Normalize an unknown caught value to an Error instance. */\nexport function toError(value: unknown): Error {\n    return value instanceof Error ? value : new Error(String(value))\n}\n\n/** Extract a human-readable message from an unknown caught value. */\nexport function toErrorMessage(value: unknown): string {\n    return value instanceof Error ? value.message : String(value)\n}\n","/**\n * Incoming message dispatcher.\n *\n * Routes batches of messages from the watch source to user callbacks\n * and plugin sinks.\n */\n\nimport { toError } from '../domain/errors'\nimport type { Message } from '../domain/message'\n\n// -----------------------------------------------\n// Port interfaces\n// -----------------------------------------------\n\n/**\n * Forwards observed messages to plugin hooks.\n *\n * Satisfied by infra's plugin manager via structural typing.\n *\n * - `onIncomingMessage` receives incoming (non-from-me) messages.\n * - `onFromMe` receives from-me messages the watcher observed in the DB,\n *   regardless of origin (this SDK, other clients, Messages.app UI).\n */\nexport interface MessageSink {\n    onIncomingMessage(message: Message): Promise<void>\n    onFromMe(message: Message): Promise<void>\n    onError(error: Error, context: string): void\n}\n\n// -----------------------------------------------\n// Types\n// -----------------------------------------------\n\n/** Callback for handling a single message. */\nexport type MessageCallback = (message: Message) => void | Promise<void>\n\n/** User-provided event handlers for watcher-observed messages. */\nexport interface DispatchEvents {\n    /** Called for every incoming (non-from-me) message. */\n    readonly onIncomingMessage?: MessageCallback\n    /** Called for incoming direct (1-on-1) messages. */\n    readonly onDirectMessage?: MessageCallback\n    /** Called for incoming group messages. */\n    readonly onGroupMessage?: MessageCallback\n    /**\n     * Called for every from-me message observed in the database, regardless\n     * of origin (this SDK, other Apple clients, Messages.app UI).\n     *\n     * This is the authoritative source of \"my send landed in chat.db\" —\n     * `sdk.send()` itself resolves on AppleScript dispatch and does not\n     * wait for a chat.db row.\n     */\n    readonly onFromMeMessage?: MessageCallback\n    /** Called when dispatch encounters an error. */\n    readonly onError?: (error: Error) => void\n}\n\n/** Dispatcher construction options. */\nexport interface DispatchOptions {\n    readonly events?: DispatchEvents\n    readonly sink?: MessageSink\n    readonly debug?: boolean\n}\n\n// -----------------------------------------------\n// Dispatcher\n// -----------------------------------------------\n\nexport class MessageDispatcher {\n    private readonly events: DispatchEvents\n    private readonly sink?: MessageSink\n    private readonly debug: boolean\n\n    constructor(options: DispatchOptions = {}) {\n        this.events = options.events ?? {}\n        this.sink = options.sink\n        this.debug = options.debug ?? false\n    }\n\n    /**\n     * Process a batch of messages from the watch source.\n     *\n     * Pipeline: partition by `isFromMe` → dispatch each branch in parallel.\n     * Within a branch, messages are processed sequentially so ordering\n     * inside the user's callback is preserved; the two branches are\n     * independent, so a slow from-me handler never blocks incoming\n     * delivery (and vice-versa).\n     *\n     * Serialization of batches is the watcher's contract — the consumer loop\n     * awaits one dispatch before producing the next batch.\n     */\n    async dispatch(messages: readonly Message[]): Promise<void> {\n        const incoming: Message[] = []\n        const fromMe: Message[] = []\n        for (const message of messages) {\n            if (message.isFromMe) fromMe.push(message)\n            else incoming.push(message)\n        }\n\n        await Promise.all([this.dispatchIncoming(incoming), this.dispatchFromMe(fromMe)])\n    }\n\n    /** Forward an external error to the sink and user callback. */\n    handleError(error: unknown, context: string): void {\n        const err = toError(error)\n\n        if (this.debug) {\n            console.error(`[MessageDispatcher] ${context}:`, err)\n        }\n\n        this.sink?.onError(err, context)\n        this.events.onError?.(err)\n    }\n\n    // -----------------------------------------------\n    // Internal\n    // -----------------------------------------------\n\n    private async dispatchIncoming(messages: readonly Message[]): Promise<void> {\n        for (const message of messages) {\n            try {\n                await this.dispatchOneIncoming(message)\n            } catch (error) {\n                this.handleError(error, 'dispatch-message')\n            }\n        }\n    }\n\n    private async dispatchOneIncoming(message: Message): Promise<void> {\n        await this.sink?.onIncomingMessage(message)\n        await this.events.onIncomingMessage?.(message)\n\n        switch (message.chatKind) {\n            case 'group':\n                await this.events.onGroupMessage?.(message)\n                break\n\n            case 'dm':\n                await this.events.onDirectMessage?.(message)\n                break\n\n            case 'unknown':\n                // No routing assumption for unknown chat kinds\n                break\n        }\n    }\n\n    private async dispatchFromMe(messages: readonly Message[]): Promise<void> {\n        for (const message of messages) {\n            try {\n                await this.sink?.onFromMe(message)\n                await this.events.onFromMeMessage?.(message)\n            } catch (error) {\n                this.handleError(error, 'dispatch-from-me')\n            }\n        }\n    }\n}\n","/**\n * Async control flow utilities.\n *\n * Delay, retry with exponential backoff, and concurrency limiting.\n */\n\n// -----------------------------------------------\n// Delay\n// -----------------------------------------------\n\n/** Delay for the specified milliseconds. Supports AbortSignal cancellation. */\nexport function delay(ms: number, signal?: AbortSignal): Promise<void> {\n    return new Promise<void>((resolve, reject) => {\n        if (signal?.aborted) {\n            reject(signal.reason ?? new Error('Aborted'))\n            return\n        }\n\n        const cleanup = () => {\n            clearTimeout(id)\n            signal?.removeEventListener('abort', onAbort)\n        }\n\n        const onAbort = () => {\n            cleanup()\n            reject(signal?.reason ?? new Error('Aborted'))\n        }\n\n        const id = setTimeout(() => {\n            cleanup()\n            resolve()\n        }, ms)\n\n        signal?.addEventListener('abort', onAbort, { once: true })\n    })\n}\n\n// -----------------------------------------------\n// Retry\n// -----------------------------------------------\n\nexport interface RetryOptions {\n    /** Maximum number of attempts (default: 3). */\n    readonly attempts?: number\n    /** Base delay in ms between retries (default: 1000). */\n    readonly delay?: number\n    /** Use exponential backoff (default: true). */\n    readonly backoff?: boolean\n    /** Maximum delay cap in ms (default: 30000). */\n    readonly maxDelay?: number\n    /** AbortSignal for cancellation. */\n    readonly signal?: AbortSignal\n}\n\n/**\n * Retry an async operation with exponential backoff and full jitter.\n *\n * Throws the last error if all attempts fail.\n */\nexport async function retry<T>(fn: () => Promise<T>, options: RetryOptions = {}): Promise<T> {\n    const attempts = Math.max(1, Math.trunc(options.attempts ?? 3))\n    const baseDelay = Math.max(0, options.delay ?? 1_000)\n    const backoff = options.backoff ?? true\n    const maxDelay = Math.max(baseDelay, options.maxDelay ?? 30_000)\n    const { signal } = options\n\n    let lastError: Error | undefined\n\n    for (let attempt = 0; attempt < attempts; attempt++) {\n        if (signal?.aborted) throw signal.reason ?? new Error('Aborted')\n\n        try {\n            return await fn()\n        } catch (err) {\n            lastError = err instanceof Error ? err : new Error(String(err))\n\n            // If the caller aborted, surface the abort reason — not the\n            // fn's internal error — so callers can distinguish cancellation\n            // from a genuine fn failure.\n            if (signal?.aborted) throw signal.reason ?? new Error('Aborted')\n\n            if (attempt < attempts - 1) {\n                const exponential = backoff ? baseDelay * 2 ** attempt : baseDelay\n                const capped = Math.min(exponential, maxDelay)\n                await delay(Math.random() * capped, signal)\n            }\n        }\n    }\n\n    throw lastError\n}\n\n// -----------------------------------------------\n// Semaphore\n// -----------------------------------------------\n\n/** Limits concurrent async operations. */\nexport class Semaphore {\n    private running = 0\n    private readonly waiting: Array<() => void> = []\n\n    constructor(private readonly limit: number) {\n        if (limit <= 0) throw new Error('Concurrency limit must be greater than 0')\n    }\n\n    /**\n     * Acquire a slot. Returns a release function.\n     *\n     * Slot-transfer semantics guarantee strict FIFO fairness:\n     * a waiter that is woken up has had the slot handed to it directly,\n     * so there is no re-check race where a late-arriving caller could\n     * jump ahead. The release function either transfers the slot to the\n     * next waiter (running unchanged) or decrements the counter.\n     */\n    async acquire(signal?: AbortSignal): Promise<() => void> {\n        if (signal?.aborted) throw signal.reason ?? new Error('Aborted')\n\n        if (this.running >= this.limit) {\n            await new Promise<void>((resolve, reject) => {\n                const onAbort = () => {\n                    const idx = this.waiting.indexOf(wrappedResolve)\n                    if (idx !== -1) this.waiting.splice(idx, 1)\n                    reject(signal?.reason ?? new Error('Aborted'))\n                }\n\n                const wrappedResolve = () => {\n                    signal?.removeEventListener('abort', onAbort)\n                    resolve()\n                }\n\n                signal?.addEventListener('abort', onAbort, { once: true })\n                this.waiting.push(wrappedResolve)\n            })\n            // Woken == slot was handed to us by a releaser; do not ++running.\n        } else {\n            this.running++\n        }\n\n        let released = false\n        return () => {\n            if (released) return\n            released = true\n            const next = this.waiting.shift()\n            if (next) {\n                next() // Transfer slot to next waiter; running stays the same.\n            } else {\n                this.running--\n            }\n        }\n    }\n\n    /** Execute fn within a concurrency slot. */\n    async run<T>(fn: () => Promise<T>, signal?: AbortSignal): Promise<T> {\n        const release = await this.acquire(signal)\n\n        try {\n            return await fn()\n        } finally {\n            release()\n        }\n    }\n}\n","/**\n * iMessage chat (conversation) model.\n *\n * Chat style values (`chat.style`):\n *\n *   43  (ASCII '+')  group chat\n *   45  (ASCII '-')  DM (1-on-1) chat\n */\n\nimport type { Service } from './service'\n\n// -----------------------------------------------\n// Types\n// -----------------------------------------------\n\n/** Normalized chat kind derived from `chat.style`. */\nexport type ChatKind = 'dm' | 'group' | 'unknown'\n\n/** Chat summary. */\nexport interface Chat {\n    /** Normalized chat id suitable for routing and matching. */\n    readonly chatId: string\n\n    /** User-visible display name. */\n    readonly name: string | null\n\n    /** Transport used by the chat when known. */\n    readonly service: Service | null\n\n    /** Normalized chat kind. */\n    readonly kind: ChatKind\n\n    /** Account login associated with the chat when known. */\n    readonly account: string | null\n\n    /** Chat is archived. */\n    readonly isArchived: boolean\n\n    /** Chat is in the filtered / unknown-senders bucket. */\n    readonly isFiltered: boolean\n\n    /** Incoming messages are silently dropped for this chat. */\n    readonly dropsIncomingMessages: boolean\n\n    /** Incoming messages are automatically deleted. */\n    readonly autoDeletesIncomingMessages: boolean\n\n    /** Last read timestamp for the chat. */\n    readonly lastReadAt: Date | null\n\n    /** Number of unread incoming messages. */\n    readonly unreadCount: number\n\n    /** Timestamp of the most recent message in the chat. */\n    readonly lastMessageAt: Date | null\n}\n\n// -----------------------------------------------\n// Constants\n// -----------------------------------------------\n\n/** `chat.style` value for group chats (ASCII '+' = 43). */\nexport const CHAT_STYLE_GROUP = 43\n\n/** `chat.style` value for DM chats (ASCII '-' = 45). */\nexport const CHAT_STYLE_DM = 45\n\n// -----------------------------------------------\n// Resolution\n// -----------------------------------------------\n\n/** Resolve `chat.style` to a typed ChatKind. */\nexport function resolveChatKind(style: number | null): ChatKind {\n    switch (style) {\n        case CHAT_STYLE_GROUP:\n            return 'group'\n\n        case CHAT_STYLE_DM:\n            return 'dm'\n\n        default:\n            return 'unknown'\n    }\n}\n","/**\n * macOS timestamp conversion.\n *\n * Messages database stores timestamps as nanoseconds since 2001-01-01T00:00:00Z.\n */\n\n// -----------------------------------------------\n// Constants\n// -----------------------------------------------\n\n/** macOS epoch (2001-01-01T00:00:00Z) in milliseconds since Unix epoch. */\nexport const MAC_EPOCH = new Date('2001-01-01T00:00:00Z').getTime()\n\n// -----------------------------------------------\n// Conversion\n// -----------------------------------------------\n\n/**\n * Convert a JS Date to a macOS nanosecond timestamp.\n *\n * Returned as a `number`. The 2001-01-01 epoch means `Number.MAX_SAFE_INTEGER`\n * is exceeded after ~104 days (≈ April 2001), so precision below ~100 ns is\n * lost for any real-world date. Millisecond-level precision — the resolution\n * of `Date` itself — is always preserved, which is sufficient for chat.db\n * WHERE comparisons.\n */\nexport function toMacTimestampNs(date: Date): number {\n    return (date.getTime() - MAC_EPOCH) * 1_000_000\n}\n\n/**\n * Convert a macOS nanosecond timestamp to a JS Date.\n *\n * Sub-millisecond precision is lost because `Date` is millisecond-resolution.\n */\nexport function fromMacTimestampNs(ns: number): Date {\n    return new Date(MAC_EPOCH + ns / 1_000_000)\n}\n","/**\n * ChatId value object.\n *\n * Parses, normalizes, validates, and matches iMessage chat identifiers.\n *\n * Supported formats:\n *\n *   service;+;guid        group chat       (iMessage;+;chat613…, any;+;chat687…)\n *   service;-;address     direct message   (iMessage;-;+1234567890)\n *   chat<id>              bare group GUID  (chat61321855167474084)\n *   bare address          DM recipient     (+1234567890, user@example.com, …)\n */\n\nimport { ConfigError } from './errors'\n\n// -----------------------------------------------\n// Types\n// -----------------------------------------------\n\n/**\n * Known chat service prefixes.\n *\n * Accepts any well-formed token for forward compatibility.\n */\nexport type ChatServicePrefix = 'iMessage' | 'SMS' | 'RCS' | 'any' | (string & {})\n\n// -----------------------------------------------\n// Constants\n// -----------------------------------------------\n\nconst GROUP_SEPARATOR = ';+;'\nconst DM_SEPARATOR = ';-;'\n\nconst CHAT_SERVICE_PREFIX_PATTERN = /^[A-Za-z][A-Za-z0-9._-]*$/\n\n/**\n * Bare Messages.app chat GUID: the literal prefix `chat` followed by at least\n * one ASCII alphanumeric or hyphen (`chat61321855167474084`, `chat687E84CA-…`).\n *\n * The trailing `+` rejects the 4-character string `\"chat\"` alone, and email\n * addresses starting with \"chat\" (e.g. `chatbot@openai.com`) fail because `@`\n * and `.` are not in the body character class.\n */\nconst BARE_GROUP_GUID_PATTERN = /^chat[A-Za-z0-9-]+$/\n\n// -----------------------------------------------\n// Helpers\n// -----------------------------------------------\n\n/**\n * Parse and validate a service prefix string.\n *\n * Returns the prefix if well-formed, or `null` if invalid.\n */\nexport function parseChatServicePrefix(value: string | null | undefined): ChatServicePrefix | null {\n    if (value == null || value === '') return null\n\n    return CHAT_SERVICE_PREFIX_PATTERN.test(value) ? (value as ChatServicePrefix) : null\n}\n\nfunction isValidPrefixedFormat(raw: string, separator: string): boolean {\n    const index = raw.indexOf(separator)\n\n    if (index === -1) return false\n\n    const prefix = raw.slice(0, index)\n    const suffix = raw.slice(index + separator.length)\n\n    return parseChatServicePrefix(prefix) != null && suffix !== ''\n}\n\n// -----------------------------------------------\n// Value object\n// -----------------------------------------------\n\nexport class ChatId {\n    /** The raw chat identifier string. */\n    readonly raw: string\n\n    /** Whether this identifies a group conversation. */\n    readonly isGroup: boolean\n\n    private constructor(raw: string, isGroup: boolean) {\n        this.raw = raw\n        this.isGroup = isGroup\n    }\n\n    // -----------------------------------------------\n    // Factory methods\n    // -----------------------------------------------\n\n    /**\n     * Construct from a raw identifier string. Whitespace is trimmed —\n     * the name signals the input may be untrusted.\n     */\n    static fromUserInput(raw: string): ChatId {\n        const trimmed = raw.trim()\n        return new ChatId(trimmed, ChatId.detectGroup(trimmed))\n    }\n\n    /** Construct a DM chat id from a recipient address and optional service prefix. */\n    static fromDMRecipient(recipient: string, prefix: ChatServicePrefix = 'iMessage'): ChatId {\n        return new ChatId(`${prefix}${DM_SEPARATOR}${recipient}`, false)\n    }\n\n    // -----------------------------------------------\n    // Computed properties\n    // -----------------------------------------------\n\n    /**\n     * Core identifier with all service prefixes stripped.\n     *\n     *   iMessage;-;pilot@photon.codes  →  pilot@photon.codes\n     *   iMessage;+;chat613ABF          →  chat613ABF\n     *   chat613ABF                     →  chat613ABF\n     */\n    get coreIdentifier(): string {\n        return this.extractAfter(GROUP_SEPARATOR) ?? this.extractAfter(DM_SEPARATOR) ?? this.raw\n    }\n\n    // -----------------------------------------------\n    // Methods\n    // -----------------------------------------------\n\n    /**\n     * Extract the recipient address from a `service;-;address` DM chat id.\n     *\n     * Returns `null` for any other form (bare address, group, etc.).\n     */\n    extractRecipient(): string | null {\n        return this.extractAfter(DM_SEPARATOR)\n    }\n\n    /**\n     * Validate the chat id format.\n     *\n     * Throws `IMessageError` (code `CONFIG`) for malformed inputs. Accepts the\n     * three documented formats: `service;+;guid`, `service;-;address`, and any\n     * non-empty bare identifier (no semicolons).\n     */\n    validate(): void {\n        if (this.raw.trim() === '') {\n            throw ConfigError('ChatId cannot be empty')\n        }\n\n        if (!this.raw.includes(';')) return\n\n        if (isValidPrefixedFormat(this.raw, GROUP_SEPARATOR) || isValidPrefixedFormat(this.raw, DM_SEPARATOR)) {\n            return\n        }\n\n        throw ConfigError(`Malformed chat id: \"${this.raw}\" (expected service;+;guid or service;-;address)`)\n    }\n\n    /**\n     * Build a full Messages.app guid with a service prefix.\n     *\n     *   chat613ABF + `iMessage`  →  iMessage;+;chat613ABF\n     *\n     * Group-only: throws `IMessageError` (code `CONFIG`) on DM instances —\n     * calling on a DM would produce a malformed id like `any;+;+1234567890`.\n     */\n    buildGroupGuid(prefix: ChatServicePrefix): string {\n        if (!this.isGroup) {\n            throw ConfigError(`buildGroupGuid is group-only; \"${this.raw}\" is not a group chat id`)\n        }\n        return `${prefix}${GROUP_SEPARATOR}${this.coreIdentifier}`\n    }\n\n    toString(): string {\n        return this.raw\n    }\n\n    // -----------------------------------------------\n    // Internal\n    // -----------------------------------------------\n\n    /**\n     * Extract everything after the first occurrence of separator, or `null`\n     * if the separator is absent OR the suffix is empty (e.g. `iMessage;-;`).\n     * Empty-suffix inputs are malformed; treating them as \"not found\" keeps\n     * callers from receiving `\"\"` as if it were a valid identifier.\n     */\n    private extractAfter(separator: string): string | null {\n        const index = this.raw.indexOf(separator)\n\n        if (index === -1) return null\n\n        const suffix = this.raw.slice(index + separator.length)\n        return suffix === '' ? null : suffix\n    }\n\n    private static detectGroup(raw: string): boolean {\n        if (raw.includes(GROUP_SEPARATOR)) return true\n\n        if (!raw.includes(';') && BARE_GROUP_GUID_PATTERN.test(raw)) return true\n\n        return false\n    }\n}\n","/**\n * Port between `reader.ts` and schema-specific query builders.\n *\n * Defines the SQL execution primitives, the `MessagesDbQueries` adapter\n * contract (implemented per macOS version — currently `macos26.ts`), the\n * reader→adapter input shapes, and the cross-version chat-id match helper.\n */\n\nimport { ChatId } from '../../domain/chat-id'\nimport type { ChatQuery, MessageQuery } from '../../types/query'\n\n// -----------------------------------------------\n// SQL primitives\n// -----------------------------------------------\n\nexport type QueryParam = string | number\n\n/** A parameterised SQL query ready for execution. */\nexport interface SqlQuery {\n    readonly sql: string\n    readonly params: readonly QueryParam[]\n}\n\n/** Function that executes a SQL query and returns raw rows. */\nexport type QueryExecutor = (sql: string, params?: readonly QueryParam[]) => Array<Record<string, unknown>>\n\n// -----------------------------------------------\n// Query input types\n// -----------------------------------------------\n\n// Input forms feed the reader→adapter boundary. They extend the public\n// query DTOs in two different directions:\n//   - add internal cursor fields the public API must not expose (MessageQueryInput)\n//   - narrow optional fields to required once the reader has applied defaults,\n//     so the builder can skip `undefined` handling (ChatQueryInput)\n\n/** `MessageQuery` plus internal cursor fields used by the watcher. */\nexport interface MessageQueryInput extends MessageQuery {\n    readonly sinceRowId?: number\n    readonly orderByRowIdAsc?: boolean\n}\n\n/**\n * `ChatQuery` with `sortBy` defaulted by the reader so the builder can skip\n * its `undefined` check. `kind` stays optional — `undefined` means \"both\n * kinds\" and the builder simply omits the filter, with no pseudo-`'all'`\n * sentinel in the type.\n */\nexport interface ChatQueryInput extends ChatQuery {\n    readonly sortBy: NonNullable<ChatQuery['sortBy']>\n}\n\n// -----------------------------------------------\n// Schema adapter interface\n// -----------------------------------------------\n\n/**\n * Query builder contract implemented by each macOS schema version.\n *\n * Returns raw SQL + params; the reader executes them and the mapper\n * transforms rows into domain models.\n */\nexport interface MessagesDbQueries {\n    readonly buildMessageQuery: (input: MessageQueryInput) => SqlQuery\n    readonly buildChatQuery: (input: ChatQueryInput) => SqlQuery\n    readonly buildAttachmentQuery: (messageIds: readonly number[]) => SqlQuery\n    /**\n     * Look up chat metadata (guid / identifier / style) for a set of\n     * message ROWIDs. Used to backfill chat info when `buildMessageQuery`'s\n     * LEFT JOIN observed the message row before its `chat_message_join` row\n     * had been committed (WAL race between the two INSERTs written by\n     * Messages.app).\n     *\n     * Returned rows: `{ message_rowid, chat_id, chat_guid, chat_style }`.\n     * A row is absent (or has nulls) if the join still has not settled.\n     */\n    readonly buildChatBackfillQuery: (messageIds: readonly number[]) => SqlQuery\n    /** Return `MAX(ROWID)` from the message table. Returned row: `{ max_id }`. */\n    readonly buildMaxRowIdQuery: () => SqlQuery\n}\n\n// -----------------------------------------------\n// Chat-id SQL matching\n// -----------------------------------------------\n\n/**\n * Build a parameterised SQL clause that matches a user-provided chat id\n * against database identifier and guid columns.\n *\n * Both columns are matched against the raw input and — when the input\n * carries a service prefix — the stripped core identifier, so\n * `iMessage;-;user@example.com` finds rows stored as `user@example.com`\n * and `iMessage;+;chatX` finds rows whose guid is `any;+;chatX`.\n *\n * Return type uses `string[]` instead of `SqlQuery` on purpose: this\n * helper only ever emits string parameters, and the narrower type lets\n * callers spread into a wider `QueryParam[]` without losing precision.\n */\nexport function buildChatIdMatchSql(\n    userInput: string,\n    columns: {\n        readonly identifier: string\n        readonly guid: string\n    }\n): { readonly sql: string; readonly params: string[] } {\n    const core = ChatId.fromUserInput(userInput).coreIdentifier\n    const values = core === userInput ? [userInput] : [userInput, core]\n    const placeholders = values.map(() => '?').join(', ')\n\n    return {\n        sql: `(${columns.identifier} IN (${placeholders}) OR ${columns.guid} IN (${placeholders}))`,\n        params: [...values, ...values],\n    }\n}\n","/**\n * macOS 26 (Tahoe) query builder.\n *\n * Implements the MessagesDbQueries contract with macOS 26-specific\n * column selections, including ck_chat_id.\n */\n\nimport { CHAT_STYLE_DM, CHAT_STYLE_GROUP } from '../../domain/chat'\nimport { toMacTimestampNs } from '../../domain/timestamp'\nimport {\n    buildChatIdMatchSql,\n    type ChatQueryInput,\n    type MessageQueryInput,\n    type MessagesDbQueries,\n    type QueryParam,\n} from './contract'\n\n// -----------------------------------------------\n// Field selections\n// -----------------------------------------------\n\nconst MESSAGE_FIELDS = [\n    'message.ROWID as id',\n    'message.guid',\n    'message.text',\n    'message.attributedBody',\n    'message.service',\n    'message.is_from_me',\n    'message.is_read',\n    'message.is_sent',\n    'message.is_delivered',\n    'message.was_downgraded',\n    'message.did_notify_recipient',\n    'message.is_auto_reply',\n    'message.is_system_message',\n    'message.is_forward',\n    'message.is_audio_message',\n    'message.is_played',\n    'message.is_expirable',\n    'message.error',\n    'message.is_spam',\n    'message.is_kt_verified',\n    'message.has_unseen_mention',\n    'message.was_delivered_quietly',\n    'message.is_sos',\n    'message.is_critical',\n    'message.sent_or_received_off_grid',\n    'message.date',\n    'message.date_delivered',\n    'message.date_read',\n    'message.date_played',\n    'message.date_edited',\n    'message.date_retracted',\n    'message.date_recovered',\n    'message.is_empty',\n    'message.message_summary_info',\n    'message.reply_to_guid',\n    'message.thread_originator_guid',\n    'message.group_title',\n    'message.expressive_send_style_id',\n    'message.balloon_bundle_id',\n    'message.destination_caller_id',\n    'message.ck_chat_id as ck_chat_id',\n    'message.was_detonated',\n    'message.expire_state',\n    'message.share_status',\n    'message.share_direction',\n    'message.schedule_type',\n    'message.schedule_state',\n    'message.part_count',\n    'message.cache_has_attachments',\n    'message.associated_message_type',\n    'message.associated_message_guid',\n    'message.associated_message_emoji',\n    'message.associated_message_range_location',\n    'message.associated_message_range_length',\n    'message.item_type',\n    'message.group_action_type',\n    'handle.id as participant',\n    'other_handle.id as affected_participant',\n    'chat.chat_identifier as chat_id',\n    'chat.guid as chat_guid',\n    'chat.style as chat_style',\n] as const\n\nconst CHAT_FIELDS = [\n    'chat.guid',\n    'chat.chat_identifier',\n    'chat.service_name',\n    'chat.style',\n    'chat.account_login',\n    'chat.is_archived',\n    'chat.is_filtered',\n    'chat.is_blackholed',\n    'chat.is_deleting_incoming_messages',\n    'chat.last_read_message_timestamp',\n    'chat.display_name',\n    'chat_stats.last_date',\n    'COALESCE(chat_stats.unread_count, 0) AS unread_count',\n] as const\n\nconst ATTACHMENT_FIELDS = [\n    'message_attachment_join.message_id as msg_id',\n    'attachment.guid',\n    'attachment.created_date',\n    'attachment.filename',\n    'attachment.uti',\n    'attachment.mime_type',\n    'attachment.transfer_state',\n    'attachment.is_outgoing',\n    'attachment.transfer_name',\n    'attachment.total_bytes',\n    'attachment.is_sticker',\n    'attachment.is_commsafety_sensitive',\n    'attachment.emoji_image_short_description',\n] as const\n\n// -----------------------------------------------\n// Query builder\n// -----------------------------------------------\n\nfunction escapeLikePattern(input: string): string {\n    return input.replace(/[%_\\\\]/g, (ch) => `\\\\${ch}`)\n}\n\n/** macOS 26 (Tahoe) query builder. */\nexport const macos26Queries: MessagesDbQueries = {\n    buildMessageQuery(filter: MessageQueryInput) {\n        const conditions: string[] = []\n        const params: QueryParam[] = []\n\n        if (filter.isRead === true) {\n            conditions.push('message.is_read = 1')\n        } else if (filter.isRead === false) {\n            conditions.push('message.is_read = 0')\n        }\n\n        if (filter.isFromMe === true) {\n            conditions.push('message.is_from_me = 1')\n        } else if (filter.isFromMe === false) {\n            conditions.push('message.is_from_me = 0')\n        }\n\n        if (filter.participant) {\n            conditions.push('handle.id = ?')\n            params.push(filter.participant)\n        }\n\n        if (filter.chatId) {\n            const match = buildChatIdMatchSql(filter.chatId, {\n                identifier: 'chat.chat_identifier',\n                guid: 'chat.guid',\n            })\n            conditions.push(match.sql)\n            params.push(...match.params)\n        }\n\n        if (filter.service) {\n            conditions.push('message.service = ?')\n            params.push(filter.service)\n        }\n\n        if (filter.hasAttachments === true) {\n            conditions.push(\n                'EXISTS (SELECT 1 FROM message_attachment_join WHERE message_attachment_join.message_id = message.ROWID)'\n            )\n        } else if (filter.hasAttachments === false) {\n            conditions.push(\n                'NOT EXISTS (SELECT 1 FROM message_attachment_join WHERE message_attachment_join.message_id = message.ROWID)'\n            )\n        }\n\n        if (filter.excludeReactions) {\n            conditions.push('(message.associated_message_type IS NULL OR message.associated_message_type = 0)')\n        }\n\n        if (filter.sinceRowId != null) {\n            conditions.push('message.ROWID > ?')\n            params.push(filter.sinceRowId)\n        }\n\n        if (filter.since) {\n            conditions.push('message.date >= ?')\n            params.push(toMacTimestampNs(filter.since))\n        }\n\n        if (filter.before) {\n            conditions.push('message.date < ?')\n            params.push(toMacTimestampNs(filter.before))\n        }\n\n        const where = conditions.length > 0 ? `WHERE ${conditions.join(' AND ')}` : ''\n\n        const hasLimit = filter.limit != null && filter.limit > 0\n        const hasOffset = filter.offset != null && filter.offset > 0\n\n        let limitClause = ''\n\n        if (hasLimit) {\n            limitClause = 'LIMIT ?'\n            params.push(filter.limit as number)\n        } else if (hasOffset) {\n            // SQLite requires a LIMIT clause whenever OFFSET is present;\n            // `LIMIT -1` means \"no limit\" and is the canonical idiom.\n            limitClause = 'LIMIT -1'\n        }\n\n        const offsetClause = hasOffset ? 'OFFSET ?' : ''\n\n        if (hasOffset) {\n            params.push(filter.offset as number)\n        }\n\n        const orderBy = filter.orderByRowIdAsc ? 'ORDER BY message.ROWID ASC' : 'ORDER BY message.date DESC'\n\n        return {\n            sql: `\n                SELECT\n                    ${MESSAGE_FIELDS.join(',\\n                    ')}\n                FROM message\n                LEFT JOIN handle ON message.handle_id = handle.ROWID\n                LEFT JOIN handle AS other_handle ON message.other_handle = other_handle.ROWID\n                -- A message can appear in multiple chat_message_join rows (rare,\n                -- e.g. cross-posted group messages). MIN(chat_id) picks the\n                -- lowest-ROWID chat deterministically so repeated queries\n                -- return the same chat_guid/chat_identifier for the message.\n                LEFT JOIN chat ON chat.ROWID = (\n                    SELECT MIN(chat_message_join.chat_id)\n                    FROM chat_message_join\n                    WHERE chat_message_join.message_id = message.ROWID\n                )\n                ${where}\n                ${orderBy}\n                ${limitClause}\n                ${offsetClause}\n            `,\n            params,\n        }\n    },\n\n    buildChatQuery(query: ChatQueryInput) {\n        const conditions: string[] = []\n        const params: QueryParam[] = []\n\n        if (query.chatId) {\n            const match = buildChatIdMatchSql(query.chatId, {\n                identifier: 'chat_identifier',\n                guid: 'guid',\n            })\n            conditions.push(match.sql)\n            params.push(...match.params)\n        }\n\n        if (query.kind === 'group') {\n            conditions.push('style = ?')\n            params.push(CHAT_STYLE_GROUP)\n        } else if (query.kind === 'dm') {\n            conditions.push('style = ?')\n            params.push(CHAT_STYLE_DM)\n        }\n\n        if (query.service) {\n            conditions.push('service_name = ?')\n            params.push(query.service)\n        }\n\n        if (query.isArchived === true) {\n            conditions.push('is_archived = 1')\n        } else if (query.isArchived === false) {\n            conditions.push('is_archived = 0')\n        }\n\n        if (query.hasUnread === true) {\n            conditions.push('unread_count > 0')\n        } else if (query.hasUnread === false) {\n            conditions.push('unread_count = 0')\n        }\n\n        if (query.search) {\n            const escaped = escapeLikePattern(query.search)\n            conditions.push(\"(display_name LIKE ? ESCAPE '\\\\' OR chat_identifier LIKE ? ESCAPE '\\\\')\")\n            params.push(`%${escaped}%`, `%${escaped}%`)\n        }\n\n        const where = conditions.length > 0 ? `WHERE ${conditions.join(' AND ')}` : ''\n\n        let orderBy = ''\n\n        if (query.sortBy === 'recent') {\n            orderBy = 'ORDER BY (last_date IS NULL), last_date DESC'\n        } else if (query.sortBy === 'name') {\n            orderBy = 'ORDER BY (display_name IS NULL), display_name ASC'\n        }\n\n        const hasLimit = query.limit != null && query.limit > 0\n        const hasOffset = query.offset != null && query.offset > 0\n\n        let limitClause = ''\n\n        if (hasLimit) {\n            limitClause = 'LIMIT ?'\n            params.push(query.limit as number)\n        } else if (hasOffset) {\n            // SQLite requires a LIMIT clause whenever OFFSET is present;\n            // `LIMIT -1` means \"no limit\" and is the canonical idiom.\n            limitClause = 'LIMIT -1'\n        }\n\n        const offsetClause = hasOffset ? 'OFFSET ?' : ''\n\n        if (hasOffset) {\n            params.push(query.offset as number)\n        }\n\n        return {\n            sql: `\n                WITH chat_stats AS (\n                    SELECT\n                        chat_message_join.chat_id,\n                        MAX(message.date) AS last_date,\n                        SUM(\n                            CASE\n                                WHEN message.is_read = 0 AND message.is_from_me = 0 THEN 1\n                                ELSE 0\n                            END\n                        ) AS unread_count\n                    FROM chat_message_join\n                    INNER JOIN message ON message.ROWID = chat_message_join.message_id\n                    GROUP BY chat_message_join.chat_id\n                ),\n                enriched AS (\n                    SELECT\n                        ${CHAT_FIELDS.join(',\\n                        ')}\n                    FROM chat\n                    LEFT JOIN chat_stats ON chat_stats.chat_id = chat.ROWID\n                )\n                SELECT *\n                FROM enriched\n                ${where}\n                ${orderBy}\n                ${limitClause}\n                ${offsetClause}\n            `,\n            params,\n        }\n    },\n\n    buildAttachmentQuery(messageIds: readonly number[]) {\n        const placeholders = messageIds.map(() => '?').join(',')\n\n        return {\n            sql: `\n                SELECT\n                    ${ATTACHMENT_FIELDS.join(',\\n                    ')}\n                FROM attachment\n                INNER JOIN message_attachment_join ON attachment.ROWID = message_attachment_join.attachment_id\n                WHERE message_attachment_join.message_id IN (\n                    ${placeholders}\n                )\n                AND (attachment.hide_attachment IS NULL OR attachment.hide_attachment = 0)\n                ORDER BY message_attachment_join.message_id ASC, message_attachment_join.attachment_id ASC\n            `,\n            params: messageIds,\n        }\n    },\n\n    buildMaxRowIdQuery() {\n        return { sql: 'SELECT MAX(ROWID) AS max_id FROM message', params: [] }\n    },\n\n    buildChatBackfillQuery(messageIds: readonly number[]) {\n        const placeholders = messageIds.map(() => '?').join(',')\n\n        // Same chat-resolution logic as buildMessageQuery: pick the lowest\n        // ROWID chat per message. Runs a moment later so chat_message_join\n        // has had time to commit.\n        return {\n            sql: `\n                SELECT\n                    chat_message_join.message_id AS message_rowid,\n                    chat.chat_identifier AS chat_id,\n                    chat.guid AS chat_guid,\n                    chat.style AS chat_style\n                FROM chat_message_join\n                INNER JOIN chat ON chat.ROWID = chat_message_join.chat_id\n                WHERE chat_message_join.message_id IN (${placeholders})\n                    AND chat_message_join.chat_id = (\n                        SELECT MIN(inner_join.chat_id)\n                        FROM chat_message_join inner_join\n                        WHERE inner_join.message_id = chat_message_join.message_id\n                    )\n            `,\n            params: messageIds,\n        }\n    },\n}\n","/**\n * iMessage attachment model.\n *\n * File transfer states (raw `transfer_state` values):\n *\n *   -1  archiving          metadata exists, no local file yet\n *    0  waitingForAccept   queued, transfer not started\n *    1  accepted           transfer request accepted\n *    2  preparing          encoding / compressing\n *    3  transferring       active data transmission\n *    4  finalizing         writing to disk / post-processing\n *    5  finished           file available on disk\n *    6  error              non-recoverable failure\n *    7  recoverableError   transient failure, may retry\n *\n * Normalized into four consumer-facing states plus an `unknown` sentinel:\n *\n *   pending       ←  -1, 0\n *   transferring  ←  1, 2, 3, 4\n *   complete      ←  5\n *   failed        ←  6, 7\n *   unknown       ←  null / any unrecognised code (forward-compat with\n *                    future macOS `transfer_state` values)\n */\n\n// -----------------------------------------------\n// Types\n// -----------------------------------------------\n\n/** Normalized attachment transfer status. */\nexport type TransferStatus = 'pending' | 'transferring' | 'complete' | 'failed' | 'unknown'\n\n/** Attachment linked to a message. */\nexport interface Attachment {\n    /** Stable identifier derived from `attachment.guid`. */\n    readonly id: string\n\n    /** Preferred file name: `transfer_name` if available, otherwise local path basename. */\n    readonly fileName: string | null\n\n    /** Absolute local path when the file exists on disk. */\n    readonly localPath: string | null\n\n    /** MIME type such as `image/jpeg`. */\n    readonly mimeType: string\n\n    /** Uniform Type Identifier such as `public.jpeg`. */\n    readonly uti: string | null\n\n    /** File size in bytes. */\n    readonly sizeBytes: number\n\n    /** Typed transfer status resolved from `attachment.transfer_state`. */\n    readonly transferStatus: TransferStatus\n\n    /** Whether the attachment was sent by the local user. */\n    readonly isFromMe: boolean\n\n    /** Whether the attachment is a sticker. */\n    readonly isSticker: boolean\n\n    /** Flagged by Apple Communication Safety (child-safety content scanning). */\n    readonly isSensitiveContent: boolean\n\n    /** Accessibility alt text or short description when available. */\n    readonly altText: string | null\n\n    /** Attachment creation timestamp. */\n    readonly createdAt: Date\n}\n\n// -----------------------------------------------\n// Resolution\n// -----------------------------------------------\n\n/** Resolve a raw `attachment.transfer_state` code to a typed status. */\nexport function resolveTransferStatus(code: number | null): TransferStatus {\n    switch (code) {\n        case -1:\n        case 0:\n            return 'pending'\n\n        case 1:\n        case 2:\n        case 3:\n        case 4:\n            return 'transferring'\n\n        case 5:\n            return 'complete'\n\n        case 6:\n        case 7:\n            return 'failed'\n\n        default:\n            return 'unknown'\n    }\n}\n","/**\n * iMessage message model.\n *\n * Message item types (`message.item_type`, Apple `IMItemType`):\n *\n *   0  Message                        text / media message\n *   1  ParticipantChange              add / remove (sub-typed by `group_action_type`)\n *   2  GroupTitleChange               display name changed\n *   3  GroupAction                    photo, background, or other group action\n *   4  LocationShareStatusChange      location sharing status change\n *   5  MessageAction                  message-level action (kept audio, etc.)\n *   6  TUConversation                 FaceTime / TelephonyUtilities conversation event\n */\n\nimport type { Attachment } from './attachment'\nimport type { ChatKind } from './chat'\nimport type { Reaction } from './reaction'\nimport type { Service } from './service'\n\n// -----------------------------------------------\n// Message kind\n// -----------------------------------------------\n\n/**\n * Normalized message kind derived from `message.item_type`.\n *\n * Orthogonal to reactions — a row with a non-null `reaction` payload still\n * carries its wire-level kind here (typically `'text'` for tapbacks).\n */\nexport type MessageKind = 'text' | 'memberAdded' | 'memberRemoved' | 'nameChanged' | 'groupAction' | 'unknown'\n\n/**\n * Resolve `item_type` and `group_action_type` into a MessageKind.\n *\n * Maps itemType 0–3 to specific kinds; 4–6 fall through to 'unknown'.\n * For itemType=1, `group_action_type` distinguishes added (0) from removed (1).\n */\nexport function resolveMessageKind(itemType: number | null, groupActionType: number | null): MessageKind {\n    switch (itemType) {\n        case 0:\n            return 'text'\n        case 1:\n            return groupActionType === 1 ? 'memberRemoved' : 'memberAdded'\n        case 2:\n            return 'nameChanged'\n        case 3:\n            return 'groupAction'\n        default:\n            return 'unknown'\n    }\n}\n\n// -----------------------------------------------\n// Expiration status\n// -----------------------------------------------\n\n/** Message expiration state derived from `message.expire_state`. */\nexport type ExpireStatus = 'active' | 'willExpire' | 'expired'\n\n/** Resolve `message.expire_state` to a typed status. */\nexport function resolveExpireStatus(code: number | null): ExpireStatus {\n    switch (code) {\n        case 1:\n            return 'willExpire'\n        case 2:\n            return 'expired'\n        default:\n            return 'active'\n    }\n}\n\n// -----------------------------------------------\n// Sharing status\n// -----------------------------------------------\n\n/** Sharing activity state derived from `message.share_status`. */\nexport type ShareActivity = 'none' | 'pending' | 'active' | 'unknown'\n\n/** Resolve `message.share_status` to a typed activity state. */\nexport function resolveShareActivity(code: number | null): ShareActivity {\n    switch (code) {\n        case 0:\n            return 'none'\n        case 1:\n            return 'pending'\n        case 2:\n            return 'active'\n        default:\n            return 'unknown'\n    }\n}\n\n/** Sharing direction derived from `message.share_direction`. */\nexport type ShareDirection = 'none' | 'incoming' | 'outgoing' | 'unknown'\n\n/** Resolve `message.share_direction` to a typed direction. */\nexport function resolveShareDirection(code: number | null): ShareDirection {\n    switch (code) {\n        case 0:\n            return 'none'\n        case 1:\n            return 'incoming'\n        case 2:\n            return 'outgoing'\n        default:\n            return 'unknown'\n    }\n}\n\n// -----------------------------------------------\n// Scheduled messages\n// -----------------------------------------------\n\n/** Scheduled message kind derived from `message.schedule_type`. */\nexport type ScheduleKind = 'none' | 'sendLater' | 'unknown'\n\n/**\n * Resolve `message.schedule_type` to a typed kind.\n *\n * Both `1` and `2` are observed in the wild as \"send later\" markers\n * (the `message_is_scheduled_message_index` in chat.db is defined on\n * `schedule_type = 2`); accept either for forward compatibility.\n */\nexport function resolveScheduleKind(code: number | null): ScheduleKind {\n    switch (code) {\n        case 0:\n            return 'none'\n        case 1:\n        case 2:\n            return 'sendLater'\n        default:\n            return 'unknown'\n    }\n}\n\n/** Scheduled message status derived from `message.schedule_state`. */\nexport type ScheduleStatus = 'none' | 'pending' | 'sent' | 'failed' | 'unknown'\n\n/**\n * Resolve `message.schedule_state` to a typed status.\n *\n * Other values (e.g. `4`, observed occasionally in chat.db) are Apple-internal\n * transient states not covered by a public enum and are reported as `unknown`.\n */\nexport function resolveScheduleStatus(code: number | null): ScheduleStatus {\n    switch (code) {\n        case 0:\n            return 'none'\n        case 1:\n            return 'pending'\n        case 2:\n            return 'sent'\n        case 3:\n            return 'failed'\n        default:\n            return 'unknown'\n    }\n}\n\n// -----------------------------------------------\n// Message\n// -----------------------------------------------\n\n/** Message model. */\nexport interface Message {\n    /** Local store row id. Useful for cursors and watcher checkpoints. */\n    readonly rowId: number\n    /** Stable message id derived from `message.guid`. */\n    readonly id: string\n    /**\n     * Normalized chat id suitable for routing and matching.\n     *\n     * `null` only when all authoritative sources are missing from the row\n     * (no `chat_guid` / `chat_id` via join, no `ck_chat_id`, and the message\n     * is in-bound so no `destination_caller_id`). Observable in rare WAL\n     * races before `chat_message_join` flushes — treat as \"chat unknown,\n     * skip routing\".\n     */\n    readonly chatId: string | null\n    /** Chat kind derived from the owning chat. */\n    readonly chatKind: ChatKind\n    /** Database-associated remote participant handle. */\n    readonly participant: string | null\n    /** Transport used for this message. `null` when the raw column is missing or unrecognized. */\n    readonly service: Service | null\n    /** Best-effort decoded text body. */\n    readonly text: string | null\n    /** Normalized message kind. */\n    readonly kind: MessageKind\n    /** Whether this row was sent by the local user. */\n    readonly isFromMe: boolean\n    /** Local read state. */\n    readonly isRead: boolean\n    /** Send completed on the local device. */\n    readonly isSent: boolean\n    /** Delivery was confirmed by the recipient device. */\n    readonly isDelivered: boolean\n    /** The message downgraded from iMessage to SMS. */\n    readonly isDowngraded: boolean\n    /** Recipient device actually displayed a notification. */\n    readonly didNotifyRecipient: boolean\n    /** Focus / DND auto-reply message. */\n    readonly isAutoReply: boolean\n    /** System-generated message row. */\n    readonly isSystem: boolean\n    /** Forwarded message. */\n    readonly isForwarded: boolean\n    /** Audio message. */\n    readonly isAudioMessage: boolean\n    /** Audio message has been played. */\n    readonly isPlayed: boolean\n    /** Message content can expire. */\n    readonly isExpirable: boolean\n    /** `true` when `errorCode !== 0`. */\n    readonly hasError: boolean\n    /** Raw error code for diagnostics. */\n    readonly errorCode: number\n    /** Marked as spam. */\n    readonly isSpam: boolean\n    /** Contact Key Verification passed. */\n    readonly isContactKeyVerified: boolean\n    /** Group chat has an unseen mention. */\n    readonly hasUnseenMention: boolean\n    /** Delivered quietly without notification. */\n    readonly wasDeliveredQuietly: boolean\n    /** Emergency SOS message. */\n    readonly isEmergencySos: boolean\n    /** Critical alert message. */\n    readonly isCriticalAlert: boolean\n    /** Message was sent or received off-grid via satellite. */\n    readonly isOffGrid: boolean\n    /** Sent or received timestamp. */\n    readonly createdAt: Date\n    /** Delivery confirmation timestamp. */\n    readonly deliveredAt: Date | null\n    /** Read timestamp. */\n    readonly readAt: Date | null\n    /** Audio playback timestamp. */\n    readonly playedAt: Date | null\n    /** Edit timestamp. */\n    readonly editedAt: Date | null\n    /** Unsend / retract timestamp. */\n    readonly retractedAt: Date | null\n    /** Recovery-from-trash timestamp. */\n    readonly recoveredAt: Date | null\n    /** Direct reply target message id. */\n    readonly replyToMessageId: string | null\n    /** Thread root message id. */\n    readonly threadRootMessageId: string | null\n    /** Participant affected by a membership change event. */\n    readonly affectedParticipant: string | null\n    /** New group name for rename events. */\n    readonly newGroupName: string | null\n    /** Send effect identifier. */\n    readonly sendEffect: string | null\n    /** Rich-message / app extension bundle identifier. */\n    readonly appBundleId: string | null\n    /** Invisible Ink content has been revealed. */\n    readonly isInvisibleInkRevealed: boolean\n    /** Expiration state derived from `message.expire_state`. */\n    readonly expireStatus: ExpireStatus\n    /** Sharing activity state derived from `message.share_status`. */\n    readonly shareActivity: ShareActivity\n    /** Sharing direction derived from `message.share_direction`. */\n    readonly shareDirection: ShareDirection\n    /** Scheduled-message kind derived from `message.schedule_type`. */\n    readonly scheduleKind: ScheduleKind\n    /** Scheduled-message status derived from `message.schedule_state`. */\n    readonly scheduleStatus: ScheduleStatus\n    /** Number of parts / segments in the message. */\n    readonly segmentCount: number\n    /**\n     * Whether `message.cache_has_attachments` is set on the underlying row.\n     *\n     * Use this to detect a WAL race where a message row is already visible\n     * but its `message_attachment_join` entries have not yet been flushed —\n     * `hasAttachments === true && attachments.length === 0` means the\n     * attachments will arrive on a subsequent batch. Treat such messages\n     * as provisional and re-query (or wait for the next watcher tick).\n     */\n    readonly hasAttachments: boolean\n    /** Reaction payload when this row is a reaction. */\n    readonly reaction: Reaction | null\n    /** Attachments linked to the message. */\n    readonly attachments: readonly Attachment[]\n}\n","/**\n * iMessage reaction model (Tapback, sticker, poll).\n *\n * Reaction codes (`associated_message_type`):\n *\n *   0, 2, 3     app / balloon marker (Polls, msgine, etc.) — NOT a reaction;\n *               `resolveReactionMeta` intentionally returns `{kind: null}`.\n *   1000        sticker placement\n *   2000–2007   add reaction (love, like, dislike, laugh, emphasize, question, emoji, sticker)\n *   3000–3007   remove reaction (base = code − 1000)\n *   4000        poll vote\n */\n\n// -----------------------------------------------\n// Types\n// -----------------------------------------------\n\n/** Normalized Tapback / sticker / poll reaction kind. */\nexport type ReactionKind =\n    | 'love'\n    | 'like'\n    | 'dislike'\n    | 'laugh'\n    | 'emphasize'\n    | 'question'\n    | 'emoji'\n    | 'sticker'\n    | 'pollVote'\n\n/** UTF-16 range inside the target message text. */\nexport interface ReactionTextRange {\n    /** UTF-16 start index. */\n    readonly location: number\n    /** UTF-16 length from `location`. */\n    readonly length: number\n}\n\n/** Tapback or sticker reaction attached to another message. */\nexport interface Reaction {\n    /** Normalized reaction kind. */\n    readonly kind: ReactionKind\n    /** Public message id that this reaction targets. */\n    readonly targetMessageId: string | null\n    /** Emoji payload for emoji reactions; `null` for classic Tapbacks. */\n    readonly emoji: string | null\n    /** Substring range inside the target message text. */\n    readonly textRange: ReactionTextRange\n    /** `true` when this row removes a previous reaction. */\n    readonly isRemoved: boolean\n}\n\n// -----------------------------------------------\n// Constants\n// -----------------------------------------------\n\n/** Maps protocol `associated_message_type` base codes to reaction kinds. */\nconst REACTION_KIND_MAP: Readonly<Record<number, ReactionKind>> = {\n    2000: 'love',\n    2001: 'like',\n    2002: 'dislike',\n    2003: 'laugh',\n    2004: 'emphasize',\n    2005: 'question',\n    2006: 'emoji',\n    2007: 'sticker',\n}\n\n/** Standalone reaction codes outside the 2000–3007 tapback range. */\nconst STANDALONE_REACTION_MAP: Readonly<Record<number, ReactionKind>> = {\n    1000: 'sticker',\n    4000: 'pollVote',\n}\n\n// -----------------------------------------------\n// Resolution\n// -----------------------------------------------\n\n/** Parsed reaction metadata. */\ninterface ReactionMeta {\n    readonly kind: ReactionKind | null\n    readonly isRemoved: boolean\n}\n\n/** Resolve `message.associated_message_type` into reaction metadata. */\nexport function resolveReactionMeta(type: number | null): ReactionMeta {\n    if (type == null || type === 0) {\n        return { kind: null, isRemoved: false }\n    }\n\n    // Standalone codes (1000 = sticker, 4000 = poll vote)\n    const standalone = STANDALONE_REACTION_MAP[type]\n    if (standalone != null) {\n        return { kind: standalone, isRemoved: false }\n    }\n\n    // Tapback range: 2000–2007 add, 3000–3007 remove\n    const isAdd = type >= 2000 && type <= 2007\n    const isRemove = type >= 3000 && type <= 3007\n\n    if (!isAdd && !isRemove) {\n        return { kind: null, isRemoved: false }\n    }\n\n    const baseType = isRemove ? type - 1000 : type\n    const kind = REACTION_KIND_MAP[baseType] ?? null\n\n    return { kind, isRemoved: isRemove }\n}\n","/**\n * iMessage transport service identification.\n *\n * Known service strings from chat.db:\n *   - \"iMessage\"\n *   - \"SMS\"\n *   - \"RCS\"\n */\n\n// -----------------------------------------------\n// Types\n// -----------------------------------------------\n\n/** Transport protocol used by a conversation or message. */\nexport type Service = 'iMessage' | 'SMS' | 'RCS'\n\n// -----------------------------------------------\n// Resolution\n// -----------------------------------------------\n\nconst SERVICE_MAP: Readonly<Record<string, Service>> = {\n    imessage: 'iMessage',\n    sms: 'SMS',\n    rcs: 'RCS',\n}\n\n/**\n * Resolve a raw service string to a typed Service value. Case-insensitive\n * exact match. Returns `null` when the raw column is null or unrecognized.\n */\nexport function resolveService(raw: string | null): Service | null {\n    if (raw == null) return null\n\n    return SERVICE_MAP[raw.toLowerCase()] ?? null\n}\n","/**\n * Decode Messages.app `attributedBody` BLOBs (typedstream) to plain text.\n */\n\nimport { NSAttributedString, Unarchiver } from '@parseaple/typedstream'\n\n/**\n * Extract plain text from a Messages `attributedBody` column BLOB.\n *\n * The BLOB is a NeXTSTEP typedstream whose single root value is an\n * `NSAttributedString`. We ask the unarchiver for the unwrapped root\n * directly — `decodeAll()` would return the outer `TypedGroup` wrappers,\n * which is one level above the object we want.\n *\n * Returns `null` on any decode error or when no string content is found.\n */\nexport function extractTextFromAttributedBody(blob: Buffer | Uint8Array): string | null {\n    try {\n        const buffer = Buffer.isBuffer(blob) ? blob : Buffer.from(blob)\n\n        if (buffer.length === 0) return null\n\n        const root = Unarchiver.open(buffer, Unarchiver.BinaryDecoding.decodable).decodeSingleRoot()\n\n        if (root instanceof NSAttributedString && root.string) {\n            return root.string\n        }\n\n        return null\n    } catch {\n        return null\n    }\n}\n","/**\n * Row-to-domain-model mapper for Messages database query results.\n *\n * Converts raw SQL rows into domain models, delegating all type\n * resolution to domain resolve functions.\n */\n\nimport { homedir } from 'node:os'\nimport { basename, join } from 'node:path'\n\nimport type { Attachment } from '../../domain/attachment'\nimport { resolveTransferStatus } from '../../domain/attachment'\nimport type { Chat, ChatKind } from '../../domain/chat'\nimport { resolveChatKind } from '../../domain/chat'\nimport { ChatId, parseChatServicePrefix } from '../../domain/chat-id'\nimport type { Message } from '../../domain/message'\nimport {\n    resolveExpireStatus,\n    resolveMessageKind,\n    resolveScheduleKind,\n    resolveScheduleStatus,\n    resolveShareActivity,\n    resolveShareDirection,\n} from '../../domain/message'\nimport type { Reaction } from '../../domain/reaction'\nimport { resolveReactionMeta } from '../../domain/reaction'\nimport { resolveService } from '../../domain/service'\nimport { fromMacTimestampNs } from '../../domain/timestamp'\nimport { extractTextFromAttributedBody } from './body-decoder'\n\nconst HOME_DIR = homedir()\n\n// -----------------------------------------------\n// Value parsers\n// -----------------------------------------------\n\n/** Parse an unknown value to a finite number, or null. */\nexport function parseNumber(value: unknown): number | null {\n    if (typeof value === 'number' && Number.isFinite(value)) {\n        return value\n    }\n\n    if (typeof value === 'bigint') {\n        const parsed = Number(value)\n        return Number.isSafeInteger(parsed) ? parsed : null\n    }\n\n    if (typeof value === 'string' && value.trim() !== '') {\n        const parsed = Number(value)\n        return Number.isFinite(parsed) ? parsed : null\n    }\n\n    return null\n}\n\nfunction optionalNumber(value: unknown, fieldName: string): number | null {\n    if (value == null) return null\n\n    const parsed = parseNumber(value)\n    if (parsed != null) return parsed\n\n    throw new Error(`Invalid numeric field: ${fieldName}`)\n}\n\nexport function requireNumber(value: unknown, fieldName: string): number {\n    const parsed = optionalNumber(value, fieldName)\n    if (parsed != null) return parsed\n\n    throw new Error(`Missing numeric field: ${fieldName}`)\n}\n\nfunction optionalString(value: unknown, fieldName: string): string | null {\n    if (value == null) return null\n    if (typeof value === 'string') return value\n\n    throw new Error(`Invalid string field: ${fieldName}`)\n}\n\nfunction optionalNonEmptyString(value: unknown, fieldName: string): string | null {\n    const parsed = optionalString(value, fieldName)\n    return parsed == null || parsed === '' ? null : parsed\n}\n\nfunction requireNonEmptyString(value: unknown, fieldName: string): string {\n    const parsed = optionalNonEmptyString(value, fieldName)\n    if (parsed != null) return parsed\n\n    throw new Error(`Missing string field: ${fieldName}`)\n}\n\nfunction flag(value: unknown, fieldName: string): boolean {\n    if (typeof value === 'boolean') return value\n    if (value == null) return false\n\n    const parsed = parseNumber(value)\n    if (parsed != null) return parsed !== 0\n\n    throw new Error(`Invalid boolean field: ${fieldName}`)\n}\n\nfunction optionalDate(value: unknown, fieldName: string): Date | null {\n    const parsed = optionalNumber(value, fieldName)\n    if (parsed == null || parsed === 0) return null\n\n    return fromMacTimestampNs(parsed)\n}\n\nfunction requireDate(value: unknown, fieldName: string): Date {\n    return fromMacTimestampNs(requireNumber(value, fieldName))\n}\n\n// -----------------------------------------------\n// Optional participant\n// -----------------------------------------------\n\nfunction optionalParticipant(value: unknown, fieldName: string): string | null {\n    const str = optionalString(value, fieldName)\n    if (str == null) return null\n\n    const trimmed = str.trim()\n    return trimmed === '' ? null : trimmed\n}\n\n// -----------------------------------------------\n// Chat-id resolution\n// -----------------------------------------------\n\nfunction resolveMessageChatId(row: Record<string, unknown>): ChatId | null {\n    // Trust the authoritative identifiers first: `chat.guid` /\n    // `chat.chat_identifier` (via the LEFT JOIN chat) or the CloudKit mirror.\n    //\n    // Deliberate asymmetry for the fallbacks:\n    //\n    //   • We fall back to `message.destination_caller_id` ONLY for\n    //     out-bound messages (is_from_me = 1). For those, it is the\n    //     recipient the user addressed, so it correctly identifies a DM\n    //     when the chat row has not yet been joined (orphan out-bound\n    //     messages during a race). For INBOUND messages the same column\n    //     holds *my own* caller id — using it would mint a DM chatId\n    //     pointing at myself, mis-routing an incoming group message as\n    //     `chatKind='dm'`.\n    //\n    //   • We do NOT fall back to `message.participant` (handle.id). For\n    //     in-bound group messages that field is the SENDER's personal\n    //     handle, not the chat. Constructing a DM chatId from it makes\n    //     `message.chatId` point at an individual, so any reply keyed on\n    //     that chatId (e.g. agents echoing back into \"the same conversation\")\n    //     lands in a 1:1 thread instead of the original group.\n    const primary = resolvePrimaryChatId(row.chat_guid, row.chat_id) ?? resolveCloudKitChatId(row.ck_chat_id)\n    if (primary != null) return primary\n\n    // Only trust destination_caller_id on out-bound messages.\n    if (!flag(row.is_from_me, 'message.is_from_me')) return null\n\n    return resolveRecipientChatId(row.destination_caller_id, row.service, 'message.destination_caller_id')\n}\n\nfunction resolveRecipientChatId(recipient: unknown, service: unknown, fieldName: string): ChatId | null {\n    const value = optionalParticipant(recipient, fieldName)\n    if (value == null) return null\n\n    const servicePrefix = parseChatServicePrefix(optionalNonEmptyString(service, 'message.service'))\n    return servicePrefix ? ChatId.fromDMRecipient(value, servicePrefix) : ChatId.fromUserInput(value)\n}\n\nfunction resolvePrimaryChatId(guid: unknown, identifier: unknown): ChatId | null {\n    const raw =\n        optionalNonEmptyString(guid, 'message.chat_guid') ?? optionalNonEmptyString(identifier, 'message.chat_id')\n\n    return raw == null ? null : ChatId.fromUserInput(raw)\n}\n\nfunction resolveCloudKitChatId(value: unknown): ChatId | null {\n    const raw = optionalParticipant(value, 'message.ck_chat_id')\n    return raw == null ? null : ChatId.fromUserInput(raw)\n}\n\n// -----------------------------------------------\n// Text extraction\n// -----------------------------------------------\n\nfunction resolveMessageText(row: Record<string, unknown>): string | null {\n    const text = optionalString(row.text, 'message.text')\n\n    if (text != null && text !== '') {\n        return text\n    }\n\n    if (row.attributedBody == null) {\n        return null\n    }\n\n    if (!Buffer.isBuffer(row.attributedBody) && !(row.attributedBody instanceof Uint8Array)) {\n        return null\n    }\n\n    const value = extractTextFromAttributedBody(row.attributedBody)\n    return value === '' ? null : value\n}\n\n// -----------------------------------------------\n// Reaction mapping\n// -----------------------------------------------\n\nfunction mapReaction(row: Record<string, unknown>): Reaction | null {\n    const meta = resolveReactionMeta(optionalNumber(row.associated_message_type, 'message.associated_message_type'))\n\n    if (meta.kind == null) {\n        return null\n    }\n\n    return {\n        kind: meta.kind,\n        targetMessageId: optionalNonEmptyString(row.associated_message_guid, 'message.associated_message_guid'),\n        emoji: optionalNonEmptyString(row.associated_message_emoji, 'message.associated_message_emoji'),\n        textRange: {\n            location:\n                optionalNumber(row.associated_message_range_location, 'message.associated_message_range_location') ?? 0,\n            length: optionalNumber(row.associated_message_range_length, 'message.associated_message_range_length') ?? 0,\n        },\n        isRemoved: meta.isRemoved,\n    }\n}\n\n// -----------------------------------------------\n// Chat mapping\n// -----------------------------------------------\n\nfunction mapChatId(row: Record<string, unknown>): string {\n    const guid = requireNonEmptyString(row.guid, 'chat.guid')\n    return ChatId.fromUserInput(guid).toString()\n}\n\n/** Convert a raw chat row to a Chat domain model. */\nexport function rowToChat(row: Record<string, unknown>): Chat {\n    return {\n        chatId: mapChatId(row),\n        name: optionalNonEmptyString(row.display_name, 'chat.display_name'),\n        service: resolveService(optionalNonEmptyString(row.service_name, 'chat.service_name')),\n        kind: resolveChatKind(optionalNumber(row.style, 'chat.style')),\n        account: optionalNonEmptyString(row.account_login, 'chat.account_login'),\n        isArchived: flag(row.is_archived, 'chat.is_archived'),\n        isFiltered: flag(row.is_filtered, 'chat.is_filtered'),\n        dropsIncomingMessages: flag(row.is_blackholed, 'chat.is_blackholed'),\n        autoDeletesIncomingMessages: flag(row.is_deleting_incoming_messages, 'chat.is_deleting_incoming_messages'),\n        lastReadAt: optionalDate(row.last_read_message_timestamp, 'chat.last_read_message_timestamp'),\n        unreadCount: requireNumber(row.unread_count, 'chat.unread_count'),\n        lastMessageAt: optionalDate(row.last_date, 'chat.last_date'),\n    }\n}\n\n// -----------------------------------------------\n// Message mapping\n// -----------------------------------------------\n\n/**\n * Resolve chatKind with `chat.style` as authoritative source.\n *\n * When `chat` did not join (WAL race before `chat_message_join` is visible),\n * fall back to the ChatId's own group detection, and finally to 'unknown'.\n */\nfunction resolveMessageChatKind(chatStyle: number | null, resolved: ChatId | null): ChatKind {\n    if (chatStyle != null) return resolveChatKind(chatStyle)\n    if (resolved == null) return 'unknown'\n    return resolved.isGroup ? 'group' : 'dm'\n}\n\n/**\n * macOS 26 (Tahoe) stopped populating `message.date_retracted` on unsend;\n * instead it sets `is_empty = 1` and writes a 5-entry `bplist00` into\n * `message_summary_info` containing keys `Samc` `Sust` `Rep` `Sotr` `Rrp`\n * (recoverable-record-part). Earlier versions used 2-entry dicts and the\n * date column. We detect Tahoe retracts via the `Rrp` marker.\n */\nfunction detectTahoeRetract(row: Record<string, unknown>): boolean {\n    const isEmpty = optionalNumber(row.is_empty, 'message.is_empty') === 1\n    if (!isEmpty) return false\n    const summary = row.message_summary_info\n    if (!summary) return false\n    let buf: Buffer | null = null\n    if (Buffer.isBuffer(summary)) buf = summary\n    else if (summary instanceof Uint8Array) buf = Buffer.from(summary)\n    if (!buf || buf.length < 6) return false\n    // ASCII 'Rrp' = 0x52 0x72 0x70 — present only when bplist dict has the\n    // retract slot. Avoids a full bplist parse; false positives would require\n    // a normal message to contain this exact 3-byte sequence in summary_info.\n    return buf.includes(Buffer.from([0x52, 0x72, 0x70]))\n}\n\n/**\n * Patch chat-related fields (`chatId`, `chatKind`) on a message using a\n * backfill row from `buildChatBackfillQuery`. Used by the reader when the\n * original `buildMessageQuery` saw `chat_message_join` before it was\n * written (WAL race). Returns the original message if the backfill row\n * carries no new information.\n *\n * Backfill rows only carry `chat_guid` / `chat_id` / `chat_style` — the\n * other fallbacks (destination_caller_id, ck_chat_id) were already\n * attempted in the original mapping, so we call the primary-chat-id\n * resolver directly.\n */\nexport function patchMessageChatInfo(message: Message, chatRow: Record<string, unknown>): Message {\n    const resolved = resolvePrimaryChatId(chatRow.chat_guid, chatRow.chat_id)\n    const chatId = resolved?.toString() ?? message.chatId\n    const chatKind = resolveMessageChatKind(optionalNumber(chatRow.chat_style, 'chat.style'), resolved)\n\n    if (chatId === message.chatId && chatKind === message.chatKind) return message\n    return { ...message, chatId, chatKind }\n}\n\n/** Convert a raw message row to a Message domain model. */\nexport function rowToMessage(row: Record<string, unknown>, attachments: readonly Attachment[]): Message {\n    const resolved = resolveMessageChatId(row)\n    const chatId = resolved?.toString() ?? null\n    const chatKind = resolveMessageChatKind(optionalNumber(row.chat_style, 'message.chat_style'), resolved)\n    const errorCode = optionalNumber(row.error, 'message.error') ?? 0\n    const reaction = mapReaction(row)\n    // Tahoe retract fallback: use date_edited (retract happens after edits)\n    // or the original send date as an approximate retract time.\n    const directRetract = optionalDate(row.date_retracted, 'message.date_retracted')\n    const retractedAt =\n        directRetract ??\n        (detectTahoeRetract(row)\n            ? (optionalDate(row.date_edited, 'message.date_edited') ?? optionalDate(row.date, 'message.date'))\n            : null)\n\n    return {\n        rowId: requireNumber(row.id, 'message.id'),\n        id: requireNonEmptyString(row.guid, 'message.guid'),\n        chatId,\n        chatKind,\n        participant: optionalParticipant(row.participant, 'message.participant'),\n        service: resolveService(optionalNonEmptyString(row.service, 'message.service')),\n        text: resolveMessageText(row),\n        kind: resolveMessageKind(\n            optionalNumber(row.item_type, 'message.item_type'),\n            optionalNumber(row.group_action_type, 'message.group_action_type')\n        ),\n        isFromMe: flag(row.is_from_me, 'message.is_from_me'),\n        isRead: flag(row.is_read, 'message.is_read'),\n        isSent: flag(row.is_sent, 'message.is_sent'),\n        isDelivered: flag(row.is_delivered, 'message.is_delivered'),\n        isDowngraded: flag(row.was_downgraded, 'message.was_downgraded'),\n        didNotifyRecipient: flag(row.did_notify_recipient, 'message.did_notify_recipient'),\n        isAutoReply: flag(row.is_auto_reply, 'message.is_auto_reply'),\n        isSystem: flag(row.is_system_message, 'message.is_system_message'),\n        isForwarded: flag(row.is_forward, 'message.is_forward'),\n        isAudioMessage: flag(row.is_audio_message, 'message.is_audio_message'),\n        isPlayed: flag(row.is_played, 'message.is_played'),\n        isExpirable: flag(row.is_expirable, 'message.is_expirable'),\n        hasError: errorCode !== 0,\n        errorCode,\n        isSpam: flag(row.is_spam, 'message.is_spam'),\n        isContactKeyVerified: flag(row.is_kt_verified, 'message.is_kt_verified'),\n        hasUnseenMention: flag(row.has_unseen_mention, 'message.has_unseen_mention'),\n        wasDeliveredQuietly: flag(row.was_delivered_quietly, 'message.was_delivered_quietly'),\n        isEmergencySos: flag(row.is_sos, 'message.is_sos'),\n        isCriticalAlert: flag(row.is_critical, 'message.is_critical'),\n        isOffGrid: flag(row.sent_or_received_off_grid, 'message.sent_or_received_off_grid'),\n        createdAt: requireDate(row.date, 'message.date'),\n        deliveredAt: optionalDate(row.date_delivered, 'message.date_delivered'),\n        readAt: optionalDate(row.date_read, 'message.date_read'),\n        playedAt: optionalDate(row.date_played, 'message.date_played'),\n        editedAt: optionalDate(row.date_edited, 'message.date_edited'),\n        retractedAt,\n        recoveredAt: optionalDate(row.date_recovered, 'message.date_recovered'),\n        replyToMessageId: optionalNonEmptyString(row.reply_to_guid, 'message.reply_to_guid'),\n        threadRootMessageId: optionalNonEmptyString(row.thread_originator_guid, 'message.thread_originator_guid'),\n        affectedParticipant: optionalParticipant(row.affected_participant, 'message.affected_participant'),\n        newGroupName: optionalNonEmptyString(row.group_title, 'message.group_title'),\n        sendEffect: optionalNonEmptyString(row.expressive_send_style_id, 'message.expressive_send_style_id'),\n        appBundleId: optionalNonEmptyString(row.balloon_bundle_id, 'message.balloon_bundle_id'),\n        isInvisibleInkRevealed: flag(row.was_detonated, 'message.was_detonated'),\n        expireStatus: resolveExpireStatus(optionalNumber(row.expire_state, 'message.expire_state')),\n        shareActivity: resolveShareActivity(optionalNumber(row.share_status, 'message.share_status')),\n        shareDirection: resolveShareDirection(optionalNumber(row.share_direction, 'message.share_direction')),\n        scheduleKind: resolveScheduleKind(optionalNumber(row.schedule_type, 'message.schedule_type')),\n        scheduleStatus: resolveScheduleStatus(optionalNumber(row.schedule_state, 'message.schedule_state')),\n        segmentCount: optionalNumber(row.part_count, 'message.part_count') ?? 0,\n        hasAttachments: flag(row.cache_has_attachments, 'message.cache_has_attachments'),\n        reaction,\n        attachments,\n    }\n}\n\n// -----------------------------------------------\n// Attachment mapping\n// -----------------------------------------------\n\nfunction resolveAttachmentLocalPath(rawFilename: unknown): string | null {\n    const filename = optionalNonEmptyString(rawFilename, 'attachment.filename')\n\n    if (filename == null) return null\n\n    if (filename.startsWith('~')) {\n        return filename.replace(/^~/, HOME_DIR)\n    }\n\n    if (!filename.startsWith('/')) {\n        return join(HOME_DIR, 'Library/Messages/Attachments', filename)\n    }\n\n    return filename\n}\n\nfunction resolveAttachmentFileName(rawTransferName: unknown, localPath: string | null): string | null {\n    const transferName = optionalNonEmptyString(rawTransferName, 'attachment.transfer_name')\n\n    if (transferName != null) return transferName\n\n    if (!localPath) return null\n\n    const name = basename(localPath)\n    return name === '' ? null : name\n}\n\n/** Convert a raw attachment row to an Attachment domain model. */\nexport function rowToAttachment(row: Record<string, unknown>): Attachment {\n    const localPath = resolveAttachmentLocalPath(row.filename)\n\n    return {\n        id: requireNonEmptyString(row.guid, 'attachment.guid'),\n        fileName: resolveAttachmentFileName(row.transfer_name, localPath),\n        localPath,\n        mimeType: optionalNonEmptyString(row.mime_type, 'attachment.mime_type') ?? 'application/octet-stream',\n        uti: optionalNonEmptyString(row.uti, 'attachment.uti'),\n        sizeBytes: optionalNumber(row.total_bytes, 'attachment.total_bytes') ?? 0,\n        transferStatus: resolveTransferStatus(optionalNumber(row.transfer_state, 'attachment.transfer_state')),\n        isFromMe: flag(row.is_outgoing, 'attachment.is_outgoing'),\n        isSticker: flag(row.is_sticker, 'attachment.is_sticker'),\n        isSensitiveContent: flag(row.is_commsafety_sensitive, 'attachment.is_commsafety_sensitive'),\n        altText: optionalNonEmptyString(row.emoji_image_short_description, 'attachment.emoji_image_short_description'),\n        createdAt: requireDate(row.created_date, 'attachment.created_date'),\n    }\n}\n","/**\n * Runtime-agnostic SQLite adapter.\n *\n * Detects Bun vs Node at first use and caches the constructor.\n * Provides a minimal statement/adapter contract consumed by the reader.\n */\n\nimport { createRequire } from 'node:module'\n\nimport { DatabaseError, toError } from '../../domain/errors'\nimport type { QueryParam } from './contract'\n\nconst require = createRequire(import.meta.url)\n\n// -----------------------------------------------\n// Adapter interfaces\n// -----------------------------------------------\n\n/** Minimal prepared-statement contract shared by bun:sqlite and better-sqlite3. */\nexport interface SqliteStatement {\n    readonly all: (...params: unknown[]) => Array<Record<string, unknown>>\n}\n\n/** Minimal database-handle contract shared by both runtimes. */\nexport interface SqliteAdapter {\n    readonly prepare: (sql: string) => SqliteStatement\n    readonly close: () => void\n}\n\ntype SqliteAdapterCtor = new (path: string, options?: { readonly?: boolean }) => SqliteAdapter\n\n// -----------------------------------------------\n// Runtime resolution\n// -----------------------------------------------\n\nlet cachedCtor: SqliteAdapterCtor | undefined\n\nfunction loadModule<T>(specifier: string, extract: (mod: unknown) => T): T {\n    try {\n        return extract(require(specifier))\n    } catch (error) {\n        const cause = toError(error)\n        throw DatabaseError(`Failed to load ${specifier}: ${cause.message}`, cause)\n    }\n}\n\nfunction resolveCtor(): SqliteAdapterCtor {\n    if (cachedCtor) return cachedCtor\n\n    cachedCtor =\n        typeof Bun !== 'undefined'\n            ? loadModule('bun:sqlite', (m) => (m as { Database: SqliteAdapterCtor }).Database)\n            : loadModule('better-sqlite3', (m) => {\n                  const mod = m as SqliteAdapterCtor | { default: SqliteAdapterCtor }\n                  return typeof mod === 'function' ? mod : mod.default\n              })\n\n    return cachedCtor\n}\n\n// -----------------------------------------------\n// SqliteClient\n// -----------------------------------------------\n\n/** Low-level SQLite client with connection lifecycle and parameterised query execution. */\nexport class SqliteClient {\n    protected readonly db: SqliteAdapter\n\n    private closed = false\n\n    /**\n     * @param path      SQLite database file path.\n     * @param readOnly  Open the database read-only. Defaults to `true` — writes to\n     *                  `chat.db` would corrupt Messages.app state, so only flip this\n     *                  when running against a test/fixture database.\n     */\n    constructor(path: string, readOnly = true) {\n        const Ctor = resolveCtor()\n\n        try {\n            this.db = new Ctor(path, { readonly: readOnly })\n        } catch (error) {\n            const cause = toError(error)\n            throw DatabaseError(`Failed to open database: ${cause.message}`, cause)\n        }\n    }\n\n    protected all(sql: string, params: readonly QueryParam[] = []): Array<Record<string, unknown>> {\n        if (this.closed) throw DatabaseError('Database is closed')\n\n        try {\n            return this.db.prepare(sql).all(...params)\n        } catch (error) {\n            const cause = toError(error)\n            throw DatabaseError(`Query failed: ${cause.message}`, cause)\n        }\n    }\n\n    close(): void {\n        if (this.closed) return\n\n        try {\n            this.db.close()\n        } catch (error) {\n            const cause = toError(error)\n            throw DatabaseError(`Failed to close database: ${cause.message}`, cause)\n        }\n\n        this.closed = true\n    }\n}\n","/**\n * Messages database reader.\n *\n * Extends SqliteClient with a query adapter (MessagesDbQueries), executes\n * the adapter's SQL, and maps rows to domain models. Currently wired to\n * macos26Queries; swap the assignment in the constructor to route a future\n * schema (e.g. macOS 27).\n *\n * Organization: the public class is a thin delegate façade — all work lives\n * in module-level free functions that take `(exec, queries, ...)` as\n * explicit dependencies. Keeps internal operations pure and testable\n * without reader instance state.\n */\n\nimport type { Attachment } from '../../domain/attachment'\nimport type { Chat } from '../../domain/chat'\nimport { DatabaseError, toErrorMessage } from '../../domain/errors'\nimport type { Message } from '../../domain/message'\nimport type { ChatQuery, MessageQuery } from '../../types/query'\nimport { delay } from '../../utils/async'\nimport type { MessageQueryInput, MessagesDbQueries, QueryExecutor, SqlQuery } from './contract'\nimport { macos26Queries } from './macos26'\nimport { parseNumber, patchMessageChatInfo, requireNumber, rowToAttachment, rowToChat, rowToMessage } from './mapper'\nimport { SqliteClient } from './sqlite-adapter'\n\n// -----------------------------------------------\n// Constants\n// -----------------------------------------------\n\nconst ATTACHMENT_QUERY_CHUNK = 500\nconst SEARCH_PAGE_SIZE = 200\n\n/**\n * Delay between backfill attempts. Absorbs the Messages.app two-write gap.\n * Heuristic — combined with CHAT_BACKFILL_MAX_RETRIES the total budget\n * before surrender is ~400ms.\n */\nconst CHAT_BACKFILL_RETRY_DELAY_MS = 200\n\n/** Retries after the initial attempt. */\nconst CHAT_BACKFILL_MAX_RETRIES = 2\n\n// -----------------------------------------------\n// MessagesDatabaseReader\n// -----------------------------------------------\n\n/** High-level Messages database reader: runs the query adapter's SQL and maps rows to domain models. */\nexport class MessagesDatabaseReader extends SqliteClient {\n    private readonly queries: MessagesDbQueries\n    private readonly exec: QueryExecutor\n\n    constructor(path: string) {\n        super(path, true)\n        this.exec = (sql, params) => this.all(sql, params ?? [])\n        this.queries = macos26Queries\n    }\n\n    /** Get the current maximum message ROWID. */\n    async getMaxRowId(): Promise<number> {\n        return queryMaxRowId(this.exec, this.queries)\n    }\n\n    /** Query messages with optional filters. */\n    async getMessages(query: MessageQuery = {}): Promise<readonly Message[]> {\n        return queryMessages(this.exec, this.queries, query)\n    }\n\n    /** Query messages newer than the given ROWID, ordered ascending. */\n    async getMessagesSinceRowId(sinceRowId: number, query: MessageQuery = {}): Promise<readonly Message[]> {\n        const messages = queryMessages(this.exec, this.queries, {\n            ...query,\n            sinceRowId,\n            orderByRowIdAsc: true,\n        })\n        return backfillMissingChatInfo(this.exec, this.queries, messages)\n    }\n\n    /** List chats with optional filters and sorting. */\n    async listChats(query: ChatQuery = {}): Promise<readonly Chat[]> {\n        return queryChats(this.exec, this.queries, query)\n    }\n}\n\n// -----------------------------------------------\n// Message query\n// -----------------------------------------------\n\nfunction queryMessages(exec: QueryExecutor, queries: MessagesDbQueries, input: MessageQueryInput): readonly Message[] {\n    const { search } = input\n    if (search) {\n        return searchMessages(exec, queries, { ...input, search })\n    }\n\n    return executeMessageQuery(exec, queries, queries.buildMessageQuery(input))\n}\n\nfunction executeMessageQuery(\n    exec: QueryExecutor,\n    queries: MessagesDbQueries,\n    sqlQuery: SqlQuery,\n    includeAttachments = true\n): readonly Message[] {\n    let messages: readonly Message[]\n\n    try {\n        const rows = exec(sqlQuery.sql, sqlQuery.params)\n        messages = rows.map((row) => rowToMessage(row, []))\n    } catch (error) {\n        throw DatabaseError(`Failed to query messages: ${toErrorMessage(error)}`, error)\n    }\n\n    if (!includeAttachments) {\n        return messages\n    }\n\n    return mergeAttachments(exec, queries, messages)\n}\n\n/**\n * Application-layer search over decoded text.\n *\n * SQL LIKE on `message.text` would drop rows whose body lives only in the\n * `attributedBody` BLOB (the norm on macOS 26). We scan in pages, decode\n * each row, and match against the final text.\n */\nfunction searchMessages(\n    exec: QueryExecutor,\n    queries: MessagesDbQueries,\n    filter: MessageQueryInput & { readonly search: string }\n): readonly Message[] {\n    const { search: rawSearch, ...sqlFilter } = filter\n    const search = rawSearch.toLowerCase()\n\n    const requestedOffset = filter.offset ?? 0\n    const requestedLimit = filter.limit ?? Number.POSITIVE_INFINITY\n    // offset applies to matches, not scanned rows — accumulate the full\n    // (offset + limit) window before slicing below.\n    const requiredMatches = requestedOffset + requestedLimit\n    // If the caller's limit exceeds the default page size, page at that\n    // size to cut the number of SQL round-trips.\n    const pageSize = Math.max(SEARCH_PAGE_SIZE, filter.limit ?? 0)\n    const matches: Message[] = []\n    let scanOffset = 0\n\n    while (matches.length < requiredMatches) {\n        const page = executeMessageQuery(\n            exec,\n            queries,\n            queries.buildMessageQuery({ ...sqlFilter, limit: pageSize, offset: scanOffset }),\n            false\n        )\n\n        if (page.length === 0) break\n\n        for (const message of page) {\n            if (message.text?.toLowerCase().includes(search) === true) {\n                matches.push(message)\n            }\n        }\n\n        if (page.length < pageSize) break\n\n        scanOffset += pageSize\n    }\n\n    // Apply the requested offset/limit window to matches (not scanned rows).\n    const end = Number.isFinite(requestedLimit) ? requestedOffset + requestedLimit : undefined\n    return mergeAttachments(exec, queries, matches.slice(requestedOffset, end))\n}\n\n// -----------------------------------------------\n// Chat-info backfill (WAL race mitigation)\n// -----------------------------------------------\n\n/**\n * Messages.app writes a new message row and its `chat_message_join` row as\n * two separate SQLite writes. A WAL-triggered watcher can observe the first\n * write before the second, so the LEFT JOIN in `buildMessageQuery` comes\n * back with `chat.*` all NULL — leaving `chatId === null` / `chatKind ===\n * 'unknown'` and silently routing the message away from `onGroupMessage` /\n * `onDirectMessage`.\n *\n * Mitigation: re-query chat metadata for any `chatId == null` row, with up\n * to `CHAT_BACKFILL_MAX_RETRIES` retries spaced by\n * `CHAT_BACKFILL_RETRY_DELAY_MS`. Skipped entirely when every row already\n * has a chat resolved (the common case). Rows still unjoined after the\n * budget are surfaced as-is — `chatId = null` is part of the public\n * contract (see llms.txt \"Auto-Reply Bot\").\n */\nasync function backfillMissingChatInfo(\n    exec: QueryExecutor,\n    queries: MessagesDbQueries,\n    messages: readonly Message[]\n): Promise<readonly Message[]> {\n    const collectMissing = (list: readonly Message[]): number[] => {\n        const ids: number[] = []\n        for (const message of list) {\n            if (message.chatId == null) ids.push(message.rowId)\n        }\n        return ids\n    }\n\n    let current = messages\n    let missing = collectMissing(current)\n    if (missing.length === 0) return current\n\n    for (let attempt = 0; attempt <= CHAT_BACKFILL_MAX_RETRIES; attempt++) {\n        if (attempt > 0) {\n            await delay(CHAT_BACKFILL_RETRY_DELAY_MS)\n        }\n        current = runChatBackfillOnce(exec, queries, current, missing)\n        missing = collectMissing(current)\n        if (missing.length === 0) break\n    }\n\n    return current\n}\n\nfunction runChatBackfillOnce(\n    exec: QueryExecutor,\n    queries: MessagesDbQueries,\n    messages: readonly Message[],\n    missingIds: readonly number[]\n): readonly Message[] {\n    const query = queries.buildChatBackfillQuery(missingIds)\n    const byRowId = new Map<number, Record<string, unknown>>()\n\n    try {\n        const rows = exec(query.sql, query.params)\n        for (const row of rows) {\n            const id = parseNumber(row.message_rowid)\n            if (id != null) byRowId.set(id, row)\n        }\n    } catch (error) {\n        throw DatabaseError(`Failed to backfill chat info: ${toErrorMessage(error)}`, error)\n    }\n\n    if (byRowId.size === 0) return messages\n\n    return messages.map((message) => {\n        if (message.chatId != null) return message\n        const row = byRowId.get(message.rowId)\n        return row ? patchMessageChatInfo(message, row) : message\n    })\n}\n\n// -----------------------------------------------\n// Chat queries\n// -----------------------------------------------\n\nfunction queryChats(exec: QueryExecutor, queries: MessagesDbQueries, input: ChatQuery): readonly Chat[] {\n    const sqlQuery = queries.buildChatQuery({\n        ...input,\n        sortBy: input.sortBy ?? 'recent',\n    })\n\n    try {\n        const rows = exec(sqlQuery.sql, sqlQuery.params)\n        return rows.map((row) => rowToChat(row))\n    } catch (error) {\n        throw DatabaseError(`Failed to list chats: ${toErrorMessage(error)}`, error)\n    }\n}\n\n// -----------------------------------------------\n// Attachment loading\n// -----------------------------------------------\n\nfunction mergeAttachments(\n    exec: QueryExecutor,\n    queries: MessagesDbQueries,\n    messages: readonly Message[]\n): readonly Message[] {\n    if (messages.length === 0) return messages\n\n    const attachmentMap = batchGetAttachments(\n        exec,\n        queries,\n        messages.map((message) => message.rowId)\n    )\n\n    return messages.map((message) => ({\n        ...message,\n        attachments: attachmentMap.get(message.rowId) ?? [],\n    }))\n}\n\nfunction batchGetAttachments(\n    exec: QueryExecutor,\n    queries: MessagesDbQueries,\n    messageIds: readonly number[]\n): Map<number, Attachment[]> {\n    const result = new Map<number, Attachment[]>()\n\n    if (messageIds.length === 0) return result\n\n    for (let i = 0; i < messageIds.length; i += ATTACHMENT_QUERY_CHUNK) {\n        const chunk = messageIds.slice(i, i + ATTACHMENT_QUERY_CHUNK)\n        const query = queries.buildAttachmentQuery(chunk)\n\n        try {\n            const rows = exec(query.sql, query.params)\n\n            for (const row of rows) {\n                const messageId = requireNumber(row.msg_id, 'attachment.msg_id')\n                const attachment = rowToAttachment(row)\n                const existing = result.get(messageId)\n\n                if (existing) {\n                    existing.push(attachment)\n                } else {\n                    result.set(messageId, [attachment])\n                }\n            }\n        } catch (error) {\n            throw DatabaseError(`Failed to query attachments: ${toErrorMessage(error)}`, error)\n        }\n    }\n\n    return result\n}\n\n// -----------------------------------------------\n// Misc\n// -----------------------------------------------\n\nfunction queryMaxRowId(exec: QueryExecutor, queries: MessagesDbQueries): number {\n    const { sql, params } = queries.buildMaxRowIdQuery()\n    try {\n        const rows = exec(sql, params)\n        return parseNumber(rows[0]?.max_id) ?? 0\n    } catch (error) {\n        throw DatabaseError(`Failed to read max ROWID: ${toErrorMessage(error)}`, error)\n    }\n}\n","/**\n * WAL-based real-time message monitor.\n *\n * State machine:\n *   WAL exists     -> watch WAL file (change events trigger polling)\n *   WAL rotated    -> switch to directory watch (wait for WAL to reappear)\n *   WAL reappears  -> switch back to WAL watch\n *   Both fail      -> stop and report error\n *\n * Event merging:\n *   fs.watch may fire many events in rapid succession. A single-slot\n *   semaphore (trigger/waitForTrigger) coalesces bursts into one\n *   consumer loop wake-up.\n */\n\nimport { type FSWatcher, watch } from 'node:fs'\nimport { basename, dirname } from 'node:path'\n\nimport { toError } from '../../domain/errors'\nimport type { Message } from '../../domain/message'\nimport type { MessageQuery } from '../../types/query'\n\n// -----------------------------------------------\n// Minimal database contract\n// -----------------------------------------------\n\n/** Minimal interface for the database reader consumed by the watcher. */\nexport interface WatchSourceDatabase {\n    readonly getMessagesSinceRowId: (sinceRowId: number, query?: MessageQuery) => Promise<readonly Message[]>\n    readonly getMaxRowId: () => Promise<number>\n}\n\n// -----------------------------------------------\n// Types\n// -----------------------------------------------\n\ntype WatchHandle = Pick<FSWatcher, 'close' | 'on'>\n\ntype WatchFactory = (\n    path: string,\n    listener: (eventType: 'change' | 'rename', filename?: string | Buffer | null) => void\n) => WatchHandle\n\n/** Configuration for the message watch source. */\nexport interface WatchSourceOptions {\n    readonly database: WatchSourceDatabase\n    readonly databasePath: string\n    readonly watchFactory?: WatchFactory\n    readonly onBatch?: (messages: readonly Message[]) => void | Promise<void>\n    readonly onError?: (error: Error) => void\n    readonly debug?: boolean\n}\n\n// -----------------------------------------------\n// Constants\n// -----------------------------------------------\n\nconst BATCH_LIMIT = 100\n\n// -----------------------------------------------\n// MessageWatchSource\n// -----------------------------------------------\n\n/** Monitors the Messages SQLite WAL file for real-time message detection. */\nexport class MessageWatchSource {\n    private readonly database: WatchSourceDatabase\n    private readonly databasePath: string\n    private readonly walPath: string\n    private readonly walFilename: string\n    private readonly watchFactory: WatchFactory\n\n    private readonly onBatch?: (messages: readonly Message[]) => void | Promise<void>\n    private readonly onError?: (error: Error) => void\n    private readonly debug: boolean\n\n    private isRunning = false\n    private lastRowId = -1\n\n    private triggerResolve: (() => void) | null = null\n    private hasPendingTrigger = false\n\n    private walWatcher: WatchHandle | null = null\n    private dirWatcher: WatchHandle | null = null\n\n    /**\n     * Handle to the running consumer loop. `stop()` awaits this to guarantee\n     * that no `onBatch` (= plugin dispatch) is in flight after stop resolves —\n     * otherwise plugin `onIncomingMessage` could race with SDK shutdown's\n     * `onDestroy`, violating the documented lifecycle contract.\n     */\n    private consumePromise: Promise<void> | null = null\n\n    constructor(options: WatchSourceOptions) {\n        this.database = options.database\n        this.databasePath = options.databasePath\n        this.walPath = `${this.databasePath}-wal`\n        this.walFilename = `${basename(this.databasePath)}-wal`\n        this.watchFactory = options.watchFactory ?? ((path, listener) => watch(path, listener))\n\n        this.onBatch = options.onBatch\n        this.onError = options.onError\n        this.debug = options.debug ?? false\n    }\n\n    // -----------------------------------------------\n    // Lifecycle\n    // -----------------------------------------------\n\n    /** Start watching for new messages. */\n    async start(): Promise<void> {\n        if (this.isRunning) return\n\n        this.lastRowId = await this.database.getMaxRowId()\n        this.isRunning = true\n\n        try {\n            this.ensureWatching()\n            this.trigger()\n            this.consumePromise = this.consumeLoop()\n        } catch (error) {\n            this.isRunning = false\n            this.detachWALWatcher()\n            this.detachDirWatcher()\n            throw error\n        }\n    }\n\n    /**\n     * Stop watching and release all resources.\n     *\n     * Resolves only after the consumer loop has actually exited — any\n     * `onBatch` in flight runs to completion first. This is the property\n     * the SDK's `close()` relies on to avoid dispatching to plugins after\n     * their `onDestroy` has already fired.\n     */\n    async stop(): Promise<void> {\n        if (!this.isRunning && !this.consumePromise) return\n\n        this.isRunning = false\n\n        this.detachWALWatcher()\n        this.detachDirWatcher()\n\n        if (this.triggerResolve) {\n            this.triggerResolve()\n            this.triggerResolve = null\n        }\n        this.hasPendingTrigger = false\n\n        const pending = this.consumePromise\n        this.consumePromise = null\n        if (pending) await pending\n    }\n\n    // -----------------------------------------------\n    // Single-slot semaphore\n    // -----------------------------------------------\n\n    private trigger(): void {\n        if (this.triggerResolve) {\n            this.triggerResolve()\n            this.triggerResolve = null\n            return\n        }\n        this.hasPendingTrigger = true\n    }\n\n    private waitForTrigger(): Promise<void> {\n        if (this.hasPendingTrigger) {\n            this.hasPendingTrigger = false\n            return Promise.resolve()\n        }\n        return new Promise<void>((resolve) => {\n            this.triggerResolve = resolve\n        })\n    }\n\n    // -----------------------------------------------\n    // Consumer loop\n    // -----------------------------------------------\n\n    private async consumeLoop(): Promise<void> {\n        while (this.isRunning) {\n            await this.waitForTrigger()\n            if (!this.isRunning) break\n\n            try {\n                while (await this.processBatch()) {\n                    if (!this.isRunning) break\n                }\n            } catch (error) {\n                this.handleError(error)\n            }\n        }\n    }\n\n    private async processBatch(): Promise<boolean> {\n        const messages = await this.database.getMessagesSinceRowId(this.lastRowId, { limit: BATCH_LIMIT })\n\n        if (messages.length > 0) {\n            if (!this.isRunning) return false\n            await this.onBatch?.(messages)\n            const last = messages[messages.length - 1]\n            if (last) this.lastRowId = last.rowId\n        }\n\n        return messages.length === BATCH_LIMIT\n    }\n\n    // -----------------------------------------------\n    // WAL / directory watcher state machine\n    // -----------------------------------------------\n\n    private ensureWatching(): void {\n        this.attachWALWatcher()\n        if (this.walWatcher) return\n\n        try {\n            this.attachDirWatcher()\n        } catch (error) {\n            const cause = toError(error)\n            throw new Error(`Failed to start watcher: WAL missing and directory watch failed — ${cause.message}`, {\n                cause,\n            })\n        }\n    }\n\n    private attachWALWatcher(): void {\n        if (this.walWatcher) return\n\n        try {\n            const watcher = this.watchFactory(this.walPath, (eventType) => {\n                if (eventType === 'change') {\n                    this.trigger()\n                } else if (eventType === 'rename') {\n                    this.detachWALWatcher()\n                    this.recoverOrStop('WAL file rotated')\n                }\n            })\n\n            watcher.on('error', () => {\n                this.detachWALWatcher()\n                this.recoverOrStop('WAL watcher failed')\n            })\n\n            this.walWatcher = watcher\n            this.detachDirWatcher()\n        } catch (error) {\n            // Only ENOENT is a legitimate fallback to dir-watch — the WAL\n            // file hasn't been created yet. Everything else (EACCES, EMFILE,\n            // …) is fatal and must surface.\n            if (!isMissingFileError(error)) throw error\n            if (this.debug) {\n                console.warn('[WatchSource] WAL missing, falling back to dir watch')\n            }\n        }\n    }\n\n    private detachWALWatcher(): void {\n        if (!this.walWatcher) return\n        this.walWatcher.close()\n        this.walWatcher = null\n    }\n\n    private attachDirWatcher(): void {\n        if (this.dirWatcher) return\n\n        const dir = dirname(this.databasePath)\n        const watcher = this.watchFactory(dir, (_eventType, filename) => {\n            const name =\n                typeof filename === 'string' ? filename : Buffer.isBuffer(filename) ? filename.toString('utf8') : null\n\n            if (name !== this.walFilename) return\n\n            // attachWALWatcher throws on non-ENOENT fs errors (EACCES,\n            // EMFILE, …). Route through handleError instead of letting\n            // the throw escape the fs.watch callback — that would\n            // surface as an uncaughtException and crash the host.\n            try {\n                this.attachWALWatcher()\n                this.trigger()\n            } catch (error) {\n                this.handleError(error)\n            }\n        })\n\n        watcher.on('error', () => {\n            this.detachDirWatcher()\n            this.recoverOrStop('Directory watcher failed')\n        })\n\n        this.dirWatcher = watcher\n    }\n\n    private detachDirWatcher(): void {\n        if (!this.dirWatcher) return\n        this.dirWatcher.close()\n        this.dirWatcher = null\n    }\n\n    // -----------------------------------------------\n    // Error handling\n    // -----------------------------------------------\n\n    private recoverOrStop(context: string): void {\n        try {\n            this.ensureWatching()\n        } catch (error) {\n            // Fire-and-forget: stop() is now async (awaits consumer loop),\n            // but this runs inside an fs.watch callback where we can't await.\n            // The error is reported immediately; the stop work completes in\n            // the background.\n            void this.stop()\n            this.handleError(new Error(`${context}: ${toError(error).message}`))\n        }\n    }\n\n    private handleError(error: unknown): void {\n        const err = toError(error)\n\n        if (this.debug) {\n            console.error('[WatchSource] Error:', err)\n        }\n\n        try {\n            this.onError?.(err)\n        } catch (callbackError) {\n            if (this.debug) {\n                console.error('[WatchSource] Error handler failed:', toError(callbackError))\n            }\n        }\n    }\n}\n\n// -----------------------------------------------\n// Helpers\n// -----------------------------------------------\n\nfunction isMissingFileError(error: unknown): boolean {\n    return typeof error === 'object' && error !== null && (error as { code?: string }).code === 'ENOENT'\n}\n","/**\n * Message target resolution.\n *\n * Maps a user-provided target string to either a DM (buddy method) or\n * group (chat method) send target. Format validity is delegated to\n * `ChatId.validate()`; this function only decides the routing kind.\n */\n\nimport { ChatId } from './chat-id'\n\n// -----------------------------------------------\n// Types\n// -----------------------------------------------\n\n/** Discriminated union for resolved send targets. */\nexport type MessageTarget =\n    | { readonly kind: 'dm'; readonly recipient: string }\n    | { readonly kind: 'group'; readonly chatId: ChatId }\n\n// -----------------------------------------------\n// Resolution\n// -----------------------------------------------\n\n/**\n * Resolve a target string.\n *\n * Exposed publicly so callers can pre-validate a `to` value (and branch\n * on DM vs group) before calling `sdk.send()` — the SDK itself invokes\n * this internally, so you only need it for up-front validation or\n * routing-aware UI.\n *\n * Accepted formats (enforced by `ChatId.validate`):\n *\n *   service;+;guid  /  chat<id>        → group\n *   service;-;addr  /  bare address    → DM\n *\n * Throws `IMessageError` (code `CONFIG`) for empty or malformed input.\n */\nexport function resolveTarget(input: string): MessageTarget {\n    const chatId = ChatId.fromUserInput(input)\n    chatId.validate()\n\n    if (chatId.isGroup) {\n        return { kind: 'group', chatId }\n    }\n\n    return { kind: 'dm', recipient: chatId.extractRecipient() ?? chatId.raw }\n}\n","/**\n * Send validation — minimal, non-heuristic.\n *\n * Only API-contract checks live here:\n *   - A send request must have text or at least one attachment.\n *   - `isURL` classifies a string as HTTP(S); infra uses it as a\n *     UX-friendly pre-check so attachment paths that look like URLs\n *     surface a clearer error than \"file not found\".\n *\n * Everything else (phone/email shape, recipient length, text length,\n * attachment count) is intentionally left to Messages.app so the user sees\n * the authoritative error instead of a local guess.\n *\n * Not a security boundary — shell/AppleScript escaping is handled in infra.\n */\n\nimport { SendError } from './errors'\n\n// -----------------------------------------------\n// URL classification\n// -----------------------------------------------\n\n/** Check whether a string looks like an HTTP(S) URL. UX pre-check only, not a security boundary. */\nexport function isURL(value: string): boolean {\n    return value.startsWith('http://') || value.startsWith('https://')\n}\n\n// -----------------------------------------------\n// Content validation\n// -----------------------------------------------\n\n/**\n * Validate that a send request has at least one piece of content.\n *\n * This is an API-contract check, not a heuristic gate: a message with\n * neither text nor attachments has nothing to send. Other dimensions\n * (text size, attachment count) are not enforced here.\n *\n * Throws `IMessageError` with code `SEND` on violation.\n */\nexport function validateMessageContent(text: string | undefined, attachments: readonly string[] | undefined): void {\n    const hasText = text != null && text !== ''\n    const hasAttachments = attachments != null && attachments.length > 0\n\n    if (!hasText && !hasAttachments) {\n        throw SendError('Message must have text or at least one attachment')\n    }\n}\n","/**\n * Platform detection.\n *\n * macOS requirement, default paths, Darwin version, and service prefix.\n */\n\nimport { homedir, release } from 'node:os'\nimport { join } from 'node:path'\nimport type { ChatServicePrefix } from '../domain/chat-id'\nimport { PlatformError, toError } from '../domain/errors'\n\n// -----------------------------------------------\n// macOS requirement\n// -----------------------------------------------\n\n/** Assert running on macOS. Throws PlatformError otherwise. */\nexport function requireMacOS(): void {\n    if (process.platform !== 'darwin') {\n        throw PlatformError('Only macOS is supported')\n    }\n}\n\n// -----------------------------------------------\n// Default paths\n// -----------------------------------------------\n\n/** Default path to the iMessage database. */\nexport function getDefaultDatabasePath(): string {\n    let home: string\n    try {\n        home = homedir()\n    } catch (cause) {\n        throw PlatformError('Unable to resolve user home directory', toError(cause))\n    }\n\n    return join(home, 'Library', 'Messages', 'chat.db')\n}\n\n// -----------------------------------------------\n// Darwin version\n// -----------------------------------------------\n\n/** Parse the Darwin major version number from os.release(). */\nexport function getDarwinMajorVersion(osRelease: string = release()): number {\n    const value = Number.parseInt(osRelease.split('.')[0] ?? '', 10)\n    return Number.isFinite(value) ? value : 0\n}\n\n// -----------------------------------------------\n// Service prefix\n// -----------------------------------------------\n\n/**\n * Map Darwin major version to the ChatId service prefix used by Messages.app.\n *\n * Threshold: Darwin 25 ≙ macOS 26 (Tahoe), where Messages.app switched from\n * the per-service `iMessage;+;…` GUID form to the transport-agnostic\n * `any;+;…` form. Earlier systems still require `iMessage`.\n */\nexport function detectChatServicePrefix(darwinMajor: number = getDarwinMajorVersion()): ChatServicePrefix {\n    return darwinMajor >= 25 ? 'any' : 'iMessage'\n}\n","/**\n * macOS / Messages.app protocol facts.\n *\n * These values are not engineering tuning — they are fixed by macOS TCC\n * sandbox policy and Messages.app handling conventions.\n */\n\n// -----------------------------------------------\n// TCC sandbox\n// -----------------------------------------------\n\n/**\n * Home-relative directories an `osascript`-launched Messages.app process can\n * read without triggering a TCC consent prompt. Attachments outside this set\n * must be copied into one of these directories before being handed to\n * Messages.app.\n *\n * Source: macOS TCC policy for the Messages sandbox (observed on macOS 14+,\n * unchanged on macOS 26).\n */\nexport const MESSAGES_APP_SANDBOX_SAFE_DIRS = ['Pictures', 'Downloads', 'Documents'] as const\n\n// -----------------------------------------------\n// Temp files\n// -----------------------------------------------\n\n/**\n * File-name prefix used by the SDK when copying an attachment into a\n * sandbox-safe directory. The temp-files cleanup pass identifies SDK-owned\n * files by this prefix before deleting them, so it must stay stable.\n */\nexport const MESSAGES_APP_TEMP_FILE_PREFIX = 'imsg_temp_'\n\n/**\n * Home-relative directory where the SDK writes bypass temp copies. Must\n * be one of {@link MESSAGES_APP_SANDBOX_SAFE_DIRS}. The write path\n * (applescript-builder), the cleanup pass (temp-files), and the sandbox\n * policy all read from this single constant.\n */\nexport const MESSAGES_APP_TEMP_WRITE_DIR = 'Pictures'\n","/**\n * AppleScript construction and attachment precheck.\n *\n * Pure, side-effect-free functions that turn a send job into an\n * osascript-ready script string. The single fs call (`statSync` in\n * `inspectAttachment`) is a precheck, not a transport.\n */\n\nimport { statSync } from 'node:fs'\nimport { homedir } from 'node:os'\nimport { basename, join } from 'node:path'\n\nimport {\n    MESSAGES_APP_SANDBOX_SAFE_DIRS,\n    MESSAGES_APP_TEMP_FILE_PREFIX,\n    MESSAGES_APP_TEMP_WRITE_DIR,\n} from '../../domain/messages-app'\n\n/** Absolute paths of TCC-safe directories. Resolved once at module load. */\nconst SANDBOX_SAFE_DIRS_ABS = MESSAGES_APP_SANDBOX_SAFE_DIRS.map((dir) => join(homedir(), dir))\n\n/** Absolute path of the bypass-temp write directory. */\nconst TEMP_WRITE_DIR_ABS = join(homedir(), MESSAGES_APP_TEMP_WRITE_DIR)\n\n// -----------------------------------------------\n// String Escaping\n// -----------------------------------------------\n\n/**\n * Escape special characters for safe embedding in an AppleScript string literal.\n */\nexport function escapeAppleScriptString(str: string): string {\n    const escapeMap: Record<string, string> = {\n        '\\\\': '\\\\\\\\',\n        '\"': '\\\\\"',\n        '\\n': '\\\\n',\n        '\\r': '\\\\r',\n        '\\t': '\\\\t',\n    }\n\n    return str.replace(/\\0/g, '').replace(/[\\\\\\n\\r\\t\"]/g, (char) => escapeMap[char] || char)\n}\n\n// -----------------------------------------------\n// Types\n// -----------------------------------------------\n\n/** AppleScript send method. `buddy` for DM recipients, `chat` for group chats. */\nexport type SendMethod = 'buddy' | 'chat'\n\n/**\n * Pre-computed facts about a local file about to be sent as an attachment.\n *\n * `needsBypass` is defined by the Messages.app sandbox policy (see\n * SANDBOX_SAFE_DIRS). Computing once upstream avoids re-scanning the path\n * while building the AppleScript.\n */\nexport interface ResolvedAttachment {\n    readonly localPath: string\n    readonly needsBypass: boolean\n}\n\n// -----------------------------------------------\n// Attachment precheck\n// -----------------------------------------------\n\n/**\n * Inspect a local file once to produce everything the send pipeline needs.\n *\n * Throws when the path is missing (`statSync` ENOENT) or is not a regular\n * file — callers map that to a user-facing `SendError`.\n */\nexport function inspectAttachment(localPath: string): ResolvedAttachment {\n    const stats = statSync(localPath)\n    if (!stats.isFile()) {\n        throw new Error(`Attachment is not a regular file: ${localPath}`)\n    }\n    const needsBypass = !SANDBOX_SAFE_DIRS_ABS.some((dir) => localPath.startsWith(`${dir}/`) || localPath === dir)\n    return { localPath, needsBypass }\n}\n\n// -----------------------------------------------\n// Script Builder\n// -----------------------------------------------\n\n/**\n * Build an AppleScript for sending a message via the Messages app.\n *\n * Uses the buddy method for DM recipients and the chat method for group chats.\n *\n * Transport selection — why buddy path hardcodes `service type = iMessage`:\n *   Messages.app's AppleScript `service type` enum contains only\n *   `iMessage` / `SMS` / `RCS` — there is no `any`. The transport-agnostic\n *   `any;+;` / `any;-;` prefix is a chat.db storage concept, not an\n *   AppleScript routing option. The chat method does accept `any;+;<guid>` /\n *   `any;-;<addr>`, but `chat id` only resolves EXISTING chats: a fresh DM to\n *   a never-contacted number errors with -1728 (\"Can't get chat id ...\"),\n *   so first-time DMs must go through the buddy path — and the buddy path\n *   requires picking a concrete `service type` enum value. We commit to\n *   iMessage; Messages.app may still auto-fall back to SMS/RCS at delivery\n *   time. The real transport only becomes observable after chat.db\n *   records it (read it from the confirmed `Message.service`).\n */\nexport function buildSendScript(params: {\n    readonly method: SendMethod\n    readonly identifier: string\n    readonly text?: string\n    readonly attachment?: ResolvedAttachment\n}): string {\n    const { method, identifier, text, attachment } = params\n    const escapedId = escapeAppleScriptString(identifier)\n\n    const targetSetup =\n        method === 'buddy'\n            ? `    set targetService to 1st service whose service type = iMessage\\n    set targetBuddy to buddy \"${escapedId}\" of targetService`\n            : `    set targetChat to chat id \"${escapedId}\"`\n\n    const targetVar = method === 'buddy' ? 'targetBuddy' : 'targetChat'\n\n    const bodyLines: string[] = []\n\n    if (text) {\n        const escapedText = escapeAppleScriptString(text)\n        bodyLines.push(`    send \"${escapedText}\" to ${targetVar}`)\n    }\n\n    if (attachment) {\n        bodyLines.push(buildAttachmentSnippet(attachment, targetVar))\n    }\n\n    const body = bodyLines.join('\\n\\n')\n\n    return `tell application \"Messages\"\n${targetSetup}\n\n${body}\nend tell`\n}\n\n// -----------------------------------------------\n// Internal\n// -----------------------------------------------\n\nfunction buildAttachmentSnippet(attachment: ResolvedAttachment, targetVar: string): string {\n    return attachment.needsBypass\n        ? buildSandboxBypassSnippet(attachment, targetVar)\n        : buildDirectSendSnippet(attachment, targetVar)\n}\n\n/**\n * Copy the file into a uniquely-named temp directory under its original\n * basename, then send that path through Messages.app.\n *\n * Why a directory instead of a renamed temp file: `mktemp` only replaces\n * trailing X's, so we can't embed the original filename (Chinese / emoji /\n * spaces) in the template. `mktemp -d` gives a unique parent; the file\n * inside keeps its exact name, which is what the recipient sees.\n *\n * Why `cat >` instead of `cp`: drops xattr / quarantine / ACL so\n * Messages.app's sandbox can read the fresh file.\n */\nfunction buildSandboxBypassSnippet(attachment: ResolvedAttachment, targetVar: string): string {\n    const { localPath } = attachment\n    const escapedFilePath = escapeAppleScriptString(localPath)\n    const escapedTempDir = escapeAppleScriptString(TEMP_WRITE_DIR_ABS)\n    const escapedBasename = escapeAppleScriptString(basename(localPath))\n\n    return `    set tmpDir to do shell script \"mktemp -d \" & quoted form of \"${escapedTempDir}/${MESSAGES_APP_TEMP_FILE_PREFIX}XXXXXXXXXX\"\n    set targetPath to tmpDir & \"/${escapedBasename}\"\n    do shell script \"cat \" & quoted form of \"${escapedFilePath}\" & \" > \" & quoted form of targetPath & \" && chmod 600 \" & quoted form of targetPath & \" || { rm -rf \" & quoted form of tmpDir & \"; exit 1; }\"\n    set theFile to (POSIX file targetPath) as alias\n    send theFile to ${targetVar}`\n}\n\nfunction buildDirectSendSnippet(attachment: ResolvedAttachment, targetVar: string): string {\n    const escapedPath = escapeAppleScriptString(attachment.localPath)\n    return `    send POSIX file \"${escapedPath}\" to ${targetVar}`\n}\n","/**\n * AppleScript execution and Messages.app liveness probe.\n *\n * Runtime-facing subprocess wrappers: stdin-based osascript execution\n * prevents shell injection; `MessagesAppProbe` caches a pgrep result so\n * high-throughput send loops don't fork a probe per send.\n */\n\nimport { type ChildProcess, execFile, spawn } from 'node:child_process'\nimport { promisify } from 'node:util'\n\nconst execFileAsync = promisify(execFile)\n\nconst DEFAULT_TIMEOUT_MS = 30_000\n\n/** Ceiling for `pgrep`-style process probes. pgrep returns in sub-ms on a healthy system. */\nconst PROBE_TIMEOUT_MS = 2_000\n\ntype OsascriptError = Error & { killed?: boolean }\n\n// -----------------------------------------------\n// Script Execution\n// -----------------------------------------------\n\n/**\n * Execute AppleScript via stdin and return stdout.\n *\n * @throws Error on execution failure or timeout\n */\nexport async function execAppleScript(\n    script: string,\n    options?: { debug?: boolean; timeout?: number; signal?: AbortSignal }\n): Promise<string> {\n    const debug = options?.debug ?? false\n    const timeoutMs = options?.timeout ?? DEFAULT_TIMEOUT_MS\n\n    if (debug) {\n        console.log('[AppleScript] Executing script:\\n', script)\n    }\n\n    try {\n        const { stdout, stderr } = await runViaStdin(script, timeoutMs, options?.signal)\n\n        if (stderr && debug) {\n            console.warn('[AppleScript] Warning:', stderr)\n        }\n\n        if (debug) {\n            console.log('[AppleScript] Success:', stdout || '(no output)')\n        }\n\n        return stdout.trim()\n    } catch (error: unknown) {\n        const err = error instanceof Error ? error : new Error(String(error))\n        const msg = err.message\n\n        // Distinguish caller-initiated abort from genuine timeout: both\n        // kill the child with SIGTERM (setting `killed`), but the abort\n        // path is expected shutdown, not a slow-network symptom.\n        if (options?.signal?.aborted) {\n            throw new Error('AppleScript execution aborted', { cause: err })\n        }\n\n        if ('killed' in err && (err as OsascriptError).killed) {\n            throw new Error(`AppleScript execution timeout (${timeoutMs}ms) - may be slow network or large file`, {\n                cause: err,\n            })\n        }\n\n        // Fragile heuristics: Messages.app stderr wording is not a stable\n        // API; these `includes` checks only remap the common cases to\n        // friendlier messages. If Apple changes the wording the generic\n        // \"AppleScript execution failed\" branch still runs, so the user\n        // still sees the underlying error.\n        if (msg.includes(\"Can't get buddy\")) {\n            throw new Error('Recipient not found or not added to iMessage contacts', { cause: err })\n        }\n\n        if (msg.includes(\"Can't send\")) {\n            throw new Error(\n                'Send failed - please check: 1) Is Messages signed in to iMessage, ' +\n                    '2) Is recipient correct, 3) Network connection',\n                { cause: err }\n            )\n        }\n\n        if (debug) {\n            console.error('[AppleScript] Error details:', err)\n        }\n\n        throw new Error(`AppleScript execution failed: ${msg}`, { cause: err })\n    }\n}\n\nfunction runViaStdin(\n    script: string,\n    timeoutMs: number,\n    signal?: AbortSignal\n): Promise<{ stdout: string; stderr: string }> {\n    return new Promise((resolve, reject) => {\n        if (signal?.aborted) {\n            reject(new Error('AppleScript execution aborted'))\n            return\n        }\n\n        const child: ChildProcess = spawn('osascript', ['-'], {\n            stdio: ['pipe', 'pipe', 'pipe'],\n            timeout: timeoutMs,\n        })\n\n        let stdout = ''\n        let stderr = ''\n        let killed = false\n\n        const onAbort = () => {\n            killed = true\n            child.kill('SIGTERM')\n        }\n        signal?.addEventListener('abort', onAbort, { once: true })\n\n        child.stdout?.on('data', (data: Buffer) => {\n            stdout += data.toString()\n        })\n        child.stderr?.on('data', (data: Buffer) => {\n            stderr += data.toString()\n        })\n\n        // If osascript dies before consuming stdin (e.g. killed by the\n        // `timeout` option or by our SIGTERM), writes emit EPIPE on the\n        // stdin stream. Without a listener Node surfaces it as an\n        // unhandled 'error' event. Swallow it — the real failure is\n        // reported by the 'close' handler below.\n        child.stdin?.on('error', () => {})\n\n        child.on('error', (err) => {\n            signal?.removeEventListener('abort', onAbort)\n            reject(err)\n        })\n\n        child.on('close', (code, sig) => {\n            signal?.removeEventListener('abort', onAbort)\n            if (sig === 'SIGTERM') killed = true\n\n            if (code === 0) {\n                resolve({ stdout, stderr })\n            } else {\n                const err = new Error(stderr || `osascript exited with code ${code}`) as OsascriptError\n                err.killed = killed\n                reject(err)\n            }\n        })\n\n        child.stdin?.write(script)\n        child.stdin?.end()\n    })\n}\n\n// -----------------------------------------------\n// Messages.app probe\n// -----------------------------------------------\n\n/**\n * Probe \"Messages.app running?\" with a short-lived cache.\n *\n * Used by Sender to avoid spawning a pgrep per send in high-throughput loops.\n * Cache is per-instance so SDK instances don't share state.\n */\nexport class MessagesAppProbe {\n    private static readonly CACHE_TTL_MS = 2_000\n    private cache: { readonly value: boolean; readonly expires: number } | null = null\n\n    async isRunning(): Promise<boolean> {\n        const now = Date.now()\n        if (this.cache && this.cache.expires > now) return this.cache.value\n\n        let value: boolean\n        try {\n            await execFileAsync('pgrep', ['-x', 'Messages'], { timeout: PROBE_TIMEOUT_MS })\n            value = true\n        } catch {\n            value = false\n        }\n\n        this.cache = { value, expires: now + MessagesAppProbe.CACHE_TTL_MS }\n        return value\n    }\n}\n","/**\n * SendPort implementation.\n *\n * Internal invariants:\n *   - Every error raised by `send()` is an `IMessageError`. Recognised\n *     `IMessageError` subclasses pass through with their original `code`\n *     (CONFIG / DATABASE / SEND) preserved; anything else is wrapped as\n *     `SendError` at the pipeline or semaphore boundary.\n *   - Dispatch is non-transactional. A multi-attachment send that fails\n *     mid-way leaves completed steps delivered; step numbering in the\n *     error description shows where the failure landed so the caller\n *     can retry only the remaining part.\n *\n * For the public contract of `send()` (acceptance vs delivery, hook\n * ordering, cancellation), see `sdk.ts::IMessageSDK.send`.\n */\n\nimport { basename, resolve } from 'node:path'\n\nimport type { SendPort } from '../../application/send-port'\nimport type { ChatServicePrefix } from '../../domain/chat-id'\nimport { IMessageError, SendError, toErrorMessage } from '../../domain/errors'\nimport { resolveTarget } from '../../domain/routing'\nimport { isURL, validateMessageContent } from '../../domain/validate'\nimport type { SendRequest } from '../../types/send'\nimport { delay, retry, type Semaphore } from '../../utils/async'\n\nimport { detectChatServicePrefix } from '../platform'\nimport { buildSendScript, inspectAttachment, type ResolvedAttachment, type SendMethod } from './applescript-builder'\nimport { execAppleScript, MessagesAppProbe } from './applescript-transport'\n\n// -----------------------------------------------\n// Defaults\n// -----------------------------------------------\n\n/** Per-osascript ceiling. Large attachments need headroom; beyond this is usually stuck. */\nconst SEND_TIMEOUT_MS = 30_000\n\n/** Total attempts per script (including the first); value of 3 → 1 initial + 2 retries. */\nconst RETRY_ATTEMPTS = 3\n\n/** Base backoff between retries (jitter on top). */\nconst RETRY_DELAY_MS = 1_500\n\n/** Gap between successive attachments; prevents Messages.app from dropping the next file. */\nconst INTER_ATTACHMENT_DELAY_MS = 500\n\n// -----------------------------------------------\n// Types\n// -----------------------------------------------\n\ntype SendTarget = { readonly method: SendMethod; readonly identifier: string }\n\ninterface NormalizedSendJob {\n    readonly target: SendTarget\n    readonly text?: string\n    readonly attachments: readonly string[]\n}\n\n/** Options for constructing a MessageSender. */\ninterface MessageSenderOptions {\n    readonly semaphore?: Semaphore\n    readonly debug?: boolean\n    readonly timeout?: number\n    /** Total attempts per AppleScript call including the first (matches `RetryOptions.attempts`). */\n    readonly retryAttempts?: number\n    readonly retryDelay?: number\n    /** Abort signal that cancels all sends on SDK shutdown. */\n    readonly signal?: AbortSignal\n}\n\n// -----------------------------------------------\n// MessageSender\n// -----------------------------------------------\n\n/** Send orchestrator implementing the application-layer SendPort. */\nexport class MessageSender implements SendPort {\n    private readonly debug: boolean\n    private readonly retryAttempts: number\n    private readonly retryDelay: number\n    private readonly sendTimeoutMs: number\n    private readonly chatServicePrefix: ChatServicePrefix\n    private readonly semaphore?: Semaphore\n    private readonly signal?: AbortSignal\n    private readonly messagesApp = new MessagesAppProbe()\n\n    constructor({\n        debug = false,\n        retryAttempts = RETRY_ATTEMPTS,\n        retryDelay = RETRY_DELAY_MS,\n        timeout = SEND_TIMEOUT_MS,\n        semaphore,\n        signal,\n    }: MessageSenderOptions = {}) {\n        this.debug = debug\n        this.retryAttempts = retryAttempts\n        this.retryDelay = retryDelay\n        this.sendTimeoutMs = timeout\n        this.semaphore = semaphore\n        this.signal = signal\n        this.chatServicePrefix = detectChatServicePrefix()\n    }\n\n    /** Implements `SendPort.send`. */\n    async send(request: SendRequest): Promise<void> {\n        const job = this.createSendJob(request)\n        const task = () => this.runPipeline(job)\n\n        try {\n            return await (this.semaphore ? this.semaphore.run(task, this.signal) : task())\n        } catch (error) {\n            // `runPipeline` already wraps everything it raises, so\n            // `IMessageError` passes through untouched. The uncovered\n            // case is an abort thrown inside `semaphore.acquire` BEFORE\n            // the task runs — wrap it here so the \"always IMessageError\"\n            // contract holds for queue-time cancellation.\n            if (error instanceof IMessageError) throw error\n            throw SendError('Send cancelled', error instanceof Error ? error : undefined)\n        }\n    }\n\n    // -----------------------------------------------\n    // Pipeline\n    // -----------------------------------------------\n\n    private async runPipeline(job: NormalizedSendJob): Promise<void> {\n        this.assertNotAborted()\n\n        try {\n            validateMessageContent(job.text, job.attachments)\n            await this.assertMessagesAppRunning()\n\n            const attachments = job.attachments.map((a) => this.resolveAttachment(a))\n            await this.dispatch(job.target, job.text, attachments)\n        } catch (error) {\n            // Inner helpers already produce fully-contextual `IMessageError`\n            // (validate, attachment-precheck, dispatch all attach their own\n            // detail). Re-wrapping here would duplicate recipient/step info,\n            // so the catch only guarantees \"always IMessageError\" — it does\n            // not append extra context.\n            if (error instanceof IMessageError) throw error\n            throw SendError(`Send failed: ${toErrorMessage(error)}`, error instanceof Error ? error : undefined)\n        }\n    }\n\n    private createSendJob(request: SendRequest): NormalizedSendJob {\n        const { to, text, attachments = [] } = request\n        const resolved = resolveTarget(to)\n\n        if (resolved.kind === 'group') {\n            const identifier = resolved.chatId.buildGroupGuid(this.chatServicePrefix)\n            return { target: { method: 'chat', identifier }, text, attachments }\n        }\n\n        return { target: { method: 'buddy', identifier: resolved.recipient }, text, attachments }\n    }\n\n    private async dispatch(\n        target: SendTarget,\n        text: string | undefined,\n        attachments: ResolvedAttachment[]\n    ): Promise<void> {\n        const { method, identifier } = target\n        const prefix = method === 'chat' ? `group ${identifier}` : identifier\n        const total = attachments.length\n        const hasText = text != null && text !== ''\n\n        // Non-transactional: N attachments dispatch up to max(1, N)\n        // osascript calls (first call bundles text + attachments[0]; each\n        // later attachment is its own call). Retry is per-step, not\n        // end-to-end — worst case is `retryAttempts × max(1, N)` osascript\n        // invocations. Resuming mid-batch is the caller's job: re-invoke\n        // send() with attachments.slice(k-1).\n        const firstLabel = total === 0 ? 'text' : hasText ? `text + attachment 1/${total}` : `attachment 1/${total}`\n        const firstScript = buildSendScript({\n            method,\n            identifier,\n            text: hasText ? text : undefined,\n            attachment: attachments[0],\n        })\n        await this.executeWithRetry(firstScript, `Send ${firstLabel} to ${prefix}`)\n\n        for (let i = 1; i < total; i++) {\n            await delay(INTER_ATTACHMENT_DELAY_MS, this.signal)\n            const script = buildSendScript({ method, identifier, attachment: attachments[i] })\n            await this.executeWithRetry(script, `Send attachment ${i + 1}/${total} to ${prefix}`)\n        }\n    }\n\n    // -----------------------------------------------\n    // Helpers\n    // -----------------------------------------------\n\n    private async executeWithRetry(script: string, description: string): Promise<void> {\n        try {\n            await retry(\n                () => execAppleScript(script, { debug: this.debug, timeout: this.sendTimeoutMs, signal: this.signal }),\n                {\n                    attempts: this.retryAttempts,\n                    delay: this.retryDelay,\n                    signal: this.signal,\n                }\n            )\n        } catch (error) {\n            throw SendError(\n                `${description} failed after ${this.retryAttempts} attempts: ${toErrorMessage(error)}`,\n                error instanceof Error ? error : undefined\n            )\n        }\n    }\n\n    private resolveAttachment(path: string): ResolvedAttachment {\n        if (isURL(path)) {\n            throw SendError(\n                `URLs are not supported as attachments. Download the file yourself and pass a local path instead: ${path.slice(0, 120)}`\n            )\n        }\n\n        const localPath = resolve(path)\n        try {\n            return inspectAttachment(localPath)\n        } catch (error) {\n            // Preserve the underlying cause (ENOENT/EACCES/EIO/…) so debuggers\n            // aren't misled into only checking whether the path exists.\n            const cause = error instanceof Error ? error : new Error(String(error))\n            throw SendError(`Attachment unreadable: ${basename(path) || 'unknown'}: ${cause.message}`, cause)\n        }\n    }\n\n    private assertNotAborted(): void {\n        if (this.signal?.aborted) throw SendError('Send cancelled')\n    }\n\n    private async assertMessagesAppRunning(): Promise<void> {\n        if (!(await this.messagesApp.isRunning())) {\n            throw SendError('Messages app is not running')\n        }\n    }\n}\n","/**\n * Temporary file lifecycle management.\n *\n * The send pipeline copies attachments into `~/Pictures/imsg_temp_*`\n * directories (see `applescript-builder.ts`) so Messages.app's sandbox\n * can read them — this manager sweeps those entries when they exceed\n * `maxAge`.\n *\n * Multi-instance safe: cleanup filters by mtime, so one SDK instance\n * never deletes another's in-flight attachments.\n */\n\nimport { existsSync, lstatSync, readdirSync, rmSync } from 'node:fs'\nimport { homedir } from 'node:os'\nimport { join } from 'node:path'\n\nimport { ConfigError } from '../../domain/errors'\nimport { MESSAGES_APP_TEMP_FILE_PREFIX, MESSAGES_APP_TEMP_WRITE_DIR } from '../../domain/messages-app'\n\nconst TEMP_DIR = join(homedir(), MESSAGES_APP_TEMP_WRITE_DIR)\n\n// -----------------------------------------------\n// Config\n// -----------------------------------------------\n\n/** Configuration for the TempFileManager. */\nexport interface TempFileManagerConfig {\n    /** File retention time in ms (default: 10 minutes). */\n    readonly maxAge?: number\n    /** Cleanup interval in ms (default: 5 minutes). */\n    readonly cleanupInterval?: number\n    /** Enable debug logs. */\n    readonly debug?: boolean\n}\n\nconst DEFAULTS = {\n    maxAge: 10 * 60 * 1_000,\n    cleanupInterval: 5 * 60 * 1_000,\n} as const\n\n// -----------------------------------------------\n// TempFileManager\n// -----------------------------------------------\n\n/** Manages lifecycle of `imsg_temp_*` entries in ~/Pictures. */\nexport class TempFileManager {\n    private readonly config: Required<TempFileManagerConfig>\n    private cleanupTimer: NodeJS.Timeout | null = null\n    private destroyPromise: Promise<void> | null = null\n\n    constructor(config: TempFileManagerConfig = {}) {\n        this.config = {\n            maxAge: config.maxAge ?? DEFAULTS.maxAge,\n            cleanupInterval: config.cleanupInterval ?? DEFAULTS.cleanupInterval,\n            debug: config.debug ?? false,\n        }\n    }\n\n    // -----------------------------------------------\n    // Lifecycle\n    // -----------------------------------------------\n\n    /** Start the periodic cleanup timer. */\n    start(): void {\n        if (this.destroyPromise) {\n            throw ConfigError('TempFileManager is destroyed or destroying, cannot start')\n        }\n\n        if (this.cleanupTimer) return\n\n        this.removeExpiredFiles()\n\n        this.cleanupTimer = setInterval(() => {\n            if (this.destroyPromise) return\n            this.removeExpiredFiles()\n        }, this.config.cleanupInterval)\n\n        // Allow process exit if this timer is the only remaining event.\n        this.cleanupTimer.unref()\n\n        if (this.config.debug) {\n            const intervalSec = this.config.cleanupInterval / 1_000\n            const maxAgeSec = this.config.maxAge / 1_000\n            console.log(`[TempFileManager] Started, interval: ${intervalSec}s, maxAge: ${maxAgeSec}s`)\n        }\n    }\n\n    /** Stop the timer and remove expired files. */\n    async destroy(): Promise<void> {\n        if (this.destroyPromise) return this.destroyPromise\n        this.destroyPromise = this.doDestroy()\n        return this.destroyPromise\n    }\n\n    // -----------------------------------------------\n    // Internal\n    // -----------------------------------------------\n\n    private async doDestroy(): Promise<void> {\n        if (this.cleanupTimer) {\n            clearInterval(this.cleanupTimer)\n            this.cleanupTimer = null\n        }\n\n        this.removeExpiredFiles()\n\n        if (this.config.debug) {\n            console.log('[TempFileManager] Destroyed')\n        }\n    }\n\n    private removeExpiredFiles(): void {\n        const now = Date.now()\n\n        try {\n            if (!existsSync(TEMP_DIR)) return\n\n            const entries = readdirSync(TEMP_DIR)\n\n            for (const entry of entries) {\n                if (!entry.startsWith(MESSAGES_APP_TEMP_FILE_PREFIX)) continue\n\n                const entryPath = join(TEMP_DIR, entry)\n\n                try {\n                    const stats = lstatSync(entryPath)\n                    const age = now - stats.mtimeMs\n                    if (age <= this.config.maxAge) continue\n\n                    // `recursive: true` handles both the current directory\n                    // layout and any legacy single-file temp entries;\n                    // `force: true` tolerates races (e.g. concurrent sweep).\n                    rmSync(entryPath, { recursive: true, force: true })\n\n                    if (this.config.debug) {\n                        console.log(`[TempFileManager] Removed: ${entry}`)\n                    }\n                } catch (error) {\n                    if (this.config.debug) {\n                        console.error(`[TempFileManager] Failed to remove: ${entry}`, error)\n                    }\n                }\n            }\n        } catch (error) {\n            if (this.config.debug) {\n                console.error('[TempFileManager] Cleanup process error:', error)\n            }\n        }\n    }\n}\n","/**\n * Plugin lifecycle management and hook dispatch.\n *\n * Three dispatch modes (aligned with Vite/Rollup conventions):\n *   - Interrupting (fail-fast): onBefore*   — first throw aborts the SDK operation.\n *     Go through `callInterruptingHook`.\n *   - Sequential (observing):   onInit, onError, onDestroy — run one at a time,\n *     failures collected and reported to `onError`. Go through `callHook`.\n *   - Parallel (observing):     onAfter*, onIncomingMessage, onFromMe — concurrent,\n *     failures collected and reported to `onError`. Go through `callHook`.\n *\n * Plugin ordering via `order` property within each mode:\n *   - 'pre' plugins run first\n *   - 'post' plugins run last\n *   - Unset (normal) plugins run in registration order between pre and post\n */\n\nimport type { MessageSink } from '../application/message-dispatcher'\nimport { ConfigError, type ErrorCode, IMessageError, toError } from '../domain/errors'\nimport type { Message } from '../domain/message'\nimport type { Plugin, PluginErrorContext, PluginHooks } from '../types/plugin'\n\n// -----------------------------------------------\n// Internal Types\n// -----------------------------------------------\n\n/** Error captured from a single plugin's hook execution. */\ntype HookError = { readonly plugin: string; readonly error: Error }\n\n/** Any hook except `onError` — used to prevent recursive error reporting. */\ntype NonErrorHookName = Exclude<keyof PluginHooks, 'onError'>\n\n// -----------------------------------------------\n// Hook Classification\n// -----------------------------------------------\n\n/**\n * Hooks that `callHook` dispatches one at a time. These are lifecycle /\n * observation hooks where ordering matters but a single failure must not\n * cascade. The `onBefore*` family is not listed here — those go through\n * `callInterruptingHook`, which is fail-fast and rethrows.\n */\nconst SEQUENTIAL_HOOKS: ReadonlySet<keyof PluginHooks> = new Set(['onInit', 'onError', 'onDestroy'])\n\n// -----------------------------------------------\n// PluginManager\n// -----------------------------------------------\n\n/** Manages plugin registration, lifecycle, and hook dispatch. */\nexport class PluginManager {\n    private plugins: Plugin[] = []\n    /**\n     * Plugins whose `onInit` is still running. They are deliberately excluded\n     * from hook dispatch until init completes — otherwise a plugin could\n     * receive `onIncomingMessage` / `onBeforeSend` before its `onInit` had a chance\n     * to run, violating the documented lifecycle contract.\n     */\n    private pendingPlugins: Plugin[] = []\n    private pendingInits: Promise<void>[] = []\n    private destroying = false\n    private destroyPromise: Promise<void> | null = null\n    /** Shared promise for concurrent `init()` callers; `_initialized` is an observation flag, not a gate. */\n    private initPromise: Promise<void> | null = null\n    private _initialized = false\n\n    get initialized(): boolean {\n        return this._initialized\n    }\n\n    // -----------------------------------------------\n    // Registration\n    // -----------------------------------------------\n\n    /** Register a plugin. Deduplicates by name; late registrations auto-init. */\n    use(plugin: Plugin): this {\n        if (this.destroying) {\n            throw ConfigError('PluginManager is destroying, cannot register new plugins')\n        }\n\n        const isDuplicate =\n            this.plugins.some((current) => current.name === plugin.name) ||\n            this.pendingPlugins.some((current) => current.name === plugin.name)\n        if (isDuplicate) {\n            throw ConfigError(`Plugin \"${plugin.name}\" is already registered`)\n        }\n\n        if (this.initPromise && plugin.onInit) {\n            // Park the plugin in `pendingPlugins` so hook dispatch skips it\n            // until `onInit` completes. Move to `plugins` afterwards, even\n            // on init failure — a failed-init plugin is still registered\n            // and should receive `onDestroy` for cleanup.\n            //\n            // Trigger condition is `initPromise`, not `_initialized`: a\n            // concurrent init may have started but not yet resolved — plugins\n            // registered in that window must still run their own onInit.\n            this.pendingPlugins.push(plugin)\n            const initPromise = (async () => {\n                let initError: unknown = null\n                try {\n                    await plugin.onInit?.()\n                } catch (error) {\n                    initError = error\n                }\n\n                const idx = this.pendingPlugins.indexOf(plugin)\n                if (idx !== -1) this.pendingPlugins.splice(idx, 1)\n                this.plugins.push(plugin)\n\n                if (initError !== null) {\n                    await this.reportHookError(plugin.name, 'onInit', initError)\n                }\n            })()\n            this.pendingInits.push(initPromise)\n        } else {\n            this.plugins.push(plugin)\n        }\n\n        return this\n    }\n\n    // -----------------------------------------------\n    // Lifecycle\n    // -----------------------------------------------\n\n    /** Initialize all registered plugins. Idempotent — subsequent calls flush late registrations. */\n    async init(): Promise<void> {\n        if (this.initPromise) {\n            await this.initPromise\n            await this.flushPendingInits()\n            return\n        }\n\n        this.initPromise = this.callHook('onInit').then(() => {\n            this._initialized = true\n        })\n        await this.initPromise\n        await this.flushPendingInits()\n    }\n\n    /**\n     * Destroy all plugins and reset state. Concurrent callers await the\n     * same in-flight destroy; sequential callers can re-register and\n     * destroy again.\n     */\n    async destroy(): Promise<void> {\n        if (this.destroyPromise) return this.destroyPromise\n\n        this.destroyPromise = (async () => {\n            this.destroying = true\n\n            try {\n                await this.flushPendingInits()\n                await this.callHook('onDestroy')\n                this.plugins = []\n                this.pendingPlugins = []\n                this._initialized = false\n                this.initPromise = null\n            } finally {\n                this.destroying = false\n                this.destroyPromise = null\n            }\n        })()\n\n        return this.destroyPromise\n    }\n\n    // -----------------------------------------------\n    // Hook Dispatch\n    // -----------------------------------------------\n\n    /**\n     * Dispatch a hook to all plugins that implement it.\n     *\n     * Collects errors without interrupting the dispatch — each plugin runs\n     * regardless of its peers' failures. Use `callInterruptingHook` for\n     * hooks whose failure must abort the surrounding operation (e.g.\n     * `onBeforeSend` acting as an authorisation gate).\n     */\n    async callHook<K extends keyof PluginHooks>(\n        hookName: K,\n        ...args: Parameters<NonNullable<PluginHooks[K]>>\n    ): Promise<HookError[]> {\n        const pluginsWithHook = this.sortedPluginsWithHook(hookName)\n\n        if (pluginsWithHook.length === 0) return []\n\n        const errors = SEQUENTIAL_HOOKS.has(hookName)\n            ? await this.dispatchSequential(pluginsWithHook, hookName, args)\n            : await this.dispatchParallel(pluginsWithHook, hookName, args)\n\n        if (errors.length > 0 && hookName !== 'onError') {\n            for (const { plugin, error } of errors) {\n                await this.reportHookError(plugin, hookName as NonErrorHookName, error)\n            }\n        }\n\n        return errors\n    }\n\n    /**\n     * Fail-fast dispatch for interception-style hooks (`onBefore*`). The\n     * first plugin that throws aborts dispatch; remaining plugins are NOT\n     * invoked, and the throw is re-raised as `IMessageError(code, ...)`\n     * with the original error as `cause`. Designed so a single plugin can\n     * gate auth / rate-limit / policy by throwing.\n     *\n     * Deliberately does NOT route the rejection through `onError`: a gate\n     * plugin rejecting a send is intended behaviour, not an unexpected\n     * error, and logging every rejection as a plugin failure is noise.\n     */\n    async callInterruptingHook<K extends keyof PluginHooks>(\n        hookName: K,\n        code: ErrorCode,\n        ...args: Parameters<NonNullable<PluginHooks[K]>>\n    ): Promise<void> {\n        const plugins = this.sortedPluginsWithHook(hookName)\n        if (plugins.length === 0) return\n\n        for (const plugin of plugins) {\n            try {\n                const hookFn = plugin[hookName] as (...a: typeof args) => void | Promise<void>\n                await Promise.resolve(hookFn(...args))\n            } catch (error) {\n                const cause = toError(error)\n                throw new IMessageError(\n                    code,\n                    `Plugin \"${plugin.name}\" ${String(hookName)} rejected: ${cause.message}`,\n                    { cause }\n                )\n            }\n        }\n    }\n\n    // -----------------------------------------------\n    // Dispatch Strategies\n    // -----------------------------------------------\n\n    private async dispatchSequential<K extends keyof PluginHooks>(\n        plugins: Plugin[],\n        hookName: K,\n        args: Parameters<NonNullable<PluginHooks[K]>>\n    ): Promise<HookError[]> {\n        const errors: HookError[] = []\n\n        for (const plugin of plugins) {\n            try {\n                const hookFn = plugin[hookName] as (...a: typeof args) => void | Promise<void>\n                await Promise.resolve(hookFn(...args))\n            } catch (error) {\n                errors.push({ plugin: plugin.name, error: toError(error) })\n            }\n        }\n\n        return errors\n    }\n\n    private async dispatchParallel<K extends keyof PluginHooks>(\n        plugins: Plugin[],\n        hookName: K,\n        args: Parameters<NonNullable<PluginHooks[K]>>\n    ): Promise<HookError[]> {\n        const outcomes = await Promise.all(\n            plugins.map(async (plugin) => {\n                try {\n                    const hookFn = plugin[hookName] as (...a: typeof args) => void | Promise<void>\n                    await Promise.resolve(hookFn(...args))\n\n                    return { plugin: plugin.name, error: null as Error | null }\n                } catch (error) {\n                    return { plugin: plugin.name, error: toError(error) }\n                }\n            })\n        )\n\n        const errors: HookError[] = []\n\n        for (const outcome of outcomes) {\n            if (outcome.error !== null) {\n                errors.push({ plugin: outcome.plugin, error: outcome.error })\n            }\n        }\n\n        return errors\n    }\n\n    // -----------------------------------------------\n    // Ordering\n    // -----------------------------------------------\n\n    private sortedPluginsWithHook<K extends keyof PluginHooks>(hookName: K): Plugin[] {\n        const withHook = this.plugins.filter((p) => p[hookName])\n        if (withHook.length <= 1) return withHook\n\n        const pre: Plugin[] = []\n        const normal: Plugin[] = []\n        const post: Plugin[] = []\n\n        for (const plugin of withHook) {\n            if (plugin.order === 'pre') pre.push(plugin)\n            else if (plugin.order === 'post') post.push(plugin)\n            else normal.push(plugin)\n        }\n\n        return [...pre, ...normal, ...post]\n    }\n\n    // -----------------------------------------------\n    // Internal Helpers\n    // -----------------------------------------------\n\n    private async flushPendingInits(): Promise<void> {\n        // Loop so late registrations arriving while we await the current\n        // batch are picked up on the next iteration. Swap-before-await\n        // prevents the bug where `this.pendingInits = []` at the end wipes\n        // promises pushed during the await.\n        while (this.pendingInits.length > 0) {\n            const toFlush = this.pendingInits\n            this.pendingInits = []\n            await Promise.all(toFlush)\n        }\n    }\n\n    private async reportHookError(plugin: string, hookName: NonErrorHookName, error: unknown): Promise<void> {\n        const normalizedError = toError(error)\n        console.error(`[Plugin ${plugin}] ${hookName} failed:`, normalizedError)\n\n        try {\n            await this.callHook('onError', {\n                error: normalizedError,\n                context: `Plugin ${plugin} - ${String(hookName)}`,\n            })\n        } catch (hookError) {\n            // Log but don't rethrow to prevent infinite recursion\n            console.error(\n                `[Plugin ${plugin}] onError hook failed (suppressed to prevent recursion):`,\n                toError(hookError)\n            )\n        }\n    }\n}\n\n// -----------------------------------------------\n// Helpers\n// -----------------------------------------------\n\n/** Identity function that provides type inference for plugin definitions. */\nexport const definePlugin = (plugin: Plugin): Plugin => plugin\n\n/** Create a MessageSink that forwards to plugin hooks. */\nexport function createPluginMessageSink(manager: PluginManager): MessageSink {\n    return {\n        async onIncomingMessage(message: Message): Promise<void> {\n            await manager.callHook('onIncomingMessage', { message })\n        },\n        async onFromMe(message: Message): Promise<void> {\n            await manager.callHook('onFromMe', { message })\n        },\n        onError(error: Error, context: string): void {\n            const ctx: PluginErrorContext = { error, context }\n            void manager.callHook('onError', ctx)\n        },\n    }\n}\n","/**\n * Canonical SDK configuration bounds.\n *\n * Standalone module with zero dependencies — safe to import from anywhere.\n */\nexport const BOUNDS = {\n    maxConcurrentSends: { default: 10, min: 1, max: 50 },\n    sendTimeout: { default: 30_000, min: 1_000, max: 300_000 },\n} as const\n","/**\n * IMessageSDK — composition root.\n *\n * Wires domain, application, and infrastructure layers into a\n * single public API. All external dependencies are resolved here.\n */\n\nimport { type DispatchEvents, MessageDispatcher } from './application/message-dispatcher'\nimport type { SendPort } from './application/send-port'\nimport type { Chat } from './domain/chat'\nimport { ConfigError, toError } from './domain/errors'\nimport type { Message } from './domain/message'\nimport { MessagesDatabaseReader } from './infra/db/reader'\nimport { MessageWatchSource } from './infra/db/watcher'\nimport { MessageSender } from './infra/outgoing/sender'\nimport { TempFileManager } from './infra/outgoing/temp-files'\nimport { getDefaultDatabasePath, requireMacOS } from './infra/platform'\nimport { createPluginMessageSink, PluginManager } from './infra/plugin'\nimport { BOUNDS } from './sdk-bounds'\nimport type { IMessageConfig } from './types/config'\nimport type { Plugin } from './types/plugin'\nimport type { ChatQuery, MessageQuery } from './types/query'\nimport type { SendRequest } from './types/send'\nimport { Semaphore } from './utils/async'\n\n// -----------------------------------------------\n// Constants\n// -----------------------------------------------\n\nconst ERROR_SDK_DESTROYED = 'SDK is destroyed'\nconst ERROR_WATCHER_RUNNING = 'Watcher is already running'\n\n/**\n * Per-component shutdown failure captured by `safeRun`.\n *\n * `close()` must run every teardown even if an earlier one throws — a single\n * plugin.onDestroy failure must not leak the database handle or temp-file\n * timer. Each step is wrapped in `safeRun`, which pushes `{component, error}`\n * instead of rethrowing; `doClose` then collects all captures into one\n * `AggregateError` so the caller sees every failure, not just the first.\n */\ntype ShutdownError = { readonly component: string; readonly error: Error }\n\n// -----------------------------------------------\n// IMessageSDK\n// -----------------------------------------------\n\nexport class IMessageSDK implements SendPort {\n    private readonly databasePath: string\n    private readonly debug: boolean\n\n    private readonly database: MessagesDatabaseReader\n    private readonly tempFiles: TempFileManager\n    private readonly sender: MessageSender\n    private readonly plugins: PluginManager\n    private readonly abortController = new AbortController()\n\n    private watchSource: MessageWatchSource | null = null\n    private destroyed = false\n    private closePromise: Promise<void> | null = null\n\n    constructor(config: IMessageConfig = {}) {\n        requireMacOS()\n\n        this.databasePath = config.databasePath ?? getDefaultDatabasePath()\n        this.debug = config.debug ?? false\n\n        const maxConcurrentSends = validateBound(\n            config.maxConcurrentSends,\n            BOUNDS.maxConcurrentSends,\n            'maxConcurrentSends'\n        )\n\n        const sendTimeout = validateBound(config.sendTimeout, BOUNDS.sendTimeout, 'sendTimeout')\n\n        this.database = new MessagesDatabaseReader(this.databasePath)\n        this.plugins = new PluginManager()\n\n        const semaphore = new Semaphore(maxConcurrentSends)\n\n        this.sender = new MessageSender({\n            semaphore,\n            debug: this.debug,\n            timeout: sendTimeout,\n            signal: this.abortController.signal,\n        })\n\n        this.tempFiles = new TempFileManager({ debug: this.debug })\n        this.tempFiles.start()\n\n        if (config.plugins) {\n            for (const plugin of config.plugins) {\n                this.plugins.use(plugin)\n            }\n        }\n\n        if (this.debug) {\n            const pluginCount = config.plugins?.length ?? 0\n            console.log(\n                `[SDK] Initialized: db=${this.databasePath} plugins=${pluginCount} ` +\n                    `maxConcurrentSends=${maxConcurrentSends} sendTimeout=${sendTimeout}ms`\n            )\n        }\n    }\n\n    // -----------------------------------------------\n    // Plugin Management\n    // -----------------------------------------------\n\n    /** Register a plugin. Late registrations are auto-initialized. */\n    use(plugin: Plugin): this {\n        this.assertNotDestroyed()\n        this.plugins.use(plugin)\n        return this\n    }\n\n    // -----------------------------------------------\n    // Message Queries\n    // -----------------------------------------------\n\n    /** Query messages with optional filters. */\n    async getMessages(query: MessageQuery = {}): Promise<readonly Message[]> {\n        this.assertNotDestroyed()\n        await this.plugins.init()\n\n        await this.plugins.callInterruptingHook('onBeforeMessageQuery', 'DATABASE', { query })\n        const messages = await this.database.getMessages(query)\n        await this.plugins.callHook('onAfterMessageQuery', { query, messages })\n\n        return messages\n    }\n\n    /** List chats with optional filters and sorting. */\n    async listChats(query: ChatQuery = {}): Promise<readonly Chat[]> {\n        this.assertNotDestroyed()\n        await this.plugins.init()\n\n        await this.plugins.callInterruptingHook('onBeforeChatQuery', 'DATABASE', { query })\n        const chats = await this.database.listChats(query)\n        await this.plugins.callHook('onAfterChatQuery', { query, chats })\n\n        return chats\n    }\n\n    // -----------------------------------------------\n    // Message Sending\n    // -----------------------------------------------\n\n    /**\n     * Resolves when Messages.app accepts the AppleScript dispatch — acceptance,\n     * not delivery. For the chat.db row or later `isDelivered` transitions\n     * observe the watcher (`onFromMeMessage` callback on `startWatching`, or\n     * plugin hook `onFromMe`); for \"accepted\" only, `onAfterSend` is lighter.\n     *\n     * The first `onBeforeSend` to throw aborts dispatch with `IMessageError`\n     * (code `SEND`, thrown error as `cause`); `onAfterSend` does not fire.\n     * Also throws `IMessageError` on validation, AppleScript dispatch, or\n     * shutdown cancellation.\n     */\n    async send(request: SendRequest): Promise<void> {\n        this.assertNotDestroyed()\n        await this.plugins.init()\n\n        await this.plugins.callInterruptingHook('onBeforeSend', 'SEND', { request })\n        await this.sender.send(request)\n        await this.plugins.callHook('onAfterSend', { request })\n    }\n\n    // -----------------------------------------------\n    // Watcher\n    // -----------------------------------------------\n\n    /**\n     * Start watching for new messages in real time.\n     *\n     * Independent of `sdk.send()` — sends do not require a watcher.\n     * A running watcher gives you:\n     *   - `onIncomingMessage` / `onDirectMessage` / `onGroupMessage` for peers' messages\n     *   - `onFromMeMessage` for your own sends (including reads of\n     *     `isDelivered`, edits, retractions as they land in chat.db)\n     *\n     * Throws `IMessageError` (code `CONFIG`) if a watcher is already\n     * running on this SDK instance — stop the existing one first.\n     */\n    async startWatching(events: DispatchEvents = {}): Promise<void> {\n        this.assertNotDestroyed()\n        if (this.watchSource) throw ConfigError(ERROR_WATCHER_RUNNING)\n\n        const dispatcher = new MessageDispatcher({\n            events,\n            sink: createPluginMessageSink(this.plugins),\n            debug: this.debug,\n        })\n\n        const watcher = new MessageWatchSource({\n            database: this.database,\n            databasePath: this.databasePath,\n            onBatch: (messages) => dispatcher.dispatch(messages),\n            onError: (error) => dispatcher.handleError(error, 'watch-source'),\n            debug: this.debug,\n        })\n\n        // Claim the slot SYNCHRONOUSLY — before any await — so a second\n        // concurrent startWatching() call in the same tick hits the\n        // `if (this.watchSource)` gate above and throws instead of\n        // silently building a parallel watcher that would orphan us.\n        // Also registers the watcher before start() so a racing\n        // stopWatching()/close() can find and stop it; watcher.stop()\n        // tolerates \"not yet running\" (see watcher.stop guard).\n        this.watchSource = watcher\n\n        try {\n            await this.plugins.init()\n            await watcher.start()\n        } catch (error) {\n            // watcher.start() already cleaned up its own resources on failure.\n            if (this.watchSource === watcher) {\n                this.watchSource = null\n            }\n            throw error\n        }\n    }\n\n    /**\n     * Stop watching for new messages.\n     *\n     * Resolves only after any in-flight batch dispatch has finished, so\n     * callers chaining `await sdk.stopWatching()` observe a truly quiet SDK.\n     */\n    async stopWatching(): Promise<void> {\n        await this.teardownWatcher()\n    }\n\n    // -----------------------------------------------\n    // Lifecycle\n    // -----------------------------------------------\n\n    /** Gracefully shut down the SDK and release all resources. */\n    async close(): Promise<void> {\n        // Concurrent callers must await the SAME in-flight shutdown — a\n        // plain `if (this.destroyed) return` would let the second caller\n        // resolve immediately while the first is still mid-teardown, so\n        // its callers could race with not-yet-released resources\n        // (database handle, temp files, plugin onDestroy).\n        if (this.closePromise) return this.closePromise\n        this.closePromise = this.doClose()\n        return this.closePromise\n    }\n\n    private async doClose(): Promise<void> {\n        this.destroyed = true\n\n        const errors: ShutdownError[] = []\n\n        this.abortController.abort(new Error('SDK closed'))\n\n        // Await watcher teardown BEFORE destroying plugins: stop() drains\n        // the consumer loop, so no onBatch (= onIncomingMessage dispatch) can\n        // fire after the plugins' onDestroy hooks run.\n        await safeRun(errors, 'watcher', () => this.teardownWatcher())\n        await safeRun(errors, 'pluginManager', () => this.plugins.destroy())\n        await safeRun(errors, 'tempFileManager', () => this.tempFiles.destroy())\n        await safeRun(errors, 'database', () => this.database.close())\n\n        if (errors.length > 0) {\n            if (this.debug) {\n                const summary = errors.map((e) => `${e.component}: ${e.error.message}`).join('; ')\n                console.error(`[SDK] Shutdown failed — ${summary}`)\n            }\n\n            throw new AggregateError(\n                errors.map((e) => e.error),\n                `SDK shutdown failed: ${errors.map((e) => e.component).join(', ')}`\n            )\n        }\n    }\n\n    async [Symbol.asyncDispose](): Promise<void> {\n        await this.close()\n    }\n\n    // -----------------------------------------------\n    // Internal\n    // -----------------------------------------------\n\n    private assertNotDestroyed(): void {\n        if (this.destroyed) throw ConfigError(ERROR_SDK_DESTROYED)\n    }\n\n    /**\n     * Single path for tearing down the watcher.\n     *\n     * Awaits `watchSource.stop()` so that any in-flight `onBatch` dispatch\n     * has completed before we return to the caller — this is what\n     * prevents plugin `onIncomingMessage` from racing with `onDestroy` during\n     * SDK shutdown.\n     */\n    private async teardownWatcher(): Promise<void> {\n        const watcher = this.watchSource\n        this.watchSource = null\n        if (watcher) await watcher.stop()\n    }\n}\n\n// -----------------------------------------------\n// Pure helpers\n// -----------------------------------------------\n\nfunction validateBound(\n    value: number | undefined,\n    bound: {\n        readonly default: number\n        readonly min: number\n        readonly max: number\n    },\n    name: string\n): number {\n    const resolved = value ?? bound.default\n\n    if (resolved < bound.min || resolved > bound.max) {\n        throw ConfigError(`${name} must be between ${bound.min} and ${bound.max}, got ${resolved}`)\n    }\n\n    return resolved\n}\n\nasync function safeRun(errors: ShutdownError[], component: string, fn: () => void | Promise<void>): Promise<void> {\n    try {\n        await fn()\n    } catch (error) {\n        errors.push({ component, error: toError(error) })\n    }\n}\n","/**\n * Read-only helpers for existing message attachments.\n *\n * Keeps only platform-relevant helpers: existence check with\n * null-safe localPath, extension normalization, and type classification.\n * Use node:fs directly for copy/read/stat — they are trivial wrappers.\n */\n\nimport { access } from 'node:fs/promises'\nimport { extname } from 'node:path'\nimport type { Attachment } from '../domain/attachment'\n\n// -----------------------------------------------\n// Extension Sets\n// -----------------------------------------------\n\nconst IMAGE_EXTENSIONS = new Set(['jpg', 'jpeg', 'png', 'gif', 'heic', 'heif', 'webp', 'bmp', 'tiff', 'svg'])\n\nconst VIDEO_EXTENSIONS = new Set(['mp4', 'mov', 'avi', 'mkv', 'm4v', 'wmv', 'flv', 'webm'])\n\nconst AUDIO_EXTENSIONS = new Set(['mp3', 'm4a', 'wav', 'aac', 'flac', 'ogg', 'wma'])\n\n// -----------------------------------------------\n// Existence\n// -----------------------------------------------\n\n/** Check whether the attachment file exists on disk. */\nexport async function attachmentExists(attachment: Attachment): Promise<boolean> {\n    if (!attachment.localPath) return false\n\n    try {\n        await access(attachment.localPath)\n        return true\n    } catch {\n        return false\n    }\n}\n\n// -----------------------------------------------\n// Type Detection\n// -----------------------------------------------\n\n/** Extract the lowercase file extension (without dot) from an attachment. */\nexport function getAttachmentExtension(attachment: Attachment): string {\n    const ext = extname(attachment.fileName ?? attachment.localPath ?? '')\n    return ext ? ext.slice(1).toLowerCase() : ''\n}\n\n/** Check whether the attachment is an image based on file extension. */\nexport function isImageAttachment(attachment: Attachment): boolean {\n    return IMAGE_EXTENSIONS.has(getAttachmentExtension(attachment))\n}\n\n/** Check whether the attachment is a video based on file extension. */\nexport function isVideoAttachment(attachment: Attachment): boolean {\n    return VIDEO_EXTENSIONS.has(getAttachmentExtension(attachment))\n}\n\n/** Check whether the attachment is audio based on file extension. */\nexport function isAudioAttachment(attachment: Attachment): boolean {\n    return AUDIO_EXTENSIONS.has(getAttachmentExtension(attachment))\n}\n"]}