/** * Shared helper for the host-side markdown formatter ↔ server-side * parser pair. Single source of truth so the host-side build (chat * bubble render) and the server-side strip (LLM input cleanup) can * never drift. * * Lib-side replacement for the hub's `lib/utils/chat-attachment-markdown.ts`. * The hub file pulled its constants from `lib/config/chat-attachment-config` * + its `ChatAttachment` type from `lib/types/chat-attachment`. Both are * inlined here as lib-local constants/types — they're stable wire-format * contracts (the hub's view-route owns the prefix + token-param name; any * change is a coordinated migration). * * URL flavors at a glance: * - HOST-SIDE (user-bubble render): uses the runtime's * `attachmentViewUrlPrefix` (hub default = `/api/storage/view/chat-attachments/`). * Embedded apps override per their reverse-proxy topology. * - SERVER-SIDE (strip regex): uses the constant * `CHAT_ATTACHMENT_VIEW_URL_PREFIX` directly. The chat ROUTE always * runs on the hub, so it always strips on the hub default. * - ANTHROPIC image-blocks: uses the RAW Supabase signed URL — NOT the * proxy URL — because Anthropic's image fetcher doesn't reliably * follow 302 redirects. * * Security gates inside the formatter: * - Filename markdown chars escaped via `escapeMarkdownInline` so a * name like `screenshot](https://evil.com).png` cannot terminate * the markdown image early and embed an attacker-controlled URL. * - `<` and `>` escaped too — prevents CommonMark autolink expansion * for filenames containing URL-shaped text. */ /** Hub-default prefix for the view-proxy URL. Embedders override via the * runtime. The server-side strip regex always uses THIS value (server * runs on the hub). */ export declare const CHAT_ATTACHMENT_VIEW_URL_PREFIX = "/api/storage/view/chat-attachments/"; /** Query parameter name for the HMAC view token. */ export declare const CHAT_ATTACHMENT_VIEW_TOKEN_QUERY_PARAM = "t"; /** Subset Anthropic's image content-block API supports. HEIC / video * attachments fall through to the text-marker form so the LLM still sees * a reference even when it can't visually parse the file. */ export declare const ANTHROPIC_SUPPORTED_IMAGE_MIME: readonly ["image/jpeg", "image/png", "image/webp", "image/gif"]; /** * Wire shape for a single chat attachment. * * `viewToken` is server-issued (HMAC-signed) and embedded in the markdown * URL's `?t=` query parameter. The client never generates it — the upload * route returns it alongside the storage path. */ export interface ChatAttachment { storagePath: string; viewToken: string; contentType: string; fileName: string; size: number; } /** * Build the markdown view-URL for a chat attachment. * * `viewUrlPrefix` is parameterized (NOT pulled from the constant) so * host-side callers can pass the runtime's prefix * (`ChatRuntime.endpoints.attachmentViewUrlPrefix`) — embedded apps * supply an absolute URL against the hub's origin so chat-history * markdown works cross-origin. * * Server-side callers (the strip regex source) should pass * `CHAT_ATTACHMENT_VIEW_URL_PREFIX` directly. */ export declare function buildChatAttachmentViewUrl(viewUrlPrefix: string, storagePath: string, viewToken: string): string; /** * Escape inline-markdown special characters from a filename before * interpolation. Closes the markdown-injection / phishing primitive: * a filename like `screenshot](https://evil.com).png` would otherwise * terminate `![filename](...)` early and emit an attacker-controlled * URL in the user's bubble. * * Escapes: `[`, `]`, `(`, `)`, `\`, `\n`, `\r`, `<`, `>`, `"`. */ export declare function escapeMarkdownInline(text: string): string; /** * Format a single chat-attachment as a markdown line to append to the * user's bubble text BEFORE sending. * * Images (MIME in `ANTHROPIC_SUPPORTED_IMAGE_MIME`) emit the `![]()` * image form so the browser renders the attachment inline. Everything * else (HEIC, video, audio) emits the `[Attached: ...]` link form so the * bubble shows a clickable file pill instead of a broken-image icon. */ export declare function formatChatAttachmentMarkdownForBubble(att: ChatAttachment, viewUrlPrefix: string): string; /** * Module-private: the `CHAT_ATTACHMENT_VIEW_URL_PREFIX` with regex * meta-characters escaped, so it can be safely interpolated into * regex sources. Computed ONCE at module load. Exported so other * regex-building call sites can share the same source of truth. */ export declare const CHAT_ATTACHMENT_VIEW_URL_PREFIX_REGEX_ESCAPED: string; /** * Single anchored regex matching both the image (`![]()`) and link * (`[Attached: ...]`) forms keyed on the server-side prefix. * * `gm` flags — multi-line anchored so the regex matches per-line. * Non-chat markdown links/images stay untouched because the regex * requires the literal `/api/storage/view/chat-attachments/` prefix. */ export declare const CHAT_ATTACHMENT_MARKDOWN_PATTERN: RegExp; /** * Strip pre-embedded chat-attachment markdown lines from `text`. * Returns the cleaned text + the storage paths extracted from the * matched URLs. */ export declare function stripChatAttachmentMarkdown(text: string): { stripped: string; storagePaths: string[]; }; //# sourceMappingURL=chat-attachment-markdown.d.ts.map