@docubook/flame 2.0.0-beta.2 → 2.0.0-beta.3

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.
Files changed (39) hide show
  1. package/.docu/lib/build.deno.js +1 -1
  2. package/.docu/lib/{build.impl-BJsi28mD.js → build.impl-Bz_p421t.js} +60 -13
  3. package/.docu/lib/build.impl-Bz_p421t.js.map +1 -0
  4. package/.docu/lib/build.impl-CtPrlYAE.js +2 -0
  5. package/.docu/lib/build.node.js +1 -1
  6. package/.docu/lib/clean.js +1 -1
  7. package/.docu/lib/deploy.deno.js +1 -1
  8. package/.docu/lib/deploy.node.js +1 -1
  9. package/.docu/lib/{deploy.shared-D3UWafa6.js → deploy.shared-fk8eM-r4.js} +3 -3
  10. package/.docu/lib/{deploy.shared-D3UWafa6.js.map → deploy.shared-fk8eM-r4.js.map} +1 -1
  11. package/.docu/lib/{html.shared-DSn-7_6t.js → html.shared-FwgbE1WG.js} +242 -13
  12. package/.docu/lib/html.shared-FwgbE1WG.js.map +1 -0
  13. package/.docu/lib/{logger-CycvLCrQ.js → logger-CQyNTE6L.js} +9 -15
  14. package/.docu/lib/logger-CQyNTE6L.js.map +1 -0
  15. package/.docu/lib/{paths-BtOIPBQ9.js → paths-Bl2cdp9E.js} +27 -3
  16. package/.docu/lib/paths-Bl2cdp9E.js.map +1 -0
  17. package/.docu/lib/preview.deno.js +1 -1
  18. package/.docu/lib/{preview.impl-CXJS2tQS.js → preview.impl-CnsbLmDA.js} +3 -3
  19. package/.docu/lib/{preview.impl-CXJS2tQS.js.map → preview.impl-CnsbLmDA.js.map} +1 -1
  20. package/.docu/lib/preview.node.js +1 -1
  21. package/.docu/lib/server.deno.js +1 -1
  22. package/.docu/lib/{server.impl-CJuWimfN.js → server.impl-CXTzYqbF.js} +4 -4
  23. package/.docu/lib/{server.impl-CJuWimfN.js.map → server.impl-CXTzYqbF.js.map} +1 -1
  24. package/.docu/lib/server.node.js +1 -1
  25. package/.docu/node/build.impl.ts +76 -11
  26. package/.docu/node/build.ts +83 -9
  27. package/.docu/node/cache-key.ts +311 -0
  28. package/.docu/node/hydrate.node.ts +8 -11
  29. package/.docu/node/hydrate.ts +13 -14
  30. package/.docu/node/mdx.ts +14 -2
  31. package/.docu/node/paths.ts +27 -1
  32. package/.docu/node/types.ts +23 -5
  33. package/bin/cli.js +56 -18
  34. package/package.json +10 -16
  35. package/.docu/lib/build.impl-BJsi28mD.js.map +0 -1
  36. package/.docu/lib/build.impl-yVLaa1eQ.js +0 -2
  37. package/.docu/lib/html.shared-DSn-7_6t.js.map +0 -1
  38. package/.docu/lib/logger-CycvLCrQ.js.map +0 -1
  39. package/.docu/lib/paths-BtOIPBQ9.js.map +0 -1
@@ -1 +0,0 @@
1
- {"version":3,"file":"html.shared-DSn-7_6t.js","names":[],"sources":["../node/plugin-loader.ts","../node/plugin-builder.ts","../node/fs-scanner.ts","../node/hydrate.ts","../node/hydrate.node.ts","../node/git.ts","../node/mdx.ts","../node/search-indexer.ts","../node/sentry.ts","../components/Breadcrumb.tsx","../node/route.ts","../components/Pagination.tsx","../components/Typography.tsx","../node/helpers.ts","../components/EditWith.tsx","../components/Social.tsx","../components/Footer.tsx","../components/ScrollTo.tsx","../components/Toc.tsx","../pages/docs/[[...slug]].tsx","../pages/404.tsx","../components/Lucide.tsx","../components/home/Hero.tsx","../components/home/Features.tsx","../pages/index.tsx","../components/Anchor.tsx","../node/client-routes.ts","../components/Sublink.tsx","../components/SidebarGroupHeader.tsx","../components/Menu.tsx","../components/DocsLayout.tsx","../node/escapeHtml.ts","../node/html.shared.ts"],"sourcesContent":["import { resolve } from \"node:path\";\nimport { PROJECT_ROOT } from \"./paths\";\nimport type { DocuBookPlugin, PluginEntry } from \"./plugin\";\n\nconst NPM_PACKAGE_RE = /^(?:@[a-z0-9-~][a-z0-9-._~]*\\/)?[a-z0-9-~][a-z0-9-._~]*$/;\n\n/**\n * Resolve a plugin specifier to an absolute path or npm package name.\n *\n * Resolution rules:\n * 1. Relative path (starts with `.`) → resolve from project root, guard traversal\n * 2. Absolute path (starts with `/`) → guard traversal\n * 3. Anything else → validate as npm package name, then pass to Bun's import\n *\n * Path traversal protection:\n * - All file-system paths (relative & absolute) must resolve within PROJECT_ROOT.\n * - This prevents `../../sensitive-file` or `/etc/passwd` from being imported.\n */\n/** @internal Exported for testing only. */\nexport function resolveSpecifier(specifier: string): string {\n let resolved: string;\n\n if (specifier.startsWith(\".\")) {\n // Relative path → resolve from project root\n resolved = resolve(PROJECT_ROOT, specifier);\n } else if (specifier.startsWith(\"/\")) {\n // Absolute path → use as-is\n resolved = specifier;\n } else {\n // npm package name → validate format, then handled by Bun's import\n if (!NPM_PACKAGE_RE.test(specifier)) {\n throw new Error(\n `[plugin-loader] Invalid plugin specifier \"${specifier}\": must be a valid npm package name, relative path, or absolute path`\n );\n }\n return specifier;\n }\n\n // Path traversal guard: resolved path must stay within PROJECT_ROOT\n const root = PROJECT_ROOT.endsWith(\"/\") ? PROJECT_ROOT : PROJECT_ROOT + \"/\";\n if (!resolved.startsWith(root)) {\n throw new Error(\n `[plugin-loader] Path traversal blocked: \"${specifier}\" resolves outside project root`\n );\n }\n\n return resolved;\n}\n\n/**\n * Load and instantiate all plugins from a config entries array.\n *\n * @param entries - Array of plugin entries from `docu.json`.\n * Each entry is either:\n * - a `string` (plugin specifier, no options)\n * - a `[string, object]` tuple (plugin specifier + factory options)\n * @returns Array of resolved `DocuBookPlugin` instances.\n *\n * @throws If a plugin specifier cannot be imported.\n * @throws If a plugin's default export lacks a `name` property.\n *\n * @example\n * const plugins = await loadPlugins([\n * \"@docubook/plugin-sitemap\",\n * [\"@docubook/plugin-analytics\", { id: \"G-XXXXXXX\" }],\n * \"./plugins/local-reading-time\",\n * ]);\n */\nexport async function loadPlugins(entries: PluginEntry[] = []): Promise<DocuBookPlugin[]> {\n const plugins: DocuBookPlugin[] = [];\n\n for (const entry of entries) {\n const [specifier, options] = Array.isArray(entry) ? entry : [entry, undefined];\n const resolved = resolveSpecifier(specifier);\n\n let mod: Record<string, unknown>;\n try {\n mod = await import(resolved);\n } catch (err) {\n const message = err instanceof Error ? err.message : String(err);\n throw new Error(`[plugin-loader] Failed to import plugin \"${specifier}\": ${message}`, {\n cause: err,\n });\n }\n\n const exported = mod.default as unknown;\n\n let plugin: DocuBookPlugin;\n\n if (typeof exported === \"function\") {\n // Factory pattern: exported function receives options, returns DocuBookPlugin\n try {\n plugin = (exported as (opts?: Record<string, unknown>) => DocuBookPlugin)(options);\n } catch (err) {\n const message = err instanceof Error ? err.message : String(err);\n throw new Error(\n `[plugin-loader] Plugin factory \"${specifier}\" threw during initialization: ${message}`,\n { cause: err }\n );\n }\n } else if (exported && typeof exported === \"object\") {\n // Simple pattern: exported object is (or duck-types as) DocuBookPlugin\n plugin = exported as DocuBookPlugin;\n } else {\n throw new Error(\n `[plugin-loader] Plugin \"${specifier}\" must export a default function or object. Got: ${typeof exported}`\n );\n }\n\n if (!plugin.name || typeof plugin.name !== \"string\") {\n throw new Error(\n `[plugin-loader] Plugin \"${specifier}\" must have a valid 'name' property (string). Got: ${typeof plugin.name}`\n );\n }\n\n if (typeof plugin.setup !== \"function\") {\n throw new Error(\n `[plugin-loader] Plugin \"${specifier}\" (name: \"${plugin.name}\") must have a 'setup(build)' function.`\n );\n }\n\n plugins.push(plugin);\n }\n\n return plugins;\n}\n","import type { Pluggable } from \"unified\";\nimport type { DocuConfig, PageContext, PageMeta, DevServerContext, PluginBuilder } from \"./plugin\";\n\ntype Awaitable<T> = T | Promise<T>;\n\ninterface OnLoadHandler {\n filter: RegExp;\n namespace?: string;\n fn: (args: {\n path: string;\n content: string;\n }) => Awaitable<{ contents?: string; loader?: \"js\" | \"ts\" | \"mdx\" } | void>;\n}\n\nexport class BuildPluginBuilder implements PluginBuilder {\n readonly config: DocuConfig;\n\n private _handleRequest: Array<\n (req: Request, context: DevServerContext) => Awaitable<Response | void>\n > = [];\n private _injectBody: Array<(context: PageContext) => string | string[]> = [];\n private _injectHead: Array<(context: PageContext) => string | string[]> = [];\n private _onEnd: Array<(config: DocuConfig, pages: PageMeta[]) => Awaitable<void>> = [];\n private _onLoad: OnLoadHandler[] = [];\n private _onStart: Array<(config: DocuConfig) => Awaitable<void>> = [];\n private _rehypePlugins: Array<() => Pluggable[]> = [];\n private _remarkPlugins: Array<() => Pluggable[]> = [];\n private _transformFrontmatter: Array<\n (\n frontmatter: Record<string, unknown>,\n context: Pick<PageContext, \"slug\" | \"filePath\" | \"content\">\n ) => Awaitable<Record<string, unknown> | void>\n > = [];\n private _transformHtml: Array<(html: string, context: PageContext) => Awaitable<string>> = [];\n\n constructor(config: DocuConfig) {\n this.config = config;\n }\n\n /**\n * Collect and deduplicate all `<body>` injection snippets from registered plugins.\n * Each callback is executed in registration order; plugin errors are wrapped\n * with a descriptive message.\n *\n * @param context - Current page context passed to each injectBody callback.\n * @returns Deduplicated array of HTML strings to inject before `</body>`.\n * @throws Error if any injectBody callback throws — wraps original error as cause.\n */\n collectBody(context: PageContext): string[] {\n const items: string[] = [];\n for (const cb of this._injectBody) {\n try {\n const result = cb(context);\n if (result) {\n this.collectItems(items, result, \"injectBody\");\n }\n } catch (err) {\n throw new Error(\n `[plugin] injectBody callback failed: ${err instanceof Error ? err.message : String(err)}`,\n { cause: err }\n );\n }\n }\n return [...new Set(items)];\n }\n\n /**\n * Collect and deduplicate all `<head>` injection snippets from registered plugins.\n * Each callback is executed in registration order; plugin errors are wrapped\n * with a descriptive message.\n *\n * @param context - Current page context passed to each injectHead callback.\n * @returns Deduplicated array of HTML strings to inject before `</head>`.\n * @throws Error if any injectHead callback throws — wraps original error as cause.\n */\n collectHead(context: PageContext): string[] {\n const items: string[] = [];\n for (const cb of this._injectHead) {\n try {\n const result = cb(context);\n if (result) {\n this.collectItems(items, result, \"injectHead\");\n }\n } catch (err) {\n throw new Error(\n `[plugin] injectHead callback failed: ${err instanceof Error ? err.message : String(err)}`,\n { cause: err }\n );\n }\n }\n return [...new Set(items)];\n }\n\n /**\n * Collect all rehype plugin arrays from registered rehypePlugins callbacks.\n * Results from all plugins are flattened into a single array.\n *\n * @returns Flattened array of rehype plugin instances applied after default set.\n * @throws Error if any rehypePlugins callback throws — wraps original error as cause.\n */\n collectRehypePlugins(): Pluggable[] {\n const plugins: Pluggable[] = [];\n for (const cb of this._rehypePlugins) {\n try {\n plugins.push(...cb());\n } catch (err) {\n throw new Error(\n `[plugin] rehypePlugins callback failed: ${err instanceof Error ? err.message : String(err)}`,\n { cause: err }\n );\n }\n }\n return plugins;\n }\n\n /**\n * Collect all remark plugin arrays from registered remarkPlugins callbacks.\n * Results from all plugins are flattened into a single array.\n *\n * @returns Flattened array of remark plugin instances applied after default set.\n * @throws Error if any remarkPlugins callback throws — wraps original error as cause.\n */\n collectRemarkPlugins(): Pluggable[] {\n const plugins: Pluggable[] = [];\n for (const cb of this._remarkPlugins) {\n try {\n plugins.push(...cb());\n } catch (err) {\n throw new Error(\n `[plugin] remarkPlugins callback failed: ${err instanceof Error ? err.message : String(err)}`,\n { cause: err }\n );\n }\n }\n return plugins;\n }\n\n /**\n * Register a callback to intercept incoming requests during development.\n * The **first** callback to return a `Response` short-circuits all subsequent handlers.\n * Errors inside callbacks are caught and logged — execution continues to next handler.\n *\n * @param callback - Receives the Request and dev server context. Return Response or void.\n *\n * @example\n * build.handleRequest((req, ctx) => {\n * if (new URL(req.url).pathname === \"/api/status\") {\n * return new Response(JSON.stringify({ ok: true }), {\n * headers: { \"Content-Type\": \"application/json\" },\n * });\n * }\n * });\n */\n handleRequest(\n callback: (req: Request, context: DevServerContext) => Awaitable<Response | void>\n ): void {\n this._handleRequest.push(callback);\n }\n\n /**\n * Register a callback that returns HTML strings to inject before `</body>`.\n * Results from all plugins are merged, deduplicated, and served via `collectBody()`.\n *\n * @param callback - Returns a single HTML string or an array. Called once per page.\n *\n * @example\n * build.injectBody(() => `<div id=\"chat-widget\"></div>`);\n */\n injectBody(callback: (context: PageContext) => string | string[]): void {\n this._injectBody.push(callback);\n }\n\n /**\n * Register a callback that returns HTML strings to inject inside `<head>`.\n * Results from all plugins are merged, deduplicated, and served via `collectHead()`.\n *\n * @param callback - Returns a single HTML string or an array. Called once per page.\n *\n * @example\n * build.injectHead(() => `<script async src=\"https://cdn.example.com/analytics.js\"></script>`);\n */\n injectHead(callback: (context: PageContext) => string | string[]): void {\n this._injectHead.push(callback);\n }\n\n /**\n * Register a callback to run once after all pages are built.\n * Receives the resolved config and aggregated page metadata.\n * Errors thrown by the callback propagate to the caller via `runOnEnd()`.\n *\n * @param callback - Receives config and page metadata array. May return a Promise.\n *\n * @example\n * build.onEnd(async (config, pages) => {\n * const xml = generateSitemap(pages, config.meta.baseURL);\n * const out = \".docu/dist/sitemap.xml\";\n * // Bun.write on Bun for speed, writeFile on Node/Deno\n * await (typeof Bun !== \"undefined\"\n * ? Bun.write(out, xml)\n * : writeFile(out, xml));\n * });\n */\n onEnd(callback: (config: DocuConfig, pages: PageMeta[]) => Awaitable<void>): void {\n this._onEnd.push(callback);\n }\n\n /**\n * Register a callback to transform raw file content before MDX compilation.\n * Filtered by regex against the file's relative path — only the **first** matching\n * handler's result is used.\n * Errors thrown by the callback propagate to the caller via `runOnLoad()`.\n *\n * @param args.filter - RegExp matched against the file's relative path.\n * @param args.namespace - Optional namespace prefix (reserved for future use).\n * @param callback - Receives file path and raw content. Return new contents or void.\n *\n * @example\n * build.onLoad({ filter: /\\.md$/ }, ({ path, content }) => {\n * return { contents: `<!-- preprocessed -->\\n${content}`, loader: \"mdx\" };\n * });\n */\n onLoad(\n args: { filter: RegExp; namespace?: string },\n callback: (args: {\n path: string;\n content: string;\n }) => Awaitable<{ contents?: string; loader?: \"js\" | \"ts\" | \"mdx\" } | void>\n ): void {\n this._onLoad.push({ ...args, fn: callback });\n }\n\n /**\n * Register a callback to run once before the build starts.\n * Receives the resolved DocuConfig for validation or resource initialization.\n * Errors thrown by the callback propagate to the caller via `runOnStart()`.\n *\n * @param callback - Receives the resolved config. May return a Promise.\n *\n * @example\n * build.onStart((config) => {\n * if (!config.meta.baseURL) throw new Error(\"baseURL required\");\n * });\n */\n onStart(callback: (config: DocuConfig) => Awaitable<void>): void {\n this._onStart.push(callback);\n }\n\n /**\n * Register additional rehype (HTML) plugins for the MDX compilation pipeline.\n * Results from all plugins are merged and applied **after** the default set.\n *\n * @param callback - Returns an array of rehype plugins.\n *\n * @example\n * build.rehypePlugins(() => [require(\"rehype-autolink-headings\")]);\n */\n rehypePlugins(callback: () => Pluggable[]): void {\n this._rehypePlugins.push(callback);\n }\n\n /**\n * Register additional remark (Markdown) plugins for the MDX compilation pipeline.\n * Results from all plugins are merged and applied **after** the default set.\n *\n * @param callback - Returns an array of remark plugins.\n *\n * @example\n * build.remarkPlugins(() => [require(\"remark-custom-heading-id\")]);\n */\n remarkPlugins(callback: () => Pluggable[]): void {\n this._remarkPlugins.push(callback);\n }\n\n /**\n * Execute all registered handleRequest callbacks sequentially.\n * Stops and returns the **first** `Response` returned by any callback.\n * Errors inside individual callbacks are caught and logged — execution\n * continues to the next callback without throwing.\n *\n * @param req - The incoming HTTP Request.\n * @param context - Dev server context (port, hostname).\n * @returns A Response if a callback intercepted the request, or null if none did.\n */\n async runHandleRequest(req: Request, context: DevServerContext): Promise<Response | null> {\n for (let i = 0; i < this._handleRequest.length; i++) {\n try {\n const result = await this._handleRequest[i](req, context);\n if (result instanceof Response) {\n return result;\n }\n } catch (err) {\n console.error(\n `[plugin] handleRequest callback #${i + 1} error: ${err instanceof Error ? err.message : String(err)}`\n );\n }\n }\n return null;\n }\n\n /**\n * Execute all registered onEnd callbacks sequentially with the resolved\n * config and aggregated page metadata.\n * Errors inside individual callbacks are caught and logged — execution\n * continues to the next callback without throwing.\n *\n * @param pages - Array of metadata for every built page.\n */\n async runOnEnd(pages: PageMeta[]): Promise<void> {\n for (let i = 0; i < this._onEnd.length; i++) {\n try {\n await this._onEnd[i](this.config, pages);\n } catch (err) {\n console.error(\n `[plugin] onEnd callback #${i + 1} error: ${err instanceof Error ? err.message : String(err)}`\n );\n }\n }\n }\n\n /**\n * Execute registered onLoad handlers in registration order against a file.\n * Only the **first** handler whose `filter` regex matches the path and returns\n * a result is applied. If a matching handler throws, the error is logged and\n * subsequent handlers are tried.\n *\n * @param path - Relative path of the file being loaded.\n * @param content - Raw file content.\n * @returns Transformed content if a matching handler returned it, or null.\n */\n async runOnLoad(\n path: string,\n content: string\n ): Promise<{ contents?: string; loader?: \"js\" | \"ts\" | \"mdx\" } | null> {\n for (const handler of this._onLoad) {\n if (handler.filter.test(path)) {\n try {\n const result = await handler.fn({ path, content });\n if (result) return result;\n } catch (err) {\n console.error(\n `[plugin] onLoad handler for filter ${handler.filter} error: ${err instanceof Error ? err.message : String(err)}`\n );\n }\n }\n }\n return null;\n }\n\n /**\n * Execute all registered onStart callbacks sequentially.\n * Each callback receives the resolved DocuConfig.\n * Errors inside individual callbacks are caught and logged — execution\n * continues to the next callback without throwing.\n */\n async runOnStart(): Promise<void> {\n for (let i = 0; i < this._onStart.length; i++) {\n try {\n await this._onStart[i](this.config);\n } catch (err) {\n console.error(\n `[plugin] onStart callback #${i + 1} error: ${err instanceof Error ? err.message : String(err)}`\n );\n }\n }\n }\n\n /**\n * Execute the transformFrontmatter chain in waterfall pattern.\n * Each callback receives the **previous** callback's return value (or the\n * original frontmatter for the first). Callbacks that return `undefined` or\n * `null` pass the current value through unchanged.\n * Callbacks that return a non-object (string, number, array) are skipped\n * with a console warning — only plain objects are accepted.\n * Errors inside individual callbacks are caught and logged — the current\n * frontmatter passes through unchanged for that step.\n *\n * @param frontmatter - Initial frontmatter object parsed from MDX.\n * @param context - Page context with slug, filePath, and raw content.\n * @returns The final transformed frontmatter object.\n */\n async runTransformFrontmatterChain(\n frontmatter: Record<string, unknown>,\n context: Pick<PageContext, \"slug\" | \"filePath\" | \"content\">\n ): Promise<Record<string, unknown>> {\n let result = frontmatter;\n for (let i = 0; i < this._transformFrontmatter.length; i++) {\n try {\n const next = await this._transformFrontmatter[i](result, context);\n if (next !== undefined && next !== null) {\n if (typeof next === \"object\" && !Array.isArray(next)) {\n result = next;\n } else {\n console.warn(\n `[plugin] transformFrontmatter callback #${i + 1} returned invalid type (expected a plain object), skipping`\n );\n }\n }\n } catch (err) {\n console.error(\n `[plugin] transformFrontmatter callback #${i + 1} error: ${err instanceof Error ? err.message : String(err)}`\n );\n }\n }\n return result;\n }\n\n /**\n * Execute the transformHtml chain in pipeline pattern.\n * Each callback receives the **previous** callback's return value (or the\n * original HTML for the first). Every callback **must** return a string.\n * Errors inside individual callbacks are caught and logged — the current\n * HTML passes through unchanged for that step.\n *\n * @param html - The initial HTML string.\n * @param context - Full page context (slug, filePath, frontmatter, content, config).\n * @returns The final transformed HTML string.\n */\n async runTransformHtmlChain(html: string, context: PageContext): Promise<string> {\n let result = html;\n for (let i = 0; i < this._transformHtml.length; i++) {\n try {\n result = await this._transformHtml[i](result, context);\n } catch (err) {\n console.error(\n `[plugin] transformHtml callback #${i + 1} error: ${err instanceof Error ? err.message : String(err)}`\n );\n }\n }\n return result;\n }\n\n /**\n * Register a callback to mutate frontmatter before MDX compilation.\n * Callbacks are chained in a waterfall: the return value of one is passed\n * as input to the next. Return `undefined` to pass through unchanged.\n *\n * **Note:** Only plain objects are accepted as return values. Returning\n * a string, number, or array will be silently skipped with a warning.\n * Plugin authors should validate their return values before returning.\n *\n * @param callback - Receives frontmatter object and page context.\n *\n * @example\n * build.transformFrontmatter((fm, ctx) => {\n * const wordCount = ctx.content!.split(/\\s+/).length;\n * return { ...fm, readingTime: `${Math.ceil(wordCount / 200)} min read` };\n * });\n */\n transformFrontmatter(\n callback: (\n frontmatter: Record<string, unknown>,\n context: Pick<PageContext, \"slug\" | \"filePath\" | \"content\">\n ) => Awaitable<Record<string, unknown> | void>\n ): void {\n this._transformFrontmatter.push(callback);\n }\n\n /**\n * Register a callback to transform the final HTML string per page.\n * This is the **last** hook before the HTML is written to disk.\n * Callbacks are chained in a pipeline: each receives the previous callback's output.\n *\n * @param callback - Receives HTML string and full page context. Must return HTML.\n *\n * @example\n * build.transformHtml((html, ctx) => {\n * return html.replace(/https?:\\/\\/old-domain\\.com\\//g, \"/\");\n * });\n */\n transformHtml(callback: (html: string, context: PageContext) => Awaitable<string>): void {\n this._transformHtml.push(callback);\n }\n\n /**\n * Collect items from a callback result, filtering only valid strings.\n * Non-string items and unexpected types are logged as warnings.\n */\n private collectItems(items: string[], result: string | string[], hookName: string): void {\n if (Array.isArray(result)) {\n for (const item of result) {\n if (typeof item === \"string\") {\n items.push(item);\n } else {\n console.warn(\n `[plugin] ${hookName} callback returned non-string item (got ${typeof item}), skipping`\n );\n }\n }\n } else if (typeof result === \"string\") {\n items.push(result);\n } else {\n console.warn(\n `[plugin] ${hookName} callback returned unexpected type (got ${typeof result}), expected string or string[], skipping`\n );\n }\n }\n}\n","/**\n * File System-Based Route Scanner\n *\n * Auto-scan docs folder at build-time, merge with manual docu.json routes.\n * User can override with manual routes in docu.json.\n *\n * Docs folder structure:\n * docs/\n * ├── getting-started/\n * │ ├── introduction.mdx → /getting-started/introduction\n * │ └── installation.mdx → /getting-started/installation\n * └── api/\n * └── reference.mdx → /api/reference\n */\n\nimport type { DocuRoute } from \"./types\";\nimport { readdirSync, statSync } from \"node:fs\";\nimport { join, relative, extname, sep } from \"node:path\";\n\ninterface FileNode {\n name: string;\n relPath: string;\n absPath: string;\n isDirectory: boolean;\n children?: FileNode[];\n}\n\nfunction toTitleCase(str: string): string {\n return str\n .replace(/-/g, \" \")\n .replace(/_/g, \" \")\n .replace(/([a-z])([A-Z])/g, \"$1 $2\")\n .split(\" \")\n .map((word) => word.charAt(0).toUpperCase() + word.slice(1).toLowerCase())\n .join(\" \");\n}\n\nfunction isDocFile(filename: string): boolean {\n const ext = extname(filename).toLowerCase();\n return [\".mdx\", \".md\"].includes(ext);\n}\n\nfunction normalizePath(path: string): string {\n return path.split(sep).join(\"/\");\n}\n\n/**\n * Recursively scan a directory and return file tree\n *\n * @param dirPath - Absolute path to scan\n * @param docsRoot - Root docs folder for relative path calculation\n */\nfunction scanDir(dirPath: string, docsRoot: string): FileNode[] {\n const nodes: FileNode[] = [];\n\n let entries: string[];\n try {\n entries = readdirSync(dirPath).sort();\n } catch (err) {\n if ((err as NodeJS.ErrnoException).code !== \"ENOENT\") throw err;\n return nodes;\n }\n\n for (const entry of entries) {\n if (entry.startsWith(\".\") || entry === \"assets\") continue;\n\n const absPath = join(dirPath, entry);\n\n try {\n const stat = statSync(absPath);\n\n if (stat.isDirectory()) {\n const children = scanDir(absPath, docsRoot);\n if (children.length > 0) {\n nodes.push({\n name: entry,\n relPath: normalizePath(relative(docsRoot, absPath)),\n absPath,\n isDirectory: true,\n children,\n });\n }\n } else if (stat.isFile() && isDocFile(entry)) {\n nodes.push({\n name: entry,\n relPath: normalizePath(relative(docsRoot, absPath).replace(/\\.(mdx|md)$/, \"\")),\n absPath,\n isDirectory: false,\n });\n }\n } catch (err) {\n if ((err as NodeJS.ErrnoException).code !== \"ENOENT\") throw err;\n continue;\n }\n }\n\n return nodes;\n}\n\nfunction fileNodesToRoutes(nodes: FileNode[], parentHref = \"\"): DocuRoute[] {\n const routes: DocuRoute[] = [];\n\n for (const node of nodes) {\n if (!node.isDirectory) {\n const baseName = node.name.replace(/\\.(mdx|md)$/, \"\");\n const isIndexFile = /^(index|readme)$/i.test(baseName);\n if (isIndexFile) continue;\n\n const segment = node.relPath.split(\"/\").pop()!;\n const href = `/${segment}`;\n\n routes.push({\n title: toTitleCase(baseName),\n href,\n });\n } else {\n const dirTitle = toTitleCase(node.name);\n const segment = node.relPath.split(\"/\").pop()!;\n const dirHref = `/${segment}`;\n\n const children = fileNodesToRoutes(node.children || [], dirHref);\n\n if (children.length === 0) continue;\n\n const hasIndexFile = (node.children || []).some(\n (c) => !c.isDirectory && /^(index|readme)\\.(mdx|md)$/i.test(c.name)\n );\n\n if (hasIndexFile) {\n routes.push({\n title: dirTitle,\n href: dirHref,\n ...(parentHref === \"\" && {\n context: { title: dirTitle, icon: \"CircleHelp\", description: dirTitle },\n }),\n items: children,\n });\n } else {\n routes.push({\n title: dirTitle,\n href: dirHref,\n noLink: true,\n ...(parentHref === \"\" && {\n context: { title: dirTitle, icon: \"CircleHelp\", description: dirTitle },\n }),\n items: children,\n });\n }\n }\n }\n\n return routes;\n}\n\n/**\n * Scan docs folder and convert to DocuRoute[]\n *\n * @param docsPath - Path to docs folder (default: \"./docs\")\n */\nexport function scanDocsFolder(docsPath = \"./docs\"): DocuRoute[] {\n const absDocsPath = join(process.cwd(), docsPath);\n const nodes = scanDir(absDocsPath, absDocsPath);\n return fileNodesToRoutes(nodes);\n}\n\n/**\n * Resolve routes:\n * 1. If docu.json has routes, use them (manual priority)\n * 2. Else, scan docs folder (auto-detect)\n *\n * @param docuJsonRoutes - Routes from docu.json (optional)\n */\nexport function resolveRoutes(docuJsonRoutes?: DocuRoute[]): DocuRoute[] {\n if (docuJsonRoutes && docuJsonRoutes.length > 0) {\n return docuJsonRoutes;\n }\n return scanDocsFolder();\n}\n","import { join } from \"node:path\";\nimport { mkdir, unlink } from \"node:fs/promises\";\nimport { existsSync, readFileSync } from \"node:fs\";\nimport { createHash } from \"node:crypto\";\nimport { resolveTheme, generateThemeCss, presetRegistry } from \"@docubook/themes-colors\";\nimport { ASSETS_DIR, cleanOldBundles, LIB_DIR, STYLES_DIR, loadDocuConfig } from \"./paths\";\nimport { resolveRoutes } from \"./fs-scanner\";\nimport type { DocuRoute } from \"./types\";\nimport type { ThemeConfig } from \"@docubook/themes-colors\";\n\nconst themeRegistry = presetRegistry;\n\n/**\n * Read the effective theme config with this priority:\n * 1. FLAME_THEME env var (CLI --theme flag)\n * 2. docu.json theme.colors field\n */\nexport function getThemeConfig(): ThemeConfig | undefined {\n if (process.env.FLAME_THEME) {\n return process.env.FLAME_THEME;\n }\n const config = loadDocuConfig();\n return config.themes?.colors;\n}\n\n/**\n * Append theme CSS to compiled Tailwind output based on theme config.\n */\nexport function buildThemeCss(baseCss: string, themeConfig: unknown): string {\n try {\n const resolved = resolveTheme(themeConfig as ThemeConfig | undefined | null, themeRegistry);\n return baseCss + \"\\n\" + generateThemeCss(resolved);\n } catch (err) {\n console.warn(\n `[flame] Failed to resolve theme CSS: ${err instanceof Error ? err.message : String(err)}`\n );\n return baseCss;\n }\n}\n\n/**\n * Compute inline theme CSS for FOUC prevention.\n * Returns undefined if no theme is configured or on error.\n */\nexport function computeInlineThemeCss(): string | undefined {\n try {\n const themeColors = getThemeConfig();\n if (themeColors) {\n const resolved = resolveTheme(themeColors, themeRegistry);\n return generateThemeCss(resolved);\n }\n } catch (err) {\n console.warn(\n `[flame] Failed to compute inline theme CSS: ${err instanceof Error ? err.message : String(err)}`\n );\n }\n return undefined;\n}\n\n/** Compute Tailwind cache key from globals.css + theme config. */\nfunction twCacheKey(): string {\n const globalsPath = join(STYLES_DIR, \"globals.css\");\n const globals = existsSync(globalsPath) ? readFileSync(globalsPath, \"utf-8\") : \"\";\n let themeSuffix = \"\";\n try {\n const themeColors = getThemeConfig();\n if (themeColors) themeSuffix = JSON.stringify(themeColors);\n } catch {\n // theme config unavailable — proceed without\n }\n return createHash(\"sha256\")\n .update(globals + themeSuffix)\n .digest(\"hex\")\n .slice(0, 16);\n}\n\n/** Run Tailwind CLI, caching by content hash. */\nasync function buildTailwindCss(key: string): Promise<{ file: string; content: string }> {\n const cachedFile = `client-${key}.css`;\n const cachedPath = join(ASSETS_DIR, cachedFile);\n\n if (existsSync(cachedPath)) {\n const content = await Bun.file(cachedPath).text();\n return { file: cachedFile, content };\n }\n\n const tmpCss = join(ASSETS_DIR, `_tmp-${key}.css`);\n const proc = Bun.spawn(\n [\n \"bun\",\n \"x\",\n \"@tailwindcss/cli\",\n \"-i\",\n join(STYLES_DIR, \"globals.css\"),\n \"-o\",\n tmpCss,\n \"--minify\",\n ],\n { stdout: \"ignore\", stderr: \"pipe\" }\n );\n await proc.exited;\n if (proc.exitCode !== 0) {\n const err = await new Response(proc.stderr).text();\n throw new Error(`Tailwind CSS build failed:\\n${err}`);\n }\n\n let cssContent = await Bun.file(tmpCss).text();\n await unlink(tmpCss);\n\n try {\n const themeColors = getThemeConfig();\n if (themeColors) cssContent = buildThemeCss(cssContent, themeColors);\n } catch (err) {\n console.warn(\n `[flame] Failed to resolve theme config: ${err instanceof Error ? err.message : String(err)}`\n );\n }\n\n // Use the same input-derived key for lookup and output — if inputs change,\n // the key changes, cache busting works without a separate content hash.\n const cssFile = `client-${key}.css`;\n const outPath = join(ASSETS_DIR, cssFile);\n if (!existsSync(outPath)) await Bun.write(outPath, cssContent);\n\n return { file: cssFile, content: cssContent };\n}\n\nexport async function buildClientBundle(\n /** slug → compiled MDX ESM module source (program format) for static hydration. */\n mdxSources: Record<string, string> = {}\n): Promise<{ js: string; css: string }> {\n await mkdir(ASSETS_DIR, { recursive: true });\n const twKey = twCacheKey();\n await cleanOldBundles(new Set([`client-${twKey}.css`]));\n\n const nodeEnv = process.env.NODE_ENV || \"development\";\n const result = await Bun.build({\n entrypoints: [join(LIB_DIR, \"client.ts\")],\n outdir: ASSETS_DIR,\n naming: \"client-[hash].[ext]\",\n target: \"browser\",\n minify: nodeEnv === \"production\",\n define: { \"process.env.NODE_ENV\": JSON.stringify(nodeEnv) },\n plugins: [\n {\n name: \"docu-config\",\n setup(build) {\n // Components import as \"../node/client-routes\" (no .ts extension),\n // so filter matches the path tail without requiring the extension.\n build.onResolve({ filter: /client-routes$/ }, (args) => ({\n path: args.path,\n namespace: \"client-routes\",\n }));\n build.onLoad({ filter: /.*/, namespace: \"client-routes\" }, () => {\n const config = loadDocuConfig();\n const resolved = {\n ...config,\n routes: resolveRoutes(config.routes as DocuRoute[] | undefined),\n };\n return {\n contents: [\n `import type { DocuRoute, DocuConfig } from \"./types\";`,\n `const docuConfig = ${JSON.stringify(resolved)};`,\n `export const routes = docuConfig.routes || [];`,\n `export const config = docuConfig;`,\n ].join(\"\\n\"),\n loader: \"ts\",\n };\n });\n },\n },\n {\n // Serves per-page compiled MDX (program format) as real modules so\n // the client hydrates the content island without `new Function`.\n // client.ts imports `{ mdxModules } from \"./mdx-manifest\"`.\n name: \"mdx-hydrate\",\n setup(build) {\n build.onResolve({ filter: /^mdx-module:/ }, (args) => ({\n path: args.path,\n namespace: \"mdx-module\",\n }));\n build.onLoad({ filter: /.*/, namespace: \"mdx-module\" }, (args) => {\n const slug = args.path.slice(\"mdx-module:\".length);\n const contents = mdxSources[slug];\n if (contents == null) {\n return {\n errors: [{ text: `unknown mdx module: ${slug}` }],\n contents: \"\",\n loader: \"js\",\n };\n }\n return { contents, loader: \"js\" };\n });\n build.onResolve({ filter: /mdx-manifest$/ }, (args) => ({\n path: args.path,\n namespace: \"mdx-manifest\",\n }));\n build.onLoad({ filter: /.*/, namespace: \"mdx-manifest\" }, () => {\n // Sort keys: the prePass fills mdxSources via Promise.all, so\n // insertion order = resolution order (non-deterministic across\n // processes). Stable key order keeps the bundle hash stable so\n // the build cache (`assetsChanged`) actually hits.\n const slugs = Object.keys(mdxSources).sort();\n const imports = slugs\n .map((slug, i) => {\n const key = slug.replace(/[\"\\\\]/g, \"\");\n return `import * as _mdx${i} from \"mdx-module:${key}\";`;\n })\n .join(\"\\n\");\n const map = slugs.map((slug, i) => `${JSON.stringify(slug)}: _mdx${i}`).join(\", \");\n return {\n contents: `${imports}\\nexport const mdxModules = { ${map} };\\n`,\n loader: \"js\",\n };\n });\n },\n },\n ],\n });\n\n if (!result.success) {\n for (const log of result.logs) console.error(log);\n throw new Error(\"Client bundle failed\");\n }\n\n if (!result.outputs[0]) {\n throw new Error(\"Client bundle produced no output files\");\n }\n const entry = result.outputs.find((o) => o.kind === \"entry-point\");\n if (!entry) {\n throw new Error(\"Client bundle produced no entry-point output\");\n }\n const jsFile = entry.path.split(\"/\").pop()!;\n\n const { file: cssFile } = await buildTailwindCss(twKey);\n\n await Bun.write(join(ASSETS_DIR, \"manifest.json\"), JSON.stringify({ js: jsFile, css: cssFile }));\n\n return { js: jsFile, css: cssFile };\n}\n","/**\n * Client bundle builder for Node/Deno runtimes.\n *\n * Uses Vite with Rolldown plugins to produce a browser-ready client\n * bundle (JS + CSS) from the same components Bun.build handles natively.\n * Theme helpers (getThemeConfig, buildThemeCss, computeInlineThemeCss)\n * are re-exported from `hydrate.ts` — that module's `buildClientBundle`\n * is Bun-only and unused here.\n */\n\nimport { execFile } from \"node:child_process\";\nimport { builtinModules, createRequire } from \"node:module\";\nimport { basename, dirname, join, resolve } from \"node:path\";\nimport { existsSync, readFileSync, readdirSync } from \"node:fs\";\nimport { promisify } from \"node:util\";\nimport { mkdir, readFile, unlink, writeFile } from \"node:fs/promises\";\nimport { createHash } from \"node:crypto\";\nimport { build as viteBuild } from \"vite\";\nimport {\n ASSETS_DIR,\n FRAMEWORK_ROOT,\n cleanOldBundles,\n LIB_DIR,\n STYLES_DIR,\n loadDocuConfig,\n} from \"./paths\";\nimport { buildThemeCss, getThemeConfig } from \"./hydrate\";\nimport { resolveRoutes } from \"./fs-scanner\";\nimport { normalizeImporterPath } from \"./security\";\nimport type { DocuConfig, DocuRoute } from \"./types\";\n\n/** Extract Lucide icon names from user docu.json configuration. */\nfunction extractConfigIcons(config: DocuConfig): string[] {\n const icons: string[] = [];\n const pushIf = (s: string | undefined) => {\n if (s) icons.push(s);\n };\n config.home?.hero?.actions?.forEach((a) => pushIf(a.icon));\n config.home?.features?.forEach((f) => pushIf(f.icon));\n (function walk(routes: DocuRoute[]) {\n for (const r of routes) {\n pushIf(r.context?.icon);\n if (r.items) walk(r.items);\n }\n })(config.routes ?? []);\n return [...new Set(icons.filter((n) => /^[A-Z]/.test(n)))];\n}\n\nexport { buildThemeCss, computeInlineThemeCss, getThemeConfig } from \"./hydrate\";\n\nconst execFileAsync = promisify(execFile);\n\n/** Resolve the @tailwindcss/cli binary path from the installed package. */\nfunction resolveTailwindBin(): string {\n const require = createRequire(import.meta.url);\n const pkgPath = require.resolve(\"@tailwindcss/cli/package.json\");\n const pkg = require(pkgPath) as { bin: string | Record<string, string> };\n const binRel = typeof pkg.bin === \"string\" ? pkg.bin : pkg.bin.tailwindcss;\n return join(dirname(pkgPath), binRel);\n}\n\n/** Compute a cache key from globals.css + theme config content. */\nfunction tailwindCacheKey(): string {\n const globalsPath = join(STYLES_DIR, \"globals.css\");\n const globalsContent = existsSync(globalsPath) ? readFileSync(globalsPath, \"utf-8\") : \"\";\n let themeSuffix = \"\";\n try {\n const themeColors = getThemeConfig();\n if (themeColors) {\n themeSuffix = JSON.stringify(themeColors);\n }\n } catch {\n // theme config unavailable — proceed without it\n }\n return createHash(\"sha256\")\n .update(globalsContent + themeSuffix)\n .digest(\"hex\")\n .slice(0, 16);\n}\n\n/**\n * Build Tailwind CSS with content-based caching.\n * If a CSS file for the current input hash already exists, skip the subprocess.\n * Returns the filename (e.g. \"client-abc123.css\") and CSS content.\n */\nasync function buildTailwindCss(key: string): Promise<{ file: string; content: string }> {\n const cachedFile = `client-${key}.css`;\n const cachedPath = join(ASSETS_DIR, cachedFile);\n\n if (existsSync(cachedPath)) {\n const content = readFileSync(cachedPath, \"utf-8\");\n return { file: cachedFile, content };\n }\n\n const tmpCss = join(ASSETS_DIR, `_tmp-${key}.css`);\n const bin = resolveTailwindBin();\n const twArgs = [\"-i\", join(STYLES_DIR, \"globals.css\"), \"-o\", tmpCss, \"--minify\"];\n const isDeno = \"Deno\" in globalThis;\n const args = isDeno ? [\"run\", \"-A\", bin, ...twArgs] : [bin, ...twArgs];\n try {\n await execFileAsync(process.execPath, args, { maxBuffer: 16 * 1024 * 1024 });\n } catch (err) {\n const stderr = (err as { stderr?: string }).stderr ?? String(err);\n throw new Error(`Tailwind CSS build failed:\\n${stderr}`, { cause: err });\n }\n\n let cssContent = await readFile(tmpCss, \"utf-8\");\n await unlink(tmpCss);\n\n try {\n const themeColors = getThemeConfig();\n if (themeColors) {\n cssContent = buildThemeCss(cssContent, themeColors);\n }\n } catch (err) {\n console.warn(\n `[flame] Failed to resolve theme config, falling back to globals.css only: ${err instanceof Error ? err.message : String(err)}`\n );\n }\n\n // Use the same input-derived key for lookup and output — if inputs change,\n // the key changes, cache busting works without a separate content hash.\n const cssFile = `client-${key}.css`;\n const outPath = join(ASSETS_DIR, cssFile);\n\n if (!existsSync(outPath)) {\n await writeFile(outPath, cssContent);\n }\n\n return { file: cssFile, content: cssContent };\n}\n\nconst NODE_BUILTINS_RE = new RegExp(\n `^(node:.*|${builtinModules.map((m) => m.replace(/\\//g, \"\\\\/\")).join(\"|\")})$`\n);\n\nlet lucideRealEntry: string | undefined;\n\n/** Resolve the real lucide-react entry path once (cached). */\nfunction getLucideRealEntry(): string {\n if (!lucideRealEntry) {\n lucideRealEntry = createRequire(import.meta.url).resolve(\"lucide-react\");\n }\n return lucideRealEntry;\n}\n\nconst LUCIDE_IMPORT_RE = /import\\s*\\{([^}]+)\\}\\s*from\\s*[\"']lucide-react[\"']/g;\nconst LUCIDE_ICON_RE = /^[A-Z]/;\n\n/** Walk a directory scanning JS/TS/TSX files for `lucide-react` named imports. */\nfunction scanDirLucideIcons(dir: string, set: Set<string>): void {\n if (!existsSync(dir)) return;\n try {\n const entries = readdirSync(dir, { withFileTypes: true });\n for (const e of entries) {\n const full = join(dir, e.name);\n if (e.isDirectory()) {\n if (e.name !== \"node_modules\") scanDirLucideIcons(full, set);\n } else if (/\\.(js|ts|tsx)$/.test(e.name)) {\n const content = readFileSync(full, \"utf-8\");\n for (const m of content.matchAll(LUCIDE_IMPORT_RE)) {\n for (const s of m[1].split(\",\")) {\n const name = s\n .trim()\n .split(/\\s+as\\s+/)[0]\n .trim();\n if (LUCIDE_ICON_RE.test(name)) set.add(name);\n }\n }\n }\n }\n } catch (err) {\n console.warn(\n `[flame] Failed to scan lucide icons: ${err instanceof Error ? err.message : String(err)}`\n );\n }\n}\n\n/** Collect every lucide icon name imported across flame sources and deps. */\nfunction collectAllLucideIcons(): string[] {\n const icons = new Set<string>();\n // Scan flame's own components and pages\n scanDirLucideIcons(join(FRAMEWORK_ROOT, \".docu/components\"), icons);\n scanDirLucideIcons(join(FRAMEWORK_ROOT, \".docu/pages\"), icons);\n // Scan dependency dist directories. In development (monorepo) they live under\n // packages/; in production they are under node_modules/@docubook/.\n const depDirs = [\n join(FRAMEWORK_ROOT, \"..\", \"mdx-content\", \"dist\"),\n join(FRAMEWORK_ROOT, \"..\", \"ui-react\", \"dist\"),\n join(FRAMEWORK_ROOT, \"..\", \"core\", \"dist\"),\n join(FRAMEWORK_ROOT, \"..\", \"themes-colors\", \"dist\"),\n ];\n for (const d of depDirs) scanDirLucideIcons(resolve(d), icons);\n return [...icons];\n}\n\n/** Build the client JS bundle and Tailwind CSS. */\nexport async function buildClientBundle(\n /** slug → compiled MDX ESM module source (program format) for static hydration. */\n mdxSources: Record<string, string> = {}\n): Promise<{ js: string; css: string }> {\n await mkdir(ASSETS_DIR, { recursive: true });\n const twKey = tailwindCacheKey();\n await cleanOldBundles(new Set([`client-${twKey}.css`]));\n\n const nodeEnv = process.env.NODE_ENV || \"development\";\n\n const entryPath = join(LIB_DIR, \"client.ts\");\n const bundle = await viteBuild({\n configFile: false,\n publicDir: false,\n define: { \"process.env.NODE_ENV\": JSON.stringify(nodeEnv) },\n plugins: [\n {\n name: \"node-builtin-stub\",\n resolveId(id) {\n if (NODE_BUILTINS_RE.test(id)) return `\\0node-stub:${id}`;\n return null;\n },\n load(id) {\n if (!id.startsWith(\"\\0node-stub:\")) return null;\n return \"export default {}; export {};\";\n },\n },\n {\n name: \"lucide-optimize\",\n resolveId(id, importer) {\n if (id !== \"lucide-react\") return null;\n if (importer) {\n const normalized = normalizeImporterPath(importer);\n if (normalized.includes(\"/markdown/dist/\")) return null;\n }\n return \"\\0lucide-virt\";\n },\n load(id) {\n if (id !== \"\\0lucide-virt\") return null;\n const scanned = collectAllLucideIcons();\n const configured = extractConfigIcons(loadDocuConfig());\n const allIcons = [...new Set([...scanned, ...configured])];\n return `export { ${allIcons.join(\", \")} } from ${JSON.stringify(getLucideRealEntry())};`;\n },\n },\n {\n name: \"docu-config\",\n resolveId(id) {\n if (!/client-routes$/.test(id)) return null;\n return \"\\0client-routes\";\n },\n load(id) {\n if (id !== \"\\0client-routes\") return null;\n const config = loadDocuConfig();\n const resolved = {\n ...config,\n routes: resolveRoutes(config.routes as DocuRoute[] | undefined),\n };\n return [\n `const docuConfig = ${JSON.stringify(resolved)};`,\n `export const routes = docuConfig.routes || [];`,\n `export const config = docuConfig;`,\n ].join(\"\\n\");\n },\n },\n {\n name: \"mdx-hydrate\",\n resolveId(id) {\n if (/mdx-manifest$/.test(id)) return \"\\0mdx-manifest\";\n if (id.startsWith(\"mdx-module:\")) return `\\0${id}`;\n return null;\n },\n load(id) {\n if (id === \"\\0mdx-manifest\") {\n const slugs = Object.keys(mdxSources).sort();\n const imports = slugs\n .map((slug, i) => {\n const key = slug.replace(/[\"\\\\]/g, \"\");\n return `import * as _mdx${i} from ${JSON.stringify(`mdx-module:${key}`)};`;\n })\n .join(\"\\n\");\n const map = slugs.map((slug, i) => `${JSON.stringify(slug)}: _mdx${i}`).join(\", \");\n return `${imports}\\nexport const mdxModules = { ${map} };\\n`;\n }\n if (!id.startsWith(\"\\0mdx-module:\")) return null;\n const slug = id.slice(\"\\0mdx-module:\".length);\n const contents = mdxSources[slug];\n if (contents == null) {\n throw new Error(`unknown mdx module: ${slug}`);\n }\n return contents;\n },\n },\n ],\n build: {\n outDir: ASSETS_DIR,\n emptyOutDir: false,\n sourcemap: true,\n minify: nodeEnv === \"production\",\n target: \"es2020\",\n rollupOptions: {\n input: entryPath,\n output: {\n format: \"es\",\n entryFileNames: \"client-[hash].js\",\n chunkFileNames: \"chunks/[name]-[hash].js\",\n assetFileNames: \"assets/[name]-[hash][extname]\",\n },\n },\n },\n });\n\n const outputs = Array.isArray(bundle) ? bundle : [bundle];\n let jsFile: string | undefined;\n for (const item of outputs) {\n if (!(\"output\" in item)) continue;\n for (const output of item.output) {\n if (\n output.type === \"chunk\" &&\n output.isEntry &&\n output.facadeModuleId &&\n resolve(output.facadeModuleId) === entryPath\n ) {\n jsFile = basename(output.fileName);\n break;\n }\n }\n if (jsFile) break;\n }\n if (!jsFile) {\n throw new Error(\"Client bundle produced no output files\");\n }\n\n const { file: cssFile } = await buildTailwindCss(twKey);\n\n await writeFile(join(ASSETS_DIR, \"manifest.json\"), JSON.stringify({ js: jsFile, css: cssFile }));\n\n return { js: jsFile, css: cssFile };\n}\n","/**\n * Runtime-neutral git helpers — same behavior as the git functions in\n * `utils.ts` (Bun-only, protected) but spawning via `node:child_process`,\n * which works on Bun, Node.js, and Deno. `mdx.ts` imports from here.\n */\n\nimport { execFile } from \"node:child_process\";\nimport { stat } from \"node:fs/promises\";\n\nfunction runGit(args: string[]): Promise<string> {\n return new Promise((resolve, reject) => {\n execFile(\"git\", args, { maxBuffer: 16 * 1024 * 1024 }, (err, stdout) => {\n if (err) reject(err);\n else resolve(stdout);\n });\n });\n}\n\nfunction sanitizePath(filePath: string): string | null {\n const cleanPath = filePath.replace(/^\\//, \"\");\n if (!cleanPath || !/^[a-zA-Z0-9\\-_/.\\s]+$/.test(cleanPath) || /(^|\\/)\\.\\.($|\\/)/.test(cleanPath))\n return null;\n return cleanPath;\n}\n\n/** Get git last modified date for a file */\nexport async function getGitLastModified(filePath: string): Promise<string | null> {\n const cleanPath = sanitizePath(filePath);\n if (!cleanPath) return null;\n try {\n const text = await runGit([\"log\", \"-1\", \"--format=%cI\", \"--\", cleanPath]);\n const date = text.trim();\n return date || null;\n } catch {\n return null;\n }\n}\n\n/**\n * Fallback to filesystem mtime when git is unavailable (shallow clone, no .git, etc.).\n * Returns ISO 8601 date string or null.\n */\nexport async function getFilesystemMtime(filePath: string): Promise<string | null> {\n try {\n const stats = await stat(filePath);\n return stats.mtime.toISOString();\n } catch {\n return null;\n }\n}\n\n/** Batch git last modified dates for multiple files in a single spawn */\nexport async function getGitLastModifiedBatch(filePaths: string[]): Promise<Map<string, string>> {\n const result = new Map<string, string>();\n if (filePaths.length === 0) return result;\n\n const safePaths: string[] = [];\n for (const fp of filePaths) {\n const cleanPath = sanitizePath(fp);\n if (!cleanPath) {\n console.warn(`[git] getGitLastModifiedBatch: skipping invalid path \"${fp}\"`);\n continue;\n }\n safePaths.push(cleanPath);\n }\n\n if (safePaths.length === 0) return result;\n\n try {\n const text = await runGit([\n \"log\",\n \"--format=%cI\",\n \"--name-only\",\n \"--diff-filter=ACMR\",\n ...safePaths,\n ]);\n let currentDate = \"\";\n\n for (const line of text.split(\"\\n\")) {\n const trimmed = line.trim();\n if (!trimmed) continue;\n if (/^\\d{4}-\\d{2}-\\d{2}T/.test(trimmed)) {\n currentDate = trimmed;\n } else if (currentDate && !result.has(trimmed)) {\n result.set(trimmed, currentDate);\n }\n }\n } catch (err) {\n console.error(\"Failed to get git last modified batch for\", filePaths, err);\n }\n\n return result;\n}\n","import React from \"react\";\nimport type { Pluggable } from \"unified\";\nimport { z, type ZodType } from \"zod\";\nimport {\n serialize,\n extractTocsFromRawMdx,\n extractFrontmatterWithContent,\n createDefaultRehypePlugins,\n createDefaultRemarkPlugins,\n MDXRemote,\n} from \"@docubook/core\";\nimport { createMdxComponents } from \"@docubook/markdown\";\nimport { getGitLastModified, getGitLastModifiedBatch, getFilesystemMtime } from \"./git\";\n\n/**\n * Return the value with `.html` appended, or null if the value should be left\n * unchanged. Rules:\n * - Must be a string\n * - Must start with /docs/ (the /docs root index needs no suffix)\n * - Must not be an external URL, contain a fragment, or already end in .html\n */\nfunction appendHtml(value: unknown): string | null {\n if (typeof value !== \"string\") return null;\n if (/^https?:\\/\\//.test(value)) return null;\n if (!value.startsWith(\"/docs/\")) return null;\n if (value.includes(\"#\")) return null;\n if (value.endsWith(\".html\")) return null;\n return `${value}.html`;\n}\n\ninterface HastNode {\n type: string;\n tagName?: string;\n properties?: Record<string, unknown>;\n children?: HastNode[];\n}\n\ninterface MdastNode {\n type: string;\n // MDX JSX nodes carry their props as an attributes array\n attributes?: { type: string; name: string; value: unknown }[];\n children?: MdastNode[];\n}\n\n/**\n * Rehype plugin: append `.html` to internal `/docs/` hrefs on HTML `<a>` nodes.\n *\n * This covers standard markdown links: `[text](/docs/page)` → `<a href=\"…\">`.\n * It runs in the HAST (HTML AST) phase, where `<a>` elements are real nodes.\n *\n * Skips: external URLs, anchor-only links, paths that already end in `.html`,\n * and the `/docs` root index (no trailing slash segment).\n */\nfunction rehypeDocsHtmlLinks() {\n return (tree: HastNode) => {\n function walk(node: HastNode): void {\n if (node.type === \"element\" && node.tagName === \"a\") {\n const fixed = appendHtml(node.properties?.href);\n if (fixed) node.properties!.href = fixed;\n }\n if (node.children) {\n for (const child of node.children) walk(child);\n }\n }\n walk(tree);\n return tree;\n };\n}\n\n/**\n * Remark plugin: append `.html` to internal `/docs/` hrefs on MDX JSX nodes.\n *\n * MDX JSX elements (`<Card href=\"…\">`, `<LinkCard href=\"…\">`, etc.) live in\n * the MDAST as `mdxJsxFlowElement` / `mdxJsxTextElement` nodes. They are\n * compiled directly to JavaScript by the MDX compiler *before* rehype runs,\n * so a rehype plugin can never see them as `<a>` elements. This remark plugin\n * intercepts them at the MDAST phase where their `attributes` array is still\n * accessible and mutable.\n *\n * Skips: same rules as `appendHtml` (external URLs, anchors, already `.html`).\n */\nfunction remarkMdxJsxDocsHtmlLinks() {\n return (tree: MdastNode) => {\n function walk(node: MdastNode): void {\n if (\n (node.type === \"mdxJsxFlowElement\" || node.type === \"mdxJsxTextElement\") &&\n node.attributes\n ) {\n for (const attr of node.attributes) {\n if (attr.type === \"mdxJsxAttribute\" && attr.name === \"href\") {\n const fixed = appendHtml(attr.value);\n if (fixed) attr.value = fixed;\n }\n }\n }\n if (node.children) {\n for (const child of node.children) walk(child);\n }\n }\n walk(tree);\n return tree;\n };\n}\n\nexport { getGitLastModifiedBatch };\n\nexport interface MdxResult {\n content: React.ReactElement;\n compiledSource: string;\n frontmatter: Frontmatter;\n tocs: ReturnType<typeof extractTocsFromRawMdx>;\n}\n\n/**\n * DocuBook frontmatter contract — single source of truth for frontmatter\n * fields. Add new properties here; types and validation derive from it.\n * YAML coerces unquoted values, so string fields use `z.coerce.*`.\n * `.passthrough()` keeps unknown fields (e.g. `author: wildan`, `tags`)\n * in the parsed output — arbitrary frontmatter metadata stays available\n * via `frontmatterField(frontmatter, key)` instead of being silently\n * stripped by Zod's default object parsing.\n */\nexport const frontmatterSchema = z\n .object({\n title: z.coerce.string().optional(),\n description: z.coerce.string().optional(),\n image: z.coerce.string().optional(),\n date: z.coerce.string().optional(),\n })\n .passthrough();\n\nexport type Frontmatter = z.infer<typeof frontmatterSchema>;\n\n/**\n * Read a string field from frontmatter after the plugin transform chain\n * (which widens the type to `Record<string, unknown>`). Returns \"\" when\n * missing or not a string.\n */\nexport function frontmatterField(frontmatter: Record<string, unknown>, key: string): string {\n return typeof frontmatter[key] === \"string\" ? (frontmatter[key] as string) : \"\";\n}\n\n/**\n * Zod schema validating frontmatter after extraction.\n * Must satisfy the frontmatter contract (defaults to `frontmatterSchema`).\n */\nexport type FrontmatterSchema = ZodType<Frontmatter>;\n\n/**\n * Compile MDX/MD content into a React element and compiled source.\n *\n * @param rawMdx - Raw MDX/MD file content\n * @param filePath - Relative file path for git date lookup\n * @param gitDates - Optional pre-fetched git last-modified map\n * @param remarkPlugins - Additional remark plugins (merged after defaults, optional)\n * @param rehypePlugins - Additional rehype plugins (merged after defaults, optional)\n * @param frontmatterSchema - Custom schema overriding the default contract\n */\n/**\n * Shared compile core used by `compileMdx` (SSR) and `compileMdxModule`\n * (static hydration). Strips frontmatter, merges the doc plugin chain\n * (defaults + .html link fixes + user plugins) and runs `serialize()`.\n */\nasync function serializeWithDocPlugins(\n rawMdx: string,\n opts: {\n outputFormat?: \"function-body\" | \"program\";\n remarkPlugins?: Pluggable[];\n rehypePlugins?: Pluggable[];\n frontmatterSchema?: FrontmatterSchema;\n } = {},\n pre?: { frontmatter: Frontmatter; strippedContent: string }\n) {\n // Parse-once: when the prePass already extracted the frontmatter + stripped\n // content, reuse it instead of re-parsing (the SSR phase skips extraction).\n const { strippedContent, frontmatter } =\n pre ?? extractFrontmatterWithContent<Frontmatter>(rawMdx, opts.frontmatterSchema);\n\n const defaultRemark = createDefaultRemarkPlugins();\n const defaultRehype = createDefaultRehypePlugins();\n\n // remarkMdxJsxDocsHtmlLinks must run before user plugins so custom remark\n // transforms see already-fixed hrefs. rehypeDocsHtmlLinks handles plain\n // markdown [text](path) → <a> elements in the HAST phase.\n const finalRemark = [...defaultRemark, remarkMdxJsxDocsHtmlLinks, ...(opts.remarkPlugins ?? [])];\n const finalRehype = [...defaultRehype, rehypeDocsHtmlLinks, ...(opts.rehypePlugins ?? [])];\n\n // v2 contract: plain markdown + directives only — authored JSX tags are\n // not parsed (dropped, content kept as text). Return the frontmatter parsed\n // above — `serialize()` only parses it when `parseFrontmatter` is set.\n return serialize(strippedContent, {\n outputFormat: opts.outputFormat,\n format: \"md\",\n mdxOptions: {\n rehypePlugins: finalRehype,\n remarkPlugins: finalRemark,\n },\n }).then((serialized) => ({ ...serialized, frontmatter, strippedContent }));\n}\n\n/**\n * Compile MDX/MD content into a React element and compiled source.\n *\n * @param rawMdx - Raw MDX/MD file content\n * @param filePath - Relative file path for git date lookup\n * @param gitDates - Optional pre-fetched git last-modified map\n * @param remarkPlugins - Additional remark plugins (merged after defaults, optional)\n * @param rehypePlugins - Additional rehype plugins (merged after defaults, optional)\n * @param frontmatterSchema - Custom schema overriding the default contract\n */\nexport async function compileMdx(\n rawMdx: string,\n filePath: string,\n gitDates?: Map<string, string>,\n remarkPlugins?: Pluggable[],\n rehypePlugins?: Pluggable[],\n frontmatterSchema?: FrontmatterSchema,\n /** Pre-pass extracted data — avoids re-parsing frontmatter in the SSR phase. */\n pre?: { frontmatter: Frontmatter; strippedContent: string }\n): Promise<MdxResult> {\n const tocs = extractTocsFromRawMdx(rawMdx);\n const frontmatter =\n pre?.frontmatter ??\n extractFrontmatterWithContent<Frontmatter>(rawMdx, frontmatterSchema).frontmatter;\n const serialized = await serializeWithDocPlugins(\n rawMdx,\n { remarkPlugins, rehypePlugins, frontmatterSchema },\n pre\n );\n\n const components = createMdxComponents();\n const content = React.createElement(MDXRemote, {\n compiledSource: serialized.compiledSource,\n scope: {},\n frontmatter: {},\n components,\n });\n\n const date =\n frontmatter.date ||\n gitDates?.get(filePath) ||\n (await getGitLastModified(filePath)) ||\n (await getFilesystemMtime(filePath)) ||\n undefined;\n\n return {\n content,\n compiledSource: serialized.compiledSource,\n frontmatter: { ...frontmatter, date },\n tocs,\n };\n}\n\n/**\n * Compile MDX to a real ESM module source (program format) for static\n * client-side hydration — the browser imports and executes it via the bundler\n * instead of `new Function(compiledSource)`. Uses the same plugin chain as\n * `compileMdx` so the hydrated tree matches the SSR output.\n */\n/**\n * Frontmatter records collected once during compilation — pagination title /\n * description and other metadata consumers read from here instead of\n * re-reading + re-parsing files (parse-once contract: the frontmatter is\n * already parsed by `serializeWithDocPlugins`).\n */\nconst pageFrontmatter = new Map<string, Frontmatter>();\n\n/** Register a page's frontmatter, keyed by its href. */\nexport function registerPageFrontmatter(href: string, frontmatter: Frontmatter): void {\n pageFrontmatter.set(href, frontmatter);\n}\n\n/** Look up a page's frontmatter (undefined when not yet compiled). */\nexport function getPageFrontmatter(href: string): Frontmatter | undefined {\n return pageFrontmatter.get(href);\n}\n\n/**\n * Frontmatter-stripped content from the prePass — lets the SSR compile\n * phase skip its own `extractFrontmatterWithContent` (parse-once across\n * both compile phases).\n */\nconst pageStripped = new Map<string, string>();\n\nexport function registerPageStripped(href: string, stripped: string): void {\n pageStripped.set(href, stripped);\n}\n\nexport function getPageStripped(href: string): string | undefined {\n return pageStripped.get(href);\n}\n\n/**\n * Original (pre-transform) file content, cached during the prePass so the\n * page loop does not re-read the file from disk — one read per file.\n */\nconst pageContent = new Map<string, string>();\n\nexport function registerPageContent(href: string, raw: string): void {\n pageContent.set(href, raw);\n}\n\nexport function getPageContent(href: string): string | undefined {\n return pageContent.get(href);\n}\n\nexport async function compileMdxModule(\n rawMdx: string,\n remarkPlugins?: Pluggable[],\n rehypePlugins?: Pluggable[],\n /** Page href — registers the frontmatter (title/description/image/date)\n * once for pagination and metadata consumers. */\n href?: string\n): Promise<string> {\n const serialized = await serializeWithDocPlugins(rawMdx, {\n outputFormat: \"program\",\n remarkPlugins,\n rehypePlugins,\n });\n if (href) {\n registerPageFrontmatter(href, serialized.frontmatter as Frontmatter);\n registerPageStripped(href, serialized.strippedContent);\n }\n return serialized.compiledSource;\n}\n","/**\n * Search Index Generator\n *\n * Scans MDX files at build-time and produces a search-index.json\n * with hierarchy-based records (similar to Algolia DocSearch crawler).\n *\n * Hierarchy levels:\n * lvl0 = section (parent route title)\n * lvl1 = page title (frontmatter title or h1)\n * lvl2-lvl6 = headings h2-h6\n * content = first paragraph/list items after each heading\n */\n\nimport { readFile, writeFile, mkdir } from \"node:fs/promises\";\nimport { resolve, join } from \"node:path\";\nimport { getPageContent } from \"./mdx\";\nimport { extractFrontmatterWithContent } from \"@docubook/core\";\nimport { frontmatterField } from \"./mdx\";\nimport { DOCS_DIR, ASSETS_DIR, loadDocuConfig } from \"./paths\";\nimport { scanMdxFiles, docsHtmlHref } from \"./utils\";\n\nconst docuConfig = loadDocuConfig();\n\nexport interface SearchRecord {\n url: string;\n hierarchy: {\n lvl0: string;\n lvl1: string | null;\n lvl2: string | null;\n lvl3: string | null;\n lvl4: string | null;\n lvl5: string | null;\n lvl6: string | null;\n };\n content: string | null;\n type: \"lvl0\" | \"lvl1\" | \"lvl2\" | \"lvl3\" | \"lvl4\" | \"lvl5\" | \"lvl6\" | \"content\";\n}\n\ninterface Frontmatter {\n title?: string;\n description?: string;\n}\n\nfunction getSectionTitle(filePath: string): string {\n const parts = filePath.split(\"/\");\n if (parts.length > 1) {\n const section = docuConfig.routes?.find(\n (r) => r.href === `/${parts[0]}` || r.href === parts[0]\n );\n if (section) return section.title;\n }\n return docuConfig.meta?.title || \"Docs\";\n}\n\nfunction slugify(text: string): string {\n return text\n .toLowerCase()\n .replace(/[^a-z0-9]+/g, \"-\")\n .replace(/^-+|-+$/g, \"\");\n}\n\nexport function stripJsx(content: string): string {\n let result = content;\n let prev = \"\";\n while (result !== prev) {\n prev = result;\n result = result\n .replace(/<[A-Z][\\w.]*[\\s\\S]*?\\/>/g, \"\")\n .replace(/<[A-Z][\\w.]*[\\s\\S]*?>([\\s\\S]*?)<\\/[A-Z][\\w.]*>/g, \"$1\");\n }\n return result;\n}\n\nexport function extractRecords(filePath: string, raw: string): SearchRecord[] {\n const { frontmatter, strippedContent: content } = extractFrontmatterWithContent<Frontmatter>(raw);\n const records: SearchRecord[] = [];\n const url = docsHtmlHref(`/docs/${filePath}`);\n const lvl0 = getSectionTitle(filePath);\n const lvl1 = frontmatterField(frontmatter, \"title\") || null;\n\n const hierarchy = {\n lvl0,\n lvl1,\n lvl2: null as string | null,\n lvl3: null as string | null,\n lvl4: null as string | null,\n lvl5: null as string | null,\n lvl6: null as string | null,\n };\n\n if (lvl1) {\n records.push({\n url,\n hierarchy: { ...hierarchy },\n content: frontmatterField(frontmatter, \"description\") || null,\n type: \"lvl1\",\n });\n }\n\n const plainContent = stripJsx(content);\n const lines = plainContent.split(\"\\n\");\n let currentParagraph: string[] = [];\n let inCodeBlock = false;\n\n const flushParagraph = () => {\n if (currentParagraph.length > 0) {\n const text = currentParagraph.join(\" \").trim();\n if (text) {\n records.push({\n url: buildAnchorUrl(),\n hierarchy: { ...hierarchy },\n content: text,\n type: \"content\",\n });\n }\n currentParagraph = [];\n }\n };\n\n const buildAnchorUrl = () => {\n for (let i = 6; i >= 2; i--) {\n const key = `lvl${i}` as keyof typeof hierarchy;\n if (hierarchy[key]) return `${url}#${slugify(hierarchy[key]!)}`;\n }\n return url;\n };\n\n for (const line of lines) {\n const trimmed = line.trim();\n\n if (trimmed.startsWith(\"```\")) {\n inCodeBlock = !inCodeBlock;\n continue;\n }\n if (inCodeBlock) continue;\n\n if (/^import\\s+[\\w{*]/.test(trimmed) || /^export\\s+[\\w{*]/.test(trimmed)) continue;\n\n const headingMatch = trimmed.match(/^(#{1,6})\\s+(.+)$/);\n if (headingMatch) {\n flushParagraph();\n const level = headingMatch[1].length;\n const title = headingMatch[2].replace(/[*`[\\]]/g, \"\").trim();\n\n for (let i = level; i <= 6; i++) {\n (hierarchy as Record<string, string | null>)[`lvl${i}`] = null;\n }\n hierarchy[`lvl${level}` as keyof typeof hierarchy] = title;\n\n if (level === 1 && !hierarchy.lvl1) {\n hierarchy.lvl1 = title;\n }\n\n if (level >= 2) {\n records.push({\n url: `${url}#${slugify(title)}`,\n hierarchy: { ...hierarchy },\n content: null,\n type: `lvl${level}` as SearchRecord[\"type\"],\n });\n }\n continue;\n }\n\n if (trimmed === \"\" || trimmed === \"---\") {\n flushParagraph();\n continue;\n }\n\n if (/^\\|.+\\|/.test(trimmed)) continue;\n\n const cleaned = trimmed\n .replace(/^[-*+]\\s+/, \"\") // list markers\n .replace(/^\\d+\\.\\s+/, \"\") // ordered list\n .replace(/^>\\s+/, \"\") // blockquote\n .replace(/\\*\\*([^*]+)\\*\\*/g, \"$1\")\n .replace(/\\*([^*]+)\\*/g, \"$1\")\n .replace(/`([^`]+)`/g, \"$1\")\n .replace(/\\[([^\\]]+)\\]\\([^)]+\\)/g, \"$1\")\n .trim();\n\n if (cleaned) currentParagraph.push(cleaned);\n }\n\n flushParagraph();\n return records;\n}\n\nexport async function generateSearchIndex(docsDir?: string, outputDir?: string): Promise<number> {\n const docs = resolve(docsDir || DOCS_DIR);\n const dist = resolve(outputDir || ASSETS_DIR);\n await mkdir(dist, { recursive: true });\n\n const mdxFiles = await scanMdxFiles(docs);\n const results = await Promise.all(\n mdxFiles.map(async (file) => {\n // Parse-once: reuse the prePass-cached raw content when available —\n // no second disk read of every file.\n const raw = getPageContent(`/${file.path}`) ?? (await readFile(file.absPath, \"utf-8\"));\n return extractRecords(file.path, raw);\n })\n );\n const allRecords = results.flat();\n\n await writeFile(join(dist, \"search-index.json\"), JSON.stringify(allRecords));\n return allRecords.length;\n}\n","/**\n * Optional Sentry error tracking integration.\n * Active only when SENTRY_DSN environment variable is set.\n * Requires @sentry/bun as an optional peer dependency.\n */\n\nlet sentry: typeof import(\"@sentry/bun\") | null = null;\nlet initialized = false;\n\nexport async function initSentry(): Promise<void> {\n const dsn = process.env.SENTRY_DSN;\n if (!dsn) return;\n\n try {\n sentry = await import(\"@sentry/bun\");\n sentry.init({\n dsn,\n environment: process.env.NODE_ENV || \"development\",\n release: process.env.SENTRY_RELEASE || undefined,\n });\n initialized = true;\n } catch {\n // @sentry/bun not installed — silently skip\n sentry = null;\n initialized = false;\n }\n}\n\nexport function captureException(err: unknown, context?: Record<string, unknown>): void {\n if (!initialized || !sentry) return;\n sentry.captureException(err, context ? { extra: context } : undefined);\n}\n\nexport function isEnabled(): boolean {\n return initialized;\n}\n","import {\n Breadcrumb,\n BreadcrumbItem,\n BreadcrumbList,\n BreadcrumbPage,\n} from \"@docubook/ui-react/breadcrumbs\";\n\nexport interface DocsBreadcrumbProps {\n paths: string[];\n}\n\nfunction toTitleCase(input: string): string {\n return input\n .split(\"-\")\n .map((word) => word.charAt(0).toUpperCase() + word.slice(1))\n .join(\" \");\n}\n\nexport default function DocsBreadcrumb({ paths }: DocsBreadcrumbProps) {\n return (\n <Breadcrumb className=\"py-4\">\n <BreadcrumbList>\n <BreadcrumbItem>\n <span className=\"text-muted-foreground\">Docs</span>\n </BreadcrumbItem>\n {paths.map((path, index) => (\n <BreadcrumbItem key={`${path}-${index}`}>\n {index < paths.length - 1 ? (\n <span className=\"text-muted-foreground\">{toTitleCase(path)}</span>\n ) : (\n <BreadcrumbPage className=\"text-base-content\">{toTitleCase(path)}</BreadcrumbPage>\n )}\n </BreadcrumbItem>\n ))}\n </BreadcrumbList>\n </Breadcrumb>\n );\n}\n","import { loadDocuConfig } from \"./paths\";\nimport type { DocuRoute } from \"./types\";\nimport { resolveRoutes } from \"./fs-scanner\";\nimport { DOCS_DIR } from \"./paths\";\nimport { readFileSync } from \"node:fs\";\nimport { join } from \"node:path\";\nimport { extractFrontmatter } from \"@docubook/core\";\nimport { getPageFrontmatter, registerPageFrontmatter } from \"./mdx\";\nimport type { Frontmatter } from \"./mdx\";\n\nconst docuConfig = loadDocuConfig();\nexport const routes: DocuRoute[] = resolveRoutes(docuConfig.routes);\n\nexport function flattenRoutes(): string[] {\n const paths: string[] = [];\n\n function traverse(route: DocuRoute, section = \"\") {\n const fullPath = route.href.startsWith(section)\n ? route.href\n : `${section}${route.href}`.replace(/\\/+/g, \"/\");\n if (route.href && !route.noLink) {\n paths.push(fullPath);\n }\n if (route.items) {\n route.items.forEach((item) => traverse(item, fullPath));\n }\n }\n\n routes.forEach((route) => traverse(route));\n return paths;\n}\n\nexport function getRouteMap(): Map<string, string> {\n const map = new Map<string, string>();\n\n function traverse(route: DocuRoute, section = \"\") {\n const fullPath = route.href.startsWith(section)\n ? route.href\n : `${section}${route.href}`.replace(/\\/+/g, \"/\");\n map.set(fullPath, route.title);\n if (route.items) {\n route.items.forEach((item) => traverse(item, fullPath));\n }\n }\n\n routes.forEach((route) => traverse(route));\n return map;\n}\n\n/**\n * Frontmatter for a page — read from the parse-once registry (populated\n * during compilation) instead of re-reading + re-parsing the file. Falls\n * back to a direct read only for pages the dev server has not compiled yet,\n * and caches the result back into the registry.\n */\nfunction readPageFrontmatter(href: string): Frontmatter {\n const registered = getPageFrontmatter(href);\n if (registered) return registered;\n\n let fm: Frontmatter = {};\n const rel = href.replace(/^\\/|$/g, \"\");\n for (const ext of [\".mdx\", \".md\"]) {\n for (const file of [join(DOCS_DIR, `${rel}${ext}`), join(DOCS_DIR, `${rel}/index${ext}`)]) {\n try {\n fm = extractFrontmatter<Frontmatter>(readFileSync(file, \"utf-8\"));\n break;\n } catch {\n // not this file — try the next candidate\n }\n }\n if (Object.keys(fm).length) break;\n }\n registerPageFrontmatter(href, fm);\n return fm;\n}\n\nexport function getPreviousNext(pathname: string) {\n const normalizedPath = pathname.replace(/^\\/|$/g, \"\");\n\n // Docs index (/docs — DocsPage renders with pathname \"\" from slug []):\n // next-only navigation into the first docs page — never read the route\n // backward from the index, so prev stays null even if a page sits before\n // it in the route list.\n if (normalizedPath === \"docs\" || normalizedPath === \"\") {\n const paths = flattenRoutes();\n const routeMap = getRouteMap();\n const first = paths[0];\n if (!first) return { prev: null, next: null };\n const fm = readPageFrontmatter(first);\n return {\n prev: null,\n next: {\n href: first,\n title: fm.title || routeMap.get(first) || \"\",\n description: fm.description || \"\",\n },\n };\n }\n\n const paths = flattenRoutes();\n\n const index = paths.findIndex((href) => href === `/${normalizedPath}` || href === normalizedPath);\n\n if (index === -1) {\n return { prev: null, next: null };\n }\n\n const routeMap = getRouteMap();\n const prevHref = index > 0 ? paths[index - 1] : null;\n const nextHref = index < paths.length - 1 ? paths[index + 1] : null;\n\n const prevFm = prevHref ? readPageFrontmatter(prevHref) : null;\n const nextFm = nextHref ? readPageFrontmatter(nextHref) : null;\n return {\n prev: prevHref\n ? { href: prevHref, title: prevFm?.title || routeMap.get(prevHref) || \"\" }\n : null,\n next: nextHref\n ? {\n href: nextHref,\n title: nextFm?.title || routeMap.get(nextHref) || \"\",\n description: nextFm?.description || \"\",\n }\n : null,\n };\n}\n\nexport function getPagination(currentPath: string) {\n return getPreviousNext(currentPath);\n}\n\nexport function getSection(pathname: string): string {\n const parts = pathname.split(\"/\").filter(Boolean);\n return parts[0] || \"home\";\n}\n","\"use client\";\n\nimport type { ReactNode } from \"react\";\nimport { getPreviousNext } from \"../node/route\";\nimport { docsHtmlHref } from \"../node/utils\";\nimport { PaginationDocs } from \"@docubook/ui-react/pagination\";\n\ninterface PaginationProps {\n pathname: string;\n className?: string;\n prevIcon?: ReactNode;\n nextIcon?: ReactNode;\n linkClassName?: string;\n}\n\nexport default function Pagination({\n pathname,\n className,\n prevIcon,\n nextIcon,\n linkClassName,\n}: PaginationProps) {\n const { prev, next } = getPreviousNext(pathname);\n\n if (!prev && !next) {\n return null;\n }\n\n return (\n <PaginationDocs\n prev={prev ? { href: docsHtmlHref(`/docs${prev.href}`), title: prev.title } : undefined}\n next={\n next\n ? {\n href: docsHtmlHref(`/docs${next.href}`),\n title: next.title,\n description: next.description,\n }\n : undefined\n }\n className={className}\n prevIcon={prevIcon}\n nextIcon={nextIcon}\n linkClassName={linkClassName}\n />\n );\n}\n","import { PropsWithChildren } from \"react\";\n\nexport function Typography({ children }: PropsWithChildren) {\n return (\n <div className=\"prose prose-zinc dark:prose-invert prose-code:font-code dark:prose-code:bg-stone-900/25 prose-code:bg-stone-50 prose-pre:bg-background max-lg:prose-headings:scroll-mt-16 prose-headings:scroll-mt-4 prose-code:text-sm prose-code:leading-6 dark:prose-code:text-white prose-code:text-stone-800 prose-code:p-1 prose-code:rounded-md prose-code:border prose-img:rounded-md prose-img:border prose-code:before:content-none prose-code:after:content-none prose-code:px-1.5 prose-code:overflow-x-auto prose-img:my-3 prose-h2:my-4 prose-h2:mt-8 w-full max-w-full! pt-2\">\n {children}\n </div>\n );\n}\n","import { loadDocuConfig } from \"./paths\";\nimport type { SocialLink } from \"./types\";\n\nconst docuConfig = loadDocuConfig();\n\nexport function getEditLink(url: string, filePath: string): string {\n const configPath = docuConfig?.repo?.path || detectPlatformPath(url);\n const encodedPath = filePath.replace(/^\\//, \"\").split(\"/\").map(encodeURIComponent).join(\"/\");\n return `${url}/${configPath}`.replace(\"{filePath}\", encodedPath);\n}\n\n/**\n * Detect the default edit path template from the repo URL hostname.\n * Supports GitHub, GitLab, Bitbucket, Gitea (cloud + self-hosted),\n * Gogs, Forgejo, and Codeberg.\n * Falls back to Gitea-style for unknown hosts — override via repo.path.\n */\nexport function detectPlatformPath(url: string): string {\n try {\n const host = new URL(url).hostname;\n if (host === \"github.com\") return \"blob/main/{filePath}\";\n if (host === \"gitlab.com\") return \"-/blob/main/{filePath}\";\n if (host === \"bitbucket.org\") return \"src/main/{filePath}\";\n if (host === \"gitea.com\") return \"src/branch/main/{filePath}\";\n if (host === \"codeberg.org\") return \"src/branch/main/{filePath}\";\n // Gogs, Forgejo, or any self-hosted Gitea-compatible forge\n return \"src/branch/main/{filePath}\";\n } catch {\n return \"blob/main/{filePath}\";\n }\n}\n\nexport function isEditEnabled(): boolean {\n return docuConfig?.repo?.edit ?? false;\n}\n\nexport function getRepoUrl(): string {\n return docuConfig?.repo?.url || \"\";\n}\n\nexport function getSocialLinks(): SocialLink[] {\n return docuConfig?.footer?.social || [];\n}\n","import { SquarePen } from \"lucide-react\";\nimport { isEditEnabled, getEditLink, getRepoUrl } from \"../node/helpers\";\n\nexport interface EditWithProps {\n filePath: string;\n text?: string;\n className?: string;\n}\n\nexport default function EditWith({\n filePath,\n text = \"Edit this page\",\n className = \"\",\n}: EditWithProps) {\n if (!isEditEnabled()) return null;\n\n const repoUrl = getRepoUrl();\n if (!repoUrl) return null;\n\n const editUrl = getEditLink(repoUrl, filePath);\n\n return (\n <div className={`text-right text-sm ${className}`}>\n <a\n href={editUrl}\n target=\"_blank\"\n rel=\"noopener noreferrer\"\n aria-label=\"Edit this page\"\n className=\"flex items-center gap-1 no-underline\"\n >\n <SquarePen className=\"h-4 w-4\" />\n {text}\n </a>\n </div>\n );\n}\n","import { getSocialLinks } from \"../node/helpers\";\n\nexport interface SocialProps {\n className?: string;\n size?: number;\n}\n\nfunction createIcon(pathData: string) {\n return function Icon({ className = \"\", size = 20 }: { className?: string; size?: number }) {\n return (\n <svg\n className={className}\n width={size}\n height={size}\n viewBox=\"0 0 24 24\"\n xmlns=\"http://www.w3.org/2000/svg\"\n fill=\"currentColor\"\n >\n <path d={pathData} />\n </svg>\n );\n };\n}\n\nconst GithubIcon = createIcon(\n \"M12 .297c-6.63 0-12 5.373-12 12 0 5.303 3.438 9.8 8.205 11.385.6.113.82-.258.82-.577 0-.285-.01-1.04-.015-2.04-3.338.724-4.042-1.61-4.042-1.61C4.422 18.07 3.633 17.7 3.633 17.7c-1.087-.744.084-.729.084-.729 1.205.084 1.838 1.236 1.838 1.236 1.07 1.835 2.809 1.305 3.495.998.108-.776.417-1.305.76-1.605-2.665-.3-5.466-1.332-5.466-5.93 0-1.31.465-2.38 1.235-3.22-.135-.303-.54-1.523.105-3.176 0 0 1.005-.322 3.3 1.23.96-.267 1.98-.399 3-.405 1.02.006 2.04.138 3 .405 2.28-1.552 3.285-1.23 3.285-1.23.645 1.653.24 2.873.12 3.176.765.84 1.23 1.91 1.23 3.22 0 4.61-2.805 5.625-5.475 5.92.42.36.81 1.096.81 2.22 0 1.606-.015 2.896-.015 3.286 0 .315.21.69.825.57C20.565 22.092 24 17.592 24 12.297c0-6.627-5.373-12-12-12\"\n);\nconst BitbucketIcon = createIcon(\n \"M.778 1.213a.768.768 0 00-.768.892l3.263 19.81c.084.5.515.868 1.022.873H19.95a.772.772 0 00.77-.646l3.27-20.03a.768.768 0 00-.768-.891zM14.52 15.53H9.522L8.17 8.466h7.561z\"\n);\nconst GitlabIcon = createIcon(\n \"m23.6004 9.5927-.0337-.0862L20.3.9814a.851.851 0 0 0-.3362-.405.8748.8748 0 0 0-.9997.0539.8748.8748 0 0 0-.29.4399l-2.2055 6.748H7.5375l-2.2057-6.748a.8573.8573 0 0 0-.29-.4412.8748.8748 0 0 0-.9997-.0537.8585.8585 0 0 0-.3362.4049L.4332 9.5015l-.0325.0862a6.0657 6.0657 0 0 0 2.0119 7.0105l.0113.0087.03.0213 4.976 3.7264 2.462 1.8633 1.4995 1.1321a1.0085 1.0085 0 0 0 1.2197 0l1.4995-1.1321 2.4619-1.8633 5.006-3.7489.0125-.01a6.0682 6.0682 0 0 0 2.0094-7.003z\"\n);\nconst NpmIcon = createIcon(\n \"M1.763 0C.786 0 0 .786 0 1.763v20.474C0 23.214.786 24 1.763 24h20.474c.977 0 1.763-.786 1.763-1.763V1.763C24 .786 23.214 0 22.237 0zM5.13 5.323l13.837.019-.009 13.836h-3.464l.01-10.382h-3.456L12.04 19.17H5.113z\"\n);\nconst YoutubeIcon = createIcon(\n \"M23.498 6.186a3.016 3.016 0 0 0-2.122-2.136C19.505 3.545 12 3.545 12 3.545s-7.505 0-9.377.505A3.017 3.017 0 0 0 .502 6.186C0 8.07 0 12 0 12s0 3.93.502 5.814a3.016 3.016 0 0 0 2.122 2.136c1.871.505 9.376.505 9.376.505s7.505 0 9.377-.505a3.015 3.015 0 0 0 2.122-2.136C24 15.93 24 12 24 12s0-3.93-.502-5.814zM9.545 15.568V8.432L15.818 12l-6.273 3.568z\"\n);\nconst TwitterIcon = createIcon(\n \"M14.234 10.162 22.977 0h-2.072l-7.591 8.824L7.251 0H.258l9.168 13.343L.258 24H2.33l8.016-9.318L16.749 24h6.993zm-2.837 3.299-.929-1.329L3.076 1.56h3.182l5.965 8.532.929 1.329 7.754 11.09h-3.182z\"\n);\nconst InstagramIcon = createIcon(\n \"M7.0301.084c-1.2768.0602-2.1487.264-2.911.5634-.7888.3075-1.4575.72-2.1228 1.3877-.6652.6677-1.075 1.3368-1.3802 2.127-.2954.7638-.4956 1.6365-.552 2.914-.0564 1.2775-.0689 1.6882-.0626 4.947.0062 3.2586.0206 3.6671.0825 4.9473.061 1.2765.264 2.1482.5635 2.9107.308.7889.72 1.4573 1.388 2.1228.6679.6655 1.3365 1.0743 2.1285 1.38.7632.295 1.6361.4961 2.9134.552 1.2773.056 1.6884.069 4.9462.0627 3.2578-.0062 3.668-.0207 4.9478-.0814 1.28-.0607 2.147-.2652 2.9098-.5633.7889-.3086 1.4578-.72 2.1228-1.3881.665-.6682 1.0745-1.3378 1.3795-2.1284.2957-.7632.4966-1.636.552-2.9124.056-1.2809.0692-1.6898.063-4.948-.0063-3.2583-.021-3.6668-.0817-4.9465-.0607-1.2797-.264-2.1487-.5633-2.9117-.3084-.7889-.72-1.4568-1.3876-2.1228C21.2982 1.33 20.628.9208 19.8378.6165 19.074.321 18.2017.1197 16.9244.0645 15.6471.0093 15.236-.005 11.977.0014 8.718.0076 8.31.0215 7.0301.0839m.1402 21.6932c-1.17-.0509-1.8053-.2453-2.2287-.408-.5606-.216-.96-.4771-1.3819-.895-.422-.4178-.6811-.8186-.9-1.378-.1644-.4234-.3624-1.058-.4171-2.228-.0595-1.2645-.072-1.6442-.079-4.848-.007-3.2037.0053-3.583.0607-4.848.05-1.169.2456-1.805.408-2.2282.216-.5613.4762-.96.895-1.3816.4188-.4217.8184-.6814 1.3783-.9003.423-.1651 1.0575-.3614 2.227-.4171 1.2655-.06 1.6447-.072 4.848-.079 3.2033-.007 3.5835.005 4.8495.0608 1.169.0508 1.8053.2445 2.228.408.5608.216.96.4754 1.3816.895.4217.4194.6816.8176.9005 1.3787.1653.4217.3617 1.056.4169 2.2263.0602 1.2655.0739 1.645.0796 4.848.0058 3.203-.0055 3.5834-.061 4.848-.051 1.17-.245 1.8055-.408 2.2294-.216.5604-.4763.96-.8954 1.3814-.419.4215-.8181.6811-1.3783.9-.4224.1649-1.0577.3617-2.2262.4174-1.2656.0595-1.6448.072-4.8493.079-3.2045.007-3.5825-.006-4.848-.0608M16.953 5.5864A1.44 1.44 0 1 0 18.39 4.144a1.44 1.44 0 0 0-1.437 1.4424M5.8385 12.012c.0067 3.4032 2.7706 6.1557 6.173 6.1493 3.4026-.0065 6.157-2.7701 6.1506-6.1733-.0065-3.4032-2.771-6.1565-6.174-6.1498-3.403.0067-6.156 2.771-6.1496 6.1738M8 12.0077a4 4 0 1 1 4.008 3.9921A3.9996 3.9996 0 0 1 8 12.0077\"\n);\nconst LinkedinIcon = createIcon(\n \"M20.447 20.452h-3.554v-5.569c0-1.328-.027-3.037-1.852-3.037-1.853 0-2.136 1.445-2.136 2.939v5.667H9.351V9h3.414v1.561h.046c.477-.9 1.637-1.85 3.37-1.85 3.601 0 4.267 2.37 4.267 5.455v6.528zM5.337 7.433c-1.144 0-2.063-.926-2.063-2.065 0-1.138.92-2.063 2.063-2.063 1.14 0 2.064.925 2.064 2.063 0 1.139-.925 2.065-2.064 2.065zm1.782 13.019H3.555V9h3.564v11.452zM22.225 0H1.771C.792 0 0 .774 0 1.729v20.542C0 23.226.792 24 1.771 24h20.451C23.2 24 24 23.226 24 22.271V1.729C24 .774 23.2 0 22.222 0h.003z\"\n);\nconst FacebookIcon = createIcon(\n \"M9.101 23.691v-7.98H6.627v-3.667h2.474v-1.58c0-4.085 1.848-5.978 5.858-5.978.401 0 .955.042 1.468.103a8.68 8.68 0 0 1 1.141.195v3.325a8.623 8.623 0 0 0-.653-.036 26.805 26.805 0 0 0-.733-.009c-.707 0-1.259.096-1.675.309a1.686 1.686 0 0 0-.679.622c-.258.42-.374.995-.374 1.752v1.297h3.919l-.386 2.103-.287 1.564h-3.246v8.245C19.396 23.238 24 18.179 24 12.044c0-6.627-5.373-12-12-12s-12 5.373-12 12c0 5.628 3.874 10.35 9.101 11.647Z\"\n);\nconst TelegramIcon = createIcon(\n \"M11.944 0A12 12 0 0 0 0 12a12 12 0 0 0 12 12 12 12 0 0 0 12-12A12 12 0 0 0 12 0a12 12 0 0 0-.056 0zm4.962 7.224c.1-.002.321.023.465.14a.506.506 0 0 1 .171.325c.016.093.036.306.02.472-.18 1.898-.962 6.502-1.36 8.627-.168.9-.499 1.201-.82 1.23-.696.065-1.225-.46-1.9-.902-1.056-.693-1.653-1.124-2.678-1.8-1.185-.78-.417-1.21.258-1.91.177-.184 3.247-2.977 3.307-3.23.007-.032.014-.15-.056-.212s-.174-.041-.249-.024c-.106.024-1.793 1.14-5.061 3.345-.48.33-.913.49-1.302.48-.428-.008-1.252-.241-1.865-.44-.752-.245-1.349-.374-1.297-.789.027-.216.325-.437.893-.663 3.498-1.524 5.83-2.529 6.998-3.014 3.332-1.386 4.025-1.627 4.476-1.635z\"\n);\nconst DiscordIcon = createIcon(\n \"M20.317 4.3698a19.7913 19.7913 0 00-4.8851-1.5152.0741.0741 0 00-.0785.0371c-.211.3753-.4447.8648-.6083 1.2495-1.8447-.2762-3.68-.2762-5.4868 0-.1636-.3933-.4058-.8742-.6177-1.2495a.077.077 0 00-.0785-.037 19.7363 0 00-4.8852 1.515.0699.0699 0 00-.0321.0277C.5334 9.0458-.319 13.5799.0992 18.0578a.0824.0824 0 00.0312.0561c2.0528 1.5076 4.0413 2.4228 5.9929 3.0294a.0777.0777 0 00.0842-.0276c.4616-.6304.8731-1.2952 1.226-1.9942a.076.076 0 00-.0416-.1057c-.6528-.2476-1.2743-.5495-1.8722-.8923a.077.077 0 01-.0076-.1277c.1258-.0943.2517-.1923.3718-.2914a.0743.0743 0 01.0776-.0105c3.9278 1.7933 8.18 1.7933 12.0614 0a.0739.0739 0 01.0785.0095c.1202.099.246.1981.3728.2924a.077.077 0 01-.0066.1276 12.2986 12.2986 0 01-1.873.8914.0766.0766 0 00-.0407.1067c.3604.698.7719 1.3628 1.225 1.9932a.076.076 0 00.0842.0286c1.961-.6067 3.9495-1.5219 6.0023-3.0294a.077.077 0 00.0313-.0552c.5004-5.177-.8382-9.6739-3.5485-13.6604a.061.061 0 00-.0312-.0286zM8.02 15.3312c-1.1825 0-2.1569-1.0857-2.1569-2.419 0-1.3332.9555-2.4189 2.157-2.4189 1.2108 0 2.1757 1.0952 2.1568 2.419 0 1.3332-.9555 2.4189-2.1569 2.4189zm7.9748 0c-1.1825 0-2.1569-1.0857-2.1569-2.419 0-1.3332.9554-2.4189 2.1569-2.4189 1.2108 0 2.1757 1.0952 2.1568 2.419 0 1.3332-.946 2.4189-2.1568 2.4189Z\"\n);\nconst ThreadsIcon = createIcon(\n \"M12.186 24h-.007c-3.581-.024-6.334-1.205-8.184-3.509C2.35 18.44 1.5 15.586 1.472 12.01v-.017c.03-3.579.879-6.43 2.525-8.482C5.845 1.205 8.6.024 12.18 0h.014c2.746.02 5.043.725 6.826 2.098 1.677 1.29 2.858 3.13 3.509 5.467l-2.04.569c-1.104-3.96-3.898-5.984-8.304-6.015-2.91.022-5.11.936-6.54 2.717C4.307 6.504 3.616 8.914 3.589 12c.027 3.086.718 5.496 2.057 7.164 1.43 1.783 3.631 2.698 6.54 2.717 2.623-.02 4.358-.631 5.8-2.045 1.647-1.613 1.618-3.593 1.09-4.798-.31-.71-.873-1.3-1.634-1.75-.192 1.352-.622 2.446-1.284 3.272-.886 1.102-2.14 1.704-3.73 1.79-1.202.065-2.361-.218-3.259-.801-1.063-.689-1.685-1.74-1.752-2.964-.065-1.19.408-2.285 1.33-3.082.88-.76 2.119-1.207 3.583-1.291a13.853 13.853 0 0 1 3.02.142c-.126-.742-.375-1.332-.75-1.757-.513-.586-1.308-.883-2.359-.89h-.029c-.844 0-1.992.232-2.721 1.32L7.734 7.847c.98-1.454 2.568-2.256 4.478-2.256h.044c3.194.02 5.097 1.975 5.287 5.388.108.046.216.094.321.142 1.49.7 2.58 1.761 3.154 3.07.797 1.82.871 4.79-1.548 7.158-1.85 1.81-4.094 2.628-7.277 2.65Zm1.003-11.69c-.242 0-.487.007-.739.021-1.836.103-2.98.946-2.916 2.143.067 1.256 1.452 1.839 2.784 1.767 1.224-.065 2.818-.543 3.086-3.71a10.5 10.5 0 0 0-2.215-.221z\"\n);\nconst MastodonIcon = createIcon(\n \"M23.268 5.313c-.35-2.578-2.617-4.61-5.304-5.004C17.51.242 15.792 0 11.813 0h-.03c-3.98 0-4.835.242-5.288.309C3.882.692 1.496 2.518.917 5.127.64 6.412.61 7.837.661 9.143c.074 1.874.088 3.745.26 5.611.118 1.24.325 2.47.62 3.68.55 2.237 2.777 4.098 4.96 4.857 2.336.792 4.849.923 7.256.38.265-.061.527-.132.786-.213.585-.184 1.27-.39 1.774-.753a.057.057 0 0 0 .023-.043v-1.809a.052.052 0 0 0-.02-.041.053.053 0 0 0-.046-.01 20.282 20.282 0 0 1-4.709.545c-2.73 0-3.463-1.284-3.674-1.818a5.593 5.593 0 0 1-.319-1.433.053.053 0 0 1 .066-.054c1.517.363 3.072.546 4.632.546.376 0 .75 0 1.125-.01 1.57-.044 3.224-.124 4.768-.422.038-.008.077-.015.11-.024 2.435-.464 4.753-1.92 4.989-5.604.008-.145.03-1.52.03-1.67.002-.512.167-3.63-.024-5.545zm-3.748 9.195h-2.561V8.29c0-1.309-.55-1.976-1.67-1.976-1.23 0-1.846.79-1.846 2.35v3.403h-2.546V8.663c0-1.56-.617-2.35-1.848-2.35-1.112 0-1.668.668-1.67 1.977v6.218H4.822V8.102c0-1.31.337-2.35 1.011-3.12.696-.77 1.608-1.164 2.74-1.164 1.311 0 2.302.5 2.962 1.498l.638 1.06.638-1.06c.66-.999 1.65-1.498 2.96-1.498 1.13 0 2.043.395 2.74 1.164.675.77 1.012 1.81 1.012 3.12z\"\n);\n\nconst iconMap: Record<string, ReturnType<typeof createIcon>> = {\n github: GithubIcon,\n gitlab: GitlabIcon,\n bitbucket: BitbucketIcon,\n npm: NpmIcon,\n youtube: YoutubeIcon,\n twitter: TwitterIcon,\n x: TwitterIcon,\n instagram: InstagramIcon,\n linkedin: LinkedinIcon,\n facebook: FacebookIcon,\n telegram: TelegramIcon,\n discord: DiscordIcon,\n threads: ThreadsIcon,\n mastodon: MastodonIcon,\n};\n\nexport function getSocialIcon(name: string) {\n const key = name.toLowerCase().replace(/\\s+/g, \"\");\n return iconMap[key] || null;\n}\n\nexport default function Social({ className = \"\", size = 16 }: SocialProps) {\n const socialLinks = getSocialLinks();\n\n if (!socialLinks?.length) return null;\n\n return (\n <div className={`flex gap-1 ${className}`}>\n {socialLinks.map((link) => {\n const Icon = getSocialIcon(link.name);\n return (\n <a\n key={link.name}\n href={link.url}\n target=\"_blank\"\n rel=\"noopener noreferrer\"\n aria-label={link.name}\n className=\"btn-xs btn-circle btn-ghost text-muted-foreground\"\n >\n {Icon && <Icon size={size} />}\n </a>\n );\n })}\n </div>\n );\n}\n","import Social from \"./Social\";\n\nexport function Footer() {\n return (\n <footer className=\"text-muted-foreground mt-auto flex w-full flex-col items-start gap-4 py-6 sm:flex-row sm:items-center sm:justify-between\">\n <Social />\n <aside className=\"sm:ml-auto\">\n <p className=\"text-xs\">\n Made with{\" \"}\n <a\n href=\"https://docubook.pro\"\n target=\"_blank\"\n rel=\"noopener noreferrer\"\n className=\"link link-hover text-muted-foreground font-medium\"\n >\n DocuBook\n </a>\n </p>\n </aside>\n </footer>\n );\n}\n","\"use client\";\n\nimport { ArrowUpIcon } from \"lucide-react\";\nimport { useEffect, useState, useCallback } from \"react\";\nimport { cn } from \"../node/utils\";\n\ninterface ScrollToProps {\n className?: string;\n showIcon?: boolean;\n offset?: number;\n onScrollToTop?: () => void;\n}\n\nexport function ScrollTo({ className, showIcon = true, onScrollToTop }: ScrollToProps) {\n const [isVisible, setIsVisible] = useState(false);\n\n const checkScroll = useCallback(() => {\n const container = document.getElementById(\"scroll-container\");\n const scrollY = container ? container.scrollTop : window.scrollY;\n const scrollHeight = container ? container.scrollHeight : document.documentElement.scrollHeight;\n const threshold = scrollHeight * 0.3;\n\n const shouldShow = scrollY > threshold;\n if (shouldShow !== isVisible) {\n setIsVisible(shouldShow);\n }\n }, [isVisible]);\n\n useEffect(() => {\n let timeoutId: ReturnType<typeof setTimeout>;\n const handleScroll = () => {\n if (timeoutId) clearTimeout(timeoutId);\n timeoutId = setTimeout(checkScroll, 100);\n };\n\n const container = document.getElementById(\"scroll-container\") || window;\n container.addEventListener(\"scroll\", handleScroll, { passive: true });\n\n return () => {\n container.removeEventListener(\"scroll\", handleScroll);\n if (timeoutId) clearTimeout(timeoutId);\n };\n }, [checkScroll]);\n\n const scrollToTop = useCallback(\n (e: React.MouseEvent) => {\n e.preventDefault();\n onScrollToTop?.();\n history.replaceState(null, \"\", \"#top\");\n const container = document.getElementById(\"scroll-container\");\n if (container) {\n container.scrollTo({ top: 0, behavior: \"smooth\" });\n } else {\n window.scrollTo({ top: 0, behavior: \"smooth\" });\n }\n },\n [onScrollToTop]\n );\n\n return (\n <div\n className={cn(\n \"border-base-300 mt-4 border-t pt-4\",\n \"transition-opacity duration-300\",\n isVisible ? \"opacity-100\" : \"pointer-events-none opacity-0\",\n className\n )}\n >\n <a\n href=\"#top\"\n onClick={scrollToTop}\n className={cn(\n \"inline-flex items-center text-sm\",\n \"link link-hover text-base-content/60 hover:text-base-content\",\n \"transition-all duration-200 hover:translate-y-px\"\n )}\n aria-label=\"Scroll to top\"\n >\n {showIcon && <ArrowUpIcon className=\"mr-1 h-3.5 w-3.5 shrink-0\" />}\n <span>Scroll to Top</span>\n </a>\n </div>\n );\n}\n","\"use client\";\n\nimport { useState, useCallback, useEffect, useRef } from \"react\";\nimport { ListIcon } from \"lucide-react\";\nimport { cn } from \"../node/utils\";\nimport { ScrollTo } from \"./ScrollTo\";\nimport { TocItem } from \"../node/types\";\n\ninterface TocProps {\n tocs: TocItem[];\n}\n\nexport default function Toc({ tocs }: TocProps) {\n const [activeId, setActiveId] = useState<string | null>(null);\n const clickedIdRef = useRef<string | null>(null);\n const clickTimerRef = useRef<ReturnType<typeof setTimeout>>(null);\n const activeIdRef = useRef<string | null>(null);\n\n useEffect(() => {\n activeIdRef.current = activeId;\n }, [activeId]);\n\n // Single source of truth for the anchor offset — used by BOTH the scroll\n // observer and the TOC click scroll so they can never disagree. Reads the\n // CSS scroll-margin-top (prose-headings:scroll-mt-4 desktop /\n // scroll-mt-16 mobile) so a change in one place updates both, and the\n // heading lands exactly where the browser would put a native anchor jump.\n const getAnchorOffset = useCallback((): number => {\n if (typeof window === \"undefined\") return 100;\n const first = tocs[0] ? document.getElementById(tocs[0].href.slice(1)) : null;\n const margin = first ? parseFloat(getComputedStyle(first).scrollMarginTop) : 0;\n return margin || 100;\n }, [tocs]);\n\n useEffect(() => {\n // Desktop-only TOC — on mobile this island is display:none but still\n // mounted; letting its observer run would hijack the URL hash while the\n // mobile bar owns TOC behavior there.\n if (typeof window === \"undefined\" || window.innerWidth < 1024) return;\n if (!tocs.length) return;\n\n const isDesktop = window.innerWidth >= 1024;\n const container = isDesktop ? document.getElementById(\"scroll-container\") : null;\n const scrollTarget = container || window;\n const offset = getAnchorOffset();\n\n const handleScroll = () => {\n if (clickedIdRef.current) return;\n\n let currentId: string | null = null;\n for (const toc of tocs) {\n const id = toc.href.slice(1);\n const el = document.getElementById(id);\n if (!el) continue;\n\n const top = container ? el.offsetTop - container.scrollTop : el.getBoundingClientRect().top;\n\n if (top <= offset) {\n currentId = id;\n } else {\n break;\n }\n }\n\n if (currentId !== activeIdRef.current) {\n setActiveId(currentId);\n history.replaceState(null, \"\", currentId ? `#${currentId}` : \"#top\");\n }\n };\n\n handleScroll(); // set initial active on mount\n\n let throttleTimer: ReturnType<typeof setTimeout> | null = null;\n const listener =\n tocs.length > 30\n ? () => {\n if (throttleTimer) return;\n throttleTimer = setTimeout(() => {\n throttleTimer = null;\n handleScroll();\n }, 50);\n }\n : handleScroll;\n\n scrollTarget.addEventListener(\"scroll\", listener, { passive: true });\n\n return () => {\n scrollTarget.removeEventListener(\"scroll\", listener);\n if (throttleTimer) clearTimeout(throttleTimer);\n };\n }, [tocs, getAnchorOffset]);\n\n const handleLinkClick = useCallback((id: string) => {\n clickedIdRef.current = id;\n setActiveId(id);\n history.replaceState(null, \"\", `#${id}`);\n if (clickTimerRef.current) clearTimeout(clickTimerRef.current);\n clickTimerRef.current = setTimeout(() => {\n clickedIdRef.current = null;\n }, 1000);\n }, []);\n\n const handleScrollToTop = useCallback(() => {\n clickedIdRef.current = \"__top__\";\n setActiveId(null);\n history.replaceState(null, \"\", \"#top\");\n if (clickTimerRef.current) clearTimeout(clickTimerRef.current);\n clickTimerRef.current = setTimeout(() => {\n clickedIdRef.current = null;\n }, 1000);\n }, []);\n\n useEffect(() => {\n return () => {\n if (clickTimerRef.current) clearTimeout(clickTimerRef.current);\n };\n }, []);\n\n const activeItemRef = useRef<HTMLDivElement | null>(null);\n\n useEffect(() => {\n if (activeId && activeItemRef.current && !clickedIdRef.current) {\n activeItemRef.current.scrollIntoView({\n block: \"nearest\",\n behavior: \"smooth\",\n });\n }\n }, [activeId]);\n\n if (!tocs.length) return null;\n\n return (\n <div className=\"flex h-full min-h-0 w-full flex-col gap-2\">\n <div className=\"flex shrink-0 items-center gap-2\">\n <ListIcon className=\"h-4 w-4\" />\n <h3 className=\"text-sm font-medium\">On this page</h3>\n </div>\n\n <div className=\"relative min-h-0 flex-1 overflow-y-auto overscroll-contain pr-1\">\n <div className=\"relative text-sm\">\n <div className=\"bg-base-300 absolute top-0 left-0 h-full w-px\" />\n\n <div className=\"flex flex-col\">\n {tocs.map(({ href, level, text }) => {\n const id = href.slice(1);\n const isActive = activeId === id;\n const levelPadding = (level - 2) * 16;\n\n return (\n <div\n key={href}\n ref={isActive ? activeItemRef : undefined}\n className={cn(\n \"relative flex items-center transition-all duration-200\",\n isActive && \"bg-primary/5\"\n )}\n >\n <div\n className={cn(\n \"flex shrink-0 items-center px-1 py-2 transition-all duration-200\",\n isActive && \"border-primary -ml-px border-l-[3px]\"\n )}\n >\n <div\n className={cn(\n \"h-px transition-colors duration-200\",\n isActive ? \"bg-primary w-3\" : \"bg-base-300 w-2\"\n )}\n />\n <div\n className={cn(\n \"h-1.5 w-1.5 shrink-0 rounded-full transition-colors duration-300\",\n isActive ? \"bg-primary\" : \"bg-base-300\"\n )}\n />\n </div>\n\n <a\n href={href}\n onClick={(e) => {\n e.preventDefault();\n handleLinkClick(id);\n const el = document.getElementById(id);\n if (el) {\n // Manual scroll with the same offset the observer uses —\n // scrollIntoView ignores scroll-margin-top on iOS Safari\n // window-scroll, landing the heading under the sticky\n // mobile bar.\n const offset = getAnchorOffset();\n const scroller =\n window.innerWidth >= 1024\n ? document.getElementById(\"scroll-container\")\n : null;\n const elTop = el.getBoundingClientRect().top;\n if (scroller) {\n // Container scroll space: element offset within the\n // container minus the anchor offset (the container\n // itself may sit below the viewport top, e.g. under\n // the navbar).\n scroller.scrollTo({\n top:\n elTop -\n scroller.getBoundingClientRect().top +\n scroller.scrollTop -\n offset,\n behavior: \"smooth\",\n });\n } else {\n window.scrollTo({\n top: elTop + window.scrollY - offset,\n behavior: \"smooth\",\n });\n }\n }\n }}\n className={cn(\n \"flex flex-1 items-center py-2 transition-all duration-200\",\n isActive\n ? \"text-primary font-medium\"\n : \"text-base-content/60 hover:text-base-content\"\n )}\n style={{ paddingLeft: `${levelPadding + 6}px` }}\n >\n <span className=\"line-clamp-2 text-sm break-words\">{text}</span>\n </a>\n </div>\n );\n })}\n </div>\n </div>\n\n <div className=\"mt-2 grid grid-cols-[28px_minmax(0,1fr)] items-start px-4 text-sm\">\n <div aria-hidden=\"true\" />\n <ScrollTo className=\"mt-0\" onScrollToTop={handleScrollToTop} />\n </div>\n </div>\n </div>\n );\n}\n","import { ChevronLeft, ChevronRight } from \"lucide-react\";\nimport DocsBreadcrumb from \"../../components/Breadcrumb\";\nimport Pagination from \"../../components/Pagination\";\nimport { Typography } from \"../../components/Typography\";\nimport EditWith from \"../../components/EditWith\";\nimport { formatDate2 } from \"../../node/utils\";\nimport type { TocItem } from \"../../node/types\";\nimport { Footer } from \"../../components/Footer\";\nimport Toc from \"../../components/Toc\";\n\ninterface DocsPageProps {\n slug: string[];\n title: string;\n description?: string;\n date?: string;\n /** SSR'd MDX content HTML — rendered as its own root so client hydration\n * (separate island root) matches useId-based ids. */\n content: string;\n tocs: TocItem[];\n filePath: string;\n repoUrl?: string;\n /** Build-time slug keying into the bundled mdxModules manifest (client.ts). */\n mdxSlug?: string;\n /** Dev-only pre-compiled source for the legacy MDXRemote eval path. */\n compiledSource?: string;\n}\n\nexport default function DocsPage({\n slug,\n title,\n description,\n date,\n content,\n tocs,\n filePath,\n repoUrl,\n mdxSlug,\n compiledSource,\n}: DocsPageProps) {\n const pathname = slug.join(\"/\");\n const tocsJson = JSON.stringify(tocs);\n\n return (\n <div className=\"flex w-full flex-1 px-0 pb-4 lg:h-[calc(100vh-4rem)] lg:px-8 lg:pb-8\">\n <div\n id=\"scroll-container\"\n className=\"bg-base-100 border-base-300 relative flex w-full flex-col items-start rounded-b-3xl border shadow-md max-lg:scroll-p-54 lg:h-full lg:flex-row lg:overflow-y-auto lg:rounded-xl\"\n >\n {/* Mobile bar - island */}\n <div\n id=\"mobile-bar-island\"\n className=\"sticky top-0 z-50 w-full lg:hidden\"\n data-tocs={tocsJson}\n data-title={title}\n data-repo={repoUrl || \"\"}\n />\n\n <div className=\"flex w-full flex-col lg:flex-row 2xl:mx-auto 2xl:max-w-[1300px]\">\n <div\n className={`w-full min-w-0 ${tocs.length > 0 ? \"flex-[7]\" : \"mx-auto max-w-[820px]\"} px-4 py-6 lg:px-12 lg:py-10`}\n >\n <DocsBreadcrumb paths={slug} />\n <Typography>\n <h1 className=\"-mt-0.5 text-3xl\">{title}</h1>\n {description && (\n <p className=\"text-muted-foreground -mt-4 text-[16.5px]\">{description}</p>\n )}\n <div\n id=\"mdx-content-island\"\n data-mdx-slug={mdxSlug}\n dangerouslySetInnerHTML={{ __html: content }}\n />\n {compiledSource && (\n <script\n id=\"mdx-compiled-source\"\n type=\"application/json\"\n dangerouslySetInnerHTML={{\n __html: JSON.stringify(compiledSource).replace(/<\\//g, \"\\\\u003C/\"),\n }}\n />\n )}\n <div className=\"border-base-300 my-8 flex items-center border-b-2 border-dashed\">\n <EditWith className=\"text-muted-foreground\" filePath={filePath} />\n {date && (\n <p className=\"text-muted-foreground ml-auto text-[13px]\">\n Last updated {formatDate2(date)}\n </p>\n )}\n </div>\n <Pagination\n pathname={pathname}\n prevIcon={<ChevronLeft className=\"h-3 w-3\" />}\n nextIcon={<ChevronRight className=\"h-3 w-3\" />}\n />\n <Footer />\n </Typography>\n </div>\n\n {/* Desktop TOC - SSR rendered */}\n {tocs.length > 0 && (\n <div\n id=\"toc-island\"\n data-tocs={tocsJson}\n className=\"sticky top-4 hidden h-[calc(100vh-8rem)] min-w-[240px] flex-[3] self-start lg:flex lg:px-4 lg:py-6\"\n >\n <Toc tocs={tocs} />\n </div>\n )}\n </div>\n </div>\n </div>\n );\n}\n","export default function NotFoundPage() {\n return (\n <div className=\"flex w-full flex-1 px-4 py-8 lg:h-[calc(100vh-4rem)] lg:px-8 lg:py-4\">\n <div className=\"bg-base-100 border-base-300 flex min-h-[50vh] w-full flex-col items-center justify-center rounded-xl border shadow-md lg:min-h-0 lg:flex-1\">\n <h1 className=\"text-6xl font-bold\">404</h1>\n <p className=\"text-base-content/60 py-4 text-xl\">Page not found</p>\n <a href=\"/docs/\" className=\"btn btn-primary mt-2\">\n Go to Docs\n </a>\n </div>\n </div>\n );\n}\n","import * as LucideIcons from \"lucide-react\";\nimport type { LucideIcon } from \"lucide-react\";\n\n/**\n * Get Lucide icon component by name\n * Icon names must match Lucide's export names exactly (e.g., \"Zap\", \"BookOpen\", \"Search\")\n */\nexport function getLucideIcon(name: string): LucideIcon | null {\n if (!name) return null;\n const icon = (LucideIcons as unknown as Record<string, LucideIcon | undefined>)[name];\n return icon || null;\n}\n\n/**\n * Render Lucide icon component\n */\nexport function renderLucideIcon(name: string, className?: string) {\n const Icon = getLucideIcon(name);\n return Icon ? <Icon className={className} /> : null;\n}\n","\"use client\";\n\nimport type { Hero as HeroType, HeroAction } from \"../../node/types\";\nimport { cn } from \"../../node/utils\";\nimport { renderLucideIcon } from \"../Lucide\";\nimport { getSocialIcon } from \"../Social\";\n\ninterface HeroProps {\n hero: HeroType;\n className?: string;\n}\n\ninterface ActionButtonProps {\n action: HeroAction;\n}\n\nfunction isExternalLink(link: string): boolean {\n return /^https?:\\/\\//.test(link);\n}\n\nfunction renderActionButtonIcon(iconName: string | undefined, className?: string) {\n if (!iconName) return null;\n\n // Try Lucide icon first\n const lucideIcon = renderLucideIcon(iconName, className);\n if (lucideIcon) return lucideIcon;\n\n // Fallback to social icon\n const SocialIcon = getSocialIcon(iconName);\n if (SocialIcon) return <SocialIcon className={className} />;\n\n return null;\n}\n\nfunction ActionButton({ action }: ActionButtonProps) {\n const themeClasses = {\n primary: \"bg-primary text-primary-foreground hover:bg-primary/90\",\n secondary: \"bg-secondary text-secondary-foreground hover:bg-secondary/90\",\n ghost: \"bg-transparent text-muted-foreground border border-base-300 hover:bg-base-200\",\n };\n\n const isExternal = isExternalLink(action.link);\n\n return (\n <a\n href={action.link}\n target={isExternal ? \"_blank\" : undefined}\n rel={isExternal ? \"noopener noreferrer\" : undefined}\n className={cn(\n \"inline-flex items-center gap-2 rounded-lg px-6 py-3 text-sm font-medium transition-colors\",\n themeClasses[action.theme || \"primary\"]\n )}\n >\n {renderActionButtonIcon(action.icon, \"h-4 w-4\")}\n {action.text}\n </a>\n );\n}\n\nexport function Hero({ hero, className }: HeroProps) {\n const { tagline, headline, description, actions } = hero;\n\n return (\n <div className={cn(\"mx-auto max-w-4xl px-6 py-32 sm:py-44\", className)}>\n <div className=\"text-center\">\n {tagline && <p className=\"text-primary mb-4 text-lg font-semibold\">{tagline}</p>}\n <h1 className=\"text-5xl font-semibold tracking-tight text-balance sm:text-7xl\">\n {headline}\n </h1>\n {description && (\n <p className=\"text-muted-foreground mt-8 text-lg text-pretty sm:text-xl\">{description}</p>\n )}\n {actions && actions.length > 0 && (\n <div className=\"mt-10 flex flex-wrap items-center justify-center gap-4\">\n {actions.map((action, index) => (\n <ActionButton key={index} action={action} />\n ))}\n </div>\n )}\n </div>\n </div>\n );\n}\n","\"use client\";\n\nimport type { HomeFeature } from \"../../node/types\";\nimport { cn } from \"../../node/utils\";\nimport { renderLucideIcon } from \"../Lucide\";\n\ninterface FeaturesProps {\n features: HomeFeature[];\n className?: string;\n}\n\ninterface FeatureCardProps {\n feature: HomeFeature;\n index: number;\n}\n\nfunction FeatureCard({ feature, index }: FeatureCardProps) {\n const Wrapper = feature.link ? \"a\" : \"div\";\n const wrapperProps = feature.link ? { href: feature.link } : {};\n\n // Use index-based patternId to avoid collisions\n const patternId = `grid-${index}`;\n\n return (\n <Wrapper\n {...wrapperProps}\n className={cn(\n \"border-base-200 bg-base-100 hover:border-primary/40 group relative overflow-hidden rounded-2xl border p-6 transition-all hover:shadow-lg\",\n feature.link && \"cursor-pointer\"\n )}\n >\n {/* Grid pattern background */}\n <svg\n className=\"absolute inset-0 h-full w-full\"\n xmlns=\"http://www.w3.org/2000/svg\"\n style={{ color: \"var(--color-primary)\" }}\n aria-hidden=\"true\"\n >\n <defs>\n <pattern id={patternId} width=\"40\" height=\"40\" patternUnits=\"userSpaceOnUse\">\n <path\n d=\"M 40 0 L 0 0 0 40\"\n fill=\"none\"\n stroke=\"currentColor\"\n strokeWidth=\"0.5\"\n opacity=\"0.15\"\n />\n </pattern>\n </defs>\n <rect width=\"100%\" height=\"100%\" fill={`url(#${patternId})`} />\n </svg>\n\n {/* Content */}\n <div className=\"relative z-10\">\n {feature.icon && (\n <div className=\"bg-primary/10 mb-4 inline-flex h-12 w-12 items-center justify-center rounded-lg\">\n {renderLucideIcon(feature.icon, \"h-6 w-6 text-primary\")}\n </div>\n )}\n <h3 className=\"mb-2 text-lg font-semibold\">{feature.title}</h3>\n <p className=\"text-muted-foreground text-sm\">{feature.description}</p>\n </div>\n </Wrapper>\n );\n}\n\nexport function Features({ features, className }: FeaturesProps) {\n if (!features || features.length === 0) return null;\n\n return (\n <div className={cn(\"mx-auto max-w-5xl px-6 pb-24\", className)}>\n <div className=\"grid grid-cols-1 gap-6 sm:grid-cols-2 lg:grid-cols-3\">\n {features.map((feature, index) => (\n <FeatureCard key={index} feature={feature} index={index} />\n ))}\n </div>\n </div>\n );\n}\n","import { loadDocuConfig } from \"../node/paths\";\nimport { docsHtmlHref, isExternalUrl } from \"../node/utils\";\nimport { Hero, Features } from \"../components/home\";\nimport type { HomeFeature } from \"../node/types\";\n\nconst docuConfig = loadDocuConfig();\n\ninterface RouteContext {\n icon?: string;\n title?: string;\n description?: string;\n}\n\ninterface RouteItem {\n title: string;\n href: string;\n context?: RouteContext;\n items?: RouteItem[];\n}\n\nexport default function IndexPage() {\n const { meta, home } = docuConfig;\n const routes = (docuConfig.routes as RouteItem[]) || [];\n\n // Docs pages under /docs/ are flat .html files; the root /docs is\n // docs/index.html via directory index — no .html suffix needed.\n const linkWithHtml = (link: string) => {\n if (isExternalUrl(link)) return link;\n if (link.startsWith(\"/docs/\")) return `${link}.html`;\n return link;\n };\n\n // Use home.features if configured, otherwise fallback to routes with context\n const features: HomeFeature[] =\n home?.features?.map((f) => ({\n ...f,\n link: f.link ? linkWithHtml(f.link) : undefined,\n })) ||\n routes\n .filter((r) => r.context)\n .map((route) => ({\n icon: route.context?.icon,\n title: route.context?.title || route.title,\n description: route.context?.description || \"\",\n link: docsHtmlHref(`/docs${route.href}${route.items?.[0]?.href || \"\"}`),\n }));\n\n // Use home.hero if configured, otherwise fallback to meta\n const hero = home?.hero\n ? {\n ...home.hero,\n actions: home.hero.actions?.map((a) => ({\n ...a,\n link: linkWithHtml(a.link),\n })),\n }\n : {\n headline: meta.title,\n description: meta.description,\n };\n\n return (\n <div className=\"bg-base-100 relative isolate min-h-screen overflow-hidden\">\n <div className=\"absolute top-4 right-4 z-10\" id=\"theme-island\" />\n\n {/* Background gradient blobs */}\n <div\n aria-hidden=\"true\"\n className=\"pointer-events-none absolute -top-40 left-1/2 -z-10 -translate-x-1/2 blur-3xl sm:-top-80\"\n >\n <div\n style={{\n clipPath:\n \"polygon(74.1% 44.1%, 100% 61.6%, 97.5% 26.9%, 85.5% 0.1%, 80.7% 2%, 72.5% 32.5%, 60.2% 62.4%, 52.4% 68.1%, 47.5% 58.3%, 45.2% 34.5%, 27.5% 76.7%, 0.1% 64.9%, 17.9% 100%, 27.6% 76.8%, 76.1% 97.7%, 74.1% 44.1%)\",\n }}\n className=\"from-primary to-accent h-[40rem] w-[80rem] bg-gradient-to-tr opacity-20\"\n />\n </div>\n\n {/* Hero Section */}\n <Hero hero={hero} />\n\n {/* Features Section */}\n <Features features={features} />\n\n {/* Bottom gradient blob */}\n <div\n aria-hidden=\"true\"\n className=\"pointer-events-none absolute bottom-0 left-1/2 -z-10 translate-x-1/4 blur-3xl\"\n >\n <div\n style={{\n clipPath:\n \"polygon(74.1% 44.1%, 100% 61.6%, 97.5% 26.9%, 85.5% 0.1%, 80.7% 2%, 72.5% 32.5%, 60.2% 62.4%, 52.4% 68.1%, 47.5% 58.3%, 45.2% 34.5%, 27.5% 76.7%, 0.1% 64.9%, 17.9% 100%, 27.6% 76.8%, 76.1% 97.7%, 74.1% 44.1%)\",\n }}\n className=\"from-accent to-primary h-[30rem] w-[70rem] bg-gradient-to-tr opacity-20\"\n />\n </div>\n </div>\n );\n}\n","import { AnchorHTMLAttributes, ReactNode } from \"react\";\nimport { ArrowUpRight } from \"lucide-react\";\nimport { cn, isExternalUrl } from \"../node/utils\";\n\nexport interface AnchorProps extends AnchorHTMLAttributes<HTMLAnchorElement> {\n href?: string;\n activeClassName?: string;\n activeWhen?: string | RegExp | ((pathname: string) => boolean);\n disabled?: boolean;\n children: ReactNode;\n className?: string;\n}\n\nexport default function Anchor({\n href = \"\",\n className = \"\",\n activeClassName = \"\",\n activeWhen,\n disabled = false,\n children,\n ...props\n}: AnchorProps) {\n const isActive = (() => {\n if (!activeWhen || typeof window === \"undefined\") return false;\n const pathname = window.location.pathname;\n if (typeof activeWhen === \"string\")\n return pathname === activeWhen || pathname.endsWith(activeWhen);\n if (activeWhen instanceof RegExp) return activeWhen.test(pathname);\n if (typeof activeWhen === \"function\") return activeWhen(pathname);\n return false;\n })();\n\n const isExternal = isExternalUrl(href);\n\n const activeClass = isActive ? activeClassName : \"\";\n const baseClasses = cn(\n \"hover:underline transition-colors\",\n className,\n activeClass,\n disabled && \"cursor-not-allowed opacity-50\"\n );\n\n if (disabled) {\n return <span className={baseClasses}>{children}</span>;\n }\n\n if (isExternal) {\n return (\n <a href={href} className={baseClasses} target=\"_blank\" rel=\"noopener noreferrer\" {...props}>\n {children}\n <ArrowUpRight className=\"ml-0.5 inline-block h-3.5 w-3.5\" />\n </a>\n );\n }\n\n return (\n <a href={href} className={baseClasses} {...props}>\n {children}\n </a>\n );\n}\n","import type { DocuRoute, DocuConfig } from \"./types\";\nimport { loadDocuConfig } from \"./paths\";\nimport { resolveRoutes } from \"./fs-scanner\";\n\nconst docuConfig = loadDocuConfig();\nexport const routes: DocuRoute[] = resolveRoutes(docuConfig.routes || []);\nexport const config = docuConfig as unknown as DocuConfig;\n","\"use client\";\n\nimport {\n createContext,\n useContext,\n useState,\n useRef,\n useEffect,\n useCallback,\n type ReactNode,\n} from \"react\";\nimport { ChevronDown } from \"lucide-react\";\nimport Anchor from \"./Anchor\";\nimport type { DocuRoute } from \"../node/types\";\nimport { cn, docsHtmlHref } from \"../node/utils\";\nimport { config as docuConfig } from \"../node/client-routes\";\n\n/** Exclusive accordion for level >= 2 sidebar groups — opening one group\n * closes the previously open one. All level >= 2 groups default to closed\n * and expand only when the header is clicked. `open` is used to auto-expand\n * the group containing the active page. */\nexport const GroupAccordionContext = createContext<{\n openId: string | null;\n open: (id: string) => void;\n toggle: (id: string) => void;\n}>({ openId: null, open: () => {}, toggle: () => {} });\n\nexport function GroupAccordionProvider({ children }: { children: ReactNode }) {\n const [openId, setOpenId] = useState<string | null>(null);\n // Exclusive: expanding B closes A — only one group stays open at a time;\n // clicking the open group again collapses it.\n const open = useCallback((id: string) => setOpenId(id), []);\n const toggle = useCallback((id: string) => setOpenId((prev) => (prev === id ? null : id)), []);\n return (\n <GroupAccordionContext.Provider value={{ openId, open, toggle }}>\n {children}\n </GroupAccordionContext.Provider>\n );\n}\n\ninterface SublinkProps extends DocuRoute {\n level: number;\n onNavigate?: () => void;\n parentHref?: string;\n pathname?: string;\n}\n\nexport default function Sublink({\n title,\n href,\n items,\n noLink,\n level,\n onNavigate,\n parentHref = \"\",\n pathname: pathnameProp,\n}: SublinkProps) {\n const fullHref = parentHref ? `${parentHref}${href}` : `/docs${href}`;\n const currentPathname =\n pathnameProp || (typeof window !== \"undefined\" ? window.location.pathname : \"/docs\");\n\n // Groups with children are exclusive accordions (default closed, expand on\n // click). In separator mode every nav item renders at level 0 (sections are\n // SidebarGroupHeader, not Sublinks), so depth can't tell them apart — the\n // mode does. In dropdown mode the top section is level 0 (stays open) and\n // everything deeper is an accordion.\n const isSeparator = docuConfig.sidebar?.context === \"separator\";\n const { openId, open, toggle } = useContext(GroupAccordionContext);\n const isAccordionGroup = Boolean(items) && (isSeparator || level >= 1);\n // Routes-tree level: separator mode renders every item at level 0 (sections\n // are SidebarGroupHeader), dropdown starts the context section at level 0.\n const treeLevel = level + (isSeparator ? 2 : 1);\n\n const [isOpen, setIsOpen] = useState(() => {\n if (isAccordionGroup) return false; // default closed — context controls it\n if (level === 0) return true; // top-level section stays open\n return false; // leaves\n });\n\n const effectiveOpen = isAccordionGroup ? openId === fullHref : isOpen;\n const handleToggle = () => {\n if (isAccordionGroup) toggle(fullHref);\n else setIsOpen((o) => !o);\n };\n\n // Auto-expand the accordion group that contains the active page — on mount\n // and whenever the current path changes. `open` is stable (useCallback), so\n // this only fires on real path changes; a manual collapse by the user is\n // respected until the path changes again.\n const isInsideActive = currentPathname.startsWith(fullHref) && currentPathname !== fullHref;\n useEffect(() => {\n if (isAccordionGroup && isInsideActive) open(fullHref);\n }, [isAccordionGroup, isInsideActive, fullHref, open]);\n\n // Shared padding based on nesting level\n const levelPadding = cn(level === 1 && \"pl-4\", level === 2 && \"pl-8\", level >= 3 && \"pl-12\");\n const isActive = currentPathname === fullHref || currentPathname === `${fullHref}.html`;\n const activeRef = useRef<HTMLDivElement>(null);\n\n useEffect(() => {\n if (isActive && activeRef.current) {\n activeRef.current.scrollIntoView({ block: \"nearest\" });\n }\n }, [isActive]);\n\n // Leaf node (no children)\n if (!items) {\n const link = (\n <Anchor\n href={docsHtmlHref(fullHref)}\n className=\"text-foreground hover:text-foreground/80 text-sm transition-colors\"\n activeClassName=\"text-primary font-medium\"\n activeWhen={(path) => path === fullHref || path === `${fullHref}.html`}\n onClick={onNavigate}\n >\n {title}\n </Anchor>\n );\n\n // Level 0: border handled by Menu.tsx wrapper\n // Level 1+: border at natural indented position, follows levelPadding\n if (level >= 1) {\n // Separator mode: active border overlaps at ul's edge\n // Each parent section adds its levelPadding to the offset\n if (docuConfig.sidebar?.context === \"separator\") {\n // Calculate accumulated offset from ul's edge to this item's natural position\n // Base: ul border(2px) + pl-3(12px) = 14px\n // Each parent section adds: level 1→16px, level 2→32px, level 3+→48px\n const sectionOffsets: Record<number, number> = { 1: 16, 2: 32 };\n let overlap = 14;\n for (let l = 1; l < level; l++) {\n overlap += sectionOffsets[l] ?? 48;\n }\n\n return (\n <div\n ref={activeRef}\n className={cn(\"border-l-2\", isActive ? \"border-primary\" : \"border-transparent\")}\n style={{ marginLeft: `-${overlap}px` }}\n >\n <div className={cn(\"py-1 pl-3\", levelPadding)}>{link}</div>\n </div>\n );\n }\n\n return (\n <div\n ref={activeRef}\n className={cn(\n \"py-1\",\n levelPadding,\n \"border-l-2\",\n isActive ? \"border-primary\" : \"border-base-300\"\n )}\n >\n {link}\n </div>\n );\n }\n\n return (\n <div ref={activeRef} className={cn(\"py-1\", levelPadding)}>\n {link}\n </div>\n );\n }\n\n // Section with children\n return (\n <div ref={isActive ? activeRef : undefined} className={cn(\"flex flex-col\", levelPadding)}>\n {/* Section header */}\n <button\n type=\"button\"\n onClick={handleToggle}\n className={cn(\n \"flex w-full cursor-pointer items-center justify-between py-1 text-left text-sm transition-colors\",\n // Only the top-level section label (routes-tree level 1) is bold.\n // Deeper groups (e.g. Search at level 2) are children that happen to\n // have items — style them like links, no header weight.\n noLink && treeLevel === 1\n ? \"text-base-content font-semibold\"\n : \"text-foreground hover:text-foreground/80\"\n )}\n >\n {noLink ? (\n <span>{title}</span>\n ) : (\n <Anchor\n href={docsHtmlHref(fullHref)}\n className=\"text-foreground hover:text-foreground/80 transition-colors\"\n activeClassName=\"text-primary\"\n activeWhen={(path) => path === fullHref || path === `${fullHref}.html`}\n onClick={onNavigate}\n >\n {title}\n </Anchor>\n )}\n <ChevronDown\n className={cn(\n \"text-base-content/40 h-4 w-4 shrink-0 transition-transform duration-200\",\n // Tree convention: closed = chevron pointing right (expandable),\n // open = pointing down — a 90° turn instead of the 180° flip.\n effectiveOpen ? \"rotate-0\" : \"-rotate-90\"\n )}\n />\n </button>\n\n {/* Children */}\n {effectiveOpen && (\n <div className=\"flex flex-col py-1\">\n {items.map((item) => (\n <Sublink\n key={`${fullHref}${item.href}`}\n {...item}\n href={item.href}\n level={level + 1}\n onNavigate={onNavigate}\n parentHref={fullHref}\n pathname={pathnameProp}\n />\n ))}\n </div>\n )}\n </div>\n );\n}\n","import { renderLucideIcon } from \"./Lucide\";\n\ninterface SidebarGroupHeaderProps {\n icon?: string;\n title: string;\n}\n\nexport default function SidebarGroupHeader({ icon, title }: SidebarGroupHeaderProps) {\n return (\n <div className=\"sidebar-group-header mb-1.5 flex items-center gap-2.5 font-medium text-gray-900 dark:text-gray-200\">\n {icon && (\n <span className=\"flex h-4 w-4 shrink-0 items-center justify-center\">\n {renderLucideIcon(icon, \"h-3.5 w-3.5\")}\n </span>\n )}\n <h3 className=\"sidebar-title font-[inherit] text-[length:inherit] leading-[inherit]\">\n <span>{title}</span>\n </h3>\n </div>\n );\n}\n","\"use client\";\n\nimport { useState } from \"react\";\nimport Sublink, { GroupAccordionProvider } from \"./Sublink\";\nimport SidebarGroupHeader from \"./SidebarGroupHeader\";\nimport type { DocuRoute } from \"../node/types\";\nimport { cn } from \"../node/utils\";\nimport { config as docuConfig } from \"../node/client-routes\";\n\ninterface MenuProps {\n onNavigate?: () => void;\n className?: string;\n pathname?: string;\n routes?: DocuRoute[];\n}\n\nfunction getCurrentContext(path: string): string | undefined {\n if (!path.startsWith(\"/docs\")) return undefined;\n const match = path.match(/^\\/docs\\/([^/]+)/);\n return match ? match[1] : undefined;\n}\n\nfunction getContextRoute(contextPath: string, routeList: DocuRoute[]): DocuRoute | undefined {\n return routeList.find((route) => {\n const normalizedHref = route.href.replace(/^\\/+|\\/+$/, \"\");\n return normalizedHref === contextPath;\n });\n}\n\nexport default function Menu({ onNavigate, className = \"\", pathname, routes = [] }: MenuProps) {\n const menuRoutes = routes;\n const [currentPath] = useState(\n () => pathname || (typeof window !== \"undefined\" ? window.location.pathname : \"/docs\")\n );\n\n if (!currentPath.startsWith(\"/docs\")) return null;\n\n const mode = docuConfig.sidebar?.context || \"dropdown\";\n const navProps = {\n \"aria-label\": \"Documentation navigation\" as const,\n className: cn(\"transition-all duration-200\", className),\n };\n\n // Shared nav item with border-left overlap wrapper\n const renderBorderItem = (item: DocuRoute, parentRouteHref: string, key: string) => {\n const fullHref = `/docs${parentRouteHref}${item.href}`;\n const isActive = currentPath === fullHref || currentPath === `${fullHref}.html`;\n return (\n <li key={key}>\n <div\n className={cn(\n \"-ml-[14px] border-l-2\",\n isActive ? \"border-primary\" : \"border-transparent\"\n )}\n >\n <div className=\"pl-3\">\n <Sublink\n {...item}\n href={item.href}\n level={0}\n onNavigate={onNavigate}\n parentHref={`/docs${parentRouteHref}`}\n />\n </div>\n </div>\n </li>\n );\n };\n\n const sharedUlClasses = \"border-base-300 flex flex-col gap-0.5 border-l-2 pb-0.5 pl-3 pt-0.5\";\n\n // Separator mode: render all context sections as group headers + nav items\n if (mode === \"separator\") {\n const contextRoutes = menuRoutes.filter((r) => r.context);\n\n // No context routes defined — fall back to flat list of all routes\n if (contextRoutes.length === 0) {\n return (\n <GroupAccordionProvider>\n <nav {...navProps}>\n <ul className={sharedUlClasses}>\n {menuRoutes.map((route) => renderBorderItem(route, \"\", route.href))}\n </ul>\n </nav>\n </GroupAccordionProvider>\n );\n }\n\n return (\n <GroupAccordionProvider>\n <nav {...navProps}>\n {contextRoutes.map((route, i) => (\n <div key={route.href} className={i > 0 ? \"mt-6 lg:mt-8\" : \"\"}>\n <SidebarGroupHeader\n icon={route.context?.icon}\n title={route.context?.title || route.title}\n />\n <ul className={sharedUlClasses}>\n {route.items?.map((item) => renderBorderItem(item, route.href, item.href))}\n </ul>\n </div>\n ))}\n </nav>\n </GroupAccordionProvider>\n );\n }\n\n // Dropdown mode: render only the active context section\n const isDocsRoot = currentPath === \"/docs\" || currentPath === \"/docs/\";\n const currentContext = isDocsRoot\n ? menuRoutes[0]?.href.replace(/^\\/+|\\/+$/, \"\")\n : getCurrentContext(currentPath);\n\n const contextRoute =\n isDocsRoot && menuRoutes[0]\n ? currentContext\n ? getContextRoute(currentContext, menuRoutes)\n : menuRoutes[0]\n : currentContext\n ? getContextRoute(currentContext, menuRoutes)\n : undefined;\n\n if (!contextRoute) return null;\n\n return (\n <GroupAccordionProvider>\n <nav {...navProps}>\n <ul className=\"flex flex-col gap-0.5 py-4\">\n <li key={contextRoute.title}>\n <Sublink\n {...contextRoute}\n href={contextRoute.href}\n level={0}\n onNavigate={onNavigate}\n parentHref=\"/docs\"\n />\n </li>\n </ul>\n </nav>\n </GroupAccordionProvider>\n );\n}\n","import React from \"react\";\nimport { loadDocuConfig } from \"../node/paths\";\nimport Menu from \"./Menu\";\n\nconst docuConfig = loadDocuConfig();\n\ninterface DocsLayoutProps {\n children?: React.ReactNode;\n repoUrl?: string;\n pathname?: string;\n}\n\nexport function DocsLayout({ children, repoUrl, pathname = \"/docs\" }: DocsLayoutProps) {\n return React.createElement(\n \"div\",\n { className: \"docs-layout flex flex-col min-h-screen w-full\" },\n React.createElement(\n \"div\",\n { className: \"flex flex-1 items-start w-full\" },\n React.createElement(\n \"aside\",\n {\n id: \"sidebar-island\",\n className:\n \"sticky top-0 hidden h-screen w-[280px] shrink-0 flex-col lg:flex border-r border-base-200 bg-base-100\",\n \"data-tocs\": \"[]\",\n \"data-title\": \"\",\n \"data-repo\": repoUrl || \"\",\n },\n // SSR sidebar content — Menu rendered server-side\n React.createElement(\n \"div\",\n { className: \"flex h-full flex-col overflow-y-auto px-4\" },\n React.createElement(Menu, { pathname, routes: docuConfig.routes || [] })\n )\n ),\n React.createElement(\n \"main\",\n { className: \"flex-1 min-w-0 min-h-screen flex flex-col\" },\n React.createElement(\n \"div\",\n { className: \"hidden lg:flex items-center justify-end gap-6 h-14 px-8\" },\n React.createElement(\n \"nav\",\n { className: \"flex items-center gap-6 text-sm font-medium text-base-content/80\" },\n ...(docuConfig.navbar?.menu || []).map((item: { title: string; href: string }) => {\n const isExternal = /^https?:\\/\\//.test(item.href);\n const isDocsActive = item.href === \"/docs\";\n return React.createElement(\n \"a\",\n {\n key: item.title,\n href: item.href,\n className: `flex items-center gap-1 hover:text-base-content transition-colors${isDocsActive ? \" text-primary font-semibold\" : \"\"}`,\n ...(isExternal ? { target: \"_blank\", rel: \"noopener noreferrer\" } : {}),\n },\n item.title,\n isExternal\n ? React.createElement(\n \"svg\",\n {\n xmlns: \"http://www.w3.org/2000/svg\",\n width: \"14\",\n height: \"14\",\n viewBox: \"0 0 24 24\",\n fill: \"none\",\n stroke: \"currentColor\",\n strokeWidth: \"2\",\n strokeLinecap: \"round\",\n strokeLinejoin: \"round\",\n },\n React.createElement(\"path\", { d: \"M7 7h10v10\" }),\n React.createElement(\"path\", { d: \"M7 17 17 7\" })\n )\n : null\n );\n })\n )\n ),\n React.createElement(\"div\", { className: \"flex-1 w-full\" }, children)\n )\n )\n );\n}\n","const ESCAPE_RE = /[&<>\"']/g;\n\nconst ESCAPE_MAP: Record<string, string> = {\n \"&\": \"&amp;\",\n \"<\": \"&lt;\",\n \">\": \"&gt;\",\n '\"': \"&quot;\",\n \"'\": \"&#x27;\",\n};\n\n/**\n * Runtime-neutral HTML escaping — same character set as `Bun.escapeHTML`\n * (& < > \" '). Used by the shared HTML shell so Node/Deno entries never\n * touch the Bun global.\n */\nexport function escapeHtml(input: string): string {\n return input.replace(ESCAPE_RE, (ch) => ESCAPE_MAP[ch]);\n}\n","/**\n * Runtime-neutral HTML shell — identical templates to `html.ts` (Bun-only,\n * protected) but escaping via the pure `escapeHtml()` so it runs on\n * Node.js and Deno as well as Bun. Shared modules (`server-routes.ts`) and\n * the non-Bun entries import from here; `build.ts`/`server.ts` keep using\n * `html.ts` untouched.\n */\n\nimport { escapeHtml } from \"./escapeHtml\";\n\nimport type { SeoMeta } from \"./seo\";\n\nexport interface HtmlShellOptions {\n title: string;\n description: string;\n body: string;\n favicon: string;\n css: string;\n js: string;\n nonce?: string;\n /**\n * Content-Security-Policy value (from `cspHeader()` in security.ts).\n * When provided, injects `<meta http-equiv=\"Content-Security-Policy\">` in `<head>`.\n * Essential for static deployment where HTTP headers cannot be set.\n */\n csp?: string;\n extraScripts?: string;\n themeCss?: string;\n /** Depth from document root (0=root, 1=subdir, 2=sub/subdir). Used for relative asset paths. */\n depth?: number;\n /** HTML strings to inject before `</head>` (from plugin `injectHead` hooks). */\n headExtra?: string[];\n /** HTML strings to inject before `</body>`, after the main script (from plugin `injectBody` hooks). */\n bodyExtra?: string[];\n /** SEO meta tags derived from config + frontmatter */\n seo?: SeoMeta;\n /** Root-absolute asset URLs (`/assets/...`). Required for pages served at\n * arbitrary paths (404 fallback) — relative depth is wrong there. */\n absoluteAssets?: boolean;\n}\n\nexport function htmlShell(opts: HtmlShellOptions): string {\n const {\n title,\n description,\n body,\n favicon,\n css,\n js,\n nonce,\n csp,\n extraScripts,\n themeCss,\n depth = 0,\n headExtra,\n bodyExtra,\n absoluteAssets = false,\n } = opts;\n const nonceAttr = nonce ? ` nonce=\"${escapeHtml(nonce)}\"` : \"\";\n const themeStyle = themeCss ? `\\n <style${nonceAttr}>${escapeHtml(themeCss)}</style>` : \"\";\n const headInjection = headExtra?.length ? `\\n ${headExtra.join(\"\\n \")}` : \"\";\n const bodyInjection = bodyExtra?.length ? `\\n ${bodyExtra.join(\"\\n \")}` : \"\";\n const depthPrefix = depth === 0 ? \"\" : \"../\".repeat(depth);\n const assetPrefix = absoluteAssets ? \"/assets/\" : depthPrefix + \"assets/\";\n const resolvePath = (path: string) =>\n absoluteAssets ? path : path.startsWith(\"/\") ? depthPrefix + path.slice(1) : path;\n\n // Build SEO meta tags (OG, Twitter, canonical)\n let seoTags = \"\";\n if (opts.seo) {\n const s = opts.seo;\n const e = escapeHtml;\n seoTags = `\\n <meta property=\"og:title\" content=\"${e(title)}\" />\\n <meta property=\"og:description\" content=\"${e(description)}\" />\\n <meta property=\"og:url\" content=\"${e(s.url)}\" />\\n <meta property=\"og:type\" content=\"website\" />\\n <meta property=\"og:site_name\" content=\"${e(s.siteName)}\" />\\n <meta name=\"twitter:card\" content=\"summary_large_image\" />\\n <link rel=\"canonical\" href=\"${e(s.url)}\" />`;\n if (s.image) {\n seoTags += `\\n <meta property=\"og:image\" content=\"${e(s.image)}\" />`;\n }\n }\n\n return `<!DOCTYPE html>\n<html lang=\"en\">\n<head>\n <meta charset=\"UTF-8\">\n <meta name=\"viewport\" content=\"width=device-width, initial-scale=1.0\">\n <title>${escapeHtml(title)}</title>\n <meta name=\"description\" content=\"${escapeHtml(description)}\">\n ${favicon ? `<link rel=\"icon\" type=\"image/x-icon\" href=\"${escapeHtml(resolvePath(favicon))}\">` : \"\"}${themeStyle}\n <link rel=\"preload\" href=\"${escapeHtml(assetPrefix + css)}\" as=\"style\">\n <link rel=\"stylesheet\" href=\"${escapeHtml(assetPrefix + css)}\">\n ${csp ? `<meta http-equiv=\"Content-Security-Policy\" content=\"${escapeHtml(csp)}\">` : \"\"}\n ${seoTags}\n <script${nonceAttr}>try{if(localStorage.getItem(\"theme\")===\"dark\")document.documentElement.classList.add(\"dark\")}catch(e){}</script>${headInjection}\n</head>\n<body>\n <div id=\"root\">${body}</div>\n <link rel=\"modulepreload\" href=\"${escapeHtml(assetPrefix + js)}\">\n <script type=\"module\"${nonceAttr} src=\"${escapeHtml(assetPrefix + js)}\"></script>${extraScripts ? `\\n ${extraScripts}` : \"\"}${bodyInjection}\n</body>\n</html>`;\n}\n\nexport function errorHtml(message: string, stack?: string): string {\n const msg = escapeHtml(message || \"Unknown error\");\n const st = escapeHtml(stack || \"\");\n return `<!DOCTYPE html>\n<html lang=\"en\">\n<head>\n <meta charset=\"utf-8\">\n <title>Server Error</title>\n <style>\n *{margin:0;padding:0;box-sizing:border-box}\n body{padding:2rem;font-family:ui-monospace,monospace;background:#1a1a2e;color:#e0e0e0}\n h1{color:#ff6b6b;font-size:1.5rem;margin-bottom:1rem}\n pre{background:#0d0d1a;border:1px solid #333;border-radius:8px;padding:1.5rem;overflow-x:auto;font-size:14px;line-height:1.6;white-space:pre-wrap;word-break:break-word}\n .msg{color:#ff6b6b;font-weight:bold}\n </style>\n</head>\n <body>\n <h1>🔥 Server Error</h1>\n <pre><span class=\"msg\">${msg}</span>${st ? `\\n\\n${st}` : \"\"}</pre>\n </body>\n</html>`;\n}\n\nexport function hmrScript(nonce: string): string {\n return `<script nonce=\"${escapeHtml(nonce)}\">\n(function(){\n const es = new EventSource(\"/__hmr\");\n es.onmessage = function(e) {\n if (e.data === \"reload\") window.location.reload();\n };\n es.onerror = function() { es.close(); setTimeout(() => { window.location.reload(); }, 2000); };\n})();\n</script>`;\n}\n"],"mappings":";;;;;;;;;;;;;;;;;;;;;AAIA,IAAM,iBAAiB;;;;;;;;;;;;;;AAevB,SAAgB,iBAAiB,WAA2B;CAC1D,IAAI;CAEJ,IAAI,UAAU,WAAW,GAAG,GAE1B,WAAW,QAAQ,cAAc,SAAS;MACrC,IAAI,UAAU,WAAW,GAAG,GAEjC,WAAW;MACN;EAEL,IAAI,CAAC,eAAe,KAAK,SAAS,GAChC,MAAM,IAAI,MACR,6CAA6C,UAAU,qEACzD;EAEF,OAAO;CACT;CAGA,MAAM,OAAO,aAAa,SAAS,GAAG,IAAI,eAAe,eAAe;CACxE,IAAI,CAAC,SAAS,WAAW,IAAI,GAC3B,MAAM,IAAI,MACR,4CAA4C,UAAU,gCACxD;CAGF,OAAO;AACT;;;;;;;;;;;;;;;;;;;;AAqBA,eAAsB,YAAY,UAAyB,CAAC,GAA8B;CACxF,MAAM,UAA4B,CAAC;CAEnC,KAAK,MAAM,SAAS,SAAS;EAC3B,MAAM,CAAC,WAAW,WAAW,MAAM,QAAQ,KAAK,IAAI,QAAQ,CAAC,OAAO,KAAA,CAAS;EAC7E,MAAM,WAAW,iBAAiB,SAAS;EAE3C,IAAI;EACJ,IAAI;GACF,MAAM,MAAM,OAAO;EACrB,SAAS,KAAK;GACZ,MAAM,UAAU,eAAe,QAAQ,IAAI,UAAU,OAAO,GAAG;GAC/D,MAAM,IAAI,MAAM,4CAA4C,UAAU,KAAK,WAAW,EACpF,OAAO,IACT,CAAC;EACH;EAEA,MAAM,WAAW,IAAI;EAErB,IAAI;EAEJ,IAAI,OAAO,aAAa,YAEtB,IAAI;GACF,SAAU,SAAgE,OAAO;EACnF,SAAS,KAAK;GACZ,MAAM,UAAU,eAAe,QAAQ,IAAI,UAAU,OAAO,GAAG;GAC/D,MAAM,IAAI,MACR,mCAAmC,UAAU,iCAAiC,WAC9E,EAAE,OAAO,IAAI,CACf;EACF;OACK,IAAI,YAAY,OAAO,aAAa,UAEzC,SAAS;OAET,MAAM,IAAI,MACR,2BAA2B,UAAU,mDAAmD,OAAO,UACjG;EAGF,IAAI,CAAC,OAAO,QAAQ,OAAO,OAAO,SAAS,UACzC,MAAM,IAAI,MACR,2BAA2B,UAAU,qDAAqD,OAAO,OAAO,MAC1G;EAGF,IAAI,OAAO,OAAO,UAAU,YAC1B,MAAM,IAAI,MACR,2BAA2B,UAAU,YAAY,OAAO,KAAK,wCAC/D;EAGF,QAAQ,KAAK,MAAM;CACrB;CAEA,OAAO;AACT;;;AC/GA,IAAa,qBAAb,MAAyD;CACvD;CAEA,iBAEI,CAAC;CACL,cAA0E,CAAC;CAC3E,cAA0E,CAAC;CAC3E,SAAoF,CAAC;CACrF,UAAmC,CAAC;CACpC,WAAmE,CAAC;CACpE,iBAAmD,CAAC;CACpD,iBAAmD,CAAC;CACpD,wBAKI,CAAC;CACL,iBAA2F,CAAC;CAE5F,YAAY,QAAoB;EAC9B,KAAK,SAAS;CAChB;;;;;;;;;;CAWA,YAAY,SAAgC;EAC1C,MAAM,QAAkB,CAAC;EACzB,KAAK,MAAM,MAAM,KAAK,aACpB,IAAI;GACF,MAAM,SAAS,GAAG,OAAO;GACzB,IAAI,QACF,KAAK,aAAa,OAAO,QAAQ,YAAY;EAEjD,SAAS,KAAK;GACZ,MAAM,IAAI,MACR,wCAAwC,eAAe,QAAQ,IAAI,UAAU,OAAO,GAAG,KACvF,EAAE,OAAO,IAAI,CACf;EACF;EAEF,OAAO,CAAC,GAAG,IAAI,IAAI,KAAK,CAAC;CAC3B;;;;;;;;;;CAWA,YAAY,SAAgC;EAC1C,MAAM,QAAkB,CAAC;EACzB,KAAK,MAAM,MAAM,KAAK,aACpB,IAAI;GACF,MAAM,SAAS,GAAG,OAAO;GACzB,IAAI,QACF,KAAK,aAAa,OAAO,QAAQ,YAAY;EAEjD,SAAS,KAAK;GACZ,MAAM,IAAI,MACR,wCAAwC,eAAe,QAAQ,IAAI,UAAU,OAAO,GAAG,KACvF,EAAE,OAAO,IAAI,CACf;EACF;EAEF,OAAO,CAAC,GAAG,IAAI,IAAI,KAAK,CAAC;CAC3B;;;;;;;;CASA,uBAAoC;EAClC,MAAM,UAAuB,CAAC;EAC9B,KAAK,MAAM,MAAM,KAAK,gBACpB,IAAI;GACF,QAAQ,KAAK,GAAG,GAAG,CAAC;EACtB,SAAS,KAAK;GACZ,MAAM,IAAI,MACR,2CAA2C,eAAe,QAAQ,IAAI,UAAU,OAAO,GAAG,KAC1F,EAAE,OAAO,IAAI,CACf;EACF;EAEF,OAAO;CACT;;;;;;;;CASA,uBAAoC;EAClC,MAAM,UAAuB,CAAC;EAC9B,KAAK,MAAM,MAAM,KAAK,gBACpB,IAAI;GACF,QAAQ,KAAK,GAAG,GAAG,CAAC;EACtB,SAAS,KAAK;GACZ,MAAM,IAAI,MACR,2CAA2C,eAAe,QAAQ,IAAI,UAAU,OAAO,GAAG,KAC1F,EAAE,OAAO,IAAI,CACf;EACF;EAEF,OAAO;CACT;;;;;;;;;;;;;;;;;CAkBA,cACE,UACM;EACN,KAAK,eAAe,KAAK,QAAQ;CACnC;;;;;;;;;;CAWA,WAAW,UAA6D;EACtE,KAAK,YAAY,KAAK,QAAQ;CAChC;;;;;;;;;;CAWA,WAAW,UAA6D;EACtE,KAAK,YAAY,KAAK,QAAQ;CAChC;;;;;;;;;;;;;;;;;;CAmBA,MAAM,UAA4E;EAChF,KAAK,OAAO,KAAK,QAAQ;CAC3B;;;;;;;;;;;;;;;;CAiBA,OACE,MACA,UAIM;EACN,KAAK,QAAQ,KAAK;GAAE,GAAG;GAAM,IAAI;EAAS,CAAC;CAC7C;;;;;;;;;;;;;CAcA,QAAQ,UAAyD;EAC/D,KAAK,SAAS,KAAK,QAAQ;CAC7B;;;;;;;;;;CAWA,cAAc,UAAmC;EAC/C,KAAK,eAAe,KAAK,QAAQ;CACnC;;;;;;;;;;CAWA,cAAc,UAAmC;EAC/C,KAAK,eAAe,KAAK,QAAQ;CACnC;;;;;;;;;;;CAYA,MAAM,iBAAiB,KAAc,SAAqD;EACxF,KAAK,IAAI,IAAI,GAAG,IAAI,KAAK,eAAe,QAAQ,KAC9C,IAAI;GACF,MAAM,SAAS,MAAM,KAAK,eAAe,EAAE,CAAC,KAAK,OAAO;GACxD,IAAI,kBAAkB,UACpB,OAAO;EAEX,SAAS,KAAK;GACZ,QAAQ,MACN,oCAAoC,IAAI,EAAE,UAAU,eAAe,QAAQ,IAAI,UAAU,OAAO,GAAG,GACrG;EACF;EAEF,OAAO;CACT;;;;;;;;;CAUA,MAAM,SAAS,OAAkC;EAC/C,KAAK,IAAI,IAAI,GAAG,IAAI,KAAK,OAAO,QAAQ,KACtC,IAAI;GACF,MAAM,KAAK,OAAO,EAAE,CAAC,KAAK,QAAQ,KAAK;EACzC,SAAS,KAAK;GACZ,QAAQ,MACN,4BAA4B,IAAI,EAAE,UAAU,eAAe,QAAQ,IAAI,UAAU,OAAO,GAAG,GAC7F;EACF;CAEJ;;;;;;;;;;;CAYA,MAAM,UACJ,MACA,SACqE;EACrE,KAAK,MAAM,WAAW,KAAK,SACzB,IAAI,QAAQ,OAAO,KAAK,IAAI,GAC1B,IAAI;GACF,MAAM,SAAS,MAAM,QAAQ,GAAG;IAAE;IAAM;GAAQ,CAAC;GACjD,IAAI,QAAQ,OAAO;EACrB,SAAS,KAAK;GACZ,QAAQ,MACN,sCAAsC,QAAQ,OAAO,UAAU,eAAe,QAAQ,IAAI,UAAU,OAAO,GAAG,GAChH;EACF;EAGJ,OAAO;CACT;;;;;;;CAQA,MAAM,aAA4B;EAChC,KAAK,IAAI,IAAI,GAAG,IAAI,KAAK,SAAS,QAAQ,KACxC,IAAI;GACF,MAAM,KAAK,SAAS,EAAE,CAAC,KAAK,MAAM;EACpC,SAAS,KAAK;GACZ,QAAQ,MACN,8BAA8B,IAAI,EAAE,UAAU,eAAe,QAAQ,IAAI,UAAU,OAAO,GAAG,GAC/F;EACF;CAEJ;;;;;;;;;;;;;;;CAgBA,MAAM,6BACJ,aACA,SACkC;EAClC,IAAI,SAAS;EACb,KAAK,IAAI,IAAI,GAAG,IAAI,KAAK,sBAAsB,QAAQ,KACrD,IAAI;GACF,MAAM,OAAO,MAAM,KAAK,sBAAsB,EAAE,CAAC,QAAQ,OAAO;GAChE,IAAI,SAAS,KAAA,KAAa,SAAS,MAAM;IACvC,IAAI,OAAO,SAAS,YAAY,CAAC,MAAM,QAAQ,IAAI,GACjD,SAAS;SAET,QAAQ,KACN,2CAA2C,IAAI,EAAE,2DACnD;GAEJ;EACF,SAAS,KAAK;GACZ,QAAQ,MACN,2CAA2C,IAAI,EAAE,UAAU,eAAe,QAAQ,IAAI,UAAU,OAAO,GAAG,GAC5G;EACF;EAEF,OAAO;CACT;;;;;;;;;;;;CAaA,MAAM,sBAAsB,MAAc,SAAuC;EAC/E,IAAI,SAAS;EACb,KAAK,IAAI,IAAI,GAAG,IAAI,KAAK,eAAe,QAAQ,KAC9C,IAAI;GACF,SAAS,MAAM,KAAK,eAAe,EAAE,CAAC,QAAQ,OAAO;EACvD,SAAS,KAAK;GACZ,QAAQ,MACN,oCAAoC,IAAI,EAAE,UAAU,eAAe,QAAQ,IAAI,UAAU,OAAO,GAAG,GACrG;EACF;EAEF,OAAO;CACT;;;;;;;;;;;;;;;;;;CAmBA,qBACE,UAIM;EACN,KAAK,sBAAsB,KAAK,QAAQ;CAC1C;;;;;;;;;;;;;CAcA,cAAc,UAA2E;EACvF,KAAK,eAAe,KAAK,QAAQ;CACnC;;;;;CAMA,aAAqB,OAAiB,QAA2B,UAAwB;EACvF,IAAI,MAAM,QAAQ,MAAM,GACtB,KAAK,MAAM,QAAQ,QACjB,IAAI,OAAO,SAAS,UAClB,MAAM,KAAK,IAAI;OAEf,QAAQ,KACN,YAAY,SAAS,0CAA0C,OAAO,KAAK,YAC7E;OAGC,IAAI,OAAO,WAAW,UAC3B,MAAM,KAAK,MAAM;OAEjB,QAAQ,KACN,YAAY,SAAS,0CAA0C,OAAO,OAAO,yCAC/E;CAEJ;AACF;;;ACrdA,SAAS,cAAY,KAAqB;CACxC,OAAO,IACJ,QAAQ,MAAM,GAAG,CAAC,CAClB,QAAQ,MAAM,GAAG,CAAC,CAClB,QAAQ,mBAAmB,OAAO,CAAC,CACnC,MAAM,GAAG,CAAC,CACV,KAAK,SAAS,KAAK,OAAO,CAAC,CAAC,CAAC,YAAY,IAAI,KAAK,MAAM,CAAC,CAAC,CAAC,YAAY,CAAC,CAAC,CACzE,KAAK,GAAG;AACb;AAEA,SAAS,UAAU,UAA2B;CAC5C,MAAM,MAAM,QAAQ,QAAQ,CAAC,CAAC,YAAY;CAC1C,OAAO,CAAC,QAAQ,KAAK,CAAC,CAAC,SAAS,GAAG;AACrC;AAEA,SAAS,cAAc,MAAsB;CAC3C,OAAO,KAAK,MAAM,GAAG,CAAC,CAAC,KAAK,GAAG;AACjC;;;;;;;AAQA,SAAS,QAAQ,SAAiB,UAA8B;CAC9D,MAAM,QAAoB,CAAC;CAE3B,IAAI;CACJ,IAAI;EACF,UAAU,YAAY,OAAO,CAAC,CAAC,KAAK;CACtC,SAAS,KAAK;EACZ,IAAK,IAA8B,SAAS,UAAU,MAAM;EAC5D,OAAO;CACT;CAEA,KAAK,MAAM,SAAS,SAAS;EAC3B,IAAI,MAAM,WAAW,GAAG,KAAK,UAAU,UAAU;EAEjD,MAAM,UAAU,KAAK,SAAS,KAAK;EAEnC,IAAI;GACF,MAAM,OAAO,SAAS,OAAO;GAE7B,IAAI,KAAK,YAAY,GAAG;IACtB,MAAM,WAAW,QAAQ,SAAS,QAAQ;IAC1C,IAAI,SAAS,SAAS,GACpB,MAAM,KAAK;KACT,MAAM;KACN,SAAS,cAAc,SAAS,UAAU,OAAO,CAAC;KAClD;KACA,aAAa;KACb;IACF,CAAC;GAEL,OAAO,IAAI,KAAK,OAAO,KAAK,UAAU,KAAK,GACzC,MAAM,KAAK;IACT,MAAM;IACN,SAAS,cAAc,SAAS,UAAU,OAAO,CAAC,CAAC,QAAQ,eAAe,EAAE,CAAC;IAC7E;IACA,aAAa;GACf,CAAC;EAEL,SAAS,KAAK;GACZ,IAAK,IAA8B,SAAS,UAAU,MAAM;GAC5D;EACF;CACF;CAEA,OAAO;AACT;AAEA,SAAS,kBAAkB,OAAmB,aAAa,IAAiB;CAC1E,MAAM,SAAsB,CAAC;CAE7B,KAAK,MAAM,QAAQ,OACjB,IAAI,CAAC,KAAK,aAAa;EACrB,MAAM,WAAW,KAAK,KAAK,QAAQ,eAAe,EAAE;EAEpD,IADoB,oBAAoB,KAAK,QACzC,GAAa;EAGjB,MAAM,OAAO,IADG,KAAK,QAAQ,MAAM,GAAG,CAAC,CAAC,IACvB;EAEjB,OAAO,KAAK;GACV,OAAO,cAAY,QAAQ;GAC3B;EACF,CAAC;CACH,OAAO;EACL,MAAM,WAAW,cAAY,KAAK,IAAI;EAEtC,MAAM,UAAU,IADA,KAAK,QAAQ,MAAM,GAAG,CAAC,CAAC,IACpB;EAEpB,MAAM,WAAW,kBAAkB,KAAK,YAAY,CAAC,GAAG,OAAO;EAE/D,IAAI,SAAS,WAAW,GAAG;EAM3B,KAJsB,KAAK,YAAY,CAAC,EAAA,CAAG,MACxC,MAAM,CAAC,EAAE,eAAe,8BAA8B,KAAK,EAAE,IAAI,CAGhE,GACF,OAAO,KAAK;GACV,OAAO;GACP,MAAM;GACN,GAAI,eAAe,MAAM,EACvB,SAAS;IAAE,OAAO;IAAU,MAAM;IAAc,aAAa;GAAS,EACxE;GACA,OAAO;EACT,CAAC;OAED,OAAO,KAAK;GACV,OAAO;GACP,MAAM;GACN,QAAQ;GACR,GAAI,eAAe,MAAM,EACvB,SAAS;IAAE,OAAO;IAAU,MAAM;IAAc,aAAa;GAAS,EACxE;GACA,OAAO;EACT,CAAC;CAEL;CAGF,OAAO;AACT;;;;;;AAOA,SAAgB,eAAe,WAAW,UAAuB;CAC/D,MAAM,cAAc,KAAK,QAAQ,IAAI,GAAG,QAAQ;CAEhD,OAAO,kBADO,QAAQ,aAAa,WACV,CAAK;AAChC;;;;;;;;AASA,SAAgB,cAAc,gBAA2C;CACvE,IAAI,kBAAkB,eAAe,SAAS,GAC5C,OAAO;CAET,OAAO,eAAe;AACxB;;;ACvKA,IAAM,gBAAgB;;;;;;AAOtB,SAAgB,iBAA0C;CACxD,IAAI,QAAQ,IAAI,aACd,OAAO,QAAQ,IAAI;CAGrB,OADe,eACR,CAAA,CAAO,QAAQ;AACxB;;;;AAKA,SAAgB,cAAc,SAAiB,aAA8B;CAC3E,IAAI;EACF,MAAM,WAAW,aAAa,aAA+C,aAAa;EAC1F,OAAO,UAAU,OAAO,iBAAiB,QAAQ;CACnD,SAAS,KAAK;EACZ,QAAQ,KACN,wCAAwC,eAAe,QAAQ,IAAI,UAAU,OAAO,GAAG,GACzF;EACA,OAAO;CACT;AACF;;;;;AAMA,SAAgB,wBAA4C;CAC1D,IAAI;EACF,MAAM,cAAc,eAAe;EACnC,IAAI,aAAa;GACf,MAAM,WAAW,aAAa,aAAa,aAAa;GACxD,OAAO,iBAAiB,QAAQ;EAClC;CACF,SAAS,KAAK;EACZ,QAAQ,KACN,+CAA+C,eAAe,QAAQ,IAAI,UAAU,OAAO,GAAG,GAChG;CACF;AAEF;;;;;;;;;;;;;ACzBA,SAAS,mBAAmB,QAA8B;CACxD,MAAM,QAAkB,CAAC;CACzB,MAAM,UAAU,MAA0B;EACxC,IAAI,GAAG,MAAM,KAAK,CAAC;CACrB;CACA,OAAO,MAAM,MAAM,SAAS,SAAS,MAAM,OAAO,EAAE,IAAI,CAAC;CACzD,OAAO,MAAM,UAAU,SAAS,MAAM,OAAO,EAAE,IAAI,CAAC;CACpD,CAAC,SAAS,KAAK,QAAqB;EAClC,KAAK,MAAM,KAAK,QAAQ;GACtB,OAAO,EAAE,SAAS,IAAI;GACtB,IAAI,EAAE,OAAO,KAAK,EAAE,KAAK;EAC3B;CACF,EAAA,CAAG,OAAO,UAAU,CAAC,CAAC;CACtB,OAAO,CAAC,GAAG,IAAI,IAAI,MAAM,QAAQ,MAAM,SAAS,KAAK,CAAC,CAAC,CAAC,CAAC;AAC3D;AAIA,IAAM,gBAAgB,UAAU,QAAQ;;AAGxC,SAAS,qBAA6B;CACpC,MAAM,UAAU,cAAc,YAAY,GAAG;CAC7C,MAAM,UAAU,QAAQ,QAAQ,+BAA+B;CAC/D,MAAM,MAAM,QAAQ,OAAO;CAC3B,MAAM,SAAS,OAAO,IAAI,QAAQ,WAAW,IAAI,MAAM,IAAI,IAAI;CAC/D,OAAO,KAAK,QAAQ,OAAO,GAAG,MAAM;AACtC;;AAGA,SAAS,mBAA2B;CAClC,MAAM,cAAc,KAAK,YAAY,aAAa;CAClD,MAAM,iBAAiB,WAAW,WAAW,IAAI,aAAa,aAAa,OAAO,IAAI;CACtF,IAAI,cAAc;CAClB,IAAI;EACF,MAAM,cAAc,eAAe;EACnC,IAAI,aACF,cAAc,KAAK,UAAU,WAAW;CAE5C,QAAQ,CAER;CACA,OAAO,WAAW,QAAQ,CAAC,CACxB,OAAO,iBAAiB,WAAW,CAAC,CACpC,OAAO,KAAK,CAAC,CACb,MAAM,GAAG,EAAE;AAChB;;;;;;AAOA,eAAe,iBAAiB,KAAyD;CACvF,MAAM,aAAa,UAAU,IAAI;CACjC,MAAM,aAAa,KAAK,YAAY,UAAU;CAE9C,IAAI,WAAW,UAAU,GAEvB,OAAO;EAAE,MAAM;EAAY,SADX,aAAa,YAAY,OACd;CAAQ;CAGrC,MAAM,SAAS,KAAK,YAAY,QAAQ,IAAI,KAAK;CACjD,MAAM,MAAM,mBAAmB;CAC/B,MAAM,SAAS;EAAC;EAAM,KAAK,YAAY,aAAa;EAAG;EAAM;EAAQ;CAAU;CAE/E,MAAM,OADS,UAAU,aACH;EAAC;EAAO;EAAM;EAAK,GAAG;CAAM,IAAI,CAAC,KAAK,GAAG,MAAM;CACrE,IAAI;EACF,MAAM,cAAc,QAAQ,UAAU,MAAM,EAAE,WAAW,SAAiB,CAAC;CAC7E,SAAS,KAAK;EACZ,MAAM,SAAU,IAA4B,UAAU,OAAO,GAAG;EAChE,MAAM,IAAI,MAAM,+BAA+B,UAAU,EAAE,OAAO,IAAI,CAAC;CACzE;CAEA,IAAI,aAAa,MAAM,SAAS,QAAQ,OAAO;CAC/C,MAAM,OAAO,MAAM;CAEnB,IAAI;EACF,MAAM,cAAc,eAAe;EACnC,IAAI,aACF,aAAa,cAAc,YAAY,WAAW;CAEtD,SAAS,KAAK;EACZ,QAAQ,KACN,6EAA6E,eAAe,QAAQ,IAAI,UAAU,OAAO,GAAG,GAC9H;CACF;CAIA,MAAM,UAAU,UAAU,IAAI;CAC9B,MAAM,UAAU,KAAK,YAAY,OAAO;CAExC,IAAI,CAAC,WAAW,OAAO,GACrB,MAAM,UAAU,SAAS,UAAU;CAGrC,OAAO;EAAE,MAAM;EAAS,SAAS;CAAW;AAC9C;AAEA,IAAM,mBAAmB,IAAI,OAC3B,aAAa,eAAe,KAAK,MAAM,EAAE,QAAQ,OAAO,KAAK,CAAC,CAAC,CAAC,KAAK,GAAG,EAAE,GAC5E;AAEA,IAAI;;AAGJ,SAAS,qBAA6B;CACpC,IAAI,CAAC,iBACH,kBAAkB,cAAc,YAAY,GAAG,CAAC,CAAC,QAAQ,cAAc;CAEzE,OAAO;AACT;AAEA,IAAM,mBAAmB;AACzB,IAAM,iBAAiB;;AAGvB,SAAS,mBAAmB,KAAa,KAAwB;CAC/D,IAAI,CAAC,WAAW,GAAG,GAAG;CACtB,IAAI;EACF,MAAM,UAAU,YAAY,KAAK,EAAE,eAAe,KAAK,CAAC;EACxD,KAAK,MAAM,KAAK,SAAS;GACvB,MAAM,OAAO,KAAK,KAAK,EAAE,IAAI;GAC7B,IAAI,EAAE,YAAY,GACZ;QAAA,EAAE,SAAS,gBAAgB,mBAAmB,MAAM,GAAG;GAAA,OACtD,IAAI,iBAAiB,KAAK,EAAE,IAAI,GAAG;IACxC,MAAM,UAAU,aAAa,MAAM,OAAO;IAC1C,KAAK,MAAM,KAAK,QAAQ,SAAS,gBAAgB,GAC/C,KAAK,MAAM,KAAK,EAAE,EAAE,CAAC,MAAM,GAAG,GAAG;KAC/B,MAAM,OAAO,EACV,KAAK,CAAC,CACN,MAAM,UAAU,CAAC,CAAC,EAAE,CACpB,KAAK;KACR,IAAI,eAAe,KAAK,IAAI,GAAG,IAAI,IAAI,IAAI;IAC7C;GAEJ;EACF;CACF,SAAS,KAAK;EACZ,QAAQ,KACN,wCAAwC,eAAe,QAAQ,IAAI,UAAU,OAAO,GAAG,GACzF;CACF;AACF;;AAGA,SAAS,wBAAkC;CACzC,MAAM,wBAAQ,IAAI,IAAY;CAE9B,mBAAmB,KAAK,gBAAgB,kBAAkB,GAAG,KAAK;CAClE,mBAAmB,KAAK,gBAAgB,aAAa,GAAG,KAAK;CAG7D,MAAM,UAAU;EACd,KAAK,gBAAgB,MAAM,eAAe,MAAM;EAChD,KAAK,gBAAgB,MAAM,YAAY,MAAM;EAC7C,KAAK,gBAAgB,MAAM,QAAQ,MAAM;EACzC,KAAK,gBAAgB,MAAM,iBAAiB,MAAM;CACpD;CACA,KAAK,MAAM,KAAK,SAAS,mBAAmB,QAAQ,CAAC,GAAG,KAAK;CAC7D,OAAO,CAAC,GAAG,KAAK;AAClB;;AAGA,eAAsB,kBAEpB,aAAqC,CAAC,GACA;CACtC,MAAM,MAAM,YAAY,EAAE,WAAW,KAAK,CAAC;CAC3C,MAAM,QAAQ,iBAAiB;CAC/B,MAAM,gCAAgB,IAAI,IAAI,CAAC,UAAU,MAAM,KAAK,CAAC,CAAC;CAEtD,MAAM,UAAA,QAAA,IAAA,YAAkC;CAExC,MAAM,YAAY,KAAK,SAAS,WAAW;CAC3C,MAAM,SAAS,MAAM,MAAU;EAC7B,YAAY;EACZ,WAAW;EACX,QAAQ,EAAE,wBAAwB,KAAK,UAAU,OAAO,EAAE;EAC1D,SAAS;GACP;IACE,MAAM;IACN,UAAU,IAAI;KACZ,IAAI,iBAAiB,KAAK,EAAE,GAAG,OAAO,eAAe;KACrD,OAAO;IACT;IACA,KAAK,IAAI;KACP,IAAI,CAAC,GAAG,WAAW,cAAc,GAAG,OAAO;KAC3C,OAAO;IACT;GACF;GACA;IACE,MAAM;IACN,UAAU,IAAI,UAAU;KACtB,IAAI,OAAO,gBAAgB,OAAO;KAClC,IAAI,UACiB;UAAA,sBAAsB,QACrC,CAAA,CAAW,SAAS,iBAAiB,GAAG,OAAO;KAAA;KAErD,OAAO;IACT;IACA,KAAK,IAAI;KACP,IAAI,OAAO,iBAAiB,OAAO;KACnC,MAAM,UAAU,sBAAsB;KACtC,MAAM,aAAa,mBAAmB,eAAe,CAAC;KAEtD,OAAO,YAAY,CADD,mBAAG,IAAI,IAAI,CAAC,GAAG,SAAS,GAAG,UAAU,CAAC,CACrC,CAAA,CAAS,KAAK,IAAI,EAAE,UAAU,KAAK,UAAU,mBAAmB,CAAC,EAAE;IACxF;GACF;GACA;IACE,MAAM;IACN,UAAU,IAAI;KACZ,IAAI,CAAC,iBAAiB,KAAK,EAAE,GAAG,OAAO;KACvC,OAAO;IACT;IACA,KAAK,IAAI;KACP,IAAI,OAAO,mBAAmB,OAAO;KACrC,MAAM,SAAS,eAAe;KAC9B,MAAM,WAAW;MACf,GAAG;MACH,QAAQ,cAAc,OAAO,MAAiC;KAChE;KACA,OAAO;MACL,sBAAsB,KAAK,UAAU,QAAQ,EAAE;MAC/C;MACA;KACF,CAAC,CAAC,KAAK,IAAI;IACb;GACF;GACA;IACE,MAAM;IACN,UAAU,IAAI;KACZ,IAAI,gBAAgB,KAAK,EAAE,GAAG,OAAO;KACrC,IAAI,GAAG,WAAW,aAAa,GAAG,OAAO,KAAK;KAC9C,OAAO;IACT;IACA,KAAK,IAAI;KACP,IAAI,OAAO,kBAAkB;MAC3B,MAAM,QAAQ,OAAO,KAAK,UAAU,CAAC,CAAC,KAAK;MAQ3C,OAAO,GAPS,MACb,KAAK,MAAM,MAAM;OAChB,MAAM,MAAM,KAAK,QAAQ,UAAU,EAAE;OACrC,OAAO,mBAAmB,EAAE,QAAQ,KAAK,UAAU,cAAc,KAAK,EAAE;MAC1E,CAAC,CAAC,CACD,KAAK,IAEE,EAAQ,gCADN,MAAM,KAAK,MAAM,MAAM,GAAG,KAAK,UAAU,IAAI,EAAE,QAAQ,GAAG,CAAC,CAAC,KAAK,IAC3B,EAAI;KACxD;KACA,IAAI,CAAC,GAAG,WAAW,eAAe,GAAG,OAAO;KAC5C,MAAM,OAAO,GAAG,MAAM,EAAsB;KAC5C,MAAM,WAAW,WAAW;KAC5B,IAAI,YAAY,MACd,MAAM,IAAI,MAAM,uBAAuB,MAAM;KAE/C,OAAO;IACT;GACF;EACF;EACA,OAAO;GACL,QAAQ;GACR,aAAa;GACb,WAAW;GACX,QAAQ,YAAY;GACpB,QAAQ;GACR,eAAe;IACb,OAAO;IACP,QAAQ;KACN,QAAQ;KACR,gBAAgB;KAChB,gBAAgB;KAChB,gBAAgB;IAClB;GACF;EACF;CACF,CAAC;CAED,MAAM,UAAU,MAAM,QAAQ,MAAM,IAAI,SAAS,CAAC,MAAM;CACxD,IAAI;CACJ,KAAK,MAAM,QAAQ,SAAS;EAC1B,IAAI,EAAE,YAAY,OAAO;EACzB,KAAK,MAAM,UAAU,KAAK,QACxB,IACE,OAAO,SAAS,WAChB,OAAO,WACP,OAAO,kBACP,QAAQ,OAAO,cAAc,MAAM,WACnC;GACA,SAAS,SAAS,OAAO,QAAQ;GACjC;EACF;EAEF,IAAI,QAAQ;CACd;CACA,IAAI,CAAC,QACH,MAAM,IAAI,MAAM,wCAAwC;CAG1D,MAAM,EAAE,MAAM,YAAY,MAAM,iBAAiB,KAAK;CAEtD,MAAM,UAAU,KAAK,YAAY,eAAe,GAAG,KAAK,UAAU;EAAE,IAAI;EAAQ,KAAK;CAAQ,CAAC,CAAC;CAE/F,OAAO;EAAE,IAAI;EAAQ,KAAK;CAAQ;AACpC;;;;;;;;ACtUA,SAAS,OAAO,MAAiC;CAC/C,OAAO,IAAI,SAAS,SAAS,WAAW;EACtC,SAAS,OAAO,MAAM,EAAE,WAAW,SAAiB,IAAI,KAAK,WAAW;GACtE,IAAI,KAAK,OAAO,GAAG;QACd,QAAQ,MAAM;EACrB,CAAC;CACH,CAAC;AACH;AAEA,SAAS,aAAa,UAAiC;CACrD,MAAM,YAAY,SAAS,QAAQ,OAAO,EAAE;CAC5C,IAAI,CAAC,aAAa,CAAC,wBAAwB,KAAK,SAAS,KAAK,mBAAmB,KAAK,SAAS,GAC7F,OAAO;CACT,OAAO;AACT;;AAGA,eAAsB,mBAAmB,UAA0C;CACjF,MAAM,YAAY,aAAa,QAAQ;CACvC,IAAI,CAAC,WAAW,OAAO;CACvB,IAAI;EAGF,QADa,MADM,OAAO;GAAC;GAAO;GAAM;GAAgB;GAAM;EAAS,CAAC,EAAA,CACtD,KACX,KAAQ;CACjB,QAAQ;EACN,OAAO;CACT;AACF;;;;;AAMA,eAAsB,mBAAmB,UAA0C;CACjF,IAAI;EAEF,QAAO,MADa,KAAK,QAAQ,EAAA,CACpB,MAAM,YAAY;CACjC,QAAQ;EACN,OAAO;CACT;AACF;;AAGA,eAAsB,wBAAwB,WAAmD;CAC/F,MAAM,yBAAS,IAAI,IAAoB;CACvC,IAAI,UAAU,WAAW,GAAG,OAAO;CAEnC,MAAM,YAAsB,CAAC;CAC7B,KAAK,MAAM,MAAM,WAAW;EAC1B,MAAM,YAAY,aAAa,EAAE;EACjC,IAAI,CAAC,WAAW;GACd,QAAQ,KAAK,yDAAyD,GAAG,EAAE;GAC3E;EACF;EACA,UAAU,KAAK,SAAS;CAC1B;CAEA,IAAI,UAAU,WAAW,GAAG,OAAO;CAEnC,IAAI;EACF,MAAM,OAAO,MAAM,OAAO;GACxB;GACA;GACA;GACA;GACA,GAAG;EACL,CAAC;EACD,IAAI,cAAc;EAElB,KAAK,MAAM,QAAQ,KAAK,MAAM,IAAI,GAAG;GACnC,MAAM,UAAU,KAAK,KAAK;GAC1B,IAAI,CAAC,SAAS;GACd,IAAI,sBAAsB,KAAK,OAAO,GACpC,cAAc;QACT,IAAI,eAAe,CAAC,OAAO,IAAI,OAAO,GAC3C,OAAO,IAAI,SAAS,WAAW;EAEnC;CACF,SAAS,KAAK;EACZ,QAAQ,MAAM,6CAA6C,WAAW,GAAG;CAC3E;CAEA,OAAO;AACT;;;;;;;;;;ACvEA,SAAS,WAAW,OAA+B;CACjD,IAAI,OAAO,UAAU,UAAU,OAAO;CACtC,IAAI,eAAe,KAAK,KAAK,GAAG,OAAO;CACvC,IAAI,CAAC,MAAM,WAAW,QAAQ,GAAG,OAAO;CACxC,IAAI,MAAM,SAAS,GAAG,GAAG,OAAO;CAChC,IAAI,MAAM,SAAS,OAAO,GAAG,OAAO;CACpC,OAAO,GAAG,MAAM;AAClB;;;;;;;;;;AAyBA,SAAS,sBAAsB;CAC7B,QAAQ,SAAmB;EACzB,SAAS,KAAK,MAAsB;GAClC,IAAI,KAAK,SAAS,aAAa,KAAK,YAAY,KAAK;IACnD,MAAM,QAAQ,WAAW,KAAK,YAAY,IAAI;IAC9C,IAAI,OAAO,KAAK,WAAY,OAAO;GACrC;GACA,IAAI,KAAK,UACP,KAAK,MAAM,SAAS,KAAK,UAAU,KAAK,KAAK;EAEjD;EACA,KAAK,IAAI;EACT,OAAO;CACT;AACF;;;;;;;;;;;;;AAcA,SAAS,4BAA4B;CACnC,QAAQ,SAAoB;EAC1B,SAAS,KAAK,MAAuB;GACnC,KACG,KAAK,SAAS,uBAAuB,KAAK,SAAS,wBACpD,KAAK,YAEA;SAAA,MAAM,QAAQ,KAAK,YACtB,IAAI,KAAK,SAAS,qBAAqB,KAAK,SAAS,QAAQ;KAC3D,MAAM,QAAQ,WAAW,KAAK,KAAK;KACnC,IAAI,OAAO,KAAK,QAAQ;IAC1B;;GAGJ,IAAI,KAAK,UACP,KAAK,MAAM,SAAS,KAAK,UAAU,KAAK,KAAK;EAEjD;EACA,KAAK,IAAI;EACT,OAAO;CACT;AACF;AAoBiC,EAC9B,OAAO;CACN,OAAO,EAAE,OAAO,OAAO,CAAC,CAAC,SAAS;CAClC,aAAa,EAAE,OAAO,OAAO,CAAC,CAAC,SAAS;CACxC,OAAO,EAAE,OAAO,OAAO,CAAC,CAAC,SAAS;CAClC,MAAM,EAAE,OAAO,OAAO,CAAC,CAAC,SAAS;AACnC,CAAC,CAAC,CACD,YAAY;;;;;;AASf,SAAgB,iBAAiB,aAAsC,KAAqB;CAC1F,OAAO,OAAO,YAAY,SAAS,WAAY,YAAY,OAAkB;AAC/E;;;;;;;;;;;;;;;;AAuBA,eAAe,wBACb,QACA,OAKI,CAAC,GACL,KACA;CAGA,MAAM,EAAE,iBAAiB,gBACvB,OAAO,8BAA2C,QAAQ,KAAK,iBAAiB;CAElF,MAAM,gBAAgB,2BAA2B;CACjD,MAAM,gBAAgB,2BAA2B;CAKjD,MAAM,cAAc;EAAC,GAAG;EAAe;EAA2B,GAAI,KAAK,iBAAiB,CAAC;CAAE;CAC/F,MAAM,cAAc;EAAC,GAAG;EAAe;EAAqB,GAAI,KAAK,iBAAiB,CAAC;CAAE;CAKzF,OAAO,UAAU,iBAAiB;EAChC,cAAc,KAAK;EACnB,QAAQ;EACR,YAAY;GACV,eAAe;GACf,eAAe;EACjB;CACF,CAAC,CAAC,CAAC,MAAM,gBAAgB;EAAE,GAAG;EAAY;EAAa;CAAgB,EAAE;AAC3E;;;;;;;;;;;AAYA,eAAsB,WACpB,QACA,UACA,UACA,eACA,eACA,mBAEA,KACoB;CACpB,MAAM,OAAO,sBAAsB,MAAM;CACzC,MAAM,cACJ,KAAK,eACL,8BAA2C,QAAQ,iBAAiB,CAAC,CAAC;CACxE,MAAM,aAAa,MAAM,wBACvB,QACA;EAAE;EAAe;EAAe;CAAkB,GAClD,GACF;CAEA,MAAM,aAAa,oBAAoB;CACvC,MAAM,UAAU,MAAM,cAAc,WAAW;EAC7C,gBAAgB,WAAW;EAC3B,OAAO,CAAC;EACR,aAAa,CAAC;EACd;CACF,CAAC;CAED,MAAM,OACJ,YAAY,QACZ,UAAU,IAAI,QAAQ,KACrB,MAAM,mBAAmB,QAAQ,KACjC,MAAM,mBAAmB,QAAQ,KAClC,KAAA;CAEF,OAAO;EACL;EACA,gBAAgB,WAAW;EAC3B,aAAa;GAAE,GAAG;GAAa;EAAK;EACpC;CACF;AACF;;;;;;;;;;;;;AAcA,IAAM,kCAAkB,IAAI,IAAyB;;AAGrD,SAAgB,wBAAwB,MAAc,aAAgC;CACpF,gBAAgB,IAAI,MAAM,WAAW;AACvC;;AAGA,SAAgB,mBAAmB,MAAuC;CACxE,OAAO,gBAAgB,IAAI,IAAI;AACjC;;;;;;AAOA,IAAM,+BAAe,IAAI,IAAoB;AAE7C,SAAgB,qBAAqB,MAAc,UAAwB;CACzE,aAAa,IAAI,MAAM,QAAQ;AACjC;AAEA,SAAgB,gBAAgB,MAAkC;CAChE,OAAO,aAAa,IAAI,IAAI;AAC9B;;;;;AAMA,IAAM,8BAAc,IAAI,IAAoB;AAE5C,SAAgB,oBAAoB,MAAc,KAAmB;CACnE,YAAY,IAAI,MAAM,GAAG;AAC3B;AAEA,SAAgB,eAAe,MAAkC;CAC/D,OAAO,YAAY,IAAI,IAAI;AAC7B;AAEA,eAAsB,iBACpB,QACA,eACA,eAGA,MACiB;CACjB,MAAM,aAAa,MAAM,wBAAwB,QAAQ;EACvD,cAAc;EACd;EACA;CACF,CAAC;CACD,IAAI,MAAM;EACR,wBAAwB,MAAM,WAAW,WAA0B;EACnE,qBAAqB,MAAM,WAAW,eAAe;CACvD;CACA,OAAO,WAAW;AACpB;;;;;;;;;;;;;;;AC/SA,IAAM,eAAa,eAAe;AAsBlC,SAAS,gBAAgB,UAA0B;CACjD,MAAM,QAAQ,SAAS,MAAM,GAAG;CAChC,IAAI,MAAM,SAAS,GAAG;EACpB,MAAM,UAAU,aAAW,QAAQ,MAChC,MAAM,EAAE,SAAS,IAAI,MAAM,QAAQ,EAAE,SAAS,MAAM,EACvD;EACA,IAAI,SAAS,OAAO,QAAQ;CAC9B;CACA,OAAO,aAAW,MAAM,SAAS;AACnC;AAEA,SAAS,QAAQ,MAAsB;CACrC,OAAO,KACJ,YAAY,CAAC,CACb,QAAQ,eAAe,GAAG,CAAC,CAC3B,QAAQ,YAAY,EAAE;AAC3B;AAEA,SAAgB,SAAS,SAAyB;CAChD,IAAI,SAAS;CACb,IAAI,OAAO;CACX,OAAO,WAAW,MAAM;EACtB,OAAO;EACP,SAAS,OACN,QAAQ,4BAA4B,EAAE,CAAC,CACvC,QAAQ,mDAAmD,IAAI;CACpE;CACA,OAAO;AACT;AAEA,SAAgB,eAAe,UAAkB,KAA6B;CAC5E,MAAM,EAAE,aAAa,iBAAiB,YAAY,8BAA2C,GAAG;CAChG,MAAM,UAA0B,CAAC;CACjC,MAAM,MAAM,aAAa,SAAS,UAAU;CAC5C,MAAM,OAAO,gBAAgB,QAAQ;CACrC,MAAM,OAAO,iBAAiB,aAAa,OAAO,KAAK;CAEvD,MAAM,YAAY;EAChB;EACA;EACA,MAAM;EACN,MAAM;EACN,MAAM;EACN,MAAM;EACN,MAAM;CACR;CAEA,IAAI,MACF,QAAQ,KAAK;EACX;EACA,WAAW,EAAE,GAAG,UAAU;EAC1B,SAAS,iBAAiB,aAAa,aAAa,KAAK;EACzD,MAAM;CACR,CAAC;CAIH,MAAM,QADe,SAAS,OAChB,CAAA,CAAa,MAAM,IAAI;CACrC,IAAI,mBAA6B,CAAC;CAClC,IAAI,cAAc;CAElB,MAAM,uBAAuB;EAC3B,IAAI,iBAAiB,SAAS,GAAG;GAC/B,MAAM,OAAO,iBAAiB,KAAK,GAAG,CAAC,CAAC,KAAK;GAC7C,IAAI,MACF,QAAQ,KAAK;IACX,KAAK,eAAe;IACpB,WAAW,EAAE,GAAG,UAAU;IAC1B,SAAS;IACT,MAAM;GACR,CAAC;GAEH,mBAAmB,CAAC;EACtB;CACF;CAEA,MAAM,uBAAuB;EAC3B,KAAK,IAAI,IAAI,GAAG,KAAK,GAAG,KAAK;GAC3B,MAAM,MAAM,MAAM;GAClB,IAAI,UAAU,MAAM,OAAO,GAAG,IAAI,GAAG,QAAQ,UAAU,IAAK;EAC9D;EACA,OAAO;CACT;CAEA,KAAK,MAAM,QAAQ,OAAO;EACxB,MAAM,UAAU,KAAK,KAAK;EAE1B,IAAI,QAAQ,WAAW,KAAK,GAAG;GAC7B,cAAc,CAAC;GACf;EACF;EACA,IAAI,aAAa;EAEjB,IAAI,mBAAmB,KAAK,OAAO,KAAK,mBAAmB,KAAK,OAAO,GAAG;EAE1E,MAAM,eAAe,QAAQ,MAAM,mBAAmB;EACtD,IAAI,cAAc;GAChB,eAAe;GACf,MAAM,QAAQ,aAAa,EAAE,CAAC;GAC9B,MAAM,QAAQ,aAAa,EAAE,CAAC,QAAQ,YAAY,EAAE,CAAC,CAAC,KAAK;GAE3D,KAAK,IAAI,IAAI,OAAO,KAAK,GAAG,KAC1B,UAA6C,MAAM,OAAO;GAE5D,UAAU,MAAM,WAAqC;GAErD,IAAI,UAAU,KAAK,CAAC,UAAU,MAC5B,UAAU,OAAO;GAGnB,IAAI,SAAS,GACX,QAAQ,KAAK;IACX,KAAK,GAAG,IAAI,GAAG,QAAQ,KAAK;IAC5B,WAAW,EAAE,GAAG,UAAU;IAC1B,SAAS;IACT,MAAM,MAAM;GACd,CAAC;GAEH;EACF;EAEA,IAAI,YAAY,MAAM,YAAY,OAAO;GACvC,eAAe;GACf;EACF;EAEA,IAAI,UAAU,KAAK,OAAO,GAAG;EAE7B,MAAM,UAAU,QACb,QAAQ,aAAa,EAAE,CAAC,CACxB,QAAQ,aAAa,EAAE,CAAC,CACxB,QAAQ,SAAS,EAAE,CAAC,CACpB,QAAQ,oBAAoB,IAAI,CAAC,CACjC,QAAQ,gBAAgB,IAAI,CAAC,CAC7B,QAAQ,cAAc,IAAI,CAAC,CAC3B,QAAQ,0BAA0B,IAAI,CAAC,CACvC,KAAK;EAER,IAAI,SAAS,iBAAiB,KAAK,OAAO;CAC5C;CAEA,eAAe;CACf,OAAO;AACT;AAEA,eAAsB,oBAAoB,SAAkB,WAAqC;CAC/F,MAAM,OAAO,QAAQ,WAAW,QAAQ;CACxC,MAAM,OAAO,QAAQ,aAAa,UAAU;CAC5C,MAAM,MAAM,MAAM,EAAE,WAAW,KAAK,CAAC;CAErC,MAAM,WAAW,MAAM,aAAa,IAAI;CASxC,MAAM,cAAa,MARG,QAAQ,IAC5B,SAAS,IAAI,OAAO,SAAS;EAG3B,MAAM,MAAM,eAAe,IAAI,KAAK,MAAM,KAAM,MAAM,SAAS,KAAK,SAAS,OAAO;EACpF,OAAO,eAAe,KAAK,MAAM,GAAG;CACtC,CAAC,CACH,EAAA,CAC2B,KAAK;CAEhC,MAAM,UAAU,KAAK,MAAM,mBAAmB,GAAG,KAAK,UAAU,UAAU,CAAC;CAC3E,OAAO,WAAW;AACpB;;;;;;;;ACxMA,IAAI,SAA8C;AAClD,IAAI,cAAc;AAElB,eAAsB,aAA4B;CAChD,MAAM,MAAM,QAAQ,IAAI;CACxB,IAAI,CAAC,KAAK;CAEV,IAAI;EACF,SAAS,MAAM,OAAO;EACtB,OAAO,KAAK;GACV;GACA,aAAA,QAAA,IAAA,YAAqC;GACrC,SAAS,QAAQ,IAAI,kBAAkB,KAAA;EACzC,CAAC;EACD,cAAc;CAChB,QAAQ;EAEN,SAAS;EACT,cAAc;CAChB;AACF;AAEA,SAAgB,iBAAiB,KAAc,SAAyC;CACtF,IAAI,CAAC,eAAe,CAAC,QAAQ;CAC7B,OAAO,iBAAiB,KAAK,UAAU,EAAE,OAAO,QAAQ,IAAI,KAAA,CAAS;AACvE;;;ACpBA,SAAS,YAAY,OAAuB;CAC1C,OAAO,MACJ,MAAM,GAAG,CAAC,CACV,KAAK,SAAS,KAAK,OAAO,CAAC,CAAC,CAAC,YAAY,IAAI,KAAK,MAAM,CAAC,CAAC,CAAC,CAC3D,KAAK,GAAG;AACb;AAEA,SAAwB,eAAe,EAAE,SAA8B;CACrE,OACE,oBAAC,YAAD;EAAY,WAAU;EACpB,UAAA,qBAAC,gBAAD,EAAA,UAAA,CACE,oBAAC,gBAAD,EAAA,UACE,oBAAC,QAAD;GAAM,WAAU;GAAwB,UAAA;EAAU,CAAA,EACpC,CAAA,GACf,MAAM,KAAK,MAAM,UAChB,oBAAC,gBAAD,EAAA,UACG,QAAQ,MAAM,SAAS,IACtB,oBAAC,QAAD;GAAM,WAAU;GAAyB,UAAA,YAAY,IAAI;EAAQ,CAAA,IAEjE,oBAAC,gBAAD;GAAgB,WAAU;GAAqB,UAAA,YAAY,IAAI;EAAkB,CAAA,EAErE,GANK,GAAG,KAAK,GAAG,OAMhB,CACjB,CACa,EAAA,CAAA;CACN,CAAA;AAEhB;AC1BA,IAAa,WAAsB,cADhB,eAC8B,CAAA,CAAW,MAAM;AAElE,SAAgB,gBAA0B;CACxC,MAAM,QAAkB,CAAC;CAEzB,SAAS,SAAS,OAAkB,UAAU,IAAI;EAChD,MAAM,WAAW,MAAM,KAAK,WAAW,OAAO,IAC1C,MAAM,OACN,GAAG,UAAU,MAAM,OAAO,QAAQ,QAAQ,GAAG;EACjD,IAAI,MAAM,QAAQ,CAAC,MAAM,QACvB,MAAM,KAAK,QAAQ;EAErB,IAAI,MAAM,OACR,MAAM,MAAM,SAAS,SAAS,SAAS,MAAM,QAAQ,CAAC;CAE1D;CAEA,SAAO,SAAS,UAAU,SAAS,KAAK,CAAC;CACzC,OAAO;AACT;AAEA,SAAgB,cAAmC;CACjD,MAAM,sBAAM,IAAI,IAAoB;CAEpC,SAAS,SAAS,OAAkB,UAAU,IAAI;EAChD,MAAM,WAAW,MAAM,KAAK,WAAW,OAAO,IAC1C,MAAM,OACN,GAAG,UAAU,MAAM,OAAO,QAAQ,QAAQ,GAAG;EACjD,IAAI,IAAI,UAAU,MAAM,KAAK;EAC7B,IAAI,MAAM,OACR,MAAM,MAAM,SAAS,SAAS,SAAS,MAAM,QAAQ,CAAC;CAE1D;CAEA,SAAO,SAAS,UAAU,SAAS,KAAK,CAAC;CACzC,OAAO;AACT;;;;;;;AAQA,SAAS,oBAAoB,MAA2B;CACtD,MAAM,aAAa,mBAAmB,IAAI;CAC1C,IAAI,YAAY,OAAO;CAEvB,IAAI,KAAkB,CAAC;CACvB,MAAM,MAAM,KAAK,QAAQ,UAAU,EAAE;CACrC,KAAK,MAAM,OAAO,CAAC,QAAQ,KAAK,GAAG;EACjC,KAAK,MAAM,QAAQ,CAAC,KAAK,UAAU,GAAG,MAAM,KAAK,GAAG,KAAK,UAAU,GAAG,IAAI,QAAQ,KAAK,CAAC,GACtF,IAAI;GACF,KAAK,mBAAgC,aAAa,MAAM,OAAO,CAAC;GAChE;EACF,QAAQ,CAER;EAEF,IAAI,OAAO,KAAK,EAAE,CAAC,CAAC,QAAQ;CAC9B;CACA,wBAAwB,MAAM,EAAE;CAChC,OAAO;AACT;AAEA,SAAgB,gBAAgB,UAAkB;CAChD,MAAM,iBAAiB,SAAS,QAAQ,UAAU,EAAE;CAMpD,IAAI,mBAAmB,UAAU,mBAAmB,IAAI;EACtD,MAAM,QAAQ,cAAc;EAC5B,MAAM,WAAW,YAAY;EAC7B,MAAM,QAAQ,MAAM;EACpB,IAAI,CAAC,OAAO,OAAO;GAAE,MAAM;GAAM,MAAM;EAAK;EAC5C,MAAM,KAAK,oBAAoB,KAAK;EACpC,OAAO;GACL,MAAM;GACN,MAAM;IACJ,MAAM;IACN,OAAO,GAAG,SAAS,SAAS,IAAI,KAAK,KAAK;IAC1C,aAAa,GAAG,eAAe;GACjC;EACF;CACF;CAEA,MAAM,QAAQ,cAAc;CAE5B,MAAM,QAAQ,MAAM,WAAW,SAAS,SAAS,IAAI,oBAAoB,SAAS,cAAc;CAEhG,IAAI,UAAU,IACZ,OAAO;EAAE,MAAM;EAAM,MAAM;CAAK;CAGlC,MAAM,WAAW,YAAY;CAC7B,MAAM,WAAW,QAAQ,IAAI,MAAM,QAAQ,KAAK;CAChD,MAAM,WAAW,QAAQ,MAAM,SAAS,IAAI,MAAM,QAAQ,KAAK;CAE/D,MAAM,SAAS,WAAW,oBAAoB,QAAQ,IAAI;CAC1D,MAAM,SAAS,WAAW,oBAAoB,QAAQ,IAAI;CAC1D,OAAO;EACL,MAAM,WACF;GAAE,MAAM;GAAU,OAAO,QAAQ,SAAS,SAAS,IAAI,QAAQ,KAAK;EAAG,IACvE;EACJ,MAAM,WACF;GACE,MAAM;GACN,OAAO,QAAQ,SAAS,SAAS,IAAI,QAAQ,KAAK;GAClD,aAAa,QAAQ,eAAe;EACtC,IACA;CACN;AACF;;;AC9GA,SAAwB,WAAW,EACjC,UACA,WACA,UACA,UACA,iBACkB;CAClB,MAAM,EAAE,MAAM,SAAS,gBAAgB,QAAQ;CAE/C,IAAI,CAAC,QAAQ,CAAC,MACZ,OAAO;CAGT,OACE,oBAAC,gBAAD;EACE,MAAM,OAAO;GAAE,MAAM,aAAa,QAAQ,KAAK,MAAM;GAAG,OAAO,KAAK;EAAM,IAAI,KAAA;EAC9E,MACE,OACI;GACE,MAAM,aAAa,QAAQ,KAAK,MAAM;GACtC,OAAO,KAAK;GACZ,aAAa,KAAK;EACpB,IACA,KAAA;EAEK;EACD;EACA;EACK;CAChB,CAAA;AAEL;;;AC5CA,SAAgB,WAAW,EAAE,YAA+B;CAC1D,OACE,oBAAC,OAAD;EAAK,WAAU;EACZ;CACE,CAAA;AAET;;;ACLA,IAAM,eAAa,eAAe;AAElC,SAAgB,YAAY,KAAa,UAA0B;CACjE,MAAM,aAAa,cAAY,MAAM,QAAQ,mBAAmB,GAAG;CACnE,MAAM,cAAc,SAAS,QAAQ,OAAO,EAAE,CAAC,CAAC,MAAM,GAAG,CAAC,CAAC,IAAI,kBAAkB,CAAC,CAAC,KAAK,GAAG;CAC3F,OAAO,GAAG,IAAI,GAAG,aAAa,QAAQ,cAAc,WAAW;AACjE;;;;;;;AAQA,SAAgB,mBAAmB,KAAqB;CACtD,IAAI;EACF,MAAM,OAAO,IAAI,IAAI,GAAG,CAAC,CAAC;EAC1B,IAAI,SAAS,cAAc,OAAO;EAClC,IAAI,SAAS,cAAc,OAAO;EAClC,IAAI,SAAS,iBAAiB,OAAO;EACrC,IAAI,SAAS,aAAa,OAAO;EACjC,IAAI,SAAS,gBAAgB,OAAO;EAEpC,OAAO;CACT,QAAQ;EACN,OAAO;CACT;AACF;AAEA,SAAgB,gBAAyB;CACvC,OAAO,cAAY,MAAM,QAAQ;AACnC;AAEA,SAAgB,aAAqB;CACnC,OAAO,cAAY,MAAM,OAAO;AAClC;AAEA,SAAgB,iBAA+B;CAC7C,OAAO,cAAY,QAAQ,UAAU,CAAC;AACxC;;;ACjCA,SAAwB,SAAS,EAC/B,UACA,OAAO,kBACP,YAAY,MACI;CAChB,IAAI,CAAC,cAAc,GAAG,OAAO;CAE7B,MAAM,UAAU,WAAW;CAC3B,IAAI,CAAC,SAAS,OAAO;CAErB,MAAM,UAAU,YAAY,SAAS,QAAQ;CAE7C,OACE,oBAAC,OAAD;EAAK,WAAW,sBAAsB;EACpC,UAAA,qBAAC,KAAD;GACE,MAAM;GACN,QAAO;GACP,KAAI;GACJ,cAAW;GACX,WAAU;GALZ,UAAA,CAOE,oBAAC,WAAD,EAAW,WAAU,UAAW,CAAA,GAC/B,IACA;;CACA,CAAA;AAET;;;AC5BA,SAAS,WAAW,UAAkB;CACpC,OAAO,SAAS,KAAK,EAAE,YAAY,IAAI,OAAO,MAA6C;EACzF,OACE,oBAAC,OAAD;GACa;GACX,OAAO;GACP,QAAQ;GACR,SAAQ;GACR,OAAM;GACN,MAAK;GAEL,UAAA,oBAAC,QAAD,EAAM,GAAG,SAAW,CAAA;EACjB,CAAA;CAET;AACF;AAEA,IAAM,aAAa,WACjB,0sBACF;AACA,IAAM,gBAAgB,WACpB,6KACF;AACA,IAAM,aAAa,WACjB,idACF;AACA,IAAM,UAAU,WACd,oNACF;AACA,IAAM,cAAc,WAClB,8VACF;AACA,IAAM,cAAc,WAClB,oMACF;AAuBA,IAAM,UAAyD;CAC7D,QAAQ;CACR,QAAQ;CACR,WAAW;CACX,KAAK;CACL,SAAS;CACT,SAAS;CACT,GAAG;CACH,WA9BoB,WACpB,s8DA6BW;CACX,UA5BmB,WACnB,ofA2BU;CACV,UA1BmB,WACnB,gbAyBU;CACV,UAxBmB,WACnB,wnBAuBU;CACV,SAtBkB,WAClB,yuCAqBS;CACT,SApBkB,WAClB,0pCAmBS;CACT,UAlBmB,WACnB,ilCAiBU;AACZ;AAEA,SAAgB,cAAc,MAAc;CAE1C,OAAO,QADK,KAAK,YAAY,CAAC,CAAC,QAAQ,QAAQ,EAChC,MAAQ;AACzB;AAEA,SAAwB,OAAO,EAAE,YAAY,IAAI,OAAO,MAAmB;CACzE,MAAM,cAAc,eAAe;CAEnC,IAAI,CAAC,aAAa,QAAQ,OAAO;CAEjC,OACE,oBAAC,OAAD;EAAK,WAAW,cAAc;EAC3B,UAAA,YAAY,KAAK,SAAS;GACzB,MAAM,OAAO,cAAc,KAAK,IAAI;GACpC,OACE,oBAAC,KAAD;IAEE,MAAM,KAAK;IACX,QAAO;IACP,KAAI;IACJ,cAAY,KAAK;IACjB,WAAU;IAET,UAAA,QAAQ,oBAAC,MAAD,EAAY,KAAO,CAAA;GAC3B,GARI,KAAK,IAQT;EAEP,CAAC;CACE,CAAA;AAET;;;AC5GA,SAAgB,SAAS;CACvB,OACE,qBAAC,UAAD;EAAQ,WAAU;EAAlB,UAAA,CACE,oBAAC,QAAD,CAAS,CAAA,GACT,oBAAC,SAAD;GAAO,WAAU;GACf,UAAA,qBAAC,KAAD;IAAG,WAAU;IAAb,UAAA;KAAuB;KACX;KACV,oBAAC,KAAD;MACE,MAAK;MACL,QAAO;MACP,KAAI;MACJ,WAAU;MACX,UAAA;KAEE,CAAA;IACF;;EACE,CAAA,CACD;;AAEZ;;;ACRA,SAAgB,SAAS,EAAE,WAAW,WAAW,MAAM,iBAAgC;CACrF,MAAM,CAAC,WAAW,gBAAgB,SAAS,KAAK;CAEhD,MAAM,cAAc,kBAAkB;EACpC,MAAM,YAAY,SAAS,eAAe,kBAAkB;EAK5D,MAAM,cAJU,YAAY,UAAU,YAAY,OAAO,YACpC,YAAY,UAAU,eAAe,SAAS,gBAAgB,gBAClD;EAGjC,IAAI,eAAe,WACjB,aAAa,UAAU;CAE3B,GAAG,CAAC,SAAS,CAAC;CAEd,gBAAgB;EACd,IAAI;EACJ,MAAM,qBAAqB;GACzB,IAAI,WAAW,aAAa,SAAS;GACrC,YAAY,WAAW,aAAa,GAAG;EACzC;EAEA,MAAM,YAAY,SAAS,eAAe,kBAAkB,KAAK;EACjE,UAAU,iBAAiB,UAAU,cAAc,EAAE,SAAS,KAAK,CAAC;EAEpE,aAAa;GACX,UAAU,oBAAoB,UAAU,YAAY;GACpD,IAAI,WAAW,aAAa,SAAS;EACvC;CACF,GAAG,CAAC,WAAW,CAAC;CAEhB,MAAM,cAAc,aACjB,MAAwB;EACvB,EAAE,eAAe;EACjB,gBAAgB;EAChB,QAAQ,aAAa,MAAM,IAAI,MAAM;EACrC,MAAM,YAAY,SAAS,eAAe,kBAAkB;EAC5D,IAAI,WACF,UAAU,SAAS;GAAE,KAAK;GAAG,UAAU;EAAS,CAAC;OAEjD,OAAO,SAAS;GAAE,KAAK;GAAG,UAAU;EAAS,CAAC;CAElD,GACA,CAAC,aAAa,CAChB;CAEA,OACE,oBAAC,OAAD;EACE,WAAW,GACT,sCACA,mCACA,YAAY,gBAAgB,iCAC5B,SACF;EAEA,UAAA,qBAAC,KAAD;GACE,MAAK;GACL,SAAS;GACT,WAAW,GACT,oCACA,gEACA,kDACF;GACA,cAAW;GARb,UAAA,CAUG,YAAY,oBAAC,aAAD,EAAa,WAAU,4BAA6B,CAAA,GACjE,oBAAC,QAAD,EAAA,UAAM,gBAAmB,CAAA,CACxB;;CACA,CAAA;AAET;;;ACvEA,SAAwB,IAAI,EAAE,QAAkB;CAC9C,MAAM,CAAC,UAAU,eAAe,SAAwB,IAAI;CAC5D,MAAM,eAAe,OAAsB,IAAI;CAC/C,MAAM,gBAAgB,OAAsC,IAAI;CAChE,MAAM,cAAc,OAAsB,IAAI;CAE9C,gBAAgB;EACd,YAAY,UAAU;CACxB,GAAG,CAAC,QAAQ,CAAC;CAOb,MAAM,kBAAkB,kBAA0B;EAChD,IAAI,OAAO,WAAW,aAAa,OAAO;EAC1C,MAAM,QAAQ,KAAK,KAAK,SAAS,eAAe,KAAK,EAAE,CAAC,KAAK,MAAM,CAAC,CAAC,IAAI;EAEzE,QADe,QAAQ,WAAW,iBAAiB,KAAK,CAAC,CAAC,eAAe,IAAI,MAC5D;CACnB,GAAG,CAAC,IAAI,CAAC;CAET,gBAAgB;EAId,IAAI,OAAO,WAAW,eAAe,OAAO,aAAa,MAAM;EAC/D,IAAI,CAAC,KAAK,QAAQ;EAGlB,MAAM,YADY,OAAO,cAAc,OACT,SAAS,eAAe,kBAAkB,IAAI;EAC5E,MAAM,eAAe,aAAa;EAClC,MAAM,SAAS,gBAAgB;EAE/B,MAAM,qBAAqB;GACzB,IAAI,aAAa,SAAS;GAE1B,IAAI,YAA2B;GAC/B,KAAK,MAAM,OAAO,MAAM;IACtB,MAAM,KAAK,IAAI,KAAK,MAAM,CAAC;IAC3B,MAAM,KAAK,SAAS,eAAe,EAAE;IACrC,IAAI,CAAC,IAAI;IAIT,KAFY,YAAY,GAAG,YAAY,UAAU,YAAY,GAAG,sBAAsB,CAAC,CAAC,QAE7E,QACT,YAAY;SAEZ;GAEJ;GAEA,IAAI,cAAc,YAAY,SAAS;IACrC,YAAY,SAAS;IACrB,QAAQ,aAAa,MAAM,IAAI,YAAY,IAAI,cAAc,MAAM;GACrE;EACF;EAEA,aAAa;EAEb,IAAI,gBAAsD;EAC1D,MAAM,WACJ,KAAK,SAAS,WACJ;GACJ,IAAI,eAAe;GACnB,gBAAgB,iBAAiB;IAC/B,gBAAgB;IAChB,aAAa;GACf,GAAG,EAAE;EACP,IACA;EAEN,aAAa,iBAAiB,UAAU,UAAU,EAAE,SAAS,KAAK,CAAC;EAEnE,aAAa;GACX,aAAa,oBAAoB,UAAU,QAAQ;GACnD,IAAI,eAAe,aAAa,aAAa;EAC/C;CACF,GAAG,CAAC,MAAM,eAAe,CAAC;CAE1B,MAAM,kBAAkB,aAAa,OAAe;EAClD,aAAa,UAAU;EACvB,YAAY,EAAE;EACd,QAAQ,aAAa,MAAM,IAAI,IAAI,IAAI;EACvC,IAAI,cAAc,SAAS,aAAa,cAAc,OAAO;EAC7D,cAAc,UAAU,iBAAiB;GACvC,aAAa,UAAU;EACzB,GAAG,GAAI;CACT,GAAG,CAAC,CAAC;CAEL,MAAM,oBAAoB,kBAAkB;EAC1C,aAAa,UAAU;EACvB,YAAY,IAAI;EAChB,QAAQ,aAAa,MAAM,IAAI,MAAM;EACrC,IAAI,cAAc,SAAS,aAAa,cAAc,OAAO;EAC7D,cAAc,UAAU,iBAAiB;GACvC,aAAa,UAAU;EACzB,GAAG,GAAI;CACT,GAAG,CAAC,CAAC;CAEL,gBAAgB;EACd,aAAa;GACX,IAAI,cAAc,SAAS,aAAa,cAAc,OAAO;EAC/D;CACF,GAAG,CAAC,CAAC;CAEL,MAAM,gBAAgB,OAA8B,IAAI;CAExD,gBAAgB;EACd,IAAI,YAAY,cAAc,WAAW,CAAC,aAAa,SACrD,cAAc,QAAQ,eAAe;GACnC,OAAO;GACP,UAAU;EACZ,CAAC;CAEL,GAAG,CAAC,QAAQ,CAAC;CAEb,IAAI,CAAC,KAAK,QAAQ,OAAO;CAEzB,OACE,qBAAC,OAAD;EAAK,WAAU;EAAf,UAAA,CACE,qBAAC,OAAD;GAAK,WAAU;GAAf,UAAA,CACE,oBAAC,UAAD,EAAU,WAAU,UAAW,CAAA,GAC/B,oBAAC,MAAD;IAAI,WAAU;IAAsB,UAAA;GAAgB,CAAA,CACjD;EAEL,CAAA,GAAA,qBAAC,OAAD;GAAK,WAAU;GAAf,UAAA,CACE,qBAAC,OAAD;IAAK,WAAU;IAAf,UAAA,CACE,oBAAC,OAAD,EAAK,WAAU,gDAAiD,CAAA,GAEhE,oBAAC,OAAD;KAAK,WAAU;KACZ,UAAA,KAAK,KAAK,EAAE,MAAM,OAAO,WAAW;MACnC,MAAM,KAAK,KAAK,MAAM,CAAC;MACvB,MAAM,WAAW,aAAa;MAC9B,MAAM,gBAAgB,QAAQ,KAAK;MAEnC,OACE,qBAAC,OAAD;OAEE,KAAK,WAAW,gBAAgB,KAAA;OAChC,WAAW,GACT,0DACA,YAAY,cACd;OANF,UAAA,CAQE,qBAAC,OAAD;QACE,WAAW,GACT,oEACA,YAAY,sCACd;QAJF,UAAA,CAME,oBAAC,OAAD,EACE,WAAW,GACT,uCACA,WAAW,mBAAmB,iBAChC,EACD,CAAA,GACD,oBAAC,OAAD,EACE,WAAW,GACT,oEACA,WAAW,eAAe,aAC5B,EACD,CAAA,CACE;OAEL,CAAA,GAAA,oBAAC,KAAD;QACQ;QACN,UAAU,MAAM;SACd,EAAE,eAAe;SACjB,gBAAgB,EAAE;SAClB,MAAM,KAAK,SAAS,eAAe,EAAE;SACrC,IAAI,IAAI;UAKN,MAAM,SAAS,gBAAgB;UAC/B,MAAM,WACJ,OAAO,cAAc,OACjB,SAAS,eAAe,kBAAkB,IAC1C;UACN,MAAM,QAAQ,GAAG,sBAAsB,CAAC,CAAC;UACzC,IAAI,UAKF,SAAS,SAAS;WAChB,KACE,QACA,SAAS,sBAAsB,CAAC,CAAC,MACjC,SAAS,YACT;WACF,UAAU;UACZ,CAAC;eAED,OAAO,SAAS;WACd,KAAK,QAAQ,OAAO,UAAU;WAC9B,UAAU;UACZ,CAAC;SAEL;QACF;QACA,WAAW,GACT,6DACA,WACI,6BACA,8CACN;QACA,OAAO,EAAE,aAAa,GAAG,eAAe,EAAE,IAAI;QAE9C,UAAA,oBAAC,QAAD;SAAM,WAAU;SAAoC,UAAA;QAAW,CAAA;OAC9D,CAAA,CACA;MA3EE,GAAA,IA2EF;KAET,CAAC;IACE,CAAA,CACF;GAEL,CAAA,GAAA,qBAAC,OAAD;IAAK,WAAU;IAAf,UAAA,CACE,oBAAC,OAAD,EAAK,eAAY,OAAQ,CAAA,GACzB,oBAAC,UAAD;KAAU,WAAU;KAAO,eAAe;IAAoB,CAAA,CAC3D;GACF,CAAA,CAAA;EACF,CAAA,CAAA;;AAET;;;ACnNA,SAAwB,SAAS,EAC/B,MACA,OACA,aACA,MACA,SACA,MACA,UACA,SACA,SACA,kBACgB;CAChB,MAAM,WAAW,KAAK,KAAK,GAAG;CAC9B,MAAM,WAAW,KAAK,UAAU,IAAI;CAEpC,OACE,oBAAC,OAAD;EAAK,WAAU;EACb,UAAA,qBAAC,OAAD;GACE,IAAG;GACH,WAAU;GAFZ,UAAA,CAKE,oBAAC,OAAD;IACE,IAAG;IACH,WAAU;IACV,aAAW;IACX,cAAY;IACZ,aAAW,WAAW;GACvB,CAAA,GAED,qBAAC,OAAD;IAAK,WAAU;IAAf,UAAA,CACE,qBAAC,OAAD;KACE,WAAW,kBAAkB,KAAK,SAAS,IAAI,aAAa,wBAAwB;KADtF,UAAA,CAGE,oBAAC,gBAAD,EAAgB,OAAO,KAAO,CAAA,GAC9B,qBAAC,YAAD,EAAA,UAAA;MACE,oBAAC,MAAD;OAAI,WAAU;OAAoB,UAAA;MAAU,CAAA;MAC3C,eACC,oBAAC,KAAD;OAAG,WAAU;OAA6C,UAAA;MAAe,CAAA;MAE3E,oBAAC,OAAD;OACE,IAAG;OACH,iBAAe;OACf,yBAAyB,EAAE,QAAQ,QAAQ;MAC5C,CAAA;MACA,kBACC,oBAAC,UAAD;OACE,IAAG;OACH,MAAK;OACL,yBAAyB,EACvB,QAAQ,KAAK,UAAU,cAAc,CAAC,CAAC,QAAQ,QAAQ,UAAU,EACnE;MACD,CAAA;MAEH,qBAAC,OAAD;OAAK,WAAU;OAAf,UAAA,CACE,oBAAC,UAAD;QAAU,WAAU;QAAkC;OAAW,CAAA,GAChE,QACC,qBAAC,KAAD;QAAG,WAAU;QAAb,UAAA,CAAyD,iBACzC,YAAY,IAAI,CAC7B;OAEF,CAAA,CAAA;;MACL,oBAAC,YAAD;OACY;OACV,UAAU,oBAAC,aAAD,EAAa,WAAU,UAAW,CAAA;OAC5C,UAAU,oBAAC,cAAD,EAAc,WAAU,UAAW,CAAA;MAC9C,CAAA;MACD,oBAAC,QAAD,CAAS,CAAA;KACC,EAAA,CAAA,CACT;IAGJ,CAAA,GAAA,KAAK,SAAS,KACb,oBAAC,OAAD;KACE,IAAG;KACH,aAAW;KACX,WAAU;KAEV,UAAA,oBAAC,KAAD,EAAW,KAAO,CAAA;IACf,CAAA,CAEJ;GACF,CAAA,CAAA;;CACF,CAAA;AAET;;;AChHA,SAAwB,eAAe;CACrC,OACE,oBAAC,OAAD;EAAK,WAAU;EACb,UAAA,qBAAC,OAAD;GAAK,WAAU;GAAf,UAAA;IACE,oBAAC,MAAD;KAAI,WAAU;KAAqB,UAAA;IAAO,CAAA;IAC1C,oBAAC,KAAD;KAAG,WAAU;KAAoC,UAAA;IAAiB,CAAA;IAClE,oBAAC,KAAD;KAAG,MAAK;KAAS,WAAU;KAAuB,UAAA;IAE/C,CAAA;GACA;;CACF,CAAA;AAET;;;;;;;ACLA,SAAgB,cAAc,MAAiC;CAC7D,IAAI,CAAC,MAAM,OAAO;CAElB,OADc,YAAkE,SACjE;AACjB;;;;AAKA,SAAgB,iBAAiB,MAAc,WAAoB;CACjE,MAAM,OAAO,cAAc,IAAI;CAC/B,OAAO,OAAO,oBAAC,MAAD,EAAiB,UAAY,CAAA,IAAI;AACjD;;;ACHA,SAAS,eAAe,MAAuB;CAC7C,OAAO,eAAe,KAAK,IAAI;AACjC;AAEA,SAAS,uBAAuB,UAA8B,WAAoB;CAChF,IAAI,CAAC,UAAU,OAAO;CAGtB,MAAM,aAAa,iBAAiB,UAAU,SAAS;CACvD,IAAI,YAAY,OAAO;CAGvB,MAAM,aAAa,cAAc,QAAQ;CACzC,IAAI,YAAY,OAAO,oBAAC,YAAD,EAAuB,UAAY,CAAA;CAE1D,OAAO;AACT;AAEA,SAAS,aAAa,EAAE,UAA6B;CACnD,MAAM,eAAe;EACnB,SAAS;EACT,WAAW;EACX,OAAO;CACT;CAEA,MAAM,aAAa,eAAe,OAAO,IAAI;CAE7C,OACE,qBAAC,KAAD;EACE,MAAM,OAAO;EACb,QAAQ,aAAa,WAAW,KAAA;EAChC,KAAK,aAAa,wBAAwB,KAAA;EAC1C,WAAW,GACT,6FACA,aAAa,OAAO,SAAS,UAC/B;EAPF,UAAA,CASG,uBAAuB,OAAO,MAAM,SAAS,GAC7C,OAAO,IACP;;AAEP;AAEA,SAAgB,KAAK,EAAE,MAAM,aAAwB;CACnD,MAAM,EAAE,SAAS,UAAU,aAAa,YAAY;CAEpD,OACE,oBAAC,OAAD;EAAK,WAAW,GAAG,yCAAyC,SAAS;EACnE,UAAA,qBAAC,OAAD;GAAK,WAAU;GAAf,UAAA;IACG,WAAW,oBAAC,KAAD;KAAG,WAAU;KAA2C,UAAA;IAAW,CAAA;IAC/E,oBAAC,MAAD;KAAI,WAAU;KACX,UAAA;IACC,CAAA;IACH,eACC,oBAAC,KAAD;KAAG,WAAU;KAA6D,UAAA;IAAe,CAAA;IAE1F,WAAW,QAAQ,SAAS,KAC3B,oBAAC,OAAD;KAAK,WAAU;KACZ,UAAA,QAAQ,KAAK,QAAQ,UACpB,oBAAC,cAAD,EAAkC,OAAS,GAAxB,KAAwB,CAC5C;IACE,CAAA;GAEJ;;CACF,CAAA;AAET;;;AClEA,SAAS,YAAY,EAAE,SAAS,SAA2B;CACzD,MAAM,UAAU,QAAQ,OAAO,MAAM;CACrC,MAAM,eAAe,QAAQ,OAAO,EAAE,MAAM,QAAQ,KAAK,IAAI,CAAC;CAG9D,MAAM,YAAY,QAAQ;CAE1B,OACE,qBAAC,SAAD;EACE,GAAI;EACJ,WAAW,GACT,4IACA,QAAQ,QAAQ,gBAClB;EALF,UAAA,CAQE,qBAAC,OAAD;GACE,WAAU;GACV,OAAM;GACN,OAAO,EAAE,OAAO,uBAAuB;GACvC,eAAY;GAJd,UAAA,CAME,oBAAC,QAAD,EAAA,UACE,oBAAC,WAAD;IAAS,IAAI;IAAW,OAAM;IAAK,QAAO;IAAK,cAAa;IAC1D,UAAA,oBAAC,QAAD;KACE,GAAE;KACF,MAAK;KACL,QAAO;KACP,aAAY;KACZ,SAAQ;IACT,CAAA;GACM,CAAA,EACL,CAAA,GACN,oBAAC,QAAD;IAAM,OAAM;IAAO,QAAO;IAAO,MAAM,QAAQ,UAAU;GAAK,CAAA,CAC3D;EAGL,CAAA,GAAA,qBAAC,OAAD;GAAK,WAAU;GAAf,UAAA;IACG,QAAQ,QACP,oBAAC,OAAD;KAAK,WAAU;KACZ,UAAA,iBAAiB,QAAQ,MAAM,sBAAsB;IACnD,CAAA;IAEP,oBAAC,MAAD;KAAI,WAAU;KAA8B,UAAA,QAAQ;IAAU,CAAA;IAC9D,oBAAC,KAAD;KAAG,WAAU;KAAiC,UAAA,QAAQ;IAAe,CAAA;GAClE;EACE,CAAA,CAAA;;AAEb;AAEA,SAAgB,SAAS,EAAE,UAAU,aAA4B;CAC/D,IAAI,CAAC,YAAY,SAAS,WAAW,GAAG,OAAO;CAE/C,OACE,oBAAC,OAAD;EAAK,WAAW,GAAG,gCAAgC,SAAS;EAC1D,UAAA,oBAAC,OAAD;GAAK,WAAU;GACZ,UAAA,SAAS,KAAK,SAAS,UACtB,oBAAC,aAAD;IAAkC;IAAgB;GAAQ,GAAxC,KAAwC,CAC3D;EACE,CAAA;CACF,CAAA;AAET;;;ACzEA,IAAM,eAAa,eAAe;AAelC,SAAwB,YAAY;CAClC,MAAM,EAAE,MAAM,SAAS;CACvB,MAAM,SAAU,aAAW,UAA0B,CAAC;CAItD,MAAM,gBAAgB,SAAiB;EACrC,IAAI,cAAc,IAAI,GAAG,OAAO;EAChC,IAAI,KAAK,WAAW,QAAQ,GAAG,OAAO,GAAG,KAAK;EAC9C,OAAO;CACT;CAGA,MAAM,WACJ,MAAM,UAAU,KAAK,OAAO;EAC1B,GAAG;EACH,MAAM,EAAE,OAAO,aAAa,EAAE,IAAI,IAAI,KAAA;CACxC,EAAE,KACF,OACG,QAAQ,MAAM,EAAE,OAAO,CAAC,CACxB,KAAK,WAAW;EACf,MAAM,MAAM,SAAS;EACrB,OAAO,MAAM,SAAS,SAAS,MAAM;EACrC,aAAa,MAAM,SAAS,eAAe;EAC3C,MAAM,aAAa,QAAQ,MAAM,OAAO,MAAM,QAAQ,EAAE,EAAE,QAAQ,IAAI;CACxE,EAAE;CAGN,MAAM,OAAO,MAAM,OACf;EACE,GAAG,KAAK;EACR,SAAS,KAAK,KAAK,SAAS,KAAK,OAAO;GACtC,GAAG;GACH,MAAM,aAAa,EAAE,IAAI;EAC3B,EAAE;CACJ,IACA;EACE,UAAU,KAAK;EACf,aAAa,KAAK;CACpB;CAEJ,OACE,qBAAC,OAAD;EAAK,WAAU;EAAf,UAAA;GACE,oBAAC,OAAD;IAAK,WAAU;IAA8B,IAAG;GAAgB,CAAA;GAGhE,oBAAC,OAAD;IACE,eAAY;IACZ,WAAU;IAEV,UAAA,oBAAC,OAAD;KACE,OAAO,EACL,UACE,mNACJ;KACA,WAAU;IACX,CAAA;GACE,CAAA;GAGL,oBAAC,MAAD,EAAY,KAAO,CAAA;GAGnB,oBAAC,UAAD,EAAoB,SAAW,CAAA;GAG/B,oBAAC,OAAD;IACE,eAAY;IACZ,WAAU;IAEV,UAAA,oBAAC,OAAD;KACE,OAAO,EACL,UACE,mNACJ;KACA,WAAU;IACX,CAAA;GACE,CAAA;EACF;;AAET;;;ACvFA,SAAwB,OAAO,EAC7B,OAAO,IACP,YAAY,IACZ,kBAAkB,IAClB,YACA,WAAW,OACX,UACA,GAAG,SACW;CACd,MAAM,kBAAkB;EACtB,IAAI,CAAC,cAAc,OAAO,WAAW,aAAa,OAAO;EACzD,MAAM,WAAW,OAAO,SAAS;EACjC,IAAI,OAAO,eAAe,UACxB,OAAO,aAAa,cAAc,SAAS,SAAS,UAAU;EAChE,IAAI,sBAAsB,QAAQ,OAAO,WAAW,KAAK,QAAQ;EACjE,IAAI,OAAO,eAAe,YAAY,OAAO,WAAW,QAAQ;EAChE,OAAO;CACT,EAAA,CAAG;CAEH,MAAM,aAAa,cAAc,IAAI;CAGrC,MAAM,cAAc,GAClB,qCACA,WAHkB,WAAW,kBAAkB,IAK/C,YAAY,+BACd;CAEA,IAAI,UACF,OAAO,oBAAC,QAAD;EAAM,WAAW;EAAc;CAAe,CAAA;CAGvD,IAAI,YACF,OACE,qBAAC,KAAD;EAAS;EAAM,WAAW;EAAa,QAAO;EAAS,KAAI;EAAsB,GAAI;EAArF,UAAA,CACG,UACD,oBAAC,cAAD,EAAc,WAAU,kCAAmC,CAAA,CAC1D;;CAIP,OACE,oBAAC,KAAD;EAAS;EAAM,WAAW;EAAa,GAAI;EACxC;CACA,CAAA;AAEP;;;ACxDA,IAAM,eAAa,eAAe;AACC,cAAc,aAAW,UAAU,CAAC,CAAC;AACxE,IAAa,SAAS;;;;;;;ACetB,IAAa,wBAAwB,cAIlC;CAAE,QAAQ;CAAM,YAAY,CAAC;CAAG,cAAc,CAAC;AAAE,CAAC;AAErD,SAAgB,uBAAuB,EAAE,YAAqC;CAC5E,MAAM,CAAC,QAAQ,aAAa,SAAwB,IAAI;CAGxD,MAAM,OAAO,aAAa,OAAe,UAAU,EAAE,GAAG,CAAC,CAAC;CAC1D,MAAM,SAAS,aAAa,OAAe,WAAW,SAAU,SAAS,KAAK,OAAO,EAAG,GAAG,CAAC,CAAC;CAC7F,OACE,oBAAC,sBAAsB,UAAvB;EAAgC,OAAO;GAAE;GAAQ;GAAM;EAAO;EAC3D;CAC6B,CAAA;AAEpC;AASA,SAAwB,QAAQ,EAC9B,OACA,MACA,OACA,QACA,OACA,YACA,aAAa,IACb,UAAU,gBACK;CACf,MAAM,WAAW,aAAa,GAAG,aAAa,SAAS,QAAQ;CAC/D,MAAM,kBACJ,iBAAiB,OAAO,WAAW,cAAc,OAAO,SAAS,WAAW;CAO9E,MAAM,cAAc,OAAW,SAAS,YAAY;CACpD,MAAM,EAAE,QAAQ,MAAM,WAAW,WAAW,qBAAqB;CACjE,MAAM,mBAAmB,QAAQ,KAAK,MAAM,eAAe,SAAS;CAGpE,MAAM,YAAY,SAAS,cAAc,IAAI;CAE7C,MAAM,CAAC,QAAQ,aAAa,eAAe;EACzC,IAAI,kBAAkB,OAAO;EAC7B,IAAI,UAAU,GAAG,OAAO;EACxB,OAAO;CACT,CAAC;CAED,MAAM,gBAAgB,mBAAmB,WAAW,WAAW;CAC/D,MAAM,qBAAqB;EACzB,IAAI,kBAAkB,OAAO,QAAQ;OAChC,WAAW,MAAM,CAAC,CAAC;CAC1B;CAMA,MAAM,iBAAiB,gBAAgB,WAAW,QAAQ,KAAK,oBAAoB;CACnF,gBAAgB;EACd,IAAI,oBAAoB,gBAAgB,KAAK,QAAQ;CACvD,GAAG;EAAC;EAAkB;EAAgB;EAAU;CAAI,CAAC;CAGrD,MAAM,eAAe,GAAG,UAAU,KAAK,QAAQ,UAAU,KAAK,QAAQ,SAAS,KAAK,OAAO;CAC3F,MAAM,WAAW,oBAAoB,YAAY,oBAAoB,GAAG,SAAS;CACjF,MAAM,YAAY,OAAuB,IAAI;CAE7C,gBAAgB;EACd,IAAI,YAAY,UAAU,SACxB,UAAU,QAAQ,eAAe,EAAE,OAAO,UAAU,CAAC;CAEzD,GAAG,CAAC,QAAQ,CAAC;CAGb,IAAI,CAAC,OAAO;EACV,MAAM,OACJ,oBAAC,QAAD;GACE,MAAM,aAAa,QAAQ;GAC3B,WAAU;GACV,iBAAgB;GAChB,aAAa,SAAS,SAAS,YAAY,SAAS,GAAG,SAAS;GAChE,SAAS;GAER,UAAA;EACK,CAAA;EAKV,IAAI,SAAS,GAAG;GAGd,IAAI,OAAW,SAAS,YAAY,aAAa;IAI/C,MAAM,iBAAyC;KAAE,GAAG;KAAI,GAAG;IAAG;IAC9D,IAAI,UAAU;IACd,KAAK,IAAI,IAAI,GAAG,IAAI,OAAO,KACzB,WAAW,eAAe,MAAM;IAGlC,OACE,oBAAC,OAAD;KACE,KAAK;KACL,WAAW,GAAG,cAAc,WAAW,mBAAmB,oBAAoB;KAC9E,OAAO,EAAE,YAAY,IAAI,QAAQ,IAAI;KAErC,UAAA,oBAAC,OAAD;MAAK,WAAW,GAAG,aAAa,YAAY;MAAI,UAAA;KAAU,CAAA;IACvD,CAAA;GAET;GAEA,OACE,oBAAC,OAAD;IACE,KAAK;IACL,WAAW,GACT,QACA,cACA,cACA,WAAW,mBAAmB,iBAChC;IAEC,UAAA;GACE,CAAA;EAET;EAEA,OACE,oBAAC,OAAD;GAAK,KAAK;GAAW,WAAW,GAAG,QAAQ,YAAY;GACpD,UAAA;EACE,CAAA;CAET;CAGA,OACE,qBAAC,OAAD;EAAK,KAAK,WAAW,YAAY,KAAA;EAAW,WAAW,GAAG,iBAAiB,YAAY;EAAvF,UAAA,CAEE,qBAAC,UAAD;GACE,MAAK;GACL,SAAS;GACT,WAAW,GACT,oGAIA,UAAU,cAAc,IACpB,oCACA,0CACN;GAXF,UAAA,CAaG,SACC,oBAAC,QAAD,EAAA,UAAO,MAAY,CAAA,IAEnB,oBAAC,QAAD;IACE,MAAM,aAAa,QAAQ;IAC3B,WAAU;IACV,iBAAgB;IAChB,aAAa,SAAS,SAAS,YAAY,SAAS,GAAG,SAAS;IAChE,SAAS;IAER,UAAA;GACK,CAAA,GAEV,oBAAC,aAAD,EACE,WAAW,GACT,2EAGA,gBAAgB,aAAa,YAC/B,EACD,CAAA,CACK;EAGP,CAAA,GAAA,iBACC,oBAAC,OAAD;GAAK,WAAU;GACZ,UAAA,MAAM,KAAK,SACV,oBAAC,SAAD;IAEE,GAAI;IACJ,MAAM,KAAK;IACX,OAAO,QAAQ;IACH;IACZ,YAAY;IACZ,UAAU;GACX,GAPM,GAAG,WAAW,KAAK,MAOzB,CACF;EACE,CAAA,CAEJ;;AAET;;;AC1NA,SAAwB,mBAAmB,EAAE,MAAM,SAAkC;CACnF,OACE,qBAAC,OAAD;EAAK,WAAU;EAAf,UAAA,CACG,QACC,oBAAC,QAAD;GAAM,WAAU;GACb,UAAA,iBAAiB,MAAM,aAAa;EACjC,CAAA,GAER,oBAAC,MAAD;GAAI,WAAU;GACZ,UAAA,oBAAC,QAAD,EAAA,UAAO,MAAY,CAAA;EACjB,CAAA,CACD;;AAET;;;ACJA,SAAS,kBAAkB,MAAkC;CAC3D,IAAI,CAAC,KAAK,WAAW,OAAO,GAAG,OAAO,KAAA;CACtC,MAAM,QAAQ,KAAK,MAAM,kBAAkB;CAC3C,OAAO,QAAQ,MAAM,KAAK,KAAA;AAC5B;AAEA,SAAS,gBAAgB,aAAqB,WAA+C;CAC3F,OAAO,UAAU,MAAM,UAAU;EAE/B,OADuB,MAAM,KAAK,QAAQ,aAAa,EAChD,MAAmB;CAC5B,CAAC;AACH;AAEA,SAAwB,KAAK,EAAE,YAAY,YAAY,IAAI,UAAU,SAAS,CAAC,KAAgB;CAC7F,MAAM,aAAa;CACnB,MAAM,CAAC,eAAe,eACd,aAAa,OAAO,WAAW,cAAc,OAAO,SAAS,WAAW,QAChF;CAEA,IAAI,CAAC,YAAY,WAAW,OAAO,GAAG,OAAO;CAE7C,MAAM,OAAO,OAAW,SAAS,WAAW;CAC5C,MAAM,WAAW;EACf,cAAc;EACd,WAAW,GAAG,+BAA+B,SAAS;CACxD;CAGA,MAAM,oBAAoB,MAAiB,iBAAyB,QAAgB;EAClF,MAAM,WAAW,QAAQ,kBAAkB,KAAK;EAChD,MAAM,WAAW,gBAAgB,YAAY,gBAAgB,GAAG,SAAS;EACzE,OACE,oBAAC,MAAD,EAAA,UACE,oBAAC,OAAD;GACE,WAAW,GACT,yBACA,WAAW,mBAAmB,oBAChC;GAEA,UAAA,oBAAC,OAAD;IAAK,WAAU;IACb,UAAA,oBAAC,SAAD;KACE,GAAI;KACJ,MAAM,KAAK;KACX,OAAO;KACK;KACZ,YAAY,QAAQ;IACrB,CAAA;GACE,CAAA;EACF,CAAA,EACH,GAjBK,GAiBL;CAER;CAEA,MAAM,kBAAkB;CAGxB,IAAI,SAAS,aAAa;EACxB,MAAM,gBAAgB,WAAW,QAAQ,MAAM,EAAE,OAAO;EAGxD,IAAI,cAAc,WAAW,GAC3B,OACE,oBAAC,wBAAD,EAAA,UACE,oBAAC,OAAD;GAAK,GAAI;GACP,UAAA,oBAAC,MAAD;IAAI,WAAW;IACZ,UAAA,WAAW,KAAK,UAAU,iBAAiB,OAAO,IAAI,MAAM,IAAI,CAAC;GAChE,CAAA;EACD,CAAA,EACiB,CAAA;EAI5B,OACE,oBAAC,wBAAD,EAAA,UACE,oBAAC,OAAD;GAAK,GAAI;GACN,UAAA,cAAc,KAAK,OAAO,MACzB,qBAAC,OAAD;IAAsB,WAAW,IAAI,IAAI,iBAAiB;IAA1D,UAAA,CACE,oBAAC,oBAAD;KACE,MAAM,MAAM,SAAS;KACrB,OAAO,MAAM,SAAS,SAAS,MAAM;IACtC,CAAA,GACD,oBAAC,MAAD;KAAI,WAAW;KACZ,UAAA,MAAM,OAAO,KAAK,SAAS,iBAAiB,MAAM,MAAM,MAAM,KAAK,IAAI,CAAC;IACvE,CAAA,CACD;GARK,GAAA,MAAM,IAQX,CACN;EACE,CAAA,EACiB,CAAA;CAE5B;CAGA,MAAM,aAAa,gBAAgB,WAAW,gBAAgB;CAC9D,MAAM,iBAAiB,aACnB,WAAW,EAAE,EAAE,KAAK,QAAQ,aAAa,EAAE,IAC3C,kBAAkB,WAAW;CAEjC,MAAM,eACJ,cAAc,WAAW,KACrB,iBACE,gBAAgB,gBAAgB,UAAU,IAC1C,WAAW,KACb,iBACE,gBAAgB,gBAAgB,UAAU,IAC1C,KAAA;CAER,IAAI,CAAC,cAAc,OAAO;CAE1B,OACE,oBAAC,wBAAD,EAAA,UACE,oBAAC,OAAD;EAAK,GAAI;EACP,UAAA,oBAAC,MAAD;GAAI,WAAU;GACZ,UAAA,oBAAC,MAAD,EAAA,UACE,oBAAC,SAAD;IACE,GAAI;IACJ,MAAM,aAAa;IACnB,OAAO;IACK;IACZ,YAAW;GACZ,CAAA,EACC,GARK,aAAa,KAQlB;EACF,CAAA;CACD,CAAA,EACiB,CAAA;AAE5B;;;ACzIA,IAAM,aAAa,eAAe;AAQlC,SAAgB,WAAW,EAAE,UAAU,SAAS,WAAW,WAA4B;CACrF,OAAO,MAAM,cACX,OACA,EAAE,WAAW,gDAAgD,GAC7D,MAAM,cACJ,OACA,EAAE,WAAW,iCAAiC,GAC9C,MAAM,cACJ,SACA;EACE,IAAI;EACJ,WACE;EACF,aAAa;EACb,cAAc;EACd,aAAa,WAAW;CAC1B,GAEA,MAAM,cACJ,OACA,EAAE,WAAW,4CAA4C,GACzD,MAAM,cAAc,MAAM;EAAE;EAAU,QAAQ,WAAW,UAAU,CAAC;CAAE,CAAC,CACzE,CACF,GACA,MAAM,cACJ,QACA,EAAE,WAAW,4CAA4C,GACzD,MAAM,cACJ,OACA,EAAE,WAAW,0DAA0D,GACvE,MAAM,cACJ,OACA,EAAE,WAAW,mEAAmE,GAChF,IAAI,WAAW,QAAQ,QAAQ,CAAC,EAAA,CAAG,KAAK,SAA0C;EAChF,MAAM,aAAa,eAAe,KAAK,KAAK,IAAI;EAChD,MAAM,eAAe,KAAK,SAAS;EACnC,OAAO,MAAM,cACX,KACA;GACE,KAAK,KAAK;GACV,MAAM,KAAK;GACX,WAAW,oEAAoE,eAAe,gCAAgC;GAC9H,GAAI,aAAa;IAAE,QAAQ;IAAU,KAAK;GAAsB,IAAI,CAAC;EACvE,GACA,KAAK,OACL,aACI,MAAM,cACJ,OACA;GACE,OAAO;GACP,OAAO;GACP,QAAQ;GACR,SAAS;GACT,MAAM;GACN,QAAQ;GACR,aAAa;GACb,eAAe;GACf,gBAAgB;EAClB,GACA,MAAM,cAAc,QAAQ,EAAE,GAAG,aAAa,CAAC,GAC/C,MAAM,cAAc,QAAQ,EAAE,GAAG,aAAa,CAAC,CACjD,IACA,IACN;CACF,CAAC,CACH,CACF,GACA,MAAM,cAAc,OAAO,EAAE,WAAW,gBAAgB,GAAG,QAAQ,CACrE,CACF,CACF;AACF;;;ACnFA,IAAM,YAAY;AAElB,IAAM,aAAqC;CACzC,KAAK;CACL,KAAK;CACL,KAAK;CACL,MAAK;CACL,KAAK;AACP;;;;;;AAOA,SAAgB,WAAW,OAAuB;CAChD,OAAO,MAAM,QAAQ,YAAY,OAAO,WAAW,GAAG;AACxD;;;;;;;;;;ACwBA,SAAgB,UAAU,MAAgC;CACxD,MAAM,EACJ,OACA,aACA,MACA,SACA,KACA,IACA,OACA,KACA,cACA,UACA,QAAQ,GACR,WACA,WACA,iBAAiB,UACf;CACJ,MAAM,YAAY,QAAQ,WAAW,WAAW,KAAK,EAAE,KAAK;CAC5D,MAAM,aAAa,WAAW,aAAa,UAAU,GAAG,WAAW,QAAQ,EAAE,YAAY;CACzF,MAAM,gBAAgB,WAAW,SAAS,OAAO,UAAU,KAAK,MAAM,MAAM;CAC5E,MAAM,gBAAgB,WAAW,SAAS,OAAO,UAAU,KAAK,MAAM,MAAM;CAC5E,MAAM,cAAc,UAAU,IAAI,KAAK,MAAM,OAAO,KAAK;CACzD,MAAM,cAAc,iBAAiB,aAAa,cAAc;CAChE,MAAM,eAAe,SACnB,iBAAiB,OAAO,KAAK,WAAW,GAAG,IAAI,cAAc,KAAK,MAAM,CAAC,IAAI;CAG/E,IAAI,UAAU;CACd,IAAI,KAAK,KAAK;EACZ,MAAM,IAAI,KAAK;EACf,MAAM,IAAI;EACV,UAAU,0CAA0C,EAAE,KAAK,EAAE,mDAAmD,EAAE,WAAW,EAAE,2CAA2C,EAAE,EAAE,GAAG,EAAE,kGAAkG,EAAE,EAAE,QAAQ,EAAE,oGAAoG,EAAE,EAAE,GAAG,EAAE;EAChZ,IAAI,EAAE,OACJ,WAAW,0CAA0C,EAAE,EAAE,KAAK,EAAE;CAEpE;CAEA,OAAO;;;;;WAKE,WAAW,KAAK,EAAE;sCACS,WAAW,WAAW,EAAE;IAC1D,UAAU,8CAA8C,WAAW,YAAY,OAAO,CAAC,EAAE,MAAM,KAAK,WAAW;8BACrF,WAAW,cAAc,GAAG,EAAE;iCAC3B,WAAW,cAAc,GAAG,EAAE;IAC3D,MAAM,uDAAuD,WAAW,GAAG,EAAE,MAAM,GAAG;IACtF,QAAQ;WACD,UAAU,oHAAmH,cAAc;;;mBAGnI,KAAK;oCACY,WAAW,cAAc,EAAE,EAAE;yBACxC,UAAU,QAAQ,WAAW,cAAc,EAAE,EAAE,cAAa,eAAe,OAAO,iBAAiB,KAAK,cAAc;;;AAG/I;AAEA,SAAgB,UAAU,SAAiB,OAAwB;CACjE,MAAM,MAAM,WAAW,WAAW,eAAe;CACjD,MAAM,KAAK,WAAW,SAAS,EAAE;CACjC,OAAO;;;;;;;;;;;;;;;6BAeoB,IAAI,SAAS,KAAK,OAAO,OAAO,GAAG;;;AAGhE;AAEA,SAAgB,UAAU,OAAuB;CAC/C,OAAO,kBAAkB,WAAW,KAAK,EAAE;;;;;;;;;AAS7C"}
@@ -1 +0,0 @@
1
- {"version":3,"file":"logger-CycvLCrQ.js","names":[],"sources":["../../package.json","../node/logger.ts"],"sourcesContent":["{\n \"name\": \"@docubook/flame\",\n \"version\": \"2.0.0-beta.2\",\n \"description\": \"A blazing-fast React + MDX framework powered by Bun, built for modern documentation experiences.\",\n \"type\": \"module\",\n \"bin\": {\n \"flame\": \"./bin/cli.js\"\n },\n \"files\": [\n \"bin\",\n \"template\",\n \"docu.schema.json\",\n \".docu\",\n \"!.docu/__tests__\",\n \"!.docu/dist\",\n \"!.docu/build-cache.json\",\n \"README.md\",\n \"LICENSE\"\n ],\n \"publishConfig\": {\n \"registry\": \"https://registry.npmjs.org/\",\n \"access\": \"public\"\n },\n \"engines\": {\n \"node\": \">=20.11\",\n \"bun\": \">=1.1.0\"\n },\n \"scripts\": {\n \"dev\": \"bun .docu/node/server.ts\",\n \"build\": \"NODE_ENV=production bun .docu/node/build.ts\",\n \"clean\": \"bun .docu/node/clean.ts\",\n \"preview\": \"bun .docu/node/preview.ts\",\n \"deploy\": \"bun .docu/node/deploy.ts\",\n \"compile:lib\": \"node bin/compile-lib.mjs\",\n \"test\": \"vitest run\",\n \"lint\": \"eslint .\",\n \"prepublishOnly\": \"bun .docu/node/clean.ts && eslint . && vitest run && node bin/compile-lib.mjs\"\n },\n \"keywords\": [\n \"docubook\",\n \"documentation\",\n \"static-site\",\n \"daisyui\",\n \"bun\",\n \"docs framework\",\n \"react\",\n \"react-dom\"\n ],\n \"homepage\": \"https://github.com/DocuBook/docubook/tree/main/packages/flame\",\n \"repository\": {\n \"type\": \"git\",\n \"url\": \"git+https://github.com/DocuBook/docubook.git\",\n \"directory\": \"packages/flame\"\n },\n \"author\": \"wildan.nrs\",\n \"author-url\": \"https://wildan.dev\",\n \"license\": \"MIT\",\n \"dependencies\": {\n \"@docubook/core\": \"workspace:^\",\n \"@docubook/markdown\": \"workspace:^\",\n \"@docubook/themes-colors\": \"workspace:^\",\n \"@docubook/ui-react\": \"workspace:^\",\n \"@mdx-js/react\": \"^3.0.1\",\n \"@tailwindcss/cli\": \"4.3.0\",\n \"@tailwindcss/typography\": \"0.5.16\",\n \"bun-plugin-tailwind\": \"^0.1.2\",\n \"daisyui\": \"^5.5.19\",\n \"vite\": \"^8.2.1\",\n \"lucide-react\": \"^1.14.0\",\n \"react\": \"^19.2.7\",\n \"react-dom\": \"^19.2.7\",\n \"unified\": \"^11.0.0\",\n \"zod\": \"^4.4.3\"\n },\n \"peerDependencies\": {\n \"@sentry/bun\": \"^10.0.0\"\n },\n \"peerDependenciesMeta\": {\n \"@sentry/bun\": {\n \"optional\": true\n }\n },\n \"devDependencies\": {\n \"@eslint/js\": \"^10.0.1\",\n \"@types/node\": \"^22.0.0\",\n \"@types/react\": \"^19.0.0\",\n \"@types/react-dom\": \"^19.0.0\",\n \"bun-types\": \"^1.3.0\",\n \"eslint\": \"^10.3.0\",\n \"eslint-plugin-perfectionist\": \"^5.9.0\",\n \"eslint-plugin-react\": \"^7.37.5\",\n \"eslint-plugin-react-hooks\": \"^7.1.1\",\n \"tailwindcss\": \"^4.3.0\",\n \"typescript\": \"^5.9.3\",\n \"typescript-eslint\": \"^8.59.2\"\n }\n}\n","/**\n * Interactive CLI logger with spinner and tree-style route display.\n * Inspired by Next.js/Turbopack build output.\n *\n * Supports structured logging via environment variables:\n * - LOG_LEVEL: debug | info | warn | error (default: info)\n * - LOG_FORMAT: json | pretty (default: pretty)\n */\n\nimport { loadDocuConfig } from \"./paths\";\nimport pkg from \"../../package.json\" with { type: \"json\" };\n\nconst docuConfig = loadDocuConfig();\nconst isCI = !!(process.env.CI || process.env.NO_COLOR || !process.stdout.isTTY);\nconst LOG_FORMAT = process.env.LOG_FORMAT || \"pretty\";\nconst isJSON = LOG_FORMAT === \"json\";\n\ntype LogLevel = \"debug\" | \"info\" | \"warn\" | \"error\";\nconst LEVELS: Record<LogLevel, number> = { debug: 0, info: 1, warn: 2, error: 3 };\nconst currentLevel = LEVELS[(process.env.LOG_LEVEL as LogLevel) || \"info\"] ?? LEVELS.info;\n\nfunction shouldLog(level: LogLevel): boolean {\n return LEVELS[level] >= currentLevel;\n}\n\nfunction jsonLog(level: LogLevel, msg: string, meta?: Record<string, unknown>) {\n if (!shouldLog(level)) return;\n const entry = { ts: new Date().toISOString(), ...meta, level, msg };\n const out = level === \"error\" ? console.error : level === \"warn\" ? console.warn : console.log;\n out(JSON.stringify(entry));\n}\n\n/** Returns true if the caller should skip (already handled or filtered). */\nfunction guard(level: LogLevel, msg: string, meta?: Record<string, unknown>): boolean {\n if (isJSON) {\n jsonLog(level, msg, meta);\n return true;\n }\n return !shouldLog(level);\n}\n\nconst c =\n isCI || isJSON\n ? {\n reset: \"\",\n bold: \"\",\n dim: \"\",\n green: \"\",\n cyan: \"\",\n magenta: \"\",\n yellow: \"\",\n red: \"\",\n white: \"\",\n gray: \"\",\n }\n : {\n reset: \"\\x1b[0m\",\n bold: \"\\x1b[1m\",\n dim: \"\\x1b[2m\",\n green: \"\\x1b[32m\",\n cyan: \"\\x1b[36m\",\n magenta: \"\\x1b[35m\",\n yellow: \"\\x1b[33m\",\n red: \"\\x1b[31m\",\n white: \"\\x1b[37m\",\n gray: \"\\x1b[90m\",\n };\n\nconst SPINNER_FRAMES = [\"⠋\", \"⠙\", \"⠹\", \"⠸\", \"⠼\", \"⠴\", \"⠦\", \"⠧\", \"⠇\", \"⠏\"];\n\nclass Spinner {\n private frame = 0;\n private message = \"\";\n private timer: ReturnType<typeof setInterval> | null = null;\n\n info(finalMsg: string) {\n if (this.timer) clearInterval(this.timer);\n this.timer = null;\n if (isCI) {\n console.log(`ℹ ${finalMsg}`);\n } else {\n process.stdout.write(`\\r\\x1b[K${c.cyan}ℹ${c.reset} ${finalMsg}\\n`);\n process.stdout.write(\"\\x1b[?25h\");\n }\n }\n\n start(msg: string) {\n this.message = msg;\n if (isCI) {\n console.log(`… ${msg}`);\n return;\n }\n this.frame = 0;\n process.stdout.write(\"\\x1b[?25l\");\n this.render();\n this.timer = setInterval(() => this.render(), 80);\n }\n\n stop(finalMsg: string) {\n if (this.timer) clearInterval(this.timer);\n this.timer = null;\n if (isCI) {\n console.log(`✓ ${finalMsg}`);\n return;\n }\n process.stdout.write(`\\r\\x1b[K${c.green}✓${c.reset} ${finalMsg}\\n`);\n process.stdout.write(\"\\x1b[?25h\");\n }\n\n private render() {\n const f = SPINNER_FRAMES[this.frame % SPINNER_FRAMES.length];\n process.stdout.write(`\\r${c.cyan}${f}${c.reset} ${this.message}`);\n this.frame++;\n }\n}\n\ninterface RouteItem {\n title: string;\n href: string;\n noLink?: boolean;\n items?: RouteItem[];\n}\n\nconst MAX_ROUTE_LINES = 5;\nlet routeLineCount = 0;\nlet routeTruncated = false;\n\nfunction printRouteTree(routes: RouteItem[], prefix = \"\", isRoot = true) {\n for (let i = 0; i < routes.length; i++) {\n if (routeTruncated) return;\n if (routeLineCount >= MAX_ROUTE_LINES) {\n routeTruncated = true;\n process.stdout.write(`${prefix}${c.dim}...${c.reset}\\n`);\n return;\n }\n\n const route = routes[i];\n const last = i === routes.length - 1;\n const connector = isRoot ? \"\" : last ? \"└── \" : \"├── \";\n const childPrefix = isRoot ? \"\" : last ? \" \" : \"│ \";\n\n const path = route.noLink\n ? `${c.dim}${route.href}${c.reset}`\n : `${c.white}${route.href}${c.reset}`;\n\n const label = route.noLink ? `${c.gray}(group)${c.reset}` : \"\";\n\n process.stdout.write(`${prefix}${connector}${path} ${label}\\n`);\n routeLineCount++;\n\n if (route.items?.length) {\n printRouteTree(route.items, prefix + childPrefix, false);\n }\n }\n}\n\nexport const logger = {\n spinner: new Spinner(),\n\n buildStart() {\n if (guard(\"info\", \"build_start\", { package: \"@docubook/flame\", version: pkg.version })) return;\n console.log(\n `\\n${c.bold}${c.cyan} 🔥 DocuBook Flame${c.reset} ${c.dim}v${pkg.version}${c.reset}\\n`\n );\n },\n\n bundleStart() {\n if (guard(\"info\", \"bundle_start\")) return;\n this.spinner.start(\"Building client bundle...\");\n },\n\n bundleDone(ms: number) {\n if (guard(\"info\", \"bundle_done\", { duration_ms: ms })) return;\n this.spinner.stop(`Client bundle compiled ${c.dim}(${ms}ms)${c.reset}`);\n },\n\n indexStart() {\n if (guard(\"info\", \"index_start\")) return;\n this.spinner.start(\"Generating search index...\");\n },\n\n indexDone(records: number, ms: number, skipped = false) {\n if (guard(\"info\", \"index_done\", { records, duration_ms: ms, skipped })) return;\n this.spinner.stop(\n skipped\n ? `Search index cached ${c.dim}(${ms}ms)${c.reset}`\n : `Search index generated ${c.dim}(${records} records, ${ms}ms)${c.reset}`\n );\n },\n\n routes() {\n if (guard(\"debug\", \"routes\")) return;\n const routes = docuConfig.routes as RouteItem[] | undefined;\n if (!routes?.length) return;\n\n console.log(`\\n${c.bold} Routes${c.reset} ${c.dim}(${countRoutes(routes)} pages)${c.reset}\\n`);\n routeLineCount = 0;\n routeTruncated = false;\n printRouteTree(routes, \" \");\n },\n\n ready(port: number, hmr = false) {\n if (guard(\"info\", \"server_ready\", { port, hmr })) return;\n console.log(\n `\\n${c.green}${c.bold} ✓ Ready${c.reset} in ${c.bold}http://localhost:${port}/docs/${c.reset}`\n );\n if (hmr) console.log(`${c.dim} HMR enabled — watching docs/ for changes${c.reset}`);\n console.log(\"\");\n },\n\n request(method: string, pathname: string, status: number, duration_ms?: number) {\n if (guard(\"info\", \"http_request\", { method, path: pathname, status, duration_ms })) return;\n const color = status >= 500 ? c.red : status >= 400 ? c.gray : c.green;\n const ts = new Date().toLocaleTimeString();\n const dur = duration_ms != null ? ` ${c.dim}${duration_ms}ms${c.reset}` : \"\";\n console.log(\n `${c.dim} ${ts}${c.reset} ${method} ${pathname} ${color}${status}${c.reset}${dur}`\n );\n },\n\n debug(msg: string, meta?: Record<string, unknown>) {\n if (guard(\"debug\", msg, meta)) return;\n console.log(`${c.gray} [debug] ${msg}${c.reset}`);\n },\n\n warn(msg: string, meta?: Record<string, unknown>) {\n if (guard(\"warn\", msg, meta)) return;\n console.warn(`${c.yellow} ⚠ ${msg}${c.reset}`);\n },\n\n error(msg: string, meta?: Record<string, unknown>) {\n if (guard(\"error\", msg, meta)) return;\n console.error(`${c.red} ✖ ${msg}${c.reset}`);\n },\n};\n\nfunction countRoutes(routes: RouteItem[]): number {\n let count = 0;\n for (const r of routes) {\n if (!r.noLink) count++;\n if (r.items) count += countRoutes(r.items);\n }\n return count;\n}\n"],"mappings":"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"}
@@ -1 +0,0 @@
1
- {"version":3,"file":"paths-BtOIPBQ9.js","names":[],"sources":["../node/paths.ts"],"sourcesContent":["import { resolve, join } from \"node:path\";\nimport { existsSync, readFileSync } from \"node:fs\";\nimport { readdir, rm, unlink } from \"node:fs/promises\";\nimport type { DocuConfig } from \"./types\";\n\n/**\n * FRAMEWORK_ROOT: Where the package code lives (.docu/components, .docu/pages, .docu/styles, .docu/node)\n * PROJECT_ROOT: Where the user's project lives (docs/, docu.json)\n */\n\n// .docu/node/paths.ts → package root is 2 levels up\nexport const FRAMEWORK_ROOT = resolve(import.meta.dirname, \"../..\");\nexport const PROJECT_ROOT = process.cwd();\n\n// Framework paths (internal)\nexport const PAGES_DIR = join(FRAMEWORK_ROOT, \".docu/pages\");\nexport const STYLES_DIR = join(FRAMEWORK_ROOT, \".docu/styles\");\nconst nodeDir = join(FRAMEWORK_ROOT, \".docu/node\");\nconst libDir = join(FRAMEWORK_ROOT, \".docu/lib\");\nexport const LIB_DIR = existsSync(nodeDir) ? nodeDir : libDir;\n\n// Build output (user project)\nexport const DIST_DIR = join(PROJECT_ROOT, \".docu/dist\");\nexport const ASSETS_DIR = join(DIST_DIR, \"assets\");\nexport const CACHE_FILE = join(PROJECT_ROOT, \".docu/build-cache.json\");\n\n// Project paths (user content)\nexport const DOCS_DIR = join(PROJECT_ROOT, \"docs\");\nexport const DOCS_ASSETS_DIR = join(PROJECT_ROOT, \"docs/assets\");\nexport const DOCU_CONFIG_PATH = join(PROJECT_ROOT, \"docu.json\");\n\n// Config singleton\nlet _config: DocuConfig | null = null;\n\n/** Clean stale client bundles from a previous build. */\nexport async function cleanOldBundles(preserve?: Set<string>) {\n try {\n const files = await readdir(ASSETS_DIR);\n for (const file of files) {\n if (preserve?.has(file)) continue;\n if (file.startsWith(\"client.\") || file.startsWith(\"client-\")) {\n await unlink(join(ASSETS_DIR, file));\n }\n }\n } catch (err) {\n if ((err as NodeJS.ErrnoException).code !== \"ENOENT\") {\n console.error(\"Failed to clean old bundles:\", (err as Error).message);\n }\n }\n try {\n await rm(join(ASSETS_DIR, \"chunks\"), { recursive: true, force: true });\n } catch (err) {\n // chunks dir may not exist, or permission error — log to avoid silent failure\n if ((err as NodeJS.ErrnoException).code !== \"ENOENT\") {\n console.warn(\"[flame] Failed to clean chunks dir:\", (err as Error).message);\n }\n }\n}\n\nexport function loadDocuConfig(): DocuConfig {\n if (_config) return _config;\n if (!existsSync(DOCU_CONFIG_PATH)) {\n throw new Error(`docu.json not found at ${DOCU_CONFIG_PATH}`);\n }\n _config = JSON.parse(readFileSync(DOCU_CONFIG_PATH, \"utf-8\"));\n return _config!;\n}\n"],"mappings":";;;;;;;;AAWA,IAAa,iBAAiB,QAAQ,YAAY,SAAS,OAAO;AAClE,IAAa,eAAe,QAAQ,IAAI;AAGf,KAAK,gBAAgB,aAAa;AAC3D,IAAa,aAAa,KAAK,gBAAgB,cAAc;AAC7D,IAAM,UAAU,KAAK,gBAAgB,YAAY;AACjD,IAAM,SAAS,KAAK,gBAAgB,WAAW;AAC/C,IAAa,UAAU,WAAW,OAAO,IAAI,UAAU;AAGvD,IAAa,WAAW,KAAK,cAAc,YAAY;AACvD,IAAa,aAAa,KAAK,UAAU,QAAQ;AACjD,IAAa,aAAa,KAAK,cAAc,wBAAwB;AAGrE,IAAa,WAAW,KAAK,cAAc,MAAM;AACjD,IAAa,kBAAkB,KAAK,cAAc,aAAa;AAC/D,IAAa,mBAAmB,KAAK,cAAc,WAAW;AAG9D,IAAI,UAA6B;;AAGjC,eAAsB,gBAAgB,UAAwB;CAC5D,IAAI;EACF,MAAM,QAAQ,MAAM,QAAQ,UAAU;EACtC,KAAK,MAAM,QAAQ,OAAO;GACxB,IAAI,UAAU,IAAI,IAAI,GAAG;GACzB,IAAI,KAAK,WAAW,SAAS,KAAK,KAAK,WAAW,SAAS,GACzD,MAAM,OAAO,KAAK,YAAY,IAAI,CAAC;EAEvC;CACF,SAAS,KAAK;EACZ,IAAK,IAA8B,SAAS,UAC1C,QAAQ,MAAM,gCAAiC,IAAc,OAAO;CAExE;CACA,IAAI;EACF,MAAM,GAAG,KAAK,YAAY,QAAQ,GAAG;GAAE,WAAW;GAAM,OAAO;EAAK,CAAC;CACvE,SAAS,KAAK;EAEZ,IAAK,IAA8B,SAAS,UAC1C,QAAQ,KAAK,uCAAwC,IAAc,OAAO;CAE9E;AACF;AAEA,SAAgB,iBAA6B;CAC3C,IAAI,SAAS,OAAO;CACpB,IAAI,CAAC,WAAW,gBAAgB,GAC9B,MAAM,IAAI,MAAM,0BAA0B,kBAAkB;CAE9D,UAAU,KAAK,MAAM,aAAa,kBAAkB,OAAO,CAAC;CAC5D,OAAO;AACT"}