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 +33 -10
- package/dist/index.cjs +11 -11
- package/dist/index.cjs.map +1 -1
- package/dist/index.js +11 -11
- package/dist/index.js.map +1 -1
- package/package.json +21 -4
package/Readme.md
CHANGED
|
@@ -6,7 +6,6 @@
|
|
|
6
6
|
[](./LICENSE)
|
|
7
7
|
[](https://vitejs.dev)
|
|
8
8
|
[](https://react.dev)
|
|
9
|
-
[](https://hono.dev)
|
|
10
9
|
[](https://hono.dev)
|
|
11
10
|
[](https://www.typescriptlang.org)
|
|
12
11
|
[](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
|
-
>
|
|
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
|
-
|
|
381
|
+
|
|
364
382
|
const app = new Hono();
|
|
365
|
-
app.
|
|
366
|
-
app.
|
|
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
|
-
"
|
|
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
|
-
|
|
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 &&
|
|
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
|
-
|
|
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(
|
|
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;
|
package/dist/index.cjs.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;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,gBAAe;AACf,kBAAiB;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,YAAAA,QAAK,KAAK,QAAQ,IAAI,GAAG,eAAe;AAC7D,QAAI,CAAC,UAAAC,QAAG,WAAW,YAAY,EAAG,QAAO;AACzC,UAAM,MAAM,UAAAA,QAAG,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,YAAAD,QAAK,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,YAAAA,QAAK,SAAS,YAAAA,QAAK,KAAK,QAAQ,IAAI,GAAG,KAAK,GAAG,QAAQ,CAAC,EACxE,QAAQ,sBAAsB,EAAE;AACrC;AAEA,SAAS,iBAAiB,UAA2B;AACnD,MAAI;AAAE,WAAO,UAAAC,QAAG,aAAa,UAAU,MAAM,EAAE,SAAS,gBAAgB;AAAA,EAAG,QACrE;AAAE,WAAO;AAAA,EAAO;AACxB;AAEA,SAAS,kBAAkB,UAA2B;AACpD,MAAI;AAAE,WAAO,cAAc,KAAK,UAAAA,QAAG,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,UAAAA,QAAG,WAAW,YAAAD,QAAK,KAAK,KAAK,CAAC,CAAC,CAAC,KAAK;AACnE;AAEA,SAAS,aAAqB;AAC5B,QAAM,KAAK,YAAAA,QAAK,KAAK,QAAQ,IAAI,GAAG,aAAa;AACjD,SAAO,UAAAC,QAAG,WAAW,EAAE,IAAI,KAAK,YAAAD,QAAK,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,YAAAA,QAAK,KAAK,SAAS,MAAM,CAAC;AACpD,QAAI,YAAAA,QAAK,QAAQ,OAAO,MAAM,YAAAA,QAAK,QAAQ,MAAM,EAAG;AACpD,UAAM,SAAS,YAAAA,QAAK,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,UAAAC,QAAG,WAAW,GAAG,EAAG,QAAO;AAEhC,MAAI;AACJ,MAAI;AAAE,cAAU,UAAAA,QAAG,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,YAAAD,QAAK,QAAQ,MAAM,IAAI;AACpC,UAAM,OAAO,YAAAA,QAAK,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,YAAAA,QAAK,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,YAAAA,QAAK,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,YAAAA,QAAK,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,UAAAC,QAAG,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,YAAAD,QAAK,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,UAAAC,QAAG,WAAW,YAAAD,QAAK,KAAK,QAAQ,CAAC,CAAC,CAAC;AAClF,QAAM,WAAe,gBAAgB,iBAAiB,YAAAA,QAAK,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,YAAAA,QAAK,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,UAAAC,QAAG,aAAa,YAAAD,QAAK,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,UAAAC,QAAG,WAAW,GAAG,EAAG,QAAO;AAEhC,MAAI;AACJ,MAAI;AAAE,cAAU,UAAAA,QAAG,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,YAAAD,QAAK,KAAK,KAAK,MAAM,IAAI;AAE1C,QAAI,MAAM,YAAY,GAAG;AACvB,YAAME,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,YAAAH,QAAK,QAAQ,MAAM,IAAI;AACpC,UAAM,OAAO,YAAAA,QAAK,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,UAAAC,QAAG,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,UAAAA,QAAG,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,YAAAD,QAAK,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,UAAAC,QAAG,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,YAAAD,QAAK,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,YAAAA,QAAK,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,YAAAA,QAAK,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,YAAAC,QAAG,UAAU,YAAAD,QAAK,QAAQ,OAAO,GAAG,EAAE,WAAW,KAAK,CAAC;AACvD,YAAAC,QAAG,cAAc,SAAS,MAAM,KAAK,IAAI,IAAI,MAAM,MAAM;AACzD,UAAQ,IAAI,kCAA6B,KAAK,YAAAD,QAAK,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,YAAAA,QAAK,KAAK,QAAQ,IAAI,GAAG,QAAQ,UAAU,SAAS;AAC5E,QAAM,YAAY,MAAM,YAAAA,QAAK,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,YAAAA,QAAK,SAAS,GAAG,YAAAA,QAAK,QAAQ,CAAC,CAAC;AAC7C,UAAM,MAAO,YAAAA,QAAK,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,YAAAA,QAAK,QAAQ,CAAC,CAAC;AAAA,EAC5D;AAGA,WAAS,WAA0B;AACjC,UAAM,MAAM,UAAU;AACtB,QAAI,CAAC,UAAAC,QAAG,WAAW,GAAG,EAAG,QAAO;AAChC,UAAM,OAAO,YAAY,GAAG;AAC5B,QAAI,SAAS,kBAAmB,QAAO;AACvC,cAAAA,QAAG,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,YAAAD,QAAK,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,UAAAC,QAAG,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,YAAAD,QAAK,SAAS,GAAG,YAAAA,QAAK,QAAQ,CAAC,CAAC;AAClD,cAAM,YAAY,YAAAA,QAAK,QAAQ,YAAAA,QAAK,QAAQ,CAAC,CAAC,MAAM,YAAAA,QAAK,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,UAAAC,QAAG,WAAW,YAAAD,QAAK,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,UAAAC,QAAG,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,UAAAA,QAAG,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":["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(
|
|
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":"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","names":["isCatchAll","isDynamic"]}
|
|
1
|
+
{"version":3,"sources":["../src/index.ts"],"sourcesContent":["import fs from 'fs';\r\nimport path from 'path';\r\nimport type { Plugin, ViteDevServer } from 'vite';\r\n\r\n// ─── Constants ────────────────────────────────────────────────────────────────\r\n\r\nconst PAGE_FILES = ['page.tsx', 'page.jsx', 'page.ts', 'page.js'] as const;\r\nconst LAYOUT_FILES = ['layout.tsx', 'layout.jsx', 'layout.ts', 'layout.js'] as const;\r\nconst SUPPORTED_EXTS = ['.tsx', '.jsx', '.ts', '.js'] as const;\r\nconst NOT_FOUND_FILES = SUPPORTED_EXTS.map(e => `not-found${e}`);\r\nconst SPECIAL_BASES = new Set(['page', 'layout', 'not-found', 'loading', 'error']);\r\nconst API_EXTS = ['.ts', '.js'] as const;\r\nconst DEBOUNCE_MS = 60;\r\nconst EVENT_DEDUP_MS = 500;\r\nconst EVENT_TTL_MS = 2000;\r\n\r\n// ─── Metadata Types ───────────────────────────────────────────────────────────\r\n\r\nexport interface IconEntry {\r\n url : string;\r\n type ?: string;\r\n sizes?: string;\r\n}\r\n\r\nexport interface MetaTags {\r\n title ?: string;\r\n description ?: string;\r\n viewport ?: string;\r\n themeColor ?: string;\r\n keywords ?: string;\r\n author ?: string;\r\n charset ?: string;\r\n robots ?: string;\r\n canonical ?: string;\r\n manifest ?: string;\r\n openGraph ?: Partial<OGMeta>;\r\n twitter ?: Partial<TwitterMeta>;\r\n icons ?: {\r\n icon ?: IconEntry[];\r\n shortcut ?: IconEntry[];\r\n apple ?: IconEntry[];\r\n };\r\n}\r\n\r\ninterface OGMeta {\r\n title : string;\r\n description : string;\r\n url : string;\r\n image : string;\r\n type : string;\r\n}\r\n\r\ninterface TwitterMeta {\r\n card : string;\r\n title : string;\r\n description : string;\r\n creator : string;\r\n image : string;\r\n}\r\n\r\n// ─── Types ────────────────────────────────────────────────────────────────────\r\n\r\ninterface RouteNode {\r\n routePath : string;\r\n filePath : string;\r\n layouts : string[];\r\n dynamic : boolean;\r\n}\r\n\r\ninterface LayoutChainGroup {\r\n layouts : string[];\r\n routes : RouteNode[];\r\n}\r\n\r\ninterface ApiRoute {\r\n routePath : string;\r\n filePath : string;\r\n}\r\n\r\nexport interface BiniPluginOptions {\r\n /** Directory for page files. Default: src/app */\r\n appDir?: string;\r\n /** Directory for API routes. Default: src/app/api */\r\n apiDir?: string;\r\n /** Enable CORS headers in the dev-server API middleware. Default: true */\r\n cors?: boolean;\r\n /**\r\n * Target deployment platform. bini-router generates a production entry\r\n * file on every build — users only write code in src/app/api/.\r\n *\r\n * 'vercel' → api/index.ts (no extra install needed)\r\n * 'node' → server/index.ts (install: @hono/node-server)\r\n * 'cloudflare' → worker.ts (install: wrangler)\r\n *\r\n * Default: undefined (no entry generated)\r\n */\r\n platform?: 'vercel' | 'node' | 'cloudflare';\r\n}\r\n\r\n// ─── Utilities ────────────────────────────────────────────────────────────────\r\n\r\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.
|
|
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",
|