bini-router 1.0.15 → 1.0.17

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/Readme.md CHANGED
@@ -6,7 +6,6 @@
6
6
  [![license](https://img.shields.io/badge/license-MIT-00CFFF?labelColor=0a0a0a&style=flat-square)](./LICENSE)
7
7
  [![vite](https://img.shields.io/badge/vite-6.x-646cff?labelColor=0a0a0a&style=flat-square)](https://vitejs.dev)
8
8
  [![react](https://img.shields.io/badge/react-18%2B-61dafb?labelColor=0a0a0a&style=flat-square)](https://react.dev)
9
- [![hono](https://img.shields.io/badge/hono-included-e36002?labelColor=0a0a0a&style=flat-square)](https://hono.dev)
10
9
  [![hono](https://img.shields.io/badge/hono-powered-fb923c?labelColor=0a0a0a&style=flat-square)](https://hono.dev)
11
10
  [![typescript](https://img.shields.io/badge/typescript-ready-3178c6?labelColor=0a0a0a&style=flat-square)](https://www.typescriptlang.org)
12
11
  [![PRs Welcome](https://img.shields.io/badge/PRs-welcome-00CFFF?labelColor=0a0a0a&style=flat-square)](https://github.com/binidu/bini-router/pulls)
@@ -36,10 +35,10 @@ Like Next.js — but pure SPA, zero server required.
36
35
  ## Install
37
36
 
38
37
  ```bash
39
- npm install bini-router
38
+ npm install bini-router hono
40
39
  ```
41
40
 
42
- > Hono is included no need to install it separately.
41
+ > `hono` is a required peer dependency. Install it alongside `bini-router`.
43
42
 
44
43
  ---
45
44
 
@@ -260,6 +259,24 @@ export default app
260
259
 
261
260
  That's it. No adapter imports, no platform code. The same file works in dev and production.
262
261
 
262
+ ### Plain function handlers
263
+
264
+ You can also export a plain async function instead of a Hono app. Both plain objects and `Response` returns are supported:
265
+
266
+ ```ts
267
+ // src/app/api/hello.ts
268
+
269
+ // ✅ Return a plain object — auto-wrapped as JSON
270
+ export default function handler(req: Request) {
271
+ return { message: 'hello', method: req.method }
272
+ }
273
+
274
+ // ✅ Return an explicit Response — passed through as-is
275
+ export default function handler(req: Request) {
276
+ return Response.json({ message: 'hello' })
277
+ }
278
+ ```
279
+
263
280
  ### Multiple methods
264
281
 
265
282
  ```ts
@@ -359,11 +376,13 @@ No extra package needed — Vercel runs a Hono app as a direct default export.
359
376
  ```ts
360
377
  // ⚠️ Auto-generated — do not edit. Add routes in src/app/api/ only.
361
378
  import { Hono } from 'hono';
379
+ import { cors } from 'hono/cors';
362
380
  import _route0 from '../src/app/api/test';
363
- import _route1 from '../src/app/api/users';
381
+
364
382
  const app = new Hono();
365
- app.route('/', _route0);
366
- app.route('/', _route1);
383
+ app.use('/api/*', cors({ origin: '*', allowMethods: ['GET','POST','PUT','PATCH','DELETE','OPTIONS'], allowHeaders: ['Content-Type','Authorization'] }));
384
+ app.all('/api/test', async (c) => { const r = await _route0(c.req.raw); return r instanceof Response ? r : c.json(r); });
385
+
367
386
  export const runtime = 'edge';
368
387
  export default app;
369
388
  ```
@@ -371,7 +390,11 @@ export default app;
371
390
  Add `vercel.json`:
372
391
  ```json
373
392
  {
374
- "rewrites": [{ "source": "/api/(.*)", "destination": "/api/index" }]
393
+ "outputDirectory": "dist",
394
+ "rewrites": [
395
+ { "source": "/api/(.*)", "destination": "/api/index" },
396
+ { "source": "/((?!api/).*)", "destination": "/index.html" }
397
+ ]
375
398
  }
376
399
  ```
377
400
 
@@ -382,7 +405,7 @@ Set build command: `vite build`, output directory: `dist`. Push and deploy.
382
405
  ### 🟠 Cloudflare Workers
383
406
 
384
407
  ```bash
385
- pnpm add wrangler
408
+ npm install wrangler
386
409
  ```
387
410
 
388
411
  ```ts
@@ -400,7 +423,7 @@ directory = "./dist"
400
423
  ```
401
424
 
402
425
  ```bash
403
- vite build && pnpm wrangler deploy
426
+ vite build && npx wrangler deploy
404
427
  ```
405
428
 
406
429
  ---
@@ -408,7 +431,7 @@ vite build && pnpm wrangler deploy
408
431
  ### 🚂 Node.js (Railway, Render, VPS, Fly.io)
409
432
 
410
433
  ```bash
411
- pnpm add @hono/node-server
434
+ npm install @hono/node-server
412
435
  ```
413
436
 
414
437
  ```ts
package/dist/index.cjs CHANGED
@@ -317,8 +317,6 @@ function Spinner() {
317
317
  );
318
318
  }
319
319
 
320
- // Renders nothing \u2014 just sets document.title when the layout mounts.
321
- // Placed outside ErrorBoundary so a layout crash doesn't block the title update.
322
320
  function TitleSetter({ title }: { title: string }) {
323
321
  React.useEffect(() => { document.title = title; }, [title]);
324
322
  return null;
@@ -661,11 +659,19 @@ function buildProductionEntry(srcApiDir, platform, enableCors) {
661
659
  if (!import_fs.default.existsSync(srcApiDir)) return;
662
660
  const routes = scanApiRoutes(srcApiDir);
663
661
  const cwd = process.cwd();
662
+ let outFile;
663
+ if (platform === "vercel") {
664
+ outFile = import_path.default.join(cwd, "api", "index.ts");
665
+ } else if (platform === "cloudflare") {
666
+ outFile = import_path.default.join(cwd, "worker.ts");
667
+ } else {
668
+ outFile = import_path.default.join(cwd, "server", "index.ts");
669
+ }
664
670
  const imports = [];
665
671
  const mountings = [];
666
672
  for (let i = 0; i < routes.length; i++) {
667
673
  const route = routes[i];
668
- const rel = norm(import_path.default.relative(cwd, route.filePath)).replace(/\.(ts|tsx)$/, "");
674
+ const rel = norm(import_path.default.relative(import_path.default.dirname(outFile), route.filePath)).replace(/\.(ts|tsx)$/, "");
669
675
  const imp = rel.startsWith(".") ? rel : `./${rel}`;
670
676
  const name = `_route${i}`;
671
677
  let src = "";
@@ -678,7 +684,7 @@ function buildProductionEntry(srcApiDir, platform, enableCors) {
678
684
  if (isHonoApp) {
679
685
  mountings.push(`app.route('/', ${name});`);
680
686
  } else {
681
- mountings.push(`app.all('${route.routePath}', (c) => ${name}(c.req.raw));`);
687
+ mountings.push(`app.all('/api${route.routePath}', async (c) => { const r = await ${name}(c.req.raw); return r instanceof Response ? r : c.json(r); });`);
682
688
  }
683
689
  }
684
690
  const corsLine = enableCors ? `app.use('/api/*', cors({ origin: '*', allowMethods: ['GET','POST','PUT','PATCH','DELETE','OPTIONS'], allowHeaders: ['Content-Type','Authorization'] }));` : null;
@@ -687,16 +693,14 @@ function buildProductionEntry(srcApiDir, platform, enableCors) {
687
693
  `// Add routes by creating files in src/app/api/ only.`
688
694
  ];
689
695
  const corsImport = enableCors ? `import { cors } from 'hono/cors';` : null;
690
- let outFile;
691
- let lines;
692
696
  const appSetup = [
693
697
  ``,
694
698
  `const app = new Hono();`,
695
699
  ...corsLine ? [corsLine] : [],
696
700
  ...mountings
697
701
  ];
702
+ let lines;
698
703
  if (platform === "vercel") {
699
- outFile = import_path.default.join(cwd, "api", "index.ts");
700
704
  lines = [
701
705
  ...header,
702
706
  `import { Hono } from 'hono';`,
@@ -708,7 +712,6 @@ function buildProductionEntry(srcApiDir, platform, enableCors) {
708
712
  `export default app;`
709
713
  ];
710
714
  } else if (platform === "cloudflare") {
711
- outFile = import_path.default.join(cwd, "worker.ts");
712
715
  lines = [
713
716
  ...header,
714
717
  `import { Hono } from 'hono';`,
@@ -719,7 +722,6 @@ function buildProductionEntry(srcApiDir, platform, enableCors) {
719
722
  `export default app;`
720
723
  ];
721
724
  } else {
722
- outFile = import_path.default.join(cwd, "server", "index.ts");
723
725
  lines = [
724
726
  ...header,
725
727
  `import { Hono } from 'hono';`,
@@ -799,8 +801,6 @@ function biniroute(options = {}) {
799
801
  return {
800
802
  name: "bini-router",
801
803
  enforce: "pre",
802
- // Strip `export const metadata = {...}` from all src/app files before
803
- // @vitejs/plugin-react's Fast Refresh transform sees them.
804
804
  transform(code, id) {
805
805
  const nid = norm(id);
806
806
  if (!isInDir(nid, norm(getAppDir()))) return;
@@ -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, '/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"]}
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\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\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 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 const routesFiltered = routes.map(r => ({\r\n ...r,\r\n layouts: r.layouts.filter(l => isUsableLayout(l)),\r\n }));\r\n\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\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\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 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\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 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 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 webRes = await (handler as any).fetch(webReq.clone());\r\n if (webRes.status === 404) continue;\r\n } else if (typeof handler === 'function') {\r\n const params = matchRoute(route.routePath, pathname);\r\n if (params === null) continue;\r\n\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 } else {\r\n continue;\r\n }\r\n } catch {\r\n continue;\r\n }\r\n\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 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\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 // ── Determine outFile FIRST so import paths can be relative to it ──────────\r\n let outFile: string;\r\n if (platform === 'vercel') {\r\n outFile = path.join(cwd, 'api', 'index.ts');\r\n } else if (platform === 'cloudflare') {\r\n outFile = path.join(cwd, 'worker.ts');\r\n } else {\r\n outFile = path.join(cwd, 'server', 'index.ts');\r\n }\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\r\n // Import path relative to the output file directory, not the project root.\r\n // e.g. api/index.ts → ../src/app/api/hello (not ./src/app/api/hello)\r\n const rel = norm(path.relative(path.dirname(outFile), route.filePath)).replace(/\\.(ts|tsx)$/, '');\r\n const imp = rel.startsWith('.') ? rel : `./${rel}`;\r\n const name = `_route${i}`;\r\n\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: prefix with /api so the route matches what callers use.\r\n // Auto-wrap plain object returns as JSON so handlers don't need to return Response manually.\r\n mountings.push(`app.all('/api${route.routePath}', async (c) => { const r = await ${name}(c.req.raw); return r instanceof Response ? r : c.json(r); });`);\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 const appSetup = [\r\n ``,\r\n `const app = new Hono();`,\r\n ...(corsLine ? [corsLine] : []),\r\n ...mountings,\r\n ];\r\n\r\n let lines: string[];\r\n\r\n if (platform === 'vercel') {\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 } else if (platform === 'cloudflare') {\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 } else {\r\n // node\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 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 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 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 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 if (url.startsWith('/api') || url.includes('.')) return next();\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 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 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 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 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 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 (!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
@@ -282,8 +282,6 @@ function Spinner() {
282
282
  );
283
283
  }
284
284
 
285
- // Renders nothing \u2014 just sets document.title when the layout mounts.
286
- // Placed outside ErrorBoundary so a layout crash doesn't block the title update.
287
285
  function TitleSetter({ title }: { title: string }) {
288
286
  React.useEffect(() => { document.title = title; }, [title]);
289
287
  return null;
@@ -626,11 +624,19 @@ function buildProductionEntry(srcApiDir, platform, enableCors) {
626
624
  if (!fs.existsSync(srcApiDir)) return;
627
625
  const routes = scanApiRoutes(srcApiDir);
628
626
  const cwd = process.cwd();
627
+ let outFile;
628
+ if (platform === "vercel") {
629
+ outFile = path.join(cwd, "api", "index.ts");
630
+ } else if (platform === "cloudflare") {
631
+ outFile = path.join(cwd, "worker.ts");
632
+ } else {
633
+ outFile = path.join(cwd, "server", "index.ts");
634
+ }
629
635
  const imports = [];
630
636
  const mountings = [];
631
637
  for (let i = 0; i < routes.length; i++) {
632
638
  const route = routes[i];
633
- const rel = norm(path.relative(cwd, route.filePath)).replace(/\.(ts|tsx)$/, "");
639
+ const rel = norm(path.relative(path.dirname(outFile), route.filePath)).replace(/\.(ts|tsx)$/, "");
634
640
  const imp = rel.startsWith(".") ? rel : `./${rel}`;
635
641
  const name = `_route${i}`;
636
642
  let src = "";
@@ -643,7 +649,7 @@ function buildProductionEntry(srcApiDir, platform, enableCors) {
643
649
  if (isHonoApp) {
644
650
  mountings.push(`app.route('/', ${name});`);
645
651
  } else {
646
- mountings.push(`app.all('${route.routePath}', (c) => ${name}(c.req.raw));`);
652
+ mountings.push(`app.all('/api${route.routePath}', async (c) => { const r = await ${name}(c.req.raw); return r instanceof Response ? r : c.json(r); });`);
647
653
  }
648
654
  }
649
655
  const corsLine = enableCors ? `app.use('/api/*', cors({ origin: '*', allowMethods: ['GET','POST','PUT','PATCH','DELETE','OPTIONS'], allowHeaders: ['Content-Type','Authorization'] }));` : null;
@@ -652,16 +658,14 @@ function buildProductionEntry(srcApiDir, platform, enableCors) {
652
658
  `// Add routes by creating files in src/app/api/ only.`
653
659
  ];
654
660
  const corsImport = enableCors ? `import { cors } from 'hono/cors';` : null;
655
- let outFile;
656
- let lines;
657
661
  const appSetup = [
658
662
  ``,
659
663
  `const app = new Hono();`,
660
664
  ...corsLine ? [corsLine] : [],
661
665
  ...mountings
662
666
  ];
667
+ let lines;
663
668
  if (platform === "vercel") {
664
- outFile = path.join(cwd, "api", "index.ts");
665
669
  lines = [
666
670
  ...header,
667
671
  `import { Hono } from 'hono';`,
@@ -673,7 +677,6 @@ function buildProductionEntry(srcApiDir, platform, enableCors) {
673
677
  `export default app;`
674
678
  ];
675
679
  } else if (platform === "cloudflare") {
676
- outFile = path.join(cwd, "worker.ts");
677
680
  lines = [
678
681
  ...header,
679
682
  `import { Hono } from 'hono';`,
@@ -684,7 +687,6 @@ function buildProductionEntry(srcApiDir, platform, enableCors) {
684
687
  `export default app;`
685
688
  ];
686
689
  } else {
687
- outFile = path.join(cwd, "server", "index.ts");
688
690
  lines = [
689
691
  ...header,
690
692
  `import { Hono } from 'hono';`,
@@ -764,8 +766,6 @@ function biniroute(options = {}) {
764
766
  return {
765
767
  name: "bini-router",
766
768
  enforce: "pre",
767
- // Strip `export const metadata = {...}` from all src/app files before
768
- // @vitejs/plugin-react's Fast Refresh transform sees them.
769
769
  transform(code, id) {
770
770
  const nid = norm(id);
771
771
  if (!isInDir(nid, norm(getAppDir()))) return;
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, '/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":";AAAA,OAAO,QAAQ;AACf,OAAO,UAAU;AAKjB,IAAM,aAAkB,CAAC,YAAY,YAAY,WAAW,SAAS;AACrE,IAAM,eAAkB,CAAC,cAAc,cAAc,aAAa,WAAW;AAC7E,IAAM,iBAAkB,CAAC,QAAQ,QAAQ,OAAO,KAAK;AACrD,IAAM,kBAAkB,eAAe,IAAI,OAAK,YAAY,CAAC,EAAE;AAC/D,IAAM,gBAAkB,oBAAI,IAAI,CAAC,QAAQ,UAAU,aAAa,WAAW,OAAO,CAAC;AACnF,IAAM,WAAkB,CAAC,OAAO,KAAK;AACrC,IAAM,cAAkB;AACxB,IAAM,iBAAkB;AACxB,IAAM,eAAkB;AAwFxB,SAAS,KAAK,GAAmB;AAC/B,SAAO,EAAE,QAAQ,OAAO,GAAG;AAC7B;AAEA,SAAS,QAAQ,MAAc,KAAsB;AACnD,QAAM,QAAQ,KAAK,IAAI;AACvB,QAAM,OAAQ,KAAK,GAAG,EAAE,QAAQ,OAAO,EAAE;AACzC,SAAO,MAAM,WAAW,OAAO,GAAG,KAAK,UAAU;AACnD;AAEA,SAAS,sBAA8C;AACrD,QAAM,UAAkC,CAAC;AACzC,MAAI;AACF,UAAM,eAAe,KAAK,KAAK,QAAQ,IAAI,GAAG,eAAe;AAC7D,QAAI,CAAC,GAAG,WAAW,YAAY,EAAG,QAAO;AACzC,UAAM,MAAM,GAAG,aAAa,cAAc,MAAM,EAC7C,QAAQ,aAAa,EAAE,EACvB,QAAQ,qBAAqB,EAAE;AAClC,UAAM,WAAY,KAAK,MAAM,GAAG;AAChC,UAAM,QAAY,UAAU,iBAAiB,SAAS,CAAC;AACvD,UAAM,UAAY,UAAU,iBAAiB,WAAW;AACxD,eAAW,CAAC,OAAO,OAAO,KAAK,OAAO,QAAQ,KAAK,GAA2B;AAC5E,YAAM,aAAc,MAAM,QAAQ,SAAS,EAAE;AAC7C,YAAM,eAAe,QAAQ,CAAC,KAAK,IAAI,QAAQ,SAAS,EAAE;AAC1D,cAAQ,UAAU,IAAI,KAAK,QAAQ,QAAQ,IAAI,GAAG,SAAS,WAAW;AAAA,IACxE;AAAA,EACF,QAAQ;AAAA,EAA0D;AAClE,SAAO;AACT;AAEA,SAAS,aAAa,UAAkB,SAAyC;AAC/E,aAAW,CAAC,OAAO,MAAM,KAAK,OAAO,QAAQ,OAAO,GAAG;AACrD,QAAI,KAAK,QAAQ,EAAE,WAAW,KAAK,MAAM,IAAI,GAAG,GAAG;AACjD,YAAM,OAAO,KAAK,QAAQ,EAAE,MAAM,KAAK,MAAM,EAAE,SAAS,CAAC,EAAE,QAAQ,sBAAsB,EAAE;AAC3F,aAAO,GAAG,KAAK,IAAI,IAAI;AAAA,IACzB;AAAA,EACF;AACA,SAAO,OAAO,KAAK,KAAK,SAAS,KAAK,KAAK,QAAQ,IAAI,GAAG,KAAK,GAAG,QAAQ,CAAC,EACxE,QAAQ,sBAAsB,EAAE;AACrC;AAEA,SAAS,iBAAiB,UAA2B;AACnD,MAAI;AAAE,WAAO,GAAG,aAAa,UAAU,MAAM,EAAE,SAAS,gBAAgB;AAAA,EAAG,QACrE;AAAE,WAAO;AAAA,EAAO;AACxB;AAEA,SAAS,kBAAkB,UAA2B;AACpD,MAAI;AAAE,WAAO,cAAc,KAAK,GAAG,aAAa,UAAU,MAAM,CAAC;AAAA,EAAG,QAC9D;AAAE,WAAO;AAAA,EAAO;AACxB;AAEA,SAAS,eAAe,UAA2B;AACjD,SAAO,iBAAiB,QAAQ,KAAK,CAAC,kBAAkB,QAAQ;AAClE;AAEA,SAAS,SAAS,KAAa,YAA8C;AAC3E,SAAO,WAAW,KAAK,OAAK,GAAG,WAAW,KAAK,KAAK,KAAK,CAAC,CAAC,CAAC,KAAK;AACnE;AAEA,SAAS,aAAqB;AAC5B,QAAM,KAAK,KAAK,KAAK,QAAQ,IAAI,GAAG,aAAa;AACjD,SAAO,GAAG,WAAW,EAAE,IAAI,KAAK,KAAK,KAAK,QAAQ,IAAI,GAAG,aAAa;AACxE;AAIA,SAAS,mBAAmB,SAAiB,QAA0B;AACrE,QAAM,QAAkB,CAAC;AACzB,MAAI,UAAU;AACd,SAAO,MAAM;AACX,UAAM,SAAS,SAAS,SAAS,YAAY;AAC7C,QAAI,OAAQ,OAAM,QAAQ,KAAK,KAAK,SAAS,MAAM,CAAC;AACpD,QAAI,KAAK,QAAQ,OAAO,MAAM,KAAK,QAAQ,MAAM,EAAG;AACpD,UAAM,SAAS,KAAK,QAAQ,OAAO;AACnC,QAAI,WAAW,QAAS;AACxB,cAAU;AAAA,EACZ;AACA,SAAO;AACT;AAIA,SAAS,WAAW,KAAa,QAAgB,YAAY,IAAiB;AAC5E,QAAM,SAAsB,CAAC;AAC7B,MAAI,CAAC,GAAG,WAAW,GAAG,EAAG,QAAO;AAEhC,MAAI;AACJ,MAAI;AAAE,cAAU,GAAG,YAAY,KAAK,EAAE,eAAe,KAAK,CAAC;AAAA,EAAG,QACxD;AAAE,WAAO;AAAA,EAAQ;AAGvB,aAAW,SAAS,SAAS;AAC3B,QAAI,CAAC,MAAM,OAAO,KAAK,MAAM,KAAK,WAAW,GAAG,KAAK,MAAM,KAAK,WAAW,GAAG,EAAG;AACjF,UAAM,MAAO,KAAK,QAAQ,MAAM,IAAI;AACpC,UAAM,OAAO,KAAK,SAAS,MAAM,MAAM,GAAG;AAC1C,QAAI,CAAE,eAAqC,SAAS,GAAG,EAAG;AAC1D,QAAI,cAAc,IAAI,IAAI,EAAG;AAC7B,WAAO,KAAK;AAAA,MACV,WAAY,GAAG,SAAS,IAAI,IAAI;AAAA,MAChC,UAAY,KAAK,KAAK,KAAK,MAAM,IAAI;AAAA,MACrC,SAAY,mBAAmB,KAAK,MAAM;AAAA,MAC1C,SAAY;AAAA,IACd,CAAC;AAAA,EACH;AAGA,aAAW,SAAS,SAAS;AAC3B,QAAI,CAAC,MAAM,YAAY,EAAG;AAC1B,QAAI,MAAM,SAAS,kBAAkB,MAAM,KAAK,WAAW,GAAG,KAAK,MAAM,SAAS,MAAO;AAEzF,UAAM,WAAY,KAAK,KAAK,KAAK,MAAM,IAAI;AAC3C,UAAM,YAAY,MAAM,KAAK,WAAW,GAAG,KAAK,MAAM,KAAK,SAAS,GAAG;AACvE,UAAM,UAAY,YAAY,IAAI,MAAM,KAAK,MAAM,GAAG,EAAE,CAAC,KAAK,MAAM;AACpE,UAAM,YAAY,GAAG,SAAS,IAAI,OAAO;AAEzC,UAAM,WAAW,SAAS,UAAU,UAAU;AAC9C,QAAI,UAAU;AACZ,aAAO,KAAK;AAAA,QACV;AAAA,QACA,UAAW,KAAK,KAAK,UAAU,QAAQ;AAAA,QACvC,SAAW,mBAAmB,UAAU,MAAM;AAAA,QAC9C,SAAW;AAAA,MACb,CAAC;AAAA,IACH;AACA,WAAO,KAAK,GAAG,WAAW,UAAU,QAAQ,SAAS,CAAC;AAAA,EACxD;AAEA,SAAO;AACT;AAIA,SAAS,kBAAkB,QAAkC;AAC3D,QAAM,OAAO,oBAAI,IAAY;AAC7B,SAAO,OAAO,OAAO,OAAK;AACxB,QAAI,KAAK,IAAI,EAAE,SAAS,EAAG,QAAO;AAClC,SAAK,IAAI,EAAE,SAAS;AACpB,WAAO;AAAA,EACT,CAAC;AACH;AAIA,SAAS,iBAAiB,YAAmC;AAC3D,MAAI,MAAM;AACV,MAAI;AAAE,UAAM,GAAG,aAAa,YAAY,MAAM;AAAA,EAAG,QAC3C;AAAE,WAAO;AAAA,EAAM;AAErB,QAAM,WAAW,IAAI,QAAQ,uBAAuB;AACpD,MAAI,aAAa,GAAI,QAAO;AAC5B,QAAM,aAAa,IAAI,QAAQ,KAAK,QAAQ;AAC5C,MAAI,eAAe,GAAI,QAAO;AAE9B,MAAI,QAAQ,GAAG,MAAM;AACrB,WAAS,IAAI,YAAY,IAAI,IAAI,QAAQ,KAAK;AAC5C,QAAI,IAAI,CAAC,MAAM,IAAK;AAAA,aACX,IAAI,CAAC,MAAM,KAAK;AAAE;AAAS,UAAI,UAAU,GAAG;AAAE,cAAM;AAAG;AAAA,MAAO;AAAA,IAAE;AAAA,EAC3E;AACA,QAAM,QAAQ,IAAI,MAAM,YAAY,MAAM,CAAC;AAC3C,QAAM,QAAQ,4CAA4C,KAAK,KAAK;AACpE,SAAO,QAAQ,MAAM,CAAC,IAAI;AAC5B;AAIA,SAAS,YACP,SACA,eACA,aACA,WACA,cACA,QACQ;AACR,QAAM,MAAM,IAAI,OAAO,MAAM;AAC7B,MAAI,QAAQ,WAAW,GAAG;AACxB,WAAO,cAAc;AAAA,MAAI,OACvB,GAAG,GAAG,gBAAgB,EAAE,SAAS,+DAA+D,UAAU,IAAI,EAAE,QAAQ,CAAC;AAAA,IAC3H,EAAE,KAAK,IAAI;AAAA,EACb;AACA,QAAM,CAAC,MAAM,GAAG,IAAI,IAAI;AACxB,QAAM,QAAa,aAAa,IAAI,IAAI;AAGxC,QAAM,cAAc,QAAQ,sBAAsB,KAAK,UAAU,KAAK,CAAC,QAAQ;AAC/E,QAAM,QAAQ,YAAY,MAAM,eAAe,aAAa,WAAW,cAAc,SAAS,CAAC;AAC/F,QAAM,OAAQ,YAAY,IAAI,IAAI;AAClC,SAAO;AAAA,IACL,GAAG,GAAG,qBAAqB,WAAW,oDAAoD,IAAI,gBAAgB,IAAI;AAAA,IAClH;AAAA,IACA,GAAG,GAAG;AAAA,EACR,EAAE,KAAK,IAAI;AACb;AAIA,SAAS,YAAY,QAAwB;AAC3C,QAAM,UAAU,oBAAoB;AACpC,QAAM,SAAU,WAAW,QAAQ,MAAM;AAEzC,QAAM,WAAW,SAAS,QAAQ,UAAU;AAC5C,MAAI,UAAU;AACZ,WAAO,QAAQ;AAAA,MACb,WAAY;AAAA,MACZ,UAAY,KAAK,KAAK,QAAQ,QAAQ;AAAA,MACtC,SAAY,mBAAmB,QAAQ,MAAM;AAAA,MAC7C,SAAY;AAAA,IACd,CAAC;AAAA,EACH;AAGA,QAAM,iBAAiB,OAAO,IAAI,QAAM;AAAA,IACtC,GAAG;AAAA,IACH,SAAS,EAAE,QAAQ,OAAO,OAAK,eAAe,CAAC,CAAC;AAAA,EAClD,EAAE;AAGF,QAAM,cAAc;AAAA,IAClB,eAAe,OAAO,OAAK,iBAAiB,EAAE,QAAQ,CAAC;AAAA,EACzD;AAEA,cAAY,KAAK,CAAC,GAAG,MAAM;AACzB,QAAI,EAAE,YAAY,EAAE,QAAS,QAAO,EAAE,UAAU,IAAI;AACpD,WAAO,EAAE,UAAU,SAAS,EAAE,UAAU;AAAA,EAC1C,CAAC;AAED,QAAM,eAAe,gBAAgB,KAAK,OAAK,GAAG,WAAW,KAAK,KAAK,QAAQ,CAAC,CAAC,CAAC;AAClF,QAAM,WAAe,gBAAgB,iBAAiB,KAAK,KAAK,QAAQ,YAAY,CAAC,IACjF,eACA;AAEJ,QAAM,aAAa,oBAAI,IAAY;AACnC,aAAW,KAAK,YAAa,GAAE,QAAQ,QAAQ,OAAK;AAClD,QAAI,eAAe,CAAC,EAAG,YAAW,IAAI,CAAC;AAAA,EACzC,CAAC;AAED,QAAM,cAAe,oBAAI,IAAoB;AAC7C,QAAM,YAAe,oBAAI,IAAoB;AAC7C,QAAM,eAAe,oBAAI,IAAoB;AAC7C,MAAI,KAAK,GAAG,KAAK;AACjB,aAAW,KAAK,YAAY;AAC1B,gBAAY,IAAI,GAAG,SAAS,IAAI,EAAE;AAClC,UAAM,QAAQ,iBAAiB,CAAC;AAChC,QAAI,MAAO,cAAa,IAAI,GAAG,KAAK;AAAA,EACtC;AACA,aAAW,KAAK,aAAa;AAC3B,QAAI,CAAC,UAAU,IAAI,EAAE,QAAQ,EAAG,WAAU,IAAI,EAAE,UAAU,OAAO,IAAI,EAAE;AAAA,EACzE;AAEA,QAAM,cAAwB,CAAC;AAC/B,aAAW,CAAC,IAAI,IAAI,KAAK;AACvB,gBAAY,KAAK,SAAS,IAAI,+BAA+B,aAAa,IAAI,OAAO,CAAC,MAAM;AAC9F,MAAI;AACF,gBAAY,KAAK,6CAA6C,aAAa,KAAK,KAAK,QAAQ,QAAQ,GAAG,OAAO,CAAC,MAAM;AACxH,QAAM,eAAe,oBAAI,IAAY;AACrC,aAAW,KAAK,aAAa;AAC3B,QAAI,aAAa,IAAI,EAAE,QAAQ,EAAG;AAClC,iBAAa,IAAI,EAAE,QAAQ;AAC3B,UAAM,OAAO,UAAU,IAAI,EAAE,QAAQ;AACrC,QAAI,CAAC,KAAM;AACX,gBAAY,KAAK,SAAS,IAAI,+BAA+B,aAAa,EAAE,UAAU,OAAO,CAAC,MAAM;AAAA,EACtG;AAEA,QAAM,WAAW,oBAAI,IAA8B;AACnD,aAAW,KAAK,aAAa;AAC3B,UAAM,MAAM,EAAE,QAAQ,KAAK,GAAG;AAC9B,QAAI,CAAC,SAAS,IAAI,GAAG,EAAG,UAAS,IAAI,KAAK,EAAE,SAAS,EAAE,SAAS,QAAQ,CAAC,EAAE,CAAC;AAC5E,aAAS,IAAI,GAAG,EAAG,OAAO,KAAK,CAAC;AAAA,EAClC;AAEA,QAAM,aAAuB,CAAC;AAC9B,aAAW,CAAC,EAAE,EAAE,SAAS,QAAQ,GAAG,CAAC,KAAK;AACxC,eAAW,KAAK,YAAY,SAAS,IAAI,aAAa,WAAW,cAAc,CAAC,CAAC;AAEnF,QAAM,WAAW,WACb,kGACA;AAEJ,SAAO;AAAA;AAAA;AAAA;AAAA;AAAA,EAKP,YAAY,KAAK,IAAI,CAAC;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EA4CtB,WAAW,KAAK;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAUhB;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAMA,WAAW,KAAK,IAAI,CAAC;AAAA,EACrB,QAAQ;AAAA;AAAA;AAAA;AAAA;AAAA;AAMV;AAIA,SAAS,iBAAiB,QAA0B;AAClD,QAAM,SAAS,SAAS,QAAQ,YAAY;AAC5C,MAAI,CAAC,OAAQ,QAAO,CAAC;AACrB,MAAI,MAAM;AACV,MAAI;AAAE,UAAM,GAAG,aAAa,KAAK,KAAK,QAAQ,MAAM,GAAG,MAAM;AAAA,EAAG,QAC1D;AAAE,WAAO,CAAC;AAAA,EAAG;AAEnB,QAAM,WAAW,IAAI,QAAQ,uBAAuB;AACpD,MAAI,aAAa,GAAI,QAAO,CAAC;AAC7B,QAAM,aAAa,IAAI,QAAQ,KAAK,QAAQ;AAC5C,MAAI,eAAe,GAAI,QAAO,CAAC;AAE/B,MAAI,QAAQ,GAAG,MAAM;AACrB,WAAS,IAAI,YAAY,IAAI,IAAI,QAAQ,KAAK;AAC5C,QAAI,IAAI,CAAC,MAAM,IAAK;AAAA,aACX,IAAI,CAAC,MAAM,KAAK;AAAE;AAAS,UAAI,UAAU,GAAG;AAAE,cAAM;AAAG;AAAA,MAAO;AAAA,IAAE;AAAA,EAC3E;AACA,QAAM,QAAQ,IAAI,MAAM,YAAY,MAAM,CAAC;AAE3C,WAAS,aAAa,QAAgB,KAAiC;AACrE,UAAM,KAAQ,IAAI,OAAO,QAAQ,GAAG,mBAAmB;AACvD,UAAM,QAAQ,GAAG,KAAK,MAAM;AAC5B,QAAI,CAAC,MAAO,QAAO;AACnB,QAAI,IAAI,GAAG,IAAI,MAAM,QAAQ,MAAM,CAAC,EAAE,SAAS;AAC/C,UAAM,QAAQ;AACd,WAAO,IAAI,OAAO,QAAQ,KAAK;AAC7B,UAAI,OAAO,CAAC,MAAM,IAAK;AAAA,eACd,OAAO,CAAC,MAAM,KAAK;AAAE;AAAK,YAAI,MAAM,EAAG,QAAO,OAAO,MAAM,OAAO,IAAI,CAAC;AAAA,MAAG;AAAA,IACrF;AACA,WAAO;AAAA,EACT;AAEA,WAAS,aAAa,QAAgB,KAAiC;AACrE,UAAM,KAAQ,IAAI,OAAO,QAAQ,GAAG,mBAAmB;AACvD,UAAM,QAAQ,GAAG,KAAK,MAAM;AAC5B,QAAI,CAAC,MAAO,QAAO;AACnB,QAAI,IAAI,GAAG,IAAI,MAAM,QAAQ,MAAM,CAAC,EAAE,SAAS;AAC/C,UAAM,QAAQ;AACd,WAAO,IAAI,OAAO,QAAQ,KAAK;AAC7B,UAAI,OAAO,CAAC,MAAM,IAAK;AAAA,eACd,OAAO,CAAC,MAAM,KAAK;AAAE;AAAK,YAAI,MAAM,EAAG,QAAO,OAAO,MAAM,OAAO,IAAI,CAAC;AAAA,MAAG;AAAA,IACrF;AACA,WAAO;AAAA,EACT;AAEA,WAAS,IAAI,QAAgB,KAAiC;AAC5D,WAAO,OAAO;AAAA,MACZ,IAAI,OAAO,QAAQ,GAAG;AAAA,UAAwC;AAAA,IAChE,IAAI,CAAC;AAAA,EACP;AAEA,WAAS,cAAc,QAAgB,KAAiC;AACtE,UAAM,MAAM,aAAa,QAAQ,GAAG;AACpC,QAAI,CAAC,IAAK,QAAO;AACjB,WAAO,IAAI,MAAM,4BAA4B,IAAI,CAAC,KAC7C,IAAI,MAAM,kBAAkB,IAAI,CAAC;AAAA,EACxC;AAEA,WAAS,aAAa,QAAgB,KAAuB;AAC3D,UAAM,MAAM,aAAa,QAAQ,GAAG;AACpC,QAAI,CAAC,IAAK,QAAO,CAAC;AAClB,WAAO,CAAC,GAAG,IAAI,SAAS,mBAAmB,CAAC,EAAE,IAAI,OAAK,EAAE,CAAC,CAAC;AAAA,EAC7D;AAEA,QAAM,OAAiB,CAAC;AAExB,MAAI,IAAI,OAAO,OAAO,EAAS,MAAK,QAAc,IAAI,OAAO,OAAO;AACpE,MAAI,IAAI,OAAO,aAAa,EAAG,MAAK,cAAc,IAAI,OAAO,aAAa;AAC1E,MAAI,IAAI,OAAO,UAAU,EAAM,MAAK,WAAc,IAAI,OAAO,UAAU;AACvE,MAAI,IAAI,OAAO,YAAY,EAAI,MAAK,aAAc,IAAI,OAAO,YAAY;AACzE,MAAI,IAAI,OAAO,SAAS,EAAO,MAAK,UAAc,IAAI,OAAO,SAAS;AACtE,MAAI,IAAI,OAAO,QAAQ,EAAQ,MAAK,SAAc,IAAI,OAAO,QAAQ;AACrE,MAAI,IAAI,OAAO,WAAW,EAAK,MAAK,YAAc,IAAI,OAAO,WAAW;AACxE,MAAI,IAAI,OAAO,UAAU,EAAM,MAAK,WAAc,IAAI,OAAO,UAAU;AAEvE,QAAM,QAAQ,IAAI,OAAO,UAAU;AACnC,MAAI,OAAO;AACT,SAAK,WAAW;AAAA,EAClB,OAAO;AACL,UAAM,QAAQ,aAAa,OAAO,UAAU;AAC5C,QAAI,MAAM,OAAQ,MAAK,WAAW,MAAM,KAAK,IAAI;AAAA,EACnD;AAEA,QAAM,YAAY,IAAI,OAAO,QAAQ;AACrC,MAAI,WAAW;AACb,SAAK,SAAS;AAAA,EAChB,OAAO;AACL,UAAM,aAAa,aAAa,OAAO,SAAS;AAChD,QAAI,YAAY;AACd,YAAM,OAAO,WAAW,MAAM,6BAA6B,IAAI,CAAC;AAChE,UAAI,KAAM,MAAK,SAAS;AAAA,IAC1B;AAAA,EACF;AAEA,MAAI,CAAC,KAAK,WAAW;AACnB,UAAM,OAAO,MAAM,MAAM,sDAAsD,IAAI,CAAC;AACpF,QAAI,KAAM,MAAK,YAAY;AAAA,EAC7B;AAEA,QAAM,UAAU,aAAa,OAAO,WAAW;AAC/C,MAAI,SAAS;AACX,SAAK,YAAY;AAAA,MACf,OAAc,IAAI,SAAS,OAAO;AAAA,MAClC,aAAc,IAAI,SAAS,aAAa;AAAA,MACxC,KAAc,IAAI,SAAS,KAAK;AAAA,MAChC,MAAc,IAAI,SAAS,MAAM;AAAA,MACjC,OAAc,cAAc,SAAS,QAAQ,KAAK,IAAI,SAAS,OAAO;AAAA,IACxE;AAAA,EACF;AAEA,QAAM,UAAU,aAAa,OAAO,SAAS;AAC7C,MAAI,SAAS;AACX,SAAK,UAAU;AAAA,MACb,MAAc,IAAI,SAAS,MAAM;AAAA,MACjC,OAAc,IAAI,SAAS,OAAO;AAAA,MAClC,aAAc,IAAI,SAAS,aAAa;AAAA,MACxC,SAAc,IAAI,SAAS,SAAS;AAAA,MACpC,OAAc,cAAc,SAAS,QAAQ,KAAK,IAAI,SAAS,OAAO;AAAA,IACxE;AAAA,EACF;AAEA,QAAM,aAAa,aAAa,OAAO,OAAO;AAC9C,MAAI,YAAY;AACd,SAAK,QAAQ;AAAA,MACX,MAAU,mBAAmB,YAAY,MAAM;AAAA,MAC/C,UAAU,mBAAmB,YAAY,UAAU;AAAA,MACnD,OAAU,mBAAmB,YAAY,OAAO;AAAA,IAClD;AAAA,EACF;AAEA,SAAO;AACT;AAEA,SAAS,mBAAmB,QAAgB,KAA0B;AACpE,QAAM,MAAM,gBAAgB,QAAQ,GAAG;AACvC,MAAI,CAAC,IAAK,QAAO,CAAC;AAClB,QAAM,UAAuB,CAAC;AAC9B,QAAM,QAAQ;AACd,MAAI;AACJ,UAAQ,IAAI,MAAM,KAAK,GAAG,OAAO,MAAM;AACrC,UAAM,MAAO,EAAE,CAAC;AAChB,UAAM,MAAO,IAAI,MAAM,4BAA4B,IAAI,CAAC;AACxD,QAAI,CAAC,IAAK;AACV,YAAQ,KAAK;AAAA,MACX;AAAA,MACA,MAAO,IAAI,MAAM,6BAA6B,IAAI,CAAC;AAAA,MACnD,OAAO,IAAI,MAAM,8BAA8B,IAAI,CAAC;AAAA,IACtD,CAAC;AAAA,EACH;AACA,MAAI,CAAC,QAAQ,QAAQ;AACnB,WAAO,CAAC,GAAG,IAAI,SAAS,mBAAmB,CAAC,EAAE,IAAI,QAAM,EAAE,KAAK,EAAE,CAAC,EAAE,EAAE;AAAA,EACxE;AACA,SAAO;AACT;AAEA,SAAS,gBAAgB,QAAgB,KAAiC;AACxE,QAAM,KAAQ,IAAI,OAAO,QAAQ,GAAG,mBAAmB;AACvD,QAAM,QAAQ,GAAG,KAAK,MAAM;AAC5B,MAAI,CAAC,MAAO,QAAO;AACnB,MAAI,IAAI,GAAG,IAAI,MAAM,QAAQ,MAAM,CAAC,EAAE,SAAS;AAC/C,QAAM,QAAQ;AACd,SAAO,IAAI,OAAO,QAAQ,KAAK;AAC7B,QAAI,OAAO,CAAC,MAAM,IAAK;AAAA,aACd,OAAO,CAAC,MAAM,KAAK;AAAE;AAAK,UAAI,MAAM,EAAG,QAAO,OAAO,MAAM,OAAO,IAAI,CAAC;AAAA,IAAG;AAAA,EACrF;AACA,SAAO;AACT;AAIA,SAAS,cAAc,KAAa,YAAY,IAAgB;AAC9D,QAAM,SAAqB,CAAC;AAC5B,MAAI,CAAC,GAAG,WAAW,GAAG,EAAG,QAAO;AAEhC,MAAI;AACJ,MAAI;AAAE,cAAU,GAAG,YAAY,KAAK,EAAE,eAAe,KAAK,CAAC;AAAA,EAAG,QACxD;AAAE,WAAO;AAAA,EAAQ;AAEvB,aAAW,SAAS,SAAS;AAC3B,QAAI,MAAM,KAAK,WAAW,GAAG,KAAK,MAAM,KAAK,WAAW,GAAG,EAAG;AAC9D,UAAM,WAAW,KAAK,KAAK,KAAK,MAAM,IAAI;AAE1C,QAAI,MAAM,YAAY,GAAG;AACvB,YAAMA,cAAa,MAAM,KAAK,WAAW,MAAM,KAAK,MAAM,KAAK,SAAS,GAAG;AAC3E,YAAMC,aAAa,MAAM,KAAK,WAAW,GAAG,KAAK,MAAM,KAAK,SAAS,GAAG;AACxE,YAAM,UAAaD,cAAa,MAAMC,aAAY,IAAI,MAAM,KAAK,MAAM,GAAG,EAAE,CAAC,KAAK,MAAM;AACxF,aAAO,KAAK,GAAG,cAAc,UAAU,GAAG,SAAS,IAAI,OAAO,EAAE,CAAC;AACjE;AAAA,IACF;AAEA,UAAM,MAAO,KAAK,QAAQ,MAAM,IAAI;AACpC,UAAM,OAAO,KAAK,SAAS,MAAM,MAAM,GAAG;AAC1C,QAAI,CAAE,SAA+B,SAAS,GAAG,EAAG;AAEpD,UAAM,aAAa,KAAK,WAAW,MAAM,KAAK,KAAK,SAAS,GAAG;AAC/D,UAAM,YAAa,KAAK,WAAW,GAAG,KAAK,KAAK,SAAS,GAAG;AAC5D,UAAM,YAAa,aACf,GAAG,SAAS,OACZ,SAAS,UACP,aAAa,MACb,YACE,GAAG,SAAS,KAAK,KAAK,MAAM,GAAG,EAAE,CAAC,KAClC,GAAG,SAAS,IAAI,IAAI;AAE5B,WAAO,KAAK,EAAE,WAAW,UAAU,SAAS,CAAC;AAAA,EAC/C;AAEA,SAAO;AACT;AAcA,SAAS,WAAW,SAAiB,UAAiD;AACpF,QAAM,WAAW,QAAQ,MAAM,GAAG,EAAE,OAAO,OAAO;AAClD,QAAM,WAAW,SAAS,MAAM,GAAG,EAAE,OAAO,OAAO;AAGnD,QAAM,aAAa,SAAS,SAAS,SAAS,CAAC,MAAM;AACrD,MAAI,YAAY;AACd,UAAM,SAAS,SAAS,MAAM,GAAG,EAAE;AACnC,QAAI,SAAS,SAAS,OAAO,OAAQ,QAAO;AAC5C,aAAS,IAAI,GAAG,IAAI,OAAO,QAAQ,KAAK;AACtC,UAAI,OAAO,CAAC,EAAE,WAAW,GAAG,EAAG;AAC/B,UAAI,OAAO,CAAC,MAAM,SAAS,CAAC,EAAG,QAAO;AAAA,IACxC;AACA,WAAO,EAAE,KAAK,SAAS,MAAM,OAAO,MAAM,EAAE,KAAK,GAAG,EAAE;AAAA,EACxD;AAEA,MAAI,SAAS,WAAW,SAAS,OAAQ,QAAO;AAEhD,QAAM,SAAiC,CAAC;AACxC,WAAS,IAAI,GAAG,IAAI,SAAS,QAAQ,KAAK;AACxC,QAAI,SAAS,CAAC,EAAE,WAAW,GAAG,GAAG;AAC/B,aAAO,SAAS,CAAC,EAAE,MAAM,CAAC,CAAC,IAAI,mBAAmB,SAAS,CAAC,CAAC;AAAA,IAC/D,WAAW,SAAS,CAAC,MAAM,SAAS,CAAC,GAAG;AACtC,aAAO;AAAA,IACT;AAAA,EACF;AACA,SAAO;AACT;AAIA,IAAM,cAAc,oBAAI,IAAiD;AAEzE,eAAe,cAAc,UAAoC;AAC/D,QAAM,EAAE,cAAc,IAAI,MAAM,OAAO,KAAK;AAC5C,MAAI,QAAQ;AACZ,MAAI;AAAE,YAAQ,GAAG,SAAS,QAAQ,EAAE;AAAA,EAAS,QAAQ;AAAA,EAAsB;AAE3E,QAAM,SAAS,YAAY,IAAI,QAAQ;AACvC,MAAI,UAAU,OAAO,UAAU,MAAO,QAAO,OAAO;AAGpD,QAAM,MAAU,MAAM,OAAO,cAAc,QAAQ,EAAE,OAAO,QAAQ;AACpE,QAAM,UAAU,IAAI,WAAW;AAC/B,cAAY,IAAI,UAAU,EAAE,OAAO,QAAQ,CAAC;AAC5C,SAAO;AACT;AAEA,eAAe,iBACb,KACA,KACA,MACA,QACA,YACA,UACA,UACA;AACA,MAAI;AAEF,QAAI,cAAc,IAAI,WAAW,WAAW;AAC1C,UAAI,aAAa;AACjB,UAAI,UAAU,+BAA+B,GAAG;AAChD,UAAI,UAAU,gCAAgC,mCAAmC;AACjF,UAAI,UAAU,gCAAgC,4BAA4B;AAC1E,UAAI,UAAU,0BAA0B,OAAO;AAC/C,UAAI,IAAI;AACR;AAAA,IACF;AAEA,QAAI,QAAQ,SAAS;AACrB,QAAI,CAAC,OAAO;AACV,cAAQ,EAAE,QAAQ,cAAc,QAAQ,MAAM,EAAE;AAChD,eAAS,KAAK;AAAA,IAChB;AAEA,UAAM,OAAW,IAAI,QAAQ,QAAQ;AACrC,UAAM,MAAW,UAAU,IAAI,GAAG,IAAI,GAAG;AACzC,UAAM,WAAW,IAAI,IAAI,GAAG,EAAE;AAE9B,UAAM,SAAmB,CAAC;AAC1B,qBAAiB,SAAS,IAAK,QAAO,KAAK,KAAe;AAC1D,UAAM,OAAO,OAAO,SAAS,IAAI,OAAO,OAAO,MAAM,IAAI;AAEzD,UAAM,SAAU,IAAI,OAAkB,YAAY;AAElD,UAAM,SAAS,IAAI,QAAQ,KAAK;AAAA,MAC9B;AAAA,MACA,SAAS,IAAI;AAAA,MACb,MAAS,CAAC,CAAC,OAAO,MAAM,EAAE,SAAS,MAAM,KAAK,MAAM,SAAS,OAAO;AAAA,IACtE,CAAC;AAED,eAAW,SAAS,MAAM,QAAQ;AAChC,YAAM,UAAU,MAAM,cAAc,MAAM,QAAQ;AAClD,UAAI,CAAC,QAAS;AAEd,UAAI;AACJ,UAAI;AACF,YAAI,OAAQ,QAAgB,UAAU,YAAY;AAEhD,mBAAS,MAAO,QAAgB,MAAM,OAAO,MAAM,CAAC;AAGpD,cAAI,OAAO,WAAW,IAAK;AAAA,QAE7B,WAAW,OAAO,YAAY,YAAY;AAGxC,gBAAM,SAAS,WAAW,MAAM,WAAW,QAAQ;AACnD,cAAI,WAAW,KAAM;AAIrB,gBAAM,kBAA0C,CAAC;AACjD,iBAAO,QAAQ,QAAQ,CAAC,GAAG,MAAM;AAAE,4BAAgB,CAAC,IAAI;AAAA,UAAG,CAAC;AAC5D,gBAAM,gBAAgB,IAAI,QAAQ,OAAO,MAAM,GAAG;AAAA,YAChD,SAAS,EAAE,GAAG,iBAAiB,iBAAiB,KAAK,UAAU,MAAM,EAAE;AAAA,UACzE,CAAC;AAED,mBAAS,MAAO,QAAkD,aAAa;AAAA,QAEjF,OAAO;AACL;AAAA,QACF;AAAA,MACF,QAAQ;AACN;AAAA,MACF;AAGA,YAAM,eAAuC,CAAC;AAC9C,aAAO,QAAQ,QAAQ,CAAC,GAAG,MAAM;AAAE,qBAAa,CAAC,IAAI;AAAA,MAAG,CAAC;AACzD,UAAI,YAAY;AACd,qBAAa,6BAA6B,IAAK;AAC/C,qBAAa,8BAA8B,IAAI;AAC/C,qBAAa,8BAA8B,IAAI;AAAA,MACjD;AAEA,UAAI,aAAa,OAAO;AACxB,iBAAW,CAAC,GAAG,CAAC,KAAK,OAAO,QAAQ,YAAY,EAAG,KAAI,UAAU,GAAG,CAAC;AACrE,UAAI,IAAI,OAAO,KAAK,MAAM,OAAO,YAAY,CAAC,CAAC;AAC/C;AAAA,IACF;AAGA,QAAI,aAAa;AACjB,QAAI,UAAU,gBAAgB,kBAAkB;AAChD,QAAI,IAAI,KAAK,UAAU,EAAE,OAAO,4BAA4B,IAAI,GAAG,GAAG,CAAC,CAAC;AAAA,EAC1E,SAAS,GAAQ;AACf,SAAK,CAAC;AAAA,EACR;AACF;AAYA,SAAS,qBAAqB,WAAmB,UAA4C,YAA2B;AACtH,MAAI,CAAC,GAAG,WAAW,SAAS,EAAG;AAE/B,QAAM,SAAS,cAAc,SAAS;AACtC,QAAM,MAAS,QAAQ,IAAI;AAE3B,QAAM,UAAsB,CAAC;AAC7B,QAAM,YAAsB,CAAC;AAE7B,WAAS,IAAI,GAAG,IAAI,OAAO,QAAQ,KAAK;AACtC,UAAM,QAAW,OAAO,CAAC;AACzB,UAAM,MAAW,KAAK,KAAK,SAAS,KAAK,MAAM,QAAQ,CAAC,EAAE,QAAQ,eAAe,EAAE;AACnF,UAAM,MAAW,IAAI,WAAW,GAAG,IAAI,MAAM,KAAK,GAAG;AACrD,UAAM,OAAW,SAAS,CAAC;AAI3B,QAAI,MAAM;AACV,QAAI;AAAE,YAAM,GAAG,aAAa,MAAM,UAAU,MAAM;AAAA,IAAG,QAAQ;AAAA,IAAa;AAC1E,UAAM,YAAY,IAAI,SAAS,aAAa,KAAK,IAAI,SAAS,aAAa;AAE3E,YAAQ,KAAK,UAAU,IAAI,UAAU,GAAG,IAAI;AAE5C,QAAI,WAAW;AAEb,gBAAU,KAAK,kBAAkB,IAAI,IAAI;AAAA,IAC3C,OAAO;AAEL,gBAAU,KAAK,YAAY,MAAM,SAAS,aAAa,IAAI,eAAe;AAAA,IAC5E;AAAA,EACF;AAEA,QAAM,WAAW,aACb,6JACA;AAEJ,QAAM,SAAS;AAAA,IACb;AAAA,IACA;AAAA,EACF;AAEA,QAAM,aAAa,aAAa,sCAAsC;AAEtE,MAAI;AACJ,MAAI;AAEJ,QAAM,WAAW;AAAA,IACf;AAAA,IACA;AAAA,IACA,GAAI,WAAW,CAAC,QAAQ,IAAI,CAAC;AAAA,IAC7B,GAAG;AAAA,EACL;AAEA,MAAI,aAAa,UAAU;AACzB,cAAU,KAAK,KAAK,KAAK,OAAO,UAAU;AAG1C,YAAQ;AAAA,MACN,GAAG;AAAA,MACH;AAAA,MACA,GAAI,aAAa,CAAC,UAAU,IAAI,CAAC;AAAA,MACjC,GAAG;AAAA,MACH,GAAG;AAAA,MACH;AAAA,MACA;AAAA,MACA;AAAA,IACF;AAAA,EAEF,WAAW,aAAa,cAAc;AACpC,cAAU,KAAK,KAAK,KAAK,WAAW;AACpC,YAAQ;AAAA,MACN,GAAG;AAAA,MACH;AAAA,MACA,GAAI,aAAa,CAAC,UAAU,IAAI,CAAC;AAAA,MACjC,GAAG;AAAA,MACH,GAAG;AAAA,MACH;AAAA,MACA;AAAA,IACF;AAAA,EAEF,OAAO;AAEL,cAAU,KAAK,KAAK,KAAK,UAAU,UAAU;AAC7C,YAAQ;AAAA,MACN,GAAG;AAAA,MACH;AAAA,MACA;AAAA,MACA;AAAA,MACA,GAAI,aAAa,CAAC,UAAU,IAAI,CAAC;AAAA,MACjC,GAAG;AAAA,MACH,GAAG;AAAA,MACH;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,IACF;AAAA,EACF;AAEA,KAAG,UAAU,KAAK,QAAQ,OAAO,GAAG,EAAE,WAAW,KAAK,CAAC;AACvD,KAAG,cAAc,SAAS,MAAM,KAAK,IAAI,IAAI,MAAM,MAAM;AACzD,UAAQ,IAAI,kCAA6B,KAAK,KAAK,SAAS,KAAK,OAAO,CAAC,CAAC,EAAE;AAC9E;AAIO,SAAS,UAAU,UAA6B,CAAC,GAAW;AACjE,QAAM,EAAE,MAAM,aAAa,MAAM,SAAS,IAAI;AAE9C,QAAM,YAAY,MAAM,KAAK,KAAK,QAAQ,IAAI,GAAG,QAAQ,UAAU,SAAS;AAC5E,QAAM,YAAY,MAAM,KAAK,KAAK,QAAQ,IAAI,GAAG,QAAQ,UAAU,aAAa;AAGhF,MAAI,gBAA0D;AAC9D,MAAI,oBAAoB;AACxB,MAAI,YAAmD;AACvD,QAAM,WAAkB,oBAAI,IAAoB;AAEhD,WAAS,cAAc,MAAc,OAAwB;AAC3D,UAAM,MAAM,GAAG,IAAI,IAAI,KAAK;AAC5B,UAAM,MAAM,KAAK,IAAI;AACrB,QAAI,OAAO,SAAS,IAAI,GAAG,KAAK,KAAK,eAAgB,QAAO;AAC5D,aAAS,IAAI,KAAK,GAAG;AACrB,eAAW,CAAC,GAAG,CAAC,KAAK,SAAU,KAAI,MAAM,IAAI,aAAc,UAAS,OAAO,CAAC;AAC5E,WAAO;AAAA,EACT;AAIA,WAAS,WAAW,GAAoB;AACtC,UAAM,KAAO,KAAK,CAAC;AACnB,UAAM,OAAO,KAAK,SAAS,GAAG,KAAK,QAAQ,CAAC,CAAC;AAC7C,UAAM,MAAO,KAAK,QAAQ,CAAC;AAC3B,QAAI,CAAE,eAAqC,SAAS,GAAG,EAAG,QAAO;AACjE,QAAI,CAAC,QAAQ,IAAI,KAAK,UAAU,CAAC,CAAC,EAAG,QAAO;AAC5C,QAAI,QAAQ,IAAI,KAAK,UAAU,CAAC,CAAC,EAAG,QAAO;AAC3C,QAAI,KAAK,WAAW,GAAG,EAAG,QAAO;AACjC,WAAO;AAAA,EACT;AAEA,WAAS,UAAU,GAAoB;AACrC,UAAM,KAAK,KAAK,CAAC;AACjB,WAAO,QAAQ,IAAI,KAAK,UAAU,CAAC,CAAC,KACjC,SAA+B,SAAS,KAAK,QAAQ,CAAC,CAAC;AAAA,EAC5D;AAGA,WAAS,WAA0B;AACjC,UAAM,MAAM,UAAU;AACtB,QAAI,CAAC,GAAG,WAAW,GAAG,EAAG,QAAO;AAChC,UAAM,OAAO,YAAY,GAAG;AAC5B,QAAI,SAAS,kBAAmB,QAAO;AACvC,OAAG,cAAc,WAAW,GAAG,MAAM,MAAM;AAC3C,wBAAoB;AACpB,WAAO;AAAA,EACT;AAEA,WAAS,cAAc,QAAuB,QAAQ,aAAa;AACjE,QAAI,cAAe,cAAa,aAAa;AAC7C,oBAAgB,WAAW,MAAM;AAC/B,sBAAgB;AAChB,UAAI,SAAS,MAAM,MAAM;AACvB,eAAO,GAAG,KAAK,EAAE,MAAM,eAAe,MAAM,IAAI,CAAC;AAAA,MACnD;AAAA,IACF,GAAG,KAAK;AAAA,EACV;AAGA,WAAS,eAAe,QAA8B;AACpD,WAAO,YAAY,IAAI,CAAC,KAAU,KAAU,SAAc;AACxD,YAAM,MAAM,IAAI;AAEhB,UAAI,IAAI,WAAW,MAAM,KAAK,IAAI,SAAS,GAAG,EAAG,QAAO,KAAK;AAE7D,UAAI,MAAM;AACV,WAAK;AAAA,IACP,CAAC;AAAA,EACH;AAEA,SAAO;AAAA,IACL,MAAS;AAAA,IACT,SAAS;AAAA;AAAA;AAAA,IAIT,UAAU,MAAM,IAAI;AAClB,YAAM,MAAM,KAAK,EAAE;AACnB,UAAI,CAAC,QAAQ,KAAK,KAAK,UAAU,CAAC,CAAC,EAAG;AACtC,YAAM,MAAM,KAAK,QAAQ,EAAE;AAC3B,UAAI,CAAE,eAAqC,SAAS,GAAG,EAAG;AAC1D,UAAI,CAAC,KAAK,SAAS,uBAAuB,EAAG;AAE7C,UAAI,SAAS;AACb,UAAI,MAAS,OAAO,QAAQ,uBAAuB;AAEnD,aAAO,QAAQ,IAAI;AACjB,cAAM,WAAW,OAAO,QAAQ,KAAK,GAAG;AACxC,YAAI,aAAa,GAAI;AAErB,YAAI,QAAQ,GAAG,MAAM;AACrB,iBAAS,IAAI,UAAU,IAAI,OAAO,QAAQ,KAAK;AAC7C,cAAI,OAAO,CAAC,MAAM,IAAU;AAAA,mBACnB,OAAO,CAAC,MAAM,KAAK;AAAE;AAAS,gBAAI,UAAU,GAAG;AAAE,oBAAM;AAAG;AAAA,YAAO;AAAA,UAAE;AAAA,QAC9E;AAEA,YAAI,OAAO,MAAM;AACjB,eAAO,OAAO,OAAO,WAAW,OAAO,IAAI,MAAM,OAAO,OAAO,IAAI,MAAM,KAAO;AAChF,YAAI,OAAO,OAAO,UAAU,OAAO,IAAI,MAAM,IAAK;AAClD,eAAO,OAAO,OAAO,WAAW,OAAO,IAAI,MAAM,QAAQ,OAAO,IAAI,MAAM,MAAO;AAEjF,iBAAS,OAAO,MAAM,GAAG,GAAG,IAAI,OAAO,MAAM,IAAI;AACjD,cAAS,OAAO,QAAQ,yBAAyB,GAAG;AAAA,MACtD;AAEA,aAAO,EAAE,MAAM,QAAQ,KAAK,KAAK;AAAA,IACnC;AAAA,IAEA,SAAa;AAAE,eAAS;AAAA,IAAG;AAAA,IAC3B,aAAa;AAAE,eAAS;AAAA,IAAG;AAAA,IAE3B,cAAc;AACZ,UAAI,SAAU,sBAAqB,UAAU,GAAG,UAAU,UAAU;AAAA,IACtE;AAAA,IAEA,WAAW;AAET,kBAAY;AACZ,kBAAY,MAAM;AAClB,UAAI,eAAe;AAAE,qBAAa,aAAa;AAAG,wBAAgB;AAAA,MAAM;AAAA,IAC1E;AAAA,IAEA,MAAM,gBAAgB,QAAQ;AAC5B,YAAM,SAAS,UAAU;AACzB,YAAM,SAAS,UAAU;AAEzB,UAAI,CAAC,GAAG,WAAW,MAAM,EAAG;AAE5B,aAAO,QAAQ,IAAI,MAAM;AAEzB,aAAO,QAAQ,GAAG,OAAU,OAAK,WAAW,CAAC,KAAK,cAAc,GAAG,KAAK,KAAQ,cAAc,QAAQ,GAAG,CAAC;AAC1G,aAAO,QAAQ,GAAG,UAAU,OAAK,WAAW,CAAC,KAAK,cAAc,GAAG,QAAQ,KAAK,cAAc,MAAM,CAAC;AACrG,aAAO,QAAQ,GAAG,UAAU,OAAK,WAAW,CAAC,KAAK,cAAc,GAAG,QAAQ,KAAK,cAAc,MAAM,CAAC;AAGrG,aAAO,QAAQ,GAAG,UAAU,OAAK;AAC/B,cAAM,OAAY,KAAK,SAAS,GAAG,KAAK,QAAQ,CAAC,CAAC;AAClD,cAAM,YAAY,KAAK,QAAQ,KAAK,QAAQ,CAAC,CAAC,MAAM,KAAK,QAAQ,MAAM;AACvE,YAAI,CAAC,aAAa,SAAS,SAAU;AACrC,eAAO,YAAY,cAAc;AACjC,eAAO,GAAG,KAAK,EAAE,MAAM,eAAe,MAAM,IAAI,CAAC;AAAA,MACnD,CAAC;AAED,aAAO,QAAQ,GAAG,UAAU,OAAK;AAC/B,cAAM,KAAK,KAAK,CAAC;AACjB,YAAI,CAAC,QAAQ,IAAI,KAAK,MAAM,CAAC,KAAK,EAAE,SAAS,cAAc,KAAK,QAAQ,IAAI,KAAK,MAAM,CAAC,EAAG;AAC3F,mBAAW,MAAM,WAAW,KAAK,OAAK,GAAG,WAAW,KAAK,KAAK,GAAG,CAAC,CAAC,CAAC,KAAK,cAAc,MAAM,GAAG,GAAG;AAAA,MACrG,CAAC;AAED,aAAO,QAAQ,GAAG,aAAa,OAAK;AAClC,cAAM,KAAK,KAAK,CAAC;AACjB,YAAI,QAAQ,IAAI,KAAK,MAAM,CAAC,KAAK,CAAC,EAAE,SAAS,cAAc,KAAK,CAAC,QAAQ,IAAI,KAAK,MAAM,CAAC;AACvF,wBAAc,MAAM;AAAA,MACxB,CAAC;AAED,UAAI,GAAG,WAAW,MAAM,GAAG;AACzB,eAAO,QAAQ,IAAI,MAAM;AAEzB,cAAM,WAAW,CAAC,MAAe;AAC/B,sBAAY;AAGZ,cAAI,EAAG,aAAY,OAAO,CAAC;AAC3B,iBAAO,GAAG,KAAK,EAAE,MAAM,eAAe,MAAM,IAAI,CAAC;AAAA,QACnD;AAEA,eAAO,QAAQ,GAAG,OAAU,OAAK,UAAU,CAAC,KAAK,SAAS,CAAC,CAAC;AAC5D,eAAO,QAAQ,GAAG,UAAU,OAAK,UAAU,CAAC,KAAK,SAAS,CAAC,CAAC;AAC5D,eAAO,QAAQ,GAAG,UAAU,OAAK,UAAU,CAAC,KAAK,SAAS,CAAC,CAAC;AAE5D,eAAO,YAAY,IAAI,CAAC,KAAU,KAAU,SAAc;AACxD,cAAI,CAAC,IAAI,KAAK,WAAW,MAAM,EAAG,QAAO,KAAK;AAC9C;AAAA,YAAiB;AAAA,YAAK;AAAA,YAAK;AAAA,YAAM;AAAA,YAAQ;AAAA,YACvC,MAAM;AAAA,YAAW,CAAC,MAAM;AAAE,0BAAY;AAAA,YAAG;AAAA,UAAC;AAAA,QAC9C,CAAC;AAAA,MACH;AAAA,IACF;AAAA,IAEA,MAAM,uBAAuB,QAAQ;AAEnC,qBAAe,MAAM;AAErB,YAAM,SAAS,UAAU;AACzB,UAAI,CAAC,GAAG,WAAW,MAAM,EAAG;AAC5B,aAAO,YAAY,IAAI,CAAC,KAAU,KAAU,SAAc;AACxD,YAAI,CAAC,IAAI,KAAK,WAAW,MAAM,EAAG,QAAO,KAAK;AAC9C;AAAA,UAAiB;AAAA,UAAK;AAAA,UAAK;AAAA,UAAM;AAAA,UAAQ;AAAA,UACvC,MAAM;AAAA,UAAW,CAAC,MAAM;AAAE,wBAAY;AAAA,UAAG;AAAA,QAAC;AAAA,MAC9C,CAAC;AAAA,IACH;AAAA,IAEA,oBAAoB;AAAA,MAClB,OAAO;AAAA,MACP,QAAQ,MAAM;AACZ,cAAM,OAAQ,iBAAiB,UAAU,CAAC;AAI1C,YAAI,CAAC,KAAK,SAAS,CAAC,KAAK,eAAe,CAAC,KAAK,aAAa,CAAC,KAAK,YAC7D,CAAC,KAAK,WAAW,SAAS,CAAC,KAAK,OAAO,MAAM,QAAQ;AACvD,iBAAO;AAAA,QACT;AAEA,cAAM,QAAQ,KAAK,SAAY;AAC/B,cAAM,KAAQ,KAAK,YAAY;AAE/B,cAAM,QAAkB,CAAC;AAEzB,cAAM,KAAK,kBAAkB,KAAK,WAAW,OAAO,MAAM;AAC1D,cAAM,KAAK,kCAAkC,EAAE,MAAM;AACrD,cAAM,KAAK,UAAU,KAAK,UAAU;AACpC,YAAI,KAAK,YAAa,OAAM,KAAK,qCAAqC,KAAK,WAAW,MAAM;AAC5F,YAAI,KAAK,WAAa,OAAM,KAAK,qCAAqC,KAAK,UAAU,MAAM;AAC3F,YAAI,KAAK,OAAa,OAAM,KAAK,gCAAgC,KAAK,MAAM,MAAM;AAClF,YAAI,KAAK,SAAa,OAAM,KAAK,kCAAkC,KAAK,QAAQ,MAAM;AACtF,YAAI,KAAK,OAAa,OAAM,KAAK,gCAAgC,KAAK,MAAM,MAAM;AAClF,YAAI,KAAK,UAAa,OAAM,KAAK,+BAA+B,KAAK,SAAS,MAAM;AACpF,YAAI,KAAK,SAAa,OAAM,KAAK,8BAA8B,KAAK,QAAQ,MAAM;AAElF,mBAAW,SAAS,KAAK,OAAO,QAAQ,CAAC,GAAG;AAC1C,gBAAM,OAAQ,MAAM,OAAQ,UAAU,MAAM,IAAI,MAAQ;AACxD,gBAAM,QAAQ,MAAM,QAAQ,WAAW,MAAM,KAAK,MAAM;AACxD,gBAAM,KAAK,0BAA0B,MAAM,GAAG,IAAI,IAAI,GAAG,KAAK,KAAK;AAAA,QACrE;AACA,mBAAW,SAAS,KAAK,OAAO,YAAY,CAAC,GAAG;AAC9C,gBAAM,KAAK,mCAAmC,MAAM,GAAG,MAAM;AAAA,QAC/D;AACA,mBAAW,SAAS,KAAK,OAAO,SAAS,CAAC,GAAG;AAC3C,gBAAM,QAAQ,MAAM,QAAQ,WAAW,MAAM,KAAK,MAAM;AACxD,gBAAM,OAAQ,MAAM,OAAQ,UAAU,MAAM,IAAI,MAAQ;AACxD,gBAAM,KAAK,sCAAsC,MAAM,GAAG,IAAI,KAAK,GAAG,IAAI,KAAK;AAAA,QACjF;AAEA,YAAI,KAAK,WAAW,OAAO;AACzB,gBAAM,KAAK,4CAA4C,KAAK,UAAU,QAAQ,SAAS,MAAM;AAC7F,gBAAM,KAAK,4CAA4C,KAAK,UAAU,KAAK,MAAM;AACjF,cAAI,KAAK,UAAU,YAAa,OAAM,KAAK,4CAA4C,KAAK,UAAU,WAAW,MAAM;AACvH,cAAI,KAAK,UAAU,IAAa,OAAM,KAAK,4CAA4C,KAAK,UAAU,GAAG,MAAM;AAC/G,cAAI,KAAK,UAAU,MAAa,OAAM,KAAK,4CAA4C,KAAK,UAAU,KAAK,MAAM;AAAA,QACnH;AAEA,YAAI,KAAK,SAAS,OAAO;AACvB,gBAAM,KAAK,6CAA6C,KAAK,QAAQ,QAAQ,qBAAqB,MAAM;AACxG,gBAAM,KAAK,6CAA6C,KAAK,QAAQ,KAAK,MAAM;AAChF,cAAI,KAAK,QAAQ,YAAa,OAAM,KAAK,6CAA6C,KAAK,QAAQ,WAAW,MAAM;AACpH,cAAI,KAAK,QAAQ,QAAa,OAAM,KAAK,6CAA6C,KAAK,QAAQ,OAAO,MAAM;AAChH,cAAI,KAAK,QAAQ,MAAa,OAAM,KAAK,6CAA6C,KAAK,QAAQ,KAAK,MAAM;AAAA,QAChH;AAEA,cAAM,WAAW,MAAM,IAAI,OAAK,OAAO,CAAC,EAAE,EAAE,KAAK,IAAI;AACrD,eAAO,KAAK,QAAQ,WAAW,GAAG,QAAQ;AAAA,UAAa;AAAA,MACzD;AAAA,IACF;AAAA,EACF;AACF;AAEA,IAAO,gBAAQ;","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\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\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 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 const routesFiltered = routes.map(r => ({\r\n ...r,\r\n layouts: r.layouts.filter(l => isUsableLayout(l)),\r\n }));\r\n\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\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\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 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\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 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 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 webRes = await (handler as any).fetch(webReq.clone());\r\n if (webRes.status === 404) continue;\r\n } else if (typeof handler === 'function') {\r\n const params = matchRoute(route.routePath, pathname);\r\n if (params === null) continue;\r\n\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 } else {\r\n continue;\r\n }\r\n } catch {\r\n continue;\r\n }\r\n\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 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\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 // ── Determine outFile FIRST so import paths can be relative to it ──────────\r\n let outFile: string;\r\n if (platform === 'vercel') {\r\n outFile = path.join(cwd, 'api', 'index.ts');\r\n } else if (platform === 'cloudflare') {\r\n outFile = path.join(cwd, 'worker.ts');\r\n } else {\r\n outFile = path.join(cwd, 'server', 'index.ts');\r\n }\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\r\n // Import path relative to the output file directory, not the project root.\r\n // e.g. api/index.ts → ../src/app/api/hello (not ./src/app/api/hello)\r\n const rel = norm(path.relative(path.dirname(outFile), route.filePath)).replace(/\\.(ts|tsx)$/, '');\r\n const imp = rel.startsWith('.') ? rel : `./${rel}`;\r\n const name = `_route${i}`;\r\n\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: prefix with /api so the route matches what callers use.\r\n // Auto-wrap plain object returns as JSON so handlers don't need to return Response manually.\r\n mountings.push(`app.all('/api${route.routePath}', async (c) => { const r = await ${name}(c.req.raw); return r instanceof Response ? r : c.json(r); });`);\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 const appSetup = [\r\n ``,\r\n `const app = new Hono();`,\r\n ...(corsLine ? [corsLine] : []),\r\n ...mountings,\r\n ];\r\n\r\n let lines: string[];\r\n\r\n if (platform === 'vercel') {\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 } else if (platform === 'cloudflare') {\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 } else {\r\n // node\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 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 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 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 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 if (url.startsWith('/api') || url.includes('.')) return next();\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 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 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 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 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 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 (!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.15",
3
+ "version": "1.0.17",
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",
@@ -23,19 +23,36 @@
23
23
  "files": [
24
24
  "dist"
25
25
  ],
26
- "dependencies": {
27
- "hono": "^4.12.5"
28
- },
26
+ "dependencies": {},
29
27
  "peerDependencies": {
28
+ "hono": ">=4.0.0",
30
29
  "vite": ">=5.0.0",
31
30
  "react": ">=18.0.0",
32
31
  "react-dom": ">=18.0.0",
33
32
  "react-router-dom": ">=6.0.0"
34
33
  },
34
+ "peerDependenciesMeta": {
35
+ "hono": {
36
+ "optional": false
37
+ },
38
+ "vite": {
39
+ "optional": false
40
+ },
41
+ "react": {
42
+ "optional": false
43
+ },
44
+ "react-dom": {
45
+ "optional": false
46
+ },
47
+ "react-router-dom": {
48
+ "optional": false
49
+ }
50
+ },
35
51
  "devDependencies": {
36
52
  "@types/node": "^25.3.5",
37
53
  "@types/react": "^19.2.14",
38
54
  "@types/react-dom": "^19.2.3",
55
+ "hono": "^4.12.5",
39
56
  "react": "^19.2.4",
40
57
  "react-dom": "^19.2.4",
41
58
  "react-router-dom": "^7.13.1",