@ai-matrx/media 0.3.0 → 0.4.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +156 -0
- package/README.md +60 -3
- package/dist/next.cjs +92 -0
- package/dist/next.cjs.map +1 -0
- package/dist/next.d.cts +74 -0
- package/dist/next.d.ts +74 -0
- package/dist/next.js +60 -0
- package/dist/next.js.map +1 -0
- package/dist/react.cjs +1 -1
- package/dist/react.cjs.map +1 -1
- package/dist/react.d.cts +10 -1
- package/dist/react.d.ts +10 -1
- package/dist/react.js +1 -1
- package/dist/react.js.map +1 -1
- package/dist/viewers.cjs +1756 -0
- package/dist/viewers.cjs.map +1 -0
- package/dist/viewers.d.cts +289 -0
- package/dist/viewers.d.ts +289 -0
- package/dist/viewers.js +1738 -0
- package/dist/viewers.js.map +1 -0
- package/package.json +31 -4
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../src/viewers.ts","../src/viewers/media-file-viewer.tsx","../src/viewers/registry.ts","../src/viewers/code-viewer.tsx","../src/react/cn.ts","../src/viewers/chrome.tsx","../src/react/icons.tsx","../src/viewers/use-viewer-bytes.ts","../src/core/use-media-blob.ts","../src/core/context.ts","../src/core/diagnostics.ts","../src/core/ref-key.ts","../src/core/use-media-resolution.ts","../src/core/file-kind.ts","../src/react/file-icon.tsx","../src/react/upload-progress-list.tsx","../src/viewers/generic-viewer.tsx","../src/viewers/html-viewer.tsx","../src/viewers/markup-chrome.tsx","../src/core/use-media-load-recovery.ts","../src/types.ts","../src/viewers/transparency-grid.ts","../src/viewers/svg-viewer.tsx","../src/viewers/text-viewer.tsx","../src/viewers/unavailable-viewer.tsx","../src/viewers/preview-kind.ts"],"sourcesContent":["/**\n * `@ai-matrx/media/viewers` — full-pane FILE VIEWERS.\n *\n * The layer above `/react`'s inline media elements: what a preview pane, a\n * file tab, or a code editor's binary-file fallback renders for ONE file.\n * `MediaFileViewer` is the whole product — kind dispatch, working bodies for\n * text / code / SVG / HTML / unknown files, and an announcing default for\n * the kinds that need a heavy browser-only engine the host registers.\n *\n * Own subpath rather than part of `/react` (C8): a consumer that only renders\n * inline images has no business carrying a full viewer stack, and heavy\n * engines ride the registry seam rather than the package's dependency graph.\n */\n\nexport {\n MediaFileViewer,\n type MediaFileViewerProps,\n} from \"./viewers/media-file-viewer\";\n\nexport {\n registerMediaViewer,\n registerMediaCodeHighlighter,\n getMediaViewer,\n getMediaCodeHighlighter,\n registeredMediaViewerKinds,\n} from \"./viewers/registry\";\n\nexport { TextViewer } from \"./viewers/text-viewer\";\nexport { CodeViewer, detectCodeLanguage } from \"./viewers/code-viewer\";\nexport { SvgViewer } from \"./viewers/svg-viewer\";\nexport { HtmlViewer } from \"./viewers/html-viewer\";\nexport { GenericViewer } from \"./viewers/generic-viewer\";\nexport { MediaViewerUnavailable } from \"./viewers/unavailable-viewer\";\nexport { getPreviewKind } from \"./viewers/preview-kind\";\n\nexport {\n ViewerCopyButton,\n ViewerError,\n ViewerSkeleton,\n ViewerToolbar,\n} from \"./viewers/chrome\";\nexport { TRANSPARENCY_GRID_STYLE } from \"./viewers/transparency-grid\";\n\nexport {\n useViewerBytes,\n useViewerDisplayUrl,\n useViewerText,\n type ViewerBytesState,\n type ViewerDisplayUrlState,\n type ViewerTextState,\n} from \"./viewers/use-viewer-bytes\";\n\nexport type {\n MediaCodeHighlighter,\n MediaCodeHighlighterProps,\n MediaViewerComponent,\n MediaViewerGenericOptions,\n MediaViewerKind,\n MediaViewerMarkupControls,\n MediaViewerMarkupMode,\n MediaViewerProps,\n MediaViewerSource,\n MediaViewerViewport,\n} from \"./viewers/types\";\n","/**\n * src/viewers/media-file-viewer.tsx — THE dispatcher.\n *\n * Absorbed from matrx-frontend\n * `features/files/components/core/FilePreview/PreviewerSwitch.tsx`, which was\n * already the app's single kind→viewer switch across three surfaces (the\n * preview pane, the inline markdown file block, and the code editor's\n * binary-file fallback). The dispatch table, the kind vocabulary and the\n * degradation arms now belong to the package; the app keeps only the\n * registration of its own heavy engines.\n *\n * RESOLUTION ORDER (deliberate):\n * 1. a host registration for the kind — a real engine, or a feature's own\n * domain viewer overriding a built-in;\n * 2. the package's built-in body — text / code / svg / html / generic;\n * 3. the ANNOUNCING default — never a dead pane.\n *\n * FRAGMENTATION LAW: this module contains ZERO dynamic imports. Every body it\n * can render is statically part of the `./viewers` graph, which is already\n * behind whatever edge the consuming surface sits on. Heavy engines are lazy\n * on the HOST side of the registry seam — one boundary, at the edge, owned by\n * the app that knows its own chunking.\n */\n\n\"use client\";\n\nimport { createElement, type ComponentType } from \"react\";\nimport { getMediaViewer } from \"./registry\";\nimport { CodeViewer } from \"./code-viewer\";\nimport { GenericViewer } from \"./generic-viewer\";\nimport { HtmlViewer } from \"./html-viewer\";\nimport { SvgViewer } from \"./svg-viewer\";\nimport { TextViewer } from \"./text-viewer\";\nimport { MediaViewerUnavailable } from \"./unavailable-viewer\";\nimport { getPreviewKind } from \"./preview-kind\";\nimport type {\n MediaViewerComponent,\n MediaViewerKind,\n MediaViewerProps,\n} from \"./types\";\n\n/** The kinds the package renders itself, with no host registration. */\nconst BUILT_IN: Partial<Record<MediaViewerKind, MediaViewerComponent>> = {\n text: TextViewer as MediaViewerComponent,\n code: CodeViewer as MediaViewerComponent,\n svg: SvgViewer as MediaViewerComponent,\n html: HtmlViewer as MediaViewerComponent,\n generic: GenericViewer as MediaViewerComponent,\n};\n\nexport interface MediaFileViewerProps extends MediaViewerProps {\n /**\n * The kind to render. Omit to let the package derive it from the file name\n * and MIME type (`getPreviewKind`).\n */\n previewKind?: MediaViewerKind | undefined;\n}\n\nexport function MediaFileViewer({\n previewKind,\n ...props\n}: MediaFileViewerProps) {\n const kind =\n previewKind ?? getPreviewKind(props.fileName, props.mimeType ?? null);\n\n // MOUNTED AS AN ELEMENT, NEVER CALLED AS A FUNCTION. `viewer(props)` would\n // run the viewer's hooks inside THIS component's hook list, so a registered\n // viewer that uses hooks (every real engine adapter does — it resolves a\n // URL, reads a theme, joins a playback session) would blow up the moment\n // the kind changed between renders. `createElement` gives each body its own\n // component instance and its own hook list.\n const viewer = (getMediaViewer(kind) ?? BUILT_IN[kind]) as\n | ComponentType<MediaViewerProps>\n | undefined;\n if (viewer) return createElement(viewer, props);\n\n return <MediaViewerUnavailable {...props} kind={kind} />;\n}\n","/**\n * src/viewers/registry.ts — the heavy-engine seam.\n *\n * The package ships working bodies for every viewer kind it can render with\n * DOM primitives alone (text, code chrome, svg, html, generic). The kinds\n * whose rendering IS a multi-megabyte browser-only engine — PDF.js, a\n * Markdown/KaTeX stack, SheetJS, a server-side Office extractor — ride this\n * seam instead (C8 + the diff-package Monaco precedent): a host registers the\n * engine once, and until it does, the dispatcher renders an ANNOUNCING\n * default that names the missing engine and still offers download/open. A\n * dead pane is never an outcome.\n *\n * MODULE-LEVEL MUTABLE STATE IS BANNED (the dual ESM/CJS bundle rule): with\n * `splitting: false` and two formats, each loader graph instantiates its own\n * copy of this module, so a plain module-scope Map would silently split the\n * registry — a host registering through the CJS graph would be invisible to a\n * component rendered from the ESM graph. The maps therefore live on\n * `globalThis` under `Symbol.for` slots, and the tarball canary proves a\n * registration made in one graph is visible from the other.\n */\n\nimport type {\n MediaCodeHighlighter,\n MediaViewerComponent,\n MediaViewerKind,\n} from \"./types\";\n\nconst VIEWER_SLOT = Symbol.for(\"ai-matrx.media.viewer-registry\");\nconst HIGHLIGHTER_SLOT = Symbol.for(\"ai-matrx.media.code-highlighter\");\n\ninterface RegistrySlots {\n [VIEWER_SLOT]?: Map<MediaViewerKind, MediaViewerComponent>;\n [HIGHLIGHTER_SLOT]?: MediaCodeHighlighter | null;\n}\n\nfunction slots(): RegistrySlots {\n return globalThis as unknown as RegistrySlots;\n}\n\nfunction viewerMap(): Map<MediaViewerKind, MediaViewerComponent> {\n const host = slots();\n const existing = host[VIEWER_SLOT];\n if (existing) return existing;\n const created = new Map<MediaViewerKind, MediaViewerComponent>();\n host[VIEWER_SLOT] = created;\n return created;\n}\n\n/**\n * Register the viewer body for a kind. Registering a kind the package already\n * renders REPLACES the built-in — that is the sanctioned host override (a\n * feature-specific domain viewer implementing the same contract).\n *\n * Returns an unregister function so a test or a hot-reloading host can undo it.\n */\nexport function registerMediaViewer(\n kind: MediaViewerKind,\n viewer: MediaViewerComponent,\n): () => void {\n const map = viewerMap();\n const previous = map.get(kind);\n map.set(kind, viewer);\n return () => {\n if (previous) map.set(kind, previous);\n else map.delete(kind);\n };\n}\n\n/** The registered viewer for a kind, or `null` when nothing is registered. */\nexport function getMediaViewer(\n kind: MediaViewerKind,\n): MediaViewerComponent | null {\n return viewerMap().get(kind) ?? null;\n}\n\n/** Every kind a host has registered — for diagnostics and tests. */\nexport function registeredMediaViewerKinds(): MediaViewerKind[] {\n return [...viewerMap().keys()];\n}\n\n/**\n * Register the syntax-highlighting engine for the built-in code viewer.\n * Without one the code viewer still renders — monospace, line-numbered,\n * copyable, truncation-honest — it simply is not colored.\n */\nexport function registerMediaCodeHighlighter(\n highlighter: MediaCodeHighlighter,\n): () => void {\n const host = slots();\n const previous = host[HIGHLIGHTER_SLOT] ?? null;\n host[HIGHLIGHTER_SLOT] = highlighter;\n return () => {\n host[HIGHLIGHTER_SLOT] = previous;\n };\n}\n\nexport function getMediaCodeHighlighter(): MediaCodeHighlighter | null {\n return slots()[HIGHLIGHTER_SLOT] ?? null;\n}\n","/**\n * src/viewers/code-viewer.tsx — source-code viewer.\n *\n * Absorbed from matrx-frontend\n * `features/files/components/core/FilePreview/previewers/CodePreview.tsx`.\n *\n * THE ONE DELIBERATE DIVERGENCE (C8 + the diff-package Monaco precedent):\n * the original imported `react-syntax-highlighter` (Prism, ~150KB min) at the\n * top of the module. A syntax highlighter is a browser-only engine that a\n * headless consumer of this package must never be forced to carry, so the\n * ENGINE rides `registerMediaCodeHighlighter` and the package ships the\n * chrome plus a capable default: monospace, line-numbered, wrap-toggling,\n * copyable, truncation-honest — everything except color. The default is not\n * a stub and never announces a failure, because nothing failed; a host that\n * wants color registers an engine in one line.\n */\n\n\"use client\";\n\nimport { createElement, useMemo, useState, type ComponentType } from \"react\";\nimport { cn } from \"../react/cn\";\nimport { ViewerCopyButton, ViewerError, ViewerSkeleton, truncationNote } from \"./chrome\";\nimport { getMediaCodeHighlighter } from \"./registry\";\nimport type { MediaCodeHighlighterProps, MediaViewerProps } from \"./types\";\nimport { useViewerText } from \"./use-viewer-bytes\";\n\n/**\n * Extension → Prism-style language id. Ported verbatim from the original;\n * unknown ids are handed through unchanged (every engine we target degrades\n * to no-highlight rather than throwing).\n */\nconst EXT_TO_LANGUAGE: Record<string, string> = {\n js: \"javascript\",\n jsx: \"jsx\",\n mjs: \"javascript\",\n cjs: \"javascript\",\n ts: \"typescript\",\n tsx: \"tsx\",\n py: \"python\",\n rb: \"ruby\",\n go: \"go\",\n rs: \"rust\",\n java: \"java\",\n kt: \"kotlin\",\n swift: \"swift\",\n c: \"c\",\n h: \"c\",\n cpp: \"cpp\",\n cc: \"cpp\",\n cxx: \"cpp\",\n hpp: \"cpp\",\n cs: \"csharp\",\n php: \"php\",\n scala: \"scala\",\n html: \"markup\",\n htm: \"markup\",\n xml: \"markup\",\n svg: \"markup\",\n css: \"css\",\n scss: \"scss\",\n less: \"less\",\n json: \"json\",\n yaml: \"yaml\",\n yml: \"yaml\",\n toml: \"toml\",\n ini: \"ini\",\n sh: \"bash\",\n bash: \"bash\",\n zsh: \"bash\",\n fish: \"bash\",\n ps1: \"powershell\",\n sql: \"sql\",\n graphql: \"graphql\",\n gql: \"graphql\",\n proto: \"protobuf\",\n dockerfile: \"docker\",\n makefile: \"makefile\",\n lua: \"lua\",\n r: \"r\",\n};\n\nfunction extensionOf(fileName: string): string {\n const base = fileName.split(/[\\\\/]/).pop() ?? fileName;\n const dot = base.lastIndexOf(\".\");\n if (dot <= 0) return \"\";\n return base.slice(dot + 1).toLowerCase();\n}\n\n/** Filename → language id. Exported: hosts registering an engine reuse it. */\nexport function detectCodeLanguage(fileName: string): string {\n const ext = extensionOf(fileName);\n if (ext) return EXT_TO_LANGUAGE[ext] ?? \"text\";\n const lower = fileName.toLowerCase();\n if (lower === \"dockerfile\") return \"docker\";\n if (lower === \"makefile\") return \"makefile\";\n return \"text\";\n}\n\nexport function CodeViewer({\n source,\n fileName,\n className,\n maxBytes = 1024 * 1024,\n}: MediaViewerProps) {\n const { text, error, loading, truncated } = useViewerText(source, maxBytes);\n const [wrap, setWrap] = useState(false);\n const language = useMemo(() => detectCodeLanguage(fileName), [fileName]);\n const highlighter = getMediaCodeHighlighter();\n\n if (error) return <ViewerError message={error} className={className} />;\n if (loading || text === null) return <ViewerSkeleton className={className} />;\n\n const lines = text.split(\"\\n\");\n\n return (\n <div\n className={cn(\n \"flex h-full w-full flex-col overflow-hidden bg-card\",\n className,\n )}\n >\n <div className=\"flex shrink-0 items-center justify-between gap-2 border-b border-border bg-muted/30 px-3 py-1.5\">\n <div className=\"flex min-w-0 items-center gap-2 text-xs text-muted-foreground\">\n <span className=\"font-mono tracking-wide uppercase\">{language}</span>\n {truncated ? (\n <span className=\"text-warning\">· {truncationNote(maxBytes)}</span>\n ) : null}\n </div>\n <div className=\"flex items-center gap-1\">\n {highlighter ? null : (\n <button\n type=\"button\"\n onClick={() => setWrap((value) => !value)}\n aria-pressed={wrap}\n className={cn(\n \"rounded-md px-2 py-1 text-xs text-muted-foreground hover:bg-accent hover:text-foreground\",\n wrap && \"bg-accent text-accent-foreground\",\n )}\n >\n Wrap\n </button>\n )}\n <ViewerCopyButton text={text} />\n </div>\n </div>\n <div className=\"min-h-0 flex-1 overflow-auto\">\n {highlighter ? (\n // Mounted as an element, never called — a real highlighter reads the\n // host's theme with a hook, and calling it would put that hook in\n // THIS component's list (see the note in media-file-viewer.tsx).\n createElement(\n highlighter as ComponentType<MediaCodeHighlighterProps>,\n { code: text, language },\n )\n ) : (\n <pre className=\"m-0 flex p-3 font-mono text-xs leading-5\">\n <code\n aria-hidden\n className=\"mr-3 shrink-0 border-r border-border/60 pr-3 text-right text-muted-foreground/60 select-none\"\n >\n {lines.map((_, index) => `${index + 1}\\n`).join(\"\")}\n </code>\n <code\n className={cn(\n \"min-w-0 flex-1 text-foreground\",\n wrap ? \"break-words whitespace-pre-wrap\" : \"whitespace-pre\",\n )}\n >\n {text}\n </code>\n </pre>\n )}\n </div>\n </div>\n );\n}\n","/**\n * src/react/cn.ts — conditional class join with last-wins Tailwind conflict\n * merging. The originals used the app's `cn` (clsx + tailwind-merge); public\n * `className` overrides depend on last-wins class-conflict merging, so a\n * naive join would be a behavior divergence (the kit `./confirm` precedent —\n * this is why `tailwind-merge` is a sanctioned runtime dep of `/react`).\n */\n\nimport { twMerge } from \"tailwind-merge\";\n\nexport type ClassValue = string | false | null | undefined | 0;\n\nexport function cn(...inputs: ClassValue[]): string {\n return twMerge(inputs.filter(Boolean).join(\" \"));\n}\n","/**\n * src/viewers/chrome.tsx — the shared viewer chrome.\n *\n * The five absorbed matrx-frontend previewers each hand-rolled the same\n * error card, the same skeleton, and the same copy button. One copy here;\n * one place to make them good.\n */\n\n\"use client\";\n\nimport { useCallback, useState } from \"react\";\nimport { cn } from \"../react/cn\";\nimport { AlertCircleIcon, CheckIcon, CopyIcon } from \"../react/icons\";\n\n/** The uniform loading bar every viewer shows while bytes are in flight. */\nexport function ViewerSkeleton({\n className,\n tone = \"muted\",\n}: {\n className?: string | undefined;\n tone?: \"muted\" | \"plain\" | undefined;\n}) {\n return (\n <div\n className={cn(\n \"flex h-full w-full items-center justify-center\",\n tone === \"muted\" && \"bg-muted/20\",\n className,\n )}\n >\n <div className=\"h-6 w-40 animate-pulse rounded bg-muted\" />\n </div>\n );\n}\n\n/**\n * The honest failure card. It shows the REAL underlying message (HTTP\n * 401/403/404/network) rather than a generic \"Preview failed\" — the original\n * previewers' deliberate choice, kept: a user who can see the status can act\n * on it, and a support thread starts with a fact instead of a shrug.\n */\nexport function ViewerError({\n title = \"Couldn't load this file\",\n message,\n hint,\n className,\n}: {\n title?: string | undefined;\n message?: string | null | undefined;\n hint?: string | undefined;\n className?: string | undefined;\n}) {\n return (\n <div\n className={cn(\n \"flex h-full w-full flex-col items-center justify-center gap-3 p-6 text-center\",\n className,\n )}\n role=\"alert\"\n >\n <div className=\"flex h-12 w-12 items-center justify-center rounded-full bg-destructive/10\">\n <AlertCircleIcon className=\"h-6 w-6 text-destructive\" />\n </div>\n <div className=\"space-y-1\">\n <h3 className=\"text-sm font-semibold\">{title}</h3>\n {message ? (\n <p className=\"max-w-md text-xs break-words text-muted-foreground\">\n {message}\n </p>\n ) : null}\n {hint ? (\n <p className=\"max-w-md text-[11px] text-muted-foreground/80\">{hint}</p>\n ) : null}\n </div>\n </div>\n );\n}\n\n/**\n * Copy-to-clipboard button with the settled-state flip. Swallows the\n * clipboard rejection that non-secure contexts always throw — a failed copy\n * is not an error worth a card, and the un-flipped button IS the signal.\n */\nexport function ViewerCopyButton({\n text,\n className,\n}: {\n text: string | null;\n className?: string | undefined;\n}) {\n const [copied, setCopied] = useState(false);\n const onCopy = useCallback(() => {\n if (text == null) return;\n void navigator.clipboard\n .writeText(text)\n .then(() => {\n setCopied(true);\n setTimeout(() => setCopied(false), 1600);\n })\n .catch(() => {\n /* non-secure context — the un-flipped button is the honest signal */\n });\n }, [text]);\n\n return (\n <button\n type=\"button\"\n onClick={onCopy}\n aria-label=\"Copy text to clipboard\"\n title=\"Copy text to clipboard\"\n className={cn(\n \"inline-flex items-center gap-1.5 rounded-md px-2 py-1 text-xs text-muted-foreground hover:bg-accent hover:text-foreground\",\n copied && \"text-emerald-600 dark:text-emerald-400\",\n className,\n )}\n >\n {copied ? (\n <CheckIcon className=\"h-3.5 w-3.5\" />\n ) : (\n <CopyIcon className=\"h-3.5 w-3.5\" />\n )}\n {copied ? \"Copied\" : \"Copy\"}\n </button>\n );\n}\n\n/** The strip above a text-shaped viewer: status on the left, copy on the right. */\nexport function ViewerToolbar({\n children,\n className,\n}: {\n children?: React.ReactNode;\n className?: string | undefined;\n}) {\n return (\n <div\n className={cn(\n \"flex shrink-0 items-center justify-between gap-2 border-b border-border/60 bg-muted/20 px-3 py-1 text-xs\",\n className,\n )}\n >\n {children}\n </div>\n );\n}\n\n/** \"truncated to first NMB\" — one phrasing across every text-shaped viewer. */\nexport function truncationNote(maxBytes: number): string {\n const mb = maxBytes / 1024 / 1024;\n return `truncated to the first ${mb >= 1 ? `${mb.toFixed(0)}MB` : `${(maxBytes / 1024).toFixed(0)}KB`}`;\n}\n","/**\n * src/react/icons.tsx — the package's OWN inlined SVG icons.\n *\n * Per campaign ruling C19 (2026-08-29): no icon-library dependency, ever.\n * Every glyph below is copied from lucide-react v1.22.0 (ISC license) exactly,\n * following the @ai-matrx/tap-target precedent. Add a new icon by copying the\n * lucide __iconNode data — never by adding a lucide peer.\n *\n * Internal module: icons are exported for the package's own components and for\n * hosts that want visual parity in slots, but they are not the product.\n */\n\nimport type { SVGProps } from \"react\";\n\nexport type MediaIconProps = SVGProps<SVGSVGElement>;\n\nfunction svgProps(props: MediaIconProps): MediaIconProps {\n return {\n xmlns: \"http://www.w3.org/2000/svg\",\n viewBox: \"0 0 24 24\",\n width: 24,\n height: 24,\n fill: \"none\",\n stroke: \"currentColor\",\n strokeWidth: 2,\n strokeLinecap: \"round\",\n strokeLinejoin: \"round\",\n \"aria-hidden\": true,\n ...props,\n };\n}\n\n// lucide: archive\nexport function ArchiveIcon(props: MediaIconProps) {\n return (\n <svg {...svgProps(props)}>\n <rect width=\"20\" height=\"5\" x=\"2\" y=\"3\" rx=\"1\" />\n <path d=\"M4 8v11a2 2 0 0 0 2 2h12a2 2 0 0 0 2-2V8\" />\n <path d=\"M10 12h4\" />\n </svg>\n );\n}\n\n// lucide: braces\nexport function BracesIcon(props: MediaIconProps) {\n return (\n <svg {...svgProps(props)}>\n <path d=\"M8 3H7a2 2 0 0 0-2 2v5a2 2 0 0 1-2 2 2 2 0 0 1 2 2v5c0 1.1.9 2 2 2h1\" />\n <path d=\"M16 21h1a2 2 0 0 0 2-2v-5c0-1.1.9-2 2-2a2 2 0 0 1-2-2V5a2 2 0 0 0-2-2h-1\" />\n </svg>\n );\n}\n\n// lucide: check\nexport function CheckIcon(props: MediaIconProps) {\n return (\n <svg {...svgProps(props)}>\n <path d=\"M20 6 9 17l-5-5\" />\n </svg>\n );\n}\n\n// lucide: code\nexport function CodeIcon(props: MediaIconProps) {\n return (\n <svg {...svgProps(props)}>\n <path d=\"m16 18 6-6-6-6\" />\n <path d=\"m8 6-6 6 6 6\" />\n </svg>\n );\n}\n\n// lucide: copy\nexport function CopyIcon(props: MediaIconProps) {\n return (\n <svg {...svgProps(props)}>\n <rect width=\"14\" height=\"14\" x=\"8\" y=\"8\" rx=\"2\" ry=\"2\" />\n <path d=\"M4 16c-1.1 0-2-.9-2-2V4c0-1.1.9-2 2-2h10c1.1 0 2 .9 2 2\" />\n </svg>\n );\n}\n\n// lucide: database\nexport function DatabaseIcon(props: MediaIconProps) {\n return (\n <svg {...svgProps(props)}>\n <ellipse cx=\"12\" cy=\"5\" rx=\"9\" ry=\"3\" />\n <path d=\"M3 5V19A9 3 0 0 0 21 19V5\" />\n <path d=\"M3 12A9 3 0 0 0 21 12\" />\n </svg>\n );\n}\n\n// lucide: download\nexport function DownloadIcon(props: MediaIconProps) {\n return (\n <svg {...svgProps(props)}>\n <path d=\"M12 15V3\" />\n <path d=\"M21 15v4a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2v-4\" />\n <path d=\"m7 10 5 5 5-5\" />\n </svg>\n );\n}\n\n// lucide: externalLink\nexport function ExternalLinkIcon(props: MediaIconProps) {\n return (\n <svg {...svgProps(props)}>\n <path d=\"M15 3h6v6\" />\n <path d=\"M10 14 21 3\" />\n <path d=\"M18 13v6a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2V8a2 2 0 0 1 2-2h6\" />\n </svg>\n );\n}\n\n// lucide: file\nexport function FileIcon(props: MediaIconProps) {\n return (\n <svg {...svgProps(props)}>\n <path d=\"M6 22a2 2 0 0 1-2-2V4a2 2 0 0 1 2-2h8a2.4 2.4 0 0 1 1.704.706l3.588 3.588A2.4 2.4 0 0 1 20 8v12a2 2 0 0 1-2 2z\" />\n <path d=\"M14 2v5a1 1 0 0 0 1 1h5\" />\n </svg>\n );\n}\n\n// lucide: fileAudio\nexport function FileAudioIcon(props: MediaIconProps) {\n return (\n <svg {...svgProps(props)}>\n <path d=\"M4 6.835V4a2 2 0 0 1 2-2h8a2.4 2.4 0 0 1 1.706.706l3.588 3.588A2.4 2.4 0 0 1 20 8v12a2 2 0 0 1-2 2h-.343\" />\n <path d=\"M14 2v5a1 1 0 0 0 1 1h5\" />\n <path d=\"M2 19a2 2 0 0 1 4 0v1a2 2 0 0 1-4 0v-4a6 6 0 0 1 12 0v4a2 2 0 0 1-4 0v-1a2 2 0 0 1 4 0\" />\n </svg>\n );\n}\n\n// lucide: fileCode\nexport function FileCodeIcon(props: MediaIconProps) {\n return (\n <svg {...svgProps(props)}>\n <path d=\"M6 22a2 2 0 0 1-2-2V4a2 2 0 0 1 2-2h8a2.4 2.4 0 0 1 1.704.706l3.588 3.588A2.4 2.4 0 0 1 20 8v12a2 2 0 0 1-2 2z\" />\n <path d=\"M14 2v5a1 1 0 0 0 1 1h5\" />\n <path d=\"M10 12.5 8 15l2 2.5\" />\n <path d=\"m14 12.5 2 2.5-2 2.5\" />\n </svg>\n );\n}\n\n// lucide: fileJson\nexport function FileJsonIcon(props: MediaIconProps) {\n return (\n <svg {...svgProps(props)}>\n <path d=\"M6 22a2 2 0 0 1-2-2V4a2 2 0 0 1 2-2h8a2.4 2.4 0 0 1 1.704.706l3.588 3.588A2.4 2.4 0 0 1 20 8v12a2 2 0 0 1-2 2z\" />\n <path d=\"M14 2v5a1 1 0 0 0 1 1h5\" />\n <path d=\"M10 12a1 1 0 0 0-1 1v1a1 1 0 0 1-1 1 1 1 0 0 1 1 1v1a1 1 0 0 0 1 1\" />\n <path d=\"M14 18a1 1 0 0 0 1-1v-1a1 1 0 0 1 1-1 1 1 0 0 1-1-1v-1a1 1 0 0 0-1-1\" />\n </svg>\n );\n}\n\n// lucide: fileSpreadsheet\nexport function FileSpreadsheetIcon(props: MediaIconProps) {\n return (\n <svg {...svgProps(props)}>\n <path d=\"M6 22a2 2 0 0 1-2-2V4a2 2 0 0 1 2-2h8a2.4 2.4 0 0 1 1.704.706l3.588 3.588A2.4 2.4 0 0 1 20 8v12a2 2 0 0 1-2 2z\" />\n <path d=\"M14 2v5a1 1 0 0 0 1 1h5\" />\n <path d=\"M8 13h2\" />\n <path d=\"M14 13h2\" />\n <path d=\"M8 17h2\" />\n <path d=\"M14 17h2\" />\n </svg>\n );\n}\n\n// lucide: fileText\nexport function FileTextIcon(props: MediaIconProps) {\n return (\n <svg {...svgProps(props)}>\n <path d=\"M6 22a2 2 0 0 1-2-2V4a2 2 0 0 1 2-2h8a2.4 2.4 0 0 1 1.704.706l3.588 3.588A2.4 2.4 0 0 1 20 8v12a2 2 0 0 1-2 2z\" />\n <path d=\"M14 2v5a1 1 0 0 0 1 1h5\" />\n <path d=\"M10 9H8\" />\n <path d=\"M16 13H8\" />\n <path d=\"M16 17H8\" />\n </svg>\n );\n}\n\n// lucide: fileType\nexport function FileTypeIcon(props: MediaIconProps) {\n return (\n <svg {...svgProps(props)}>\n <path d=\"M6 22a2 2 0 0 1-2-2V4a2 2 0 0 1 2-2h8a2.4 2.4 0 0 1 1.704.706l3.588 3.588A2.4 2.4 0 0 1 20 8v12a2 2 0 0 1-2 2z\" />\n <path d=\"M14 2v5a1 1 0 0 0 1 1h5\" />\n <path d=\"M11 18h2\" />\n <path d=\"M12 12v6\" />\n <path d=\"M9 13v-.5a.5.5 0 0 1 .5-.5h5a.5.5 0 0 1 .5.5v.5\" />\n </svg>\n );\n}\n\n// lucide: fileVideo\nexport function FileVideoIcon(props: MediaIconProps) {\n return (\n <svg {...svgProps(props)}>\n <path d=\"M6 22a2 2 0 0 1-2-2V4a2 2 0 0 1 2-2h8a2.4 2.4 0 0 1 1.704.706l3.588 3.588A2.4 2.4 0 0 1 20 8v12a2 2 0 0 1-2 2z\" />\n <path d=\"M14 2v5a1 1 0 0 0 1 1h5\" />\n <path d=\"M15.033 13.44a.647.647 0 0 1 0 1.12l-4.065 2.352a.645.645 0 0 1-.968-.56v-4.704a.645.645 0 0 1 .967-.56z\" />\n </svg>\n );\n}\n\n// lucide: folder\nexport function FolderIcon(props: MediaIconProps) {\n return (\n <svg {...svgProps(props)}>\n <path d=\"M20 20a2 2 0 0 0 2-2V8a2 2 0 0 0-2-2h-7.9a2 2 0 0 1-1.69-.9L9.6 3.9A2 2 0 0 0 7.93 3H4a2 2 0 0 0-2 2v13a2 2 0 0 0 2 2Z\" />\n </svg>\n );\n}\n\n// lucide: folderOpen\nexport function FolderOpenIcon(props: MediaIconProps) {\n return (\n <svg {...svgProps(props)}>\n <path d=\"m6 14 1.5-2.9A2 2 0 0 1 9.24 10H20a2 2 0 0 1 1.94 2.5l-1.54 6a2 2 0 0 1-1.95 1.5H4a2 2 0 0 1-2-2V5a2 2 0 0 1 2-2h3.9a2 2 0 0 1 1.69.9l.81 1.2a2 2 0 0 0 1.67.9H18a2 2 0 0 1 2 2v2\" />\n </svg>\n );\n}\n\n// lucide: image\nexport function ImageIcon(props: MediaIconProps) {\n return (\n <svg {...svgProps(props)}>\n <rect width=\"18\" height=\"18\" x=\"3\" y=\"3\" rx=\"2\" ry=\"2\" />\n <circle cx=\"9\" cy=\"9\" r=\"2\" />\n <path d=\"m21 15-3.086-3.086a2 2 0 0 0-2.828 0L6 21\" />\n </svg>\n );\n}\n\n// lucide: imageOff\nexport function ImageOffIcon(props: MediaIconProps) {\n return (\n <svg {...svgProps(props)}>\n <line x1=\"2\" x2=\"22\" y1=\"2\" y2=\"22\" />\n <path d=\"M10.41 10.41a2 2 0 1 1-2.83-2.83\" />\n <line x1=\"13.5\" x2=\"6\" y1=\"13.5\" y2=\"21\" />\n <line x1=\"18\" x2=\"21\" y1=\"12\" y2=\"15\" />\n <path d=\"M3.59 3.59A1.99 1.99 0 0 0 3 5v14a2 2 0 0 0 2 2h14c.55 0 1.052-.22 1.41-.59\" />\n <path d=\"M21 15V5a2 2 0 0 0-2-2H9\" />\n </svg>\n );\n}\n\n// lucide: music\nexport function MusicIcon(props: MediaIconProps) {\n return (\n <svg {...svgProps(props)}>\n <path d=\"M9 18V5l12-2v13\" />\n <circle cx=\"6\" cy=\"18\" r=\"3\" />\n <circle cx=\"18\" cy=\"16\" r=\"3\" />\n </svg>\n );\n}\n\n// lucide: packageBox\nexport function PackageBoxIcon(props: MediaIconProps) {\n return (\n <svg {...svgProps(props)}>\n <path d=\"M11 21.73a2 2 0 0 0 2 0l7-4A2 2 0 0 0 21 16V8a2 2 0 0 0-1-1.73l-7-4a2 2 0 0 0-2 0l-7 4A2 2 0 0 0 3 8v8a2 2 0 0 0 1 1.73z\" />\n <path d=\"M12 22V12\" />\n <polyline points=\"3.29 7 12 12 20.71 7\" />\n <path d=\"m7.5 4.27 9 5.15\" />\n </svg>\n );\n}\n\n// lucide: penTool\nexport function PenToolIcon(props: MediaIconProps) {\n return (\n <svg {...svgProps(props)}>\n <path d=\"M15.707 21.293a1 1 0 0 1-1.414 0l-1.586-1.586a1 1 0 0 1 0-1.414l5.586-5.586a1 1 0 0 1 1.414 0l1.586 1.586a1 1 0 0 1 0 1.414z\" />\n <path d=\"m18 13-1.375-6.874a1 1 0 0 0-.746-.776L3.235 2.028a1 1 0 0 0-1.207 1.207L5.35 15.879a1 1 0 0 0 .776.746L13 18\" />\n <path d=\"m2.3 2.3 7.286 7.286\" />\n <circle cx=\"11\" cy=\"11\" r=\"2\" />\n </svg>\n );\n}\n\n// lucide: share2\nexport function Share2Icon(props: MediaIconProps) {\n return (\n <svg {...svgProps(props)}>\n <circle cx=\"18\" cy=\"5\" r=\"3\" />\n <circle cx=\"6\" cy=\"12\" r=\"3\" />\n <circle cx=\"18\" cy=\"19\" r=\"3\" />\n <line x1=\"8.59\" x2=\"15.42\" y1=\"13.51\" y2=\"17.49\" />\n <line x1=\"15.41\" x2=\"8.59\" y1=\"6.51\" y2=\"10.49\" />\n </svg>\n );\n}\n\n// lucide: subtitles\nexport function SubtitlesIcon(props: MediaIconProps) {\n return (\n <svg {...svgProps(props)}>\n <rect width=\"18\" height=\"14\" x=\"3\" y=\"5\" rx=\"2\" ry=\"2\" />\n <path d=\"M7 15h4M15 15h2M7 11h2M13 11h4\" />\n </svg>\n );\n}\n\n// lucide: upload\nexport function UploadIcon(props: MediaIconProps) {\n return (\n <svg {...svgProps(props)}>\n <path d=\"M12 3v12\" />\n <path d=\"m17 8-5-5-5 5\" />\n <path d=\"M21 15v4a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2v-4\" />\n </svg>\n );\n}\n\n// lucide: video\nexport function VideoIcon(props: MediaIconProps) {\n return (\n <svg {...svgProps(props)}>\n <path d=\"m16 13 5.223 3.482a.5.5 0 0 0 .777-.416V7.87a.5.5 0 0 0-.752-.432L16 10.5\" />\n <rect x=\"2\" y=\"6\" width=\"14\" height=\"12\" rx=\"2\" />\n </svg>\n );\n}\n\n// lucide: videoOff\nexport function VideoOffIcon(props: MediaIconProps) {\n return (\n <svg {...svgProps(props)}>\n <path d=\"M10.66 6H14a2 2 0 0 1 2 2v2.5l5.248-3.062A.5.5 0 0 1 22 7.87v8.196\" />\n <path d=\"M16 16a2 2 0 0 1-2 2H4a2 2 0 0 1-2-2V8a2 2 0 0 1 2-2h2\" />\n <path d=\"m2 2 20 20\" />\n </svg>\n );\n}\n\n// lucide: volumeX\nexport function VolumeXIcon(props: MediaIconProps) {\n return (\n <svg {...svgProps(props)}>\n <path d=\"M11 4.702a.705.705 0 0 0-1.203-.498L6.413 7.587A1.4 1.4 0 0 1 5.416 8H3a1 1 0 0 0-1 1v6a1 1 0 0 0 1 1h2.416a1.4 1.4 0 0 1 .997.413l3.383 3.384A.705.705 0 0 0 11 19.298z\" />\n <line x1=\"22\" x2=\"16\" y1=\"9\" y2=\"15\" />\n <line x1=\"16\" x2=\"22\" y1=\"9\" y2=\"15\" />\n </svg>\n );\n}\n\n// lucide: x\nexport function XIcon(props: MediaIconProps) {\n return (\n <svg {...svgProps(props)}>\n <path d=\"M18 6 6 18\" />\n <path d=\"m6 6 12 12\" />\n </svg>\n );\n}\n\n// lucide: alertCircle\nexport function AlertCircleIcon(props: MediaIconProps) {\n return (\n <svg {...svgProps(props)}>\n <circle cx=\"12\" cy=\"12\" r=\"10\" />\n <line x1=\"12\" x2=\"12\" y1=\"8\" y2=\"12\" />\n <line x1=\"12\" x2=\"12.01\" y1=\"16\" y2=\"16\" />\n </svg>\n );\n}\n\n// lucide: checkCircle2\nexport function CheckCircle2Icon(props: MediaIconProps) {\n return (\n <svg {...svgProps(props)}>\n <path d=\"M21.801 10A10 10 0 1 1 17 3.335\" />\n <path d=\"m9 11 3 3L22 4\" />\n </svg>\n );\n}\n\n// lucide: globe\nexport function GlobeIcon(props: MediaIconProps) {\n return (\n <svg {...svgProps(props)}>\n <circle cx=\"12\" cy=\"12\" r=\"10\" />\n <path d=\"M12 2a14.5 14.5 0 0 0 0 20 14.5 14.5 0 0 0 0-20\" />\n <path d=\"M2 12h20\" />\n </svg>\n );\n}\n\n// lucide: link-2\nexport function Link2Icon(props: MediaIconProps) {\n return (\n <svg {...svgProps(props)}>\n <path d=\"M9 17H7A5 5 0 0 1 7 7h2\" />\n <path d=\"M15 7h2a5 5 0 1 1 0 10h-2\" />\n <line x1=\"8\" x2=\"16\" y1=\"12\" y2=\"12\" />\n </svg>\n );\n}\n\n// lucide: settings-2\nexport function Settings2Icon(props: MediaIconProps) {\n return (\n <svg {...svgProps(props)}>\n <path d=\"M20 7h-9\" />\n <path d=\"M14 17H5\" />\n <circle cx=\"17\" cy=\"17\" r=\"3\" />\n <circle cx=\"7\" cy=\"7\" r=\"3\" />\n </svg>\n );\n}\n\n// lucide: loader-circle (a.k.a. Loader2)\nexport function SpinnerIcon(props: MediaIconProps) {\n return (\n <svg {...svgProps(props)}>\n <path d=\"M21 12a9 9 0 1 1-6.219-8.56\" />\n </svg>\n );\n}\n\n// lucide: plus\nexport function PlusIcon(props: MediaIconProps) {\n return (\n <svg {...svgProps(props)}>\n <path d=\"M5 12h14\" />\n <path d=\"M12 5v14\" />\n </svg>\n );\n}\n\n// lucide: search\nexport function SearchIcon(props: MediaIconProps) {\n return (\n <svg {...svgProps(props)}>\n <circle cx=\"11\" cy=\"11\" r=\"8\" />\n <path d=\"m21 21-4.3-4.3\" />\n </svg>\n );\n}\n","/**\n * src/viewers/use-viewer-bytes.ts — the ONE byte/text/URL machinery every\n * viewer body shares.\n *\n * Four separate matrx-frontend previewers (Text, Code, the SVG source view,\n * the HTML source view) each carried their own copy of \"read the blob, cap it\n * at N bytes, mark it truncated, surface the REAL backend error verbatim,\n * cancel on unmount\". Four copies is four places to drift; C22 says that\n * machinery lives in the package exactly once.\n */\n\nimport { useEffect, useState } from \"react\";\nimport { useMediaBlob } from \"../core/use-media-blob\";\nimport { useMediaResolution } from \"../core/use-media-resolution\";\nimport type { MediaViewerSource } from \"./types\";\n\nexport interface ViewerBytesState {\n blob: Blob | null;\n loading: boolean;\n /** The real underlying message (HTTP 401/403/404/network) — never generic. */\n error: string | null;\n}\n\n/**\n * Bytes for a viewer source. A `blob` source is already resolved; a `ref`\n * source goes through `MediaClient.getBlob` (which is also what emits the\n * terminal-failure diagnostics — see `useMediaBlob`).\n *\n * `useMediaBlob` is called UNCONDITIONALLY (with `null` for blob sources) so\n * the hook order never changes with the source shape.\n */\nexport function useViewerBytes(source: MediaViewerSource): ViewerBytesState {\n const fromClient = useMediaBlob(source.kind === \"ref\" ? source.ref : null);\n if (source.kind === \"blob\") {\n return { blob: source.blob, loading: false, error: null };\n }\n return {\n blob: fromClient.blob,\n loading: fromClient.loading,\n error: fromClient.error,\n };\n}\n\n/**\n * Blob → string, across every runtime we ship into.\n *\n * `Blob.prototype.text()` is the modern one-liner and is what the\n * matrx-frontend originals used — but it does not exist in Safari < 14, in\n * older WebViews (the Tauri shell's floor), or in jsdom, and the failure mode\n * is a raw \"blob.text is not a function\" TypeError rendered to the user as if\n * the FILE were broken. Per C22 this quirk branch belongs in the package, once.\n */\nasync function readBlobText(blob: Blob): Promise<string> {\n const maybeText = (blob as { text?: () => Promise<string> }).text;\n if (typeof maybeText === \"function\") return await maybeText.call(blob);\n\n const maybeArrayBuffer = (blob as { arrayBuffer?: () => Promise<ArrayBuffer> })\n .arrayBuffer;\n if (typeof maybeArrayBuffer === \"function\") {\n return new TextDecoder().decode(await maybeArrayBuffer.call(blob));\n }\n\n return await new Promise<string>((resolve, reject) => {\n const reader = new FileReader();\n reader.onload = () => resolve(String(reader.result ?? \"\"));\n reader.onerror = () =>\n reject(reader.error ?? new Error(\"could not read the file's bytes\"));\n reader.readAsText(blob);\n });\n}\n\nexport interface ViewerTextState {\n text: string | null;\n loading: boolean;\n error: string | null;\n /** True when the file exceeded `maxBytes` and only the head was read. */\n truncated: boolean;\n}\n\n/**\n * Bytes → text, capped. The cap is not a nicety: a 500MB log file decoded in\n * full takes the tab down, which is how the original previewers were written\n * and why the cap must travel with the package rather than be re-derived.\n */\nexport function useViewerText(\n source: MediaViewerSource,\n maxBytes = 1024 * 1024,\n): ViewerTextState {\n const { blob, loading, error: bytesError } = useViewerBytes(source);\n const [text, setText] = useState<string | null>(null);\n const [readError, setReadError] = useState<string | null>(null);\n const [truncated, setTruncated] = useState(false);\n\n useEffect(() => {\n if (!blob) {\n setText(null);\n return undefined;\n }\n let cancelled = false;\n setReadError(null);\n setText(null);\n setTruncated(false);\n void (async () => {\n try {\n const oversized = blob.size > maxBytes;\n const value = await readBlobText(\n oversized ? blob.slice(0, maxBytes) : blob,\n );\n if (cancelled) return;\n setTruncated(oversized);\n setText(value);\n } catch (err) {\n if (cancelled) return;\n setReadError(err instanceof Error ? err.message : String(err));\n }\n })();\n return () => {\n cancelled = true;\n };\n }, [blob, maxBytes]);\n\n const error = readError ?? bytesError;\n return {\n text,\n error,\n truncated,\n loading: (loading || text === null) && error === null,\n };\n}\n\nexport interface ViewerDisplayUrlState {\n /**\n * The URL a media element may bind. Durable by construction: it is either\n * a `MediaClient.resolve()` result or the host's own object URL.\n */\n url: string | null;\n /**\n * Whether the client's ONE retry policy can rescue a load failure. False\n * for object URLs and for resolutions the client marked unrecoverable\n * (foreign links) — a session refresh cannot resurrect someone else's URL.\n */\n recoverable: boolean;\n /** `resolve()` refused the ref — render the honest unavailable state. */\n unavailable: boolean;\n loading: boolean;\n}\n\n/**\n * The display URL for a viewer source. Law 2: even for a `ref` carrying a\n * caller-supplied URL, resolution goes through the client — the package never\n * trusts a string it was handed.\n */\nexport function useViewerDisplayUrl(\n source: MediaViewerSource,\n): ViewerDisplayUrlState {\n const resolved = useMediaResolution(\n source.kind === \"ref\" ? source.ref : null,\n );\n if (source.kind === \"blob\") {\n return {\n url: source.url,\n recoverable: false,\n unavailable: false,\n loading: false,\n };\n }\n return {\n url: resolved.resolution?.src ?? null,\n recoverable: resolved.resolution?.recoverable !== false,\n unavailable: resolved.status === \"unavailable\",\n loading: resolved.status === \"empty\",\n };\n}\n","/**\n * src/core/use-media-blob.ts — bytes for canvas/crossOrigin/private-pixel\n * consumers, as state.\n *\n * The behavior contract is ported from matrx-frontend `hooks/useFileBlob.ts`;\n * the byte machinery (auth, caching, in-flight dedup, IDB tiers, progress) is\n * the CLIENT's (C10 persistence-injected — the package owns no cache). The\n * hook owns only the React lifecycle: load on mount/ref change, release the\n * handle on unmount, expose a retry.\n */\n\nimport { useEffect, useState } from \"react\";\nimport type { MediaRefLike } from \"../types\";\nimport { useMediaClient } from \"./context\";\nimport { failureMediaIdentity, useMediaFailureCapture } from \"./diagnostics\";\nimport { stableRefKey } from \"./ref-key\";\n\n/** Structural HTTP status probe for client errors (never a validation). */\nfunction statusOf(err: unknown): number | undefined {\n if (err && typeof err === \"object\") {\n const candidate =\n (err as { status?: unknown }).status ??\n (err as { statusCode?: unknown }).statusCode;\n if (typeof candidate === \"number\") return candidate;\n }\n return undefined;\n}\n\nexport interface MediaBlobState {\n /** `blob:` object URL safe to feed into any browser API. `null` until ready. */\n url: string | null;\n blob: Blob | null;\n loading: boolean;\n error: string | null;\n /** Force a fresh byte read (the client decides whether to drop its cache). */\n retry: () => void;\n}\n\nexport function useMediaBlob(\n ref: MediaRefLike | null | undefined,\n): MediaBlobState {\n const client = useMediaClient();\n const capture = useMediaFailureCapture();\n const refKey = stableRefKey(ref);\n const [state, setState] = useState<{\n url: string | null;\n blob: Blob | null;\n loading: boolean;\n error: string | null;\n }>({ url: null, blob: null, loading: !!ref, error: null });\n const [retryToken, setRetryToken] = useState(0);\n\n useEffect(() => {\n if (!ref) {\n setState({ url: null, blob: null, loading: false, error: null });\n return undefined;\n }\n let cancelled = false;\n let release: (() => void) | null = null;\n setState({ url: null, blob: null, loading: true, error: null });\n client.getBlob(ref).then(\n (handle) => {\n if (cancelled) {\n handle.release();\n return;\n }\n release = handle.release;\n setState({ url: handle.url, blob: handle.blob, loading: false, error: null });\n },\n (err: unknown) => {\n if (cancelled) return;\n const message =\n err instanceof Error ? err.message : String(err ?? \"Failed to load file\");\n setState({ url: null, blob: null, loading: false, error: message });\n // Terminal-failure capture (phase \"blob\"): the private-pixels bytes\n // never arrived. Latched per media identity by the machinery.\n const status = statusOf(err);\n capture({\n phase: \"blob\",\n mediaRef: failureMediaIdentity(ref),\n terminal: true,\n message: `getBlob() failed: ${message}`,\n ...(status !== undefined ? { status } : {}),\n });\n },\n );\n return () => {\n cancelled = true;\n release?.();\n };\n // eslint-disable-next-line react-hooks/exhaustive-deps\n }, [client, refKey, retryToken]);\n\n return {\n ...state,\n retry: () => setRetryToken((t) => t + 1),\n };\n}\n","/**\n * src/core/context.ts — the MediaClient / host-ports React contexts.\n *\n * The context OBJECTS live on `globalThis` under `Symbol.for` slots — NOT at\n * module level. With `splitting: false` this module is duplicated into the\n * `/core` and `/react` bundles, and CJS/ESM each instantiate their own module\n * graph; a module-level `createContext` would silently produce two different\n * contexts (a Provider from one graph invisible to a consumer from the\n * other) — the kit tap-target/link-registry lesson. Never \"clean this up\".\n */\n\nimport {\n createContext,\n createElement,\n useContext,\n type Context,\n type ReactNode,\n} from \"react\";\nimport type { MediaClient, MediaHostPorts } from \"../types\";\n\nconst CLIENT_SLOT = Symbol.for(\"ai-matrx.media.client-context\");\nconst PORTS_SLOT = Symbol.for(\"ai-matrx.media.host-ports-context\");\n\ntype SlotHost = typeof globalThis & {\n [CLIENT_SLOT]?: Context<MediaClient | null>;\n [PORTS_SLOT]?: Context<MediaHostPorts>;\n};\n\nfunction clientContext(): Context<MediaClient | null> {\n const host = globalThis as SlotHost;\n host[CLIENT_SLOT] ??= createContext<MediaClient | null>(null);\n return host[CLIENT_SLOT];\n}\n\nconst INERT_PORTS: MediaHostPorts = {};\n\nfunction portsContext(): Context<MediaHostPorts> {\n const host = globalThis as SlotHost;\n host[PORTS_SLOT] ??= createContext<MediaHostPorts>(INERT_PORTS);\n return host[PORTS_SLOT];\n}\n\nexport interface MediaProviderProps {\n client: MediaClient;\n /**\n * Optional host ports (playback session, actions, ImageComponent). Must be\n * referentially stable — the playback port members are hooks.\n */\n ports?: MediaHostPorts | undefined;\n children?: ReactNode;\n}\n\n/** Wire the injected MediaClient (and optional host ports) into the tree. */\nexport function MediaProvider({ client, ports, children }: MediaProviderProps) {\n const ClientCtx = clientContext();\n const PortsCtx = portsContext();\n return createElement(\n ClientCtx.Provider,\n { value: client },\n createElement(PortsCtx.Provider, { value: ports ?? INERT_PORTS }, children),\n );\n}\n\n/** The injected MediaClient. Throws when no MediaProvider is mounted. */\nexport function useMediaClient(): MediaClient {\n const client = useContext(clientContext());\n if (!client) {\n throw new Error(\n \"@ai-matrx/media: no MediaClient. Mount <MediaProvider client={...}> \" +\n \"above every media surface (canonically wired to @ai-matrx/data/files).\",\n );\n }\n return client;\n}\n\n/** The injected host ports; inert defaults when none were provided. */\nexport function useMediaHostPorts(): MediaHostPorts {\n return useContext(portsContext());\n}\n","/**\n * src/core/diagnostics.ts — the terminal-failure capture machinery.\n *\n * Born from the 2026-08-30 prod outage: server-side cookie-secret drift\n * killed every private image, the package rendered its honest \"unavailable\"\n * panel — and nothing reached the host's Error Inspector or error DB,\n * because the package had no diagnostics port and the host cannot capture\n * what it never learns about. Per ruling C22 the capture logic lives HERE,\n * so every consuming repo inherits it.\n *\n * The contract:\n *\n * - every terminal failure path emits exactly ONE {@link MediaFailureInfo}\n * per media identity (latched — re-renders, remounts and the unavailable\n * panel backstop never spam);\n * - a bound `MediaHostPorts.diagnostics.capture` receives the payload;\n * WITHOUT one (or if it throws) the package `console.error`s the same\n * structured payload — the loud default. A media failure is NEVER silent;\n * - the payload never carries a signed URL: identity is the file id or a\n * query-stripped URL key ({@link failureMediaIdentity}).\n *\n * The latch lives on `globalThis` under a `Symbol.for` slot (same reason as\n * context.ts: with `splitting: false` + dual formats, module-level state\n * silently duplicates across bundle/loader graphs).\n */\n\nimport { useCallback, useRef } from \"react\";\nimport type { MediaFailureInfo, MediaRefLike } from \"../types\";\nimport { useMediaHostPorts } from \"./context\";\n\nconst LATCH_SLOT = Symbol.for(\"ai-matrx.media.failure-latch\");\n\ntype SlotHost = typeof globalThis & {\n [LATCH_SLOT]?: Set<string>;\n};\n\nfunction latch(): Set<string> {\n const host = globalThis as SlotHost;\n host[LATCH_SLOT] ??= new Set<string>();\n return host[LATCH_SLOT];\n}\n\n/**\n * Clear the once-per-failure latch. For tests, and for hosts at auth\n * boundaries (a sign-in can genuinely fix a previously-terminal failure, and\n * a recurrence after it deserves a fresh capture).\n */\nexport function resetMediaFailureLatch(): void {\n latch().clear();\n}\n\n/**\n * Durable diagnostics identity for a media reference. NEVER a signed URL:\n * file ids win, and any URL is stripped to origin + path (signatures ride\n * query strings).\n */\nexport function failureMediaIdentity(\n ref: MediaRefLike | null | undefined,\n src?: string | null,\n): string {\n if (ref && typeof ref === \"object\" && ref.file_id) return `file:${ref.file_id}`;\n const raw =\n typeof ref === \"string\"\n ? ref\n : (ref && typeof ref === \"object\" ? (ref.url ?? null) : null) ?? src ?? null;\n if (!raw) return \"<unknown-media>\";\n if (raw.startsWith(\"blob:\")) return \"blob:object-url\";\n try {\n const u = new URL(raw);\n return `url:${u.origin}${u.pathname}`;\n } catch {\n // A bare fileId string, or an unparseable fragment — still strip any query.\n const clean = raw.split(/[?#]/, 1)[0] ?? raw;\n return `ref:${clean}`;\n }\n}\n\n/**\n * Emit one media-failure capture through the host sink, or the loud\n * console.error default when no sink is bound (or the sink throws).\n * Latched per (terminal|warning, mediaRef) — one capture per failure,\n * however many renders, hooks, or backstops observe it.\n */\nexport function emitMediaFailure(\n capture: ((info: MediaFailureInfo) => void) | undefined,\n info: MediaFailureInfo,\n): void {\n const key = `${info.terminal ? \"terminal\" : \"warning\"}|${info.mediaRef}`;\n const seen = latch();\n if (seen.has(key)) return;\n seen.add(key);\n if (capture) {\n try {\n capture(info);\n return;\n } catch {\n // A broken sink must not re-silence the failure — fall through.\n }\n }\n console.error(\n \"[@ai-matrx/media] media failure (no diagnostics sink captured it — \" +\n \"bind MediaHostPorts.diagnostics.capture to your error system)\",\n info,\n );\n}\n\n/**\n * Hook form: a stable capture function wired to the host ports. Every core\n * hook and the unavailable-panel backstop route through this — the phase\n * vocabulary and the latch stay in ONE place.\n */\nexport function useMediaFailureCapture(): (\n info: Omit<MediaFailureInfo, \"source\">,\n) => void {\n const ports = useMediaHostPorts();\n const capture = ports.diagnostics?.capture;\n // The latest sink without invalidating effect deps in the calling hooks —\n // the port object is referentially stable by contract, but a fresh binding\n // (e.g. tests swapping providers) must not capture stale.\n const captureRef = useRef(capture);\n captureRef.current = capture;\n return useCallback((info: Omit<MediaFailureInfo, \"source\">) => {\n emitMediaFailure(captureRef.current, { source: \"media\", ...info });\n }, []);\n}\n","/**\n * src/core/ref-key.ts — stable identity key for a MediaRefLike.\n *\n * Callers routinely pass fresh object literals every render; hooks key their\n * effects/memos on this string instead of object identity. Ported from the\n * original `stableSourceKey` (matrx-frontend `handler/hooks/useFileAs.ts`).\n */\n\nimport type { MediaRefLike } from \"../types\";\n\nexport function stableRefKey(ref: MediaRefLike | null | undefined): string {\n if (!ref) return \"<none>\";\n if (typeof ref === \"string\") return `s:${ref}`;\n if (ref.file_id) return `id:${ref.file_id}:${ref.mime_type ?? \"\"}`;\n if (ref.url) return `url:${ref.url}:${ref.mime_type ?? \"\"}`;\n return \"<empty-ref>\";\n}\n","/**\n * src/core/use-media-resolution.ts — ref → durable resolution, as state.\n *\n * Law 2: every consumer resolves media through the client, unconditionally —\n * even a caller-supplied URL string is classified, never trusted. Law 15 of\n * the handler (unavailable is a rendered state): a throwing `resolve()` is\n * classified via `classifyError` and returned as typed state — never\n * re-thrown. It IS however a terminal failure, so it also emits exactly one\n * `MediaFailureInfo` (phase \"resolve\") through the diagnostics machinery —\n * the 2026-08-30 outage rule: an unavailable render is honest to the USER but\n * must never be silent to the SYSTEM.\n */\n\nimport { useEffect, useMemo } from \"react\";\nimport type {\n MediaRefLike,\n MediaResolution,\n MediaUnavailableReason,\n} from \"../types\";\nimport { useMediaClient } from \"./context\";\nimport { failureMediaIdentity, useMediaFailureCapture } from \"./diagnostics\";\nimport { stableRefKey } from \"./ref-key\";\n\nexport interface MediaResolutionState {\n resolution: MediaResolution | null;\n /**\n * \"empty\" — no ref, or a ref with no usable identity (render fallback)\n * \"ready\" — resolution available\n * \"unavailable\" — resolve() refused (signed URL, access denied…); render\n * the typed unavailable state, never an incident\n */\n status: \"empty\" | \"ready\" | \"unavailable\";\n reason: MediaUnavailableReason | null;\n}\n\nexport function useMediaResolution(\n ref: MediaRefLike | null | undefined,\n): MediaResolutionState {\n const client = useMediaClient();\n const capture = useMediaFailureCapture();\n const refKey = stableRefKey(ref);\n const { state, failureMessage } = useMemo<{\n state: MediaResolutionState;\n failureMessage: string | null;\n }>(() => {\n if (!ref) {\n return {\n state: { resolution: null, status: \"empty\", reason: null },\n failureMessage: null,\n };\n }\n try {\n const resolution = client.resolve(ref);\n if (!resolution) {\n return {\n state: { resolution: null, status: \"empty\", reason: null },\n failureMessage: null,\n };\n }\n return {\n state: { resolution, status: \"ready\", reason: null },\n failureMessage: null,\n };\n } catch (err) {\n return {\n state: {\n resolution: null,\n status: \"unavailable\",\n reason: client.classifyError(err),\n },\n failureMessage:\n err instanceof Error ? err.message : String(err ?? \"resolve() failed\"),\n };\n }\n // eslint-disable-next-line react-hooks/exhaustive-deps\n }, [client, refKey]);\n\n // Terminal-failure capture (phase \"resolve\") — an effect, never a render\n // side effect; latched per media identity by the diagnostics machinery.\n useEffect(() => {\n if (state.status !== \"unavailable\") return;\n capture({\n phase: \"resolve\",\n mediaRef: failureMediaIdentity(ref ?? null),\n terminal: true,\n message: `resolve() refused (${state.reason ?? \"unknown\"}): ${\n failureMessage ?? \"no error message\"\n }`,\n });\n // eslint-disable-next-line react-hooks/exhaustive-deps\n }, [refKey, state.status]);\n\n return state;\n}\n","/**\n * src/core/file-kind.ts — filename/MIME → category, icon name, color.\n *\n * Condensed port of the icon-relevant slice of matrx-frontend\n * `features/files/utils/file-types.ts` (the FILE_TYPES registry): every\n * extension→{category,icon,color,displayName} row is preserved; the\n * preview/thumbnail/size-cap columns stay in the app (C8 — they belong to\n * the previewer world, not the media kit). MIME-prefix fallback, the\n * dotfile-looks-like-text heuristic, folder details and the unknown default\n * are ported verbatim in behavior.\n *\n * Platform-free: icon NAMES only — `/react` maps names to its inlined SVGs;\n * a future `/react-native` binding maps the same names to its own glyphs.\n */\n\nexport type FileCategory =\n | \"CODE\"\n | \"DOCUMENT\"\n | \"AUDIO\"\n | \"IMAGE\"\n | \"VIDEO\"\n | \"ARCHIVE\"\n | \"DATA\"\n | \"NOTEBOOK\"\n | \"SUBTITLES\"\n | \"EMAIL\"\n | \"EBOOK\"\n | \"MODEL_3D\"\n | \"UNKNOWN\"\n | \"FOLDER\";\n\nexport type FileIconName =\n | \"image\"\n | \"pen-tool\"\n | \"video\"\n | \"music\"\n | \"file-type\"\n | \"file-text\"\n | \"code\"\n | \"braces\"\n | \"subtitles\"\n | \"file-code\"\n | \"file-json\"\n | \"file-spreadsheet\"\n | \"database\"\n | \"package\"\n | \"archive\"\n | \"folder\"\n | \"folder-open\"\n | \"file\"\n | \"file-audio\"\n | \"file-video\";\n\nexport interface FileKindDetails {\n category: FileCategory;\n displayName: string;\n /** Tailwind text color token, matching the original registry exactly. */\n colorClass: string;\n icon: FileIconName;\n}\n\ntype Row = [\n extensions: string[],\n category: FileCategory,\n colorClass: string,\n icon: FileIconName,\n displayName: string,\n];\n\n// Rows ported from the FILE_TYPES registry (icon-relevant columns), grouped\n// exactly as the original's icon/color assignments group them.\nconst ROWS: Row[] = [\n [[\"jpg\", \"jpeg\", \"png\", \"gif\", \"webp\", \"avif\", \"heic\", \"heif\", \"bmp\", \"tif\", \"tiff\", \"ico\"], \"IMAGE\", \"text-emerald-500\", \"image\", \"Image\"],\n [[\"svg\"], \"IMAGE\", \"text-amber-500\", \"pen-tool\", \"SVG image\"],\n [[\"mp4\", \"mov\", \"webm\", \"mkv\", \"avi\", \"m4v\"], \"VIDEO\", \"text-purple-500\", \"video\", \"Video\"],\n [[\"mp3\", \"wav\", \"ogg\", \"m4a\", \"aac\", \"flac\", \"opus\"], \"AUDIO\", \"text-pink-500\", \"music\", \"Audio\"],\n [[\"pdf\"], \"DOCUMENT\", \"text-red-500\", \"file-type\", \"PDF Document\"],\n [[\"md\", \"markdown\", \"mdx\", \"rst\", \"adoc\", \"asciidoc\", \"org\"], \"DOCUMENT\", \"text-slate-400\", \"file-text\", \"Markdown\"],\n [[\"txt\", \"text\", \"asc\", \"me\", \"log\", \"out\", \"err\"], \"DOCUMENT\", \"text-muted-foreground\", \"file-text\", \"Text\"],\n [[\"dockerfile\", \"containerfile\", \"lua\"], \"CODE\", \"text-blue-500\", \"code\", \"Code\"],\n [[\"mk\", \"make\", \"swift\", \"ml\", \"mli\", \"fs\", \"fsi\", \"fsx\", \"svelte\"], \"CODE\", \"text-orange-500\", \"code\", \"Code\"],\n [[\"diff\", \"patch\", \"pem\", \"csr\", \"crt\", \"cer\", \"der\", \"key\", \"pub\", \"p7b\", \"p7c\", \"pfx\", \"p12\"], \"CODE\", \"text-amber-500\", \"file-text\", \"Text\"],\n [[\"ini\", \"cfg\", \"conf\", \"config\", \"properties\", \"prefs\"], \"CODE\", \"text-amber-400\", \"braces\", \"Config\"],\n [[\"tex\", \"latex\", \"ltx\", \"sty\", \"cls\", \"bib\"], \"CODE\", \"text-emerald-500\", \"file-text\", \"LaTeX\"],\n [[\"srt\", \"vtt\"], \"SUBTITLES\", \"text-cyan-500\", \"subtitles\", \"Subtitles\"],\n [[\"js\", \"mjs\", \"cjs\", \"jsx\"], \"CODE\", \"text-yellow-500\", \"file-code\", \"JavaScript\"],\n [[\"ts\", \"tsx\"], \"CODE\", \"text-blue-500\", \"file-code\", \"TypeScript\"],\n [[\"py\", \"clj\", \"cljs\", \"cljc\", \"edn\", \"vue\", \"styl\", \"stylus\"], \"CODE\", \"text-emerald-500\", \"code\", \"Code\"],\n [[\"rb\", \"rbw\", \"rake\", \"ru\", \"gemspec\", \"scala\", \"sbt\"], \"CODE\", \"text-red-500\", \"code\", \"Code\"],\n [[\"go\", \"dart\"], \"CODE\", \"text-cyan-500\", \"code\", \"Code\"],\n [[\"rs\"], \"CODE\", \"text-orange-600\", \"code\", \"Rust\"],\n [[\"java\"], \"CODE\", \"text-red-600\", \"code\", \"Java\"],\n [[\"c\", \"h\"], \"CODE\", \"text-blue-600\", \"code\", \"C\"],\n [[\"cpp\", \"cc\", \"cxx\", \"hpp\"], \"CODE\", \"text-blue-700\", \"code\", \"C++\"],\n [[\"cs\"], \"CODE\", \"text-purple-600\", \"code\", \"C#\"],\n [[\"html\", \"htm\", \"kt\", \"kts\"], \"CODE\", \"text-orange-400\", \"code\", \"Code\"],\n [[\"css\"], \"CODE\", \"text-sky-400\", \"code\", \"CSS\"],\n [[\"scss\"], \"CODE\", \"text-pink-400\", \"code\", \"SCSS\"],\n [[\"sh\", \"bash\", \"zsh\", \"fish\", \"ksh\", \"ash\", \"bat\", \"cmd\", \"twig\", \"jinja\", \"j2\", \"njk\"], \"CODE\", \"text-emerald-400\", \"code\", \"Script\"],\n [[\"sql\"], \"CODE\", \"text-amber-400\", \"code\", \"SQL\"],\n [[\"pl\", \"pm\"], \"CODE\", \"text-indigo-400\", \"code\", \"Perl\"],\n [[\"r\", \"rmd\", \"proto\", \"ps1\", \"psm1\", \"psd1\", \"less\"], \"CODE\", \"text-blue-400\", \"code\", \"Code\"],\n [[\"ex\", \"exs\"], \"CODE\", \"text-purple-400\", \"code\", \"Elixir\"],\n [[\"erl\", \"hrl\"], \"CODE\", \"text-rose-500\", \"code\", \"Erlang\"],\n [[\"hs\", \"lhs\"], \"CODE\", \"text-violet-500\", \"code\", \"Haskell\"],\n [[\"zig\"], \"CODE\", \"text-yellow-500\", \"code\", \"Zig\"],\n [[\"nim\", \"nims\"], \"CODE\", \"text-yellow-400\", \"code\", \"Nim\"],\n [[\"jl\"], \"CODE\", \"text-purple-500\", \"code\", \"Julia\"],\n [[\"astro\"], \"CODE\", \"text-fuchsia-500\", \"code\", \"Astro\"],\n [[\"graphql\", \"gql\", \"graphqls\"], \"CODE\", \"text-pink-500\", \"code\", \"GraphQL\"],\n [[\"sol\"], \"CODE\", \"text-slate-400\", \"code\", \"Solidity\"],\n [[\"php\", \"phtml\", \"phps\"], \"CODE\", \"text-indigo-500\", \"code\", \"PHP\"],\n [[\"hbs\", \"handlebars\", \"mustache\", \"ejs\", \"liquid\"], \"CODE\", \"text-amber-500\", \"code\", \"Template\"],\n [[\"json\", \"jsonc\", \"json5\", \"har\", \"geojson\", \"topojson\"], \"DATA\", \"text-amber-500\", \"file-json\", \"JSON\"],\n [[\"yaml\", \"yml\", \"toml\"], \"CODE\", \"text-amber-500\", \"braces\", \"Config\"],\n [[\"xml\"], \"DATA\", \"text-amber-500\", \"braces\", \"XML\"],\n [[\"csv\", \"tsv\"], \"DATA\", \"text-orange-500\", \"file-spreadsheet\", \"Spreadsheet data\"],\n [[\"sqlite\", \"sqlite3\", \"db\"], \"DATA\", \"text-blue-400\", \"database\", \"Database\"],\n [[\"ttl\", \"n3\", \"nt\", \"nq\", \"trig\"], \"DATA\", \"text-fuchsia-400\", \"braces\", \"RDF data\"],\n [[\"xlsx\", \"xls\"], \"DOCUMENT\", \"text-emerald-600\", \"file-spreadsheet\", \"Excel workbook\"],\n [[\"doc\", \"docx\"], \"DOCUMENT\", \"text-blue-500\", \"file-text\", \"Word document\"],\n [[\"ppt\", \"pptx\"], \"DOCUMENT\", \"text-orange-600\", \"file-type\", \"Presentation\"],\n [[\"ipynb\"], \"NOTEBOOK\", \"text-orange-400\", \"file-json\", \"Notebook\"],\n [[\"epub\"], \"EBOOK\", \"text-indigo-500\", \"file-text\", \"eBook\"],\n [[\"eml\"], \"EMAIL\", \"text-blue-400\", \"file-text\", \"Email\"],\n [[\"glb\", \"gltf\", \"stl\", \"obj\", \"fbx\"], \"MODEL_3D\", \"text-violet-400\", \"package\", \"3D model\"],\n [[\"zip\", \"rar\", \"7z\"], \"ARCHIVE\", \"text-amber-600\", \"archive\", \"Archive\"],\n [[\"tar\", \"gz\", \"tgz\"], \"ARCHIVE\", \"text-amber-600\", \"package\", \"Archive\"],\n];\n\nconst BY_EXTENSION = new Map<string, FileKindDetails>();\nfor (const [extensions, category, colorClass, icon, displayName] of ROWS) {\n for (const ext of extensions) {\n BY_EXTENSION.set(ext, { category, colorClass, icon, displayName });\n }\n}\n\nconst UNKNOWN_DETAILS: FileKindDetails = {\n category: \"UNKNOWN\",\n displayName: \"File\",\n colorClass: \"text-muted-foreground\",\n icon: \"file\",\n};\n\nconst ASSUMED_TEXT_DETAILS: FileKindDetails = {\n category: \"DOCUMENT\",\n displayName: \"Text\",\n colorClass: \"text-muted-foreground\",\n icon: \"file-text\",\n};\n\nconst FOLDER_DETAILS: FileKindDetails = {\n category: \"FOLDER\",\n displayName: \"Folder\",\n colorClass: \"text-sky-500\",\n icon: \"folder\",\n};\n\nconst IMAGE_DETAILS = BY_EXTENSION.get(\"png\") as FileKindDetails;\nconst VIDEO_DETAILS = BY_EXTENSION.get(\"mp4\") as FileKindDetails;\nconst AUDIO_DETAILS = BY_EXTENSION.get(\"mp3\") as FileKindDetails;\nconst PDF_DETAILS = BY_EXTENSION.get(\"pdf\") as FileKindDetails;\nconst SVG_DETAILS = BY_EXTENSION.get(\"svg\") as FileKindDetails;\n\nfunction basenameOf(path: string): string {\n const idx = Math.max(path.lastIndexOf(\"/\"), path.lastIndexOf(\"\\\\\"));\n return idx >= 0 ? path.slice(idx + 1) : path;\n}\n\nfunction extOf(name: string): string | null {\n const idx = name.lastIndexOf(\".\");\n if (idx <= 0 || idx === name.length - 1) return null;\n return name.slice(idx + 1).toLowerCase();\n}\n\n/**\n * Dotfile heuristic (ported): unrecognized dotfiles are almost always text —\n * bias toward the text profile instead of the binary \"File\" default.\n */\nfunction dotfileLooksLikeText(filename: string): boolean {\n const name = basenameOf(filename);\n if (!name.startsWith(\".\")) return false;\n for (let i = 1; i < name.length; i++) {\n const c = name.charCodeAt(i);\n if (\n (c >= 48 && c <= 57) ||\n (c >= 65 && c <= 90) ||\n (c >= 97 && c <= 122) ||\n c === 95 ||\n c === 45\n ) {\n return true;\n }\n }\n return false;\n}\n\n/** Strip MIME parameters (`;codecs=opus`, etc.). */\nfunction canonicalMimeBase(raw: string): string {\n return raw.split(\";\")[0]?.trim().toLowerCase() ?? raw;\n}\n\n/**\n * Resolve icon details from a filename and (optionally) the server MIME.\n * MIME-prefix override handles \"the browser knows `image/avif` but the\n * extension table doesn't\" — and disambiguates audio/webm vs video/webm.\n */\nexport function getFileKindDetails(\n fileName: string,\n mimeType?: string | null,\n): FileKindDetails {\n const name = basenameOf(fileName);\n const lower = name.toLowerCase();\n const ext = lower === \"dockerfile\" || lower === \"containerfile\" ? lower : extOf(name);\n const fromExt = ext ? BY_EXTENSION.get(ext) : undefined;\n\n const mime = mimeType ? canonicalMimeBase(mimeType) : null;\n if (mime) {\n if (mime === \"image/svg+xml\") return fromExt ?? SVG_DETAILS;\n if (mime.startsWith(\"image/\")) return fromExt?.category === \"IMAGE\" ? fromExt : IMAGE_DETAILS;\n if (mime.startsWith(\"video/\")) return fromExt?.category === \"VIDEO\" ? fromExt : VIDEO_DETAILS;\n if (mime.startsWith(\"audio/\")) return fromExt?.category === \"AUDIO\" ? fromExt : AUDIO_DETAILS;\n if (mime === \"application/pdf\") return PDF_DETAILS;\n }\n\n if (fromExt) return fromExt;\n if (dotfileLooksLikeText(fileName)) return ASSUMED_TEXT_DETAILS;\n return UNKNOWN_DETAILS;\n}\n\n/** Folder icon details (open picks the open-folder glyph). */\nexport function getFolderKindDetails(open = false): FileKindDetails {\n return open ? { ...FOLDER_DETAILS, icon: \"folder-open\" } : FOLDER_DETAILS;\n}\n","/**\n * src/react/file-icon.tsx — icon tile for any file or folder.\n *\n * Verbatim port of matrx-frontend `components/core/FileIcon/FileIcon.tsx`\n * with two seam inversions: the registry lookup is the package's own\n * `getFileKindDetails` (`/core`), and the glyphs are the package's own\n * inlined SVGs (C19 — no lucide peer).\n */\n\nimport type { CSSProperties } from \"react\";\nimport {\n getFileKindDetails,\n getFolderKindDetails,\n type FileIconName,\n} from \"../core/file-kind\";\nimport { cn } from \"./cn\";\nimport {\n ArchiveIcon,\n BracesIcon,\n CodeIcon,\n DatabaseIcon,\n FileAudioIcon,\n FileCodeIcon,\n FileIcon as FileGlyph,\n FileJsonIcon,\n FileSpreadsheetIcon,\n FileTextIcon,\n FileTypeIcon,\n FileVideoIcon,\n FolderIcon,\n FolderOpenIcon,\n ImageIcon,\n MusicIcon,\n PackageBoxIcon,\n PenToolIcon,\n SubtitlesIcon,\n VideoIcon,\n type MediaIconProps,\n} from \"./icons\";\n\nconst ICONS: Record<FileIconName, (props: MediaIconProps) => ReturnType<typeof FileGlyph>> = {\n image: ImageIcon,\n \"pen-tool\": PenToolIcon,\n video: VideoIcon,\n music: MusicIcon,\n \"file-type\": FileTypeIcon,\n \"file-text\": FileTextIcon,\n code: CodeIcon,\n braces: BracesIcon,\n subtitles: SubtitlesIcon,\n \"file-code\": FileCodeIcon,\n \"file-json\": FileJsonIcon,\n \"file-spreadsheet\": FileSpreadsheetIcon,\n database: DatabaseIcon,\n package: PackageBoxIcon,\n archive: ArchiveIcon,\n folder: FolderIcon,\n \"folder-open\": FolderOpenIcon,\n file: FileGlyph,\n \"file-audio\": FileAudioIcon,\n \"file-video\": FileVideoIcon,\n};\n\nexport interface FileIconProps {\n /** Either the filename (for files) or omitted for folders. */\n fileName?: string | undefined;\n /** Server MIME — when set, resolves audio/webm vs video/webm correctly. */\n mimeType?: string | null | undefined;\n /** If true, renders a folder icon. `open` picks the open-folder glyph. */\n isFolder?: boolean | undefined;\n open?: boolean | undefined;\n /** Override the mapped color (useful for selected states). */\n colorClass?: string | undefined;\n className?: string | undefined;\n size?: number | undefined;\n}\n\nexport function FileIcon({\n fileName,\n mimeType = null,\n isFolder,\n open,\n colorClass,\n className,\n size = 16,\n}: FileIconProps) {\n const details = isFolder\n ? getFolderKindDetails(open)\n : getFileKindDetails(fileName ?? \"\", mimeType);\n const Icon = ICONS[details.icon];\n const style: CSSProperties = {\n width: `${size}px`,\n height: `${size}px`,\n minWidth: `${size}px`,\n };\n return (\n <Icon\n style={style}\n className={cn(\"shrink-0\", colorClass ?? details.colorClass, className)}\n aria-hidden=\"true\"\n />\n );\n}\n","/**\n * src/react/upload-progress-list.tsx — the live upload tray.\n *\n * Verbatim behavior port of matrx-frontend\n * `FileUploadDropzone/UploadProgressList.tsx` with the Redux seams inverted:\n * entries come from `useMediaUpload().entries` (or any structurally equal\n * list) and dismissal is the injected `onDismiss` instead of a dispatched\n * `clearUpload`.\n *\n * Behavior: in-flight entries show a live progress bar + percentage;\n * successful entries persist with an \"Open\" affordance and auto-dismiss\n * after 10s — the timer pauses while the pointer is over the tray; failed\n * entries persist until manually dismissed.\n */\n\n\"use client\";\n\nimport { memo, useEffect, useRef, useState } from \"react\";\nimport type { MediaUploadEntry } from \"../core/use-media-upload\";\nimport { cn } from \"./cn\";\nimport { FileIcon } from \"./file-icon\";\nimport {\n AlertCircleIcon,\n CheckCircle2Icon,\n ExternalLinkIcon,\n XIcon,\n} from \"./icons\";\n\n/** How long a successful upload lingers in the tray before auto-dismissing. */\nconst AUTO_DISMISS_MS = 10_000;\n\n/**\n * Human file size.\n *\n * `null` / `undefined` / NaN / negative collapse to an em-dash, NOT to\n * \"0 B\" (fixed at 0.4.0 while absorbing the viewer bodies — matrx-frontend's\n * `formatFileSize` already had this guard and the package's did not, so a\n * corrupt or mid-upload `size` row rendered as a confident, wrong \"0 B\"\n * instead of an honest \"size unknown\").\n */\nexport function formatFileSize(bytes: number | null | undefined): string {\n if (bytes == null || !Number.isFinite(bytes) || bytes < 0) return \"—\";\n if (bytes < 1024) return `${bytes} B`;\n const units = [\"KB\", \"MB\", \"GB\", \"TB\"] as const;\n let value = bytes;\n let unit = -1;\n do {\n value /= 1024;\n unit += 1;\n } while (value >= 1024 && unit < units.length - 1);\n return `${value >= 10 ? Math.round(value) : value.toFixed(1)} ${units[unit] ?? \"TB\"}`;\n}\n\nexport interface UploadProgressListProps {\n uploads: MediaUploadEntry[];\n /** Remove an entry from the tray (wire to `useMediaUpload().clearEntry`). */\n onDismiss: (id: string) => void;\n /**\n * Reveal a finished file — opens the preview pane / scrolls the row.\n * When omitted, the \"Open\" affordance is hidden.\n */\n onOpenFile?: ((fileId: string) => void) | undefined;\n className?: string | undefined;\n}\n\nfunction UploadProgressListImpl({\n uploads,\n onDismiss,\n onOpenFile,\n className,\n}: UploadProgressListProps) {\n const [hovered, setHovered] = useState(false);\n\n const activeCount = uploads.filter((u) => u.status === \"uploading\").length;\n const successCount = uploads.filter((u) => u.status === \"success\").length;\n const errorCount = uploads.filter((u) => u.status === \"error\").length;\n\n // Auto-dismiss successful entries. The timer is paused (cleared) while the\n // pointer is over the tray so a user reaching for \"Open\" is never cut off.\n const timersRef = useRef<Map<string, ReturnType<typeof setTimeout>>>(\n new Map(),\n );\n const onDismissRef = useRef(onDismiss);\n onDismissRef.current = onDismiss;\n useEffect(() => {\n const timers = timersRef.current;\n if (hovered) {\n timers.forEach((t) => clearTimeout(t));\n timers.clear();\n return;\n }\n for (const u of uploads) {\n if (u.status !== \"success\") continue;\n if (timers.has(u.id)) continue;\n const elapsed = u.completedAt ? Date.now() - u.completedAt : 0;\n const remaining = Math.max(0, AUTO_DISMISS_MS - elapsed);\n const handle = setTimeout(() => {\n timers.delete(u.id);\n onDismissRef.current(u.id);\n }, remaining);\n timers.set(u.id, handle);\n }\n const liveSuccessIds = new Set(\n uploads.filter((u) => u.status === \"success\").map((u) => u.id),\n );\n for (const [id, handle] of timers) {\n if (!liveSuccessIds.has(id)) {\n clearTimeout(handle);\n timers.delete(id);\n }\n }\n }, [uploads, hovered]);\n\n useEffect(() => {\n const timers = timersRef.current;\n return () => {\n timers.forEach((t) => clearTimeout(t));\n timers.clear();\n };\n }, []);\n\n if (uploads.length === 0) return null;\n\n const headerLabel =\n activeCount > 0\n ? `Uploading ${activeCount} file${activeCount === 1 ? \"\" : \"s\"}…`\n : errorCount > 0 && successCount === 0\n ? `${errorCount} upload${errorCount === 1 ? \"\" : \"s\"} failed`\n : `Uploaded ${successCount} file${successCount === 1 ? \"\" : \"s\"}`;\n\n const completedIds = uploads\n .filter((u) => u.status === \"success\" || u.status === \"error\")\n .map((u) => u.id);\n\n return (\n <div\n className={cn(\n \"overflow-hidden rounded-lg border bg-background/95 shadow-lg backdrop-blur\",\n className,\n )}\n onMouseEnter={() => setHovered(true)}\n onMouseLeave={() => setHovered(false)}\n aria-label=\"Uploads\"\n >\n <div className=\"flex items-center justify-between gap-2 border-b bg-muted/40 px-3 py-1.5\">\n <span className=\"truncate text-xs font-medium text-foreground\">\n {headerLabel}\n </span>\n {completedIds.length > 0 ? (\n <button\n type=\"button\"\n onClick={() => {\n for (const id of completedIds) onDismiss(id);\n }}\n className=\"shrink-0 rounded px-1.5 py-0.5 text-[11px] text-muted-foreground hover:bg-accent hover:text-foreground\"\n >\n Clear\n </button>\n ) : null}\n </div>\n\n <ul className=\"max-h-72 space-y-1 overflow-y-auto p-2\">\n {uploads.map((u) => {\n const percent =\n u.fileSize > 0\n ? Math.min(100, Math.round((u.bytesUploaded / u.fileSize) * 100))\n : 0;\n const done = u.status === \"success\";\n const failed = u.status === \"error\";\n const canOpen = done && !!u.fileId && !!onOpenFile;\n return (\n <li\n key={u.id}\n className={cn(\n \"flex items-center gap-2 rounded-md px-2 py-1.5 text-xs\",\n canOpen && \"cursor-pointer hover:bg-accent/60\",\n )}\n onClick={\n canOpen ? () => onOpenFile(u.fileId as string) : undefined\n }\n >\n <FileIcon fileName={u.fileName} size={18} className=\"shrink-0\" />\n <div className=\"min-w-0 flex-1\">\n <div className=\"flex items-center justify-between gap-2\">\n <span className=\"truncate font-medium text-foreground\">\n {u.fileName}\n </span>\n <span className=\"shrink-0 tabular-nums text-muted-foreground\">\n {failed ? \"Failed\" : done ? \"Done\" : `${percent}%`}\n </span>\n </div>\n {done ? null : (\n <div className=\"mt-1 h-1 w-full rounded bg-muted\">\n <div\n className={cn(\n \"h-1 rounded transition-all\",\n failed ? \"bg-destructive\" : \"bg-primary\",\n )}\n style={{ width: failed ? \"100%\" : `${percent}%` }}\n />\n </div>\n )}\n {failed && u.error ? (\n <p className=\"mt-0.5 truncate text-[10px] text-destructive\">\n {u.error}\n </p>\n ) : !done ? (\n <p className=\"mt-0.5 text-[10px] text-muted-foreground\">\n {formatFileSize(u.bytesUploaded)} /{\" \"}\n {formatFileSize(u.fileSize)}\n </p>\n ) : null}\n </div>\n\n {canOpen ? (\n <span className=\"flex shrink-0 items-center gap-1 rounded px-1.5 py-0.5 text-[11px] font-medium text-primary\">\n <ExternalLinkIcon className=\"h-3 w-3\" width={12} height={12} />\n Open\n </span>\n ) : done ? (\n <CheckCircle2Icon\n className=\"h-4 w-4 shrink-0 text-emerald-500\"\n width={16}\n height={16}\n />\n ) : failed ? (\n <AlertCircleIcon\n className=\"h-4 w-4 shrink-0 text-destructive\"\n width={16}\n height={16}\n />\n ) : null}\n\n {done || failed ? (\n <button\n type=\"button\"\n onClick={(e) => {\n e.stopPropagation();\n onDismiss(u.id);\n }}\n aria-label=\"Dismiss\"\n className=\"flex h-5 w-5 shrink-0 items-center justify-center rounded text-muted-foreground hover:bg-accent hover:text-foreground\"\n >\n <XIcon className=\"h-3 w-3\" width={12} height={12} />\n </button>\n ) : null}\n </li>\n );\n })}\n </ul>\n </div>\n );\n}\n\nexport const UploadProgressList = memo(UploadProgressListImpl);\n","/**\n * src/viewers/generic-viewer.tsx — the no-dedicated-viewer card.\n *\n * Absorbed from matrx-frontend\n * `features/files/components/core/FilePreview/previewers/GenericPreview.tsx`.\n *\n * DEFECT FIXED IN THE PORT (recorded in CHANGELOG 0.4.0, never silently):\n * the original shipped a `DEBUG_RING_GENERIC_PREVIEW` fuchsia ring plus a\n * \"GenericPreview\" corner badge — a layering-debug artifact marked \"Rip this\n * out when done\" that reached users on every unpreviewable file. Absorption\n * kills it; the package has no debug chrome.\n */\n\n\"use client\";\n\nimport { cn } from \"../react/cn\";\nimport { FileIcon } from \"../react/file-icon\";\nimport { DownloadIcon, FileTextIcon, SpinnerIcon } from \"../react/icons\";\nimport { formatFileSize } from \"../react/upload-progress-list\";\nimport type { MediaViewerProps } from \"./types\";\n\nexport function GenericViewer({\n fileName,\n fileSize,\n generic,\n className,\n}: MediaViewerProps) {\n const onDownload = generic?.onDownload;\n const onViewAsText = generic?.onViewAsText;\n const viewAsTextLabel = generic?.viewAsTextLabel ?? \"View as text\";\n const viewAsTextPrimary = generic?.viewAsTextPrimary ?? true;\n const viewAsTextBusy = generic?.viewAsTextBusy ?? false;\n const hasViewAsText = typeof onViewAsText === \"function\";\n const hasDownload = typeof onDownload === \"function\";\n\n return (\n <div\n className={cn(\n \"relative flex h-full w-full flex-col items-center justify-center gap-4 p-6 text-center\",\n className,\n )}\n >\n <FileIcon fileName={fileName} size={48} />\n <div>\n <p className=\"max-w-md truncate text-sm font-medium\">{fileName}</p>\n <p className=\"text-xs text-muted-foreground\">\n {formatFileSize(fileSize ?? null)}\n </p>\n </div>\n <p className=\"max-w-sm text-sm text-muted-foreground\">\n {generic?.message ??\n (hasViewAsText\n ? \"No built-in previewer for this file type.\"\n : \"This file type can't be previewed here.\")}\n </p>\n <div className=\"flex flex-wrap items-center justify-center gap-2\">\n {onViewAsText && viewAsTextPrimary ? (\n <ViewAsTextButton\n onClick={onViewAsText}\n label={viewAsTextLabel}\n busy={viewAsTextBusy}\n variant=\"primary\"\n />\n ) : null}\n {onDownload ? (\n <button\n type=\"button\"\n onClick={onDownload}\n className={cn(\n \"inline-flex items-center gap-2 rounded-md px-3 py-1.5 text-sm\",\n hasViewAsText && viewAsTextPrimary\n ? \"border border-input bg-background text-foreground hover:bg-accent hover:text-accent-foreground\"\n : \"bg-primary text-primary-foreground hover:bg-primary/90\",\n )}\n >\n <DownloadIcon className=\"h-4 w-4\" />\n Download\n </button>\n ) : null}\n {onViewAsText && !viewAsTextPrimary ? (\n <ViewAsTextButton\n onClick={onViewAsText}\n label={viewAsTextLabel}\n busy={viewAsTextBusy}\n variant=\"secondary\"\n />\n ) : null}\n </div>\n {!hasDownload && !hasViewAsText ? (\n <p className=\"max-w-sm text-[11px] text-muted-foreground/70\">\n Download it from the file's actions menu to open it in another\n application.\n </p>\n ) : null}\n </div>\n );\n}\n\nfunction ViewAsTextButton({\n onClick,\n label,\n busy,\n variant,\n}: {\n onClick: () => void;\n label: string;\n busy: boolean;\n variant: \"primary\" | \"secondary\";\n}) {\n return (\n <button\n type=\"button\"\n onClick={onClick}\n disabled={busy}\n className={cn(\n \"inline-flex items-center gap-2 rounded-md px-3 py-1.5 text-sm transition-colors\",\n \"disabled:cursor-not-allowed disabled:opacity-60\",\n variant === \"primary\"\n ? \"bg-primary text-primary-foreground hover:bg-primary/90\"\n : \"border border-input bg-background text-foreground hover:bg-accent hover:text-accent-foreground\",\n )}\n >\n {busy ? (\n <SpinnerIcon className=\"h-4 w-4 animate-spin\" />\n ) : (\n <FileTextIcon className=\"h-4 w-4\" />\n )}\n {label}\n </button>\n );\n}\n","/**\n * src/viewers/html-viewer.tsx — saved-HTML viewer (rendered + source).\n *\n * Absorbed from matrx-frontend\n * `features/files/components/core/FilePreview/previewers/HtmlPreview.tsx`.\n *\n * THE SANDBOX IS THE POINT, AND IT IS WHY THIS BELONGS IN THE PACKAGE. The\n * rendered view mounts `sandbox=\"allow-scripts allow-popups allow-forms\"`\n * WITHOUT `allow-same-origin`: the framed page may run scripts (most saved\n * pages need them to look right) but cannot read the host app's cookies,\n * browser persistence, or call its APIs, and cannot navigate the top frame.\n * `referrerPolicy=\"no-referrer\"` keeps the durable URL out of the framed\n * page's outbound requests. Every app that renders user-supplied HTML needs\n * exactly this attribute set, and getting one token wrong is a real XSS —\n * the textbook case for Arman's third test (\"less-than-perfect unless done\n * perfectly → in the package\"). Hosts do not get to configure it.\n */\n\n\"use client\";\n\nimport { useEffect, useState } from \"react\";\nimport { cn } from \"../react/cn\";\nimport { ViewerError, ViewerSkeleton } from \"./chrome\";\nimport { MarkupModeToggle, useMarkupMode } from \"./markup-chrome\";\nimport type { MediaViewerProps, MediaViewerViewport } from \"./types\";\nimport { useViewerDisplayUrl, useViewerText } from \"./use-viewer-bytes\";\n\n/** Device widths for the viewport simulator. Ported from the original. */\nconst VIEWPORT_WIDTH: Record<Exclude<MediaViewerViewport, \"auto\">, number> = {\n mobile: 390,\n tablet: 768,\n desktop: 1280,\n};\n\nexport function HtmlViewer(props: MediaViewerProps) {\n const { className, fileName, markupControls } = props;\n const { mode, setMode, controlled } = useMarkupMode(markupControls);\n\n return (\n <div className={cn(\"flex h-full w-full flex-col\", className)}>\n {controlled ? null : (\n <div className=\"flex shrink-0 items-center justify-between gap-2 border-b border-border/60 bg-background px-3 py-1.5 text-xs\">\n <span className=\"truncate font-medium text-foreground\">\n {fileName}\n </span>\n <MarkupModeToggle\n mode={mode}\n onChange={setMode}\n renderedLabel=\"Rendered\"\n renderedIcon=\"globe\"\n />\n </div>\n )}\n <div className=\"relative min-h-0 flex-1\">\n {mode === \"rendered\" ? (\n <HtmlRenderedView {...props} />\n ) : (\n <HtmlSourceView {...props} />\n )}\n </div>\n </div>\n );\n}\n\nfunction HtmlRenderedView({ source, fileName, markupControls }: MediaViewerProps) {\n const { url, unavailable } = useViewerDisplayUrl(source);\n const viewport = markupControls?.viewport ?? \"auto\";\n const reloadKey = markupControls?.reloadKey ?? 0;\n const [errored, setErrored] = useState(false);\n\n useEffect(() => {\n setErrored(false);\n }, [reloadKey, url]);\n\n if (unavailable) {\n return (\n <ViewerError\n title=\"This page isn't available\"\n hint=\"You may not have access to it, or it may have been deleted.\"\n />\n );\n }\n if (!url) return <ViewerSkeleton />;\n if (errored) return <ViewerError title=\"Preview unavailable\" />;\n\n const constrained = viewport !== \"auto\";\n const width = constrained ? VIEWPORT_WIDTH[viewport] : undefined;\n\n return (\n <div\n className={cn(\n \"h-full w-full overflow-auto bg-muted/10\",\n constrained && \"flex items-start justify-center\",\n )}\n >\n <div\n className={cn(\n \"h-full bg-background\",\n constrained\n ? \"my-4 overflow-hidden rounded-md border border-border/60 shadow-lg\"\n : \"w-full\",\n )}\n style={constrained ? { width } : undefined}\n >\n <iframe\n // `reloadKey` in the key forces a clean re-mount on an explicit reload.\n key={`${reloadKey}-${url}`}\n src={url}\n title={fileName}\n // NEVER add `allow-same-origin` here — see the module header.\n sandbox=\"allow-scripts allow-popups allow-forms\"\n referrerPolicy=\"no-referrer\"\n className=\"h-full w-full border-0 bg-white\"\n onError={() => setErrored(true)}\n />\n </div>\n </div>\n );\n}\n\nfunction HtmlSourceView({ source, maxBytes = 1024 * 1024 }: MediaViewerProps) {\n const { text, error, loading } = useViewerText(source, maxBytes);\n if (error) return <ViewerError title=\"Couldn't load source\" message={error} />;\n if (loading || text === null) return <ViewerSkeleton />;\n return (\n <pre className=\"h-full w-full overflow-auto bg-muted/10 p-4 font-mono text-xs leading-relaxed break-all whitespace-pre-wrap\">\n {text}\n </pre>\n );\n}\n","/**\n * src/viewers/markup-chrome.tsx — the rendered/source switch shared by the\n * SVG and HTML viewers, and the controlled/uncontrolled mode resolution both\n * of them need.\n *\n * The matrx-frontend originals each hand-rolled this (SvgPreview a floating\n * segmented control, HtmlPreview a header strip), and each hard-wired itself\n * to the app's `FileViewerControlsContext`. Here the host rail arrives as\n * OPTIONAL props: when a host drives the mode, the viewer hides its own\n * toolbar and obeys; when nothing drives it, the viewer is fully capable on\n * its own (C23).\n */\n\n\"use client\";\n\nimport { useState } from \"react\";\nimport { cn } from \"../react/cn\";\nimport { CodeIcon, GlobeIcon, ImageIcon } from \"../react/icons\";\nimport type { MediaViewerMarkupControls, MediaViewerMarkupMode } from \"./types\";\n\nexport interface ResolvedMarkupMode {\n mode: MediaViewerMarkupMode;\n setMode: (mode: MediaViewerMarkupMode) => void;\n /** True when the HOST drives the mode — the viewer must not draw a toolbar. */\n controlled: boolean;\n}\n\nexport function useMarkupMode(\n controls: MediaViewerMarkupControls | undefined,\n): ResolvedMarkupMode {\n const [localMode, setLocalMode] = useState<MediaViewerMarkupMode>(\"rendered\");\n const controlled = controls?.mode !== undefined;\n return {\n mode: controls?.mode ?? localMode,\n setMode: controls?.onModeChange ?? setLocalMode,\n controlled,\n };\n}\n\nexport function MarkupModeToggle({\n mode,\n onChange,\n renderedLabel = \"Rendered\",\n renderedIcon = \"image\",\n className,\n}: {\n mode: MediaViewerMarkupMode;\n onChange: (mode: MediaViewerMarkupMode) => void;\n renderedLabel?: string | undefined;\n renderedIcon?: \"image\" | \"globe\" | undefined;\n className?: string | undefined;\n}) {\n return (\n <div className={cn(\"flex items-center gap-0.5\", className)}>\n <ToggleButton\n active={mode === \"rendered\"}\n onClick={() => onChange(\"rendered\")}\n label={renderedLabel}\n icon={\n renderedIcon === \"globe\" ? (\n <GlobeIcon className=\"h-3.5 w-3.5\" />\n ) : (\n <ImageIcon className=\"h-3.5 w-3.5\" />\n )\n }\n />\n <ToggleButton\n active={mode === \"source\"}\n onClick={() => onChange(\"source\")}\n label=\"Source\"\n icon={<CodeIcon className=\"h-3.5 w-3.5\" />}\n />\n </div>\n );\n}\n\nfunction ToggleButton({\n active,\n onClick,\n icon,\n label,\n}: {\n active: boolean;\n onClick: () => void;\n icon: React.ReactNode;\n label: string;\n}) {\n return (\n <button\n type=\"button\"\n onClick={onClick}\n aria-pressed={active}\n className={cn(\n \"inline-flex items-center gap-1.5 rounded px-2 py-1 text-[11px] font-medium transition-colors\",\n active\n ? \"bg-accent text-accent-foreground\"\n : \"text-muted-foreground hover:bg-muted hover:text-foreground\",\n )}\n >\n {icon}\n <span>{label}</span>\n </button>\n );\n}\n","/**\n * src/core/use-media-load-recovery.ts — the durable-URL load-error machine.\n *\n * Ported from matrx-frontend `handler/hooks/useDurableSrc.ts`, with the\n * recovery POLICY inverted onto `MediaClient.recoverLoadError` (session\n * refresh → same-URL retry → terminal; the package may not implement a retry\n * of its own — that invariant is what killed the divergent\n * useUnifiedImageUrl/useUnifiedVideoUrl copies).\n *\n * `recoverable: false` resolutions (foreign URLs, blob: object URLs) skip the\n * client and fail straight through — a session refresh can't resurrect\n * someone else's link rot.\n *\n * Every terminal outcome emits exactly one `MediaFailureInfo` through the\n * diagnostics machinery (the 2026-08-30 outage rule):\n *\n * - element error, recovery impossible → phase \"element-load\",\n * retryOutcome \"not-attempted\"\n * - terminal verdict after a granted retry → phase \"element-load\",\n * retryOutcome \"retried\"\n * - terminal verdict on the FIRST attempt → phase \"recovery\",\n * retryOutcome \"not-attempted\"\n * (the recovery machinery itself declined — usually the session mint\n * came back unusable)\n * - `recoverLoadError` rejected → phase \"session\",\n * retryOutcome \"recovery-failed\"\n *\n * A structured `MediaRecoveryReport` verdict may additionally carry the\n * `/files/session` mint's `secret_source`; `\"ephemeral\"` emits a NON-terminal\n * warning (\"private renders will break across restarts/instances\") the moment\n * the client sees it — before the outage, not after. The bare string verdict\n * stays fully supported; the field is tolerated absent.\n */\n\nimport { useEffect, useRef, useState } from \"react\";\nimport {\n mintDurableSrc,\n type DurableSrc,\n type MediaRecoveryReport,\n type MediaRecoveryVerdict,\n type MediaRefLike,\n} from \"../types\";\nimport { useMediaClient } from \"./context\";\nimport { failureMediaIdentity, useMediaFailureCapture } from \"./diagnostics\";\n\nexport interface MediaLoadRecovery {\n /**\n * Bump this into the media element's `key` (or otherwise force a remount)\n * so a retry actually re-fires the network request for the same src.\n */\n retryKey: number;\n /** Wire to the media element's `onError`. */\n onLoadError: (event?: unknown) => void;\n /** True once recovery is exhausted (or was never possible). */\n failed: boolean;\n}\n\nfunction normalizeOutcome(\n outcome: MediaRecoveryVerdict | MediaRecoveryReport,\n): MediaRecoveryReport {\n return typeof outcome === \"string\" ? { verdict: outcome } : outcome;\n}\n\n/** The app-wide latch identity for the ephemeral-secret warning. */\nconst EPHEMERAL_SECRET_IDENTITY = \"server:files-session-secret\";\n\nexport function useMediaLoadRecovery(\n src: DurableSrc | string | null,\n options?: {\n recoverable?: boolean | undefined;\n /** Fires once recovery is exhausted, with the original element event. */\n onTerminal?: ((event?: unknown) => void) | undefined;\n /**\n * Durable identity of the media being recovered, for diagnostics —\n * failures are reported against the file id / ref key, never the URL.\n * Falls back to the query-stripped src when absent.\n */\n failureRef?: MediaRefLike | null | undefined;\n },\n): MediaLoadRecovery {\n const client = useMediaClient();\n const capture = useMediaFailureCapture();\n const recoverable = options?.recoverable !== false;\n const onTerminal = options?.onTerminal;\n const failureRef = options?.failureRef;\n const [result, setResult] = useState<{\n source: string | null;\n retryKey: number;\n failed: boolean;\n }>({ source: src, retryKey: 0, failed: false });\n const attemptRef = useRef(0);\n\n // A different URL deserves a fresh recovery allowance. The visible state is\n // keyed by source below, so this effect only resets the attempt counter.\n useEffect(() => {\n attemptRef.current = 0;\n }, [src]);\n\n const identity = () => failureMediaIdentity(failureRef ?? null, src);\n\n const onLoadError = (event?: unknown) => {\n if (!src || !recoverable) {\n setResult({ source: src, retryKey: 0, failed: true });\n if (src) {\n capture({\n phase: \"element-load\",\n mediaRef: identity(),\n terminal: true,\n retryOutcome: \"not-attempted\",\n message:\n \"media element failed to load and the source is unrecoverable \" +\n \"(foreign/object URL — a session refresh cannot fix it)\",\n });\n }\n onTerminal?.(event);\n return;\n }\n attemptRef.current += 1;\n const attempt = attemptRef.current;\n // Re-branding is sound here: only resolution srcs reach the recoverable\n // lane (blob:/foreign URLs come in with `recoverable: false`).\n client.recoverLoadError(mintDurableSrc(src), attempt).then(\n (outcome) => {\n const report = normalizeOutcome(outcome);\n if (report.secretSource === \"ephemeral\") {\n // The server signs the files-session cookie with a boot-generated\n // secret. Warn NOW — this is the exact drift that silently killed\n // every private render on 2026-08-30.\n capture({\n phase: \"session\",\n mediaRef: EPHEMERAL_SECRET_IDENTITY,\n terminal: false,\n message:\n \"server cookie secret is ephemeral — private renders will \" +\n \"break across restarts/instances (set a persistent \" +\n \"files-session secret on the server)\",\n });\n }\n if (report.verdict === \"retry\") {\n setResult((current) => ({\n source: src,\n retryKey: current.source === src ? current.retryKey + 1 : 1,\n failed: false,\n }));\n } else {\n setResult({ source: src, retryKey: 0, failed: true });\n capture({\n phase: attempt > 1 ? \"element-load\" : \"recovery\",\n mediaRef: identity(),\n terminal: true,\n retryOutcome: attempt > 1 ? \"retried\" : \"not-attempted\",\n message:\n attempt > 1\n ? \"media element failed to load after the session-refresh retry\"\n : \"media load recovery declined on the first attempt \" +\n \"(session refresh did not produce a usable session)\",\n ...(report.status !== undefined ? { status: report.status } : {}),\n });\n onTerminal?.(event);\n }\n },\n (err: unknown) => {\n setResult({ source: src, retryKey: 0, failed: true });\n capture({\n phase: \"session\",\n mediaRef: identity(),\n terminal: true,\n retryOutcome: \"recovery-failed\",\n message: `session recovery failed: ${\n err instanceof Error ? err.message : String(err ?? \"unknown error\")\n }`,\n });\n onTerminal?.(event);\n },\n );\n };\n\n return {\n retryKey: result.source === src ? result.retryKey : 0,\n onLoadError,\n failed: result.source === src ? result.failed : false,\n };\n}\n","/**\n * @ai-matrx/media — the root types: the MediaClient port and the host ports.\n *\n * The package renders Matrx durable media; it NEVER talks to a network.\n * Everything data-shaped arrives through the injected {@link MediaClient}\n * (canonically implemented by `@ai-matrx/data/files`; any structural\n * implementation works — the strangler step wires it over an app's existing\n * file handler). The five file-handling laws are enforced here at the type\n * level:\n *\n * 1. Never fetch a media URL yourself — the package contains zero network\n * primitives; bytes exist only via {@link MediaClient.getBlob}.\n * 2. Off-boundary code resolves media itself — every component takes a\n * {@link MediaRefLike} and calls `resolve()` unconditionally. There is\n * NO `src` prop on any component in this package.\n * 3. A signed URL is a handoff, never an identity — the only string that\n * reaches a media element is the branded {@link DurableSrc}, which only\n * a MediaClient implementation can mint (via {@link mintDurableSrc}).\n * 4. Public-facing media is persisted public, never signed —\n * {@link MediaClient.shareableUrl} fails closed (`null` → the action\n * renders disabled).\n * 5. One URL contract; the engine builds URLs — zero URL construction in\n * this package; `resolve()` is the only door.\n */\n\n// ---------------------------------------------------------------------------\n// Identity\n// ---------------------------------------------------------------------------\n\n/** The canonical durable media reference. `file_id` is the identity. */\nexport interface MediaRef {\n file_id?: string | null;\n url?: string | null;\n mime_type?: string | null;\n metadata?: Record<string, unknown> | null;\n}\n\n/**\n * Identity in. A raw string is a fileId or an EXTERNAL public URL — never a\n * signed URL (the client's `resolve()` classifies and screams on one).\n */\nexport type MediaRefLike = MediaRef | string;\n\ndeclare const durable: unique symbol;\n\n/**\n * A URL that has passed through `MediaClient.resolve()` — the only string\n * type any media element in this package will bind. A caller cannot pass an\n * expiring URL through the package's types without an explicit unsafe cast.\n */\nexport type DurableSrc = string & { readonly [durable]: true };\n\n/**\n * Brand a URL as durable. FOR MediaClient IMPLEMENTATIONS ONLY — the\n * implementation must classify the URL first (the ONE signed-URL classifier\n * lives with the platform's files layer; never re-implement it here or in a\n * host). Calling this on an unclassified string defeats law 3.\n */\nexport function mintDurableSrc(url: string): DurableSrc {\n return url as DurableSrc;\n}\n\n// ---------------------------------------------------------------------------\n// Resolution\n// ---------------------------------------------------------------------------\n\nexport type MediaKind = \"image\" | \"video\" | \"audio\" | \"file\";\n\nexport interface MediaResolution {\n src: DurableSrc;\n /** RN auth lane (`<Image source={{uri, headers}}>`); absent on web (cookie session). */\n headers?: Record<string, string> | undefined;\n mimeType?: string | undefined;\n kind: MediaKind;\n /**\n * How pixels must travel. `\"element\"` (default): bind `src` directly to the\n * media element. `\"blob\"`: the bytes require bearer auth the element cannot\n * attach — consumers go through {@link MediaClient.getBlob} and render the\n * returned object URL (the private-image lane).\n */\n transport?: \"element\" | \"blob\" | undefined;\n /**\n * A server-rendered thumbnail for this file, when the client knows one\n * (Matrx: `FileRecord.thumbnail_url` / asset variants). Consumed by the\n * thumbnail tier machine.\n */\n thumbnailSrc?: DurableSrc | undefined;\n /**\n * True when this is a permanent public CDN URL — lets a host-supplied\n * `ImageComponent` (e.g. a next/image adapter) take the render, and marks\n * the URL CORS-safe for element-level `crossOrigin`.\n */\n isCdn?: boolean | undefined;\n /**\n * Whether a load error can be recovered by the client's ONE retry policy\n * (session-refresh → same-URL retry). False for foreign/external URLs —\n * a session refresh can't resurrect someone else's link rot. Default true.\n */\n recoverable?: boolean | undefined;\n}\n\n/** Typed unavailable states — render-as-state, never thrown as incidents. */\nexport type MediaUnavailableReason =\n | \"access_denied\"\n | \"not_found\"\n | \"deleted\"\n | \"unknown\";\n\n// ---------------------------------------------------------------------------\n// Diagnostics — the terminal-failure capture contract (the 2026-08-30 outage\n// class: every private image failed, the honest unavailable panel rendered,\n// and NOTHING reached the host's error system because the package had no\n// diagnostics port). Per C22 the capture logic lives IN the package; a host\n// binds only a sink. Absent sink → the package console.errors the same\n// structured payload once per failure — a media failure is NEVER silent.\n// ---------------------------------------------------------------------------\n\n/** Where in the pipeline a media failure surfaced. */\nexport type MediaFailurePhase =\n /** `MediaClient.resolve()` refused the ref (threw). */\n | \"resolve\"\n /** The client's session bootstrap/mint failed (`recoverLoadError` rejected),\n * or the server reported an ephemeral cookie secret (warning). */\n | \"session\"\n /** `MediaClient.getBlob()` rejected — private-pixels bytes never arrived. */\n | \"blob\"\n /** The media element errored and recovery was exhausted or impossible. */\n | \"element-load\"\n /** The client's recovery machinery declined to retry on the first attempt. */\n | \"recovery\";\n\n/** What the ONE retry policy did before the failure went terminal. */\nexport type MediaRetryOutcome =\n /** Recovery was impossible (unrecoverable source) or was never reached. */\n | \"not-attempted\"\n /** The client granted a session-refresh retry and the retry ALSO failed. */\n | \"retried\"\n /** The recovery call itself threw/rejected. */\n | \"recovery-failed\";\n\n/**\n * The strictly-typed structural payload every terminal media failure emits.\n * `mediaRef` is DURABLE IDENTITY ONLY — a `file:<id>` / query-stripped URL\n * key, NEVER a signed URL (signatures live in query strings, which\n * {@link failureMediaIdentity} removes).\n */\nexport interface MediaFailureInfo {\n source: \"media\";\n phase: MediaFailurePhase;\n /** File id / ref key identity — never a signed URL. */\n mediaRef: string;\n /** HTTP status when known (e.g. from a structured client error). */\n status?: number | undefined;\n /** Outcome of the client's ONE retry policy, when the phase reached it. */\n retryOutcome?: MediaRetryOutcome | undefined;\n /** True for a dead render; false for a captured warning (ephemeral secret). */\n terminal: boolean;\n message: string;\n}\n\n/**\n * The host's error-capture sink. Bind `capture` to the app's error system\n * (matrx-frontend: `captureError` in lib/diagnostics/errorCaptureStore).\n * When absent, the package console.errors the same payload once per failure\n * (the loud default) — it never downgrades to silence.\n */\nexport interface MediaDiagnosticsPort {\n capture?: ((info: MediaFailureInfo) => void) | undefined;\n}\n\n/** String verdicts of the ONE retry policy. */\nexport type MediaRecoveryVerdict = \"retry\" | \"terminal\";\n\n/**\n * Structured `recoverLoadError` result — optional; the bare string verdict\n * remains fully supported. Lets the client surface what it learned during the\n * session bootstrap without a second channel:\n *\n * - `status` — HTTP status of the failed mint/probe, forwarded into the\n * terminal {@link MediaFailureInfo};\n * - `secretSource` — the `/files/session` mint response's `secret_source`\n * when the server sends one (a matrx-connect field). `\"ephemeral\"` means\n * the server signs cookies with a boot-generated secret: private renders\n * WILL break across restarts/instances, and the package captures a\n * non-terminal warning immediately instead of waiting for the outage.\n */\nexport interface MediaRecoveryReport {\n verdict: MediaRecoveryVerdict;\n status?: number | undefined;\n secretSource?: string | undefined;\n}\n\n// ---------------------------------------------------------------------------\n// Bytes / upload\n// ---------------------------------------------------------------------------\n\nexport interface MediaBlobHandle {\n /** `blob:` object URL safe for any browser API. */\n url: string;\n blob: Blob;\n /** Release the handle. Implementations backed by a shared cache may no-op. */\n release(): void;\n}\n\nexport interface MediaUploadOptions {\n onProgress?: ((loaded: number, total: number) => void) | undefined;\n fileName?: string | undefined;\n mimeType?: string | undefined;\n /** Host visibility vocabulary passes through structurally. */\n visibility?: string | undefined;\n parentFolderId?: string | null | undefined;\n metadata?: Record<string, unknown> | undefined;\n}\n\n/** Upload → durable identity. `fileId` is required at compile time and runtime. */\nexport interface MediaUploadResult {\n fileId: string;\n ref: MediaRef;\n}\n\nexport interface MediaMultiUploadResult {\n /** File ids for every successful upload. */\n uploaded: string[];\n /** Per-file failure with the real backend error message. */\n failed: Array<{ name: string; error: string }>;\n /** True when the host's pre-flight (e.g. a duplicate dialog) cancelled the batch. */\n cancelled: boolean;\n}\n\n// ---------------------------------------------------------------------------\n// THE port — one structural interface, owned by this package, implemented by\n// the data layer (canonically `@ai-matrx/data/files`).\n// ---------------------------------------------------------------------------\n\nexport interface MediaClient {\n /**\n * Synchronous durable-URL build + classification. Returns `null` when the\n * ref carries no usable identity (components render their fallback).\n * THROWS (and screams via its own diagnostics sink) on a signed/expiring\n * URL — the D108 guard lives behind this door.\n */\n resolve(ref: MediaRefLike): MediaResolution | null;\n /** Bytes for canvas/crossOrigin/private-pixel consumers. */\n getBlob(ref: MediaRefLike): Promise<MediaBlobHandle>;\n /**\n * Session bootstrap + the ONE retry policy: refresh-then-same-URL-retry,\n * second failure terminal. Called by the package's onError path, never\n * re-implemented.\n */\n recoverLoadError(\n src: DurableSrc,\n attempt: number,\n ): Promise<MediaRecoveryVerdict | MediaRecoveryReport>;\n /** Upload → durable identity. */\n upload(file: File | Blob, opts?: MediaUploadOptions): Promise<MediaUploadResult>;\n /**\n * Optional batch upload with host pre-flight (dedup dialogs etc.). When\n * absent, `useMediaUpload().uploadMany` falls back to sequential `upload`.\n */\n uploadMany?(files: File[], opts?: MediaUploadOptions): Promise<MediaMultiUploadResult>;\n /** Share affordances — fails closed (null), never emits a signed URL. */\n shareableUrl(ref: MediaRefLike): Promise<string | null>;\n /** Typed unavailable states — render-as-state, never thrown as incidents. */\n classifyError(err: unknown): MediaUnavailableReason;\n}\n\n// ---------------------------------------------------------------------------\n// Host ports — all optional, all defaulting to inert.\n// ---------------------------------------------------------------------------\n\n/**\n * Structural component slot. `(props) => unknown` keeps the root entry free\n * of React type imports; any React function component satisfies it.\n */\nexport type MediaSlotComponent<P> = (props: P) => unknown;\n\nexport interface MediaImageComponentProps {\n src: string;\n alt: string;\n width: number;\n height: number;\n className?: string | undefined;\n onError?: ((event: unknown) => void) | undefined;\n onClick?: ((event: unknown) => void) | undefined;\n onKeyDown?: ((event: unknown) => void) | undefined;\n role?: string | undefined;\n tabIndex?: number | undefined;\n}\n\nexport interface PlaybackSessionRegistration {\n isPlaying: boolean;\n source: string;\n label: string;\n trackKey?: string | undefined;\n}\n\n/**\n * The host's audio system (exclusive-playback lock, output-sink routing).\n * Both members are HOOKS — the package calls them unconditionally on every\n * render of a media element, so implementations must obey the Rules of Hooks\n * and the port object must be referentially stable.\n */\nexport interface PlaybackSessionPort {\n /**\n * Returns a ref callback for the underlying media element (routes audio\n * output / setSinkId on hosts that support it) and forwards to the caller's\n * own element ref.\n */\n useMediaElementSink(\n forward:\n | ((node: unknown) => void)\n | { current: unknown }\n | null\n | undefined,\n ): (node: unknown) => void;\n /** Joins the host's unified playback session for the element. */\n usePlaybackSession(\n registration: PlaybackSessionRegistration,\n elementRef: { current: unknown },\n ): void;\n}\n\n// ---------------------------------------------------------------------------\n// THE SHARE MANDATE (C19) — the complete headless media-actions contract.\n//\n// v0.1 ships this contract plus toolbar/lightbox shells wired to it, typed so\n// the associations/sharing package can plug in WITHOUT a media release: it\n// implements MediaActionsPort (handlers and/or the SharePopover body) and the\n// host injects it through MediaHostPorts. Nothing here may change shape in a\n// breaking way for that wave.\n// ---------------------------------------------------------------------------\n\nexport type MediaActionKind = \"share\" | \"download\" | \"copy\" | \"open\";\n\nexport interface MediaActionContext {\n ref: MediaRefLike;\n resolution: MediaResolution | null;\n fileName?: string | undefined;\n alt?: string | undefined;\n}\n\nexport interface MediaSharePopoverProps {\n context: MediaActionContext;\n onClose: () => void;\n}\n\nexport type MediaActionHandler = (ctx: MediaActionContext) => Promise<void>;\n\nexport interface MediaActionsPort {\n /**\n * Quick-share handler (copy a share link, open the native share sheet…).\n * Implementations obtain URLs ONLY via `MediaClient.shareableUrl` /\n * durable identities — never a signed URL (law 4).\n */\n share?: MediaActionHandler | undefined;\n download?: MediaActionHandler | undefined;\n copy?: MediaActionHandler | undefined;\n open?: MediaActionHandler | undefined;\n /**\n * Rich share UI body — the slot the associations package fills. When\n * present, the shells open it instead of (or on top of) the `share`\n * handler. Receives {@link MediaSharePopoverProps}.\n */\n SharePopover?: MediaSlotComponent<MediaSharePopoverProps> | undefined;\n}\n\nexport interface MediaHostPorts {\n playbackSession?: PlaybackSessionPort | undefined;\n actions?: MediaActionsPort | undefined;\n /** Web host may pass a next/image adapter; default is a plain `<img>`. */\n ImageComponent?: MediaSlotComponent<MediaImageComponentProps> | undefined;\n /**\n * Error-capture sink for terminal media failures (and the ephemeral-secret\n * warning). Bind to the host's error system; absent → loud console.error\n * default. See {@link MediaDiagnosticsPort}.\n */\n diagnostics?: MediaDiagnosticsPort | undefined;\n}\n","/**\n * src/viewers/transparency-grid.ts — the alpha-channel checkerboard.\n *\n * Ships as inline style rather than a utility class: the matrx-frontend\n * originals used two different mechanisms for the same thing (an inline\n * gradient stack in ImagePreview, a `bg-checkerboard` utility in SvgPreview),\n * and a utility class is exactly the kind of host-owned dependency C26 bans a\n * package component from assuming. Sized in CSS pixels so the pattern reads\n * the same at any zoom.\n */\n\nexport const TRANSPARENCY_GRID_STYLE: {\n backgroundImage: string;\n backgroundSize: string;\n backgroundPosition: string;\n} = {\n backgroundImage:\n \"linear-gradient(45deg, rgb(0 0 0 / 0.08) 25%, transparent 25%), \" +\n \"linear-gradient(-45deg, rgb(0 0 0 / 0.08) 25%, transparent 25%), \" +\n \"linear-gradient(45deg, transparent 75%, rgb(0 0 0 / 0.08) 75%), \" +\n \"linear-gradient(-45deg, transparent 75%, rgb(0 0 0 / 0.08) 75%)\",\n backgroundSize: \"16px 16px\",\n backgroundPosition: \"0 0, 0 8px, 8px -8px, -8px 0\",\n};\n","/**\n * src/viewers/svg-viewer.tsx — SVG viewer (rendered + XML source).\n *\n * Absorbed from matrx-frontend\n * `features/files/components/core/FilePreview/previewers/SvgPreview.tsx`.\n *\n * SVG is the one image format that is also text, so it gets two views. The\n * rendered view binds the durable URL straight into an `<img>` (no CORS\n * preflight, no byte fetch); the source view pulls bytes only when the user\n * asks — so the default path costs exactly what a plain image costs.\n *\n * Seam inversions from the original: `recognizeOurFileUrl` (the host's\n * recoverability classifier) becomes `MediaResolution.recoverable`, which the\n * MediaClient already decides; `useFileBlob` becomes `useViewerText`; the\n * transparency grid ships as package CSS-in-style rather than the host's\n * `bg-checkerboard` utility (which no fresh app would have — C26).\n */\n\n\"use client\";\n\nimport { cn } from \"../react/cn\";\nimport { useMediaLoadRecovery } from \"../core/use-media-load-recovery\";\nimport { ViewerError, ViewerSkeleton } from \"./chrome\";\nimport { MarkupModeToggle, useMarkupMode } from \"./markup-chrome\";\nimport { TRANSPARENCY_GRID_STYLE } from \"./transparency-grid\";\nimport type { MediaViewerProps } from \"./types\";\nimport { useViewerDisplayUrl, useViewerText } from \"./use-viewer-bytes\";\n\nexport function SvgViewer(props: MediaViewerProps) {\n const { className, markupControls } = props;\n const { mode, setMode, controlled } = useMarkupMode(markupControls);\n\n return (\n <div\n className={cn(\n \"relative flex h-full min-h-0 w-full flex-col bg-background\",\n className,\n )}\n >\n {controlled ? null : (\n <MarkupModeToggle\n mode={mode}\n onChange={setMode}\n className=\"absolute top-3 right-3 z-10 rounded-md border border-border bg-background/95 p-0.5 shadow-sm backdrop-blur-sm\"\n />\n )}\n {mode === \"rendered\" ? (\n <SvgRenderedView {...props} />\n ) : (\n <SvgSourceView {...props} />\n )}\n </div>\n );\n}\n\nfunction SvgRenderedView({ source, fileName }: MediaViewerProps) {\n const { url, recoverable, unavailable } = useViewerDisplayUrl(source);\n // Hook order first: recovery is called unconditionally, before any return.\n const { retryKey, onLoadError, failed } = useMediaLoadRecovery(url, {\n recoverable,\n ...(source.kind === \"ref\" ? { failureRef: source.ref } : {}),\n });\n\n if (unavailable) {\n return (\n <ViewerError\n title=\"This SVG isn't available\"\n hint=\"You may not have access to it, or it may have been deleted.\"\n />\n );\n }\n if (!url) return <ViewerSkeleton className=\"flex-1\" />;\n if (failed) {\n return (\n <ViewerError\n title=\"SVG could not be rendered\"\n hint=\"Switch to the Source view to inspect the markup.\"\n />\n );\n }\n\n return (\n <div\n className=\"flex flex-1 items-center justify-center overflow-auto p-4\"\n style={TRANSPARENCY_GRID_STYLE}\n >\n {/* eslint-disable-next-line @next/next/no-img-element */}\n <img\n key={retryKey}\n src={url}\n alt={fileName}\n className=\"max-h-full max-w-full object-contain drop-shadow-sm\"\n onError={onLoadError}\n />\n </div>\n );\n}\n\nfunction SvgSourceView({ source, maxBytes = 1024 * 1024 }: MediaViewerProps) {\n const { text, error, loading } = useViewerText(source, maxBytes);\n if (error) return <ViewerError title=\"Could not load source\" message={error} />;\n if (loading || text === null) return <ViewerSkeleton className=\"flex-1\" />;\n return (\n <pre className=\"m-0 flex-1 overflow-auto bg-muted/20 px-4 py-3 font-mono text-xs leading-relaxed break-words whitespace-pre-wrap text-foreground\">\n {text}\n </pre>\n );\n}\n","/**\n * src/viewers/text-viewer.tsx — plain-text viewer.\n *\n * Absorbed from matrx-frontend\n * `features/files/components/core/FilePreview/previewers/TextPreview.tsx`\n * (behavior ported verbatim; the byte/text/cap machinery moved to\n * `useViewerText`, the error card and copy button to `chrome.tsx`).\n */\n\n\"use client\";\n\nimport { cn } from \"../react/cn\";\nimport { ViewerCopyButton, ViewerError, ViewerSkeleton, ViewerToolbar, truncationNote } from \"./chrome\";\nimport type { MediaViewerProps } from \"./types\";\nimport { useViewerText } from \"./use-viewer-bytes\";\n\nexport function TextViewer({\n source,\n className,\n maxBytes = 1024 * 1024,\n}: MediaViewerProps) {\n const { text, error, loading, truncated } = useViewerText(source, maxBytes);\n\n if (error) return <ViewerError message={error} className={className} />;\n if (loading || text === null) {\n return <ViewerSkeleton tone=\"plain\" className={className} />;\n }\n\n return (\n <div\n className={cn(\"flex h-full w-full flex-col overflow-hidden\", className)}\n >\n <ViewerToolbar>\n <span className=\"text-muted-foreground\">\n {truncated\n ? `Preview ${truncationNote(maxBytes)}.`\n : `${text.length.toLocaleString()} characters`}\n </span>\n <ViewerCopyButton text={text} />\n </ViewerToolbar>\n <pre className=\"flex-1 overflow-auto bg-background p-3 font-mono text-xs leading-5 break-words whitespace-pre-wrap\">\n {text}\n </pre>\n </div>\n );\n}\n","/**\n * src/viewers/unavailable-viewer.tsx — THE ANNOUNCING DEFAULT (C23 + law 4,\n * \"nothing fails silently\").\n *\n * This renders when a kind needs a heavy engine the host has not registered\n * (PDF.js, a Markdown/KaTeX stack, SheetJS, an Office extractor). It is the\n * one place in the package where a default IS a shortfall, so unlike the\n * code viewer's un-highlighted default it says so — plainly, with the remedy\n * — and it still gives the user every action that remains possible: the\n * generic card's download / view-as-text escape hatches.\n *\n * The forbidden alternatives are a blank pane, a spinner that never resolves,\n * and a disabled-looking control. A screen is absent or honest.\n */\n\n\"use client\";\n\nimport { cn } from \"../react/cn\";\nimport { GenericViewer } from \"./generic-viewer\";\nimport type { MediaViewerKind, MediaViewerProps } from \"./types\";\n\n/** What a host must register to make this kind render properly. */\nconst ENGINE_FOR_KIND: Partial<Record<MediaViewerKind, string>> = {\n pdf: \"a PDF engine (e.g. PDF.js / react-pdf)\",\n markdown: \"a Markdown renderer\",\n data: \"a spreadsheet/CSV parser\",\n spreadsheet: \"a spreadsheet/CSV parser\",\n office: \"an Office document extractor\",\n image: \"an image viewer\",\n video: \"a video player\",\n audio: \"an audio player\",\n};\n\nexport function MediaViewerUnavailable({\n kind,\n ...props\n}: MediaViewerProps & { kind: MediaViewerKind }) {\n const engine = ENGINE_FOR_KIND[kind] ?? `a \"${kind}\" viewer`;\n const generic = props.generic;\n return (\n <div className={cn(\"flex h-full w-full flex-col\", props.className)}>\n <div className=\"shrink-0 border-b border-amber-500/30 bg-amber-500/10 px-3 py-2 text-center text-xs text-amber-700 dark:text-amber-300\">\n No {kind} viewer is registered in this app, so this file can't be\n displayed here. An app developer registers {engine} with{\" \"}\n <code className=\"font-mono\">\n registerMediaViewer("{kind}", …)\n </code>\n .\n </div>\n <div className=\"min-h-0 flex-1\">\n <GenericViewer\n {...props}\n className={undefined}\n generic={{\n ...generic,\n message:\n generic?.message ??\n \"You can still download this file and open it in another application.\",\n }}\n />\n </div>\n </div>\n );\n}\n","/**\n * src/viewers/preview-kind.ts — filename/MIME → viewer kind.\n *\n * The DEFAULT resolution, derived from the package's own file-kind registry\n * (`getFileKindDetails`) so a fresh app gets correct dispatch with zero setup.\n * A host with a richer registry of its own — matrx-frontend's `FILE_TYPES`\n * carries preview/thumbnail/size-cap columns this package deliberately does\n * not absorb (C8) — passes `previewKind` explicitly and this is never called.\n */\n\nimport { getFileKindDetails } from \"../core/file-kind\";\nimport type { MediaViewerKind } from \"./types\";\n\nconst EXTENSION_KIND: Record<string, MediaViewerKind> = {\n svg: \"svg\",\n pdf: \"pdf\",\n md: \"markdown\",\n markdown: \"markdown\",\n mdx: \"markdown\",\n html: \"html\",\n htm: \"html\",\n csv: \"data\",\n tsv: \"data\",\n xlsx: \"spreadsheet\",\n xls: \"spreadsheet\",\n doc: \"office\",\n docx: \"office\",\n ppt: \"office\",\n pptx: \"office\",\n txt: \"text\",\n log: \"text\",\n text: \"text\",\n};\n\nfunction extensionOf(fileName: string): string {\n const base = fileName.split(/[\\\\/]/).pop() ?? fileName;\n const dot = base.lastIndexOf(\".\");\n if (dot <= 0) return \"\";\n return base.slice(dot + 1).toLowerCase();\n}\n\nexport function getPreviewKind(\n fileName: string,\n mimeType?: string | null,\n): MediaViewerKind {\n const explicit = EXTENSION_KIND[extensionOf(fileName)];\n if (explicit) return explicit;\n\n const details = getFileKindDetails(fileName, mimeType ?? undefined);\n switch (details.category) {\n case \"IMAGE\":\n return details.icon === \"pen-tool\" ? \"svg\" : \"image\";\n case \"VIDEO\":\n return \"video\";\n case \"AUDIO\":\n return \"audio\";\n case \"CODE\":\n return \"code\";\n case \"DATA\":\n return \"code\";\n case \"NOTEBOOK\":\n return \"code\";\n case \"SUBTITLES\":\n return \"text\";\n case \"DOCUMENT\":\n // The DOCUMENT bucket holds PDFs, markdown and plain text; the explicit\n // extension table above already caught the first two, so anything left\n // is text-shaped.\n return \"text\";\n default:\n return \"generic\";\n }\n}\n"],"mappings":";;;;;;;;;;;;;;;;;;;;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;;;AC0BA,IAAAA,iBAAkD;;;ACClD,IAAM,cAAc,uBAAO,IAAI,gCAAgC;AAC/D,IAAM,mBAAmB,uBAAO,IAAI,iCAAiC;AAOrE,SAAS,QAAuB;AAC9B,SAAO;AACT;AAEA,SAAS,YAAwD;AAC/D,QAAM,OAAO,MAAM;AACnB,QAAM,WAAW,KAAK,WAAW;AACjC,MAAI,SAAU,QAAO;AACrB,QAAM,UAAU,oBAAI,IAA2C;AAC/D,OAAK,WAAW,IAAI;AACpB,SAAO;AACT;AASO,SAAS,oBACd,MACA,QACY;AACZ,QAAM,MAAM,UAAU;AACtB,QAAM,WAAW,IAAI,IAAI,IAAI;AAC7B,MAAI,IAAI,MAAM,MAAM;AACpB,SAAO,MAAM;AACX,QAAI,SAAU,KAAI,IAAI,MAAM,QAAQ;AAAA,QAC/B,KAAI,OAAO,IAAI;AAAA,EACtB;AACF;AAGO,SAAS,eACd,MAC6B;AAC7B,SAAO,UAAU,EAAE,IAAI,IAAI,KAAK;AAClC;AAGO,SAAS,6BAAgD;AAC9D,SAAO,CAAC,GAAG,UAAU,EAAE,KAAK,CAAC;AAC/B;AAOO,SAAS,6BACd,aACY;AACZ,QAAM,OAAO,MAAM;AACnB,QAAM,WAAW,KAAK,gBAAgB,KAAK;AAC3C,OAAK,gBAAgB,IAAI;AACzB,SAAO,MAAM;AACX,SAAK,gBAAgB,IAAI;AAAA,EAC3B;AACF;AAEO,SAAS,0BAAuD;AACrE,SAAO,MAAM,EAAE,gBAAgB,KAAK;AACtC;;;AC/EA,IAAAC,gBAAqE;;;ACXrE,4BAAwB;AAIjB,SAAS,MAAM,QAA8B;AAClD,aAAO,+BAAQ,OAAO,OAAO,OAAO,EAAE,KAAK,GAAG,CAAC;AACjD;;;ACJA,mBAAsC;;;ACyBlC;AAnBJ,SAAS,SAAS,OAAuC;AACvD,SAAO;AAAA,IACL,OAAO;AAAA,IACP,SAAS;AAAA,IACT,OAAO;AAAA,IACP,QAAQ;AAAA,IACR,MAAM;AAAA,IACN,QAAQ;AAAA,IACR,aAAa;AAAA,IACb,eAAe;AAAA,IACf,gBAAgB;AAAA,IAChB,eAAe;AAAA,IACf,GAAG;AAAA,EACL;AACF;AAGO,SAAS,YAAY,OAAuB;AACjD,SACE,6CAAC,SAAK,GAAG,SAAS,KAAK,GACrB;AAAA,gDAAC,UAAK,OAAM,MAAK,QAAO,KAAI,GAAE,KAAI,GAAE,KAAI,IAAG,KAAI;AAAA,IAC/C,4CAAC,UAAK,GAAE,4CAA2C;AAAA,IACnD,4CAAC,UAAK,GAAE,YAAW;AAAA,KACrB;AAEJ;AAGO,SAAS,WAAW,OAAuB;AAChD,SACE,6CAAC,SAAK,GAAG,SAAS,KAAK,GACrB;AAAA,gDAAC,UAAK,GAAE,wEAAuE;AAAA,IAC/E,4CAAC,UAAK,GAAE,4EAA2E;AAAA,KACrF;AAEJ;AAGO,SAAS,UAAU,OAAuB;AAC/C,SACE,4CAAC,SAAK,GAAG,SAAS,KAAK,GACrB,sDAAC,UAAK,GAAE,mBAAkB,GAC5B;AAEJ;AAGO,SAAS,SAAS,OAAuB;AAC9C,SACE,6CAAC,SAAK,GAAG,SAAS,KAAK,GACrB;AAAA,gDAAC,UAAK,GAAE,kBAAiB;AAAA,IACzB,4CAAC,UAAK,GAAE,gBAAe;AAAA,KACzB;AAEJ;AAGO,SAAS,SAAS,OAAuB;AAC9C,SACE,6CAAC,SAAK,GAAG,SAAS,KAAK,GACrB;AAAA,gDAAC,UAAK,OAAM,MAAK,QAAO,MAAK,GAAE,KAAI,GAAE,KAAI,IAAG,KAAI,IAAG,KAAI;AAAA,IACvD,4CAAC,UAAK,GAAE,2DAA0D;AAAA,KACpE;AAEJ;AAGO,SAAS,aAAa,OAAuB;AAClD,SACE,6CAAC,SAAK,GAAG,SAAS,KAAK,GACrB;AAAA,gDAAC,aAAQ,IAAG,MAAK,IAAG,KAAI,IAAG,KAAI,IAAG,KAAI;AAAA,IACtC,4CAAC,UAAK,GAAE,6BAA4B;AAAA,IACpC,4CAAC,UAAK,GAAE,yBAAwB;AAAA,KAClC;AAEJ;AAGO,SAAS,aAAa,OAAuB;AAClD,SACE,6CAAC,SAAK,GAAG,SAAS,KAAK,GACrB;AAAA,gDAAC,UAAK,GAAE,YAAW;AAAA,IACnB,4CAAC,UAAK,GAAE,6CAA4C;AAAA,IACpD,4CAAC,UAAK,GAAE,iBAAgB;AAAA,KAC1B;AAEJ;AAGO,SAAS,iBAAiB,OAAuB;AACtD,SACE,6CAAC,SAAK,GAAG,SAAS,KAAK,GACrB;AAAA,gDAAC,UAAK,GAAE,aAAY;AAAA,IACpB,4CAAC,UAAK,GAAE,eAAc;AAAA,IACtB,4CAAC,UAAK,GAAE,4DAA2D;AAAA,KACrE;AAEJ;AAGO,SAAS,SAAS,OAAuB;AAC9C,SACE,6CAAC,SAAK,GAAG,SAAS,KAAK,GACrB;AAAA,gDAAC,UAAK,GAAE,kHAAiH;AAAA,IACzH,4CAAC,UAAK,GAAE,2BAA0B;AAAA,KACpC;AAEJ;AAGO,SAAS,cAAc,OAAuB;AACnD,SACE,6CAAC,SAAK,GAAG,SAAS,KAAK,GACrB;AAAA,gDAAC,UAAK,GAAE,4GAA2G;AAAA,IACnH,4CAAC,UAAK,GAAE,2BAA0B;AAAA,IAClC,4CAAC,UAAK,GAAE,0FAAyF;AAAA,KACnG;AAEJ;AAGO,SAAS,aAAa,OAAuB;AAClD,SACE,6CAAC,SAAK,GAAG,SAAS,KAAK,GACrB;AAAA,gDAAC,UAAK,GAAE,kHAAiH;AAAA,IACzH,4CAAC,UAAK,GAAE,2BAA0B;AAAA,IAClC,4CAAC,UAAK,GAAE,uBAAsB;AAAA,IAC9B,4CAAC,UAAK,GAAE,wBAAuB;AAAA,KACjC;AAEJ;AAGO,SAAS,aAAa,OAAuB;AAClD,SACE,6CAAC,SAAK,GAAG,SAAS,KAAK,GACrB;AAAA,gDAAC,UAAK,GAAE,kHAAiH;AAAA,IACzH,4CAAC,UAAK,GAAE,2BAA0B;AAAA,IAClC,4CAAC,UAAK,GAAE,sEAAqE;AAAA,IAC7E,4CAAC,UAAK,GAAE,wEAAuE;AAAA,KACjF;AAEJ;AAGO,SAAS,oBAAoB,OAAuB;AACzD,SACE,6CAAC,SAAK,GAAG,SAAS,KAAK,GACrB;AAAA,gDAAC,UAAK,GAAE,kHAAiH;AAAA,IACzH,4CAAC,UAAK,GAAE,2BAA0B;AAAA,IAClC,4CAAC,UAAK,GAAE,WAAU;AAAA,IAClB,4CAAC,UAAK,GAAE,YAAW;AAAA,IACnB,4CAAC,UAAK,GAAE,WAAU;AAAA,IAClB,4CAAC,UAAK,GAAE,YAAW;AAAA,KACrB;AAEJ;AAGO,SAAS,aAAa,OAAuB;AAClD,SACE,6CAAC,SAAK,GAAG,SAAS,KAAK,GACrB;AAAA,gDAAC,UAAK,GAAE,kHAAiH;AAAA,IACzH,4CAAC,UAAK,GAAE,2BAA0B;AAAA,IAClC,4CAAC,UAAK,GAAE,WAAU;AAAA,IAClB,4CAAC,UAAK,GAAE,YAAW;AAAA,IACnB,4CAAC,UAAK,GAAE,YAAW;AAAA,KACrB;AAEJ;AAGO,SAAS,aAAa,OAAuB;AAClD,SACE,6CAAC,SAAK,GAAG,SAAS,KAAK,GACrB;AAAA,gDAAC,UAAK,GAAE,kHAAiH;AAAA,IACzH,4CAAC,UAAK,GAAE,2BAA0B;AAAA,IAClC,4CAAC,UAAK,GAAE,YAAW;AAAA,IACnB,4CAAC,UAAK,GAAE,YAAW;AAAA,IACnB,4CAAC,UAAK,GAAE,mDAAkD;AAAA,KAC5D;AAEJ;AAGO,SAAS,cAAc,OAAuB;AACnD,SACE,6CAAC,SAAK,GAAG,SAAS,KAAK,GACrB;AAAA,gDAAC,UAAK,GAAE,kHAAiH;AAAA,IACzH,4CAAC,UAAK,GAAE,2BAA0B;AAAA,IAClC,4CAAC,UAAK,GAAE,4GAA2G;AAAA,KACrH;AAEJ;AAGO,SAAS,WAAW,OAAuB;AAChD,SACE,4CAAC,SAAK,GAAG,SAAS,KAAK,GACrB,sDAAC,UAAK,GAAE,0HAAyH,GACnI;AAEJ;AAGO,SAAS,eAAe,OAAuB;AACpD,SACE,4CAAC,SAAK,GAAG,SAAS,KAAK,GACrB,sDAAC,UAAK,GAAE,qLAAoL,GAC9L;AAEJ;AAGO,SAAS,UAAU,OAAuB;AAC/C,SACE,6CAAC,SAAK,GAAG,SAAS,KAAK,GACrB;AAAA,gDAAC,UAAK,OAAM,MAAK,QAAO,MAAK,GAAE,KAAI,GAAE,KAAI,IAAG,KAAI,IAAG,KAAI;AAAA,IACvD,4CAAC,YAAO,IAAG,KAAI,IAAG,KAAI,GAAE,KAAI;AAAA,IAC5B,4CAAC,UAAK,GAAE,6CAA4C;AAAA,KACtD;AAEJ;AAiBO,SAAS,UAAU,OAAuB;AAC/C,SACE,6CAAC,SAAK,GAAG,SAAS,KAAK,GACrB;AAAA,gDAAC,UAAK,GAAE,mBAAkB;AAAA,IAC1B,4CAAC,YAAO,IAAG,KAAI,IAAG,MAAK,GAAE,KAAI;AAAA,IAC7B,4CAAC,YAAO,IAAG,MAAK,IAAG,MAAK,GAAE,KAAI;AAAA,KAChC;AAEJ;AAGO,SAAS,eAAe,OAAuB;AACpD,SACE,6CAAC,SAAK,GAAG,SAAS,KAAK,GACrB;AAAA,gDAAC,UAAK,GAAE,4HAA2H;AAAA,IACnI,4CAAC,UAAK,GAAE,aAAY;AAAA,IACpB,4CAAC,cAAS,QAAO,wBAAuB;AAAA,IACxC,4CAAC,UAAK,GAAE,oBAAmB;AAAA,KAC7B;AAEJ;AAGO,SAAS,YAAY,OAAuB;AACjD,SACE,6CAAC,SAAK,GAAG,SAAS,KAAK,GACrB;AAAA,gDAAC,UAAK,GAAE,gIAA+H;AAAA,IACvI,4CAAC,UAAK,GAAE,iHAAgH;AAAA,IACxH,4CAAC,UAAK,GAAE,wBAAuB;AAAA,IAC/B,4CAAC,YAAO,IAAG,MAAK,IAAG,MAAK,GAAE,KAAI;AAAA,KAChC;AAEJ;AAgBO,SAAS,cAAc,OAAuB;AACnD,SACE,6CAAC,SAAK,GAAG,SAAS,KAAK,GACrB;AAAA,gDAAC,UAAK,OAAM,MAAK,QAAO,MAAK,GAAE,KAAI,GAAE,KAAI,IAAG,KAAI,IAAG,KAAI;AAAA,IACvD,4CAAC,UAAK,GAAE,kCAAiC;AAAA,KAC3C;AAEJ;AAcO,SAAS,UAAU,OAAuB;AAC/C,SACE,6CAAC,SAAK,GAAG,SAAS,KAAK,GACrB;AAAA,gDAAC,UAAK,GAAE,6EAA4E;AAAA,IACpF,4CAAC,UAAK,GAAE,KAAI,GAAE,KAAI,OAAM,MAAK,QAAO,MAAK,IAAG,KAAI;AAAA,KAClD;AAEJ;AAyBO,SAAS,MAAM,OAAuB;AAC3C,SACE,6CAAC,SAAK,GAAG,SAAS,KAAK,GACrB;AAAA,gDAAC,UAAK,GAAE,cAAa;AAAA,IACrB,4CAAC,UAAK,GAAE,cAAa;AAAA,KACvB;AAEJ;AAGO,SAAS,gBAAgB,OAAuB;AACrD,SACE,6CAAC,SAAK,GAAG,SAAS,KAAK,GACrB;AAAA,gDAAC,YAAO,IAAG,MAAK,IAAG,MAAK,GAAE,MAAK;AAAA,IAC/B,4CAAC,UAAK,IAAG,MAAK,IAAG,MAAK,IAAG,KAAI,IAAG,MAAK;AAAA,IACrC,4CAAC,UAAK,IAAG,MAAK,IAAG,SAAQ,IAAG,MAAK,IAAG,MAAK;AAAA,KAC3C;AAEJ;AAGO,SAAS,iBAAiB,OAAuB;AACtD,SACE,6CAAC,SAAK,GAAG,SAAS,KAAK,GACrB;AAAA,gDAAC,UAAK,GAAE,mCAAkC;AAAA,IAC1C,4CAAC,UAAK,GAAE,kBAAiB;AAAA,KAC3B;AAEJ;AAGO,SAAS,UAAU,OAAuB;AAC/C,SACE,6CAAC,SAAK,GAAG,SAAS,KAAK,GACrB;AAAA,gDAAC,YAAO,IAAG,MAAK,IAAG,MAAK,GAAE,MAAK;AAAA,IAC/B,4CAAC,UAAK,GAAE,mDAAkD;AAAA,IAC1D,4CAAC,UAAK,GAAE,YAAW;AAAA,KACrB;AAEJ;AA0BO,SAAS,YAAY,OAAuB;AACjD,SACE,4CAAC,SAAK,GAAG,SAAS,KAAK,GACrB,sDAAC,UAAK,GAAE,+BAA8B,GACxC;AAEJ;;;AD7YM,IAAAC,sBAAA;AAfC,SAAS,eAAe;AAAA,EAC7B;AAAA,EACA,OAAO;AACT,GAGG;AACD,SACE;AAAA,IAAC;AAAA;AAAA,MACC,WAAW;AAAA,QACT;AAAA,QACA,SAAS,WAAW;AAAA,QACpB;AAAA,MACF;AAAA,MAEA,uDAAC,SAAI,WAAU,2CAA0C;AAAA;AAAA,EAC3D;AAEJ;AAQO,SAAS,YAAY;AAAA,EAC1B,QAAQ;AAAA,EACR;AAAA,EACA;AAAA,EACA;AACF,GAKG;AACD,SACE;AAAA,IAAC;AAAA;AAAA,MACC,WAAW;AAAA,QACT;AAAA,QACA;AAAA,MACF;AAAA,MACA,MAAK;AAAA,MAEL;AAAA,qDAAC,SAAI,WAAU,6EACb,uDAAC,mBAAgB,WAAU,4BAA2B,GACxD;AAAA,QACA,8CAAC,SAAI,WAAU,aACb;AAAA,uDAAC,QAAG,WAAU,yBAAyB,iBAAM;AAAA,UAC5C,UACC,6CAAC,OAAE,WAAU,sDACV,mBACH,IACE;AAAA,UACH,OACC,6CAAC,OAAE,WAAU,iDAAiD,gBAAK,IACjE;AAAA,WACN;AAAA;AAAA;AAAA,EACF;AAEJ;AAOO,SAAS,iBAAiB;AAAA,EAC/B;AAAA,EACA;AACF,GAGG;AACD,QAAM,CAAC,QAAQ,SAAS,QAAI,uBAAS,KAAK;AAC1C,QAAM,aAAS,0BAAY,MAAM;AAC/B,QAAI,QAAQ,KAAM;AAClB,SAAK,UAAU,UACZ,UAAU,IAAI,EACd,KAAK,MAAM;AACV,gBAAU,IAAI;AACd,iBAAW,MAAM,UAAU,KAAK,GAAG,IAAI;AAAA,IACzC,CAAC,EACA,MAAM,MAAM;AAAA,IAEb,CAAC;AAAA,EACL,GAAG,CAAC,IAAI,CAAC;AAET,SACE;AAAA,IAAC;AAAA;AAAA,MACC,MAAK;AAAA,MACL,SAAS;AAAA,MACT,cAAW;AAAA,MACX,OAAM;AAAA,MACN,WAAW;AAAA,QACT;AAAA,QACA,UAAU;AAAA,QACV;AAAA,MACF;AAAA,MAEC;AAAA,iBACC,6CAAC,aAAU,WAAU,eAAc,IAEnC,6CAAC,YAAS,WAAU,eAAc;AAAA,QAEnC,SAAS,WAAW;AAAA;AAAA;AAAA,EACvB;AAEJ;AAGO,SAAS,cAAc;AAAA,EAC5B;AAAA,EACA;AACF,GAGG;AACD,SACE;AAAA,IAAC;AAAA;AAAA,MACC,WAAW;AAAA,QACT;AAAA,QACA;AAAA,MACF;AAAA,MAEC;AAAA;AAAA,EACH;AAEJ;AAGO,SAAS,eAAe,UAA0B;AACvD,QAAM,KAAK,WAAW,OAAO;AAC7B,SAAO,0BAA0B,MAAM,IAAI,GAAG,GAAG,QAAQ,CAAC,CAAC,OAAO,IAAI,WAAW,MAAM,QAAQ,CAAC,CAAC,IAAI;AACvG;;;AE3IA,IAAAC,gBAAoC;;;ACApC,IAAAC,gBAAoC;;;ACApC,IAAAC,gBAMO;AAGP,IAAM,cAAc,uBAAO,IAAI,+BAA+B;AAC9D,IAAM,aAAa,uBAAO,IAAI,mCAAmC;AAOjE,SAAS,gBAA6C;AACpD,QAAM,OAAO;AACb,OAAK,WAAW,UAAM,6BAAkC,IAAI;AAC5D,SAAO,KAAK,WAAW;AACzB;AAEA,IAAM,cAA8B,CAAC;AAErC,SAAS,eAAwC;AAC/C,QAAM,OAAO;AACb,OAAK,UAAU,UAAM,6BAA8B,WAAW;AAC9D,SAAO,KAAK,UAAU;AACxB;AAwBO,SAAS,iBAA8B;AAC5C,QAAM,aAAS,0BAAW,cAAc,CAAC;AACzC,MAAI,CAAC,QAAQ;AACX,UAAM,IAAI;AAAA,MACR;AAAA,IAEF;AAAA,EACF;AACA,SAAO;AACT;AAGO,SAAS,oBAAoC;AAClD,aAAO,0BAAW,aAAa,CAAC;AAClC;;;ACpDA,IAAAC,gBAAoC;AAIpC,IAAM,aAAa,uBAAO,IAAI,8BAA8B;AAM5D,SAAS,QAAqB;AAC5B,QAAM,OAAO;AACb,OAAK,UAAU,MAAM,oBAAI,IAAY;AACrC,SAAO,KAAK,UAAU;AACxB;AAgBO,SAAS,qBACd,KACA,KACQ;AACR,MAAI,OAAO,OAAO,QAAQ,YAAY,IAAI,QAAS,QAAO,QAAQ,IAAI,OAAO;AAC7E,QAAM,MACJ,OAAO,QAAQ,WACX,OACC,OAAO,OAAO,QAAQ,WAAY,IAAI,OAAO,OAAQ,SAAS,OAAO;AAC5E,MAAI,CAAC,IAAK,QAAO;AACjB,MAAI,IAAI,WAAW,OAAO,EAAG,QAAO;AACpC,MAAI;AACF,UAAM,IAAI,IAAI,IAAI,GAAG;AACrB,WAAO,OAAO,EAAE,MAAM,GAAG,EAAE,QAAQ;AAAA,EACrC,QAAQ;AAEN,UAAM,QAAQ,IAAI,MAAM,QAAQ,CAAC,EAAE,CAAC,KAAK;AACzC,WAAO,OAAO,KAAK;AAAA,EACrB;AACF;AAQO,SAAS,iBACd,SACA,MACM;AACN,QAAM,MAAM,GAAG,KAAK,WAAW,aAAa,SAAS,IAAI,KAAK,QAAQ;AACtE,QAAM,OAAO,MAAM;AACnB,MAAI,KAAK,IAAI,GAAG,EAAG;AACnB,OAAK,IAAI,GAAG;AACZ,MAAI,SAAS;AACX,QAAI;AACF,cAAQ,IAAI;AACZ;AAAA,IACF,QAAQ;AAAA,IAER;AAAA,EACF;AACA,UAAQ;AAAA,IACN;AAAA,IAEA;AAAA,EACF;AACF;AAOO,SAAS,yBAEN;AACR,QAAM,QAAQ,kBAAkB;AAChC,QAAM,UAAU,MAAM,aAAa;AAInC,QAAM,iBAAa,sBAAO,OAAO;AACjC,aAAW,UAAU;AACrB,aAAO,2BAAY,CAAC,SAA2C;AAC7D,qBAAiB,WAAW,SAAS,EAAE,QAAQ,SAAS,GAAG,KAAK,CAAC;AAAA,EACnE,GAAG,CAAC,CAAC;AACP;;;AClHO,SAAS,aAAa,KAA8C;AACzE,MAAI,CAAC,IAAK,QAAO;AACjB,MAAI,OAAO,QAAQ,SAAU,QAAO,KAAK,GAAG;AAC5C,MAAI,IAAI,QAAS,QAAO,MAAM,IAAI,OAAO,IAAI,IAAI,aAAa,EAAE;AAChE,MAAI,IAAI,IAAK,QAAO,OAAO,IAAI,GAAG,IAAI,IAAI,aAAa,EAAE;AACzD,SAAO;AACT;;;AHEA,SAAS,SAAS,KAAkC;AAClD,MAAI,OAAO,OAAO,QAAQ,UAAU;AAClC,UAAM,YACH,IAA6B,UAC7B,IAAiC;AACpC,QAAI,OAAO,cAAc,SAAU,QAAO;AAAA,EAC5C;AACA,SAAO;AACT;AAYO,SAAS,aACd,KACgB;AAChB,QAAM,SAAS,eAAe;AAC9B,QAAM,UAAU,uBAAuB;AACvC,QAAM,SAAS,aAAa,GAAG;AAC/B,QAAM,CAAC,OAAO,QAAQ,QAAI,wBAKvB,EAAE,KAAK,MAAM,MAAM,MAAM,SAAS,CAAC,CAAC,KAAK,OAAO,KAAK,CAAC;AACzD,QAAM,CAAC,YAAY,aAAa,QAAI,wBAAS,CAAC;AAE9C,+BAAU,MAAM;AACd,QAAI,CAAC,KAAK;AACR,eAAS,EAAE,KAAK,MAAM,MAAM,MAAM,SAAS,OAAO,OAAO,KAAK,CAAC;AAC/D,aAAO;AAAA,IACT;AACA,QAAI,YAAY;AAChB,QAAI,UAA+B;AACnC,aAAS,EAAE,KAAK,MAAM,MAAM,MAAM,SAAS,MAAM,OAAO,KAAK,CAAC;AAC9D,WAAO,QAAQ,GAAG,EAAE;AAAA,MAClB,CAAC,WAAW;AACV,YAAI,WAAW;AACb,iBAAO,QAAQ;AACf;AAAA,QACF;AACA,kBAAU,OAAO;AACjB,iBAAS,EAAE,KAAK,OAAO,KAAK,MAAM,OAAO,MAAM,SAAS,OAAO,OAAO,KAAK,CAAC;AAAA,MAC9E;AAAA,MACA,CAAC,QAAiB;AAChB,YAAI,UAAW;AACf,cAAM,UACJ,eAAe,QAAQ,IAAI,UAAU,OAAO,OAAO,qBAAqB;AAC1E,iBAAS,EAAE,KAAK,MAAM,MAAM,MAAM,SAAS,OAAO,OAAO,QAAQ,CAAC;AAGlE,cAAM,SAAS,SAAS,GAAG;AAC3B,gBAAQ;AAAA,UACN,OAAO;AAAA,UACP,UAAU,qBAAqB,GAAG;AAAA,UAClC,UAAU;AAAA,UACV,SAAS,qBAAqB,OAAO;AAAA,UACrC,GAAI,WAAW,SAAY,EAAE,OAAO,IAAI,CAAC;AAAA,QAC3C,CAAC;AAAA,MACH;AAAA,IACF;AACA,WAAO,MAAM;AACX,kBAAY;AACZ,gBAAU;AAAA,IACZ;AAAA,EAEF,GAAG,CAAC,QAAQ,QAAQ,UAAU,CAAC;AAE/B,SAAO;AAAA,IACL,GAAG;AAAA,IACH,OAAO,MAAM,cAAc,CAAC,MAAM,IAAI,CAAC;AAAA,EACzC;AACF;;;AIpFA,IAAAC,gBAAmC;AAsB5B,SAAS,mBACd,KACsB;AACtB,QAAM,SAAS,eAAe;AAC9B,QAAM,UAAU,uBAAuB;AACvC,QAAM,SAAS,aAAa,GAAG;AAC/B,QAAM,EAAE,OAAO,eAAe,QAAI,uBAG/B,MAAM;AACP,QAAI,CAAC,KAAK;AACR,aAAO;AAAA,QACL,OAAO,EAAE,YAAY,MAAM,QAAQ,SAAS,QAAQ,KAAK;AAAA,QACzD,gBAAgB;AAAA,MAClB;AAAA,IACF;AACA,QAAI;AACF,YAAM,aAAa,OAAO,QAAQ,GAAG;AACrC,UAAI,CAAC,YAAY;AACf,eAAO;AAAA,UACL,OAAO,EAAE,YAAY,MAAM,QAAQ,SAAS,QAAQ,KAAK;AAAA,UACzD,gBAAgB;AAAA,QAClB;AAAA,MACF;AACA,aAAO;AAAA,QACL,OAAO,EAAE,YAAY,QAAQ,SAAS,QAAQ,KAAK;AAAA,QACnD,gBAAgB;AAAA,MAClB;AAAA,IACF,SAAS,KAAK;AACZ,aAAO;AAAA,QACL,OAAO;AAAA,UACL,YAAY;AAAA,UACZ,QAAQ;AAAA,UACR,QAAQ,OAAO,cAAc,GAAG;AAAA,QAClC;AAAA,QACA,gBACE,eAAe,QAAQ,IAAI,UAAU,OAAO,OAAO,kBAAkB;AAAA,MACzE;AAAA,IACF;AAAA,EAEF,GAAG,CAAC,QAAQ,MAAM,CAAC;AAInB,+BAAU,MAAM;AACd,QAAI,MAAM,WAAW,cAAe;AACpC,YAAQ;AAAA,MACN,OAAO;AAAA,MACP,UAAU,qBAAqB,OAAO,IAAI;AAAA,MAC1C,UAAU;AAAA,MACV,SAAS,sBAAsB,MAAM,UAAU,SAAS,MACtD,kBAAkB,kBACpB;AAAA,IACF,CAAC;AAAA,EAEH,GAAG,CAAC,QAAQ,MAAM,MAAM,CAAC;AAEzB,SAAO;AACT;;;AL9DO,SAAS,eAAe,QAA6C;AAC1E,QAAM,aAAa,aAAa,OAAO,SAAS,QAAQ,OAAO,MAAM,IAAI;AACzE,MAAI,OAAO,SAAS,QAAQ;AAC1B,WAAO,EAAE,MAAM,OAAO,MAAM,SAAS,OAAO,OAAO,KAAK;AAAA,EAC1D;AACA,SAAO;AAAA,IACL,MAAM,WAAW;AAAA,IACjB,SAAS,WAAW;AAAA,IACpB,OAAO,WAAW;AAAA,EACpB;AACF;AAWA,eAAe,aAAa,MAA6B;AACvD,QAAM,YAAa,KAA0C;AAC7D,MAAI,OAAO,cAAc,WAAY,QAAO,MAAM,UAAU,KAAK,IAAI;AAErE,QAAM,mBAAoB,KACvB;AACH,MAAI,OAAO,qBAAqB,YAAY;AAC1C,WAAO,IAAI,YAAY,EAAE,OAAO,MAAM,iBAAiB,KAAK,IAAI,CAAC;AAAA,EACnE;AAEA,SAAO,MAAM,IAAI,QAAgB,CAAC,SAAS,WAAW;AACpD,UAAM,SAAS,IAAI,WAAW;AAC9B,WAAO,SAAS,MAAM,QAAQ,OAAO,OAAO,UAAU,EAAE,CAAC;AACzD,WAAO,UAAU,MACf,OAAO,OAAO,SAAS,IAAI,MAAM,iCAAiC,CAAC;AACrE,WAAO,WAAW,IAAI;AAAA,EACxB,CAAC;AACH;AAeO,SAAS,cACd,QACA,WAAW,OAAO,MACD;AACjB,QAAM,EAAE,MAAM,SAAS,OAAO,WAAW,IAAI,eAAe,MAAM;AAClE,QAAM,CAAC,MAAM,OAAO,QAAI,wBAAwB,IAAI;AACpD,QAAM,CAAC,WAAW,YAAY,QAAI,wBAAwB,IAAI;AAC9D,QAAM,CAAC,WAAW,YAAY,QAAI,wBAAS,KAAK;AAEhD,+BAAU,MAAM;AACd,QAAI,CAAC,MAAM;AACT,cAAQ,IAAI;AACZ,aAAO;AAAA,IACT;AACA,QAAI,YAAY;AAChB,iBAAa,IAAI;AACjB,YAAQ,IAAI;AACZ,iBAAa,KAAK;AAClB,UAAM,YAAY;AAChB,UAAI;AACF,cAAM,YAAY,KAAK,OAAO;AAC9B,cAAM,QAAQ,MAAM;AAAA,UAClB,YAAY,KAAK,MAAM,GAAG,QAAQ,IAAI;AAAA,QACxC;AACA,YAAI,UAAW;AACf,qBAAa,SAAS;AACtB,gBAAQ,KAAK;AAAA,MACf,SAAS,KAAK;AACZ,YAAI,UAAW;AACf,qBAAa,eAAe,QAAQ,IAAI,UAAU,OAAO,GAAG,CAAC;AAAA,MAC/D;AAAA,IACF,GAAG;AACH,WAAO,MAAM;AACX,kBAAY;AAAA,IACd;AAAA,EACF,GAAG,CAAC,MAAM,QAAQ,CAAC;AAEnB,QAAM,QAAQ,aAAa;AAC3B,SAAO;AAAA,IACL;AAAA,IACA;AAAA,IACA;AAAA,IACA,UAAU,WAAW,SAAS,SAAS,UAAU;AAAA,EACnD;AACF;AAwBO,SAAS,oBACd,QACuB;AACvB,QAAM,WAAW;AAAA,IACf,OAAO,SAAS,QAAQ,OAAO,MAAM;AAAA,EACvC;AACA,MAAI,OAAO,SAAS,QAAQ;AAC1B,WAAO;AAAA,MACL,KAAK,OAAO;AAAA,MACZ,aAAa;AAAA,MACb,aAAa;AAAA,MACb,SAAS;AAAA,IACX;AAAA,EACF;AACA,SAAO;AAAA,IACL,KAAK,SAAS,YAAY,OAAO;AAAA,IACjC,aAAa,SAAS,YAAY,gBAAgB;AAAA,IAClD,aAAa,SAAS,WAAW;AAAA,IACjC,SAAS,SAAS,WAAW;AAAA,EAC/B;AACF;;;AJ/DoB,IAAAC,sBAAA;AA9EpB,IAAM,kBAA0C;AAAA,EAC9C,IAAI;AAAA,EACJ,KAAK;AAAA,EACL,KAAK;AAAA,EACL,KAAK;AAAA,EACL,IAAI;AAAA,EACJ,KAAK;AAAA,EACL,IAAI;AAAA,EACJ,IAAI;AAAA,EACJ,IAAI;AAAA,EACJ,IAAI;AAAA,EACJ,MAAM;AAAA,EACN,IAAI;AAAA,EACJ,OAAO;AAAA,EACP,GAAG;AAAA,EACH,GAAG;AAAA,EACH,KAAK;AAAA,EACL,IAAI;AAAA,EACJ,KAAK;AAAA,EACL,KAAK;AAAA,EACL,IAAI;AAAA,EACJ,KAAK;AAAA,EACL,OAAO;AAAA,EACP,MAAM;AAAA,EACN,KAAK;AAAA,EACL,KAAK;AAAA,EACL,KAAK;AAAA,EACL,KAAK;AAAA,EACL,MAAM;AAAA,EACN,MAAM;AAAA,EACN,MAAM;AAAA,EACN,MAAM;AAAA,EACN,KAAK;AAAA,EACL,MAAM;AAAA,EACN,KAAK;AAAA,EACL,IAAI;AAAA,EACJ,MAAM;AAAA,EACN,KAAK;AAAA,EACL,MAAM;AAAA,EACN,KAAK;AAAA,EACL,KAAK;AAAA,EACL,SAAS;AAAA,EACT,KAAK;AAAA,EACL,OAAO;AAAA,EACP,YAAY;AAAA,EACZ,UAAU;AAAA,EACV,KAAK;AAAA,EACL,GAAG;AACL;AAEA,SAAS,YAAY,UAA0B;AAC7C,QAAM,OAAO,SAAS,MAAM,OAAO,EAAE,IAAI,KAAK;AAC9C,QAAM,MAAM,KAAK,YAAY,GAAG;AAChC,MAAI,OAAO,EAAG,QAAO;AACrB,SAAO,KAAK,MAAM,MAAM,CAAC,EAAE,YAAY;AACzC;AAGO,SAAS,mBAAmB,UAA0B;AAC3D,QAAM,MAAM,YAAY,QAAQ;AAChC,MAAI,IAAK,QAAO,gBAAgB,GAAG,KAAK;AACxC,QAAM,QAAQ,SAAS,YAAY;AACnC,MAAI,UAAU,aAAc,QAAO;AACnC,MAAI,UAAU,WAAY,QAAO;AACjC,SAAO;AACT;AAEO,SAAS,WAAW;AAAA,EACzB;AAAA,EACA;AAAA,EACA;AAAA,EACA,WAAW,OAAO;AACpB,GAAqB;AACnB,QAAM,EAAE,MAAM,OAAO,SAAS,UAAU,IAAI,cAAc,QAAQ,QAAQ;AAC1E,QAAM,CAAC,MAAM,OAAO,QAAI,wBAAS,KAAK;AACtC,QAAM,eAAW,uBAAQ,MAAM,mBAAmB,QAAQ,GAAG,CAAC,QAAQ,CAAC;AACvE,QAAM,cAAc,wBAAwB;AAE5C,MAAI,MAAO,QAAO,6CAAC,eAAY,SAAS,OAAO,WAAsB;AACrE,MAAI,WAAW,SAAS,KAAM,QAAO,6CAAC,kBAAe,WAAsB;AAE3E,QAAM,QAAQ,KAAK,MAAM,IAAI;AAE7B,SACE;AAAA,IAAC;AAAA;AAAA,MACC,WAAW;AAAA,QACT;AAAA,QACA;AAAA,MACF;AAAA,MAEA;AAAA,sDAAC,SAAI,WAAU,mGACb;AAAA,wDAAC,SAAI,WAAU,iEACb;AAAA,yDAAC,UAAK,WAAU,qCAAqC,oBAAS;AAAA,YAC7D,YACC,8CAAC,UAAK,WAAU,gBAAe;AAAA;AAAA,cAAG,eAAe,QAAQ;AAAA,eAAE,IACzD;AAAA,aACN;AAAA,UACA,8CAAC,SAAI,WAAU,2BACZ;AAAA,0BAAc,OACb;AAAA,cAAC;AAAA;AAAA,gBACC,MAAK;AAAA,gBACL,SAAS,MAAM,QAAQ,CAAC,UAAU,CAAC,KAAK;AAAA,gBACxC,gBAAc;AAAA,gBACd,WAAW;AAAA,kBACT;AAAA,kBACA,QAAQ;AAAA,gBACV;AAAA,gBACD;AAAA;AAAA,YAED;AAAA,YAEF,6CAAC,oBAAiB,MAAY;AAAA,aAChC;AAAA,WACF;AAAA,QACA,6CAAC,SAAI,WAAU,gCACZ;AAAA;AAAA;AAAA;AAAA,cAIC;AAAA,YACE;AAAA,YACA,EAAE,MAAM,MAAM,SAAS;AAAA,UACzB;AAAA,YAEA,8CAAC,SAAI,WAAU,4CACb;AAAA;AAAA,YAAC;AAAA;AAAA,cACC,eAAW;AAAA,cACX,WAAU;AAAA,cAET,gBAAM,IAAI,CAAC,GAAG,UAAU,GAAG,QAAQ,CAAC;AAAA,CAAI,EAAE,KAAK,EAAE;AAAA;AAAA,UACpD;AAAA,UACA;AAAA,YAAC;AAAA;AAAA,cACC,WAAW;AAAA,gBACT;AAAA,gBACA,OAAO,oCAAoC;AAAA,cAC7C;AAAA,cAEC;AAAA;AAAA,UACH;AAAA,WACF,GAEJ;AAAA;AAAA;AAAA,EACF;AAEJ;;;AUxGA,IAAM,OAAc;AAAA,EAClB,CAAC,CAAC,OAAO,QAAQ,OAAO,OAAO,QAAQ,QAAQ,QAAQ,QAAQ,OAAO,OAAO,QAAQ,KAAK,GAAG,SAAS,oBAAoB,SAAS,OAAO;AAAA,EAC1I,CAAC,CAAC,KAAK,GAAG,SAAS,kBAAkB,YAAY,WAAW;AAAA,EAC5D,CAAC,CAAC,OAAO,OAAO,QAAQ,OAAO,OAAO,KAAK,GAAG,SAAS,mBAAmB,SAAS,OAAO;AAAA,EAC1F,CAAC,CAAC,OAAO,OAAO,OAAO,OAAO,OAAO,QAAQ,MAAM,GAAG,SAAS,iBAAiB,SAAS,OAAO;AAAA,EAChG,CAAC,CAAC,KAAK,GAAG,YAAY,gBAAgB,aAAa,cAAc;AAAA,EACjE,CAAC,CAAC,MAAM,YAAY,OAAO,OAAO,QAAQ,YAAY,KAAK,GAAG,YAAY,kBAAkB,aAAa,UAAU;AAAA,EACnH,CAAC,CAAC,OAAO,QAAQ,OAAO,MAAM,OAAO,OAAO,KAAK,GAAG,YAAY,yBAAyB,aAAa,MAAM;AAAA,EAC5G,CAAC,CAAC,cAAc,iBAAiB,KAAK,GAAG,QAAQ,iBAAiB,QAAQ,MAAM;AAAA,EAChF,CAAC,CAAC,MAAM,QAAQ,SAAS,MAAM,OAAO,MAAM,OAAO,OAAO,QAAQ,GAAG,QAAQ,mBAAmB,QAAQ,MAAM;AAAA,EAC9G,CAAC,CAAC,QAAQ,SAAS,OAAO,OAAO,OAAO,OAAO,OAAO,OAAO,OAAO,OAAO,OAAO,OAAO,KAAK,GAAG,QAAQ,kBAAkB,aAAa,MAAM;AAAA,EAC9I,CAAC,CAAC,OAAO,OAAO,QAAQ,UAAU,cAAc,OAAO,GAAG,QAAQ,kBAAkB,UAAU,QAAQ;AAAA,EACtG,CAAC,CAAC,OAAO,SAAS,OAAO,OAAO,OAAO,KAAK,GAAG,QAAQ,oBAAoB,aAAa,OAAO;AAAA,EAC/F,CAAC,CAAC,OAAO,KAAK,GAAG,aAAa,iBAAiB,aAAa,WAAW;AAAA,EACvE,CAAC,CAAC,MAAM,OAAO,OAAO,KAAK,GAAG,QAAQ,mBAAmB,aAAa,YAAY;AAAA,EAClF,CAAC,CAAC,MAAM,KAAK,GAAG,QAAQ,iBAAiB,aAAa,YAAY;AAAA,EAClE,CAAC,CAAC,MAAM,OAAO,QAAQ,QAAQ,OAAO,OAAO,QAAQ,QAAQ,GAAG,QAAQ,oBAAoB,QAAQ,MAAM;AAAA,EAC1G,CAAC,CAAC,MAAM,OAAO,QAAQ,MAAM,WAAW,SAAS,KAAK,GAAG,QAAQ,gBAAgB,QAAQ,MAAM;AAAA,EAC/F,CAAC,CAAC,MAAM,MAAM,GAAG,QAAQ,iBAAiB,QAAQ,MAAM;AAAA,EACxD,CAAC,CAAC,IAAI,GAAG,QAAQ,mBAAmB,QAAQ,MAAM;AAAA,EAClD,CAAC,CAAC,MAAM,GAAG,QAAQ,gBAAgB,QAAQ,MAAM;AAAA,EACjD,CAAC,CAAC,KAAK,GAAG,GAAG,QAAQ,iBAAiB,QAAQ,GAAG;AAAA,EACjD,CAAC,CAAC,OAAO,MAAM,OAAO,KAAK,GAAG,QAAQ,iBAAiB,QAAQ,KAAK;AAAA,EACpE,CAAC,CAAC,IAAI,GAAG,QAAQ,mBAAmB,QAAQ,IAAI;AAAA,EAChD,CAAC,CAAC,QAAQ,OAAO,MAAM,KAAK,GAAG,QAAQ,mBAAmB,QAAQ,MAAM;AAAA,EACxE,CAAC,CAAC,KAAK,GAAG,QAAQ,gBAAgB,QAAQ,KAAK;AAAA,EAC/C,CAAC,CAAC,MAAM,GAAG,QAAQ,iBAAiB,QAAQ,MAAM;AAAA,EAClD,CAAC,CAAC,MAAM,QAAQ,OAAO,QAAQ,OAAO,OAAO,OAAO,OAAO,QAAQ,SAAS,MAAM,KAAK,GAAG,QAAQ,oBAAoB,QAAQ,QAAQ;AAAA,EACtI,CAAC,CAAC,KAAK,GAAG,QAAQ,kBAAkB,QAAQ,KAAK;AAAA,EACjD,CAAC,CAAC,MAAM,IAAI,GAAG,QAAQ,mBAAmB,QAAQ,MAAM;AAAA,EACxD,CAAC,CAAC,KAAK,OAAO,SAAS,OAAO,QAAQ,QAAQ,MAAM,GAAG,QAAQ,iBAAiB,QAAQ,MAAM;AAAA,EAC9F,CAAC,CAAC,MAAM,KAAK,GAAG,QAAQ,mBAAmB,QAAQ,QAAQ;AAAA,EAC3D,CAAC,CAAC,OAAO,KAAK,GAAG,QAAQ,iBAAiB,QAAQ,QAAQ;AAAA,EAC1D,CAAC,CAAC,MAAM,KAAK,GAAG,QAAQ,mBAAmB,QAAQ,SAAS;AAAA,EAC5D,CAAC,CAAC,KAAK,GAAG,QAAQ,mBAAmB,QAAQ,KAAK;AAAA,EAClD,CAAC,CAAC,OAAO,MAAM,GAAG,QAAQ,mBAAmB,QAAQ,KAAK;AAAA,EAC1D,CAAC,CAAC,IAAI,GAAG,QAAQ,mBAAmB,QAAQ,OAAO;AAAA,EACnD,CAAC,CAAC,OAAO,GAAG,QAAQ,oBAAoB,QAAQ,OAAO;AAAA,EACvD,CAAC,CAAC,WAAW,OAAO,UAAU,GAAG,QAAQ,iBAAiB,QAAQ,SAAS;AAAA,EAC3E,CAAC,CAAC,KAAK,GAAG,QAAQ,kBAAkB,QAAQ,UAAU;AAAA,EACtD,CAAC,CAAC,OAAO,SAAS,MAAM,GAAG,QAAQ,mBAAmB,QAAQ,KAAK;AAAA,EACnE,CAAC,CAAC,OAAO,cAAc,YAAY,OAAO,QAAQ,GAAG,QAAQ,kBAAkB,QAAQ,UAAU;AAAA,EACjG,CAAC,CAAC,QAAQ,SAAS,SAAS,OAAO,WAAW,UAAU,GAAG,QAAQ,kBAAkB,aAAa,MAAM;AAAA,EACxG,CAAC,CAAC,QAAQ,OAAO,MAAM,GAAG,QAAQ,kBAAkB,UAAU,QAAQ;AAAA,EACtE,CAAC,CAAC,KAAK,GAAG,QAAQ,kBAAkB,UAAU,KAAK;AAAA,EACnD,CAAC,CAAC,OAAO,KAAK,GAAG,QAAQ,mBAAmB,oBAAoB,kBAAkB;AAAA,EAClF,CAAC,CAAC,UAAU,WAAW,IAAI,GAAG,QAAQ,iBAAiB,YAAY,UAAU;AAAA,EAC7E,CAAC,CAAC,OAAO,MAAM,MAAM,MAAM,MAAM,GAAG,QAAQ,oBAAoB,UAAU,UAAU;AAAA,EACpF,CAAC,CAAC,QAAQ,KAAK,GAAG,YAAY,oBAAoB,oBAAoB,gBAAgB;AAAA,EACtF,CAAC,CAAC,OAAO,MAAM,GAAG,YAAY,iBAAiB,aAAa,eAAe;AAAA,EAC3E,CAAC,CAAC,OAAO,MAAM,GAAG,YAAY,mBAAmB,aAAa,cAAc;AAAA,EAC5E,CAAC,CAAC,OAAO,GAAG,YAAY,mBAAmB,aAAa,UAAU;AAAA,EAClE,CAAC,CAAC,MAAM,GAAG,SAAS,mBAAmB,aAAa,OAAO;AAAA,EAC3D,CAAC,CAAC,KAAK,GAAG,SAAS,iBAAiB,aAAa,OAAO;AAAA,EACxD,CAAC,CAAC,OAAO,QAAQ,OAAO,OAAO,KAAK,GAAG,YAAY,mBAAmB,WAAW,UAAU;AAAA,EAC3F,CAAC,CAAC,OAAO,OAAO,IAAI,GAAG,WAAW,kBAAkB,WAAW,SAAS;AAAA,EACxE,CAAC,CAAC,OAAO,MAAM,KAAK,GAAG,WAAW,kBAAkB,WAAW,SAAS;AAC1E;AAEA,IAAM,eAAe,oBAAI,IAA6B;AACtD,WAAW,CAAC,YAAY,UAAU,YAAY,MAAM,WAAW,KAAK,MAAM;AACxE,aAAW,OAAO,YAAY;AAC5B,iBAAa,IAAI,KAAK,EAAE,UAAU,YAAY,MAAM,YAAY,CAAC;AAAA,EACnE;AACF;AAEA,IAAM,kBAAmC;AAAA,EACvC,UAAU;AAAA,EACV,aAAa;AAAA,EACb,YAAY;AAAA,EACZ,MAAM;AACR;AAEA,IAAM,uBAAwC;AAAA,EAC5C,UAAU;AAAA,EACV,aAAa;AAAA,EACb,YAAY;AAAA,EACZ,MAAM;AACR;AAEA,IAAM,iBAAkC;AAAA,EACtC,UAAU;AAAA,EACV,aAAa;AAAA,EACb,YAAY;AAAA,EACZ,MAAM;AACR;AAEA,IAAM,gBAAgB,aAAa,IAAI,KAAK;AAC5C,IAAM,gBAAgB,aAAa,IAAI,KAAK;AAC5C,IAAM,gBAAgB,aAAa,IAAI,KAAK;AAC5C,IAAM,cAAc,aAAa,IAAI,KAAK;AAC1C,IAAM,cAAc,aAAa,IAAI,KAAK;AAE1C,SAAS,WAAW,MAAsB;AACxC,QAAM,MAAM,KAAK,IAAI,KAAK,YAAY,GAAG,GAAG,KAAK,YAAY,IAAI,CAAC;AAClE,SAAO,OAAO,IAAI,KAAK,MAAM,MAAM,CAAC,IAAI;AAC1C;AAEA,SAAS,MAAM,MAA6B;AAC1C,QAAM,MAAM,KAAK,YAAY,GAAG;AAChC,MAAI,OAAO,KAAK,QAAQ,KAAK,SAAS,EAAG,QAAO;AAChD,SAAO,KAAK,MAAM,MAAM,CAAC,EAAE,YAAY;AACzC;AAMA,SAAS,qBAAqB,UAA2B;AACvD,QAAM,OAAO,WAAW,QAAQ;AAChC,MAAI,CAAC,KAAK,WAAW,GAAG,EAAG,QAAO;AAClC,WAAS,IAAI,GAAG,IAAI,KAAK,QAAQ,KAAK;AACpC,UAAM,IAAI,KAAK,WAAW,CAAC;AAC3B,QACG,KAAK,MAAM,KAAK,MAChB,KAAK,MAAM,KAAK,MAChB,KAAK,MAAM,KAAK,OACjB,MAAM,MACN,MAAM,IACN;AACA,aAAO;AAAA,IACT;AAAA,EACF;AACA,SAAO;AACT;AAGA,SAAS,kBAAkB,KAAqB;AAC9C,SAAO,IAAI,MAAM,GAAG,EAAE,CAAC,GAAG,KAAK,EAAE,YAAY,KAAK;AACpD;AAOO,SAAS,mBACd,UACA,UACiB;AACjB,QAAM,OAAO,WAAW,QAAQ;AAChC,QAAM,QAAQ,KAAK,YAAY;AAC/B,QAAM,MAAM,UAAU,gBAAgB,UAAU,kBAAkB,QAAQ,MAAM,IAAI;AACpF,QAAM,UAAU,MAAM,aAAa,IAAI,GAAG,IAAI;AAE9C,QAAM,OAAO,WAAW,kBAAkB,QAAQ,IAAI;AACtD,MAAI,MAAM;AACR,QAAI,SAAS,gBAAiB,QAAO,WAAW;AAChD,QAAI,KAAK,WAAW,QAAQ,EAAG,QAAO,SAAS,aAAa,UAAU,UAAU;AAChF,QAAI,KAAK,WAAW,QAAQ,EAAG,QAAO,SAAS,aAAa,UAAU,UAAU;AAChF,QAAI,KAAK,WAAW,QAAQ,EAAG,QAAO,SAAS,aAAa,UAAU,UAAU;AAChF,QAAI,SAAS,kBAAmB,QAAO;AAAA,EACzC;AAEA,MAAI,QAAS,QAAO;AACpB,MAAI,qBAAqB,QAAQ,EAAG,QAAO;AAC3C,SAAO;AACT;AAGO,SAAS,qBAAqB,OAAO,OAAwB;AAClE,SAAO,OAAO,EAAE,GAAG,gBAAgB,MAAM,cAAc,IAAI;AAC7D;;;ACzII,IAAAC,sBAAA;AAxDJ,IAAM,QAAuF;AAAA,EAC3F,OAAO;AAAA,EACP,YAAY;AAAA,EACZ,OAAO;AAAA,EACP,OAAO;AAAA,EACP,aAAa;AAAA,EACb,aAAa;AAAA,EACb,MAAM;AAAA,EACN,QAAQ;AAAA,EACR,WAAW;AAAA,EACX,aAAa;AAAA,EACb,aAAa;AAAA,EACb,oBAAoB;AAAA,EACpB,UAAU;AAAA,EACV,SAAS;AAAA,EACT,SAAS;AAAA,EACT,QAAQ;AAAA,EACR,eAAe;AAAA,EACf,MAAM;AAAA,EACN,cAAc;AAAA,EACd,cAAc;AAChB;AAgBO,SAASC,UAAS;AAAA,EACvB;AAAA,EACA,WAAW;AAAA,EACX;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA,OAAO;AACT,GAAkB;AAChB,QAAM,UAAU,WACZ,qBAAqB,IAAI,IACzB,mBAAmB,YAAY,IAAI,QAAQ;AAC/C,QAAM,OAAO,MAAM,QAAQ,IAAI;AAC/B,QAAM,QAAuB;AAAA,IAC3B,OAAO,GAAG,IAAI;AAAA,IACd,QAAQ,GAAG,IAAI;AAAA,IACf,UAAU,GAAG,IAAI;AAAA,EACnB;AACA,SACE;AAAA,IAAC;AAAA;AAAA,MACC;AAAA,MACA,WAAW,GAAG,YAAY,cAAc,QAAQ,YAAY,SAAS;AAAA,MACrE,eAAY;AAAA;AAAA,EACd;AAEJ;;;ACrFA,IAAAC,gBAAkD;AA+H5C,IAAAC,sBAAA;AAnHN,IAAM,kBAAkB;AAWjB,SAAS,eAAe,OAA0C;AACvE,MAAI,SAAS,QAAQ,CAAC,OAAO,SAAS,KAAK,KAAK,QAAQ,EAAG,QAAO;AAClE,MAAI,QAAQ,KAAM,QAAO,GAAG,KAAK;AACjC,QAAM,QAAQ,CAAC,MAAM,MAAM,MAAM,IAAI;AACrC,MAAI,QAAQ;AACZ,MAAI,OAAO;AACX,KAAG;AACD,aAAS;AACT,YAAQ;AAAA,EACV,SAAS,SAAS,QAAQ,OAAO,MAAM,SAAS;AAChD,SAAO,GAAG,SAAS,KAAK,KAAK,MAAM,KAAK,IAAI,MAAM,QAAQ,CAAC,CAAC,IAAI,MAAM,IAAI,KAAK,IAAI;AACrF;AAcA,SAAS,uBAAuB;AAAA,EAC9B;AAAA,EACA;AAAA,EACA;AAAA,EACA;AACF,GAA4B;AAC1B,QAAM,CAAC,SAAS,UAAU,QAAI,wBAAS,KAAK;AAE5C,QAAM,cAAc,QAAQ,OAAO,CAAC,MAAM,EAAE,WAAW,WAAW,EAAE;AACpE,QAAM,eAAe,QAAQ,OAAO,CAAC,MAAM,EAAE,WAAW,SAAS,EAAE;AACnE,QAAM,aAAa,QAAQ,OAAO,CAAC,MAAM,EAAE,WAAW,OAAO,EAAE;AAI/D,QAAM,gBAAY;AAAA,IAChB,oBAAI,IAAI;AAAA,EACV;AACA,QAAM,mBAAe,sBAAO,SAAS;AACrC,eAAa,UAAU;AACvB,+BAAU,MAAM;AACd,UAAM,SAAS,UAAU;AACzB,QAAI,SAAS;AACX,aAAO,QAAQ,CAAC,MAAM,aAAa,CAAC,CAAC;AACrC,aAAO,MAAM;AACb;AAAA,IACF;AACA,eAAW,KAAK,SAAS;AACvB,UAAI,EAAE,WAAW,UAAW;AAC5B,UAAI,OAAO,IAAI,EAAE,EAAE,EAAG;AACtB,YAAM,UAAU,EAAE,cAAc,KAAK,IAAI,IAAI,EAAE,cAAc;AAC7D,YAAM,YAAY,KAAK,IAAI,GAAG,kBAAkB,OAAO;AACvD,YAAM,SAAS,WAAW,MAAM;AAC9B,eAAO,OAAO,EAAE,EAAE;AAClB,qBAAa,QAAQ,EAAE,EAAE;AAAA,MAC3B,GAAG,SAAS;AACZ,aAAO,IAAI,EAAE,IAAI,MAAM;AAAA,IACzB;AACA,UAAM,iBAAiB,IAAI;AAAA,MACzB,QAAQ,OAAO,CAAC,MAAM,EAAE,WAAW,SAAS,EAAE,IAAI,CAAC,MAAM,EAAE,EAAE;AAAA,IAC/D;AACA,eAAW,CAAC,IAAI,MAAM,KAAK,QAAQ;AACjC,UAAI,CAAC,eAAe,IAAI,EAAE,GAAG;AAC3B,qBAAa,MAAM;AACnB,eAAO,OAAO,EAAE;AAAA,MAClB;AAAA,IACF;AAAA,EACF,GAAG,CAAC,SAAS,OAAO,CAAC;AAErB,+BAAU,MAAM;AACd,UAAM,SAAS,UAAU;AACzB,WAAO,MAAM;AACX,aAAO,QAAQ,CAAC,MAAM,aAAa,CAAC,CAAC;AACrC,aAAO,MAAM;AAAA,IACf;AAAA,EACF,GAAG,CAAC,CAAC;AAEL,MAAI,QAAQ,WAAW,EAAG,QAAO;AAEjC,QAAM,cACJ,cAAc,IACV,aAAa,WAAW,QAAQ,gBAAgB,IAAI,KAAK,GAAG,WAC5D,aAAa,KAAK,iBAAiB,IACjC,GAAG,UAAU,UAAU,eAAe,IAAI,KAAK,GAAG,YAClD,YAAY,YAAY,QAAQ,iBAAiB,IAAI,KAAK,GAAG;AAErE,QAAM,eAAe,QAClB,OAAO,CAAC,MAAM,EAAE,WAAW,aAAa,EAAE,WAAW,OAAO,EAC5D,IAAI,CAAC,MAAM,EAAE,EAAE;AAElB,SACE;AAAA,IAAC;AAAA;AAAA,MACC,WAAW;AAAA,QACT;AAAA,QACA;AAAA,MACF;AAAA,MACA,cAAc,MAAM,WAAW,IAAI;AAAA,MACnC,cAAc,MAAM,WAAW,KAAK;AAAA,MACpC,cAAW;AAAA,MAEX;AAAA,sDAAC,SAAI,WAAU,4EACb;AAAA,uDAAC,UAAK,WAAU,gDACb,uBACH;AAAA,UACC,aAAa,SAAS,IACrB;AAAA,YAAC;AAAA;AAAA,cACC,MAAK;AAAA,cACL,SAAS,MAAM;AACb,2BAAW,MAAM,aAAc,WAAU,EAAE;AAAA,cAC7C;AAAA,cACA,WAAU;AAAA,cACX;AAAA;AAAA,UAED,IACE;AAAA,WACN;AAAA,QAEA,6CAAC,QAAG,WAAU,0CACX,kBAAQ,IAAI,CAAC,MAAM;AAClB,gBAAM,UACJ,EAAE,WAAW,IACT,KAAK,IAAI,KAAK,KAAK,MAAO,EAAE,gBAAgB,EAAE,WAAY,GAAG,CAAC,IAC9D;AACN,gBAAM,OAAO,EAAE,WAAW;AAC1B,gBAAM,SAAS,EAAE,WAAW;AAC5B,gBAAM,UAAU,QAAQ,CAAC,CAAC,EAAE,UAAU,CAAC,CAAC;AACxC,iBACE;AAAA,YAAC;AAAA;AAAA,cAEC,WAAW;AAAA,gBACT;AAAA,gBACA,WAAW;AAAA,cACb;AAAA,cACA,SACE,UAAU,MAAM,WAAW,EAAE,MAAgB,IAAI;AAAA,cAGnD;AAAA,6DAACC,WAAA,EAAS,UAAU,EAAE,UAAU,MAAM,IAAI,WAAU,YAAW;AAAA,gBAC/D,8CAAC,SAAI,WAAU,kBACb;AAAA,gEAAC,SAAI,WAAU,2CACb;AAAA,iEAAC,UAAK,WAAU,wCACb,YAAE,UACL;AAAA,oBACA,6CAAC,UAAK,WAAU,+CACb,mBAAS,WAAW,OAAO,SAAS,GAAG,OAAO,KACjD;AAAA,qBACF;AAAA,kBACC,OAAO,OACN,6CAAC,SAAI,WAAU,oCACb;AAAA,oBAAC;AAAA;AAAA,sBACC,WAAW;AAAA,wBACT;AAAA,wBACA,SAAS,mBAAmB;AAAA,sBAC9B;AAAA,sBACA,OAAO,EAAE,OAAO,SAAS,SAAS,GAAG,OAAO,IAAI;AAAA;AAAA,kBAClD,GACF;AAAA,kBAED,UAAU,EAAE,QACX,6CAAC,OAAE,WAAU,gDACV,YAAE,OACL,IACE,CAAC,OACH,8CAAC,OAAE,WAAU,4CACV;AAAA,mCAAe,EAAE,aAAa;AAAA,oBAAE;AAAA,oBAAG;AAAA,oBACnC,eAAe,EAAE,QAAQ;AAAA,qBAC5B,IACE;AAAA,mBACN;AAAA,gBAEC,UACC,8CAAC,UAAK,WAAU,+FACd;AAAA,+DAAC,oBAAiB,WAAU,WAAU,OAAO,IAAI,QAAQ,IAAI;AAAA,kBAAE;AAAA,mBAEjE,IACE,OACF;AAAA,kBAAC;AAAA;AAAA,oBACC,WAAU;AAAA,oBACV,OAAO;AAAA,oBACP,QAAQ;AAAA;AAAA,gBACV,IACE,SACF;AAAA,kBAAC;AAAA;AAAA,oBACC,WAAU;AAAA,oBACV,OAAO;AAAA,oBACP,QAAQ;AAAA;AAAA,gBACV,IACE;AAAA,gBAEH,QAAQ,SACP;AAAA,kBAAC;AAAA;AAAA,oBACC,MAAK;AAAA,oBACL,SAAS,CAAC,MAAM;AACd,wBAAE,gBAAgB;AAClB,gCAAU,EAAE,EAAE;AAAA,oBAChB;AAAA,oBACA,cAAW;AAAA,oBACX,WAAU;AAAA,oBAEV,uDAAC,SAAM,WAAU,WAAU,OAAO,IAAI,QAAQ,IAAI;AAAA;AAAA,gBACpD,IACE;AAAA;AAAA;AAAA,YAzEC,EAAE;AAAA,UA0ET;AAAA,QAEJ,CAAC,GACH;AAAA;AAAA;AAAA,EACF;AAEJ;AAEO,IAAM,yBAAqB,oBAAK,sBAAsB;;;ACpNvD,IAAAC,sBAAA;AArBC,SAAS,cAAc;AAAA,EAC5B;AAAA,EACA;AAAA,EACA;AAAA,EACA;AACF,GAAqB;AACnB,QAAM,aAAa,SAAS;AAC5B,QAAM,eAAe,SAAS;AAC9B,QAAM,kBAAkB,SAAS,mBAAmB;AACpD,QAAM,oBAAoB,SAAS,qBAAqB;AACxD,QAAM,iBAAiB,SAAS,kBAAkB;AAClD,QAAM,gBAAgB,OAAO,iBAAiB;AAC9C,QAAM,cAAc,OAAO,eAAe;AAE1C,SACE;AAAA,IAAC;AAAA;AAAA,MACC,WAAW;AAAA,QACT;AAAA,QACA;AAAA,MACF;AAAA,MAEA;AAAA,qDAACC,WAAA,EAAS,UAAoB,MAAM,IAAI;AAAA,QACxC,8CAAC,SACC;AAAA,uDAAC,OAAE,WAAU,yCAAyC,oBAAS;AAAA,UAC/D,6CAAC,OAAE,WAAU,iCACV,yBAAe,YAAY,IAAI,GAClC;AAAA,WACF;AAAA,QACA,6CAAC,OAAE,WAAU,0CACV,mBAAS,YACP,gBACG,8CACA,4CACR;AAAA,QACA,8CAAC,SAAI,WAAU,oDACZ;AAAA,0BAAgB,oBACf;AAAA,YAAC;AAAA;AAAA,cACC,SAAS;AAAA,cACT,OAAO;AAAA,cACP,MAAM;AAAA,cACN,SAAQ;AAAA;AAAA,UACV,IACE;AAAA,UACH,aACC;AAAA,YAAC;AAAA;AAAA,cACC,MAAK;AAAA,cACL,SAAS;AAAA,cACT,WAAW;AAAA,gBACT;AAAA,gBACA,iBAAiB,oBACb,mGACA;AAAA,cACN;AAAA,cAEA;AAAA,6DAAC,gBAAa,WAAU,WAAU;AAAA,gBAAE;AAAA;AAAA;AAAA,UAEtC,IACE;AAAA,UACH,gBAAgB,CAAC,oBAChB;AAAA,YAAC;AAAA;AAAA,cACC,SAAS;AAAA,cACT,OAAO;AAAA,cACP,MAAM;AAAA,cACN,SAAQ;AAAA;AAAA,UACV,IACE;AAAA,WACN;AAAA,QACC,CAAC,eAAe,CAAC,gBAChB,6CAAC,OAAE,WAAU,iDAAgD,yFAG7D,IACE;AAAA;AAAA;AAAA,EACN;AAEJ;AAEA,SAAS,iBAAiB;AAAA,EACxB;AAAA,EACA;AAAA,EACA;AAAA,EACA;AACF,GAKG;AACD,SACE;AAAA,IAAC;AAAA;AAAA,MACC,MAAK;AAAA,MACL;AAAA,MACA,UAAU;AAAA,MACV,WAAW;AAAA,QACT;AAAA,QACA;AAAA,QACA,YAAY,YACR,2DACA;AAAA,MACN;AAAA,MAEC;AAAA,eACC,6CAAC,eAAY,WAAU,wBAAuB,IAE9C,6CAAC,gBAAa,WAAU,WAAU;AAAA,QAEnC;AAAA;AAAA;AAAA,EACH;AAEJ;;;AC9GA,IAAAC,iBAAoC;;;ACLpC,IAAAC,gBAAyB;AAsCrB,IAAAC,sBAAA;AA1BG,SAAS,cACd,UACoB;AACpB,QAAM,CAAC,WAAW,YAAY,QAAI,wBAAgC,UAAU;AAC5E,QAAM,aAAa,UAAU,SAAS;AACtC,SAAO;AAAA,IACL,MAAM,UAAU,QAAQ;AAAA,IACxB,SAAS,UAAU,gBAAgB;AAAA,IACnC;AAAA,EACF;AACF;AAEO,SAAS,iBAAiB;AAAA,EAC/B;AAAA,EACA;AAAA,EACA,gBAAgB;AAAA,EAChB,eAAe;AAAA,EACf;AACF,GAMG;AACD,SACE,8CAAC,SAAI,WAAW,GAAG,6BAA6B,SAAS,GACvD;AAAA;AAAA,MAAC;AAAA;AAAA,QACC,QAAQ,SAAS;AAAA,QACjB,SAAS,MAAM,SAAS,UAAU;AAAA,QAClC,OAAO;AAAA,QACP,MACE,iBAAiB,UACf,6CAAC,aAAU,WAAU,eAAc,IAEnC,6CAAC,aAAU,WAAU,eAAc;AAAA;AAAA,IAGzC;AAAA,IACA;AAAA,MAAC;AAAA;AAAA,QACC,QAAQ,SAAS;AAAA,QACjB,SAAS,MAAM,SAAS,QAAQ;AAAA,QAChC,OAAM;AAAA,QACN,MAAM,6CAAC,YAAS,WAAU,eAAc;AAAA;AAAA,IAC1C;AAAA,KACF;AAEJ;AAEA,SAAS,aAAa;AAAA,EACpB;AAAA,EACA;AAAA,EACA;AAAA,EACA;AACF,GAKG;AACD,SACE;AAAA,IAAC;AAAA;AAAA,MACC,MAAK;AAAA,MACL;AAAA,MACA,gBAAc;AAAA,MACd,WAAW;AAAA,QACT;AAAA,QACA,SACI,qCACA;AAAA,MACN;AAAA,MAEC;AAAA;AAAA,QACD,6CAAC,UAAM,iBAAM;AAAA;AAAA;AAAA,EACf;AAEJ;;;AD9DQ,IAAAC,sBAAA;AAbR,IAAM,iBAAuE;AAAA,EAC3E,QAAQ;AAAA,EACR,QAAQ;AAAA,EACR,SAAS;AACX;AAEO,SAAS,WAAW,OAAyB;AAClD,QAAM,EAAE,WAAW,UAAU,eAAe,IAAI;AAChD,QAAM,EAAE,MAAM,SAAS,WAAW,IAAI,cAAc,cAAc;AAElE,SACE,8CAAC,SAAI,WAAW,GAAG,+BAA+B,SAAS,GACxD;AAAA,iBAAa,OACZ,8CAAC,SAAI,WAAU,gHACb;AAAA,mDAAC,UAAK,WAAU,wCACb,oBACH;AAAA,MACA;AAAA,QAAC;AAAA;AAAA,UACC;AAAA,UACA,UAAU;AAAA,UACV,eAAc;AAAA,UACd,cAAa;AAAA;AAAA,MACf;AAAA,OACF;AAAA,IAEF,6CAAC,SAAI,WAAU,2BACZ,mBAAS,aACR,6CAAC,oBAAkB,GAAG,OAAO,IAE7B,6CAAC,kBAAgB,GAAG,OAAO,GAE/B;AAAA,KACF;AAEJ;AAEA,SAAS,iBAAiB,EAAE,QAAQ,UAAU,eAAe,GAAqB;AAChF,QAAM,EAAE,KAAK,YAAY,IAAI,oBAAoB,MAAM;AACvD,QAAM,WAAW,gBAAgB,YAAY;AAC7C,QAAM,YAAY,gBAAgB,aAAa;AAC/C,QAAM,CAAC,SAAS,UAAU,QAAI,yBAAS,KAAK;AAE5C,gCAAU,MAAM;AACd,eAAW,KAAK;AAAA,EAClB,GAAG,CAAC,WAAW,GAAG,CAAC;AAEnB,MAAI,aAAa;AACf,WACE;AAAA,MAAC;AAAA;AAAA,QACC,OAAM;AAAA,QACN,MAAK;AAAA;AAAA,IACP;AAAA,EAEJ;AACA,MAAI,CAAC,IAAK,QAAO,6CAAC,kBAAe;AACjC,MAAI,QAAS,QAAO,6CAAC,eAAY,OAAM,uBAAsB;AAE7D,QAAM,cAAc,aAAa;AACjC,QAAM,QAAQ,cAAc,eAAe,QAAQ,IAAI;AAEvD,SACE;AAAA,IAAC;AAAA;AAAA,MACC,WAAW;AAAA,QACT;AAAA,QACA,eAAe;AAAA,MACjB;AAAA,MAEA;AAAA,QAAC;AAAA;AAAA,UACC,WAAW;AAAA,YACT;AAAA,YACA,cACI,sEACA;AAAA,UACN;AAAA,UACA,OAAO,cAAc,EAAE,MAAM,IAAI;AAAA,UAEjC;AAAA,YAAC;AAAA;AAAA,cAGC,KAAK;AAAA,cACL,OAAO;AAAA,cAEP,SAAQ;AAAA,cACR,gBAAe;AAAA,cACf,WAAU;AAAA,cACV,SAAS,MAAM,WAAW,IAAI;AAAA;AAAA,YAPzB,GAAG,SAAS,IAAI,GAAG;AAAA,UAQ1B;AAAA;AAAA,MACF;AAAA;AAAA,EACF;AAEJ;AAEA,SAAS,eAAe,EAAE,QAAQ,WAAW,OAAO,KAAK,GAAqB;AAC5E,QAAM,EAAE,MAAM,OAAO,QAAQ,IAAI,cAAc,QAAQ,QAAQ;AAC/D,MAAI,MAAO,QAAO,6CAAC,eAAY,OAAM,wBAAuB,SAAS,OAAO;AAC5E,MAAI,WAAW,SAAS,KAAM,QAAO,6CAAC,kBAAe;AACrD,SACE,6CAAC,SAAI,WAAU,+GACZ,gBACH;AAEJ;;;AE/FA,IAAAC,iBAA4C;;;ACwBrC,SAAS,eAAe,KAAyB;AACtD,SAAO;AACT;;;ADHA,SAAS,iBACP,SACqB;AACrB,SAAO,OAAO,YAAY,WAAW,EAAE,SAAS,QAAQ,IAAI;AAC9D;AAGA,IAAM,4BAA4B;AAE3B,SAAS,qBACd,KACA,SAWmB;AACnB,QAAM,SAAS,eAAe;AAC9B,QAAM,UAAU,uBAAuB;AACvC,QAAM,cAAc,SAAS,gBAAgB;AAC7C,QAAM,aAAa,SAAS;AAC5B,QAAM,aAAa,SAAS;AAC5B,QAAM,CAAC,QAAQ,SAAS,QAAI,yBAIzB,EAAE,QAAQ,KAAK,UAAU,GAAG,QAAQ,MAAM,CAAC;AAC9C,QAAM,iBAAa,uBAAO,CAAC;AAI3B,gCAAU,MAAM;AACd,eAAW,UAAU;AAAA,EACvB,GAAG,CAAC,GAAG,CAAC;AAER,QAAM,WAAW,MAAM,qBAAqB,cAAc,MAAM,GAAG;AAEnE,QAAM,cAAc,CAAC,UAAoB;AACvC,QAAI,CAAC,OAAO,CAAC,aAAa;AACxB,gBAAU,EAAE,QAAQ,KAAK,UAAU,GAAG,QAAQ,KAAK,CAAC;AACpD,UAAI,KAAK;AACP,gBAAQ;AAAA,UACN,OAAO;AAAA,UACP,UAAU,SAAS;AAAA,UACnB,UAAU;AAAA,UACV,cAAc;AAAA,UACd,SACE;AAAA,QAEJ,CAAC;AAAA,MACH;AACA,mBAAa,KAAK;AAClB;AAAA,IACF;AACA,eAAW,WAAW;AACtB,UAAM,UAAU,WAAW;AAG3B,WAAO,iBAAiB,eAAe,GAAG,GAAG,OAAO,EAAE;AAAA,MACpD,CAAC,YAAY;AACX,cAAM,SAAS,iBAAiB,OAAO;AACvC,YAAI,OAAO,iBAAiB,aAAa;AAIvC,kBAAQ;AAAA,YACN,OAAO;AAAA,YACP,UAAU;AAAA,YACV,UAAU;AAAA,YACV,SACE;AAAA,UAGJ,CAAC;AAAA,QACH;AACA,YAAI,OAAO,YAAY,SAAS;AAC9B,oBAAU,CAAC,aAAa;AAAA,YACtB,QAAQ;AAAA,YACR,UAAU,QAAQ,WAAW,MAAM,QAAQ,WAAW,IAAI;AAAA,YAC1D,QAAQ;AAAA,UACV,EAAE;AAAA,QACJ,OAAO;AACL,oBAAU,EAAE,QAAQ,KAAK,UAAU,GAAG,QAAQ,KAAK,CAAC;AACpD,kBAAQ;AAAA,YACN,OAAO,UAAU,IAAI,iBAAiB;AAAA,YACtC,UAAU,SAAS;AAAA,YACnB,UAAU;AAAA,YACV,cAAc,UAAU,IAAI,YAAY;AAAA,YACxC,SACE,UAAU,IACN,iEACA;AAAA,YAEN,GAAI,OAAO,WAAW,SAAY,EAAE,QAAQ,OAAO,OAAO,IAAI,CAAC;AAAA,UACjE,CAAC;AACD,uBAAa,KAAK;AAAA,QACpB;AAAA,MACF;AAAA,MACA,CAAC,QAAiB;AAChB,kBAAU,EAAE,QAAQ,KAAK,UAAU,GAAG,QAAQ,KAAK,CAAC;AACpD,gBAAQ;AAAA,UACN,OAAO;AAAA,UACP,UAAU,SAAS;AAAA,UACnB,UAAU;AAAA,UACV,cAAc;AAAA,UACd,SAAS,4BACP,eAAe,QAAQ,IAAI,UAAU,OAAO,OAAO,eAAe,CACpE;AAAA,QACF,CAAC;AACD,qBAAa,KAAK;AAAA,MACpB;AAAA,IACF;AAAA,EACF;AAEA,SAAO;AAAA,IACL,UAAU,OAAO,WAAW,MAAM,OAAO,WAAW;AAAA,IACpD;AAAA,IACA,QAAQ,OAAO,WAAW,MAAM,OAAO,SAAS;AAAA,EAClD;AACF;;;AE3KO,IAAM,0BAIT;AAAA,EACF,iBACE;AAAA,EAIF,gBAAgB;AAAA,EAChB,oBAAoB;AACtB;;;ACUI,IAAAC,sBAAA;AALG,SAAS,UAAU,OAAyB;AACjD,QAAM,EAAE,WAAW,eAAe,IAAI;AACtC,QAAM,EAAE,MAAM,SAAS,WAAW,IAAI,cAAc,cAAc;AAElE,SACE;AAAA,IAAC;AAAA;AAAA,MACC,WAAW;AAAA,QACT;AAAA,QACA;AAAA,MACF;AAAA,MAEC;AAAA,qBAAa,OACZ;AAAA,UAAC;AAAA;AAAA,YACC;AAAA,YACA,UAAU;AAAA,YACV,WAAU;AAAA;AAAA,QACZ;AAAA,QAED,SAAS,aACR,6CAAC,mBAAiB,GAAG,OAAO,IAE5B,6CAAC,iBAAe,GAAG,OAAO;AAAA;AAAA;AAAA,EAE9B;AAEJ;AAEA,SAAS,gBAAgB,EAAE,QAAQ,SAAS,GAAqB;AAC/D,QAAM,EAAE,KAAK,aAAa,YAAY,IAAI,oBAAoB,MAAM;AAEpE,QAAM,EAAE,UAAU,aAAa,OAAO,IAAI,qBAAqB,KAAK;AAAA,IAClE;AAAA,IACA,GAAI,OAAO,SAAS,QAAQ,EAAE,YAAY,OAAO,IAAI,IAAI,CAAC;AAAA,EAC5D,CAAC;AAED,MAAI,aAAa;AACf,WACE;AAAA,MAAC;AAAA;AAAA,QACC,OAAM;AAAA,QACN,MAAK;AAAA;AAAA,IACP;AAAA,EAEJ;AACA,MAAI,CAAC,IAAK,QAAO,6CAAC,kBAAe,WAAU,UAAS;AACpD,MAAI,QAAQ;AACV,WACE;AAAA,MAAC;AAAA;AAAA,QACC,OAAM;AAAA,QACN,MAAK;AAAA;AAAA,IACP;AAAA,EAEJ;AAEA,SACE;AAAA,IAAC;AAAA;AAAA,MACC,WAAU;AAAA,MACV,OAAO;AAAA,MAGP;AAAA,QAAC;AAAA;AAAA,UAEC,KAAK;AAAA,UACL,KAAK;AAAA,UACL,WAAU;AAAA,UACV,SAAS;AAAA;AAAA,QAJJ;AAAA,MAKP;AAAA;AAAA,EACF;AAEJ;AAEA,SAAS,cAAc,EAAE,QAAQ,WAAW,OAAO,KAAK,GAAqB;AAC3E,QAAM,EAAE,MAAM,OAAO,QAAQ,IAAI,cAAc,QAAQ,QAAQ;AAC/D,MAAI,MAAO,QAAO,6CAAC,eAAY,OAAM,yBAAwB,SAAS,OAAO;AAC7E,MAAI,WAAW,SAAS,KAAM,QAAO,6CAAC,kBAAe,WAAU,UAAS;AACxE,SACE,6CAAC,SAAI,WAAU,oIACZ,gBACH;AAEJ;;;ACpFoB,IAAAC,uBAAA;AAPb,SAAS,WAAW;AAAA,EACzB;AAAA,EACA;AAAA,EACA,WAAW,OAAO;AACpB,GAAqB;AACnB,QAAM,EAAE,MAAM,OAAO,SAAS,UAAU,IAAI,cAAc,QAAQ,QAAQ;AAE1E,MAAI,MAAO,QAAO,8CAAC,eAAY,SAAS,OAAO,WAAsB;AACrE,MAAI,WAAW,SAAS,MAAM;AAC5B,WAAO,8CAAC,kBAAe,MAAK,SAAQ,WAAsB;AAAA,EAC5D;AAEA,SACE;AAAA,IAAC;AAAA;AAAA,MACC,WAAW,GAAG,+CAA+C,SAAS;AAAA,MAEtE;AAAA,uDAAC,iBACC;AAAA,wDAAC,UAAK,WAAU,yBACb,sBACG,WAAW,eAAe,QAAQ,CAAC,MACnC,GAAG,KAAK,OAAO,eAAe,CAAC,eACrC;AAAA,UACA,8CAAC,oBAAiB,MAAY;AAAA,WAChC;AAAA,QACA,8CAAC,SAAI,WAAU,sGACZ,gBACH;AAAA;AAAA;AAAA,EACF;AAEJ;;;ACDQ,IAAAC,uBAAA;AAtBR,IAAM,kBAA4D;AAAA,EAChE,KAAK;AAAA,EACL,UAAU;AAAA,EACV,MAAM;AAAA,EACN,aAAa;AAAA,EACb,QAAQ;AAAA,EACR,OAAO;AAAA,EACP,OAAO;AAAA,EACP,OAAO;AACT;AAEO,SAAS,uBAAuB;AAAA,EACrC;AAAA,EACA,GAAG;AACL,GAAiD;AAC/C,QAAM,SAAS,gBAAgB,IAAI,KAAK,MAAM,IAAI;AAClD,QAAM,UAAU,MAAM;AACtB,SACE,+CAAC,SAAI,WAAW,GAAG,+BAA+B,MAAM,SAAS,GAC/D;AAAA,mDAAC,SAAI,WAAU,0HAAyH;AAAA;AAAA,MAClI;AAAA,MAAK;AAAA,MACmC;AAAA,MAAO;AAAA,MAAM;AAAA,MACzD,+CAAC,UAAK,WAAU,aAAY;AAAA;AAAA,QACC;AAAA,QAAK;AAAA,SAClC;AAAA,MAAO;AAAA,OAET;AAAA,IACA,8CAAC,SAAI,WAAU,kBACb;AAAA,MAAC;AAAA;AAAA,QACE,GAAG;AAAA,QACJ,WAAW;AAAA,QACX,SAAS;AAAA,UACP,GAAG;AAAA,UACH,SACE,SAAS,WACT;AAAA,QACJ;AAAA;AAAA,IACF,GACF;AAAA,KACF;AAEJ;;;AClDA,IAAM,iBAAkD;AAAA,EACtD,KAAK;AAAA,EACL,KAAK;AAAA,EACL,IAAI;AAAA,EACJ,UAAU;AAAA,EACV,KAAK;AAAA,EACL,MAAM;AAAA,EACN,KAAK;AAAA,EACL,KAAK;AAAA,EACL,KAAK;AAAA,EACL,MAAM;AAAA,EACN,KAAK;AAAA,EACL,KAAK;AAAA,EACL,MAAM;AAAA,EACN,KAAK;AAAA,EACL,MAAM;AAAA,EACN,KAAK;AAAA,EACL,KAAK;AAAA,EACL,MAAM;AACR;AAEA,SAASC,aAAY,UAA0B;AAC7C,QAAM,OAAO,SAAS,MAAM,OAAO,EAAE,IAAI,KAAK;AAC9C,QAAM,MAAM,KAAK,YAAY,GAAG;AAChC,MAAI,OAAO,EAAG,QAAO;AACrB,SAAO,KAAK,MAAM,MAAM,CAAC,EAAE,YAAY;AACzC;AAEO,SAAS,eACd,UACA,UACiB;AACjB,QAAM,WAAW,eAAeA,aAAY,QAAQ,CAAC;AACrD,MAAI,SAAU,QAAO;AAErB,QAAM,UAAU,mBAAmB,UAAU,YAAY,MAAS;AAClE,UAAQ,QAAQ,UAAU;AAAA,IACxB,KAAK;AACH,aAAO,QAAQ,SAAS,aAAa,QAAQ;AAAA,IAC/C,KAAK;AACH,aAAO;AAAA,IACT,KAAK;AACH,aAAO;AAAA,IACT,KAAK;AACH,aAAO;AAAA,IACT,KAAK;AACH,aAAO;AAAA,IACT,KAAK;AACH,aAAO;AAAA,IACT,KAAK;AACH,aAAO;AAAA,IACT,KAAK;AAIH,aAAO;AAAA,IACT;AACE,aAAO;AAAA,EACX;AACF;;;AxBIS,IAAAC,uBAAA;AAlCT,IAAM,WAAmE;AAAA,EACvE,MAAM;AAAA,EACN,MAAM;AAAA,EACN,KAAK;AAAA,EACL,MAAM;AAAA,EACN,SAAS;AACX;AAUO,SAAS,gBAAgB;AAAA,EAC9B;AAAA,EACA,GAAG;AACL,GAAyB;AACvB,QAAM,OACJ,eAAe,eAAe,MAAM,UAAU,MAAM,YAAY,IAAI;AAQtE,QAAM,SAAU,eAAe,IAAI,KAAK,SAAS,IAAI;AAGrD,MAAI,OAAQ,YAAO,8BAAc,QAAQ,KAAK;AAE9C,SAAO,8CAAC,0BAAwB,GAAG,OAAO,MAAY;AACxD;","names":["import_react","import_react","import_jsx_runtime","import_react","import_react","import_react","import_react","import_react","import_jsx_runtime","import_jsx_runtime","FileIcon","import_react","import_jsx_runtime","FileIcon","import_jsx_runtime","FileIcon","import_react","import_react","import_jsx_runtime","import_jsx_runtime","import_react","import_jsx_runtime","import_jsx_runtime","import_jsx_runtime","extensionOf","import_jsx_runtime"]}
|