bini-router 1.0.13 → 1.0.15

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/index.cjs CHANGED
@@ -596,7 +596,7 @@ async function handleApiRequest(req, res, next, apiDir, enableCors, getCache, se
596
596
  }
597
597
  let cache = getCache();
598
598
  if (!cache) {
599
- cache = { routes: scanApiRoutes(apiDir) };
599
+ cache = { routes: scanApiRoutes(apiDir, "/api") };
600
600
  setCache(cache);
601
601
  }
602
602
  const host = req.headers.host ?? "localhost";
@@ -923,6 +923,9 @@ function biniroute(options = {}) {
923
923
  order: "pre",
924
924
  handler(html) {
925
925
  const meta = parseAppMetadata(getAppDir());
926
+ if (!meta.title && !meta.description && !meta.canonical && !meta.manifest && !meta.openGraph?.title && !meta.icons?.icon?.length) {
927
+ return html;
928
+ }
926
929
  const title = meta.title ?? "Bini App";
927
930
  const vp = meta.viewport ?? "width=device-width, initial-scale=1.0";
928
931
  const lines = [];
@@ -964,7 +967,7 @@ function biniroute(options = {}) {
964
967
  if (meta.twitter.image) lines.push(`<meta name="twitter:image" content="${meta.twitter.image}" />`);
965
968
  }
966
969
  const injected = lines.map((l) => ` ${l}`).join("\n");
967
- return html.replace(/<meta\s+charset[^>]*\/?>/gi, "").replace(/<meta\s+name="viewport"[^>]*\/?>/gi, "").replace(/<meta\s+name="description"[^>]*\/?>/gi, "").replace(/<meta\s+name="theme-color"[^>]*\/?>/gi, "").replace(/<meta\s+name="robots"[^>]*\/?>/gi, "").replace(/<meta\s+name="keywords"[^>]*\/?>/gi, "").replace(/<meta\s+name="author"[^>]*\/?>/gi, "").replace(/<meta\s+property="og:[^"]*"[^>]*\/?>/gi, "").replace(/<meta\s+name="twitter:[^"]*"[^>]*\/?>/gi, "").replace(/<link\s+rel="canonical"[^>]*\/?>/gi, "").replace(/<link\s+rel="manifest"[^>]*\/?>/gi, "").replace(/<link\s+rel="icon"[^>]*\/?>/gi, "").replace(/<link\s+rel="shortcut icon"[^>]*\/?>/gi, "").replace(/<link\s+rel="apple-touch-icon"[^>]*\/?>/gi, "").replace(/<title>.*?<\/title>/si, "").replace("</head>", `${injected}
970
+ return html.replace("</head>", `${injected}
968
971
  </head>`);
969
972
  }
970
973
  }
@@ -1 +1 @@
1
- {"version":3,"sources":["../src/index.ts"],"sourcesContent":["import fs from 'fs';\r\nimport path from 'path';\r\nimport type { Plugin, ViteDevServer } from 'vite';\r\n\r\n// ─── Constants ────────────────────────────────────────────────────────────────\r\n\r\nconst PAGE_FILES = ['page.tsx', 'page.jsx', 'page.ts', 'page.js'] as const;\r\nconst LAYOUT_FILES = ['layout.tsx', 'layout.jsx', 'layout.ts', 'layout.js'] as const;\r\nconst SUPPORTED_EXTS = ['.tsx', '.jsx', '.ts', '.js'] as const;\r\nconst NOT_FOUND_FILES = SUPPORTED_EXTS.map(e => `not-found${e}`);\r\nconst SPECIAL_BASES = new Set(['page', 'layout', 'not-found', 'loading', 'error']);\r\nconst API_EXTS = ['.ts', '.js'] as const;\r\nconst DEBOUNCE_MS = 60;\r\nconst EVENT_DEDUP_MS = 500;\r\nconst EVENT_TTL_MS = 2000;\r\n\r\n// ─── Metadata Types ───────────────────────────────────────────────────────────\r\n\r\nexport interface IconEntry {\r\n url : string;\r\n type ?: string;\r\n sizes?: string;\r\n}\r\n\r\nexport interface MetaTags {\r\n title ?: string;\r\n description ?: string;\r\n viewport ?: string;\r\n themeColor ?: string;\r\n keywords ?: string;\r\n author ?: string;\r\n charset ?: string;\r\n robots ?: string;\r\n canonical ?: string;\r\n manifest ?: string;\r\n openGraph ?: Partial<OGMeta>;\r\n twitter ?: Partial<TwitterMeta>;\r\n icons ?: {\r\n icon ?: IconEntry[];\r\n shortcut ?: IconEntry[];\r\n apple ?: IconEntry[];\r\n };\r\n}\r\n\r\ninterface OGMeta {\r\n title : string;\r\n description : string;\r\n url : string;\r\n image : string;\r\n type : string;\r\n}\r\n\r\ninterface TwitterMeta {\r\n card : string;\r\n title : string;\r\n description : string;\r\n creator : string;\r\n image : string;\r\n}\r\n\r\n// ─── Types ────────────────────────────────────────────────────────────────────\r\n\r\ninterface RouteNode {\r\n routePath : string;\r\n filePath : string;\r\n layouts : string[];\r\n dynamic : boolean;\r\n}\r\n\r\ninterface LayoutChainGroup {\r\n layouts : string[];\r\n routes : RouteNode[];\r\n}\r\n\r\ninterface ApiRoute {\r\n routePath : string;\r\n filePath : string;\r\n}\r\n\r\nexport interface BiniPluginOptions {\r\n /** Directory for page files. Default: src/app */\r\n appDir?: string;\r\n /** Directory for API routes. Default: src/app/api */\r\n apiDir?: string;\r\n /** Enable CORS headers in the dev-server API middleware. Default: true */\r\n cors?: boolean;\r\n /**\r\n * Target deployment platform. bini-router generates a production entry\r\n * file on every build — users only write code in src/app/api/.\r\n *\r\n * 'vercel' → api/index.ts (no extra install needed)\r\n * 'node' → server/index.ts (install: @hono/node-server)\r\n * 'cloudflare' → worker.ts (install: wrangler)\r\n *\r\n * Default: undefined (no entry generated)\r\n */\r\n platform?: 'vercel' | 'node' | 'cloudflare';\r\n}\r\n\r\n// ─── Utilities ────────────────────────────────────────────────────────────────\r\n\r\n// Normalize to forward slashes for reliable cross-platform path comparisons.\r\nfunction norm(p: string): string {\r\n return p.replace(/\\\\/g, '/');\r\n}\r\n\r\nfunction isInDir(file: string, dir: string): boolean {\r\n const nFile = norm(file);\r\n const nDir = norm(dir).replace(/\\/$/, '');\r\n return nFile.startsWith(nDir + '/') || nFile === nDir;\r\n}\r\n\r\nfunction readTsconfigAliases(): Record<string, string> {\r\n const aliases: Record<string, string> = {};\r\n try {\r\n const tsconfigPath = path.join(process.cwd(), 'tsconfig.json');\r\n if (!fs.existsSync(tsconfigPath)) return aliases;\r\n const raw = fs.readFileSync(tsconfigPath, 'utf8')\r\n .replace(/\\/\\/.*$/gm, '')\r\n .replace(/\\/\\*[\\s\\S]*?\\*\\//g, '');\r\n const tsconfig = JSON.parse(raw);\r\n const paths = tsconfig?.compilerOptions?.paths ?? {};\r\n const baseUrl = tsconfig?.compilerOptions?.baseUrl ?? '.';\r\n for (const [alias, targets] of Object.entries(paths) as [string, string[]][]) {\r\n const cleanAlias = alias.replace(/\\/\\*$/, '');\r\n const cleanTarget = (targets[0] ?? '').replace(/\\/\\*$/, '');\r\n aliases[cleanAlias] = path.resolve(process.cwd(), baseUrl, cleanTarget);\r\n }\r\n } catch { /* tsconfig unreadable — fall back to relative paths */ }\r\n return aliases;\r\n}\r\n\r\nfunction toImportPath(filePath: string, aliases: Record<string, string>): string {\r\n for (const [alias, target] of Object.entries(aliases)) {\r\n if (norm(filePath).startsWith(norm(target) + '/')) {\r\n const rest = norm(filePath).slice(norm(target).length + 1).replace(/\\.(tsx|ts|jsx|js)$/, '');\r\n return `${alias}/${rest}`;\r\n }\r\n }\r\n return './' + norm(path.relative(path.join(process.cwd(), 'src'), filePath))\r\n .replace(/\\.(tsx|ts|jsx|js)$/, '');\r\n}\r\n\r\nfunction hasDefaultExport(filePath: string): boolean {\r\n try { return fs.readFileSync(filePath, 'utf8').includes('export default'); }\r\n catch { return false; }\r\n}\r\n\r\nfunction isHtmlShellLayout(filePath: string): boolean {\r\n try { return /<html[\\s>]/i.test(fs.readFileSync(filePath, 'utf8')); }\r\n catch { return false; }\r\n}\r\n\r\nfunction isUsableLayout(filePath: string): boolean {\r\n return hasDefaultExport(filePath) && !isHtmlShellLayout(filePath);\r\n}\r\n\r\nfunction findFile(dir: string, candidates: readonly string[]): string | null {\r\n return candidates.find(f => fs.existsSync(path.join(dir, f))) ?? null;\r\n}\r\n\r\nfunction getAppFile(): string {\r\n const ts = path.join(process.cwd(), 'src/App.tsx');\r\n return fs.existsSync(ts) ? ts : path.join(process.cwd(), 'src/App.jsx');\r\n}\r\n\r\n// ─── Layout Resolution ────────────────────────────────────────────────────────\r\n\r\nfunction resolveLayoutChain(pageDir: string, appDir: string): string[] {\r\n const chain: string[] = [];\r\n let current = pageDir;\r\n while (true) {\r\n const layout = findFile(current, LAYOUT_FILES);\r\n if (layout) chain.unshift(path.join(current, layout));\r\n if (path.resolve(current) === path.resolve(appDir)) break;\r\n const parent = path.dirname(current);\r\n if (parent === current) break;\r\n current = parent;\r\n }\r\n return chain;\r\n}\r\n\r\n// ─── Route Scanner ────────────────────────────────────────────────────────────\r\n\r\nfunction scanRoutes(dir: string, appDir: string, baseRoute = ''): RouteNode[] {\r\n const routes: RouteNode[] = [];\r\n if (!fs.existsSync(dir)) return routes;\r\n\r\n let entries: fs.Dirent[];\r\n try { entries = fs.readdirSync(dir, { withFileTypes: true }); }\r\n catch { return routes; }\r\n\r\n // File-based: about.tsx → /about\r\n for (const entry of entries) {\r\n if (!entry.isFile() || entry.name.startsWith('.') || entry.name.startsWith('_')) continue;\r\n const ext = path.extname(entry.name);\r\n const base = path.basename(entry.name, ext);\r\n if (!(SUPPORTED_EXTS as readonly string[]).includes(ext)) continue;\r\n if (SPECIAL_BASES.has(base)) continue;\r\n routes.push({\r\n routePath : `${baseRoute}/${base}`,\r\n filePath : path.join(dir, entry.name),\r\n layouts : resolveLayoutChain(dir, appDir),\r\n dynamic : false,\r\n });\r\n }\r\n\r\n // Directory-based: [id]/page.tsx → /:id\r\n for (const entry of entries) {\r\n if (!entry.isDirectory()) continue;\r\n if (entry.name === 'node_modules' || entry.name.startsWith('.') || entry.name === 'api') continue;\r\n\r\n const fullPath = path.join(dir, entry.name);\r\n const isDynamic = entry.name.startsWith('[') && entry.name.endsWith(']');\r\n const segment = isDynamic ? `:${entry.name.slice(1, -1)}` : entry.name;\r\n const routePath = `${baseRoute}/${segment}`;\r\n\r\n const pageFile = findFile(fullPath, PAGE_FILES);\r\n if (pageFile) {\r\n routes.push({\r\n routePath,\r\n filePath : path.join(fullPath, pageFile),\r\n layouts : resolveLayoutChain(fullPath, appDir),\r\n dynamic : isDynamic,\r\n });\r\n }\r\n routes.push(...scanRoutes(fullPath, appDir, routePath));\r\n }\r\n\r\n return routes;\r\n}\r\n\r\n// Detect duplicate routePaths and keep the first encountered (file-based wins\r\n// over directory-based since we unshift the root page before sorting).\r\nfunction deduplicateRoutes(routes: RouteNode[]): RouteNode[] {\r\n const seen = new Set<string>();\r\n return routes.filter(r => {\r\n if (seen.has(r.routePath)) return false;\r\n seen.add(r.routePath);\r\n return true;\r\n });\r\n}\r\n\r\n// ─── Per-layout title extractor ──────────────────────────────────────────────\r\n\r\nfunction parseLayoutTitle(layoutFile: string): string | null {\r\n let src = '';\r\n try { src = fs.readFileSync(layoutFile, 'utf8'); }\r\n catch { return null; }\r\n\r\n const startIdx = src.indexOf('export const metadata');\r\n if (startIdx === -1) return null;\r\n const braceStart = src.indexOf('{', startIdx);\r\n if (braceStart === -1) return null;\r\n\r\n let depth = 0, end = braceStart;\r\n for (let i = braceStart; i < src.length; i++) {\r\n if (src[i] === '{') depth++;\r\n else if (src[i] === '}') { depth--; if (depth === 0) { end = i; break; } }\r\n }\r\n const block = src.slice(braceStart, end + 1);\r\n const match = /['\"]?title['\"]?\\s*:\\s*['\"`]([^'\"`]+)['\"`]/.exec(block);\r\n return match ? match[1] : null;\r\n}\r\n\r\n// ─── Route Tree Renderer ──────────────────────────────────────────────────────\r\n\r\nfunction renderChain(\r\n layouts : string[],\r\n routesInChain : RouteNode[],\r\n layoutNames : Map<string, string>,\r\n pageNames : Map<string, string>,\r\n layoutTitles : Map<string, string>,\r\n indent : number,\r\n): string {\r\n const pad = ' '.repeat(indent);\r\n if (layouts.length === 0) {\r\n return routesInChain.map(r =>\r\n `${pad}<Route path=\"${r.routePath}\" element={<Suspense fallback={<Spinner />}><ErrorBoundary><${pageNames.get(r.filePath)} /></ErrorBoundary></Suspense>} />`\r\n ).join('\\n');\r\n }\r\n const [head, ...tail] = layouts;\r\n const title = layoutTitles.get(head);\r\n // TitleSetter is rendered OUTSIDE ErrorBoundary so a layout crash doesn't\r\n // prevent the title from updating.\r\n const titleSetter = title ? `<TitleSetter title=${JSON.stringify(title)} />` : '';\r\n const inner = renderChain(tail, routesInChain, layoutNames, pageNames, layoutTitles, indent + 2);\r\n const name = layoutNames.get(head);\r\n return [\r\n `${pad}<Route element={<>${titleSetter}<Suspense fallback={<Spinner />}><ErrorBoundary><${name}><Outlet /></${name}></ErrorBoundary></Suspense></>}>`,\r\n inner,\r\n `${pad}</Route>`,\r\n ].join('\\n');\r\n}\r\n\r\n// ─── App Generator ────────────────────────────────────────────────────────────\r\n\r\nfunction generateApp(appDir: string): string {\r\n const aliases = readTsconfigAliases();\r\n const routes = scanRoutes(appDir, appDir);\r\n\r\n const rootPage = findFile(appDir, PAGE_FILES);\r\n if (rootPage) {\r\n routes.unshift({\r\n routePath : '/',\r\n filePath : path.join(appDir, rootPage),\r\n layouts : resolveLayoutChain(appDir, appDir),\r\n dynamic : false,\r\n });\r\n }\r\n\r\n // Strip html-shell layouts and layouts with no default export.\r\n const routesFiltered = routes.map(r => ({\r\n ...r,\r\n layouts: r.layouts.filter(l => isUsableLayout(l)),\r\n }));\r\n\r\n // Only include routes whose page file has a default export.\r\n const validRoutes = deduplicateRoutes(\r\n routesFiltered.filter(r => hasDefaultExport(r.filePath))\r\n );\r\n\r\n validRoutes.sort((a, b) => {\r\n if (a.dynamic !== b.dynamic) return a.dynamic ? 1 : -1;\r\n return a.routePath.length - b.routePath.length;\r\n });\r\n\r\n const notFoundFile = NOT_FOUND_FILES.find(f => fs.existsSync(path.join(appDir, f)));\r\n const notFound = notFoundFile && hasDefaultExport(path.join(appDir, notFoundFile))\r\n ? notFoundFile\r\n : undefined;\r\n\r\n const allLayouts = new Set<string>();\r\n for (const r of validRoutes) r.layouts.forEach(l => {\r\n if (isUsableLayout(l)) allLayouts.add(l);\r\n });\r\n\r\n const layoutNames = new Map<string, string>();\r\n const pageNames = new Map<string, string>();\r\n const layoutTitles = new Map<string, string>();\r\n let li = 0, pi = 0;\r\n for (const l of allLayouts) {\r\n layoutNames.set(l, `Layout${li++}`);\r\n const title = parseLayoutTitle(l);\r\n if (title) layoutTitles.set(l, title);\r\n }\r\n for (const r of validRoutes) {\r\n if (!pageNames.has(r.filePath)) pageNames.set(r.filePath, `Page${pi++}`);\r\n }\r\n\r\n const lazyImports: string[] = [];\r\n for (const [fp, name] of layoutNames)\r\n lazyImports.push(`const ${name} = React.lazy(() => import('${toImportPath(fp, aliases)}'));`);\r\n if (notFound)\r\n lazyImports.push(`const NotFound = React.lazy(() => import('${toImportPath(path.join(appDir, notFound), aliases)}'));`);\r\n const emittedPages = new Set<string>();\r\n for (const r of validRoutes) {\r\n if (emittedPages.has(r.filePath)) continue;\r\n emittedPages.add(r.filePath);\r\n const name = pageNames.get(r.filePath);\r\n if (!name) continue;\r\n lazyImports.push(`const ${name} = React.lazy(() => import('${toImportPath(r.filePath, aliases)}'));`);\r\n }\r\n\r\n const chainMap = new Map<string, LayoutChainGroup>();\r\n for (const r of validRoutes) {\r\n const key = r.layouts.join('|');\r\n if (!chainMap.has(key)) chainMap.set(key, { layouts: r.layouts, routes: [] });\r\n chainMap.get(key)!.routes.push(r);\r\n }\r\n\r\n const routeLines: string[] = [];\r\n for (const [, { layouts, routes: cr }] of chainMap)\r\n routeLines.push(renderChain(layouts, cr, layoutNames, pageNames, layoutTitles, 8));\r\n\r\n const catchAll = notFound\r\n ? ` <Route path=\"*\" element={<Suspense fallback={<Spinner />}><NotFound /></Suspense>} />`\r\n : ` <Route path=\"*\" element={<Default404 />} />`;\r\n\r\n return `// ⚠️ Auto-generated by bini-router — do not edit.\r\nimport React, { Suspense } from 'react';\r\nimport { BrowserRouter, Routes, Route, Outlet } from 'react-router-dom';\r\nimport './app/globals.css';\r\n\r\n${lazyImports.join('\\n')}\r\n\r\n// ─── Error Boundary ───────────────────────────────────────────────────────────\r\nclass ErrorBoundary extends React.Component<\r\n { children: React.ReactNode },\r\n { error: Error | null }\r\n> {\r\n constructor(props: { children: React.ReactNode }) {\r\n super(props);\r\n this.state = { error: null };\r\n }\r\n static getDerivedStateFromError(error: Error) { return { error }; }\r\n override render() {\r\n if (this.state.error) return (\r\n <div style={{ minHeight: '100vh', display: 'flex', alignItems: 'center', justifyContent: 'center', fontFamily: 'system-ui,sans-serif', padding: '2rem' }}>\r\n <div style={{ maxWidth: 480, width: '100%', textAlign: 'center' }}>\r\n <h2 style={{ color: '#e74c3c', marginBottom: '1rem' }}>Something went wrong</h2>\r\n <pre style={{ background: '#fef2f2', padding: '1rem', borderRadius: '0.5rem', textAlign: 'left', fontSize: '0.8rem', color: '#e74c3c', overflow: 'auto' }}>{this.state.error.toString()}</pre>\r\n <button onClick={() => this.setState({ error: null })} style={{ marginTop: '1rem', padding: '0.5rem 1.5rem', background: '#00CFFF', color: 'white', border: 'none', borderRadius: '0.5rem', cursor: 'pointer', fontWeight: 600 }}>\r\n Try again\r\n </button>\r\n </div>\r\n </div>\r\n );\r\n return this.props.children;\r\n }\r\n}\r\n\r\nfunction Spinner() {\r\n return (\r\n <div style={{ minHeight: '100vh', display: 'flex', alignItems: 'center', justifyContent: 'center' }}>\r\n <div style={{ width: 32, height: 32, border: '3px solid #eee', borderTop: '3px solid #00CFFF', borderRadius: '50%', animation: 'spin 0.8s linear infinite' }} />\r\n <style>{\\`@keyframes spin{to{transform:rotate(360deg)}}\\`}</style>\r\n </div>\r\n );\r\n}\r\n\r\n// Renders nothing — just sets document.title when the layout mounts.\r\n// Placed outside ErrorBoundary so a layout crash doesn't block the title update.\r\nfunction TitleSetter({ title }: { title: string }) {\r\n React.useEffect(() => { document.title = title; }, [title]);\r\n return null;\r\n}\r\n\r\n${notFound ? '' : `function Default404() {\r\n return (\r\n <div style={{ minHeight: '100vh', display: 'flex', alignItems: 'center', justifyContent: 'center', background: 'linear-gradient(135deg,#00CFFF,#0077FF)', color: 'white', fontFamily: 'system-ui,sans-serif' }}>\r\n <div style={{ textAlign: 'center' }}>\r\n <h1 style={{ fontSize: '5rem', fontWeight: 800, margin: 0 }}>404</h1>\r\n <p style={{ fontSize: '1.25rem', margin: '0.5rem 0 2rem' }}>Page not found</p>\r\n <a href=\"/\" style={{ padding: '0.65rem 1.5rem', background: 'white', color: '#00CFFF', textDecoration: 'none', borderRadius: '0.5rem', fontWeight: 600 }}>← Back to Home</a>\r\n </div>\r\n </div>\r\n );\r\n}`}\r\n\r\nexport default function App() {\r\n return (\r\n <BrowserRouter>\r\n <Routes>\r\n${routeLines.join('\\n')}\r\n${catchAll}\r\n </Routes>\r\n </BrowserRouter>\r\n );\r\n}\r\n`;\r\n}\r\n\r\n// ─── Metadata Parser ──────────────────────────────────────────────────────────\r\n\r\nfunction parseAppMetadata(appDir: string): MetaTags {\r\n const layout = findFile(appDir, LAYOUT_FILES);\r\n if (!layout) return {};\r\n let src = '';\r\n try { src = fs.readFileSync(path.join(appDir, layout), 'utf8'); }\r\n catch { return {}; }\r\n\r\n const startIdx = src.indexOf('export const metadata');\r\n if (startIdx === -1) return {};\r\n const braceStart = src.indexOf('{', startIdx);\r\n if (braceStart === -1) return {};\r\n\r\n let depth = 0, end = braceStart;\r\n for (let i = braceStart; i < src.length; i++) {\r\n if (src[i] === '{') depth++;\r\n else if (src[i] === '}') { depth--; if (depth === 0) { end = i; break; } }\r\n }\r\n const block = src.slice(braceStart, end + 1);\r\n\r\n function extractBlock(source: string, key: string): string | undefined {\r\n const re = new RegExp(`['\"]?${key}['\"]?\\\\s*:\\\\s*\\\\{`);\r\n const match = re.exec(source);\r\n if (!match) return undefined;\r\n let d = 0, i = match.index + match[0].length - 1;\r\n const start = i;\r\n for (; i < source.length; i++) {\r\n if (source[i] === '{') d++;\r\n else if (source[i] === '}') { d--; if (d === 0) return source.slice(start, i + 1); }\r\n }\r\n return undefined;\r\n }\r\n\r\n function extractArray(source: string, key: string): string | undefined {\r\n const re = new RegExp(`['\"]?${key}['\"]?\\\\s*:\\\\s*\\\\[`);\r\n const match = re.exec(source);\r\n if (!match) return undefined;\r\n let d = 0, i = match.index + match[0].length - 1;\r\n const start = i;\r\n for (; i < source.length; i++) {\r\n if (source[i] === '[') d++;\r\n else if (source[i] === ']') { d--; if (d === 0) return source.slice(start, i + 1); }\r\n }\r\n return undefined;\r\n }\r\n\r\n function str(source: string, key: string): string | undefined {\r\n return source.match(\r\n new RegExp(`['\"]?${key}['\"]?\\\\s*:\\\\s*['\"\\`]([^'\"\\`\\n]+)['\"\\`]`)\r\n )?.[1];\r\n }\r\n\r\n function firstArrayStr(source: string, key: string): string | undefined {\r\n const arr = extractArray(source, key);\r\n if (!arr) return undefined;\r\n return arr.match(/url\\s*:\\s*['\"]([^'\"]+)['\"]/)?.[1]\r\n ?? arr.match(/['\"]([^'\"]+)['\"]/)?.[1];\r\n }\r\n\r\n function allArrayStrs(source: string, key: string): string[] {\r\n const arr = extractArray(source, key);\r\n if (!arr) return [];\r\n return [...arr.matchAll(/['\"]([^'\"]+)['\"]/g)].map(m => m[1]);\r\n }\r\n\r\n const meta: MetaTags = {};\r\n\r\n if (str(block, 'title')) meta.title = str(block, 'title');\r\n if (str(block, 'description')) meta.description = str(block, 'description');\r\n if (str(block, 'viewport')) meta.viewport = str(block, 'viewport');\r\n if (str(block, 'themeColor')) meta.themeColor = str(block, 'themeColor');\r\n if (str(block, 'charset')) meta.charset = str(block, 'charset');\r\n if (str(block, 'robots')) meta.robots = str(block, 'robots');\r\n if (str(block, 'canonical')) meta.canonical = str(block, 'canonical');\r\n if (str(block, 'manifest')) meta.manifest = str(block, 'manifest');\r\n\r\n const kwStr = str(block, 'keywords');\r\n if (kwStr) {\r\n meta.keywords = kwStr;\r\n } else {\r\n const kwArr = allArrayStrs(block, 'keywords');\r\n if (kwArr.length) meta.keywords = kwArr.join(', ');\r\n }\r\n\r\n const authorStr = str(block, 'author');\r\n if (authorStr) {\r\n meta.author = authorStr;\r\n } else {\r\n const authorsArr = extractArray(block, 'authors');\r\n if (authorsArr) {\r\n const name = authorsArr.match(/name\\s*:\\s*['\"]([^'\"]+)['\"]/)?.[1];\r\n if (name) meta.author = name;\r\n }\r\n }\r\n\r\n if (!meta.canonical) {\r\n const base = block.match(/metadataBase\\s*:\\s*new\\s+URL\\s*\\(\\s*['\"]([^'\"]+)['\"]/)?.[1];\r\n if (base) meta.canonical = base;\r\n }\r\n\r\n const ogBlock = extractBlock(block, 'openGraph');\r\n if (ogBlock) {\r\n meta.openGraph = {\r\n title : str(ogBlock, 'title'),\r\n description : str(ogBlock, 'description'),\r\n url : str(ogBlock, 'url'),\r\n type : str(ogBlock, 'type'),\r\n image : firstArrayStr(ogBlock, 'images') ?? str(ogBlock, 'image'),\r\n };\r\n }\r\n\r\n const twBlock = extractBlock(block, 'twitter');\r\n if (twBlock) {\r\n meta.twitter = {\r\n card : str(twBlock, 'card'),\r\n title : str(twBlock, 'title'),\r\n description : str(twBlock, 'description'),\r\n creator : str(twBlock, 'creator'),\r\n image : firstArrayStr(twBlock, 'images') ?? str(twBlock, 'image'),\r\n };\r\n }\r\n\r\n const iconsBlock = extractBlock(block, 'icons');\r\n if (iconsBlock) {\r\n meta.icons = {\r\n icon : collectIconEntries(iconsBlock, 'icon'),\r\n shortcut: collectIconEntries(iconsBlock, 'shortcut'),\r\n apple : collectIconEntries(iconsBlock, 'apple'),\r\n };\r\n }\r\n\r\n return meta;\r\n}\r\n\r\nfunction collectIconEntries(source: string, key: string): IconEntry[] {\r\n const arr = extractArrayRaw(source, key);\r\n if (!arr) return [];\r\n const entries: IconEntry[] = [];\r\n const objRe = /\\{([^}]+)\\}/g;\r\n let m: RegExpExecArray | null;\r\n while ((m = objRe.exec(arr)) !== null) {\r\n const obj = m[1];\r\n const url = obj.match(/url\\s*:\\s*['\"]([^'\"]+)['\"]/)?.[1];\r\n if (!url) continue;\r\n entries.push({\r\n url,\r\n type : obj.match(/type\\s*:\\s*['\"]([^'\"]+)['\"]/)?.[1],\r\n sizes: obj.match(/sizes\\s*:\\s*['\"]([^'\"]+)['\"]/)?.[1],\r\n });\r\n }\r\n if (!entries.length) {\r\n return [...arr.matchAll(/['\"]([^'\"]+)['\"]/g)].map(x => ({ url: x[1] }));\r\n }\r\n return entries;\r\n}\r\n\r\nfunction extractArrayRaw(source: string, key: string): string | undefined {\r\n const re = new RegExp(`['\"]?${key}['\"]?\\\\s*:\\\\s*\\\\[`);\r\n const match = re.exec(source);\r\n if (!match) return undefined;\r\n let d = 0, i = match.index + match[0].length - 1;\r\n const start = i;\r\n for (; i < source.length; i++) {\r\n if (source[i] === '[') d++;\r\n else if (source[i] === ']') { d--; if (d === 0) return source.slice(start, i + 1); }\r\n }\r\n return undefined;\r\n}\r\n\r\n// ─── API Route Scanner ────────────────────────────────────────────────────────\r\n\r\nfunction scanApiRoutes(dir: string, baseRoute = ''): ApiRoute[] {\r\n const routes: ApiRoute[] = [];\r\n if (!fs.existsSync(dir)) return routes;\r\n\r\n let entries: fs.Dirent[];\r\n try { entries = fs.readdirSync(dir, { withFileTypes: true }); }\r\n catch { return routes; }\r\n\r\n for (const entry of entries) {\r\n if (entry.name.startsWith('_') || entry.name.startsWith('.')) continue;\r\n const fullPath = path.join(dir, entry.name);\r\n\r\n if (entry.isDirectory()) {\r\n const isCatchAll = entry.name.startsWith('[...') && entry.name.endsWith(']');\r\n const isDynamic = entry.name.startsWith('[') && entry.name.endsWith(']');\r\n const segment = isCatchAll ? '*' : isDynamic ? `:${entry.name.slice(1, -1)}` : entry.name;\r\n routes.push(...scanApiRoutes(fullPath, `${baseRoute}/${segment}`));\r\n continue;\r\n }\r\n\r\n const ext = path.extname(entry.name);\r\n const base = path.basename(entry.name, ext);\r\n if (!(API_EXTS as readonly string[]).includes(ext)) continue;\r\n\r\n const isCatchAll = base.startsWith('[...') && base.endsWith(']');\r\n const isDynamic = base.startsWith('[') && base.endsWith(']');\r\n const routePath = isCatchAll\r\n ? `${baseRoute}/*`\r\n : base === 'index'\r\n ? baseRoute || '/'\r\n : isDynamic\r\n ? `${baseRoute}/:${base.slice(1, -1)}`\r\n : `${baseRoute}/${base}`;\r\n\r\n routes.push({ routePath, filePath: fullPath });\r\n }\r\n\r\n return routes;\r\n}\r\n\r\n// ─── Hono dev/preview server ──────────────────────────────────────────────────\r\n//\r\n// API files in src/app/api/ can export:\r\n// export default new Hono().basePath('/api') ← Hono app (routing handled internally)\r\n// export default async function(req: Request) {...} ← plain function (bini-router matches route)\r\n//\r\n// Module cache: re-imports only when the file's mtime changes, not on every request.\r\n// Route matching: plain functions are matched against their scanned routePath pattern\r\n// before the handler is called — so dynamic params ([id]) are resolved correctly.\r\n\r\n// Matches a URL pathname against a route pattern like /api/users/:id or /api/files/*\r\n// Returns extracted params if matched, or null if not.\r\nfunction matchRoute(pattern: string, pathname: string): Record<string, string> | null {\r\n const patParts = pattern.split('/').filter(Boolean);\r\n const urlParts = pathname.split('/').filter(Boolean);\r\n\r\n // Catch-all: pattern ends with * — match everything after the prefix\r\n const isCatchAll = patParts[patParts.length - 1] === '*';\r\n if (isCatchAll) {\r\n const prefix = patParts.slice(0, -1);\r\n if (urlParts.length < prefix.length) return null;\r\n for (let i = 0; i < prefix.length; i++) {\r\n if (prefix[i].startsWith(':')) continue;\r\n if (prefix[i] !== urlParts[i]) return null;\r\n }\r\n return { '*': urlParts.slice(prefix.length).join('/') };\r\n }\r\n\r\n if (patParts.length !== urlParts.length) return null;\r\n\r\n const params: Record<string, string> = {};\r\n for (let i = 0; i < patParts.length; i++) {\r\n if (patParts[i].startsWith(':')) {\r\n params[patParts[i].slice(1)] = decodeURIComponent(urlParts[i]);\r\n } else if (patParts[i] !== urlParts[i]) {\r\n return null;\r\n }\r\n }\r\n return params;\r\n}\r\n\r\n// Per-file module cache: maps filePath → { mtime, handler }\r\n// Avoids re-importing on every request while still picking up file changes.\r\nconst moduleCache = new Map<string, { mtime: number; handler: unknown }>();\r\n\r\nasync function importHandler(filePath: string): Promise<unknown> {\r\n const { pathToFileURL } = await import('url');\r\n let mtime = 0;\r\n try { mtime = fs.statSync(filePath).mtimeMs; } catch { /* file vanished */ }\r\n\r\n const cached = moduleCache.get(filePath);\r\n if (cached && cached.mtime === mtime) return cached.handler;\r\n\r\n // File changed or not yet cached — re-import with cache-bust\r\n const mod = await import(pathToFileURL(filePath).href + '?t=' + mtime);\r\n const handler = mod.default ?? null;\r\n moduleCache.set(filePath, { mtime, handler });\r\n return handler;\r\n}\r\n\r\nasync function handleApiRequest(\r\n req : any,\r\n res : any,\r\n next : any,\r\n apiDir : string,\r\n enableCors : boolean,\r\n getCache : () => { routes: ApiRoute[] } | null,\r\n setCache : (v: { routes: ApiRoute[] }) => void,\r\n) {\r\n try {\r\n // Handle CORS preflight immediately — no need to hit a handler.\r\n if (enableCors && req.method === 'OPTIONS') {\r\n res.statusCode = 204;\r\n res.setHeader('Access-Control-Allow-Origin', '*');\r\n res.setHeader('Access-Control-Allow-Methods', 'GET,POST,PUT,PATCH,DELETE,OPTIONS');\r\n res.setHeader('Access-Control-Allow-Headers', 'Content-Type,Authorization');\r\n res.setHeader('Access-Control-Max-Age', '86400');\r\n res.end();\r\n return;\r\n }\r\n\r\n let cache = getCache();\r\n if (!cache) {\r\n cache = { routes: scanApiRoutes(apiDir) };\r\n setCache(cache);\r\n }\r\n\r\n const host = req.headers.host ?? 'localhost';\r\n const url = `http://${host}${req.url}`;\r\n const pathname = new URL(url).pathname;\r\n\r\n const chunks: Buffer[] = [];\r\n for await (const chunk of req) chunks.push(chunk as Buffer);\r\n const body = chunks.length > 0 ? Buffer.concat(chunks) : undefined;\r\n\r\n const method = (req.method as string).toUpperCase();\r\n\r\n const webReq = new Request(url, {\r\n method,\r\n headers: req.headers as HeadersInit,\r\n body : !['GET', 'HEAD'].includes(method) && body?.length ? body : undefined,\r\n });\r\n\r\n for (const route of cache.routes) {\r\n const handler = await importHandler(route.filePath);\r\n if (!handler) continue;\r\n\r\n let webRes: Response;\r\n try {\r\n if (typeof (handler as any).fetch === 'function') {\r\n // Hono app — has its own internal router, pass the full request directly.\r\n webRes = await (handler as any).fetch(webReq.clone());\r\n\r\n // Hono returns 404 when no route matched — try next file.\r\n if (webRes.status === 404) continue;\r\n\r\n } else if (typeof handler === 'function') {\r\n // Plain function — match the URL against this file's route pattern first.\r\n // This gives dynamic params ([id] → :id) without the function needing a router.\r\n const params = matchRoute(route.routePath, pathname);\r\n if (params === null) continue; // URL doesn't match this file's pattern\r\n\r\n // Inject matched params into the Request so the handler can read them.\r\n // We attach them as a custom header so no extra dependency is needed.\r\n const existingHeaders: Record<string, string> = {};\r\n webReq.headers.forEach((v, k) => { existingHeaders[k] = v; });\r\n const reqWithParams = new Request(webReq.clone(), {\r\n headers: { ...existingHeaders, 'x-bini-params': JSON.stringify(params) },\r\n });\r\n\r\n webRes = await (handler as (...args: any[]) => Promise<Response>)(reqWithParams);\r\n\r\n } else {\r\n continue;\r\n }\r\n } catch {\r\n continue; // handler threw — not its route, try next\r\n }\r\n\r\n // Build final headers — Response.headers is immutable so copy to plain object first\r\n const finalHeaders: Record<string, string> = {};\r\n webRes.headers.forEach((v, k) => { finalHeaders[k] = v; });\r\n if (enableCors) {\r\n finalHeaders['access-control-allow-origin'] = '*';\r\n finalHeaders['access-control-allow-methods'] = 'GET,POST,PUT,PATCH,DELETE,OPTIONS';\r\n finalHeaders['access-control-allow-headers'] = 'Content-Type,Authorization';\r\n }\r\n\r\n res.statusCode = webRes.status;\r\n for (const [k, v] of Object.entries(finalHeaders)) res.setHeader(k, v);\r\n res.end(Buffer.from(await webRes.arrayBuffer()));\r\n return;\r\n }\r\n\r\n // No handler matched\r\n res.statusCode = 404;\r\n res.setHeader('Content-Type', 'application/json');\r\n res.end(JSON.stringify({ error: `No API handler found for ${req.url}` }));\r\n } catch (e: any) {\r\n next(e);\r\n }\r\n}\r\n\r\n// ─── Production Entry Generator ───────────────────────────────────────────────\r\n//\r\n// Mirrors what SvelteKit/Nuxt adapters do at build time:\r\n// scan src/app/api/, merge all handlers, wrap with the platform adapter.\r\n// User writes only in src/app/api/ — never touches the generated entry file.\r\n//\r\n// Supports both export styles:\r\n// export default new Hono() ← merged via .route()\r\n// export default async function handler(req: Request) {...} ← wrapped in Hono app\r\n\r\nfunction buildProductionEntry(srcApiDir: string, platform: 'vercel' | 'node' | 'cloudflare', enableCors: boolean): void {\r\n if (!fs.existsSync(srcApiDir)) return;\r\n\r\n const routes = scanApiRoutes(srcApiDir);\r\n const cwd = process.cwd();\r\n\r\n const imports : string[] = [];\r\n const mountings: string[] = [];\r\n\r\n for (let i = 0; i < routes.length; i++) {\r\n const route = routes[i];\r\n const rel = norm(path.relative(cwd, route.filePath)).replace(/\\.(ts|tsx)$/, '');\r\n const imp = rel.startsWith('.') ? rel : `./${rel}`;\r\n const name = `_route${i}`;\r\n\r\n // Detect at build time whether this file exports a Hono app or a plain function\r\n // by reading the source — if it imports from 'hono' it's a Hono app, otherwise wrap it.\r\n let src = '';\r\n try { src = fs.readFileSync(route.filePath, 'utf8'); } catch { /* skip */ }\r\n const isHonoApp = src.includes(\"from 'hono'\") || src.includes('from \"hono\"');\r\n\r\n imports.push(`import ${name} from '${imp}';`);\r\n\r\n if (isHonoApp) {\r\n // Hono app: merge directly into root app\r\n mountings.push(`app.route('/', ${name});`);\r\n } else {\r\n // Plain function: wrap in Hono and mount at its route path\r\n mountings.push(`app.all('${route.routePath}', (c) => ${name}(c.req.raw));`);\r\n }\r\n }\r\n\r\n const corsLine = enableCors\r\n ? `app.use('/api/*', cors({ origin: '*', allowMethods: ['GET','POST','PUT','PATCH','DELETE','OPTIONS'], allowHeaders: ['Content-Type','Authorization'] }));`\r\n : null;\r\n\r\n const header = [\r\n `// ⚠️ Auto-generated by bini-router on every build — do not edit.`,\r\n `// Add routes by creating files in src/app/api/ only.`,\r\n ];\r\n\r\n const corsImport = enableCors ? `import { cors } from 'hono/cors';` : null;\r\n\r\n let outFile: string;\r\n let lines : string[];\r\n\r\n const appSetup = [\r\n ``,\r\n `const app = new Hono();`,\r\n ...(corsLine ? [corsLine] : []),\r\n ...mountings,\r\n ];\r\n\r\n if (platform === 'vercel') {\r\n outFile = path.join(cwd, 'api', 'index.ts');\r\n // Vercel runs a Hono app directly as a default export — no handle() wrapper needed.\r\n // Import is from 'hono/vercel' (built into hono, no separate package to install).\r\n lines = [\r\n ...header,\r\n `import { Hono } from 'hono';`,\r\n ...(corsImport ? [corsImport] : []),\r\n ...imports,\r\n ...appSetup,\r\n ``,\r\n `export const runtime = 'edge';`,\r\n `export default app;`,\r\n ];\r\n\r\n } else if (platform === 'cloudflare') {\r\n outFile = path.join(cwd, 'worker.ts');\r\n lines = [\r\n ...header,\r\n `import { Hono } from 'hono';`,\r\n ...(corsImport ? [corsImport] : []),\r\n ...imports,\r\n ...appSetup,\r\n ``,\r\n `export default app;`,\r\n ];\r\n\r\n } else {\r\n // node\r\n outFile = path.join(cwd, 'server', 'index.ts');\r\n lines = [\r\n ...header,\r\n `import { Hono } from 'hono';`,\r\n `import { serve } from '@hono/node-server';`,\r\n `import { serveStatic } from '@hono/node-server/serve-static';`,\r\n ...(corsImport ? [corsImport] : []),\r\n ...imports,\r\n ...appSetup,\r\n `app.use('/*', serveStatic({ root: './dist' }));`,\r\n `app.use('/*', serveStatic({ path: './dist/index.html' }));`,\r\n ``,\r\n `serve({ fetch: app.fetch, port: Number(process.env.PORT ?? 3000) }, (i) => {`,\r\n ` console.log(\\`Server running on http://localhost:\\${i.port}\\`);`,\r\n `});`,\r\n ];\r\n }\r\n\r\n fs.mkdirSync(path.dirname(outFile), { recursive: true });\r\n fs.writeFileSync(outFile, lines.join('\\n') + '\\n', 'utf8');\r\n console.log(`[bini-router] ✓ Generated ${norm(path.relative(cwd, outFile))}`);\r\n}\r\n\r\n// ─── Plugin ───────────────────────────────────────────────────────────────────\r\n\r\nexport function biniroute(options: BiniPluginOptions = {}): Plugin {\r\n const { cors: enableCors = true, platform } = options;\r\n\r\n const getAppDir = () => path.join(process.cwd(), options.appDir ?? 'src/app');\r\n const getApiDir = () => path.join(process.cwd(), options.apiDir ?? 'src/app/api');\r\n\r\n // ── Per-instance state (fixes shared-state bug) ───────────────────────────\r\n let debounceTimer : ReturnType<typeof setTimeout> | null = null;\r\n let lastGeneratedCode = '';\r\n let honoCache : { routes: ApiRoute[] } | null = null;\r\n const eventLog = new Map<string, number>();\r\n\r\n function shouldProcess(file: string, event: string): boolean {\r\n const key = `${file}:${event}`;\r\n const now = Date.now();\r\n if (now - (eventLog.get(key) ?? 0) < EVENT_DEDUP_MS) return false;\r\n eventLog.set(key, now);\r\n for (const [k, v] of eventLog) if (now - v > EVENT_TTL_MS) eventLog.delete(k);\r\n return true;\r\n }\r\n\r\n // Only trigger regen for page/layout files, not utils/hooks.\r\n // Uses forward-slash comparison to work correctly on Windows.\r\n function isPageFile(f: string): boolean {\r\n const nf = norm(f);\r\n const base = path.basename(f, path.extname(f));\r\n const ext = path.extname(f);\r\n if (!(SUPPORTED_EXTS as readonly string[]).includes(ext)) return false;\r\n if (!isInDir(nf, norm(getAppDir()))) return false;\r\n if (isInDir(nf, norm(getApiDir()))) return false;\r\n if (base.startsWith('_')) return false;\r\n return true;\r\n }\r\n\r\n function isApiFile(f: string): boolean {\r\n const nf = norm(f);\r\n return isInDir(nf, norm(getApiDir())) &&\r\n (API_EXTS as readonly string[]).includes(path.extname(f));\r\n }\r\n\r\n // Single helper used by both config/buildStart and scheduleRegen.\r\n function applyApp(): string | null {\r\n const dir = getAppDir();\r\n if (!fs.existsSync(dir)) return null;\r\n const code = generateApp(dir);\r\n if (code === lastGeneratedCode) return null;\r\n fs.writeFileSync(getAppFile(), code, 'utf8');\r\n lastGeneratedCode = code;\r\n return code;\r\n }\r\n\r\n function scheduleRegen(server: ViteDevServer, delay = DEBOUNCE_MS) {\r\n if (debounceTimer) clearTimeout(debounceTimer);\r\n debounceTimer = setTimeout(() => {\r\n debounceTimer = null;\r\n if (applyApp() !== null) {\r\n server.ws.send({ type: 'full-reload', path: '*' });\r\n }\r\n }, delay);\r\n }\r\n\r\n // Preview server needs SPA fallback so direct URL navigation works.\r\n function addSpaFallback(server: { middlewares: any }) {\r\n server.middlewares.use((req: any, res: any, next: any) => {\r\n const url = req.url as string;\r\n // Let Vite handle static assets and the API\r\n if (url.startsWith('/api') || url.includes('.')) return next();\r\n // Rewrite everything else to index.html for client-side routing\r\n req.url = '/index.html';\r\n next();\r\n });\r\n }\r\n\r\n return {\r\n name : 'bini-router',\r\n enforce: 'pre',\r\n\r\n // Strip `export const metadata = {...}` from all src/app files before\r\n // @vitejs/plugin-react's Fast Refresh transform sees them.\r\n transform(code, id) {\r\n const nid = norm(id);\r\n if (!isInDir(nid, norm(getAppDir()))) return;\r\n const ext = path.extname(id);\r\n if (!(SUPPORTED_EXTS as readonly string[]).includes(ext)) return;\r\n if (!code.includes('export const metadata')) return;\r\n\r\n let result = code;\r\n let idx = result.indexOf('export const metadata');\r\n\r\n while (idx !== -1) {\r\n const braceIdx = result.indexOf('{', idx);\r\n if (braceIdx === -1) break;\r\n\r\n let depth = 0, end = braceIdx;\r\n for (let i = braceIdx; i < result.length; i++) {\r\n if (result[i] === '{') depth++;\r\n else if (result[i] === '}') { depth--; if (depth === 0) { end = i; break; } }\r\n }\r\n\r\n let tail = end + 1;\r\n while (tail < result.length && (result[tail] === ' ' || result[tail] === '\\t')) tail++;\r\n if (tail < result.length && result[tail] === ';') tail++;\r\n while (tail < result.length && (result[tail] === '\\n' || result[tail] === '\\r')) tail++;\r\n\r\n result = result.slice(0, idx) + result.slice(tail);\r\n idx = result.indexOf('export const metadata', idx);\r\n }\r\n\r\n return { code: result, map: null };\r\n },\r\n\r\n config() { applyApp(); },\r\n buildStart() { applyApp(); },\r\n\r\n closeBundle() {\r\n if (platform) buildProductionEntry(getApiDir(), platform, enableCors);\r\n },\r\n\r\n buildEnd() {\r\n // Clear caches between builds so stale routes/modules don't persist.\r\n honoCache = null;\r\n moduleCache.clear();\r\n if (debounceTimer) { clearTimeout(debounceTimer); debounceTimer = null; }\r\n },\r\n\r\n async configureServer(server) {\r\n const appDir = getAppDir();\r\n const apiDir = getApiDir();\r\n\r\n if (!fs.existsSync(appDir)) return;\r\n\r\n server.watcher.add(appDir);\r\n\r\n server.watcher.on('add', f => isPageFile(f) && shouldProcess(f, 'add') && scheduleRegen(server, 300));\r\n server.watcher.on('unlink', f => isPageFile(f) && shouldProcess(f, 'unlink') && scheduleRegen(server));\r\n server.watcher.on('change', f => isPageFile(f) && shouldProcess(f, 'change') && scheduleRegen(server));\r\n\r\n // When root layout.tsx changes, re-run transformIndexHtml with fresh metadata.\r\n server.watcher.on('change', f => {\r\n const base = path.basename(f, path.extname(f));\r\n const inAppRoot = path.resolve(path.dirname(f)) === path.resolve(appDir);\r\n if (!inAppRoot || base !== 'layout') return;\r\n server.moduleGraph.invalidateAll();\r\n server.ws.send({ type: 'full-reload', path: '*' });\r\n });\r\n\r\n server.watcher.on('addDir', d => {\r\n const nd = norm(d);\r\n if (!isInDir(nd, norm(appDir)) || d.includes('node_modules') || isInDir(nd, norm(apiDir))) return;\r\n setTimeout(() => PAGE_FILES.some(f => fs.existsSync(path.join(d, f))) && scheduleRegen(server), 300);\r\n });\r\n\r\n server.watcher.on('unlinkDir', d => {\r\n const nd = norm(d);\r\n if (isInDir(nd, norm(appDir)) && !d.includes('node_modules') && !isInDir(nd, norm(apiDir)))\r\n scheduleRegen(server);\r\n });\r\n\r\n if (fs.existsSync(apiDir)) {\r\n server.watcher.add(apiDir);\r\n\r\n const resetApi = (f?: string) => {\r\n honoCache = null;\r\n // Clear the module cache entry for this specific file so importHandler\r\n // re-imports it on the next request rather than serving a stale handler.\r\n if (f) moduleCache.delete(f);\r\n server.ws.send({ type: 'full-reload', path: '*' });\r\n };\r\n\r\n server.watcher.on('add', f => isApiFile(f) && resetApi(f));\r\n server.watcher.on('unlink', f => isApiFile(f) && resetApi(f));\r\n server.watcher.on('change', f => isApiFile(f) && resetApi(f));\r\n\r\n server.middlewares.use((req: any, res: any, next: any) => {\r\n if (!req.url?.startsWith('/api')) return next();\r\n handleApiRequest(req, res, next, apiDir, enableCors,\r\n () => honoCache, (v) => { honoCache = v; });\r\n });\r\n }\r\n },\r\n\r\n async configurePreviewServer(server) {\r\n // SPA fallback so /register etc. don't 404 in preview mode.\r\n addSpaFallback(server);\r\n\r\n const apiDir = getApiDir();\r\n if (!fs.existsSync(apiDir)) return;\r\n server.middlewares.use((req: any, res: any, next: any) => {\r\n if (!req.url?.startsWith('/api')) return next();\r\n handleApiRequest(req, res, next, apiDir, enableCors,\r\n () => honoCache, (v) => { honoCache = v; });\r\n });\r\n },\r\n\r\n transformIndexHtml: {\r\n order: 'pre',\r\n handler(html) {\r\n const meta = parseAppMetadata(getAppDir());\r\n const title = meta.title ?? 'Bini App';\r\n const vp = meta.viewport ?? 'width=device-width, initial-scale=1.0';\r\n\r\n const lines: string[] = [];\r\n\r\n lines.push(`<meta charset=\"${meta.charset ?? 'UTF-8'}\" />`);\r\n lines.push(`<meta name=\"viewport\" content=\"${vp}\" />`);\r\n lines.push(`<title>${title}</title>`);\r\n if (meta.description) lines.push(`<meta name=\"description\" content=\"${meta.description}\" />`);\r\n if (meta.themeColor) lines.push(`<meta name=\"theme-color\" content=\"${meta.themeColor}\" />`);\r\n if (meta.robots) lines.push(`<meta name=\"robots\" content=\"${meta.robots}\" />`);\r\n if (meta.keywords) lines.push(`<meta name=\"keywords\" content=\"${meta.keywords}\" />`);\r\n if (meta.author) lines.push(`<meta name=\"author\" content=\"${meta.author}\" />`);\r\n if (meta.canonical) lines.push(`<link rel=\"canonical\" href=\"${meta.canonical}\" />`);\r\n if (meta.manifest) lines.push(`<link rel=\"manifest\" href=\"${meta.manifest}\" />`);\r\n\r\n for (const entry of meta.icons?.icon ?? []) {\r\n const type = entry.type ? ` type=\"${entry.type}\"` : '';\r\n const sizes = entry.sizes ? ` sizes=\"${entry.sizes}\"` : '';\r\n lines.push(`<link rel=\"icon\" href=\"${entry.url}\"${type}${sizes} />`);\r\n }\r\n for (const entry of meta.icons?.shortcut ?? []) {\r\n lines.push(`<link rel=\"shortcut icon\" href=\"${entry.url}\" />`);\r\n }\r\n for (const entry of meta.icons?.apple ?? []) {\r\n const sizes = entry.sizes ? ` sizes=\"${entry.sizes}\"` : '';\r\n const type = entry.type ? ` type=\"${entry.type}\"` : '';\r\n lines.push(`<link rel=\"apple-touch-icon\" href=\"${entry.url}\"${sizes}${type} />`);\r\n }\r\n\r\n if (meta.openGraph?.title) {\r\n lines.push(`<meta property=\"og:type\" content=\"${meta.openGraph.type ?? 'website'}\" />`);\r\n lines.push(`<meta property=\"og:title\" content=\"${meta.openGraph.title}\" />`);\r\n if (meta.openGraph.description) lines.push(`<meta property=\"og:description\" content=\"${meta.openGraph.description}\" />`);\r\n if (meta.openGraph.url) lines.push(`<meta property=\"og:url\" content=\"${meta.openGraph.url}\" />`);\r\n if (meta.openGraph.image) lines.push(`<meta property=\"og:image\" content=\"${meta.openGraph.image}\" />`);\r\n }\r\n\r\n if (meta.twitter?.title) {\r\n lines.push(`<meta name=\"twitter:card\" content=\"${meta.twitter.card ?? 'summary_large_image'}\" />`);\r\n lines.push(`<meta name=\"twitter:title\" content=\"${meta.twitter.title}\" />`);\r\n if (meta.twitter.description) lines.push(`<meta name=\"twitter:description\" content=\"${meta.twitter.description}\" />`);\r\n if (meta.twitter.creator) lines.push(`<meta name=\"twitter:creator\" content=\"${meta.twitter.creator}\" />`);\r\n if (meta.twitter.image) lines.push(`<meta name=\"twitter:image\" content=\"${meta.twitter.image}\" />`);\r\n }\r\n\r\n const injected = lines.map(l => ` ${l}`).join('\\n');\r\n\r\n return html\r\n .replace(/<meta\\s+charset[^>]*\\/?>/gi, '')\r\n .replace(/<meta\\s+name=\"viewport\"[^>]*\\/?>/gi, '')\r\n .replace(/<meta\\s+name=\"description\"[^>]*\\/?>/gi, '')\r\n .replace(/<meta\\s+name=\"theme-color\"[^>]*\\/?>/gi, '')\r\n .replace(/<meta\\s+name=\"robots\"[^>]*\\/?>/gi, '')\r\n .replace(/<meta\\s+name=\"keywords\"[^>]*\\/?>/gi, '')\r\n .replace(/<meta\\s+name=\"author\"[^>]*\\/?>/gi, '')\r\n .replace(/<meta\\s+property=\"og:[^\"]*\"[^>]*\\/?>/gi, '')\r\n .replace(/<meta\\s+name=\"twitter:[^\"]*\"[^>]*\\/?>/gi, '')\r\n .replace(/<link\\s+rel=\"canonical\"[^>]*\\/?>/gi, '')\r\n .replace(/<link\\s+rel=\"manifest\"[^>]*\\/?>/gi, '')\r\n .replace(/<link\\s+rel=\"icon\"[^>]*\\/?>/gi, '')\r\n .replace(/<link\\s+rel=\"shortcut icon\"[^>]*\\/?>/gi, '')\r\n .replace(/<link\\s+rel=\"apple-touch-icon\"[^>]*\\/?>/gi, '')\r\n .replace(/<title>.*?<\\/title>/si, '')\r\n .replace('</head>', `${injected}\\n </head>`);\r\n },\r\n },\r\n };\r\n}\r\n\r\nexport default biniroute;"],"mappings":"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","names":["path","fs","isCatchAll","isDynamic"]}
1
+ {"version":3,"sources":["../src/index.ts"],"sourcesContent":["import fs from 'fs';\r\nimport path from 'path';\r\nimport type { Plugin, ViteDevServer } from 'vite';\r\n\r\n// ─── Constants ────────────────────────────────────────────────────────────────\r\n\r\nconst PAGE_FILES = ['page.tsx', 'page.jsx', 'page.ts', 'page.js'] as const;\r\nconst LAYOUT_FILES = ['layout.tsx', 'layout.jsx', 'layout.ts', 'layout.js'] as const;\r\nconst SUPPORTED_EXTS = ['.tsx', '.jsx', '.ts', '.js'] as const;\r\nconst NOT_FOUND_FILES = SUPPORTED_EXTS.map(e => `not-found${e}`);\r\nconst SPECIAL_BASES = new Set(['page', 'layout', 'not-found', 'loading', 'error']);\r\nconst API_EXTS = ['.ts', '.js'] as const;\r\nconst DEBOUNCE_MS = 60;\r\nconst EVENT_DEDUP_MS = 500;\r\nconst EVENT_TTL_MS = 2000;\r\n\r\n// ─── Metadata Types ───────────────────────────────────────────────────────────\r\n\r\nexport interface IconEntry {\r\n url : string;\r\n type ?: string;\r\n sizes?: string;\r\n}\r\n\r\nexport interface MetaTags {\r\n title ?: string;\r\n description ?: string;\r\n viewport ?: string;\r\n themeColor ?: string;\r\n keywords ?: string;\r\n author ?: string;\r\n charset ?: string;\r\n robots ?: string;\r\n canonical ?: string;\r\n manifest ?: string;\r\n openGraph ?: Partial<OGMeta>;\r\n twitter ?: Partial<TwitterMeta>;\r\n icons ?: {\r\n icon ?: IconEntry[];\r\n shortcut ?: IconEntry[];\r\n apple ?: IconEntry[];\r\n };\r\n}\r\n\r\ninterface OGMeta {\r\n title : string;\r\n description : string;\r\n url : string;\r\n image : string;\r\n type : string;\r\n}\r\n\r\ninterface TwitterMeta {\r\n card : string;\r\n title : string;\r\n description : string;\r\n creator : string;\r\n image : string;\r\n}\r\n\r\n// ─── Types ────────────────────────────────────────────────────────────────────\r\n\r\ninterface RouteNode {\r\n routePath : string;\r\n filePath : string;\r\n layouts : string[];\r\n dynamic : boolean;\r\n}\r\n\r\ninterface LayoutChainGroup {\r\n layouts : string[];\r\n routes : RouteNode[];\r\n}\r\n\r\ninterface ApiRoute {\r\n routePath : string;\r\n filePath : string;\r\n}\r\n\r\nexport interface BiniPluginOptions {\r\n /** Directory for page files. Default: src/app */\r\n appDir?: string;\r\n /** Directory for API routes. Default: src/app/api */\r\n apiDir?: string;\r\n /** Enable CORS headers in the dev-server API middleware. Default: true */\r\n cors?: boolean;\r\n /**\r\n * Target deployment platform. bini-router generates a production entry\r\n * file on every build — users only write code in src/app/api/.\r\n *\r\n * 'vercel' → api/index.ts (no extra install needed)\r\n * 'node' → server/index.ts (install: @hono/node-server)\r\n * 'cloudflare' → worker.ts (install: wrangler)\r\n *\r\n * Default: undefined (no entry generated)\r\n */\r\n platform?: 'vercel' | 'node' | 'cloudflare';\r\n}\r\n\r\n// ─── Utilities ────────────────────────────────────────────────────────────────\r\n\r\n// Normalize to forward slashes for reliable cross-platform path comparisons.\r\nfunction norm(p: string): string {\r\n return p.replace(/\\\\/g, '/');\r\n}\r\n\r\nfunction isInDir(file: string, dir: string): boolean {\r\n const nFile = norm(file);\r\n const nDir = norm(dir).replace(/\\/$/, '');\r\n return nFile.startsWith(nDir + '/') || nFile === nDir;\r\n}\r\n\r\nfunction readTsconfigAliases(): Record<string, string> {\r\n const aliases: Record<string, string> = {};\r\n try {\r\n const tsconfigPath = path.join(process.cwd(), 'tsconfig.json');\r\n if (!fs.existsSync(tsconfigPath)) return aliases;\r\n const raw = fs.readFileSync(tsconfigPath, 'utf8')\r\n .replace(/\\/\\/.*$/gm, '')\r\n .replace(/\\/\\*[\\s\\S]*?\\*\\//g, '');\r\n const tsconfig = JSON.parse(raw);\r\n const paths = tsconfig?.compilerOptions?.paths ?? {};\r\n const baseUrl = tsconfig?.compilerOptions?.baseUrl ?? '.';\r\n for (const [alias, targets] of Object.entries(paths) as [string, string[]][]) {\r\n const cleanAlias = alias.replace(/\\/\\*$/, '');\r\n const cleanTarget = (targets[0] ?? '').replace(/\\/\\*$/, '');\r\n aliases[cleanAlias] = path.resolve(process.cwd(), baseUrl, cleanTarget);\r\n }\r\n } catch { /* tsconfig unreadable — fall back to relative paths */ }\r\n return aliases;\r\n}\r\n\r\nfunction toImportPath(filePath: string, aliases: Record<string, string>): string {\r\n for (const [alias, target] of Object.entries(aliases)) {\r\n if (norm(filePath).startsWith(norm(target) + '/')) {\r\n const rest = norm(filePath).slice(norm(target).length + 1).replace(/\\.(tsx|ts|jsx|js)$/, '');\r\n return `${alias}/${rest}`;\r\n }\r\n }\r\n return './' + norm(path.relative(path.join(process.cwd(), 'src'), filePath))\r\n .replace(/\\.(tsx|ts|jsx|js)$/, '');\r\n}\r\n\r\nfunction hasDefaultExport(filePath: string): boolean {\r\n try { return fs.readFileSync(filePath, 'utf8').includes('export default'); }\r\n catch { return false; }\r\n}\r\n\r\nfunction isHtmlShellLayout(filePath: string): boolean {\r\n try { return /<html[\\s>]/i.test(fs.readFileSync(filePath, 'utf8')); }\r\n catch { return false; }\r\n}\r\n\r\nfunction isUsableLayout(filePath: string): boolean {\r\n return hasDefaultExport(filePath) && !isHtmlShellLayout(filePath);\r\n}\r\n\r\nfunction findFile(dir: string, candidates: readonly string[]): string | null {\r\n return candidates.find(f => fs.existsSync(path.join(dir, f))) ?? null;\r\n}\r\n\r\nfunction getAppFile(): string {\r\n const ts = path.join(process.cwd(), 'src/App.tsx');\r\n return fs.existsSync(ts) ? ts : path.join(process.cwd(), 'src/App.jsx');\r\n}\r\n\r\n// ─── Layout Resolution ────────────────────────────────────────────────────────\r\n\r\nfunction resolveLayoutChain(pageDir: string, appDir: string): string[] {\r\n const chain: string[] = [];\r\n let current = pageDir;\r\n while (true) {\r\n const layout = findFile(current, LAYOUT_FILES);\r\n if (layout) chain.unshift(path.join(current, layout));\r\n if (path.resolve(current) === path.resolve(appDir)) break;\r\n const parent = path.dirname(current);\r\n if (parent === current) break;\r\n current = parent;\r\n }\r\n return chain;\r\n}\r\n\r\n// ─── Route Scanner ────────────────────────────────────────────────────────────\r\n\r\nfunction scanRoutes(dir: string, appDir: string, baseRoute = ''): RouteNode[] {\r\n const routes: RouteNode[] = [];\r\n if (!fs.existsSync(dir)) return routes;\r\n\r\n let entries: fs.Dirent[];\r\n try { entries = fs.readdirSync(dir, { withFileTypes: true }); }\r\n catch { return routes; }\r\n\r\n // File-based: about.tsx → /about\r\n for (const entry of entries) {\r\n if (!entry.isFile() || entry.name.startsWith('.') || entry.name.startsWith('_')) continue;\r\n const ext = path.extname(entry.name);\r\n const base = path.basename(entry.name, ext);\r\n if (!(SUPPORTED_EXTS as readonly string[]).includes(ext)) continue;\r\n if (SPECIAL_BASES.has(base)) continue;\r\n routes.push({\r\n routePath : `${baseRoute}/${base}`,\r\n filePath : path.join(dir, entry.name),\r\n layouts : resolveLayoutChain(dir, appDir),\r\n dynamic : false,\r\n });\r\n }\r\n\r\n // Directory-based: [id]/page.tsx → /:id\r\n for (const entry of entries) {\r\n if (!entry.isDirectory()) continue;\r\n if (entry.name === 'node_modules' || entry.name.startsWith('.') || entry.name === 'api') continue;\r\n\r\n const fullPath = path.join(dir, entry.name);\r\n const isDynamic = entry.name.startsWith('[') && entry.name.endsWith(']');\r\n const segment = isDynamic ? `:${entry.name.slice(1, -1)}` : entry.name;\r\n const routePath = `${baseRoute}/${segment}`;\r\n\r\n const pageFile = findFile(fullPath, PAGE_FILES);\r\n if (pageFile) {\r\n routes.push({\r\n routePath,\r\n filePath : path.join(fullPath, pageFile),\r\n layouts : resolveLayoutChain(fullPath, appDir),\r\n dynamic : isDynamic,\r\n });\r\n }\r\n routes.push(...scanRoutes(fullPath, appDir, routePath));\r\n }\r\n\r\n return routes;\r\n}\r\n\r\n// Detect duplicate routePaths and keep the first encountered (file-based wins\r\n// over directory-based since we unshift the root page before sorting).\r\nfunction deduplicateRoutes(routes: RouteNode[]): RouteNode[] {\r\n const seen = new Set<string>();\r\n return routes.filter(r => {\r\n if (seen.has(r.routePath)) return false;\r\n seen.add(r.routePath);\r\n return true;\r\n });\r\n}\r\n\r\n// ─── Per-layout title extractor ──────────────────────────────────────────────\r\n\r\nfunction parseLayoutTitle(layoutFile: string): string | null {\r\n let src = '';\r\n try { src = fs.readFileSync(layoutFile, 'utf8'); }\r\n catch { return null; }\r\n\r\n const startIdx = src.indexOf('export const metadata');\r\n if (startIdx === -1) return null;\r\n const braceStart = src.indexOf('{', startIdx);\r\n if (braceStart === -1) return null;\r\n\r\n let depth = 0, end = braceStart;\r\n for (let i = braceStart; i < src.length; i++) {\r\n if (src[i] === '{') depth++;\r\n else if (src[i] === '}') { depth--; if (depth === 0) { end = i; break; } }\r\n }\r\n const block = src.slice(braceStart, end + 1);\r\n const match = /['\"]?title['\"]?\\s*:\\s*['\"`]([^'\"`]+)['\"`]/.exec(block);\r\n return match ? match[1] : null;\r\n}\r\n\r\n// ─── Route Tree Renderer ──────────────────────────────────────────────────────\r\n\r\nfunction renderChain(\r\n layouts : string[],\r\n routesInChain : RouteNode[],\r\n layoutNames : Map<string, string>,\r\n pageNames : Map<string, string>,\r\n layoutTitles : Map<string, string>,\r\n indent : number,\r\n): string {\r\n const pad = ' '.repeat(indent);\r\n if (layouts.length === 0) {\r\n return routesInChain.map(r =>\r\n `${pad}<Route path=\"${r.routePath}\" element={<Suspense fallback={<Spinner />}><ErrorBoundary><${pageNames.get(r.filePath)} /></ErrorBoundary></Suspense>} />`\r\n ).join('\\n');\r\n }\r\n const [head, ...tail] = layouts;\r\n const title = layoutTitles.get(head);\r\n // TitleSetter is rendered OUTSIDE ErrorBoundary so a layout crash doesn't\r\n // prevent the title from updating.\r\n const titleSetter = title ? `<TitleSetter title=${JSON.stringify(title)} />` : '';\r\n const inner = renderChain(tail, routesInChain, layoutNames, pageNames, layoutTitles, indent + 2);\r\n const name = layoutNames.get(head);\r\n return [\r\n `${pad}<Route element={<>${titleSetter}<Suspense fallback={<Spinner />}><ErrorBoundary><${name}><Outlet /></${name}></ErrorBoundary></Suspense></>}>`,\r\n inner,\r\n `${pad}</Route>`,\r\n ].join('\\n');\r\n}\r\n\r\n// ─── App Generator ────────────────────────────────────────────────────────────\r\n\r\nfunction generateApp(appDir: string): string {\r\n const aliases = readTsconfigAliases();\r\n const routes = scanRoutes(appDir, appDir);\r\n\r\n const rootPage = findFile(appDir, PAGE_FILES);\r\n if (rootPage) {\r\n routes.unshift({\r\n routePath : '/',\r\n filePath : path.join(appDir, rootPage),\r\n layouts : resolveLayoutChain(appDir, appDir),\r\n dynamic : false,\r\n });\r\n }\r\n\r\n // Strip html-shell layouts and layouts with no default export.\r\n const routesFiltered = routes.map(r => ({\r\n ...r,\r\n layouts: r.layouts.filter(l => isUsableLayout(l)),\r\n }));\r\n\r\n // Only include routes whose page file has a default export.\r\n const validRoutes = deduplicateRoutes(\r\n routesFiltered.filter(r => hasDefaultExport(r.filePath))\r\n );\r\n\r\n validRoutes.sort((a, b) => {\r\n if (a.dynamic !== b.dynamic) return a.dynamic ? 1 : -1;\r\n return a.routePath.length - b.routePath.length;\r\n });\r\n\r\n const notFoundFile = NOT_FOUND_FILES.find(f => fs.existsSync(path.join(appDir, f)));\r\n const notFound = notFoundFile && hasDefaultExport(path.join(appDir, notFoundFile))\r\n ? notFoundFile\r\n : undefined;\r\n\r\n const allLayouts = new Set<string>();\r\n for (const r of validRoutes) r.layouts.forEach(l => {\r\n if (isUsableLayout(l)) allLayouts.add(l);\r\n });\r\n\r\n const layoutNames = new Map<string, string>();\r\n const pageNames = new Map<string, string>();\r\n const layoutTitles = new Map<string, string>();\r\n let li = 0, pi = 0;\r\n for (const l of allLayouts) {\r\n layoutNames.set(l, `Layout${li++}`);\r\n const title = parseLayoutTitle(l);\r\n if (title) layoutTitles.set(l, title);\r\n }\r\n for (const r of validRoutes) {\r\n if (!pageNames.has(r.filePath)) pageNames.set(r.filePath, `Page${pi++}`);\r\n }\r\n\r\n const lazyImports: string[] = [];\r\n for (const [fp, name] of layoutNames)\r\n lazyImports.push(`const ${name} = React.lazy(() => import('${toImportPath(fp, aliases)}'));`);\r\n if (notFound)\r\n lazyImports.push(`const NotFound = React.lazy(() => import('${toImportPath(path.join(appDir, notFound), aliases)}'));`);\r\n const emittedPages = new Set<string>();\r\n for (const r of validRoutes) {\r\n if (emittedPages.has(r.filePath)) continue;\r\n emittedPages.add(r.filePath);\r\n const name = pageNames.get(r.filePath);\r\n if (!name) continue;\r\n lazyImports.push(`const ${name} = React.lazy(() => import('${toImportPath(r.filePath, aliases)}'));`);\r\n }\r\n\r\n const chainMap = new Map<string, LayoutChainGroup>();\r\n for (const r of validRoutes) {\r\n const key = r.layouts.join('|');\r\n if (!chainMap.has(key)) chainMap.set(key, { layouts: r.layouts, routes: [] });\r\n chainMap.get(key)!.routes.push(r);\r\n }\r\n\r\n const routeLines: string[] = [];\r\n for (const [, { layouts, routes: cr }] of chainMap)\r\n routeLines.push(renderChain(layouts, cr, layoutNames, pageNames, layoutTitles, 8));\r\n\r\n const catchAll = notFound\r\n ? ` <Route path=\"*\" element={<Suspense fallback={<Spinner />}><NotFound /></Suspense>} />`\r\n : ` <Route path=\"*\" element={<Default404 />} />`;\r\n\r\n return `// ⚠️ Auto-generated by bini-router — do not edit.\r\nimport React, { Suspense } from 'react';\r\nimport { BrowserRouter, Routes, Route, Outlet } from 'react-router-dom';\r\nimport './app/globals.css';\r\n\r\n${lazyImports.join('\\n')}\r\n\r\n// ─── Error Boundary ───────────────────────────────────────────────────────────\r\nclass ErrorBoundary extends React.Component<\r\n { children: React.ReactNode },\r\n { error: Error | null }\r\n> {\r\n constructor(props: { children: React.ReactNode }) {\r\n super(props);\r\n this.state = { error: null };\r\n }\r\n static getDerivedStateFromError(error: Error) { return { error }; }\r\n override render() {\r\n if (this.state.error) return (\r\n <div style={{ minHeight: '100vh', display: 'flex', alignItems: 'center', justifyContent: 'center', fontFamily: 'system-ui,sans-serif', padding: '2rem' }}>\r\n <div style={{ maxWidth: 480, width: '100%', textAlign: 'center' }}>\r\n <h2 style={{ color: '#e74c3c', marginBottom: '1rem' }}>Something went wrong</h2>\r\n <pre style={{ background: '#fef2f2', padding: '1rem', borderRadius: '0.5rem', textAlign: 'left', fontSize: '0.8rem', color: '#e74c3c', overflow: 'auto' }}>{this.state.error.toString()}</pre>\r\n <button onClick={() => this.setState({ error: null })} style={{ marginTop: '1rem', padding: '0.5rem 1.5rem', background: '#00CFFF', color: 'white', border: 'none', borderRadius: '0.5rem', cursor: 'pointer', fontWeight: 600 }}>\r\n Try again\r\n </button>\r\n </div>\r\n </div>\r\n );\r\n return this.props.children;\r\n }\r\n}\r\n\r\nfunction Spinner() {\r\n return (\r\n <div style={{ minHeight: '100vh', display: 'flex', alignItems: 'center', justifyContent: 'center' }}>\r\n <div style={{ width: 32, height: 32, border: '3px solid #eee', borderTop: '3px solid #00CFFF', borderRadius: '50%', animation: 'spin 0.8s linear infinite' }} />\r\n <style>{\\`@keyframes spin{to{transform:rotate(360deg)}}\\`}</style>\r\n </div>\r\n );\r\n}\r\n\r\n// Renders nothing — just sets document.title when the layout mounts.\r\n// Placed outside ErrorBoundary so a layout crash doesn't block the title update.\r\nfunction TitleSetter({ title }: { title: string }) {\r\n React.useEffect(() => { document.title = title; }, [title]);\r\n return null;\r\n}\r\n\r\n${notFound ? '' : `function Default404() {\r\n return (\r\n <div style={{ minHeight: '100vh', display: 'flex', alignItems: 'center', justifyContent: 'center', background: 'linear-gradient(135deg,#00CFFF,#0077FF)', color: 'white', fontFamily: 'system-ui,sans-serif' }}>\r\n <div style={{ textAlign: 'center' }}>\r\n <h1 style={{ fontSize: '5rem', fontWeight: 800, margin: 0 }}>404</h1>\r\n <p style={{ fontSize: '1.25rem', margin: '0.5rem 0 2rem' }}>Page not found</p>\r\n <a href=\"/\" style={{ padding: '0.65rem 1.5rem', background: 'white', color: '#00CFFF', textDecoration: 'none', borderRadius: '0.5rem', fontWeight: 600 }}>← Back to Home</a>\r\n </div>\r\n </div>\r\n );\r\n}`}\r\n\r\nexport default function App() {\r\n return (\r\n <BrowserRouter>\r\n <Routes>\r\n${routeLines.join('\\n')}\r\n${catchAll}\r\n </Routes>\r\n </BrowserRouter>\r\n );\r\n}\r\n`;\r\n}\r\n\r\n// ─── Metadata Parser ──────────────────────────────────────────────────────────\r\n\r\nfunction parseAppMetadata(appDir: string): MetaTags {\r\n const layout = findFile(appDir, LAYOUT_FILES);\r\n if (!layout) return {};\r\n let src = '';\r\n try { src = fs.readFileSync(path.join(appDir, layout), 'utf8'); }\r\n catch { return {}; }\r\n\r\n const startIdx = src.indexOf('export const metadata');\r\n if (startIdx === -1) return {};\r\n const braceStart = src.indexOf('{', startIdx);\r\n if (braceStart === -1) return {};\r\n\r\n let depth = 0, end = braceStart;\r\n for (let i = braceStart; i < src.length; i++) {\r\n if (src[i] === '{') depth++;\r\n else if (src[i] === '}') { depth--; if (depth === 0) { end = i; break; } }\r\n }\r\n const block = src.slice(braceStart, end + 1);\r\n\r\n function extractBlock(source: string, key: string): string | undefined {\r\n const re = new RegExp(`['\"]?${key}['\"]?\\\\s*:\\\\s*\\\\{`);\r\n const match = re.exec(source);\r\n if (!match) return undefined;\r\n let d = 0, i = match.index + match[0].length - 1;\r\n const start = i;\r\n for (; i < source.length; i++) {\r\n if (source[i] === '{') d++;\r\n else if (source[i] === '}') { d--; if (d === 0) return source.slice(start, i + 1); }\r\n }\r\n return undefined;\r\n }\r\n\r\n function extractArray(source: string, key: string): string | undefined {\r\n const re = new RegExp(`['\"]?${key}['\"]?\\\\s*:\\\\s*\\\\[`);\r\n const match = re.exec(source);\r\n if (!match) return undefined;\r\n let d = 0, i = match.index + match[0].length - 1;\r\n const start = i;\r\n for (; i < source.length; i++) {\r\n if (source[i] === '[') d++;\r\n else if (source[i] === ']') { d--; if (d === 0) return source.slice(start, i + 1); }\r\n }\r\n return undefined;\r\n }\r\n\r\n function str(source: string, key: string): string | undefined {\r\n return source.match(\r\n new RegExp(`['\"]?${key}['\"]?\\\\s*:\\\\s*['\"\\`]([^'\"\\`\\n]+)['\"\\`]`)\r\n )?.[1];\r\n }\r\n\r\n function firstArrayStr(source: string, key: string): string | undefined {\r\n const arr = extractArray(source, key);\r\n if (!arr) return undefined;\r\n return arr.match(/url\\s*:\\s*['\"]([^'\"]+)['\"]/)?.[1]\r\n ?? arr.match(/['\"]([^'\"]+)['\"]/)?.[1];\r\n }\r\n\r\n function allArrayStrs(source: string, key: string): string[] {\r\n const arr = extractArray(source, key);\r\n if (!arr) return [];\r\n return [...arr.matchAll(/['\"]([^'\"]+)['\"]/g)].map(m => m[1]);\r\n }\r\n\r\n const meta: MetaTags = {};\r\n\r\n if (str(block, 'title')) meta.title = str(block, 'title');\r\n if (str(block, 'description')) meta.description = str(block, 'description');\r\n if (str(block, 'viewport')) meta.viewport = str(block, 'viewport');\r\n if (str(block, 'themeColor')) meta.themeColor = str(block, 'themeColor');\r\n if (str(block, 'charset')) meta.charset = str(block, 'charset');\r\n if (str(block, 'robots')) meta.robots = str(block, 'robots');\r\n if (str(block, 'canonical')) meta.canonical = str(block, 'canonical');\r\n if (str(block, 'manifest')) meta.manifest = str(block, 'manifest');\r\n\r\n const kwStr = str(block, 'keywords');\r\n if (kwStr) {\r\n meta.keywords = kwStr;\r\n } else {\r\n const kwArr = allArrayStrs(block, 'keywords');\r\n if (kwArr.length) meta.keywords = kwArr.join(', ');\r\n }\r\n\r\n const authorStr = str(block, 'author');\r\n if (authorStr) {\r\n meta.author = authorStr;\r\n } else {\r\n const authorsArr = extractArray(block, 'authors');\r\n if (authorsArr) {\r\n const name = authorsArr.match(/name\\s*:\\s*['\"]([^'\"]+)['\"]/)?.[1];\r\n if (name) meta.author = name;\r\n }\r\n }\r\n\r\n if (!meta.canonical) {\r\n const base = block.match(/metadataBase\\s*:\\s*new\\s+URL\\s*\\(\\s*['\"]([^'\"]+)['\"]/)?.[1];\r\n if (base) meta.canonical = base;\r\n }\r\n\r\n const ogBlock = extractBlock(block, 'openGraph');\r\n if (ogBlock) {\r\n meta.openGraph = {\r\n title : str(ogBlock, 'title'),\r\n description : str(ogBlock, 'description'),\r\n url : str(ogBlock, 'url'),\r\n type : str(ogBlock, 'type'),\r\n image : firstArrayStr(ogBlock, 'images') ?? str(ogBlock, 'image'),\r\n };\r\n }\r\n\r\n const twBlock = extractBlock(block, 'twitter');\r\n if (twBlock) {\r\n meta.twitter = {\r\n card : str(twBlock, 'card'),\r\n title : str(twBlock, 'title'),\r\n description : str(twBlock, 'description'),\r\n creator : str(twBlock, 'creator'),\r\n image : firstArrayStr(twBlock, 'images') ?? str(twBlock, 'image'),\r\n };\r\n }\r\n\r\n const iconsBlock = extractBlock(block, 'icons');\r\n if (iconsBlock) {\r\n meta.icons = {\r\n icon : collectIconEntries(iconsBlock, 'icon'),\r\n shortcut: collectIconEntries(iconsBlock, 'shortcut'),\r\n apple : collectIconEntries(iconsBlock, 'apple'),\r\n };\r\n }\r\n\r\n return meta;\r\n}\r\n\r\nfunction collectIconEntries(source: string, key: string): IconEntry[] {\r\n const arr = extractArrayRaw(source, key);\r\n if (!arr) return [];\r\n const entries: IconEntry[] = [];\r\n const objRe = /\\{([^}]+)\\}/g;\r\n let m: RegExpExecArray | null;\r\n while ((m = objRe.exec(arr)) !== null) {\r\n const obj = m[1];\r\n const url = obj.match(/url\\s*:\\s*['\"]([^'\"]+)['\"]/)?.[1];\r\n if (!url) continue;\r\n entries.push({\r\n url,\r\n type : obj.match(/type\\s*:\\s*['\"]([^'\"]+)['\"]/)?.[1],\r\n sizes: obj.match(/sizes\\s*:\\s*['\"]([^'\"]+)['\"]/)?.[1],\r\n });\r\n }\r\n if (!entries.length) {\r\n return [...arr.matchAll(/['\"]([^'\"]+)['\"]/g)].map(x => ({ url: x[1] }));\r\n }\r\n return entries;\r\n}\r\n\r\nfunction extractArrayRaw(source: string, key: string): string | undefined {\r\n const re = new RegExp(`['\"]?${key}['\"]?\\\\s*:\\\\s*\\\\[`);\r\n const match = re.exec(source);\r\n if (!match) return undefined;\r\n let d = 0, i = match.index + match[0].length - 1;\r\n const start = i;\r\n for (; i < source.length; i++) {\r\n if (source[i] === '[') d++;\r\n else if (source[i] === ']') { d--; if (d === 0) return source.slice(start, i + 1); }\r\n }\r\n return undefined;\r\n}\r\n\r\n// ─── API Route Scanner ────────────────────────────────────────────────────────\r\n\r\nfunction scanApiRoutes(dir: string, baseRoute = ''): ApiRoute[] {\r\n const routes: ApiRoute[] = [];\r\n if (!fs.existsSync(dir)) return routes;\r\n\r\n let entries: fs.Dirent[];\r\n try { entries = fs.readdirSync(dir, { withFileTypes: true }); }\r\n catch { return routes; }\r\n\r\n for (const entry of entries) {\r\n if (entry.name.startsWith('_') || entry.name.startsWith('.')) continue;\r\n const fullPath = path.join(dir, entry.name);\r\n\r\n if (entry.isDirectory()) {\r\n const isCatchAll = entry.name.startsWith('[...') && entry.name.endsWith(']');\r\n const isDynamic = entry.name.startsWith('[') && entry.name.endsWith(']');\r\n const segment = isCatchAll ? '*' : isDynamic ? `:${entry.name.slice(1, -1)}` : entry.name;\r\n routes.push(...scanApiRoutes(fullPath, `${baseRoute}/${segment}`));\r\n continue;\r\n }\r\n\r\n const ext = path.extname(entry.name);\r\n const base = path.basename(entry.name, ext);\r\n if (!(API_EXTS as readonly string[]).includes(ext)) continue;\r\n\r\n const isCatchAll = base.startsWith('[...') && base.endsWith(']');\r\n const isDynamic = base.startsWith('[') && base.endsWith(']');\r\n const routePath = isCatchAll\r\n ? `${baseRoute}/*`\r\n : base === 'index'\r\n ? baseRoute || '/'\r\n : isDynamic\r\n ? `${baseRoute}/:${base.slice(1, -1)}`\r\n : `${baseRoute}/${base}`;\r\n\r\n routes.push({ routePath, filePath: fullPath });\r\n }\r\n\r\n return routes;\r\n}\r\n\r\n// ─── Hono dev/preview server ──────────────────────────────────────────────────\r\n//\r\n// API files in src/app/api/ can export:\r\n// export default new Hono().basePath('/api') ← Hono app (routing handled internally)\r\n// export default async function(req: Request) {...} ← plain function (bini-router matches route)\r\n//\r\n// Module cache: re-imports only when the file's mtime changes, not on every request.\r\n// Route matching: plain functions are matched against their scanned routePath pattern\r\n// before the handler is called — so dynamic params ([id]) are resolved correctly.\r\n\r\n// Matches a URL pathname against a route pattern like /api/users/:id or /api/files/*\r\n// Returns extracted params if matched, or null if not.\r\nfunction matchRoute(pattern: string, pathname: string): Record<string, string> | null {\r\n const patParts = pattern.split('/').filter(Boolean);\r\n const urlParts = pathname.split('/').filter(Boolean);\r\n\r\n // Catch-all: pattern ends with * — match everything after the prefix\r\n const isCatchAll = patParts[patParts.length - 1] === '*';\r\n if (isCatchAll) {\r\n const prefix = patParts.slice(0, -1);\r\n if (urlParts.length < prefix.length) return null;\r\n for (let i = 0; i < prefix.length; i++) {\r\n if (prefix[i].startsWith(':')) continue;\r\n if (prefix[i] !== urlParts[i]) return null;\r\n }\r\n return { '*': urlParts.slice(prefix.length).join('/') };\r\n }\r\n\r\n if (patParts.length !== urlParts.length) return null;\r\n\r\n const params: Record<string, string> = {};\r\n for (let i = 0; i < patParts.length; i++) {\r\n if (patParts[i].startsWith(':')) {\r\n params[patParts[i].slice(1)] = decodeURIComponent(urlParts[i]);\r\n } else if (patParts[i] !== urlParts[i]) {\r\n return null;\r\n }\r\n }\r\n return params;\r\n}\r\n\r\n// Per-file module cache: maps filePath → { mtime, handler }\r\n// Avoids re-importing on every request while still picking up file changes.\r\nconst moduleCache = new Map<string, { mtime: number; handler: unknown }>();\r\n\r\nasync function importHandler(filePath: string): Promise<unknown> {\r\n const { pathToFileURL } = await import('url');\r\n let mtime = 0;\r\n try { mtime = fs.statSync(filePath).mtimeMs; } catch { /* file vanished */ }\r\n\r\n const cached = moduleCache.get(filePath);\r\n if (cached && cached.mtime === mtime) return cached.handler;\r\n\r\n // File changed or not yet cached — re-import with cache-bust\r\n const mod = await import(pathToFileURL(filePath).href + '?t=' + mtime);\r\n const handler = mod.default ?? null;\r\n moduleCache.set(filePath, { mtime, handler });\r\n return handler;\r\n}\r\n\r\nasync function handleApiRequest(\r\n req : any,\r\n res : any,\r\n next : any,\r\n apiDir : string,\r\n enableCors : boolean,\r\n getCache : () => { routes: ApiRoute[] } | null,\r\n setCache : (v: { routes: ApiRoute[] }) => void,\r\n) {\r\n try {\r\n // Handle CORS preflight immediately — no need to hit a handler.\r\n if (enableCors && req.method === 'OPTIONS') {\r\n res.statusCode = 204;\r\n res.setHeader('Access-Control-Allow-Origin', '*');\r\n res.setHeader('Access-Control-Allow-Methods', 'GET,POST,PUT,PATCH,DELETE,OPTIONS');\r\n res.setHeader('Access-Control-Allow-Headers', 'Content-Type,Authorization');\r\n res.setHeader('Access-Control-Max-Age', '86400');\r\n res.end();\r\n return;\r\n }\r\n\r\n let cache = getCache();\r\n if (!cache) {\r\n cache = { routes: scanApiRoutes(apiDir, '/api') };\r\n setCache(cache);\r\n }\r\n\r\n const host = req.headers.host ?? 'localhost';\r\n const url = `http://${host}${req.url}`;\r\n const pathname = new URL(url).pathname;\r\n\r\n const chunks: Buffer[] = [];\r\n for await (const chunk of req) chunks.push(chunk as Buffer);\r\n const body = chunks.length > 0 ? Buffer.concat(chunks) : undefined;\r\n\r\n const method = (req.method as string).toUpperCase();\r\n\r\n const webReq = new Request(url, {\r\n method,\r\n headers: req.headers as HeadersInit,\r\n body : !['GET', 'HEAD'].includes(method) && body?.length ? body : undefined,\r\n });\r\n\r\n for (const route of cache.routes) {\r\n const handler = await importHandler(route.filePath);\r\n if (!handler) continue;\r\n\r\n let webRes: Response;\r\n try {\r\n if (typeof (handler as any).fetch === 'function') {\r\n // Hono app — has its own internal router, pass the full request directly.\r\n webRes = await (handler as any).fetch(webReq.clone());\r\n\r\n // Hono returns 404 when no route matched — try next file.\r\n if (webRes.status === 404) continue;\r\n\r\n } else if (typeof handler === 'function') {\r\n // Plain function — match the URL against this file's route pattern first.\r\n // This gives dynamic params ([id] → :id) without the function needing a router.\r\n const params = matchRoute(route.routePath, pathname);\r\n if (params === null) continue; // URL doesn't match this file's pattern\r\n\r\n // Inject matched params into the Request so the handler can read them.\r\n // We attach them as a custom header so no extra dependency is needed.\r\n const existingHeaders: Record<string, string> = {};\r\n webReq.headers.forEach((v, k) => { existingHeaders[k] = v; });\r\n const reqWithParams = new Request(webReq.clone(), {\r\n headers: { ...existingHeaders, 'x-bini-params': JSON.stringify(params) },\r\n });\r\n\r\n webRes = await (handler as (...args: any[]) => Promise<Response>)(reqWithParams);\r\n\r\n } else {\r\n continue;\r\n }\r\n } catch {\r\n continue; // handler threw — not its route, try next\r\n }\r\n\r\n // Build final headers — Response.headers is immutable so copy to plain object first\r\n const finalHeaders: Record<string, string> = {};\r\n webRes.headers.forEach((v, k) => { finalHeaders[k] = v; });\r\n if (enableCors) {\r\n finalHeaders['access-control-allow-origin'] = '*';\r\n finalHeaders['access-control-allow-methods'] = 'GET,POST,PUT,PATCH,DELETE,OPTIONS';\r\n finalHeaders['access-control-allow-headers'] = 'Content-Type,Authorization';\r\n }\r\n\r\n res.statusCode = webRes.status;\r\n for (const [k, v] of Object.entries(finalHeaders)) res.setHeader(k, v);\r\n res.end(Buffer.from(await webRes.arrayBuffer()));\r\n return;\r\n }\r\n\r\n // No handler matched\r\n res.statusCode = 404;\r\n res.setHeader('Content-Type', 'application/json');\r\n res.end(JSON.stringify({ error: `No API handler found for ${req.url}` }));\r\n } catch (e: any) {\r\n next(e);\r\n }\r\n}\r\n\r\n// ─── Production Entry Generator ───────────────────────────────────────────────\r\n//\r\n// Mirrors what SvelteKit/Nuxt adapters do at build time:\r\n// scan src/app/api/, merge all handlers, wrap with the platform adapter.\r\n// User writes only in src/app/api/ — never touches the generated entry file.\r\n//\r\n// Supports both export styles:\r\n// export default new Hono() ← merged via .route()\r\n// export default async function handler(req: Request) {...} ← wrapped in Hono app\r\n\r\nfunction buildProductionEntry(srcApiDir: string, platform: 'vercel' | 'node' | 'cloudflare', enableCors: boolean): void {\r\n if (!fs.existsSync(srcApiDir)) return;\r\n\r\n const routes = scanApiRoutes(srcApiDir);\r\n const cwd = process.cwd();\r\n\r\n const imports : string[] = [];\r\n const mountings: string[] = [];\r\n\r\n for (let i = 0; i < routes.length; i++) {\r\n const route = routes[i];\r\n const rel = norm(path.relative(cwd, route.filePath)).replace(/\\.(ts|tsx)$/, '');\r\n const imp = rel.startsWith('.') ? rel : `./${rel}`;\r\n const name = `_route${i}`;\r\n\r\n // Detect at build time whether this file exports a Hono app or a plain function\r\n // by reading the source — if it imports from 'hono' it's a Hono app, otherwise wrap it.\r\n let src = '';\r\n try { src = fs.readFileSync(route.filePath, 'utf8'); } catch { /* skip */ }\r\n const isHonoApp = src.includes(\"from 'hono'\") || src.includes('from \"hono\"');\r\n\r\n imports.push(`import ${name} from '${imp}';`);\r\n\r\n if (isHonoApp) {\r\n // Hono app: merge directly into root app\r\n mountings.push(`app.route('/', ${name});`);\r\n } else {\r\n // Plain function: wrap in Hono and mount at its route path\r\n mountings.push(`app.all('${route.routePath}', (c) => ${name}(c.req.raw));`);\r\n }\r\n }\r\n\r\n const corsLine = enableCors\r\n ? `app.use('/api/*', cors({ origin: '*', allowMethods: ['GET','POST','PUT','PATCH','DELETE','OPTIONS'], allowHeaders: ['Content-Type','Authorization'] }));`\r\n : null;\r\n\r\n const header = [\r\n `// ⚠️ Auto-generated by bini-router on every build — do not edit.`,\r\n `// Add routes by creating files in src/app/api/ only.`,\r\n ];\r\n\r\n const corsImport = enableCors ? `import { cors } from 'hono/cors';` : null;\r\n\r\n let outFile: string;\r\n let lines : string[];\r\n\r\n const appSetup = [\r\n ``,\r\n `const app = new Hono();`,\r\n ...(corsLine ? [corsLine] : []),\r\n ...mountings,\r\n ];\r\n\r\n if (platform === 'vercel') {\r\n outFile = path.join(cwd, 'api', 'index.ts');\r\n // Vercel runs a Hono app directly as a default export — no handle() wrapper needed.\r\n // Import is from 'hono/vercel' (built into hono, no separate package to install).\r\n lines = [\r\n ...header,\r\n `import { Hono } from 'hono';`,\r\n ...(corsImport ? [corsImport] : []),\r\n ...imports,\r\n ...appSetup,\r\n ``,\r\n `export const runtime = 'edge';`,\r\n `export default app;`,\r\n ];\r\n\r\n } else if (platform === 'cloudflare') {\r\n outFile = path.join(cwd, 'worker.ts');\r\n lines = [\r\n ...header,\r\n `import { Hono } from 'hono';`,\r\n ...(corsImport ? [corsImport] : []),\r\n ...imports,\r\n ...appSetup,\r\n ``,\r\n `export default app;`,\r\n ];\r\n\r\n } else {\r\n // node\r\n outFile = path.join(cwd, 'server', 'index.ts');\r\n lines = [\r\n ...header,\r\n `import { Hono } from 'hono';`,\r\n `import { serve } from '@hono/node-server';`,\r\n `import { serveStatic } from '@hono/node-server/serve-static';`,\r\n ...(corsImport ? [corsImport] : []),\r\n ...imports,\r\n ...appSetup,\r\n `app.use('/*', serveStatic({ root: './dist' }));`,\r\n `app.use('/*', serveStatic({ path: './dist/index.html' }));`,\r\n ``,\r\n `serve({ fetch: app.fetch, port: Number(process.env.PORT ?? 3000) }, (i) => {`,\r\n ` console.log(\\`Server running on http://localhost:\\${i.port}\\`);`,\r\n `});`,\r\n ];\r\n }\r\n\r\n fs.mkdirSync(path.dirname(outFile), { recursive: true });\r\n fs.writeFileSync(outFile, lines.join('\\n') + '\\n', 'utf8');\r\n console.log(`[bini-router] ✓ Generated ${norm(path.relative(cwd, outFile))}`);\r\n}\r\n\r\n// ─── Plugin ───────────────────────────────────────────────────────────────────\r\n\r\nexport function biniroute(options: BiniPluginOptions = {}): Plugin {\r\n const { cors: enableCors = true, platform } = options;\r\n\r\n const getAppDir = () => path.join(process.cwd(), options.appDir ?? 'src/app');\r\n const getApiDir = () => path.join(process.cwd(), options.apiDir ?? 'src/app/api');\r\n\r\n // ── Per-instance state (fixes shared-state bug) ───────────────────────────\r\n let debounceTimer : ReturnType<typeof setTimeout> | null = null;\r\n let lastGeneratedCode = '';\r\n let honoCache : { routes: ApiRoute[] } | null = null;\r\n const eventLog = new Map<string, number>();\r\n\r\n function shouldProcess(file: string, event: string): boolean {\r\n const key = `${file}:${event}`;\r\n const now = Date.now();\r\n if (now - (eventLog.get(key) ?? 0) < EVENT_DEDUP_MS) return false;\r\n eventLog.set(key, now);\r\n for (const [k, v] of eventLog) if (now - v > EVENT_TTL_MS) eventLog.delete(k);\r\n return true;\r\n }\r\n\r\n // Only trigger regen for page/layout files, not utils/hooks.\r\n // Uses forward-slash comparison to work correctly on Windows.\r\n function isPageFile(f: string): boolean {\r\n const nf = norm(f);\r\n const base = path.basename(f, path.extname(f));\r\n const ext = path.extname(f);\r\n if (!(SUPPORTED_EXTS as readonly string[]).includes(ext)) return false;\r\n if (!isInDir(nf, norm(getAppDir()))) return false;\r\n if (isInDir(nf, norm(getApiDir()))) return false;\r\n if (base.startsWith('_')) return false;\r\n return true;\r\n }\r\n\r\n function isApiFile(f: string): boolean {\r\n const nf = norm(f);\r\n return isInDir(nf, norm(getApiDir())) &&\r\n (API_EXTS as readonly string[]).includes(path.extname(f));\r\n }\r\n\r\n // Single helper used by both config/buildStart and scheduleRegen.\r\n function applyApp(): string | null {\r\n const dir = getAppDir();\r\n if (!fs.existsSync(dir)) return null;\r\n const code = generateApp(dir);\r\n if (code === lastGeneratedCode) return null;\r\n fs.writeFileSync(getAppFile(), code, 'utf8');\r\n lastGeneratedCode = code;\r\n return code;\r\n }\r\n\r\n function scheduleRegen(server: ViteDevServer, delay = DEBOUNCE_MS) {\r\n if (debounceTimer) clearTimeout(debounceTimer);\r\n debounceTimer = setTimeout(() => {\r\n debounceTimer = null;\r\n if (applyApp() !== null) {\r\n server.ws.send({ type: 'full-reload', path: '*' });\r\n }\r\n }, delay);\r\n }\r\n\r\n // Preview server needs SPA fallback so direct URL navigation works.\r\n function addSpaFallback(server: { middlewares: any }) {\r\n server.middlewares.use((req: any, res: any, next: any) => {\r\n const url = req.url as string;\r\n // Let Vite handle static assets and the API\r\n if (url.startsWith('/api') || url.includes('.')) return next();\r\n // Rewrite everything else to index.html for client-side routing\r\n req.url = '/index.html';\r\n next();\r\n });\r\n }\r\n\r\n return {\r\n name : 'bini-router',\r\n enforce: 'pre',\r\n\r\n // Strip `export const metadata = {...}` from all src/app files before\r\n // @vitejs/plugin-react's Fast Refresh transform sees them.\r\n transform(code, id) {\r\n const nid = norm(id);\r\n if (!isInDir(nid, norm(getAppDir()))) return;\r\n const ext = path.extname(id);\r\n if (!(SUPPORTED_EXTS as readonly string[]).includes(ext)) return;\r\n if (!code.includes('export const metadata')) return;\r\n\r\n let result = code;\r\n let idx = result.indexOf('export const metadata');\r\n\r\n while (idx !== -1) {\r\n const braceIdx = result.indexOf('{', idx);\r\n if (braceIdx === -1) break;\r\n\r\n let depth = 0, end = braceIdx;\r\n for (let i = braceIdx; i < result.length; i++) {\r\n if (result[i] === '{') depth++;\r\n else if (result[i] === '}') { depth--; if (depth === 0) { end = i; break; } }\r\n }\r\n\r\n let tail = end + 1;\r\n while (tail < result.length && (result[tail] === ' ' || result[tail] === '\\t')) tail++;\r\n if (tail < result.length && result[tail] === ';') tail++;\r\n while (tail < result.length && (result[tail] === '\\n' || result[tail] === '\\r')) tail++;\r\n\r\n result = result.slice(0, idx) + result.slice(tail);\r\n idx = result.indexOf('export const metadata', idx);\r\n }\r\n\r\n return { code: result, map: null };\r\n },\r\n\r\n config() { applyApp(); },\r\n buildStart() { applyApp(); },\r\n\r\n closeBundle() {\r\n if (platform) buildProductionEntry(getApiDir(), platform, enableCors);\r\n },\r\n\r\n buildEnd() {\r\n // Clear caches between builds so stale routes/modules don't persist.\r\n honoCache = null;\r\n moduleCache.clear();\r\n if (debounceTimer) { clearTimeout(debounceTimer); debounceTimer = null; }\r\n },\r\n\r\n async configureServer(server) {\r\n const appDir = getAppDir();\r\n const apiDir = getApiDir();\r\n\r\n if (!fs.existsSync(appDir)) return;\r\n\r\n server.watcher.add(appDir);\r\n\r\n server.watcher.on('add', f => isPageFile(f) && shouldProcess(f, 'add') && scheduleRegen(server, 300));\r\n server.watcher.on('unlink', f => isPageFile(f) && shouldProcess(f, 'unlink') && scheduleRegen(server));\r\n server.watcher.on('change', f => isPageFile(f) && shouldProcess(f, 'change') && scheduleRegen(server));\r\n\r\n // When root layout.tsx changes, re-run transformIndexHtml with fresh metadata.\r\n server.watcher.on('change', f => {\r\n const base = path.basename(f, path.extname(f));\r\n const inAppRoot = path.resolve(path.dirname(f)) === path.resolve(appDir);\r\n if (!inAppRoot || base !== 'layout') return;\r\n server.moduleGraph.invalidateAll();\r\n server.ws.send({ type: 'full-reload', path: '*' });\r\n });\r\n\r\n server.watcher.on('addDir', d => {\r\n const nd = norm(d);\r\n if (!isInDir(nd, norm(appDir)) || d.includes('node_modules') || isInDir(nd, norm(apiDir))) return;\r\n setTimeout(() => PAGE_FILES.some(f => fs.existsSync(path.join(d, f))) && scheduleRegen(server), 300);\r\n });\r\n\r\n server.watcher.on('unlinkDir', d => {\r\n const nd = norm(d);\r\n if (isInDir(nd, norm(appDir)) && !d.includes('node_modules') && !isInDir(nd, norm(apiDir)))\r\n scheduleRegen(server);\r\n });\r\n\r\n if (fs.existsSync(apiDir)) {\r\n server.watcher.add(apiDir);\r\n\r\n const resetApi = (f?: string) => {\r\n honoCache = null;\r\n // Clear the module cache entry for this specific file so importHandler\r\n // re-imports it on the next request rather than serving a stale handler.\r\n if (f) moduleCache.delete(f);\r\n server.ws.send({ type: 'full-reload', path: '*' });\r\n };\r\n\r\n server.watcher.on('add', f => isApiFile(f) && resetApi(f));\r\n server.watcher.on('unlink', f => isApiFile(f) && resetApi(f));\r\n server.watcher.on('change', f => isApiFile(f) && resetApi(f));\r\n\r\n server.middlewares.use((req: any, res: any, next: any) => {\r\n if (!req.url?.startsWith('/api')) return next();\r\n handleApiRequest(req, res, next, apiDir, enableCors,\r\n () => honoCache, (v) => { honoCache = v; });\r\n });\r\n }\r\n },\r\n\r\n async configurePreviewServer(server) {\r\n // SPA fallback so /register etc. don't 404 in preview mode.\r\n addSpaFallback(server);\r\n\r\n const apiDir = getApiDir();\r\n if (!fs.existsSync(apiDir)) return;\r\n server.middlewares.use((req: any, res: any, next: any) => {\r\n if (!req.url?.startsWith('/api')) return next();\r\n handleApiRequest(req, res, next, apiDir, enableCors,\r\n () => honoCache, (v) => { honoCache = v; });\r\n });\r\n },\r\n\r\n transformIndexHtml: {\r\n order: 'pre',\r\n handler(html) {\r\n const meta = parseAppMetadata(getAppDir());\r\n\r\n // If no layout or metadata found, leave the HTML completely untouched.\r\n // Stripping tags without re-injecting them would break the page.\r\n if (!meta.title && !meta.description && !meta.canonical && !meta.manifest &&\r\n !meta.openGraph?.title && !meta.icons?.icon?.length) {\r\n return html;\r\n }\r\n\r\n const title = meta.title ?? 'Bini App';\r\n const vp = meta.viewport ?? 'width=device-width, initial-scale=1.0';\r\n\r\n const lines: string[] = [];\r\n\r\n lines.push(`<meta charset=\"${meta.charset ?? 'UTF-8'}\" />`);\r\n lines.push(`<meta name=\"viewport\" content=\"${vp}\" />`);\r\n lines.push(`<title>${title}</title>`);\r\n if (meta.description) lines.push(`<meta name=\"description\" content=\"${meta.description}\" />`);\r\n if (meta.themeColor) lines.push(`<meta name=\"theme-color\" content=\"${meta.themeColor}\" />`);\r\n if (meta.robots) lines.push(`<meta name=\"robots\" content=\"${meta.robots}\" />`);\r\n if (meta.keywords) lines.push(`<meta name=\"keywords\" content=\"${meta.keywords}\" />`);\r\n if (meta.author) lines.push(`<meta name=\"author\" content=\"${meta.author}\" />`);\r\n if (meta.canonical) lines.push(`<link rel=\"canonical\" href=\"${meta.canonical}\" />`);\r\n if (meta.manifest) lines.push(`<link rel=\"manifest\" href=\"${meta.manifest}\" />`);\r\n\r\n for (const entry of meta.icons?.icon ?? []) {\r\n const type = entry.type ? ` type=\"${entry.type}\"` : '';\r\n const sizes = entry.sizes ? ` sizes=\"${entry.sizes}\"` : '';\r\n lines.push(`<link rel=\"icon\" href=\"${entry.url}\"${type}${sizes} />`);\r\n }\r\n for (const entry of meta.icons?.shortcut ?? []) {\r\n lines.push(`<link rel=\"shortcut icon\" href=\"${entry.url}\" />`);\r\n }\r\n for (const entry of meta.icons?.apple ?? []) {\r\n const sizes = entry.sizes ? ` sizes=\"${entry.sizes}\"` : '';\r\n const type = entry.type ? ` type=\"${entry.type}\"` : '';\r\n lines.push(`<link rel=\"apple-touch-icon\" href=\"${entry.url}\"${sizes}${type} />`);\r\n }\r\n\r\n if (meta.openGraph?.title) {\r\n lines.push(`<meta property=\"og:type\" content=\"${meta.openGraph.type ?? 'website'}\" />`);\r\n lines.push(`<meta property=\"og:title\" content=\"${meta.openGraph.title}\" />`);\r\n if (meta.openGraph.description) lines.push(`<meta property=\"og:description\" content=\"${meta.openGraph.description}\" />`);\r\n if (meta.openGraph.url) lines.push(`<meta property=\"og:url\" content=\"${meta.openGraph.url}\" />`);\r\n if (meta.openGraph.image) lines.push(`<meta property=\"og:image\" content=\"${meta.openGraph.image}\" />`);\r\n }\r\n\r\n if (meta.twitter?.title) {\r\n lines.push(`<meta name=\"twitter:card\" content=\"${meta.twitter.card ?? 'summary_large_image'}\" />`);\r\n lines.push(`<meta name=\"twitter:title\" content=\"${meta.twitter.title}\" />`);\r\n if (meta.twitter.description) lines.push(`<meta name=\"twitter:description\" content=\"${meta.twitter.description}\" />`);\r\n if (meta.twitter.creator) lines.push(`<meta name=\"twitter:creator\" content=\"${meta.twitter.creator}\" />`);\r\n if (meta.twitter.image) lines.push(`<meta name=\"twitter:image\" content=\"${meta.twitter.image}\" />`);\r\n }\r\n\r\n const injected = lines.map(l => ` ${l}`).join('\\n');\r\n return html.replace('</head>', `${injected}\\n </head>`);\r\n },\r\n },\r\n };\r\n}\r\n\r\nexport default biniroute;"],"mappings":"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","names":["path","fs","isCatchAll","isDynamic"]}
package/dist/index.js CHANGED
@@ -561,7 +561,7 @@ async function handleApiRequest(req, res, next, apiDir, enableCors, getCache, se
561
561
  }
562
562
  let cache = getCache();
563
563
  if (!cache) {
564
- cache = { routes: scanApiRoutes(apiDir) };
564
+ cache = { routes: scanApiRoutes(apiDir, "/api") };
565
565
  setCache(cache);
566
566
  }
567
567
  const host = req.headers.host ?? "localhost";
@@ -888,6 +888,9 @@ function biniroute(options = {}) {
888
888
  order: "pre",
889
889
  handler(html) {
890
890
  const meta = parseAppMetadata(getAppDir());
891
+ if (!meta.title && !meta.description && !meta.canonical && !meta.manifest && !meta.openGraph?.title && !meta.icons?.icon?.length) {
892
+ return html;
893
+ }
891
894
  const title = meta.title ?? "Bini App";
892
895
  const vp = meta.viewport ?? "width=device-width, initial-scale=1.0";
893
896
  const lines = [];
@@ -929,7 +932,7 @@ function biniroute(options = {}) {
929
932
  if (meta.twitter.image) lines.push(`<meta name="twitter:image" content="${meta.twitter.image}" />`);
930
933
  }
931
934
  const injected = lines.map((l) => ` ${l}`).join("\n");
932
- return html.replace(/<meta\s+charset[^>]*\/?>/gi, "").replace(/<meta\s+name="viewport"[^>]*\/?>/gi, "").replace(/<meta\s+name="description"[^>]*\/?>/gi, "").replace(/<meta\s+name="theme-color"[^>]*\/?>/gi, "").replace(/<meta\s+name="robots"[^>]*\/?>/gi, "").replace(/<meta\s+name="keywords"[^>]*\/?>/gi, "").replace(/<meta\s+name="author"[^>]*\/?>/gi, "").replace(/<meta\s+property="og:[^"]*"[^>]*\/?>/gi, "").replace(/<meta\s+name="twitter:[^"]*"[^>]*\/?>/gi, "").replace(/<link\s+rel="canonical"[^>]*\/?>/gi, "").replace(/<link\s+rel="manifest"[^>]*\/?>/gi, "").replace(/<link\s+rel="icon"[^>]*\/?>/gi, "").replace(/<link\s+rel="shortcut icon"[^>]*\/?>/gi, "").replace(/<link\s+rel="apple-touch-icon"[^>]*\/?>/gi, "").replace(/<title>.*?<\/title>/si, "").replace("</head>", `${injected}
935
+ return html.replace("</head>", `${injected}
933
936
  </head>`);
934
937
  }
935
938
  }
package/dist/index.js.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"sources":["../src/index.ts"],"sourcesContent":["import fs from 'fs';\r\nimport path from 'path';\r\nimport type { Plugin, ViteDevServer } from 'vite';\r\n\r\n// ─── Constants ────────────────────────────────────────────────────────────────\r\n\r\nconst PAGE_FILES = ['page.tsx', 'page.jsx', 'page.ts', 'page.js'] as const;\r\nconst LAYOUT_FILES = ['layout.tsx', 'layout.jsx', 'layout.ts', 'layout.js'] as const;\r\nconst SUPPORTED_EXTS = ['.tsx', '.jsx', '.ts', '.js'] as const;\r\nconst NOT_FOUND_FILES = SUPPORTED_EXTS.map(e => `not-found${e}`);\r\nconst SPECIAL_BASES = new Set(['page', 'layout', 'not-found', 'loading', 'error']);\r\nconst API_EXTS = ['.ts', '.js'] as const;\r\nconst DEBOUNCE_MS = 60;\r\nconst EVENT_DEDUP_MS = 500;\r\nconst EVENT_TTL_MS = 2000;\r\n\r\n// ─── Metadata Types ───────────────────────────────────────────────────────────\r\n\r\nexport interface IconEntry {\r\n url : string;\r\n type ?: string;\r\n sizes?: string;\r\n}\r\n\r\nexport interface MetaTags {\r\n title ?: string;\r\n description ?: string;\r\n viewport ?: string;\r\n themeColor ?: string;\r\n keywords ?: string;\r\n author ?: string;\r\n charset ?: string;\r\n robots ?: string;\r\n canonical ?: string;\r\n manifest ?: string;\r\n openGraph ?: Partial<OGMeta>;\r\n twitter ?: Partial<TwitterMeta>;\r\n icons ?: {\r\n icon ?: IconEntry[];\r\n shortcut ?: IconEntry[];\r\n apple ?: IconEntry[];\r\n };\r\n}\r\n\r\ninterface OGMeta {\r\n title : string;\r\n description : string;\r\n url : string;\r\n image : string;\r\n type : string;\r\n}\r\n\r\ninterface TwitterMeta {\r\n card : string;\r\n title : string;\r\n description : string;\r\n creator : string;\r\n image : string;\r\n}\r\n\r\n// ─── Types ────────────────────────────────────────────────────────────────────\r\n\r\ninterface RouteNode {\r\n routePath : string;\r\n filePath : string;\r\n layouts : string[];\r\n dynamic : boolean;\r\n}\r\n\r\ninterface LayoutChainGroup {\r\n layouts : string[];\r\n routes : RouteNode[];\r\n}\r\n\r\ninterface ApiRoute {\r\n routePath : string;\r\n filePath : string;\r\n}\r\n\r\nexport interface BiniPluginOptions {\r\n /** Directory for page files. Default: src/app */\r\n appDir?: string;\r\n /** Directory for API routes. Default: src/app/api */\r\n apiDir?: string;\r\n /** Enable CORS headers in the dev-server API middleware. Default: true */\r\n cors?: boolean;\r\n /**\r\n * Target deployment platform. bini-router generates a production entry\r\n * file on every build — users only write code in src/app/api/.\r\n *\r\n * 'vercel' → api/index.ts (no extra install needed)\r\n * 'node' → server/index.ts (install: @hono/node-server)\r\n * 'cloudflare' → worker.ts (install: wrangler)\r\n *\r\n * Default: undefined (no entry generated)\r\n */\r\n platform?: 'vercel' | 'node' | 'cloudflare';\r\n}\r\n\r\n// ─── Utilities ────────────────────────────────────────────────────────────────\r\n\r\n// Normalize to forward slashes for reliable cross-platform path comparisons.\r\nfunction norm(p: string): string {\r\n return p.replace(/\\\\/g, '/');\r\n}\r\n\r\nfunction isInDir(file: string, dir: string): boolean {\r\n const nFile = norm(file);\r\n const nDir = norm(dir).replace(/\\/$/, '');\r\n return nFile.startsWith(nDir + '/') || nFile === nDir;\r\n}\r\n\r\nfunction readTsconfigAliases(): Record<string, string> {\r\n const aliases: Record<string, string> = {};\r\n try {\r\n const tsconfigPath = path.join(process.cwd(), 'tsconfig.json');\r\n if (!fs.existsSync(tsconfigPath)) return aliases;\r\n const raw = fs.readFileSync(tsconfigPath, 'utf8')\r\n .replace(/\\/\\/.*$/gm, '')\r\n .replace(/\\/\\*[\\s\\S]*?\\*\\//g, '');\r\n const tsconfig = JSON.parse(raw);\r\n const paths = tsconfig?.compilerOptions?.paths ?? {};\r\n const baseUrl = tsconfig?.compilerOptions?.baseUrl ?? '.';\r\n for (const [alias, targets] of Object.entries(paths) as [string, string[]][]) {\r\n const cleanAlias = alias.replace(/\\/\\*$/, '');\r\n const cleanTarget = (targets[0] ?? '').replace(/\\/\\*$/, '');\r\n aliases[cleanAlias] = path.resolve(process.cwd(), baseUrl, cleanTarget);\r\n }\r\n } catch { /* tsconfig unreadable — fall back to relative paths */ }\r\n return aliases;\r\n}\r\n\r\nfunction toImportPath(filePath: string, aliases: Record<string, string>): string {\r\n for (const [alias, target] of Object.entries(aliases)) {\r\n if (norm(filePath).startsWith(norm(target) + '/')) {\r\n const rest = norm(filePath).slice(norm(target).length + 1).replace(/\\.(tsx|ts|jsx|js)$/, '');\r\n return `${alias}/${rest}`;\r\n }\r\n }\r\n return './' + norm(path.relative(path.join(process.cwd(), 'src'), filePath))\r\n .replace(/\\.(tsx|ts|jsx|js)$/, '');\r\n}\r\n\r\nfunction hasDefaultExport(filePath: string): boolean {\r\n try { return fs.readFileSync(filePath, 'utf8').includes('export default'); }\r\n catch { return false; }\r\n}\r\n\r\nfunction isHtmlShellLayout(filePath: string): boolean {\r\n try { return /<html[\\s>]/i.test(fs.readFileSync(filePath, 'utf8')); }\r\n catch { return false; }\r\n}\r\n\r\nfunction isUsableLayout(filePath: string): boolean {\r\n return hasDefaultExport(filePath) && !isHtmlShellLayout(filePath);\r\n}\r\n\r\nfunction findFile(dir: string, candidates: readonly string[]): string | null {\r\n return candidates.find(f => fs.existsSync(path.join(dir, f))) ?? null;\r\n}\r\n\r\nfunction getAppFile(): string {\r\n const ts = path.join(process.cwd(), 'src/App.tsx');\r\n return fs.existsSync(ts) ? ts : path.join(process.cwd(), 'src/App.jsx');\r\n}\r\n\r\n// ─── Layout Resolution ────────────────────────────────────────────────────────\r\n\r\nfunction resolveLayoutChain(pageDir: string, appDir: string): string[] {\r\n const chain: string[] = [];\r\n let current = pageDir;\r\n while (true) {\r\n const layout = findFile(current, LAYOUT_FILES);\r\n if (layout) chain.unshift(path.join(current, layout));\r\n if (path.resolve(current) === path.resolve(appDir)) break;\r\n const parent = path.dirname(current);\r\n if (parent === current) break;\r\n current = parent;\r\n }\r\n return chain;\r\n}\r\n\r\n// ─── Route Scanner ────────────────────────────────────────────────────────────\r\n\r\nfunction scanRoutes(dir: string, appDir: string, baseRoute = ''): RouteNode[] {\r\n const routes: RouteNode[] = [];\r\n if (!fs.existsSync(dir)) return routes;\r\n\r\n let entries: fs.Dirent[];\r\n try { entries = fs.readdirSync(dir, { withFileTypes: true }); }\r\n catch { return routes; }\r\n\r\n // File-based: about.tsx → /about\r\n for (const entry of entries) {\r\n if (!entry.isFile() || entry.name.startsWith('.') || entry.name.startsWith('_')) continue;\r\n const ext = path.extname(entry.name);\r\n const base = path.basename(entry.name, ext);\r\n if (!(SUPPORTED_EXTS as readonly string[]).includes(ext)) continue;\r\n if (SPECIAL_BASES.has(base)) continue;\r\n routes.push({\r\n routePath : `${baseRoute}/${base}`,\r\n filePath : path.join(dir, entry.name),\r\n layouts : resolveLayoutChain(dir, appDir),\r\n dynamic : false,\r\n });\r\n }\r\n\r\n // Directory-based: [id]/page.tsx → /:id\r\n for (const entry of entries) {\r\n if (!entry.isDirectory()) continue;\r\n if (entry.name === 'node_modules' || entry.name.startsWith('.') || entry.name === 'api') continue;\r\n\r\n const fullPath = path.join(dir, entry.name);\r\n const isDynamic = entry.name.startsWith('[') && entry.name.endsWith(']');\r\n const segment = isDynamic ? `:${entry.name.slice(1, -1)}` : entry.name;\r\n const routePath = `${baseRoute}/${segment}`;\r\n\r\n const pageFile = findFile(fullPath, PAGE_FILES);\r\n if (pageFile) {\r\n routes.push({\r\n routePath,\r\n filePath : path.join(fullPath, pageFile),\r\n layouts : resolveLayoutChain(fullPath, appDir),\r\n dynamic : isDynamic,\r\n });\r\n }\r\n routes.push(...scanRoutes(fullPath, appDir, routePath));\r\n }\r\n\r\n return routes;\r\n}\r\n\r\n// Detect duplicate routePaths and keep the first encountered (file-based wins\r\n// over directory-based since we unshift the root page before sorting).\r\nfunction deduplicateRoutes(routes: RouteNode[]): RouteNode[] {\r\n const seen = new Set<string>();\r\n return routes.filter(r => {\r\n if (seen.has(r.routePath)) return false;\r\n seen.add(r.routePath);\r\n return true;\r\n });\r\n}\r\n\r\n// ─── Per-layout title extractor ──────────────────────────────────────────────\r\n\r\nfunction parseLayoutTitle(layoutFile: string): string | null {\r\n let src = '';\r\n try { src = fs.readFileSync(layoutFile, 'utf8'); }\r\n catch { return null; }\r\n\r\n const startIdx = src.indexOf('export const metadata');\r\n if (startIdx === -1) return null;\r\n const braceStart = src.indexOf('{', startIdx);\r\n if (braceStart === -1) return null;\r\n\r\n let depth = 0, end = braceStart;\r\n for (let i = braceStart; i < src.length; i++) {\r\n if (src[i] === '{') depth++;\r\n else if (src[i] === '}') { depth--; if (depth === 0) { end = i; break; } }\r\n }\r\n const block = src.slice(braceStart, end + 1);\r\n const match = /['\"]?title['\"]?\\s*:\\s*['\"`]([^'\"`]+)['\"`]/.exec(block);\r\n return match ? match[1] : null;\r\n}\r\n\r\n// ─── Route Tree Renderer ──────────────────────────────────────────────────────\r\n\r\nfunction renderChain(\r\n layouts : string[],\r\n routesInChain : RouteNode[],\r\n layoutNames : Map<string, string>,\r\n pageNames : Map<string, string>,\r\n layoutTitles : Map<string, string>,\r\n indent : number,\r\n): string {\r\n const pad = ' '.repeat(indent);\r\n if (layouts.length === 0) {\r\n return routesInChain.map(r =>\r\n `${pad}<Route path=\"${r.routePath}\" element={<Suspense fallback={<Spinner />}><ErrorBoundary><${pageNames.get(r.filePath)} /></ErrorBoundary></Suspense>} />`\r\n ).join('\\n');\r\n }\r\n const [head, ...tail] = layouts;\r\n const title = layoutTitles.get(head);\r\n // TitleSetter is rendered OUTSIDE ErrorBoundary so a layout crash doesn't\r\n // prevent the title from updating.\r\n const titleSetter = title ? `<TitleSetter title=${JSON.stringify(title)} />` : '';\r\n const inner = renderChain(tail, routesInChain, layoutNames, pageNames, layoutTitles, indent + 2);\r\n const name = layoutNames.get(head);\r\n return [\r\n `${pad}<Route element={<>${titleSetter}<Suspense fallback={<Spinner />}><ErrorBoundary><${name}><Outlet /></${name}></ErrorBoundary></Suspense></>}>`,\r\n inner,\r\n `${pad}</Route>`,\r\n ].join('\\n');\r\n}\r\n\r\n// ─── App Generator ────────────────────────────────────────────────────────────\r\n\r\nfunction generateApp(appDir: string): string {\r\n const aliases = readTsconfigAliases();\r\n const routes = scanRoutes(appDir, appDir);\r\n\r\n const rootPage = findFile(appDir, PAGE_FILES);\r\n if (rootPage) {\r\n routes.unshift({\r\n routePath : '/',\r\n filePath : path.join(appDir, rootPage),\r\n layouts : resolveLayoutChain(appDir, appDir),\r\n dynamic : false,\r\n });\r\n }\r\n\r\n // Strip html-shell layouts and layouts with no default export.\r\n const routesFiltered = routes.map(r => ({\r\n ...r,\r\n layouts: r.layouts.filter(l => isUsableLayout(l)),\r\n }));\r\n\r\n // Only include routes whose page file has a default export.\r\n const validRoutes = deduplicateRoutes(\r\n routesFiltered.filter(r => hasDefaultExport(r.filePath))\r\n );\r\n\r\n validRoutes.sort((a, b) => {\r\n if (a.dynamic !== b.dynamic) return a.dynamic ? 1 : -1;\r\n return a.routePath.length - b.routePath.length;\r\n });\r\n\r\n const notFoundFile = NOT_FOUND_FILES.find(f => fs.existsSync(path.join(appDir, f)));\r\n const notFound = notFoundFile && hasDefaultExport(path.join(appDir, notFoundFile))\r\n ? notFoundFile\r\n : undefined;\r\n\r\n const allLayouts = new Set<string>();\r\n for (const r of validRoutes) r.layouts.forEach(l => {\r\n if (isUsableLayout(l)) allLayouts.add(l);\r\n });\r\n\r\n const layoutNames = new Map<string, string>();\r\n const pageNames = new Map<string, string>();\r\n const layoutTitles = new Map<string, string>();\r\n let li = 0, pi = 0;\r\n for (const l of allLayouts) {\r\n layoutNames.set(l, `Layout${li++}`);\r\n const title = parseLayoutTitle(l);\r\n if (title) layoutTitles.set(l, title);\r\n }\r\n for (const r of validRoutes) {\r\n if (!pageNames.has(r.filePath)) pageNames.set(r.filePath, `Page${pi++}`);\r\n }\r\n\r\n const lazyImports: string[] = [];\r\n for (const [fp, name] of layoutNames)\r\n lazyImports.push(`const ${name} = React.lazy(() => import('${toImportPath(fp, aliases)}'));`);\r\n if (notFound)\r\n lazyImports.push(`const NotFound = React.lazy(() => import('${toImportPath(path.join(appDir, notFound), aliases)}'));`);\r\n const emittedPages = new Set<string>();\r\n for (const r of validRoutes) {\r\n if (emittedPages.has(r.filePath)) continue;\r\n emittedPages.add(r.filePath);\r\n const name = pageNames.get(r.filePath);\r\n if (!name) continue;\r\n lazyImports.push(`const ${name} = React.lazy(() => import('${toImportPath(r.filePath, aliases)}'));`);\r\n }\r\n\r\n const chainMap = new Map<string, LayoutChainGroup>();\r\n for (const r of validRoutes) {\r\n const key = r.layouts.join('|');\r\n if (!chainMap.has(key)) chainMap.set(key, { layouts: r.layouts, routes: [] });\r\n chainMap.get(key)!.routes.push(r);\r\n }\r\n\r\n const routeLines: string[] = [];\r\n for (const [, { layouts, routes: cr }] of chainMap)\r\n routeLines.push(renderChain(layouts, cr, layoutNames, pageNames, layoutTitles, 8));\r\n\r\n const catchAll = notFound\r\n ? ` <Route path=\"*\" element={<Suspense fallback={<Spinner />}><NotFound /></Suspense>} />`\r\n : ` <Route path=\"*\" element={<Default404 />} />`;\r\n\r\n return `// ⚠️ Auto-generated by bini-router — do not edit.\r\nimport React, { Suspense } from 'react';\r\nimport { BrowserRouter, Routes, Route, Outlet } from 'react-router-dom';\r\nimport './app/globals.css';\r\n\r\n${lazyImports.join('\\n')}\r\n\r\n// ─── Error Boundary ───────────────────────────────────────────────────────────\r\nclass ErrorBoundary extends React.Component<\r\n { children: React.ReactNode },\r\n { error: Error | null }\r\n> {\r\n constructor(props: { children: React.ReactNode }) {\r\n super(props);\r\n this.state = { error: null };\r\n }\r\n static getDerivedStateFromError(error: Error) { return { error }; }\r\n override render() {\r\n if (this.state.error) return (\r\n <div style={{ minHeight: '100vh', display: 'flex', alignItems: 'center', justifyContent: 'center', fontFamily: 'system-ui,sans-serif', padding: '2rem' }}>\r\n <div style={{ maxWidth: 480, width: '100%', textAlign: 'center' }}>\r\n <h2 style={{ color: '#e74c3c', marginBottom: '1rem' }}>Something went wrong</h2>\r\n <pre style={{ background: '#fef2f2', padding: '1rem', borderRadius: '0.5rem', textAlign: 'left', fontSize: '0.8rem', color: '#e74c3c', overflow: 'auto' }}>{this.state.error.toString()}</pre>\r\n <button onClick={() => this.setState({ error: null })} style={{ marginTop: '1rem', padding: '0.5rem 1.5rem', background: '#00CFFF', color: 'white', border: 'none', borderRadius: '0.5rem', cursor: 'pointer', fontWeight: 600 }}>\r\n Try again\r\n </button>\r\n </div>\r\n </div>\r\n );\r\n return this.props.children;\r\n }\r\n}\r\n\r\nfunction Spinner() {\r\n return (\r\n <div style={{ minHeight: '100vh', display: 'flex', alignItems: 'center', justifyContent: 'center' }}>\r\n <div style={{ width: 32, height: 32, border: '3px solid #eee', borderTop: '3px solid #00CFFF', borderRadius: '50%', animation: 'spin 0.8s linear infinite' }} />\r\n <style>{\\`@keyframes spin{to{transform:rotate(360deg)}}\\`}</style>\r\n </div>\r\n );\r\n}\r\n\r\n// Renders nothing — just sets document.title when the layout mounts.\r\n// Placed outside ErrorBoundary so a layout crash doesn't block the title update.\r\nfunction TitleSetter({ title }: { title: string }) {\r\n React.useEffect(() => { document.title = title; }, [title]);\r\n return null;\r\n}\r\n\r\n${notFound ? '' : `function Default404() {\r\n return (\r\n <div style={{ minHeight: '100vh', display: 'flex', alignItems: 'center', justifyContent: 'center', background: 'linear-gradient(135deg,#00CFFF,#0077FF)', color: 'white', fontFamily: 'system-ui,sans-serif' }}>\r\n <div style={{ textAlign: 'center' }}>\r\n <h1 style={{ fontSize: '5rem', fontWeight: 800, margin: 0 }}>404</h1>\r\n <p style={{ fontSize: '1.25rem', margin: '0.5rem 0 2rem' }}>Page not found</p>\r\n <a href=\"/\" style={{ padding: '0.65rem 1.5rem', background: 'white', color: '#00CFFF', textDecoration: 'none', borderRadius: '0.5rem', fontWeight: 600 }}>← Back to Home</a>\r\n </div>\r\n </div>\r\n );\r\n}`}\r\n\r\nexport default function App() {\r\n return (\r\n <BrowserRouter>\r\n <Routes>\r\n${routeLines.join('\\n')}\r\n${catchAll}\r\n </Routes>\r\n </BrowserRouter>\r\n );\r\n}\r\n`;\r\n}\r\n\r\n// ─── Metadata Parser ──────────────────────────────────────────────────────────\r\n\r\nfunction parseAppMetadata(appDir: string): MetaTags {\r\n const layout = findFile(appDir, LAYOUT_FILES);\r\n if (!layout) return {};\r\n let src = '';\r\n try { src = fs.readFileSync(path.join(appDir, layout), 'utf8'); }\r\n catch { return {}; }\r\n\r\n const startIdx = src.indexOf('export const metadata');\r\n if (startIdx === -1) return {};\r\n const braceStart = src.indexOf('{', startIdx);\r\n if (braceStart === -1) return {};\r\n\r\n let depth = 0, end = braceStart;\r\n for (let i = braceStart; i < src.length; i++) {\r\n if (src[i] === '{') depth++;\r\n else if (src[i] === '}') { depth--; if (depth === 0) { end = i; break; } }\r\n }\r\n const block = src.slice(braceStart, end + 1);\r\n\r\n function extractBlock(source: string, key: string): string | undefined {\r\n const re = new RegExp(`['\"]?${key}['\"]?\\\\s*:\\\\s*\\\\{`);\r\n const match = re.exec(source);\r\n if (!match) return undefined;\r\n let d = 0, i = match.index + match[0].length - 1;\r\n const start = i;\r\n for (; i < source.length; i++) {\r\n if (source[i] === '{') d++;\r\n else if (source[i] === '}') { d--; if (d === 0) return source.slice(start, i + 1); }\r\n }\r\n return undefined;\r\n }\r\n\r\n function extractArray(source: string, key: string): string | undefined {\r\n const re = new RegExp(`['\"]?${key}['\"]?\\\\s*:\\\\s*\\\\[`);\r\n const match = re.exec(source);\r\n if (!match) return undefined;\r\n let d = 0, i = match.index + match[0].length - 1;\r\n const start = i;\r\n for (; i < source.length; i++) {\r\n if (source[i] === '[') d++;\r\n else if (source[i] === ']') { d--; if (d === 0) return source.slice(start, i + 1); }\r\n }\r\n return undefined;\r\n }\r\n\r\n function str(source: string, key: string): string | undefined {\r\n return source.match(\r\n new RegExp(`['\"]?${key}['\"]?\\\\s*:\\\\s*['\"\\`]([^'\"\\`\\n]+)['\"\\`]`)\r\n )?.[1];\r\n }\r\n\r\n function firstArrayStr(source: string, key: string): string | undefined {\r\n const arr = extractArray(source, key);\r\n if (!arr) return undefined;\r\n return arr.match(/url\\s*:\\s*['\"]([^'\"]+)['\"]/)?.[1]\r\n ?? arr.match(/['\"]([^'\"]+)['\"]/)?.[1];\r\n }\r\n\r\n function allArrayStrs(source: string, key: string): string[] {\r\n const arr = extractArray(source, key);\r\n if (!arr) return [];\r\n return [...arr.matchAll(/['\"]([^'\"]+)['\"]/g)].map(m => m[1]);\r\n }\r\n\r\n const meta: MetaTags = {};\r\n\r\n if (str(block, 'title')) meta.title = str(block, 'title');\r\n if (str(block, 'description')) meta.description = str(block, 'description');\r\n if (str(block, 'viewport')) meta.viewport = str(block, 'viewport');\r\n if (str(block, 'themeColor')) meta.themeColor = str(block, 'themeColor');\r\n if (str(block, 'charset')) meta.charset = str(block, 'charset');\r\n if (str(block, 'robots')) meta.robots = str(block, 'robots');\r\n if (str(block, 'canonical')) meta.canonical = str(block, 'canonical');\r\n if (str(block, 'manifest')) meta.manifest = str(block, 'manifest');\r\n\r\n const kwStr = str(block, 'keywords');\r\n if (kwStr) {\r\n meta.keywords = kwStr;\r\n } else {\r\n const kwArr = allArrayStrs(block, 'keywords');\r\n if (kwArr.length) meta.keywords = kwArr.join(', ');\r\n }\r\n\r\n const authorStr = str(block, 'author');\r\n if (authorStr) {\r\n meta.author = authorStr;\r\n } else {\r\n const authorsArr = extractArray(block, 'authors');\r\n if (authorsArr) {\r\n const name = authorsArr.match(/name\\s*:\\s*['\"]([^'\"]+)['\"]/)?.[1];\r\n if (name) meta.author = name;\r\n }\r\n }\r\n\r\n if (!meta.canonical) {\r\n const base = block.match(/metadataBase\\s*:\\s*new\\s+URL\\s*\\(\\s*['\"]([^'\"]+)['\"]/)?.[1];\r\n if (base) meta.canonical = base;\r\n }\r\n\r\n const ogBlock = extractBlock(block, 'openGraph');\r\n if (ogBlock) {\r\n meta.openGraph = {\r\n title : str(ogBlock, 'title'),\r\n description : str(ogBlock, 'description'),\r\n url : str(ogBlock, 'url'),\r\n type : str(ogBlock, 'type'),\r\n image : firstArrayStr(ogBlock, 'images') ?? str(ogBlock, 'image'),\r\n };\r\n }\r\n\r\n const twBlock = extractBlock(block, 'twitter');\r\n if (twBlock) {\r\n meta.twitter = {\r\n card : str(twBlock, 'card'),\r\n title : str(twBlock, 'title'),\r\n description : str(twBlock, 'description'),\r\n creator : str(twBlock, 'creator'),\r\n image : firstArrayStr(twBlock, 'images') ?? str(twBlock, 'image'),\r\n };\r\n }\r\n\r\n const iconsBlock = extractBlock(block, 'icons');\r\n if (iconsBlock) {\r\n meta.icons = {\r\n icon : collectIconEntries(iconsBlock, 'icon'),\r\n shortcut: collectIconEntries(iconsBlock, 'shortcut'),\r\n apple : collectIconEntries(iconsBlock, 'apple'),\r\n };\r\n }\r\n\r\n return meta;\r\n}\r\n\r\nfunction collectIconEntries(source: string, key: string): IconEntry[] {\r\n const arr = extractArrayRaw(source, key);\r\n if (!arr) return [];\r\n const entries: IconEntry[] = [];\r\n const objRe = /\\{([^}]+)\\}/g;\r\n let m: RegExpExecArray | null;\r\n while ((m = objRe.exec(arr)) !== null) {\r\n const obj = m[1];\r\n const url = obj.match(/url\\s*:\\s*['\"]([^'\"]+)['\"]/)?.[1];\r\n if (!url) continue;\r\n entries.push({\r\n url,\r\n type : obj.match(/type\\s*:\\s*['\"]([^'\"]+)['\"]/)?.[1],\r\n sizes: obj.match(/sizes\\s*:\\s*['\"]([^'\"]+)['\"]/)?.[1],\r\n });\r\n }\r\n if (!entries.length) {\r\n return [...arr.matchAll(/['\"]([^'\"]+)['\"]/g)].map(x => ({ url: x[1] }));\r\n }\r\n return entries;\r\n}\r\n\r\nfunction extractArrayRaw(source: string, key: string): string | undefined {\r\n const re = new RegExp(`['\"]?${key}['\"]?\\\\s*:\\\\s*\\\\[`);\r\n const match = re.exec(source);\r\n if (!match) return undefined;\r\n let d = 0, i = match.index + match[0].length - 1;\r\n const start = i;\r\n for (; i < source.length; i++) {\r\n if (source[i] === '[') d++;\r\n else if (source[i] === ']') { d--; if (d === 0) return source.slice(start, i + 1); }\r\n }\r\n return undefined;\r\n}\r\n\r\n// ─── API Route Scanner ────────────────────────────────────────────────────────\r\n\r\nfunction scanApiRoutes(dir: string, baseRoute = ''): ApiRoute[] {\r\n const routes: ApiRoute[] = [];\r\n if (!fs.existsSync(dir)) return routes;\r\n\r\n let entries: fs.Dirent[];\r\n try { entries = fs.readdirSync(dir, { withFileTypes: true }); }\r\n catch { return routes; }\r\n\r\n for (const entry of entries) {\r\n if (entry.name.startsWith('_') || entry.name.startsWith('.')) continue;\r\n const fullPath = path.join(dir, entry.name);\r\n\r\n if (entry.isDirectory()) {\r\n const isCatchAll = entry.name.startsWith('[...') && entry.name.endsWith(']');\r\n const isDynamic = entry.name.startsWith('[') && entry.name.endsWith(']');\r\n const segment = isCatchAll ? '*' : isDynamic ? `:${entry.name.slice(1, -1)}` : entry.name;\r\n routes.push(...scanApiRoutes(fullPath, `${baseRoute}/${segment}`));\r\n continue;\r\n }\r\n\r\n const ext = path.extname(entry.name);\r\n const base = path.basename(entry.name, ext);\r\n if (!(API_EXTS as readonly string[]).includes(ext)) continue;\r\n\r\n const isCatchAll = base.startsWith('[...') && base.endsWith(']');\r\n const isDynamic = base.startsWith('[') && base.endsWith(']');\r\n const routePath = isCatchAll\r\n ? `${baseRoute}/*`\r\n : base === 'index'\r\n ? baseRoute || '/'\r\n : isDynamic\r\n ? `${baseRoute}/:${base.slice(1, -1)}`\r\n : `${baseRoute}/${base}`;\r\n\r\n routes.push({ routePath, filePath: fullPath });\r\n }\r\n\r\n return routes;\r\n}\r\n\r\n// ─── Hono dev/preview server ──────────────────────────────────────────────────\r\n//\r\n// API files in src/app/api/ can export:\r\n// export default new Hono().basePath('/api') ← Hono app (routing handled internally)\r\n// export default async function(req: Request) {...} ← plain function (bini-router matches route)\r\n//\r\n// Module cache: re-imports only when the file's mtime changes, not on every request.\r\n// Route matching: plain functions are matched against their scanned routePath pattern\r\n// before the handler is called — so dynamic params ([id]) are resolved correctly.\r\n\r\n// Matches a URL pathname against a route pattern like /api/users/:id or /api/files/*\r\n// Returns extracted params if matched, or null if not.\r\nfunction matchRoute(pattern: string, pathname: string): Record<string, string> | null {\r\n const patParts = pattern.split('/').filter(Boolean);\r\n const urlParts = pathname.split('/').filter(Boolean);\r\n\r\n // Catch-all: pattern ends with * — match everything after the prefix\r\n const isCatchAll = patParts[patParts.length - 1] === '*';\r\n if (isCatchAll) {\r\n const prefix = patParts.slice(0, -1);\r\n if (urlParts.length < prefix.length) return null;\r\n for (let i = 0; i < prefix.length; i++) {\r\n if (prefix[i].startsWith(':')) continue;\r\n if (prefix[i] !== urlParts[i]) return null;\r\n }\r\n return { '*': urlParts.slice(prefix.length).join('/') };\r\n }\r\n\r\n if (patParts.length !== urlParts.length) return null;\r\n\r\n const params: Record<string, string> = {};\r\n for (let i = 0; i < patParts.length; i++) {\r\n if (patParts[i].startsWith(':')) {\r\n params[patParts[i].slice(1)] = decodeURIComponent(urlParts[i]);\r\n } else if (patParts[i] !== urlParts[i]) {\r\n return null;\r\n }\r\n }\r\n return params;\r\n}\r\n\r\n// Per-file module cache: maps filePath → { mtime, handler }\r\n// Avoids re-importing on every request while still picking up file changes.\r\nconst moduleCache = new Map<string, { mtime: number; handler: unknown }>();\r\n\r\nasync function importHandler(filePath: string): Promise<unknown> {\r\n const { pathToFileURL } = await import('url');\r\n let mtime = 0;\r\n try { mtime = fs.statSync(filePath).mtimeMs; } catch { /* file vanished */ }\r\n\r\n const cached = moduleCache.get(filePath);\r\n if (cached && cached.mtime === mtime) return cached.handler;\r\n\r\n // File changed or not yet cached — re-import with cache-bust\r\n const mod = await import(pathToFileURL(filePath).href + '?t=' + mtime);\r\n const handler = mod.default ?? null;\r\n moduleCache.set(filePath, { mtime, handler });\r\n return handler;\r\n}\r\n\r\nasync function handleApiRequest(\r\n req : any,\r\n res : any,\r\n next : any,\r\n apiDir : string,\r\n enableCors : boolean,\r\n getCache : () => { routes: ApiRoute[] } | null,\r\n setCache : (v: { routes: ApiRoute[] }) => void,\r\n) {\r\n try {\r\n // Handle CORS preflight immediately — no need to hit a handler.\r\n if (enableCors && req.method === 'OPTIONS') {\r\n res.statusCode = 204;\r\n res.setHeader('Access-Control-Allow-Origin', '*');\r\n res.setHeader('Access-Control-Allow-Methods', 'GET,POST,PUT,PATCH,DELETE,OPTIONS');\r\n res.setHeader('Access-Control-Allow-Headers', 'Content-Type,Authorization');\r\n res.setHeader('Access-Control-Max-Age', '86400');\r\n res.end();\r\n return;\r\n }\r\n\r\n let cache = getCache();\r\n if (!cache) {\r\n cache = { routes: scanApiRoutes(apiDir) };\r\n setCache(cache);\r\n }\r\n\r\n const host = req.headers.host ?? 'localhost';\r\n const url = `http://${host}${req.url}`;\r\n const pathname = new URL(url).pathname;\r\n\r\n const chunks: Buffer[] = [];\r\n for await (const chunk of req) chunks.push(chunk as Buffer);\r\n const body = chunks.length > 0 ? Buffer.concat(chunks) : undefined;\r\n\r\n const method = (req.method as string).toUpperCase();\r\n\r\n const webReq = new Request(url, {\r\n method,\r\n headers: req.headers as HeadersInit,\r\n body : !['GET', 'HEAD'].includes(method) && body?.length ? body : undefined,\r\n });\r\n\r\n for (const route of cache.routes) {\r\n const handler = await importHandler(route.filePath);\r\n if (!handler) continue;\r\n\r\n let webRes: Response;\r\n try {\r\n if (typeof (handler as any).fetch === 'function') {\r\n // Hono app — has its own internal router, pass the full request directly.\r\n webRes = await (handler as any).fetch(webReq.clone());\r\n\r\n // Hono returns 404 when no route matched — try next file.\r\n if (webRes.status === 404) continue;\r\n\r\n } else if (typeof handler === 'function') {\r\n // Plain function — match the URL against this file's route pattern first.\r\n // This gives dynamic params ([id] → :id) without the function needing a router.\r\n const params = matchRoute(route.routePath, pathname);\r\n if (params === null) continue; // URL doesn't match this file's pattern\r\n\r\n // Inject matched params into the Request so the handler can read them.\r\n // We attach them as a custom header so no extra dependency is needed.\r\n const existingHeaders: Record<string, string> = {};\r\n webReq.headers.forEach((v, k) => { existingHeaders[k] = v; });\r\n const reqWithParams = new Request(webReq.clone(), {\r\n headers: { ...existingHeaders, 'x-bini-params': JSON.stringify(params) },\r\n });\r\n\r\n webRes = await (handler as (...args: any[]) => Promise<Response>)(reqWithParams);\r\n\r\n } else {\r\n continue;\r\n }\r\n } catch {\r\n continue; // handler threw — not its route, try next\r\n }\r\n\r\n // Build final headers — Response.headers is immutable so copy to plain object first\r\n const finalHeaders: Record<string, string> = {};\r\n webRes.headers.forEach((v, k) => { finalHeaders[k] = v; });\r\n if (enableCors) {\r\n finalHeaders['access-control-allow-origin'] = '*';\r\n finalHeaders['access-control-allow-methods'] = 'GET,POST,PUT,PATCH,DELETE,OPTIONS';\r\n finalHeaders['access-control-allow-headers'] = 'Content-Type,Authorization';\r\n }\r\n\r\n res.statusCode = webRes.status;\r\n for (const [k, v] of Object.entries(finalHeaders)) res.setHeader(k, v);\r\n res.end(Buffer.from(await webRes.arrayBuffer()));\r\n return;\r\n }\r\n\r\n // No handler matched\r\n res.statusCode = 404;\r\n res.setHeader('Content-Type', 'application/json');\r\n res.end(JSON.stringify({ error: `No API handler found for ${req.url}` }));\r\n } catch (e: any) {\r\n next(e);\r\n }\r\n}\r\n\r\n// ─── Production Entry Generator ───────────────────────────────────────────────\r\n//\r\n// Mirrors what SvelteKit/Nuxt adapters do at build time:\r\n// scan src/app/api/, merge all handlers, wrap with the platform adapter.\r\n// User writes only in src/app/api/ — never touches the generated entry file.\r\n//\r\n// Supports both export styles:\r\n// export default new Hono() ← merged via .route()\r\n// export default async function handler(req: Request) {...} ← wrapped in Hono app\r\n\r\nfunction buildProductionEntry(srcApiDir: string, platform: 'vercel' | 'node' | 'cloudflare', enableCors: boolean): void {\r\n if (!fs.existsSync(srcApiDir)) return;\r\n\r\n const routes = scanApiRoutes(srcApiDir);\r\n const cwd = process.cwd();\r\n\r\n const imports : string[] = [];\r\n const mountings: string[] = [];\r\n\r\n for (let i = 0; i < routes.length; i++) {\r\n const route = routes[i];\r\n const rel = norm(path.relative(cwd, route.filePath)).replace(/\\.(ts|tsx)$/, '');\r\n const imp = rel.startsWith('.') ? rel : `./${rel}`;\r\n const name = `_route${i}`;\r\n\r\n // Detect at build time whether this file exports a Hono app or a plain function\r\n // by reading the source — if it imports from 'hono' it's a Hono app, otherwise wrap it.\r\n let src = '';\r\n try { src = fs.readFileSync(route.filePath, 'utf8'); } catch { /* skip */ }\r\n const isHonoApp = src.includes(\"from 'hono'\") || src.includes('from \"hono\"');\r\n\r\n imports.push(`import ${name} from '${imp}';`);\r\n\r\n if (isHonoApp) {\r\n // Hono app: merge directly into root app\r\n mountings.push(`app.route('/', ${name});`);\r\n } else {\r\n // Plain function: wrap in Hono and mount at its route path\r\n mountings.push(`app.all('${route.routePath}', (c) => ${name}(c.req.raw));`);\r\n }\r\n }\r\n\r\n const corsLine = enableCors\r\n ? `app.use('/api/*', cors({ origin: '*', allowMethods: ['GET','POST','PUT','PATCH','DELETE','OPTIONS'], allowHeaders: ['Content-Type','Authorization'] }));`\r\n : null;\r\n\r\n const header = [\r\n `// ⚠️ Auto-generated by bini-router on every build — do not edit.`,\r\n `// Add routes by creating files in src/app/api/ only.`,\r\n ];\r\n\r\n const corsImport = enableCors ? `import { cors } from 'hono/cors';` : null;\r\n\r\n let outFile: string;\r\n let lines : string[];\r\n\r\n const appSetup = [\r\n ``,\r\n `const app = new Hono();`,\r\n ...(corsLine ? [corsLine] : []),\r\n ...mountings,\r\n ];\r\n\r\n if (platform === 'vercel') {\r\n outFile = path.join(cwd, 'api', 'index.ts');\r\n // Vercel runs a Hono app directly as a default export — no handle() wrapper needed.\r\n // Import is from 'hono/vercel' (built into hono, no separate package to install).\r\n lines = [\r\n ...header,\r\n `import { Hono } from 'hono';`,\r\n ...(corsImport ? [corsImport] : []),\r\n ...imports,\r\n ...appSetup,\r\n ``,\r\n `export const runtime = 'edge';`,\r\n `export default app;`,\r\n ];\r\n\r\n } else if (platform === 'cloudflare') {\r\n outFile = path.join(cwd, 'worker.ts');\r\n lines = [\r\n ...header,\r\n `import { Hono } from 'hono';`,\r\n ...(corsImport ? [corsImport] : []),\r\n ...imports,\r\n ...appSetup,\r\n ``,\r\n `export default app;`,\r\n ];\r\n\r\n } else {\r\n // node\r\n outFile = path.join(cwd, 'server', 'index.ts');\r\n lines = [\r\n ...header,\r\n `import { Hono } from 'hono';`,\r\n `import { serve } from '@hono/node-server';`,\r\n `import { serveStatic } from '@hono/node-server/serve-static';`,\r\n ...(corsImport ? [corsImport] : []),\r\n ...imports,\r\n ...appSetup,\r\n `app.use('/*', serveStatic({ root: './dist' }));`,\r\n `app.use('/*', serveStatic({ path: './dist/index.html' }));`,\r\n ``,\r\n `serve({ fetch: app.fetch, port: Number(process.env.PORT ?? 3000) }, (i) => {`,\r\n ` console.log(\\`Server running on http://localhost:\\${i.port}\\`);`,\r\n `});`,\r\n ];\r\n }\r\n\r\n fs.mkdirSync(path.dirname(outFile), { recursive: true });\r\n fs.writeFileSync(outFile, lines.join('\\n') + '\\n', 'utf8');\r\n console.log(`[bini-router] ✓ Generated ${norm(path.relative(cwd, outFile))}`);\r\n}\r\n\r\n// ─── Plugin ───────────────────────────────────────────────────────────────────\r\n\r\nexport function biniroute(options: BiniPluginOptions = {}): Plugin {\r\n const { cors: enableCors = true, platform } = options;\r\n\r\n const getAppDir = () => path.join(process.cwd(), options.appDir ?? 'src/app');\r\n const getApiDir = () => path.join(process.cwd(), options.apiDir ?? 'src/app/api');\r\n\r\n // ── Per-instance state (fixes shared-state bug) ───────────────────────────\r\n let debounceTimer : ReturnType<typeof setTimeout> | null = null;\r\n let lastGeneratedCode = '';\r\n let honoCache : { routes: ApiRoute[] } | null = null;\r\n const eventLog = new Map<string, number>();\r\n\r\n function shouldProcess(file: string, event: string): boolean {\r\n const key = `${file}:${event}`;\r\n const now = Date.now();\r\n if (now - (eventLog.get(key) ?? 0) < EVENT_DEDUP_MS) return false;\r\n eventLog.set(key, now);\r\n for (const [k, v] of eventLog) if (now - v > EVENT_TTL_MS) eventLog.delete(k);\r\n return true;\r\n }\r\n\r\n // Only trigger regen for page/layout files, not utils/hooks.\r\n // Uses forward-slash comparison to work correctly on Windows.\r\n function isPageFile(f: string): boolean {\r\n const nf = norm(f);\r\n const base = path.basename(f, path.extname(f));\r\n const ext = path.extname(f);\r\n if (!(SUPPORTED_EXTS as readonly string[]).includes(ext)) return false;\r\n if (!isInDir(nf, norm(getAppDir()))) return false;\r\n if (isInDir(nf, norm(getApiDir()))) return false;\r\n if (base.startsWith('_')) return false;\r\n return true;\r\n }\r\n\r\n function isApiFile(f: string): boolean {\r\n const nf = norm(f);\r\n return isInDir(nf, norm(getApiDir())) &&\r\n (API_EXTS as readonly string[]).includes(path.extname(f));\r\n }\r\n\r\n // Single helper used by both config/buildStart and scheduleRegen.\r\n function applyApp(): string | null {\r\n const dir = getAppDir();\r\n if (!fs.existsSync(dir)) return null;\r\n const code = generateApp(dir);\r\n if (code === lastGeneratedCode) return null;\r\n fs.writeFileSync(getAppFile(), code, 'utf8');\r\n lastGeneratedCode = code;\r\n return code;\r\n }\r\n\r\n function scheduleRegen(server: ViteDevServer, delay = DEBOUNCE_MS) {\r\n if (debounceTimer) clearTimeout(debounceTimer);\r\n debounceTimer = setTimeout(() => {\r\n debounceTimer = null;\r\n if (applyApp() !== null) {\r\n server.ws.send({ type: 'full-reload', path: '*' });\r\n }\r\n }, delay);\r\n }\r\n\r\n // Preview server needs SPA fallback so direct URL navigation works.\r\n function addSpaFallback(server: { middlewares: any }) {\r\n server.middlewares.use((req: any, res: any, next: any) => {\r\n const url = req.url as string;\r\n // Let Vite handle static assets and the API\r\n if (url.startsWith('/api') || url.includes('.')) return next();\r\n // Rewrite everything else to index.html for client-side routing\r\n req.url = '/index.html';\r\n next();\r\n });\r\n }\r\n\r\n return {\r\n name : 'bini-router',\r\n enforce: 'pre',\r\n\r\n // Strip `export const metadata = {...}` from all src/app files before\r\n // @vitejs/plugin-react's Fast Refresh transform sees them.\r\n transform(code, id) {\r\n const nid = norm(id);\r\n if (!isInDir(nid, norm(getAppDir()))) return;\r\n const ext = path.extname(id);\r\n if (!(SUPPORTED_EXTS as readonly string[]).includes(ext)) return;\r\n if (!code.includes('export const metadata')) return;\r\n\r\n let result = code;\r\n let idx = result.indexOf('export const metadata');\r\n\r\n while (idx !== -1) {\r\n const braceIdx = result.indexOf('{', idx);\r\n if (braceIdx === -1) break;\r\n\r\n let depth = 0, end = braceIdx;\r\n for (let i = braceIdx; i < result.length; i++) {\r\n if (result[i] === '{') depth++;\r\n else if (result[i] === '}') { depth--; if (depth === 0) { end = i; break; } }\r\n }\r\n\r\n let tail = end + 1;\r\n while (tail < result.length && (result[tail] === ' ' || result[tail] === '\\t')) tail++;\r\n if (tail < result.length && result[tail] === ';') tail++;\r\n while (tail < result.length && (result[tail] === '\\n' || result[tail] === '\\r')) tail++;\r\n\r\n result = result.slice(0, idx) + result.slice(tail);\r\n idx = result.indexOf('export const metadata', idx);\r\n }\r\n\r\n return { code: result, map: null };\r\n },\r\n\r\n config() { applyApp(); },\r\n buildStart() { applyApp(); },\r\n\r\n closeBundle() {\r\n if (platform) buildProductionEntry(getApiDir(), platform, enableCors);\r\n },\r\n\r\n buildEnd() {\r\n // Clear caches between builds so stale routes/modules don't persist.\r\n honoCache = null;\r\n moduleCache.clear();\r\n if (debounceTimer) { clearTimeout(debounceTimer); debounceTimer = null; }\r\n },\r\n\r\n async configureServer(server) {\r\n const appDir = getAppDir();\r\n const apiDir = getApiDir();\r\n\r\n if (!fs.existsSync(appDir)) return;\r\n\r\n server.watcher.add(appDir);\r\n\r\n server.watcher.on('add', f => isPageFile(f) && shouldProcess(f, 'add') && scheduleRegen(server, 300));\r\n server.watcher.on('unlink', f => isPageFile(f) && shouldProcess(f, 'unlink') && scheduleRegen(server));\r\n server.watcher.on('change', f => isPageFile(f) && shouldProcess(f, 'change') && scheduleRegen(server));\r\n\r\n // When root layout.tsx changes, re-run transformIndexHtml with fresh metadata.\r\n server.watcher.on('change', f => {\r\n const base = path.basename(f, path.extname(f));\r\n const inAppRoot = path.resolve(path.dirname(f)) === path.resolve(appDir);\r\n if (!inAppRoot || base !== 'layout') return;\r\n server.moduleGraph.invalidateAll();\r\n server.ws.send({ type: 'full-reload', path: '*' });\r\n });\r\n\r\n server.watcher.on('addDir', d => {\r\n const nd = norm(d);\r\n if (!isInDir(nd, norm(appDir)) || d.includes('node_modules') || isInDir(nd, norm(apiDir))) return;\r\n setTimeout(() => PAGE_FILES.some(f => fs.existsSync(path.join(d, f))) && scheduleRegen(server), 300);\r\n });\r\n\r\n server.watcher.on('unlinkDir', d => {\r\n const nd = norm(d);\r\n if (isInDir(nd, norm(appDir)) && !d.includes('node_modules') && !isInDir(nd, norm(apiDir)))\r\n scheduleRegen(server);\r\n });\r\n\r\n if (fs.existsSync(apiDir)) {\r\n server.watcher.add(apiDir);\r\n\r\n const resetApi = (f?: string) => {\r\n honoCache = null;\r\n // Clear the module cache entry for this specific file so importHandler\r\n // re-imports it on the next request rather than serving a stale handler.\r\n if (f) moduleCache.delete(f);\r\n server.ws.send({ type: 'full-reload', path: '*' });\r\n };\r\n\r\n server.watcher.on('add', f => isApiFile(f) && resetApi(f));\r\n server.watcher.on('unlink', f => isApiFile(f) && resetApi(f));\r\n server.watcher.on('change', f => isApiFile(f) && resetApi(f));\r\n\r\n server.middlewares.use((req: any, res: any, next: any) => {\r\n if (!req.url?.startsWith('/api')) return next();\r\n handleApiRequest(req, res, next, apiDir, enableCors,\r\n () => honoCache, (v) => { honoCache = v; });\r\n });\r\n }\r\n },\r\n\r\n async configurePreviewServer(server) {\r\n // SPA fallback so /register etc. don't 404 in preview mode.\r\n addSpaFallback(server);\r\n\r\n const apiDir = getApiDir();\r\n if (!fs.existsSync(apiDir)) return;\r\n server.middlewares.use((req: any, res: any, next: any) => {\r\n if (!req.url?.startsWith('/api')) return next();\r\n handleApiRequest(req, res, next, apiDir, enableCors,\r\n () => honoCache, (v) => { honoCache = v; });\r\n });\r\n },\r\n\r\n transformIndexHtml: {\r\n order: 'pre',\r\n handler(html) {\r\n const meta = parseAppMetadata(getAppDir());\r\n const title = meta.title ?? 'Bini App';\r\n const vp = meta.viewport ?? 'width=device-width, initial-scale=1.0';\r\n\r\n const lines: string[] = [];\r\n\r\n lines.push(`<meta charset=\"${meta.charset ?? 'UTF-8'}\" />`);\r\n lines.push(`<meta name=\"viewport\" content=\"${vp}\" />`);\r\n lines.push(`<title>${title}</title>`);\r\n if (meta.description) lines.push(`<meta name=\"description\" content=\"${meta.description}\" />`);\r\n if (meta.themeColor) lines.push(`<meta name=\"theme-color\" content=\"${meta.themeColor}\" />`);\r\n if (meta.robots) lines.push(`<meta name=\"robots\" content=\"${meta.robots}\" />`);\r\n if (meta.keywords) lines.push(`<meta name=\"keywords\" content=\"${meta.keywords}\" />`);\r\n if (meta.author) lines.push(`<meta name=\"author\" content=\"${meta.author}\" />`);\r\n if (meta.canonical) lines.push(`<link rel=\"canonical\" href=\"${meta.canonical}\" />`);\r\n if (meta.manifest) lines.push(`<link rel=\"manifest\" href=\"${meta.manifest}\" />`);\r\n\r\n for (const entry of meta.icons?.icon ?? []) {\r\n const type = entry.type ? ` type=\"${entry.type}\"` : '';\r\n const sizes = entry.sizes ? ` sizes=\"${entry.sizes}\"` : '';\r\n lines.push(`<link rel=\"icon\" href=\"${entry.url}\"${type}${sizes} />`);\r\n }\r\n for (const entry of meta.icons?.shortcut ?? []) {\r\n lines.push(`<link rel=\"shortcut icon\" href=\"${entry.url}\" />`);\r\n }\r\n for (const entry of meta.icons?.apple ?? []) {\r\n const sizes = entry.sizes ? ` sizes=\"${entry.sizes}\"` : '';\r\n const type = entry.type ? ` type=\"${entry.type}\"` : '';\r\n lines.push(`<link rel=\"apple-touch-icon\" href=\"${entry.url}\"${sizes}${type} />`);\r\n }\r\n\r\n if (meta.openGraph?.title) {\r\n lines.push(`<meta property=\"og:type\" content=\"${meta.openGraph.type ?? 'website'}\" />`);\r\n lines.push(`<meta property=\"og:title\" content=\"${meta.openGraph.title}\" />`);\r\n if (meta.openGraph.description) lines.push(`<meta property=\"og:description\" content=\"${meta.openGraph.description}\" />`);\r\n if (meta.openGraph.url) lines.push(`<meta property=\"og:url\" content=\"${meta.openGraph.url}\" />`);\r\n if (meta.openGraph.image) lines.push(`<meta property=\"og:image\" content=\"${meta.openGraph.image}\" />`);\r\n }\r\n\r\n if (meta.twitter?.title) {\r\n lines.push(`<meta name=\"twitter:card\" content=\"${meta.twitter.card ?? 'summary_large_image'}\" />`);\r\n lines.push(`<meta name=\"twitter:title\" content=\"${meta.twitter.title}\" />`);\r\n if (meta.twitter.description) lines.push(`<meta name=\"twitter:description\" content=\"${meta.twitter.description}\" />`);\r\n if (meta.twitter.creator) lines.push(`<meta name=\"twitter:creator\" content=\"${meta.twitter.creator}\" />`);\r\n if (meta.twitter.image) lines.push(`<meta name=\"twitter:image\" content=\"${meta.twitter.image}\" />`);\r\n }\r\n\r\n const injected = lines.map(l => ` ${l}`).join('\\n');\r\n\r\n return html\r\n .replace(/<meta\\s+charset[^>]*\\/?>/gi, '')\r\n .replace(/<meta\\s+name=\"viewport\"[^>]*\\/?>/gi, '')\r\n .replace(/<meta\\s+name=\"description\"[^>]*\\/?>/gi, '')\r\n .replace(/<meta\\s+name=\"theme-color\"[^>]*\\/?>/gi, '')\r\n .replace(/<meta\\s+name=\"robots\"[^>]*\\/?>/gi, '')\r\n .replace(/<meta\\s+name=\"keywords\"[^>]*\\/?>/gi, '')\r\n .replace(/<meta\\s+name=\"author\"[^>]*\\/?>/gi, '')\r\n .replace(/<meta\\s+property=\"og:[^\"]*\"[^>]*\\/?>/gi, '')\r\n .replace(/<meta\\s+name=\"twitter:[^\"]*\"[^>]*\\/?>/gi, '')\r\n .replace(/<link\\s+rel=\"canonical\"[^>]*\\/?>/gi, '')\r\n .replace(/<link\\s+rel=\"manifest\"[^>]*\\/?>/gi, '')\r\n .replace(/<link\\s+rel=\"icon\"[^>]*\\/?>/gi, '')\r\n .replace(/<link\\s+rel=\"shortcut icon\"[^>]*\\/?>/gi, '')\r\n .replace(/<link\\s+rel=\"apple-touch-icon\"[^>]*\\/?>/gi, '')\r\n .replace(/<title>.*?<\\/title>/si, '')\r\n .replace('</head>', `${injected}\\n </head>`);\r\n },\r\n },\r\n };\r\n}\r\n\r\nexport default biniroute;"],"mappings":"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","names":["isCatchAll","isDynamic"]}
1
+ {"version":3,"sources":["../src/index.ts"],"sourcesContent":["import fs from 'fs';\r\nimport path from 'path';\r\nimport type { Plugin, ViteDevServer } from 'vite';\r\n\r\n// ─── Constants ────────────────────────────────────────────────────────────────\r\n\r\nconst PAGE_FILES = ['page.tsx', 'page.jsx', 'page.ts', 'page.js'] as const;\r\nconst LAYOUT_FILES = ['layout.tsx', 'layout.jsx', 'layout.ts', 'layout.js'] as const;\r\nconst SUPPORTED_EXTS = ['.tsx', '.jsx', '.ts', '.js'] as const;\r\nconst NOT_FOUND_FILES = SUPPORTED_EXTS.map(e => `not-found${e}`);\r\nconst SPECIAL_BASES = new Set(['page', 'layout', 'not-found', 'loading', 'error']);\r\nconst API_EXTS = ['.ts', '.js'] as const;\r\nconst DEBOUNCE_MS = 60;\r\nconst EVENT_DEDUP_MS = 500;\r\nconst EVENT_TTL_MS = 2000;\r\n\r\n// ─── Metadata Types ───────────────────────────────────────────────────────────\r\n\r\nexport interface IconEntry {\r\n url : string;\r\n type ?: string;\r\n sizes?: string;\r\n}\r\n\r\nexport interface MetaTags {\r\n title ?: string;\r\n description ?: string;\r\n viewport ?: string;\r\n themeColor ?: string;\r\n keywords ?: string;\r\n author ?: string;\r\n charset ?: string;\r\n robots ?: string;\r\n canonical ?: string;\r\n manifest ?: string;\r\n openGraph ?: Partial<OGMeta>;\r\n twitter ?: Partial<TwitterMeta>;\r\n icons ?: {\r\n icon ?: IconEntry[];\r\n shortcut ?: IconEntry[];\r\n apple ?: IconEntry[];\r\n };\r\n}\r\n\r\ninterface OGMeta {\r\n title : string;\r\n description : string;\r\n url : string;\r\n image : string;\r\n type : string;\r\n}\r\n\r\ninterface TwitterMeta {\r\n card : string;\r\n title : string;\r\n description : string;\r\n creator : string;\r\n image : string;\r\n}\r\n\r\n// ─── Types ────────────────────────────────────────────────────────────────────\r\n\r\ninterface RouteNode {\r\n routePath : string;\r\n filePath : string;\r\n layouts : string[];\r\n dynamic : boolean;\r\n}\r\n\r\ninterface LayoutChainGroup {\r\n layouts : string[];\r\n routes : RouteNode[];\r\n}\r\n\r\ninterface ApiRoute {\r\n routePath : string;\r\n filePath : string;\r\n}\r\n\r\nexport interface BiniPluginOptions {\r\n /** Directory for page files. Default: src/app */\r\n appDir?: string;\r\n /** Directory for API routes. Default: src/app/api */\r\n apiDir?: string;\r\n /** Enable CORS headers in the dev-server API middleware. Default: true */\r\n cors?: boolean;\r\n /**\r\n * Target deployment platform. bini-router generates a production entry\r\n * file on every build — users only write code in src/app/api/.\r\n *\r\n * 'vercel' → api/index.ts (no extra install needed)\r\n * 'node' → server/index.ts (install: @hono/node-server)\r\n * 'cloudflare' → worker.ts (install: wrangler)\r\n *\r\n * Default: undefined (no entry generated)\r\n */\r\n platform?: 'vercel' | 'node' | 'cloudflare';\r\n}\r\n\r\n// ─── Utilities ────────────────────────────────────────────────────────────────\r\n\r\n// Normalize to forward slashes for reliable cross-platform path comparisons.\r\nfunction norm(p: string): string {\r\n return p.replace(/\\\\/g, '/');\r\n}\r\n\r\nfunction isInDir(file: string, dir: string): boolean {\r\n const nFile = norm(file);\r\n const nDir = norm(dir).replace(/\\/$/, '');\r\n return nFile.startsWith(nDir + '/') || nFile === nDir;\r\n}\r\n\r\nfunction readTsconfigAliases(): Record<string, string> {\r\n const aliases: Record<string, string> = {};\r\n try {\r\n const tsconfigPath = path.join(process.cwd(), 'tsconfig.json');\r\n if (!fs.existsSync(tsconfigPath)) return aliases;\r\n const raw = fs.readFileSync(tsconfigPath, 'utf8')\r\n .replace(/\\/\\/.*$/gm, '')\r\n .replace(/\\/\\*[\\s\\S]*?\\*\\//g, '');\r\n const tsconfig = JSON.parse(raw);\r\n const paths = tsconfig?.compilerOptions?.paths ?? {};\r\n const baseUrl = tsconfig?.compilerOptions?.baseUrl ?? '.';\r\n for (const [alias, targets] of Object.entries(paths) as [string, string[]][]) {\r\n const cleanAlias = alias.replace(/\\/\\*$/, '');\r\n const cleanTarget = (targets[0] ?? '').replace(/\\/\\*$/, '');\r\n aliases[cleanAlias] = path.resolve(process.cwd(), baseUrl, cleanTarget);\r\n }\r\n } catch { /* tsconfig unreadable — fall back to relative paths */ }\r\n return aliases;\r\n}\r\n\r\nfunction toImportPath(filePath: string, aliases: Record<string, string>): string {\r\n for (const [alias, target] of Object.entries(aliases)) {\r\n if (norm(filePath).startsWith(norm(target) + '/')) {\r\n const rest = norm(filePath).slice(norm(target).length + 1).replace(/\\.(tsx|ts|jsx|js)$/, '');\r\n return `${alias}/${rest}`;\r\n }\r\n }\r\n return './' + norm(path.relative(path.join(process.cwd(), 'src'), filePath))\r\n .replace(/\\.(tsx|ts|jsx|js)$/, '');\r\n}\r\n\r\nfunction hasDefaultExport(filePath: string): boolean {\r\n try { return fs.readFileSync(filePath, 'utf8').includes('export default'); }\r\n catch { return false; }\r\n}\r\n\r\nfunction isHtmlShellLayout(filePath: string): boolean {\r\n try { return /<html[\\s>]/i.test(fs.readFileSync(filePath, 'utf8')); }\r\n catch { return false; }\r\n}\r\n\r\nfunction isUsableLayout(filePath: string): boolean {\r\n return hasDefaultExport(filePath) && !isHtmlShellLayout(filePath);\r\n}\r\n\r\nfunction findFile(dir: string, candidates: readonly string[]): string | null {\r\n return candidates.find(f => fs.existsSync(path.join(dir, f))) ?? null;\r\n}\r\n\r\nfunction getAppFile(): string {\r\n const ts = path.join(process.cwd(), 'src/App.tsx');\r\n return fs.existsSync(ts) ? ts : path.join(process.cwd(), 'src/App.jsx');\r\n}\r\n\r\n// ─── Layout Resolution ────────────────────────────────────────────────────────\r\n\r\nfunction resolveLayoutChain(pageDir: string, appDir: string): string[] {\r\n const chain: string[] = [];\r\n let current = pageDir;\r\n while (true) {\r\n const layout = findFile(current, LAYOUT_FILES);\r\n if (layout) chain.unshift(path.join(current, layout));\r\n if (path.resolve(current) === path.resolve(appDir)) break;\r\n const parent = path.dirname(current);\r\n if (parent === current) break;\r\n current = parent;\r\n }\r\n return chain;\r\n}\r\n\r\n// ─── Route Scanner ────────────────────────────────────────────────────────────\r\n\r\nfunction scanRoutes(dir: string, appDir: string, baseRoute = ''): RouteNode[] {\r\n const routes: RouteNode[] = [];\r\n if (!fs.existsSync(dir)) return routes;\r\n\r\n let entries: fs.Dirent[];\r\n try { entries = fs.readdirSync(dir, { withFileTypes: true }); }\r\n catch { return routes; }\r\n\r\n // File-based: about.tsx → /about\r\n for (const entry of entries) {\r\n if (!entry.isFile() || entry.name.startsWith('.') || entry.name.startsWith('_')) continue;\r\n const ext = path.extname(entry.name);\r\n const base = path.basename(entry.name, ext);\r\n if (!(SUPPORTED_EXTS as readonly string[]).includes(ext)) continue;\r\n if (SPECIAL_BASES.has(base)) continue;\r\n routes.push({\r\n routePath : `${baseRoute}/${base}`,\r\n filePath : path.join(dir, entry.name),\r\n layouts : resolveLayoutChain(dir, appDir),\r\n dynamic : false,\r\n });\r\n }\r\n\r\n // Directory-based: [id]/page.tsx → /:id\r\n for (const entry of entries) {\r\n if (!entry.isDirectory()) continue;\r\n if (entry.name === 'node_modules' || entry.name.startsWith('.') || entry.name === 'api') continue;\r\n\r\n const fullPath = path.join(dir, entry.name);\r\n const isDynamic = entry.name.startsWith('[') && entry.name.endsWith(']');\r\n const segment = isDynamic ? `:${entry.name.slice(1, -1)}` : entry.name;\r\n const routePath = `${baseRoute}/${segment}`;\r\n\r\n const pageFile = findFile(fullPath, PAGE_FILES);\r\n if (pageFile) {\r\n routes.push({\r\n routePath,\r\n filePath : path.join(fullPath, pageFile),\r\n layouts : resolveLayoutChain(fullPath, appDir),\r\n dynamic : isDynamic,\r\n });\r\n }\r\n routes.push(...scanRoutes(fullPath, appDir, routePath));\r\n }\r\n\r\n return routes;\r\n}\r\n\r\n// Detect duplicate routePaths and keep the first encountered (file-based wins\r\n// over directory-based since we unshift the root page before sorting).\r\nfunction deduplicateRoutes(routes: RouteNode[]): RouteNode[] {\r\n const seen = new Set<string>();\r\n return routes.filter(r => {\r\n if (seen.has(r.routePath)) return false;\r\n seen.add(r.routePath);\r\n return true;\r\n });\r\n}\r\n\r\n// ─── Per-layout title extractor ──────────────────────────────────────────────\r\n\r\nfunction parseLayoutTitle(layoutFile: string): string | null {\r\n let src = '';\r\n try { src = fs.readFileSync(layoutFile, 'utf8'); }\r\n catch { return null; }\r\n\r\n const startIdx = src.indexOf('export const metadata');\r\n if (startIdx === -1) return null;\r\n const braceStart = src.indexOf('{', startIdx);\r\n if (braceStart === -1) return null;\r\n\r\n let depth = 0, end = braceStart;\r\n for (let i = braceStart; i < src.length; i++) {\r\n if (src[i] === '{') depth++;\r\n else if (src[i] === '}') { depth--; if (depth === 0) { end = i; break; } }\r\n }\r\n const block = src.slice(braceStart, end + 1);\r\n const match = /['\"]?title['\"]?\\s*:\\s*['\"`]([^'\"`]+)['\"`]/.exec(block);\r\n return match ? match[1] : null;\r\n}\r\n\r\n// ─── Route Tree Renderer ──────────────────────────────────────────────────────\r\n\r\nfunction renderChain(\r\n layouts : string[],\r\n routesInChain : RouteNode[],\r\n layoutNames : Map<string, string>,\r\n pageNames : Map<string, string>,\r\n layoutTitles : Map<string, string>,\r\n indent : number,\r\n): string {\r\n const pad = ' '.repeat(indent);\r\n if (layouts.length === 0) {\r\n return routesInChain.map(r =>\r\n `${pad}<Route path=\"${r.routePath}\" element={<Suspense fallback={<Spinner />}><ErrorBoundary><${pageNames.get(r.filePath)} /></ErrorBoundary></Suspense>} />`\r\n ).join('\\n');\r\n }\r\n const [head, ...tail] = layouts;\r\n const title = layoutTitles.get(head);\r\n // TitleSetter is rendered OUTSIDE ErrorBoundary so a layout crash doesn't\r\n // prevent the title from updating.\r\n const titleSetter = title ? `<TitleSetter title=${JSON.stringify(title)} />` : '';\r\n const inner = renderChain(tail, routesInChain, layoutNames, pageNames, layoutTitles, indent + 2);\r\n const name = layoutNames.get(head);\r\n return [\r\n `${pad}<Route element={<>${titleSetter}<Suspense fallback={<Spinner />}><ErrorBoundary><${name}><Outlet /></${name}></ErrorBoundary></Suspense></>}>`,\r\n inner,\r\n `${pad}</Route>`,\r\n ].join('\\n');\r\n}\r\n\r\n// ─── App Generator ────────────────────────────────────────────────────────────\r\n\r\nfunction generateApp(appDir: string): string {\r\n const aliases = readTsconfigAliases();\r\n const routes = scanRoutes(appDir, appDir);\r\n\r\n const rootPage = findFile(appDir, PAGE_FILES);\r\n if (rootPage) {\r\n routes.unshift({\r\n routePath : '/',\r\n filePath : path.join(appDir, rootPage),\r\n layouts : resolveLayoutChain(appDir, appDir),\r\n dynamic : false,\r\n });\r\n }\r\n\r\n // Strip html-shell layouts and layouts with no default export.\r\n const routesFiltered = routes.map(r => ({\r\n ...r,\r\n layouts: r.layouts.filter(l => isUsableLayout(l)),\r\n }));\r\n\r\n // Only include routes whose page file has a default export.\r\n const validRoutes = deduplicateRoutes(\r\n routesFiltered.filter(r => hasDefaultExport(r.filePath))\r\n );\r\n\r\n validRoutes.sort((a, b) => {\r\n if (a.dynamic !== b.dynamic) return a.dynamic ? 1 : -1;\r\n return a.routePath.length - b.routePath.length;\r\n });\r\n\r\n const notFoundFile = NOT_FOUND_FILES.find(f => fs.existsSync(path.join(appDir, f)));\r\n const notFound = notFoundFile && hasDefaultExport(path.join(appDir, notFoundFile))\r\n ? notFoundFile\r\n : undefined;\r\n\r\n const allLayouts = new Set<string>();\r\n for (const r of validRoutes) r.layouts.forEach(l => {\r\n if (isUsableLayout(l)) allLayouts.add(l);\r\n });\r\n\r\n const layoutNames = new Map<string, string>();\r\n const pageNames = new Map<string, string>();\r\n const layoutTitles = new Map<string, string>();\r\n let li = 0, pi = 0;\r\n for (const l of allLayouts) {\r\n layoutNames.set(l, `Layout${li++}`);\r\n const title = parseLayoutTitle(l);\r\n if (title) layoutTitles.set(l, title);\r\n }\r\n for (const r of validRoutes) {\r\n if (!pageNames.has(r.filePath)) pageNames.set(r.filePath, `Page${pi++}`);\r\n }\r\n\r\n const lazyImports: string[] = [];\r\n for (const [fp, name] of layoutNames)\r\n lazyImports.push(`const ${name} = React.lazy(() => import('${toImportPath(fp, aliases)}'));`);\r\n if (notFound)\r\n lazyImports.push(`const NotFound = React.lazy(() => import('${toImportPath(path.join(appDir, notFound), aliases)}'));`);\r\n const emittedPages = new Set<string>();\r\n for (const r of validRoutes) {\r\n if (emittedPages.has(r.filePath)) continue;\r\n emittedPages.add(r.filePath);\r\n const name = pageNames.get(r.filePath);\r\n if (!name) continue;\r\n lazyImports.push(`const ${name} = React.lazy(() => import('${toImportPath(r.filePath, aliases)}'));`);\r\n }\r\n\r\n const chainMap = new Map<string, LayoutChainGroup>();\r\n for (const r of validRoutes) {\r\n const key = r.layouts.join('|');\r\n if (!chainMap.has(key)) chainMap.set(key, { layouts: r.layouts, routes: [] });\r\n chainMap.get(key)!.routes.push(r);\r\n }\r\n\r\n const routeLines: string[] = [];\r\n for (const [, { layouts, routes: cr }] of chainMap)\r\n routeLines.push(renderChain(layouts, cr, layoutNames, pageNames, layoutTitles, 8));\r\n\r\n const catchAll = notFound\r\n ? ` <Route path=\"*\" element={<Suspense fallback={<Spinner />}><NotFound /></Suspense>} />`\r\n : ` <Route path=\"*\" element={<Default404 />} />`;\r\n\r\n return `// ⚠️ Auto-generated by bini-router — do not edit.\r\nimport React, { Suspense } from 'react';\r\nimport { BrowserRouter, Routes, Route, Outlet } from 'react-router-dom';\r\nimport './app/globals.css';\r\n\r\n${lazyImports.join('\\n')}\r\n\r\n// ─── Error Boundary ───────────────────────────────────────────────────────────\r\nclass ErrorBoundary extends React.Component<\r\n { children: React.ReactNode },\r\n { error: Error | null }\r\n> {\r\n constructor(props: { children: React.ReactNode }) {\r\n super(props);\r\n this.state = { error: null };\r\n }\r\n static getDerivedStateFromError(error: Error) { return { error }; }\r\n override render() {\r\n if (this.state.error) return (\r\n <div style={{ minHeight: '100vh', display: 'flex', alignItems: 'center', justifyContent: 'center', fontFamily: 'system-ui,sans-serif', padding: '2rem' }}>\r\n <div style={{ maxWidth: 480, width: '100%', textAlign: 'center' }}>\r\n <h2 style={{ color: '#e74c3c', marginBottom: '1rem' }}>Something went wrong</h2>\r\n <pre style={{ background: '#fef2f2', padding: '1rem', borderRadius: '0.5rem', textAlign: 'left', fontSize: '0.8rem', color: '#e74c3c', overflow: 'auto' }}>{this.state.error.toString()}</pre>\r\n <button onClick={() => this.setState({ error: null })} style={{ marginTop: '1rem', padding: '0.5rem 1.5rem', background: '#00CFFF', color: 'white', border: 'none', borderRadius: '0.5rem', cursor: 'pointer', fontWeight: 600 }}>\r\n Try again\r\n </button>\r\n </div>\r\n </div>\r\n );\r\n return this.props.children;\r\n }\r\n}\r\n\r\nfunction Spinner() {\r\n return (\r\n <div style={{ minHeight: '100vh', display: 'flex', alignItems: 'center', justifyContent: 'center' }}>\r\n <div style={{ width: 32, height: 32, border: '3px solid #eee', borderTop: '3px solid #00CFFF', borderRadius: '50%', animation: 'spin 0.8s linear infinite' }} />\r\n <style>{\\`@keyframes spin{to{transform:rotate(360deg)}}\\`}</style>\r\n </div>\r\n );\r\n}\r\n\r\n// Renders nothing — just sets document.title when the layout mounts.\r\n// Placed outside ErrorBoundary so a layout crash doesn't block the title update.\r\nfunction TitleSetter({ title }: { title: string }) {\r\n React.useEffect(() => { document.title = title; }, [title]);\r\n return null;\r\n}\r\n\r\n${notFound ? '' : `function Default404() {\r\n return (\r\n <div style={{ minHeight: '100vh', display: 'flex', alignItems: 'center', justifyContent: 'center', background: 'linear-gradient(135deg,#00CFFF,#0077FF)', color: 'white', fontFamily: 'system-ui,sans-serif' }}>\r\n <div style={{ textAlign: 'center' }}>\r\n <h1 style={{ fontSize: '5rem', fontWeight: 800, margin: 0 }}>404</h1>\r\n <p style={{ fontSize: '1.25rem', margin: '0.5rem 0 2rem' }}>Page not found</p>\r\n <a href=\"/\" style={{ padding: '0.65rem 1.5rem', background: 'white', color: '#00CFFF', textDecoration: 'none', borderRadius: '0.5rem', fontWeight: 600 }}>← Back to Home</a>\r\n </div>\r\n </div>\r\n );\r\n}`}\r\n\r\nexport default function App() {\r\n return (\r\n <BrowserRouter>\r\n <Routes>\r\n${routeLines.join('\\n')}\r\n${catchAll}\r\n </Routes>\r\n </BrowserRouter>\r\n );\r\n}\r\n`;\r\n}\r\n\r\n// ─── Metadata Parser ──────────────────────────────────────────────────────────\r\n\r\nfunction parseAppMetadata(appDir: string): MetaTags {\r\n const layout = findFile(appDir, LAYOUT_FILES);\r\n if (!layout) return {};\r\n let src = '';\r\n try { src = fs.readFileSync(path.join(appDir, layout), 'utf8'); }\r\n catch { return {}; }\r\n\r\n const startIdx = src.indexOf('export const metadata');\r\n if (startIdx === -1) return {};\r\n const braceStart = src.indexOf('{', startIdx);\r\n if (braceStart === -1) return {};\r\n\r\n let depth = 0, end = braceStart;\r\n for (let i = braceStart; i < src.length; i++) {\r\n if (src[i] === '{') depth++;\r\n else if (src[i] === '}') { depth--; if (depth === 0) { end = i; break; } }\r\n }\r\n const block = src.slice(braceStart, end + 1);\r\n\r\n function extractBlock(source: string, key: string): string | undefined {\r\n const re = new RegExp(`['\"]?${key}['\"]?\\\\s*:\\\\s*\\\\{`);\r\n const match = re.exec(source);\r\n if (!match) return undefined;\r\n let d = 0, i = match.index + match[0].length - 1;\r\n const start = i;\r\n for (; i < source.length; i++) {\r\n if (source[i] === '{') d++;\r\n else if (source[i] === '}') { d--; if (d === 0) return source.slice(start, i + 1); }\r\n }\r\n return undefined;\r\n }\r\n\r\n function extractArray(source: string, key: string): string | undefined {\r\n const re = new RegExp(`['\"]?${key}['\"]?\\\\s*:\\\\s*\\\\[`);\r\n const match = re.exec(source);\r\n if (!match) return undefined;\r\n let d = 0, i = match.index + match[0].length - 1;\r\n const start = i;\r\n for (; i < source.length; i++) {\r\n if (source[i] === '[') d++;\r\n else if (source[i] === ']') { d--; if (d === 0) return source.slice(start, i + 1); }\r\n }\r\n return undefined;\r\n }\r\n\r\n function str(source: string, key: string): string | undefined {\r\n return source.match(\r\n new RegExp(`['\"]?${key}['\"]?\\\\s*:\\\\s*['\"\\`]([^'\"\\`\\n]+)['\"\\`]`)\r\n )?.[1];\r\n }\r\n\r\n function firstArrayStr(source: string, key: string): string | undefined {\r\n const arr = extractArray(source, key);\r\n if (!arr) return undefined;\r\n return arr.match(/url\\s*:\\s*['\"]([^'\"]+)['\"]/)?.[1]\r\n ?? arr.match(/['\"]([^'\"]+)['\"]/)?.[1];\r\n }\r\n\r\n function allArrayStrs(source: string, key: string): string[] {\r\n const arr = extractArray(source, key);\r\n if (!arr) return [];\r\n return [...arr.matchAll(/['\"]([^'\"]+)['\"]/g)].map(m => m[1]);\r\n }\r\n\r\n const meta: MetaTags = {};\r\n\r\n if (str(block, 'title')) meta.title = str(block, 'title');\r\n if (str(block, 'description')) meta.description = str(block, 'description');\r\n if (str(block, 'viewport')) meta.viewport = str(block, 'viewport');\r\n if (str(block, 'themeColor')) meta.themeColor = str(block, 'themeColor');\r\n if (str(block, 'charset')) meta.charset = str(block, 'charset');\r\n if (str(block, 'robots')) meta.robots = str(block, 'robots');\r\n if (str(block, 'canonical')) meta.canonical = str(block, 'canonical');\r\n if (str(block, 'manifest')) meta.manifest = str(block, 'manifest');\r\n\r\n const kwStr = str(block, 'keywords');\r\n if (kwStr) {\r\n meta.keywords = kwStr;\r\n } else {\r\n const kwArr = allArrayStrs(block, 'keywords');\r\n if (kwArr.length) meta.keywords = kwArr.join(', ');\r\n }\r\n\r\n const authorStr = str(block, 'author');\r\n if (authorStr) {\r\n meta.author = authorStr;\r\n } else {\r\n const authorsArr = extractArray(block, 'authors');\r\n if (authorsArr) {\r\n const name = authorsArr.match(/name\\s*:\\s*['\"]([^'\"]+)['\"]/)?.[1];\r\n if (name) meta.author = name;\r\n }\r\n }\r\n\r\n if (!meta.canonical) {\r\n const base = block.match(/metadataBase\\s*:\\s*new\\s+URL\\s*\\(\\s*['\"]([^'\"]+)['\"]/)?.[1];\r\n if (base) meta.canonical = base;\r\n }\r\n\r\n const ogBlock = extractBlock(block, 'openGraph');\r\n if (ogBlock) {\r\n meta.openGraph = {\r\n title : str(ogBlock, 'title'),\r\n description : str(ogBlock, 'description'),\r\n url : str(ogBlock, 'url'),\r\n type : str(ogBlock, 'type'),\r\n image : firstArrayStr(ogBlock, 'images') ?? str(ogBlock, 'image'),\r\n };\r\n }\r\n\r\n const twBlock = extractBlock(block, 'twitter');\r\n if (twBlock) {\r\n meta.twitter = {\r\n card : str(twBlock, 'card'),\r\n title : str(twBlock, 'title'),\r\n description : str(twBlock, 'description'),\r\n creator : str(twBlock, 'creator'),\r\n image : firstArrayStr(twBlock, 'images') ?? str(twBlock, 'image'),\r\n };\r\n }\r\n\r\n const iconsBlock = extractBlock(block, 'icons');\r\n if (iconsBlock) {\r\n meta.icons = {\r\n icon : collectIconEntries(iconsBlock, 'icon'),\r\n shortcut: collectIconEntries(iconsBlock, 'shortcut'),\r\n apple : collectIconEntries(iconsBlock, 'apple'),\r\n };\r\n }\r\n\r\n return meta;\r\n}\r\n\r\nfunction collectIconEntries(source: string, key: string): IconEntry[] {\r\n const arr = extractArrayRaw(source, key);\r\n if (!arr) return [];\r\n const entries: IconEntry[] = [];\r\n const objRe = /\\{([^}]+)\\}/g;\r\n let m: RegExpExecArray | null;\r\n while ((m = objRe.exec(arr)) !== null) {\r\n const obj = m[1];\r\n const url = obj.match(/url\\s*:\\s*['\"]([^'\"]+)['\"]/)?.[1];\r\n if (!url) continue;\r\n entries.push({\r\n url,\r\n type : obj.match(/type\\s*:\\s*['\"]([^'\"]+)['\"]/)?.[1],\r\n sizes: obj.match(/sizes\\s*:\\s*['\"]([^'\"]+)['\"]/)?.[1],\r\n });\r\n }\r\n if (!entries.length) {\r\n return [...arr.matchAll(/['\"]([^'\"]+)['\"]/g)].map(x => ({ url: x[1] }));\r\n }\r\n return entries;\r\n}\r\n\r\nfunction extractArrayRaw(source: string, key: string): string | undefined {\r\n const re = new RegExp(`['\"]?${key}['\"]?\\\\s*:\\\\s*\\\\[`);\r\n const match = re.exec(source);\r\n if (!match) return undefined;\r\n let d = 0, i = match.index + match[0].length - 1;\r\n const start = i;\r\n for (; i < source.length; i++) {\r\n if (source[i] === '[') d++;\r\n else if (source[i] === ']') { d--; if (d === 0) return source.slice(start, i + 1); }\r\n }\r\n return undefined;\r\n}\r\n\r\n// ─── API Route Scanner ────────────────────────────────────────────────────────\r\n\r\nfunction scanApiRoutes(dir: string, baseRoute = ''): ApiRoute[] {\r\n const routes: ApiRoute[] = [];\r\n if (!fs.existsSync(dir)) return routes;\r\n\r\n let entries: fs.Dirent[];\r\n try { entries = fs.readdirSync(dir, { withFileTypes: true }); }\r\n catch { return routes; }\r\n\r\n for (const entry of entries) {\r\n if (entry.name.startsWith('_') || entry.name.startsWith('.')) continue;\r\n const fullPath = path.join(dir, entry.name);\r\n\r\n if (entry.isDirectory()) {\r\n const isCatchAll = entry.name.startsWith('[...') && entry.name.endsWith(']');\r\n const isDynamic = entry.name.startsWith('[') && entry.name.endsWith(']');\r\n const segment = isCatchAll ? '*' : isDynamic ? `:${entry.name.slice(1, -1)}` : entry.name;\r\n routes.push(...scanApiRoutes(fullPath, `${baseRoute}/${segment}`));\r\n continue;\r\n }\r\n\r\n const ext = path.extname(entry.name);\r\n const base = path.basename(entry.name, ext);\r\n if (!(API_EXTS as readonly string[]).includes(ext)) continue;\r\n\r\n const isCatchAll = base.startsWith('[...') && base.endsWith(']');\r\n const isDynamic = base.startsWith('[') && base.endsWith(']');\r\n const routePath = isCatchAll\r\n ? `${baseRoute}/*`\r\n : base === 'index'\r\n ? baseRoute || '/'\r\n : isDynamic\r\n ? `${baseRoute}/:${base.slice(1, -1)}`\r\n : `${baseRoute}/${base}`;\r\n\r\n routes.push({ routePath, filePath: fullPath });\r\n }\r\n\r\n return routes;\r\n}\r\n\r\n// ─── Hono dev/preview server ──────────────────────────────────────────────────\r\n//\r\n// API files in src/app/api/ can export:\r\n// export default new Hono().basePath('/api') ← Hono app (routing handled internally)\r\n// export default async function(req: Request) {...} ← plain function (bini-router matches route)\r\n//\r\n// Module cache: re-imports only when the file's mtime changes, not on every request.\r\n// Route matching: plain functions are matched against their scanned routePath pattern\r\n// before the handler is called — so dynamic params ([id]) are resolved correctly.\r\n\r\n// Matches a URL pathname against a route pattern like /api/users/:id or /api/files/*\r\n// Returns extracted params if matched, or null if not.\r\nfunction matchRoute(pattern: string, pathname: string): Record<string, string> | null {\r\n const patParts = pattern.split('/').filter(Boolean);\r\n const urlParts = pathname.split('/').filter(Boolean);\r\n\r\n // Catch-all: pattern ends with * — match everything after the prefix\r\n const isCatchAll = patParts[patParts.length - 1] === '*';\r\n if (isCatchAll) {\r\n const prefix = patParts.slice(0, -1);\r\n if (urlParts.length < prefix.length) return null;\r\n for (let i = 0; i < prefix.length; i++) {\r\n if (prefix[i].startsWith(':')) continue;\r\n if (prefix[i] !== urlParts[i]) return null;\r\n }\r\n return { '*': urlParts.slice(prefix.length).join('/') };\r\n }\r\n\r\n if (patParts.length !== urlParts.length) return null;\r\n\r\n const params: Record<string, string> = {};\r\n for (let i = 0; i < patParts.length; i++) {\r\n if (patParts[i].startsWith(':')) {\r\n params[patParts[i].slice(1)] = decodeURIComponent(urlParts[i]);\r\n } else if (patParts[i] !== urlParts[i]) {\r\n return null;\r\n }\r\n }\r\n return params;\r\n}\r\n\r\n// Per-file module cache: maps filePath → { mtime, handler }\r\n// Avoids re-importing on every request while still picking up file changes.\r\nconst moduleCache = new Map<string, { mtime: number; handler: unknown }>();\r\n\r\nasync function importHandler(filePath: string): Promise<unknown> {\r\n const { pathToFileURL } = await import('url');\r\n let mtime = 0;\r\n try { mtime = fs.statSync(filePath).mtimeMs; } catch { /* file vanished */ }\r\n\r\n const cached = moduleCache.get(filePath);\r\n if (cached && cached.mtime === mtime) return cached.handler;\r\n\r\n // File changed or not yet cached — re-import with cache-bust\r\n const mod = await import(pathToFileURL(filePath).href + '?t=' + mtime);\r\n const handler = mod.default ?? null;\r\n moduleCache.set(filePath, { mtime, handler });\r\n return handler;\r\n}\r\n\r\nasync function handleApiRequest(\r\n req : any,\r\n res : any,\r\n next : any,\r\n apiDir : string,\r\n enableCors : boolean,\r\n getCache : () => { routes: ApiRoute[] } | null,\r\n setCache : (v: { routes: ApiRoute[] }) => void,\r\n) {\r\n try {\r\n // Handle CORS preflight immediately — no need to hit a handler.\r\n if (enableCors && req.method === 'OPTIONS') {\r\n res.statusCode = 204;\r\n res.setHeader('Access-Control-Allow-Origin', '*');\r\n res.setHeader('Access-Control-Allow-Methods', 'GET,POST,PUT,PATCH,DELETE,OPTIONS');\r\n res.setHeader('Access-Control-Allow-Headers', 'Content-Type,Authorization');\r\n res.setHeader('Access-Control-Max-Age', '86400');\r\n res.end();\r\n return;\r\n }\r\n\r\n let cache = getCache();\r\n if (!cache) {\r\n cache = { routes: scanApiRoutes(apiDir, '/api') };\r\n setCache(cache);\r\n }\r\n\r\n const host = req.headers.host ?? 'localhost';\r\n const url = `http://${host}${req.url}`;\r\n const pathname = new URL(url).pathname;\r\n\r\n const chunks: Buffer[] = [];\r\n for await (const chunk of req) chunks.push(chunk as Buffer);\r\n const body = chunks.length > 0 ? Buffer.concat(chunks) : undefined;\r\n\r\n const method = (req.method as string).toUpperCase();\r\n\r\n const webReq = new Request(url, {\r\n method,\r\n headers: req.headers as HeadersInit,\r\n body : !['GET', 'HEAD'].includes(method) && body?.length ? body : undefined,\r\n });\r\n\r\n for (const route of cache.routes) {\r\n const handler = await importHandler(route.filePath);\r\n if (!handler) continue;\r\n\r\n let webRes: Response;\r\n try {\r\n if (typeof (handler as any).fetch === 'function') {\r\n // Hono app — has its own internal router, pass the full request directly.\r\n webRes = await (handler as any).fetch(webReq.clone());\r\n\r\n // Hono returns 404 when no route matched — try next file.\r\n if (webRes.status === 404) continue;\r\n\r\n } else if (typeof handler === 'function') {\r\n // Plain function — match the URL against this file's route pattern first.\r\n // This gives dynamic params ([id] → :id) without the function needing a router.\r\n const params = matchRoute(route.routePath, pathname);\r\n if (params === null) continue; // URL doesn't match this file's pattern\r\n\r\n // Inject matched params into the Request so the handler can read them.\r\n // We attach them as a custom header so no extra dependency is needed.\r\n const existingHeaders: Record<string, string> = {};\r\n webReq.headers.forEach((v, k) => { existingHeaders[k] = v; });\r\n const reqWithParams = new Request(webReq.clone(), {\r\n headers: { ...existingHeaders, 'x-bini-params': JSON.stringify(params) },\r\n });\r\n\r\n webRes = await (handler as (...args: any[]) => Promise<Response>)(reqWithParams);\r\n\r\n } else {\r\n continue;\r\n }\r\n } catch {\r\n continue; // handler threw — not its route, try next\r\n }\r\n\r\n // Build final headers — Response.headers is immutable so copy to plain object first\r\n const finalHeaders: Record<string, string> = {};\r\n webRes.headers.forEach((v, k) => { finalHeaders[k] = v; });\r\n if (enableCors) {\r\n finalHeaders['access-control-allow-origin'] = '*';\r\n finalHeaders['access-control-allow-methods'] = 'GET,POST,PUT,PATCH,DELETE,OPTIONS';\r\n finalHeaders['access-control-allow-headers'] = 'Content-Type,Authorization';\r\n }\r\n\r\n res.statusCode = webRes.status;\r\n for (const [k, v] of Object.entries(finalHeaders)) res.setHeader(k, v);\r\n res.end(Buffer.from(await webRes.arrayBuffer()));\r\n return;\r\n }\r\n\r\n // No handler matched\r\n res.statusCode = 404;\r\n res.setHeader('Content-Type', 'application/json');\r\n res.end(JSON.stringify({ error: `No API handler found for ${req.url}` }));\r\n } catch (e: any) {\r\n next(e);\r\n }\r\n}\r\n\r\n// ─── Production Entry Generator ───────────────────────────────────────────────\r\n//\r\n// Mirrors what SvelteKit/Nuxt adapters do at build time:\r\n// scan src/app/api/, merge all handlers, wrap with the platform adapter.\r\n// User writes only in src/app/api/ — never touches the generated entry file.\r\n//\r\n// Supports both export styles:\r\n// export default new Hono() ← merged via .route()\r\n// export default async function handler(req: Request) {...} ← wrapped in Hono app\r\n\r\nfunction buildProductionEntry(srcApiDir: string, platform: 'vercel' | 'node' | 'cloudflare', enableCors: boolean): void {\r\n if (!fs.existsSync(srcApiDir)) return;\r\n\r\n const routes = scanApiRoutes(srcApiDir);\r\n const cwd = process.cwd();\r\n\r\n const imports : string[] = [];\r\n const mountings: string[] = [];\r\n\r\n for (let i = 0; i < routes.length; i++) {\r\n const route = routes[i];\r\n const rel = norm(path.relative(cwd, route.filePath)).replace(/\\.(ts|tsx)$/, '');\r\n const imp = rel.startsWith('.') ? rel : `./${rel}`;\r\n const name = `_route${i}`;\r\n\r\n // Detect at build time whether this file exports a Hono app or a plain function\r\n // by reading the source — if it imports from 'hono' it's a Hono app, otherwise wrap it.\r\n let src = '';\r\n try { src = fs.readFileSync(route.filePath, 'utf8'); } catch { /* skip */ }\r\n const isHonoApp = src.includes(\"from 'hono'\") || src.includes('from \"hono\"');\r\n\r\n imports.push(`import ${name} from '${imp}';`);\r\n\r\n if (isHonoApp) {\r\n // Hono app: merge directly into root app\r\n mountings.push(`app.route('/', ${name});`);\r\n } else {\r\n // Plain function: wrap in Hono and mount at its route path\r\n mountings.push(`app.all('${route.routePath}', (c) => ${name}(c.req.raw));`);\r\n }\r\n }\r\n\r\n const corsLine = enableCors\r\n ? `app.use('/api/*', cors({ origin: '*', allowMethods: ['GET','POST','PUT','PATCH','DELETE','OPTIONS'], allowHeaders: ['Content-Type','Authorization'] }));`\r\n : null;\r\n\r\n const header = [\r\n `// ⚠️ Auto-generated by bini-router on every build — do not edit.`,\r\n `// Add routes by creating files in src/app/api/ only.`,\r\n ];\r\n\r\n const corsImport = enableCors ? `import { cors } from 'hono/cors';` : null;\r\n\r\n let outFile: string;\r\n let lines : string[];\r\n\r\n const appSetup = [\r\n ``,\r\n `const app = new Hono();`,\r\n ...(corsLine ? [corsLine] : []),\r\n ...mountings,\r\n ];\r\n\r\n if (platform === 'vercel') {\r\n outFile = path.join(cwd, 'api', 'index.ts');\r\n // Vercel runs a Hono app directly as a default export — no handle() wrapper needed.\r\n // Import is from 'hono/vercel' (built into hono, no separate package to install).\r\n lines = [\r\n ...header,\r\n `import { Hono } from 'hono';`,\r\n ...(corsImport ? [corsImport] : []),\r\n ...imports,\r\n ...appSetup,\r\n ``,\r\n `export const runtime = 'edge';`,\r\n `export default app;`,\r\n ];\r\n\r\n } else if (platform === 'cloudflare') {\r\n outFile = path.join(cwd, 'worker.ts');\r\n lines = [\r\n ...header,\r\n `import { Hono } from 'hono';`,\r\n ...(corsImport ? [corsImport] : []),\r\n ...imports,\r\n ...appSetup,\r\n ``,\r\n `export default app;`,\r\n ];\r\n\r\n } else {\r\n // node\r\n outFile = path.join(cwd, 'server', 'index.ts');\r\n lines = [\r\n ...header,\r\n `import { Hono } from 'hono';`,\r\n `import { serve } from '@hono/node-server';`,\r\n `import { serveStatic } from '@hono/node-server/serve-static';`,\r\n ...(corsImport ? [corsImport] : []),\r\n ...imports,\r\n ...appSetup,\r\n `app.use('/*', serveStatic({ root: './dist' }));`,\r\n `app.use('/*', serveStatic({ path: './dist/index.html' }));`,\r\n ``,\r\n `serve({ fetch: app.fetch, port: Number(process.env.PORT ?? 3000) }, (i) => {`,\r\n ` console.log(\\`Server running on http://localhost:\\${i.port}\\`);`,\r\n `});`,\r\n ];\r\n }\r\n\r\n fs.mkdirSync(path.dirname(outFile), { recursive: true });\r\n fs.writeFileSync(outFile, lines.join('\\n') + '\\n', 'utf8');\r\n console.log(`[bini-router] ✓ Generated ${norm(path.relative(cwd, outFile))}`);\r\n}\r\n\r\n// ─── Plugin ───────────────────────────────────────────────────────────────────\r\n\r\nexport function biniroute(options: BiniPluginOptions = {}): Plugin {\r\n const { cors: enableCors = true, platform } = options;\r\n\r\n const getAppDir = () => path.join(process.cwd(), options.appDir ?? 'src/app');\r\n const getApiDir = () => path.join(process.cwd(), options.apiDir ?? 'src/app/api');\r\n\r\n // ── Per-instance state (fixes shared-state bug) ───────────────────────────\r\n let debounceTimer : ReturnType<typeof setTimeout> | null = null;\r\n let lastGeneratedCode = '';\r\n let honoCache : { routes: ApiRoute[] } | null = null;\r\n const eventLog = new Map<string, number>();\r\n\r\n function shouldProcess(file: string, event: string): boolean {\r\n const key = `${file}:${event}`;\r\n const now = Date.now();\r\n if (now - (eventLog.get(key) ?? 0) < EVENT_DEDUP_MS) return false;\r\n eventLog.set(key, now);\r\n for (const [k, v] of eventLog) if (now - v > EVENT_TTL_MS) eventLog.delete(k);\r\n return true;\r\n }\r\n\r\n // Only trigger regen for page/layout files, not utils/hooks.\r\n // Uses forward-slash comparison to work correctly on Windows.\r\n function isPageFile(f: string): boolean {\r\n const nf = norm(f);\r\n const base = path.basename(f, path.extname(f));\r\n const ext = path.extname(f);\r\n if (!(SUPPORTED_EXTS as readonly string[]).includes(ext)) return false;\r\n if (!isInDir(nf, norm(getAppDir()))) return false;\r\n if (isInDir(nf, norm(getApiDir()))) return false;\r\n if (base.startsWith('_')) return false;\r\n return true;\r\n }\r\n\r\n function isApiFile(f: string): boolean {\r\n const nf = norm(f);\r\n return isInDir(nf, norm(getApiDir())) &&\r\n (API_EXTS as readonly string[]).includes(path.extname(f));\r\n }\r\n\r\n // Single helper used by both config/buildStart and scheduleRegen.\r\n function applyApp(): string | null {\r\n const dir = getAppDir();\r\n if (!fs.existsSync(dir)) return null;\r\n const code = generateApp(dir);\r\n if (code === lastGeneratedCode) return null;\r\n fs.writeFileSync(getAppFile(), code, 'utf8');\r\n lastGeneratedCode = code;\r\n return code;\r\n }\r\n\r\n function scheduleRegen(server: ViteDevServer, delay = DEBOUNCE_MS) {\r\n if (debounceTimer) clearTimeout(debounceTimer);\r\n debounceTimer = setTimeout(() => {\r\n debounceTimer = null;\r\n if (applyApp() !== null) {\r\n server.ws.send({ type: 'full-reload', path: '*' });\r\n }\r\n }, delay);\r\n }\r\n\r\n // Preview server needs SPA fallback so direct URL navigation works.\r\n function addSpaFallback(server: { middlewares: any }) {\r\n server.middlewares.use((req: any, res: any, next: any) => {\r\n const url = req.url as string;\r\n // Let Vite handle static assets and the API\r\n if (url.startsWith('/api') || url.includes('.')) return next();\r\n // Rewrite everything else to index.html for client-side routing\r\n req.url = '/index.html';\r\n next();\r\n });\r\n }\r\n\r\n return {\r\n name : 'bini-router',\r\n enforce: 'pre',\r\n\r\n // Strip `export const metadata = {...}` from all src/app files before\r\n // @vitejs/plugin-react's Fast Refresh transform sees them.\r\n transform(code, id) {\r\n const nid = norm(id);\r\n if (!isInDir(nid, norm(getAppDir()))) return;\r\n const ext = path.extname(id);\r\n if (!(SUPPORTED_EXTS as readonly string[]).includes(ext)) return;\r\n if (!code.includes('export const metadata')) return;\r\n\r\n let result = code;\r\n let idx = result.indexOf('export const metadata');\r\n\r\n while (idx !== -1) {\r\n const braceIdx = result.indexOf('{', idx);\r\n if (braceIdx === -1) break;\r\n\r\n let depth = 0, end = braceIdx;\r\n for (let i = braceIdx; i < result.length; i++) {\r\n if (result[i] === '{') depth++;\r\n else if (result[i] === '}') { depth--; if (depth === 0) { end = i; break; } }\r\n }\r\n\r\n let tail = end + 1;\r\n while (tail < result.length && (result[tail] === ' ' || result[tail] === '\\t')) tail++;\r\n if (tail < result.length && result[tail] === ';') tail++;\r\n while (tail < result.length && (result[tail] === '\\n' || result[tail] === '\\r')) tail++;\r\n\r\n result = result.slice(0, idx) + result.slice(tail);\r\n idx = result.indexOf('export const metadata', idx);\r\n }\r\n\r\n return { code: result, map: null };\r\n },\r\n\r\n config() { applyApp(); },\r\n buildStart() { applyApp(); },\r\n\r\n closeBundle() {\r\n if (platform) buildProductionEntry(getApiDir(), platform, enableCors);\r\n },\r\n\r\n buildEnd() {\r\n // Clear caches between builds so stale routes/modules don't persist.\r\n honoCache = null;\r\n moduleCache.clear();\r\n if (debounceTimer) { clearTimeout(debounceTimer); debounceTimer = null; }\r\n },\r\n\r\n async configureServer(server) {\r\n const appDir = getAppDir();\r\n const apiDir = getApiDir();\r\n\r\n if (!fs.existsSync(appDir)) return;\r\n\r\n server.watcher.add(appDir);\r\n\r\n server.watcher.on('add', f => isPageFile(f) && shouldProcess(f, 'add') && scheduleRegen(server, 300));\r\n server.watcher.on('unlink', f => isPageFile(f) && shouldProcess(f, 'unlink') && scheduleRegen(server));\r\n server.watcher.on('change', f => isPageFile(f) && shouldProcess(f, 'change') && scheduleRegen(server));\r\n\r\n // When root layout.tsx changes, re-run transformIndexHtml with fresh metadata.\r\n server.watcher.on('change', f => {\r\n const base = path.basename(f, path.extname(f));\r\n const inAppRoot = path.resolve(path.dirname(f)) === path.resolve(appDir);\r\n if (!inAppRoot || base !== 'layout') return;\r\n server.moduleGraph.invalidateAll();\r\n server.ws.send({ type: 'full-reload', path: '*' });\r\n });\r\n\r\n server.watcher.on('addDir', d => {\r\n const nd = norm(d);\r\n if (!isInDir(nd, norm(appDir)) || d.includes('node_modules') || isInDir(nd, norm(apiDir))) return;\r\n setTimeout(() => PAGE_FILES.some(f => fs.existsSync(path.join(d, f))) && scheduleRegen(server), 300);\r\n });\r\n\r\n server.watcher.on('unlinkDir', d => {\r\n const nd = norm(d);\r\n if (isInDir(nd, norm(appDir)) && !d.includes('node_modules') && !isInDir(nd, norm(apiDir)))\r\n scheduleRegen(server);\r\n });\r\n\r\n if (fs.existsSync(apiDir)) {\r\n server.watcher.add(apiDir);\r\n\r\n const resetApi = (f?: string) => {\r\n honoCache = null;\r\n // Clear the module cache entry for this specific file so importHandler\r\n // re-imports it on the next request rather than serving a stale handler.\r\n if (f) moduleCache.delete(f);\r\n server.ws.send({ type: 'full-reload', path: '*' });\r\n };\r\n\r\n server.watcher.on('add', f => isApiFile(f) && resetApi(f));\r\n server.watcher.on('unlink', f => isApiFile(f) && resetApi(f));\r\n server.watcher.on('change', f => isApiFile(f) && resetApi(f));\r\n\r\n server.middlewares.use((req: any, res: any, next: any) => {\r\n if (!req.url?.startsWith('/api')) return next();\r\n handleApiRequest(req, res, next, apiDir, enableCors,\r\n () => honoCache, (v) => { honoCache = v; });\r\n });\r\n }\r\n },\r\n\r\n async configurePreviewServer(server) {\r\n // SPA fallback so /register etc. don't 404 in preview mode.\r\n addSpaFallback(server);\r\n\r\n const apiDir = getApiDir();\r\n if (!fs.existsSync(apiDir)) return;\r\n server.middlewares.use((req: any, res: any, next: any) => {\r\n if (!req.url?.startsWith('/api')) return next();\r\n handleApiRequest(req, res, next, apiDir, enableCors,\r\n () => honoCache, (v) => { honoCache = v; });\r\n });\r\n },\r\n\r\n transformIndexHtml: {\r\n order: 'pre',\r\n handler(html) {\r\n const meta = parseAppMetadata(getAppDir());\r\n\r\n // If no layout or metadata found, leave the HTML completely untouched.\r\n // Stripping tags without re-injecting them would break the page.\r\n if (!meta.title && !meta.description && !meta.canonical && !meta.manifest &&\r\n !meta.openGraph?.title && !meta.icons?.icon?.length) {\r\n return html;\r\n }\r\n\r\n const title = meta.title ?? 'Bini App';\r\n const vp = meta.viewport ?? 'width=device-width, initial-scale=1.0';\r\n\r\n const lines: string[] = [];\r\n\r\n lines.push(`<meta charset=\"${meta.charset ?? 'UTF-8'}\" />`);\r\n lines.push(`<meta name=\"viewport\" content=\"${vp}\" />`);\r\n lines.push(`<title>${title}</title>`);\r\n if (meta.description) lines.push(`<meta name=\"description\" content=\"${meta.description}\" />`);\r\n if (meta.themeColor) lines.push(`<meta name=\"theme-color\" content=\"${meta.themeColor}\" />`);\r\n if (meta.robots) lines.push(`<meta name=\"robots\" content=\"${meta.robots}\" />`);\r\n if (meta.keywords) lines.push(`<meta name=\"keywords\" content=\"${meta.keywords}\" />`);\r\n if (meta.author) lines.push(`<meta name=\"author\" content=\"${meta.author}\" />`);\r\n if (meta.canonical) lines.push(`<link rel=\"canonical\" href=\"${meta.canonical}\" />`);\r\n if (meta.manifest) lines.push(`<link rel=\"manifest\" href=\"${meta.manifest}\" />`);\r\n\r\n for (const entry of meta.icons?.icon ?? []) {\r\n const type = entry.type ? ` type=\"${entry.type}\"` : '';\r\n const sizes = entry.sizes ? ` sizes=\"${entry.sizes}\"` : '';\r\n lines.push(`<link rel=\"icon\" href=\"${entry.url}\"${type}${sizes} />`);\r\n }\r\n for (const entry of meta.icons?.shortcut ?? []) {\r\n lines.push(`<link rel=\"shortcut icon\" href=\"${entry.url}\" />`);\r\n }\r\n for (const entry of meta.icons?.apple ?? []) {\r\n const sizes = entry.sizes ? ` sizes=\"${entry.sizes}\"` : '';\r\n const type = entry.type ? ` type=\"${entry.type}\"` : '';\r\n lines.push(`<link rel=\"apple-touch-icon\" href=\"${entry.url}\"${sizes}${type} />`);\r\n }\r\n\r\n if (meta.openGraph?.title) {\r\n lines.push(`<meta property=\"og:type\" content=\"${meta.openGraph.type ?? 'website'}\" />`);\r\n lines.push(`<meta property=\"og:title\" content=\"${meta.openGraph.title}\" />`);\r\n if (meta.openGraph.description) lines.push(`<meta property=\"og:description\" content=\"${meta.openGraph.description}\" />`);\r\n if (meta.openGraph.url) lines.push(`<meta property=\"og:url\" content=\"${meta.openGraph.url}\" />`);\r\n if (meta.openGraph.image) lines.push(`<meta property=\"og:image\" content=\"${meta.openGraph.image}\" />`);\r\n }\r\n\r\n if (meta.twitter?.title) {\r\n lines.push(`<meta name=\"twitter:card\" content=\"${meta.twitter.card ?? 'summary_large_image'}\" />`);\r\n lines.push(`<meta name=\"twitter:title\" content=\"${meta.twitter.title}\" />`);\r\n if (meta.twitter.description) lines.push(`<meta name=\"twitter:description\" content=\"${meta.twitter.description}\" />`);\r\n if (meta.twitter.creator) lines.push(`<meta name=\"twitter:creator\" content=\"${meta.twitter.creator}\" />`);\r\n if (meta.twitter.image) lines.push(`<meta name=\"twitter:image\" content=\"${meta.twitter.image}\" />`);\r\n }\r\n\r\n const injected = lines.map(l => ` ${l}`).join('\\n');\r\n return html.replace('</head>', `${injected}\\n </head>`);\r\n },\r\n },\r\n };\r\n}\r\n\r\nexport default biniroute;"],"mappings":"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","names":["isCatchAll","isDynamic"]}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "bini-router",
3
- "version": "1.0.13",
3
+ "version": "1.0.15",
4
4
  "description": "File-based routing, nested layouts, and Hono-powered API routes for Vite + React",
5
5
  "author": "bini.js",
6
6
  "license": "MIT",