@withl5e/l5e 1.1.0-alpha.2 → 1.1.0-alpha.3

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/README.md CHANGED
@@ -23,7 +23,8 @@ export default defineConfig({
23
23
 
24
24
  See the root README and `examples/basic` for a full app.
25
25
 
26
- Compact chunking is experimental and opt-in:
26
+ Compact chunking is experimental and opt-in. The staged activation behavior and
27
+ `islandRuntime` option below require the `1.1.0-alpha.3` prerelease:
27
28
 
28
29
  ```ts
29
30
  coreVite({
@@ -48,6 +49,13 @@ contexts or client caches that multiple islands must share in `islandRuntime`.
48
49
  Only the configured static closure is included, and dynamic imports are not
49
50
  promoted. Compact mode requires native import-map support.
50
51
 
52
+ Compact chunking applies to production builds. Development keeps Vite source modules
53
+ and HMR, and its Network requests are not subject to the production three-file limit.
54
+
51
55
  The alpha renderer bridge expects Vite to emit one entry facade and one canonical
52
56
  renderer export chunk. A different renderer shape is rejected during server setup
53
57
  because merging multiple minified export namespaces can make aliases ambiguous.
58
+
59
+ See [runtime script bundles and shared modules](../../docs/runtime-script-bundling.md)
60
+ for the download/evaluation/mount lifecycle, strategy behavior, ownership rules,
61
+ activation examples and current alpha limitations.
package/dist/index.js CHANGED
@@ -5,5 +5,5 @@ import { render as L } from "./entry-server.js";
5
5
  import { n as R, t as z } from "./middleware-CnDqZobD.js";
6
6
  import { t as B } from "./defineMiddleware-D017PWDc.js";
7
7
  import { a as V, n as H } from "./server-C35BtVu8.js";
8
- import { t as U } from "./vite-plugin-BOuzxmb2.js";
8
+ import { t as U } from "./vite-plugin-Bln1di66.js";
9
9
  export { I as BadRequestException, T as Fragment, _ as HEAD_PRIORITY, b as Head, N as HttpException, F as InternalServerErrorException, M as NotFoundException, j as RedirectException, P as ServiceUnavailableException, C as addCacheTag, g as cloneElement, U as coreVite, z as createContext, H as createServer, B as defineMiddleware, r as escapeHTML, t as escapeProp, l as getCacheTags, x as getClientJsEntries, w as getCssEntries, d as getHeadContent, v as getIslandEntries, E as getIslandProps, f as getSchemas, p as getSsrIslands, S as isIslandPropsExternalized, y as isValidElement, h as jsxFactory, m as pushIslandProps, c as pushMetadata, D as pushSchema, A as registerIsland, u as registerSsrIsland, L as render, n as renderJsxToHtmlString, e as renderToRenderedNode, k as resolveMetadata, o as runInRenderContext, R as sequence, i as setViewName, V as startServer, O as useClientJs, s as useCss, a as useRequest };
@@ -110,16 +110,16 @@ function v(e = {}) {
110
110
  maxSize: t.maxSize,
111
111
  includeDependenciesRecursively: e.mode === "compact"
112
112
  })),
113
- {
114
- name: (e) => s.get(e)?.group === "lazy-react-runtime" ? "lazy-react-runtime" : null,
115
- includeDependenciesRecursively: !0
116
- },
117
113
  {
118
114
  name: (e) => {
119
115
  let t = s.get(e)?.group;
120
116
  return t === "lazy-react-runtime" ? null : t || null;
121
117
  },
122
118
  includeDependenciesRecursively: !1
119
+ },
120
+ {
121
+ name: (e) => s.get(e)?.group === "lazy-react-runtime" ? "lazy-react-runtime" : null,
122
+ includeDependenciesRecursively: !0
123
123
  }
124
124
  ];
125
125
  },
@@ -130,13 +130,15 @@ function v(e = {}) {
130
130
  warnings: [...l],
131
131
  chunks: Object.values(t).flatMap((t) => {
132
132
  if (t.type !== "chunk") return [];
133
- let n = t.facadeModuleId ? u(t.facadeModuleId) : null, r = n === "src/client.global.ts" ? "global" : n && /(?:^|\/)react\//.test(n) ? "island" : t.isEntry || t.isDynamicEntry ? "page" : "shared";
133
+ let n = new Set(Object.keys(t.modules).map((e) => s.get(e)?.group));
134
+ if (e.mode === "compact" && n.has("global-owner") && n.has("lazy-react-runtime")) throw Error(`[l5e chunking] ${t.fileName} mixes global-owned and lazy island runtime modules. Keep eager owners separate before recursively collecting the lazy runtime.`);
135
+ let r = t.facadeModuleId ? u(t.facadeModuleId) : null, i = r === "src/client.global.ts" ? "global" : r && /(?:^|\/)react\//.test(r) ? "island" : t.isEntry || t.isDynamicEntry ? "page" : "shared";
134
136
  return [{
135
137
  file: t.fileName,
136
- kind: r,
138
+ kind: i,
137
139
  canonicalShared: e.mode === "compact" && t.name === "shared",
138
140
  canonicalGlobal: e.mode === "compact" && t.name === "global-owner",
139
- source: n,
141
+ source: r,
140
142
  bytes: Buffer.byteLength(t.code),
141
143
  imports: t.imports,
142
144
  dynamicImports: t.dynamicImports,
@@ -424,12 +426,12 @@ function R(e = {}) {
424
426
  resolveId(e) {
425
427
  return e === y ? "\0virtual:l5e-views" : e === b ? "\0virtual:l5e-route" : e === x ? "\0virtual:l5e-ssr-entry" : e === S ? "\0virtual:l5e-global-loader" : e === C ? "\0virtual:l5e-island-strategies" : e === w ? "\0virtual:l5e-islands" : e === T ? "\0virtual:l5e-compact-renderer" : e === E ? "\0virtual:l5e-actions" : e === D ? "\0virtual:l5e-middleware" : null;
426
428
  },
427
- async transform(t, n, i) {
428
- if (n.replace(/\\/g, "/").endsWith("src/client.global.ts") && !i?.ssr) return {
429
- code: `import '@withl5e/l5e/island/${e.chunking && e.chunking.mode === "compact" ? "compact-runtime" : "runtime"}';\n${t}`,
429
+ async transform(t, n, a) {
430
+ if (n.replace(/\\/g, "/").endsWith("src/client.global.ts") && !a?.ssr) return {
431
+ code: `import '@withl5e/l5e/island/${i && e.chunking && e.chunking.mode === "compact" ? "compact-runtime" : "runtime"}';\n${t}`,
430
432
  map: null
431
433
  };
432
- if (!i?.ssr) {
434
+ if (!a?.ssr) {
433
435
  let e = n.replace(/\\/g, "/").match(/\/src\/(.+)\/actions\.(ts|tsx)$/);
434
436
  if (e) {
435
437
  let n = e[1], r = /export\s+const\s+(\w+)\s*=\s*defineAction\s*\(/g, i = [], a;
@@ -479,7 +481,7 @@ function R(e = {}) {
479
481
  } catch (e) {
480
482
  throw console.error(`[l5e] Failed to transform JSX in ${n}:`, e), e;
481
483
  }
482
- if (i?.ssr) {
484
+ if (a?.ssr) {
483
485
  let e = t, n = !1;
484
486
  if (e = e.replace(/import\.meta\.env\.([a-zA-Z_][a-zA-Z0-9_]*)/g, (e, t) => O.has(t) ? e : (n = !0, `process.env.${t}`)), e = e.replace(/import\.meta\.env\[(['"`])([^'"`]+)\1\]/g, (e, t, r) => O.has(r) ? e : (n = !0, `process.env[${t}${r}${t}]`)), n) return {
485
487
  code: e,
@@ -512,4 +514,4 @@ export const actionRegistry = ${JSON.stringify(e)};`;
512
514
  //#endregion
513
515
  export { R as t };
514
516
 
515
- //# sourceMappingURL=vite-plugin-BOuzxmb2.js.map
517
+ //# sourceMappingURL=vite-plugin-Bln1di66.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"vite-plugin-Bln1di66.js","names":["join"],"sources":["../src/core/chunking.ts","../src/core/vite-plugin.ts"],"sourcesContent":["import { createHash } from 'node:crypto';\nimport path from 'node:path';\nimport type { CodeSplittingGroup, ModuleInfo, OutputBundle } from 'rolldown';\n\nexport interface SharedChunkGroup {\n name: string;\n /** Exact package names, including their subpath imports. */\n packages?: string[];\n /** Module specifiers resolved by Vite, including aliases. */\n modules?: string[];\n priority?: number;\n /** Approximate uncompressed maximum; not a hard network byte budget. */\n maxSize?: number;\n}\n\nexport interface ChunkingOptions {\n /**\n * Opt in to at most one global, one page bundle and one canonical shared file.\n * State that must retain identity across page bundles must be listed in `shared`.\n */\n mode?: 'compact';\n shared?: SharedChunkGroup[];\n /** Static UI/runtime roots that join React's canonical lazy activation chunk. */\n islandRuntime?: Pick<SharedChunkGroup, 'packages' | 'modules'>;\n}\n\nexport interface CoreViteOptions {\n /** false leaves chunk placement to Vite; runtime identity protection stays enabled. */\n chunking?: ChunkingOptions | false;\n}\n\nconst normalize = (id: string) => id.replace(/\\\\/g, '/');\nconst digest = (value: string) => createHash('sha256').update(value).digest('hex').slice(0, 8);\n\n/** The last node_modules segment also handles pnpm's nested package layout. */\nfunction packageName(id: string): string | undefined {\n const suffix = normalize(id).split('/node_modules/').at(-1);\n if (suffix === normalize(id)) return undefined;\n const parts = suffix!.split('/');\n return parts[0].startsWith('@') ? parts.slice(0, 2).join('/') : parts[0];\n}\n\ntype Decision = { group: string | null; rule?: string; consumers: string[]; reason: string };\n\n/** One build-time plan drives placement and the diagnostic report. Runtime reads Vite's manifest. */\nexport function createChunkPlanner(options: ChunkingOptions = {}) {\n const rules = options.shared || [];\n const islandRuntimeRule = options.islandRuntime;\n if (\n islandRuntimeRule &&\n !islandRuntimeRule.packages?.length &&\n !islandRuntimeRule.modules?.length\n ) {\n throw new Error('[l5e chunking] islandRuntime needs packages or modules.');\n }\n if (options.mode === 'compact' && rules.length > 1) {\n throw new Error('[l5e chunking] Compact mode accepts one canonical shared group.');\n }\n const names = new Set<string>();\n for (const rule of rules) {\n if (!/^[a-zA-Z0-9][a-zA-Z0-9_-]*$/.test(rule.name) || names.has(rule.name)) {\n throw new Error(`[l5e chunking] Invalid or duplicate shared group: ${rule.name}`);\n }\n if (!rule.packages?.length && !rule.modules?.length) {\n throw new Error(`[l5e chunking] Group ${rule.name} needs packages or modules.`);\n }\n if (rule.maxSize !== undefined && (!Number.isFinite(rule.maxSize) || rule.maxSize <= 0)) {\n throw new Error(`[l5e chunking] Invalid maxSize for ${rule.name}`);\n }\n if (options.mode === 'compact' && rule.maxSize !== undefined) {\n throw new Error(\n `[l5e chunking] Compact mode cannot use maxSize for ${rule.name}; it would split the canonical shared file.`,\n );\n }\n names.add(rule.name);\n }\n let root = '';\n const resolvedRules = new Map<SharedChunkGroup, Set<string>>();\n let resolvedIslandRuntime = new Set<string>();\n const decisions = new Map<string, Decision>();\n const warnings = new Set<string>();\n const portable = (id: string) => {\n const pkg = packageName(id);\n if (pkg) return `npm:${normalize(id).split('/node_modules/').at(-1)}`;\n return normalize(path.relative(root, id));\n };\n\n return {\n async resolve(\n projectRoot: string,\n resolveId: (id: string, importer: string) => Promise<string | null>,\n ) {\n root = projectRoot;\n resolvedRules.clear();\n resolvedIslandRuntime = new Set();\n decisions.clear();\n warnings.clear();\n for (const rule of rules) {\n const ids = new Set<string>();\n for (const specifier of rule.modules || []) {\n const id = await resolveId(specifier, path.join(root, 'index.html'));\n if (!id) throw new Error(`[l5e chunking] Cannot resolve ${specifier} in ${rule.name}`);\n ids.add(id);\n }\n resolvedRules.set(rule, ids);\n }\n if (islandRuntimeRule) {\n for (const specifier of islandRuntimeRule.modules || []) {\n const id = await resolveId(specifier, path.join(root, 'index.html'));\n if (!id) throw new Error(`[l5e chunking] Cannot resolve ${specifier} in islandRuntime`);\n resolvedIslandRuntime.add(id);\n }\n }\n },\n analyze(modules: ModuleInfo[]) {\n decisions.clear();\n const graph = new Map(modules.map((mod) => [mod.id, mod]));\n if (options.mode === 'compact') {\n const reachability = new Map<string, Map<string, boolean>>();\n for (const entry of modules.filter((mod) => mod.isEntry)) {\n const visit = (id: string, lazy: boolean) => {\n const owners = reachability.get(id) || new Map<string, boolean>();\n const previous = owners.get(entry.id);\n if (previous === false || previous === lazy) return;\n owners.set(entry.id, lazy);\n reachability.set(id, owners);\n const module = graph.get(id);\n if (!module) return;\n module.importedIds.forEach((dependency) => visit(dependency, lazy));\n module.dynamicallyImportedIds.forEach((dependency) => visit(dependency, true));\n };\n visit(entry.id, false);\n }\n const globalEntry = modules.find(\n (mod) => mod.isEntry && normalize(mod.id).endsWith('/src/client.global.ts'),\n );\n if (globalEntry) {\n for (const [id, owners] of reachability) {\n if (\n !/\\.css(?:\\?|$)/.test(normalize(id)) &&\n owners.get(globalEntry.id) === true &&\n [...owners.keys()].some((owner) => owner !== globalEntry.id)\n ) {\n throw new Error(\n `[l5e chunking] Compact mode cannot bridge a dynamic-only global overlap: ${portable(id)}. Import it statically from global or place state behind an explicit shared root.`,\n );\n }\n }\n }\n }\n const roots = modules.filter((mod) => mod.isEntry || mod.dynamicImporters.length > 0);\n const consumers = new Map<string, Set<string>>();\n for (const entry of roots) {\n const visited = new Set<string>();\n const visit = (id: string) => {\n if (visited.has(id)) return;\n visited.add(id);\n const mod = graph.get(id);\n if (!mod) return;\n const users = consumers.get(id) || new Set<string>();\n users.add(entry.id);\n consumers.set(id, users);\n mod.importedIds.forEach(visit);\n };\n visit(entry.id);\n }\n const rank = (id: string) => {\n const mod = graph.get(id)!;\n if (!mod.isEntry) return 3;\n if (normalize(id).endsWith('/src/client.global.ts')) return 0;\n if (normalize(id).includes('virtual:l5e-compact-renderer')) return 2;\n if (/\\/react\\//.test(normalize(id)) && !packageName(id)) return 2;\n return 1;\n };\n const matched = new Set<SharedChunkGroup>();\n for (const mod of modules) {\n const users = [...(consumers.get(mod.id) || [])].sort();\n const labels = users.map(portable).sort();\n const matches = rules\n .filter(\n (rule) =>\n resolvedRules.get(rule)?.has(mod.id) ||\n rule.packages?.includes(packageName(mod.id) || ''),\n )\n .sort((a, b) => (b.priority || 0) - (a.priority || 0));\n matches.forEach((rule) => matched.add(rule));\n if (matches.length > 1)\n warnings.add(\n `${portable(mod.id)} matches ${matches.map((r) => r.name).join(', ')}; using ${matches[0].name}.`,\n );\n let group: string | null = null;\n let reason = 'Private dependency stays with its entry or dynamic import.';\n const pkg = packageName(mod.id);\n const islandRuntimeMatch =\n resolvedIslandRuntime.has(mod.id) ||\n islandRuntimeRule?.packages?.includes(pkg || '') === true;\n if (\n options.mode === 'compact' &&\n normalize(mod.id).includes('virtual:l5e-compact-renderer')\n ) {\n group = 'lazy-react-runtime';\n reason = 'Renderer joins the canonical React runtime activation.';\n } else if (\n options.mode === 'compact' &&\n !mod.isEntry &&\n (pkg === 'react' || pkg === 'react-dom' || pkg === 'scheduler') &&\n users.length > 0 &&\n users.every((id) => rank(id) >= 2)\n ) {\n group = 'lazy-react-runtime';\n reason = 'Canonical React runtime is fetched when the first island activates.';\n } else if (!mod.isEntry && users.length && matches.length) {\n // Explicit groups can combine consumers at the same activation tier.\n // Never promote island-only code into global/page, or dynamic-only code\n // into a static entry. Distinct dynamic roots remain separate as well.\n const tier = Math.min(...users.map(rank));\n const activation =\n tier === 3\n ? `lazy-${digest(JSON.stringify(labels))}`\n : ['global', 'page', 'island'][tier];\n group = options.mode === 'compact' ? 'shared' : `shared-${matches[0].name}-${activation}`;\n reason = `Configured group ${matches[0].name}; activation ${activation}.`;\n } else if (options.mode === 'compact' && !mod.isEntry && islandRuntimeMatch) {\n group = 'lazy-react-runtime';\n reason = 'Configured canonical island runtime is fetched with the first island consumer.';\n } else if (\n options.mode === 'compact' &&\n !mod.isEntry &&\n users.some((id) => rank(id) === 0) &&\n users.some((id) => rank(id) > 0)\n ) {\n group = 'global-owner';\n reason = 'Static global/page overlap is exported by the canonical global artifact.';\n } else if (options.mode !== 'compact' && !mod.isEntry && users.length > 1) {\n group = `shared-auto-${digest(JSON.stringify(labels))}`;\n reason = 'Shared by the same static consumers; preserves dynamic import roots.';\n }\n decisions.set(mod.id, { group, rule: matches[0]?.name, consumers: labels, reason });\n }\n for (const rule of rules) {\n if (!matched.has(rule))\n warnings.add(`Group ${rule.name} matched no modules in this client build.`);\n }\n return [...warnings];\n },\n groups(): CodeSplittingGroup[] {\n return [\n ...rules.map((rule) => ({\n name: (id: string) => {\n const decision = decisions.get(id);\n return decision?.rule === rule.name ? decision.group : null;\n },\n maxSize: rule.maxSize,\n includeDependenciesRecursively: options.mode === 'compact',\n })),\n // Reserve eager owners before recursively collecting the lazy UI closure.\n // Otherwise a lazy hook's dynamic import can capture Vite's preload helper\n // and force global to import the entire React renderer chunk for that helper.\n {\n name: (id: string) => {\n const group = decisions.get(id)?.group;\n return group === 'lazy-react-runtime' ? null : group || null;\n },\n includeDependenciesRecursively: false,\n },\n {\n name: (id: string) =>\n decisions.get(id)?.group === 'lazy-react-runtime' ? 'lazy-react-runtime' : null,\n includeDependenciesRecursively: true,\n },\n ];\n },\n report(bundle: OutputBundle) {\n return {\n version: 2,\n mode: options.mode || 'default',\n warnings: [...warnings],\n chunks: Object.values(bundle).flatMap((chunk) => {\n if (chunk.type !== 'chunk') return [];\n const moduleGroups = new Set(\n Object.keys(chunk.modules).map((id) => decisions.get(id)?.group),\n );\n if (\n options.mode === 'compact' &&\n moduleGroups.has('global-owner') &&\n moduleGroups.has('lazy-react-runtime')\n ) {\n throw new Error(\n `[l5e chunking] ${chunk.fileName} mixes global-owned and lazy island runtime modules. ` +\n 'Keep eager owners separate before recursively collecting the lazy runtime.',\n );\n }\n const source = chunk.facadeModuleId ? portable(chunk.facadeModuleId) : null;\n const kind =\n source === 'src/client.global.ts'\n ? 'global'\n : source && /(?:^|\\/)react\\//.test(source)\n ? 'island'\n : chunk.isEntry || chunk.isDynamicEntry\n ? 'page'\n : 'shared';\n return [\n {\n file: chunk.fileName,\n kind,\n canonicalShared: options.mode === 'compact' && chunk.name === 'shared',\n canonicalGlobal: options.mode === 'compact' && chunk.name === 'global-owner',\n source,\n bytes: Buffer.byteLength(chunk.code),\n imports: chunk.imports,\n dynamicImports: chunk.dynamicImports,\n modules: Object.keys(chunk.modules).map((id) => ({\n id: portable(id),\n ...decisions.get(id),\n })),\n },\n ];\n }),\n };\n },\n };\n}\n","import { transform } from 'esbuild';\nimport {\n existsSync,\n mkdirSync,\n readdirSync,\n readFileSync,\n rmSync,\n statSync,\n writeFileSync,\n} from 'fs';\nimport { dirname, join, relative, resolve } from 'path';\nimport type { Plugin, UserConfig } from 'vite';\nimport { findGlobalStyleInput } from './global-style';\nimport { createChunkPlanner, type CoreViteOptions } from './chunking';\nexport type { CoreViteOptions, ChunkingOptions, SharedChunkGroup } from './chunking';\n\nconst VIRTUAL_L5E_VIEWS = 'virtual:l5e-views';\nconst VIRTUAL_L5E_ROUTE = 'virtual:l5e-route';\nconst VIRTUAL_L5E_SSR_ENTRY = 'virtual:l5e-ssr-entry';\nconst VIRTUAL_L5E_GLOBAL_LOADER = 'virtual:l5e-global-loader';\nconst VIRTUAL_L5E_ISLAND_STRATEGIES = 'virtual:l5e-island-strategies';\nconst VIRTUAL_L5E_ISLANDS = 'virtual:l5e-islands';\nconst VIRTUAL_L5E_COMPACT_RENDERER = 'virtual:l5e-compact-renderer';\nconst VIRTUAL_L5E_ACTIONS = 'virtual:l5e-actions';\nconst VIRTUAL_L5E_MIDDLEWARE = 'virtual:l5e-middleware';\n\n/**\n * Vite's built-in env vars on `import.meta.env`. These are statically replaced\n * by Vite itself (DEV/PROD/SSR are booleans, MODE/BASE_URL strings), so the SSR\n * `import.meta.env.* -> process.env.*` rewrite must skip them — otherwise it\n * clobbers Vite defaults (e.g. `import.meta.env.DEV` would become the undefined\n * `process.env.DEV`).\n */\nconst VITE_RESERVED_ENV = new Set(['MODE', 'BASE_URL', 'PROD', 'DEV', 'SSR', 'LEGACY']);\n\n/**\n * Recursively scan directory for .tsx and .ts files\n */\nfunction scanTsFiles(dir: string, fileList: string[] = []): string[] {\n const files = readdirSync(dir);\n\n for (const file of files) {\n const filePath = join(dir, file);\n const stat = statSync(filePath);\n\n if (stat.isDirectory()) {\n // Skip node_modules and dist directories\n if (file === 'node_modules' || file === 'dist' || file === '.git') {\n continue;\n }\n scanTsFiles(filePath, fileList);\n } else if (file.endsWith('.tsx') || file.endsWith('.ts')) {\n fileList.push(filePath);\n }\n }\n\n return fileList;\n}\n\n/**\n * Short hash function for island keys\n */\nfunction shortHash(str: string): string {\n let hash = 0;\n for (let i = 0; i < str.length; i++) {\n hash = (hash << 5) - hash + str.charCodeAt(i);\n hash = hash & hash;\n }\n return Math.abs(hash).toString(16).slice(0, 4);\n}\n\n/**\n * Derive component name from path: \"./react/Counter\" → \"Counter\"\n */\nfunction deriveComponentName(fromPath: string): string {\n const segments = fromPath.split('/');\n let filename = segments[segments.length - 1];\n // Remove extension if present\n filename = filename.replace(/\\.(tsx?|jsx?)$/, '');\n return filename;\n}\n\n/**\n * Create island registry key: \"/src/views/test-island/react/Counter\" → \"Counter_a3f2\"\n */\nfunction makeIslandKey(resolvedPath: string): string {\n const name = deriveComponentName(resolvedPath);\n return `${name}_${shortHash(resolvedPath)}`;\n}\n\n/**\n * Resolve file path with extension (.tsx, .ts, .jsx, .js)\n * Returns the relative path with extension (e.g., \"src/views/.../Counter.tsx\")\n * or null if file not found\n */\nfunction resolveWithExtension(resolvedPath: string, rootDir: string): string | null {\n // resolvedPath: \"/src/views/test-island/react/Counter\" (no extension, leading /)\n const relPath = resolvedPath.replace(/^\\//, ''); // \"src/views/.../Counter\"\n const absBase = resolve(rootDir, relPath);\n\n // Check with extensions\n for (const ext of ['.tsx', '.ts', '.jsx', '.js']) {\n if (existsSync(absBase + ext)) {\n return relPath + ext; // \"src/views/.../Counter.tsx\"\n }\n }\n // Check without extension (file might already have one)\n if (existsSync(absBase)) {\n return relPath;\n }\n return null;\n}\n\n/**\n * Extract island entries from file using regex on JSX source\n */\nfunction extractIslandEntries(\n filePath: string,\n rootDir: string,\n): Array<{ component: string; resolvedPath: string; src: string; key: string }> {\n const content = readFileSync(filePath, 'utf-8');\n const entries: Array<{ component: string; resolvedPath: string; src: string; key: string }> = [];\n\n // Regex scan JSX source (NOT post-transform code).\n // Just find <ClientIsland ... from=\"Y\" ...> — component name derived from path.\n const regex = /<ClientIsland\\s[^>]*?from\\s*=\\s*\"([^\"]+)\"/g;\n\n const seen = new Set<string>();\n let match;\n\n while ((match = regex.exec(content)) !== null) {\n const fromPath = match[1];\n\n // Resolve relative path → absolute\n let resolvedPath: string;\n if (fromPath.startsWith('~/')) {\n // Alias ~/ → /src/ (project convention)\n resolvedPath = '/src/' + fromPath.substring(2);\n } else if (fromPath.startsWith('/src/')) {\n resolvedPath = fromPath;\n } else if (fromPath.startsWith('./') || fromPath.startsWith('../')) {\n const abs = resolve(filePath, '..', fromPath);\n resolvedPath = '/' + relative(rootDir, abs).replace(/\\\\/g, '/');\n } else {\n resolvedPath = fromPath;\n }\n\n // Resolve file extension for manifest compatibility\n const src = resolveWithExtension(resolvedPath, rootDir);\n if (!src) {\n console.warn(\n `[l5e] Island component not found: ${resolvedPath} (from ${fromPath} in ${filePath})`,\n );\n continue;\n }\n\n const key = makeIslandKey(resolvedPath);\n if (!seen.has(key)) {\n seen.add(key);\n entries.push({\n component: deriveComponentName(resolvedPath),\n resolvedPath,\n src, // \"src/views/.../Counter.tsx\" — matches manifest key format\n key,\n });\n }\n }\n return entries;\n}\n\n/**\n * Extract paths from useCss and useClientJs calls using regex\n */\nfunction extractPathsFromFile(filePath: string, rootDir: string): { css: string[]; js: string[] } {\n const content = readFileSync(filePath, 'utf-8');\n const css: string[] = [];\n const js: string[] = [];\n\n // Regex patterns to match useCss('path') or useCss(\"path\")\n // Handles single and double quotes, and escaped quotes\n const useCssPattern = /useCss\\s*\\(\\s*['\"]([^'\"]+)['\"]\\s*,?\\s*\\)/g;\n const useClientJsPattern = /useClientJs\\s*\\(\\s*['\"]([^'\"]+)['\"]\\s*,?\\s*\\)/g;\n\n let match;\n\n // Extract CSS paths\n while ((match = useCssPattern.exec(content)) !== null) {\n const path = match[1];\n // Convert relative path to absolute if needed\n if (path.startsWith('/src/')) {\n css.push(path);\n } else if (path.startsWith('./') || path.startsWith('../')) {\n // Resolve relative path\n const absolutePath = resolve(filePath, '..', path);\n const relativePath = '/' + relative(rootDir, absolutePath).replace(/\\\\/g, '/');\n css.push(relativePath);\n } else {\n css.push(path);\n }\n }\n\n // Extract JS paths\n while ((match = useClientJsPattern.exec(content)) !== null) {\n const path = match[1];\n if (path.startsWith('/src/')) {\n js.push(path);\n } else if (path.startsWith('./') || path.startsWith('../')) {\n const absolutePath = resolve(filePath, '..', path);\n const relativePath = '/' + relative(rootDir, absolutePath).replace(/\\\\/g, '/');\n js.push(relativePath);\n } else {\n js.push(path);\n }\n }\n\n return { css, js };\n}\n\n/**\n * Auto-discover bundler input entries from useCss and useClientJs calls\n */\nfunction discoverBundlerInput(rootDir: string): {\n input: Record<string, string>;\n islandRegistry: Map<string, string>;\n pathToKey: Map<string, string>;\n keyToSrc: Map<string, string>;\n actionRegistry: Map<string, { modulePath: string; actionName: string }>;\n} {\n const input: Record<string, string> = {};\n const srcDir = join(rootDir, 'src');\n\n // Island registries\n const islandRegistry = new Map<string, string>(); // key → resolvedPath\n const pathToKey = new Map<string, string>(); // resolvedPath → key\n const keyToSrc = new Map<string, string>(); // key → src (manifest-compatible path with extension)\n\n // Action registry: actionKey → { modulePath, actionName }\n const actionRegistry = new Map<string, { modulePath: string; actionName: string }>();\n\n try {\n // Check if src directory exists\n if (!statSync(srcDir).isDirectory()) {\n return { input, islandRegistry, pathToKey, keyToSrc, actionRegistry };\n }\n\n // Check if src/client.global.ts exists and add it as an entry\n const globalTsPath = join(rootDir, 'src', 'client.global.ts');\n if (existsSync(globalTsPath)) {\n input['global'] = globalTsPath;\n console.log('[l5e] Detected src/client.global.ts and added as entry');\n }\n\n const globalStyleInput = findGlobalStyleInput(rootDir);\n if (globalStyleInput) {\n input['global-style'] = globalStyleInput;\n console.log('[l5e] Detected src/global.css and added as global stylesheet');\n }\n\n // Scan all .tsx and .ts files\n const tsFiles = scanTsFiles(srcDir);\n\n // Extract all paths\n const allCssPaths = new Set<string>();\n const allJsPaths = new Set<string>();\n\n for (const file of tsFiles) {\n const { css, js } = extractPathsFromFile(file, rootDir);\n css.forEach((path) => allCssPaths.add(path));\n js.forEach((path) => allJsPaths.add(path));\n\n // Extract island entries\n const islandEntries = extractIslandEntries(file, rootDir);\n for (const entry of islandEntries) {\n islandRegistry.set(entry.key, entry.resolvedPath);\n pathToKey.set(entry.resolvedPath, entry.key);\n keyToSrc.set(entry.key, entry.src);\n }\n\n // Extract action entries from actions.ts/tsx files\n const normalizedFile = file.replace(/\\\\/g, '/');\n if (/\\/actions\\.(ts|tsx)$/.test(normalizedFile)) {\n const content = readFileSync(file, 'utf-8');\n const actionExportRegex = /export\\s+const\\s+(\\w+)\\s*=\\s*defineAction\\s*\\(/g;\n let actionMatch;\n\n // Compute modulePath: relative path from src/ to parent dir\n const relFromSrc = relative(srcDir, dirname(file)).replace(/\\\\/g, '/');\n const modulePath = relFromSrc || '.';\n\n while ((actionMatch = actionExportRegex.exec(content)) !== null) {\n const actionName = actionMatch[1];\n const actionKey = `${actionName}_${shortHash(modulePath)}`;\n actionRegistry.set(actionKey, { modulePath, actionName });\n }\n }\n }\n\n // Convert paths to bundler input entries\n // CSS files\n for (const cssPath of allCssPaths) {\n // Remove leading /src/ and convert to relative path\n const relativePath = cssPath.startsWith('/src/')\n ? cssPath.substring(1) // Remove leading /\n : cssPath.startsWith('/')\n ? cssPath.substring(1)\n : cssPath;\n\n const absolutePath = resolve(rootDir, relativePath);\n\n // src/global.css is already a dedicated convention entry. Keeping one\n // Separate input entries avoid collisions if a shared layout also calls useCss().\n if (globalStyleInput && resolve(absolutePath) === resolve(globalStyleInput)) {\n continue;\n }\n\n // Only add if file exists\n if (!existsSync(absolutePath)) {\n console.warn(`[l5e] CSS file not found: ${absolutePath} (from ${cssPath})`);\n continue;\n }\n\n // Generate entry name from path (e.g., /src/views/home/home.css -> views-home-home)\n const entryName = relativePath\n .replace(/^src\\//, '')\n .replace(/\\.css$/, '')\n .replace(/\\//g, '-')\n .replace(/\\\\/g, '-');\n\n input[entryName] = absolutePath;\n }\n\n // JS/TS files\n for (const jsPath of allJsPaths) {\n const relativePath = jsPath.startsWith('/src/')\n ? jsPath.substring(1)\n : jsPath.startsWith('/')\n ? jsPath.substring(1)\n : jsPath;\n\n const absolutePath = resolve(rootDir, relativePath);\n\n // Only add if file exists\n if (!existsSync(absolutePath)) {\n console.warn(`[l5e] JS/TS file not found: ${absolutePath} (from ${jsPath})`);\n continue;\n }\n\n // Generate entry name from path\n const entryName = relativePath\n .replace(/^src\\//, '')\n .replace(/\\.(ts|tsx|js|jsx)$/, '')\n .replace(/\\//g, '-')\n .replace(/\\\\/g, '-');\n\n input[entryName] = absolutePath;\n }\n\n // Add island component files to the bundler input so they appear in the manifest.\n // server.ts looks up manifest at runtime to resolve per-page island URLs.\n for (const [key, src] of keyToSrc) {\n const absolutePath = resolve(rootDir, src);\n input[`island-${key}`] = absolutePath;\n }\n\n if (islandRegistry.size > 0) {\n console.log(`[l5e] Detected ${islandRegistry.size} island(s)`);\n }\n if (actionRegistry.size > 0) {\n console.log(`[l5e] Detected ${actionRegistry.size} action(s)`);\n }\n } catch (error) {\n // Silently fail if directory doesn't exist or other errors\n console.warn('[l5e] Failed to discover bundler input:', error);\n }\n\n return { input, islandRegistry, pathToKey, keyToSrc, actionRegistry };\n}\n\n/**\n * Inject __key prop into ClientIsland calls\n * Use anchor-based approach to avoid fragile regex with nested objects\n */\nfunction injectIslandKeys(\n code: string,\n fileId: string,\n rootDir: string,\n pathToKey: Map<string, string>,\n keyToSrc: Map<string, string>,\n): string {\n // After esbuild, code has form:\n // jsxFactory(ClientIsland, { from: \"./react/Counter\", props: { n: 5 } })\n // ^anchor ^find from here\n\n const result: string[] = [];\n let lastIndex = 0;\n\n // Find each position \"ClientIsland,\" (anchor)\n const anchorRegex = /ClientIsland\\s*,\\s*\\{/g;\n let anchorMatch;\n\n while ((anchorMatch = anchorRegex.exec(code)) !== null) {\n const searchStart = anchorMatch.index + anchorMatch[0].length;\n\n // Scan for from: \"...\" in window ~500 chars after anchor\n const window = code.substring(searchStart, searchStart + 500);\n const fromMatch = /from:\\s*\"([^\"]+)\"/.exec(window);\n\n if (!fromMatch) continue;\n\n const fromPath = fromMatch[1];\n\n // Resolve path (handle ~/ alias)\n let resolved: string;\n if (fromPath.startsWith('~/')) {\n resolved = '/src/' + fromPath.substring(2);\n } else if (fromPath.startsWith('/src/')) {\n resolved = fromPath;\n } else if (fromPath.startsWith('./') || fromPath.startsWith('../')) {\n const abs = resolve(fileId, '..', fromPath);\n resolved = '/' + relative(rootDir, abs).replace(/\\\\/g, '/');\n } else {\n resolved = fromPath;\n }\n\n const key = pathToKey.get(resolved);\n if (!key) continue;\n\n const src = keyToSrc.get(key);\n if (!src) continue;\n\n // Inject __key and __src right after from: \"...\"\n const insertPos = searchStart + fromMatch.index + fromMatch[0].length;\n result.push(code.substring(lastIndex, insertPos));\n result.push(`, __key: \"${key}\", __src: \"${src}\"`);\n lastIndex = insertPos;\n }\n\n result.push(code.substring(lastIndex));\n return result.join('');\n}\n\nexport function coreVite(options: CoreViteOptions = {}): Plugin {\n let rootDir: string = process.cwd();\n let clientBuild = false;\n const planner = options.chunking === false ? null : createChunkPlanner(options.chunking);\n let islandRegistry = new Map<string, string>();\n let pathToKey = new Map<string, string>();\n let keyToSrc = new Map<string, string>();\n let actionRegistry = new Map<string, { modulePath: string; actionName: string }>();\n\n return {\n name: 'l5e-jsx-classic',\n enforce: 'pre',\n\n configResolved(resolvedConfig) {\n // Store root directory for later use\n rootDir = resolvedConfig.root || process.cwd();\n clientBuild = resolvedConfig.command === 'build' && !resolvedConfig.build.ssr;\n },\n\n async buildStart() {\n if (clientBuild && planner) {\n await planner.resolve(rootDir, async (id, importer) => {\n const resolved = await this.resolve(id, importer);\n return resolved && !resolved.external ? resolved.id : null;\n });\n }\n },\n\n generateBundle(_options, bundle) {\n if (clientBuild && planner) {\n this.emitFile({\n type: 'asset',\n fileName: '.vite/l5e-chunks.json',\n source: JSON.stringify(planner.report(bundle), null, 2),\n });\n }\n },\n\n handleHotUpdate({ file, server }) {\n const relPath = relative(rootDir, file);\n\n // Re-scan action registry when an actions file changes\n if (/actions\\.(ts|tsx)$/.test(file)) {\n const discovered = discoverBundlerInput(rootDir);\n actionRegistry = discovered.actionRegistry;\n // Invalidate the virtual:l5e-actions module so server picks up new registry\n const mod = server.moduleGraph.getModuleById('\\0' + VIRTUAL_L5E_ACTIONS);\n if (mod) {\n server.moduleGraph.invalidateModule(mod);\n }\n console.log(\n `[l5e] Action file changed: ${relPath} — re-scanned ${actionRegistry.size} action(s)`,\n );\n }\n\n // Allow Vite's default HMR for CSS and client-side JS files\n if (file.endsWith('.css')) {\n console.log(`[l5e] CSS changed: ${relPath} - using Vite HMR`);\n return; // Let Vite handle CSS HMR\n }\n\n if (file.includes('client.ts')) {\n console.log(`[l5e] Client JS changed: ${relPath} - using Vite HMR`);\n return; // Let Vite handle client JS HMR\n }\n\n // Trigger full page reload for SSR-related file changes (components, loaders, routes)\n // This ensures that server-side rendered components update properly\n if (file.includes('/src/') || file.includes('\\\\src\\\\')) {\n console.log(`[l5e] SSR file changed: ${relPath} - triggering full reload`);\n server.ws.send({\n type: 'full-reload',\n path: '*',\n });\n return []; // Prevent Vite's default HMR behavior\n }\n },\n\n buildEnd(error) {\n if (!error && clientBuild && planner) {\n const modules = [...this.getModuleIds()]\n .map((id) => this.getModuleInfo(id))\n .filter((mod) => mod !== null);\n for (const warning of planner.analyze(modules)) this.warn(`[l5e chunking] ${warning}`);\n }\n // Cleanup temporary files after build\n const tempDir = join(rootDir, '.l5e-temp');\n if (existsSync(tempDir)) {\n try {\n rmSync(tempDir, { recursive: true, force: true });\n console.log('[l5e] Cleaned up temporary files');\n } catch (error) {\n console.warn('[l5e] Failed to cleanup temporary files:', error);\n }\n }\n },\n\n writeBundle(_options, _bundle) {\n // Emit action registry JSON for production server\n if (actionRegistry.size > 0) {\n const outDir = join(rootDir, 'dist', 'server');\n if (!existsSync(outDir)) {\n mkdirSync(outDir, { recursive: true });\n }\n const registryObj = Object.fromEntries(actionRegistry);\n writeFileSync(join(outDir, 'action-registry.json'), JSON.stringify(registryObj), 'utf-8');\n console.log(`[l5e] Wrote action-registry.json (${actionRegistry.size} actions)`);\n }\n },\n\n config(userConfig) {\n // Auto-discover bundler input from useCss and useClientJs\n const projectRoot = userConfig.root || process.cwd();\n const output = userConfig.build?.rolldownOptions?.output;\n const configureChunks = !userConfig.build?.ssr && planner !== null;\n if (\n configureChunks &&\n (Array.isArray(output) || output?.manualChunks || output?.codeSplitting !== undefined)\n ) {\n throw new Error(\n '[l5e chunking] Use coreVite({ chunking: { shared: [...] } }) or set chunking: false when configuring raw Rolldown chunk placement.',\n );\n }\n const discovered = discoverBundlerInput(projectRoot);\n\n // Store island registries for use in other hooks\n islandRegistry = discovered.islandRegistry;\n pathToKey = discovered.pathToKey;\n keyToSrc = discovered.keyToSrc;\n actionRegistry = discovered.actionRegistry;\n\n // Merge with existing rolldownOptions.input if any\n const existingInput = userConfig.build?.rolldownOptions?.input || {};\n const mergedInput =\n typeof existingInput === 'object' && !Array.isArray(existingInput)\n ? { ...discovered.input, ...existingInput }\n : discovered.input;\n if (options.chunking && options.chunking.mode === 'compact') {\n mergedInput['l5e-compact-renderer'] = VIRTUAL_L5E_COMPACT_RENDERER;\n }\n\n return {\n build: {\n ...(options.chunking && options.chunking.mode === 'compact'\n ? {\n modulePreload: {\n resolveDependencies: (\n _filename: string,\n dependencies: string[],\n context: { hostType: 'html' | 'js' },\n ) =>\n context.hostType === 'html'\n ? dependencies.filter(\n (dependency) => !/\\.[cm]?js(?:\\?|$)/.test(dependency),\n )\n : dependencies,\n },\n }\n : {}),\n rolldownOptions: {\n ...userConfig.build?.rolldownOptions,\n input: Object.keys(mergedInput).length > 0 ? mergedInput : undefined,\n // Preserve exports for island component entries — without this,\n // The bundler tree-shakes their exports since nothing imports them\n // (they're loaded at runtime via dynamic import from the island runtime).\n preserveEntrySignatures: configureChunks ? 'allow-extension' : 'exports-only',\n ...(configureChunks\n ? {\n output: {\n ...output,\n strictExecutionOrder: true,\n codeSplitting: { groups: planner!.groups() },\n entryFileNames: (chunk) => {\n const source = chunk.facadeModuleId?.replace(/\\\\/g, '/') || '';\n if (source.endsWith('/src/client.global.ts'))\n return 'assets/global-[hash].js';\n if (/\\/react\\//.test(source))\n return chunk.name.startsWith('island-')\n ? 'assets/[name]-[hash].js'\n : 'assets/island-[name]-[hash].js';\n return 'assets/bundle-[name]-[hash].js';\n },\n chunkFileNames: (chunk) =>\n chunk.name.startsWith('shared-')\n ? 'assets/[name]-[hash].js'\n : chunk.name === 'shared'\n ? 'assets/shared-[hash].js'\n : chunk.name === 'lazy-react-runtime'\n ? 'assets/lazy-react-runtime-[hash].js'\n : chunk.isDynamicEntry\n ? 'assets/bundle-[name]-[hash].js'\n : 'assets/shared-[name]-[hash].js',\n },\n }\n : {}),\n },\n },\n } satisfies UserConfig;\n },\n\n resolveId(id) {\n if (id === VIRTUAL_L5E_VIEWS) {\n return '\\0' + VIRTUAL_L5E_VIEWS;\n }\n if (id === VIRTUAL_L5E_ROUTE) {\n return '\\0' + VIRTUAL_L5E_ROUTE;\n }\n if (id === VIRTUAL_L5E_SSR_ENTRY) {\n return '\\0' + VIRTUAL_L5E_SSR_ENTRY;\n }\n if (id === VIRTUAL_L5E_GLOBAL_LOADER) {\n return '\\0' + VIRTUAL_L5E_GLOBAL_LOADER;\n }\n if (id === VIRTUAL_L5E_ISLAND_STRATEGIES) {\n return '\\0' + VIRTUAL_L5E_ISLAND_STRATEGIES;\n }\n if (id === VIRTUAL_L5E_ISLANDS) {\n return '\\0' + VIRTUAL_L5E_ISLANDS;\n }\n if (id === VIRTUAL_L5E_COMPACT_RENDERER) {\n return '\\0' + VIRTUAL_L5E_COMPACT_RENDERER;\n }\n if (id === VIRTUAL_L5E_ACTIONS) {\n return '\\0' + VIRTUAL_L5E_ACTIONS;\n }\n if (id === VIRTUAL_L5E_MIDDLEWARE) {\n return '\\0' + VIRTUAL_L5E_MIDDLEWARE;\n }\n return null;\n },\n\n async transform(code, id, transformOptions) {\n // Auto-inject island runtime into client.global.ts so it's always loaded globally\n if (id.replace(/\\\\/g, '/').endsWith('src/client.global.ts') && !transformOptions?.ssr) {\n const compactRuntime =\n clientBuild && options.chunking && options.chunking.mode === 'compact';\n return {\n code: `import '@withl5e/l5e/island/${compactRuntime ? 'compact-runtime' : 'runtime'}';\\n${code}`,\n map: null,\n };\n }\n\n // Client-side action transform: replace defineAction exports with fetch stubs\n // Supports actions anywhere under src/ (e.g., src/views/*, src/features/*, etc.)\n if (!transformOptions?.ssr) {\n const normalizedId = id.replace(/\\\\/g, '/');\n const actionMatch = normalizedId.match(/\\/src\\/(.+)\\/actions\\.(ts|tsx)$/);\n if (actionMatch) {\n const modulePath = actionMatch[1];\n\n // Parse exported action names\n const exportRegex = /export\\s+const\\s+(\\w+)\\s*=\\s*defineAction\\s*\\(/g;\n const actions: Array<{ name: string; method: string }> = [];\n let m;\n while ((m = exportRegex.exec(code)) !== null) {\n const name = m[1];\n // Find method for this action — scan from the defineAction( position\n const chunk = code.substring(m.index, m.index + 500);\n const methodMatch = chunk.match(/method:\\s*['\"](\\w+)['\"]/);\n const method = methodMatch ? methodMatch[1].toUpperCase() : 'GET';\n actions.push({ name, method });\n }\n\n if (actions.length > 0) {\n const stubs = actions.map(({ name, method }) => {\n const actionKey = `${name}_${shortHash(modulePath)}`;\n if (method === 'GET') {\n return `export async function ${name}(params) {\n const res = await fetch('/_l5e/action/${actionKey}?' + new URLSearchParams(params));\n if (!res.ok) throw Object.assign(new Error('HTTP ' + res.status), { status: res.status });\n return res;\n}`;\n }\n return `export async function ${name}(body) {\n const res = await fetch('/_l5e/action/${actionKey}', {\n method: '${method}',\n headers: { 'Content-Type': 'application/json' },\n body: JSON.stringify(body),\n });\n if (!res.ok) throw Object.assign(new Error('HTTP ' + res.status), { status: res.status });\n return res;\n}`;\n });\n\n return {\n code: stubs.join('\\n\\n'),\n map: null,\n };\n }\n }\n }\n\n // Skip node_modules\n if (id.includes('node_modules')) {\n return null;\n }\n\n // Skip files in /react/ directories\n if (id.includes('/react/') || id.includes('\\\\react\\\\')) {\n return null;\n }\n\n // Check if this is a JSX/TSX file that needs L5E JSX transformation\n const isJsxFile = /\\.(tsx|jsx)$/.test(id);\n\n if (isJsxFile) {\n try {\n const injected = `import { Fragment as __Fragment, jsxFactory } from \"@withl5e/l5e/jsx-runtime\"\\n${code}`;\n\n // Transform JSX using esbuild with L5E's JSX runtime (async)\n const result = await transform(injected, {\n loader: id.endsWith('.tsx') ? 'tsx' : 'jsx',\n jsx: 'transform',\n jsxFactory: 'jsxFactory',\n jsxFragment: '__Fragment',\n sourcemap: true,\n sourcefile: id,\n target: 'es2020',\n });\n\n let transformedCode = result.code;\n\n // Inject __key and __src for ALL ClientIsland calls\n if (transformedCode.includes('ClientIsland')) {\n transformedCode = injectIslandKeys(transformedCode, id, rootDir, pathToKey, keyToSrc);\n }\n\n return {\n code: transformedCode,\n map: result.map || null,\n };\n } catch (error) {\n // Log error but let Vite handle it\n console.error(`[l5e] Failed to transform JSX in ${id}:`, error);\n throw error;\n }\n }\n\n // Transform import.meta.env thành process.env ở server side\n // Server side có thể access tất cả env variables\n // Client side chỉ access được VITE_ env variables\n // Transform này chạy ở runtime khi module được load trong SSR context\n if (transformOptions?.ssr) {\n let transformedCode = code;\n let hasChanges = false;\n\n // Thay thế import.meta.env.VARIABLE_NAME thành process.env.VARIABLE_NAME\n // Match: import.meta.env.VITE_EVENT_CATEGORY_SLUG\n transformedCode = transformedCode.replace(\n /import\\.meta\\.env\\.([a-zA-Z_][a-zA-Z0-9_]*)/g,\n (match, varName) => {\n // Leave Vite's built-in env vars for Vite to handle.\n if (VITE_RESERVED_ENV.has(varName)) return match;\n hasChanges = true;\n return `process.env.${varName}`;\n },\n );\n\n // Thay thế import.meta.env['VARIABLE_NAME'] hoặc import.meta.env[\"VARIABLE_NAME\"]\n // thành process.env['VARIABLE_NAME'] hoặc process.env[\"VARIABLE_NAME\"]\n // Match: import.meta.env['VITE_EVENT_CATEGORY_SLUG'] hoặc import.meta.env[\"VITE_EVENT_CATEGORY_SLUG\"]\n transformedCode = transformedCode.replace(\n /import\\.meta\\.env\\[(['\"`])([^'\"`]+)\\1\\]/g,\n (match, quote, varName) => {\n // Leave Vite's built-in env vars for Vite to handle.\n if (VITE_RESERVED_ENV.has(varName)) return match;\n hasChanges = true;\n return `process.env[${quote}${varName}${quote}]`;\n },\n );\n\n if (hasChanges) {\n return {\n code: transformedCode,\n map: null, // Không cần source map cho env transform\n };\n }\n }\n return null;\n },\n\n load(id) {\n // Virtual module: l5e-views\n if (id === '\\0' + VIRTUAL_L5E_VIEWS) {\n return `\nexport const viewLoaders = import.meta.glob('/src/views/*/loader.{ts,tsx}');\nexport const viewComponents = import.meta.glob('/src/views/*/index.tsx');\n`;\n }\n\n // Virtual module: l5e-route\n if (id === '\\0' + VIRTUAL_L5E_ROUTE) {\n // Load /src/route.ts LAZILY (dynamic import inside the handler) rather\n // than via a static `export { default } from '/src/route.ts'`.\n //\n // A static re-export drags the user's route module — and everything it\n // imports — into entry-server's *static* SSR graph. Route files commonly\n // import the `@withl5e/l5e` barrel (for RedirectException, types, ...),\n // and that barrel re-exports `render` from entry-server. That closes a\n // static import cycle:\n // entry-server → virtual:l5e-route → /src/route.ts → @withl5e/l5e → entry-server\n // On the first dev request Vite can begin evaluating entry-server while\n // it is still suspended awaiting this very import, so `render()` runs\n // before `const __vite_ssr_import_N__ = await import('virtual:l5e-route')`\n // has been assigned — throwing \"Cannot access '__vite_ssr_import_N__'\n // before initialization\". A page reload \"fixes\" it only because the graph\n // is fully warm the second time.\n //\n // Importing lazily removes /src/route.ts from the static graph: entry-server\n // finishes initializing first, and the route module (with its barrel import\n // back to a now-complete entry-server) is pulled only on the first render()\n // call. No manual caching — Vite/ESM caches the evaluated module and later\n // imports still observe HMR invalidations of route.ts.\n return `export default function routeHandler(requestInfo) {\n return import('/src/route.ts').then((mod) => mod.default(requestInfo));\n}`;\n }\n\n // Virtual module: l5e-ssr-entry\n if (id === '\\0' + VIRTUAL_L5E_SSR_ENTRY) {\n return `export { render } from '@withl5e/l5e/entry-server';\nexport { viewActions } from 'virtual:l5e-actions';`;\n }\n\n // Virtual module: l5e-global-loader\n if (id === '\\0' + VIRTUAL_L5E_GLOBAL_LOADER) {\n return `export const globalLoader = import.meta.glob('/src/global-loader.{ts,tsx}', { eager: false });`;\n }\n\n // Virtual module: l5e-actions\n if (id === '\\0' + VIRTUAL_L5E_ACTIONS) {\n const registryObj = Object.fromEntries(actionRegistry);\n return `export const viewActions = import.meta.glob('/src/**/actions.{ts,tsx}');\nexport const actionRegistry = ${JSON.stringify(registryObj)};`;\n }\n\n // Virtual module: l5e-middleware\n if (id === '\\0' + VIRTUAL_L5E_MIDDLEWARE) {\n return `\nconst middlewareModules = import.meta.glob([\n '/src/middleware.{ts,tsx,js,jsx}',\n '/src/middleware/index.{ts,tsx,js,jsx}',\n]);\n\nconst middlewarePaths = [\n '/src/middleware.ts',\n '/src/middleware.tsx',\n '/src/middleware.js',\n '/src/middleware.jsx',\n '/src/middleware/index.ts',\n '/src/middleware/index.tsx',\n '/src/middleware/index.js',\n '/src/middleware/index.jsx',\n];\n\nexport async function loadMiddleware() {\n const middlewarePath = middlewarePaths.find((path) => middlewareModules[path]);\n if (!middlewarePath) return undefined;\n\n const mod = await middlewareModules[middlewarePath]();\n return mod.onRequest;\n}\n`;\n }\n\n // Virtual module: l5e-islands\n // Lazy glob of all React island components so the SSR entry can import a\n // component by its __src path and renderToString() it. Non-eager → only\n // islands actually present on a page (with ssr) get imported at runtime.\n if (id === '\\0' + VIRTUAL_L5E_ISLANDS) {\n return `export const islandModules = import.meta.glob('/src/**/react/*.{tsx,jsx}');`;\n }\n if (id === '\\0' + VIRTUAL_L5E_COMPACT_RENDERER) {\n return `export * as reactDomClient from 'react-dom/client'; export { createElement } from 'react';`;\n }\n\n // Virtual module: l5e-island-strategies\n if (id === '\\0' + VIRTUAL_L5E_ISLAND_STRATEGIES) {\n // Check if src/island-strategies.ts exists\n const strategiesFile = join(rootDir, 'src', 'island-strategies.ts');\n if (existsSync(strategiesFile)) {\n // Re-export user's file → Vite will build this file\n return `import '/src/island-strategies.ts';`;\n }\n // No file → empty module, no error\n return `/* no custom island strategies */`;\n }\n\n return null;\n },\n };\n}\n\nexport default coreVite;\n"],"mappings":"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"}
@@ -1,2 +1,2 @@
1
- import { t as e } from "./vite-plugin-BOuzxmb2.js";
1
+ import { t as e } from "./vite-plugin-Bln1di66.js";
2
2
  export { e as coreVite, e as default };
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@withl5e/l5e",
3
- "version": "1.1.0-alpha.2",
3
+ "version": "1.1.0-alpha.3",
4
4
  "description": "HTML-first SSR MPA framework with loaders, middleware, islands, actions, swap, SEO and cache controls.",
5
5
  "type": "module",
6
6
  "license": "MIT",
@@ -253,11 +253,9 @@ export function createChunkPlanner(options: ChunkingOptions = {}) {
253
253
  maxSize: rule.maxSize,
254
254
  includeDependenciesRecursively: options.mode === 'compact',
255
255
  })),
256
- {
257
- name: (id: string) =>
258
- decisions.get(id)?.group === 'lazy-react-runtime' ? 'lazy-react-runtime' : null,
259
- includeDependenciesRecursively: true,
260
- },
256
+ // Reserve eager owners before recursively collecting the lazy UI closure.
257
+ // Otherwise a lazy hook's dynamic import can capture Vite's preload helper
258
+ // and force global to import the entire React renderer chunk for that helper.
261
259
  {
262
260
  name: (id: string) => {
263
261
  const group = decisions.get(id)?.group;
@@ -265,6 +263,11 @@ export function createChunkPlanner(options: ChunkingOptions = {}) {
265
263
  },
266
264
  includeDependenciesRecursively: false,
267
265
  },
266
+ {
267
+ name: (id: string) =>
268
+ decisions.get(id)?.group === 'lazy-react-runtime' ? 'lazy-react-runtime' : null,
269
+ includeDependenciesRecursively: true,
270
+ },
268
271
  ];
269
272
  },
270
273
  report(bundle: OutputBundle) {
@@ -274,6 +277,19 @@ export function createChunkPlanner(options: ChunkingOptions = {}) {
274
277
  warnings: [...warnings],
275
278
  chunks: Object.values(bundle).flatMap((chunk) => {
276
279
  if (chunk.type !== 'chunk') return [];
280
+ const moduleGroups = new Set(
281
+ Object.keys(chunk.modules).map((id) => decisions.get(id)?.group),
282
+ );
283
+ if (
284
+ options.mode === 'compact' &&
285
+ moduleGroups.has('global-owner') &&
286
+ moduleGroups.has('lazy-react-runtime')
287
+ ) {
288
+ throw new Error(
289
+ `[l5e chunking] ${chunk.fileName} mixes global-owned and lazy island runtime modules. ` +
290
+ 'Keep eager owners separate before recursively collecting the lazy runtime.',
291
+ );
292
+ }
277
293
  const source = chunk.facadeModuleId ? portable(chunk.facadeModuleId) : null;
278
294
  const kind =
279
295
  source === 'src/client.global.ts'
@@ -673,8 +673,10 @@ export function coreVite(options: CoreViteOptions = {}): Plugin {
673
673
  async transform(code, id, transformOptions) {
674
674
  // Auto-inject island runtime into client.global.ts so it's always loaded globally
675
675
  if (id.replace(/\\/g, '/').endsWith('src/client.global.ts') && !transformOptions?.ssr) {
676
+ const compactRuntime =
677
+ clientBuild && options.chunking && options.chunking.mode === 'compact';
676
678
  return {
677
- code: `import '@withl5e/l5e/island/${options.chunking && options.chunking.mode === 'compact' ? 'compact-runtime' : 'runtime'}';\n${code}`,
679
+ code: `import '@withl5e/l5e/island/${compactRuntime ? 'compact-runtime' : 'runtime'}';\n${code}`,
678
680
  map: null,
679
681
  };
680
682
  }
@@ -1 +0,0 @@
1
- {"version":3,"file":"vite-plugin-BOuzxmb2.js","names":["join"],"sources":["../src/core/chunking.ts","../src/core/vite-plugin.ts"],"sourcesContent":["import { createHash } from 'node:crypto';\nimport path from 'node:path';\nimport type { CodeSplittingGroup, ModuleInfo, OutputBundle } from 'rolldown';\n\nexport interface SharedChunkGroup {\n name: string;\n /** Exact package names, including their subpath imports. */\n packages?: string[];\n /** Module specifiers resolved by Vite, including aliases. */\n modules?: string[];\n priority?: number;\n /** Approximate uncompressed maximum; not a hard network byte budget. */\n maxSize?: number;\n}\n\nexport interface ChunkingOptions {\n /**\n * Opt in to at most one global, one page bundle and one canonical shared file.\n * State that must retain identity across page bundles must be listed in `shared`.\n */\n mode?: 'compact';\n shared?: SharedChunkGroup[];\n /** Static UI/runtime roots that join React's canonical lazy activation chunk. */\n islandRuntime?: Pick<SharedChunkGroup, 'packages' | 'modules'>;\n}\n\nexport interface CoreViteOptions {\n /** false leaves chunk placement to Vite; runtime identity protection stays enabled. */\n chunking?: ChunkingOptions | false;\n}\n\nconst normalize = (id: string) => id.replace(/\\\\/g, '/');\nconst digest = (value: string) => createHash('sha256').update(value).digest('hex').slice(0, 8);\n\n/** The last node_modules segment also handles pnpm's nested package layout. */\nfunction packageName(id: string): string | undefined {\n const suffix = normalize(id).split('/node_modules/').at(-1);\n if (suffix === normalize(id)) return undefined;\n const parts = suffix!.split('/');\n return parts[0].startsWith('@') ? parts.slice(0, 2).join('/') : parts[0];\n}\n\ntype Decision = { group: string | null; rule?: string; consumers: string[]; reason: string };\n\n/** One build-time plan drives placement and the diagnostic report. Runtime reads Vite's manifest. */\nexport function createChunkPlanner(options: ChunkingOptions = {}) {\n const rules = options.shared || [];\n const islandRuntimeRule = options.islandRuntime;\n if (\n islandRuntimeRule &&\n !islandRuntimeRule.packages?.length &&\n !islandRuntimeRule.modules?.length\n ) {\n throw new Error('[l5e chunking] islandRuntime needs packages or modules.');\n }\n if (options.mode === 'compact' && rules.length > 1) {\n throw new Error('[l5e chunking] Compact mode accepts one canonical shared group.');\n }\n const names = new Set<string>();\n for (const rule of rules) {\n if (!/^[a-zA-Z0-9][a-zA-Z0-9_-]*$/.test(rule.name) || names.has(rule.name)) {\n throw new Error(`[l5e chunking] Invalid or duplicate shared group: ${rule.name}`);\n }\n if (!rule.packages?.length && !rule.modules?.length) {\n throw new Error(`[l5e chunking] Group ${rule.name} needs packages or modules.`);\n }\n if (rule.maxSize !== undefined && (!Number.isFinite(rule.maxSize) || rule.maxSize <= 0)) {\n throw new Error(`[l5e chunking] Invalid maxSize for ${rule.name}`);\n }\n if (options.mode === 'compact' && rule.maxSize !== undefined) {\n throw new Error(\n `[l5e chunking] Compact mode cannot use maxSize for ${rule.name}; it would split the canonical shared file.`,\n );\n }\n names.add(rule.name);\n }\n let root = '';\n const resolvedRules = new Map<SharedChunkGroup, Set<string>>();\n let resolvedIslandRuntime = new Set<string>();\n const decisions = new Map<string, Decision>();\n const warnings = new Set<string>();\n const portable = (id: string) => {\n const pkg = packageName(id);\n if (pkg) return `npm:${normalize(id).split('/node_modules/').at(-1)}`;\n return normalize(path.relative(root, id));\n };\n\n return {\n async resolve(\n projectRoot: string,\n resolveId: (id: string, importer: string) => Promise<string | null>,\n ) {\n root = projectRoot;\n resolvedRules.clear();\n resolvedIslandRuntime = new Set();\n decisions.clear();\n warnings.clear();\n for (const rule of rules) {\n const ids = new Set<string>();\n for (const specifier of rule.modules || []) {\n const id = await resolveId(specifier, path.join(root, 'index.html'));\n if (!id) throw new Error(`[l5e chunking] Cannot resolve ${specifier} in ${rule.name}`);\n ids.add(id);\n }\n resolvedRules.set(rule, ids);\n }\n if (islandRuntimeRule) {\n for (const specifier of islandRuntimeRule.modules || []) {\n const id = await resolveId(specifier, path.join(root, 'index.html'));\n if (!id) throw new Error(`[l5e chunking] Cannot resolve ${specifier} in islandRuntime`);\n resolvedIslandRuntime.add(id);\n }\n }\n },\n analyze(modules: ModuleInfo[]) {\n decisions.clear();\n const graph = new Map(modules.map((mod) => [mod.id, mod]));\n if (options.mode === 'compact') {\n const reachability = new Map<string, Map<string, boolean>>();\n for (const entry of modules.filter((mod) => mod.isEntry)) {\n const visit = (id: string, lazy: boolean) => {\n const owners = reachability.get(id) || new Map<string, boolean>();\n const previous = owners.get(entry.id);\n if (previous === false || previous === lazy) return;\n owners.set(entry.id, lazy);\n reachability.set(id, owners);\n const module = graph.get(id);\n if (!module) return;\n module.importedIds.forEach((dependency) => visit(dependency, lazy));\n module.dynamicallyImportedIds.forEach((dependency) => visit(dependency, true));\n };\n visit(entry.id, false);\n }\n const globalEntry = modules.find(\n (mod) => mod.isEntry && normalize(mod.id).endsWith('/src/client.global.ts'),\n );\n if (globalEntry) {\n for (const [id, owners] of reachability) {\n if (\n !/\\.css(?:\\?|$)/.test(normalize(id)) &&\n owners.get(globalEntry.id) === true &&\n [...owners.keys()].some((owner) => owner !== globalEntry.id)\n ) {\n throw new Error(\n `[l5e chunking] Compact mode cannot bridge a dynamic-only global overlap: ${portable(id)}. Import it statically from global or place state behind an explicit shared root.`,\n );\n }\n }\n }\n }\n const roots = modules.filter((mod) => mod.isEntry || mod.dynamicImporters.length > 0);\n const consumers = new Map<string, Set<string>>();\n for (const entry of roots) {\n const visited = new Set<string>();\n const visit = (id: string) => {\n if (visited.has(id)) return;\n visited.add(id);\n const mod = graph.get(id);\n if (!mod) return;\n const users = consumers.get(id) || new Set<string>();\n users.add(entry.id);\n consumers.set(id, users);\n mod.importedIds.forEach(visit);\n };\n visit(entry.id);\n }\n const rank = (id: string) => {\n const mod = graph.get(id)!;\n if (!mod.isEntry) return 3;\n if (normalize(id).endsWith('/src/client.global.ts')) return 0;\n if (normalize(id).includes('virtual:l5e-compact-renderer')) return 2;\n if (/\\/react\\//.test(normalize(id)) && !packageName(id)) return 2;\n return 1;\n };\n const matched = new Set<SharedChunkGroup>();\n for (const mod of modules) {\n const users = [...(consumers.get(mod.id) || [])].sort();\n const labels = users.map(portable).sort();\n const matches = rules\n .filter(\n (rule) =>\n resolvedRules.get(rule)?.has(mod.id) ||\n rule.packages?.includes(packageName(mod.id) || ''),\n )\n .sort((a, b) => (b.priority || 0) - (a.priority || 0));\n matches.forEach((rule) => matched.add(rule));\n if (matches.length > 1)\n warnings.add(\n `${portable(mod.id)} matches ${matches.map((r) => r.name).join(', ')}; using ${matches[0].name}.`,\n );\n let group: string | null = null;\n let reason = 'Private dependency stays with its entry or dynamic import.';\n const pkg = packageName(mod.id);\n const islandRuntimeMatch =\n resolvedIslandRuntime.has(mod.id) ||\n islandRuntimeRule?.packages?.includes(pkg || '') === true;\n if (\n options.mode === 'compact' &&\n normalize(mod.id).includes('virtual:l5e-compact-renderer')\n ) {\n group = 'lazy-react-runtime';\n reason = 'Renderer joins the canonical React runtime activation.';\n } else if (\n options.mode === 'compact' &&\n !mod.isEntry &&\n (pkg === 'react' || pkg === 'react-dom' || pkg === 'scheduler') &&\n users.length > 0 &&\n users.every((id) => rank(id) >= 2)\n ) {\n group = 'lazy-react-runtime';\n reason = 'Canonical React runtime is fetched when the first island activates.';\n } else if (!mod.isEntry && users.length && matches.length) {\n // Explicit groups can combine consumers at the same activation tier.\n // Never promote island-only code into global/page, or dynamic-only code\n // into a static entry. Distinct dynamic roots remain separate as well.\n const tier = Math.min(...users.map(rank));\n const activation =\n tier === 3\n ? `lazy-${digest(JSON.stringify(labels))}`\n : ['global', 'page', 'island'][tier];\n group = options.mode === 'compact' ? 'shared' : `shared-${matches[0].name}-${activation}`;\n reason = `Configured group ${matches[0].name}; activation ${activation}.`;\n } else if (options.mode === 'compact' && !mod.isEntry && islandRuntimeMatch) {\n group = 'lazy-react-runtime';\n reason = 'Configured canonical island runtime is fetched with the first island consumer.';\n } else if (\n options.mode === 'compact' &&\n !mod.isEntry &&\n users.some((id) => rank(id) === 0) &&\n users.some((id) => rank(id) > 0)\n ) {\n group = 'global-owner';\n reason = 'Static global/page overlap is exported by the canonical global artifact.';\n } else if (options.mode !== 'compact' && !mod.isEntry && users.length > 1) {\n group = `shared-auto-${digest(JSON.stringify(labels))}`;\n reason = 'Shared by the same static consumers; preserves dynamic import roots.';\n }\n decisions.set(mod.id, { group, rule: matches[0]?.name, consumers: labels, reason });\n }\n for (const rule of rules) {\n if (!matched.has(rule))\n warnings.add(`Group ${rule.name} matched no modules in this client build.`);\n }\n return [...warnings];\n },\n groups(): CodeSplittingGroup[] {\n return [\n ...rules.map((rule) => ({\n name: (id: string) => {\n const decision = decisions.get(id);\n return decision?.rule === rule.name ? decision.group : null;\n },\n maxSize: rule.maxSize,\n includeDependenciesRecursively: options.mode === 'compact',\n })),\n {\n name: (id: string) =>\n decisions.get(id)?.group === 'lazy-react-runtime' ? 'lazy-react-runtime' : null,\n includeDependenciesRecursively: true,\n },\n {\n name: (id: string) => {\n const group = decisions.get(id)?.group;\n return group === 'lazy-react-runtime' ? null : group || null;\n },\n includeDependenciesRecursively: false,\n },\n ];\n },\n report(bundle: OutputBundle) {\n return {\n version: 2,\n mode: options.mode || 'default',\n warnings: [...warnings],\n chunks: Object.values(bundle).flatMap((chunk) => {\n if (chunk.type !== 'chunk') return [];\n const source = chunk.facadeModuleId ? portable(chunk.facadeModuleId) : null;\n const kind =\n source === 'src/client.global.ts'\n ? 'global'\n : source && /(?:^|\\/)react\\//.test(source)\n ? 'island'\n : chunk.isEntry || chunk.isDynamicEntry\n ? 'page'\n : 'shared';\n return [\n {\n file: chunk.fileName,\n kind,\n canonicalShared: options.mode === 'compact' && chunk.name === 'shared',\n canonicalGlobal: options.mode === 'compact' && chunk.name === 'global-owner',\n source,\n bytes: Buffer.byteLength(chunk.code),\n imports: chunk.imports,\n dynamicImports: chunk.dynamicImports,\n modules: Object.keys(chunk.modules).map((id) => ({\n id: portable(id),\n ...decisions.get(id),\n })),\n },\n ];\n }),\n };\n },\n };\n}\n","import { transform } from 'esbuild';\nimport {\n existsSync,\n mkdirSync,\n readdirSync,\n readFileSync,\n rmSync,\n statSync,\n writeFileSync,\n} from 'fs';\nimport { dirname, join, relative, resolve } from 'path';\nimport type { Plugin, UserConfig } from 'vite';\nimport { findGlobalStyleInput } from './global-style';\nimport { createChunkPlanner, type CoreViteOptions } from './chunking';\nexport type { CoreViteOptions, ChunkingOptions, SharedChunkGroup } from './chunking';\n\nconst VIRTUAL_L5E_VIEWS = 'virtual:l5e-views';\nconst VIRTUAL_L5E_ROUTE = 'virtual:l5e-route';\nconst VIRTUAL_L5E_SSR_ENTRY = 'virtual:l5e-ssr-entry';\nconst VIRTUAL_L5E_GLOBAL_LOADER = 'virtual:l5e-global-loader';\nconst VIRTUAL_L5E_ISLAND_STRATEGIES = 'virtual:l5e-island-strategies';\nconst VIRTUAL_L5E_ISLANDS = 'virtual:l5e-islands';\nconst VIRTUAL_L5E_COMPACT_RENDERER = 'virtual:l5e-compact-renderer';\nconst VIRTUAL_L5E_ACTIONS = 'virtual:l5e-actions';\nconst VIRTUAL_L5E_MIDDLEWARE = 'virtual:l5e-middleware';\n\n/**\n * Vite's built-in env vars on `import.meta.env`. These are statically replaced\n * by Vite itself (DEV/PROD/SSR are booleans, MODE/BASE_URL strings), so the SSR\n * `import.meta.env.* -> process.env.*` rewrite must skip them — otherwise it\n * clobbers Vite defaults (e.g. `import.meta.env.DEV` would become the undefined\n * `process.env.DEV`).\n */\nconst VITE_RESERVED_ENV = new Set(['MODE', 'BASE_URL', 'PROD', 'DEV', 'SSR', 'LEGACY']);\n\n/**\n * Recursively scan directory for .tsx and .ts files\n */\nfunction scanTsFiles(dir: string, fileList: string[] = []): string[] {\n const files = readdirSync(dir);\n\n for (const file of files) {\n const filePath = join(dir, file);\n const stat = statSync(filePath);\n\n if (stat.isDirectory()) {\n // Skip node_modules and dist directories\n if (file === 'node_modules' || file === 'dist' || file === '.git') {\n continue;\n }\n scanTsFiles(filePath, fileList);\n } else if (file.endsWith('.tsx') || file.endsWith('.ts')) {\n fileList.push(filePath);\n }\n }\n\n return fileList;\n}\n\n/**\n * Short hash function for island keys\n */\nfunction shortHash(str: string): string {\n let hash = 0;\n for (let i = 0; i < str.length; i++) {\n hash = (hash << 5) - hash + str.charCodeAt(i);\n hash = hash & hash;\n }\n return Math.abs(hash).toString(16).slice(0, 4);\n}\n\n/**\n * Derive component name from path: \"./react/Counter\" → \"Counter\"\n */\nfunction deriveComponentName(fromPath: string): string {\n const segments = fromPath.split('/');\n let filename = segments[segments.length - 1];\n // Remove extension if present\n filename = filename.replace(/\\.(tsx?|jsx?)$/, '');\n return filename;\n}\n\n/**\n * Create island registry key: \"/src/views/test-island/react/Counter\" → \"Counter_a3f2\"\n */\nfunction makeIslandKey(resolvedPath: string): string {\n const name = deriveComponentName(resolvedPath);\n return `${name}_${shortHash(resolvedPath)}`;\n}\n\n/**\n * Resolve file path with extension (.tsx, .ts, .jsx, .js)\n * Returns the relative path with extension (e.g., \"src/views/.../Counter.tsx\")\n * or null if file not found\n */\nfunction resolveWithExtension(resolvedPath: string, rootDir: string): string | null {\n // resolvedPath: \"/src/views/test-island/react/Counter\" (no extension, leading /)\n const relPath = resolvedPath.replace(/^\\//, ''); // \"src/views/.../Counter\"\n const absBase = resolve(rootDir, relPath);\n\n // Check with extensions\n for (const ext of ['.tsx', '.ts', '.jsx', '.js']) {\n if (existsSync(absBase + ext)) {\n return relPath + ext; // \"src/views/.../Counter.tsx\"\n }\n }\n // Check without extension (file might already have one)\n if (existsSync(absBase)) {\n return relPath;\n }\n return null;\n}\n\n/**\n * Extract island entries from file using regex on JSX source\n */\nfunction extractIslandEntries(\n filePath: string,\n rootDir: string,\n): Array<{ component: string; resolvedPath: string; src: string; key: string }> {\n const content = readFileSync(filePath, 'utf-8');\n const entries: Array<{ component: string; resolvedPath: string; src: string; key: string }> = [];\n\n // Regex scan JSX source (NOT post-transform code).\n // Just find <ClientIsland ... from=\"Y\" ...> — component name derived from path.\n const regex = /<ClientIsland\\s[^>]*?from\\s*=\\s*\"([^\"]+)\"/g;\n\n const seen = new Set<string>();\n let match;\n\n while ((match = regex.exec(content)) !== null) {\n const fromPath = match[1];\n\n // Resolve relative path → absolute\n let resolvedPath: string;\n if (fromPath.startsWith('~/')) {\n // Alias ~/ → /src/ (project convention)\n resolvedPath = '/src/' + fromPath.substring(2);\n } else if (fromPath.startsWith('/src/')) {\n resolvedPath = fromPath;\n } else if (fromPath.startsWith('./') || fromPath.startsWith('../')) {\n const abs = resolve(filePath, '..', fromPath);\n resolvedPath = '/' + relative(rootDir, abs).replace(/\\\\/g, '/');\n } else {\n resolvedPath = fromPath;\n }\n\n // Resolve file extension for manifest compatibility\n const src = resolveWithExtension(resolvedPath, rootDir);\n if (!src) {\n console.warn(\n `[l5e] Island component not found: ${resolvedPath} (from ${fromPath} in ${filePath})`,\n );\n continue;\n }\n\n const key = makeIslandKey(resolvedPath);\n if (!seen.has(key)) {\n seen.add(key);\n entries.push({\n component: deriveComponentName(resolvedPath),\n resolvedPath,\n src, // \"src/views/.../Counter.tsx\" — matches manifest key format\n key,\n });\n }\n }\n return entries;\n}\n\n/**\n * Extract paths from useCss and useClientJs calls using regex\n */\nfunction extractPathsFromFile(filePath: string, rootDir: string): { css: string[]; js: string[] } {\n const content = readFileSync(filePath, 'utf-8');\n const css: string[] = [];\n const js: string[] = [];\n\n // Regex patterns to match useCss('path') or useCss(\"path\")\n // Handles single and double quotes, and escaped quotes\n const useCssPattern = /useCss\\s*\\(\\s*['\"]([^'\"]+)['\"]\\s*,?\\s*\\)/g;\n const useClientJsPattern = /useClientJs\\s*\\(\\s*['\"]([^'\"]+)['\"]\\s*,?\\s*\\)/g;\n\n let match;\n\n // Extract CSS paths\n while ((match = useCssPattern.exec(content)) !== null) {\n const path = match[1];\n // Convert relative path to absolute if needed\n if (path.startsWith('/src/')) {\n css.push(path);\n } else if (path.startsWith('./') || path.startsWith('../')) {\n // Resolve relative path\n const absolutePath = resolve(filePath, '..', path);\n const relativePath = '/' + relative(rootDir, absolutePath).replace(/\\\\/g, '/');\n css.push(relativePath);\n } else {\n css.push(path);\n }\n }\n\n // Extract JS paths\n while ((match = useClientJsPattern.exec(content)) !== null) {\n const path = match[1];\n if (path.startsWith('/src/')) {\n js.push(path);\n } else if (path.startsWith('./') || path.startsWith('../')) {\n const absolutePath = resolve(filePath, '..', path);\n const relativePath = '/' + relative(rootDir, absolutePath).replace(/\\\\/g, '/');\n js.push(relativePath);\n } else {\n js.push(path);\n }\n }\n\n return { css, js };\n}\n\n/**\n * Auto-discover bundler input entries from useCss and useClientJs calls\n */\nfunction discoverBundlerInput(rootDir: string): {\n input: Record<string, string>;\n islandRegistry: Map<string, string>;\n pathToKey: Map<string, string>;\n keyToSrc: Map<string, string>;\n actionRegistry: Map<string, { modulePath: string; actionName: string }>;\n} {\n const input: Record<string, string> = {};\n const srcDir = join(rootDir, 'src');\n\n // Island registries\n const islandRegistry = new Map<string, string>(); // key → resolvedPath\n const pathToKey = new Map<string, string>(); // resolvedPath → key\n const keyToSrc = new Map<string, string>(); // key → src (manifest-compatible path with extension)\n\n // Action registry: actionKey → { modulePath, actionName }\n const actionRegistry = new Map<string, { modulePath: string; actionName: string }>();\n\n try {\n // Check if src directory exists\n if (!statSync(srcDir).isDirectory()) {\n return { input, islandRegistry, pathToKey, keyToSrc, actionRegistry };\n }\n\n // Check if src/client.global.ts exists and add it as an entry\n const globalTsPath = join(rootDir, 'src', 'client.global.ts');\n if (existsSync(globalTsPath)) {\n input['global'] = globalTsPath;\n console.log('[l5e] Detected src/client.global.ts and added as entry');\n }\n\n const globalStyleInput = findGlobalStyleInput(rootDir);\n if (globalStyleInput) {\n input['global-style'] = globalStyleInput;\n console.log('[l5e] Detected src/global.css and added as global stylesheet');\n }\n\n // Scan all .tsx and .ts files\n const tsFiles = scanTsFiles(srcDir);\n\n // Extract all paths\n const allCssPaths = new Set<string>();\n const allJsPaths = new Set<string>();\n\n for (const file of tsFiles) {\n const { css, js } = extractPathsFromFile(file, rootDir);\n css.forEach((path) => allCssPaths.add(path));\n js.forEach((path) => allJsPaths.add(path));\n\n // Extract island entries\n const islandEntries = extractIslandEntries(file, rootDir);\n for (const entry of islandEntries) {\n islandRegistry.set(entry.key, entry.resolvedPath);\n pathToKey.set(entry.resolvedPath, entry.key);\n keyToSrc.set(entry.key, entry.src);\n }\n\n // Extract action entries from actions.ts/tsx files\n const normalizedFile = file.replace(/\\\\/g, '/');\n if (/\\/actions\\.(ts|tsx)$/.test(normalizedFile)) {\n const content = readFileSync(file, 'utf-8');\n const actionExportRegex = /export\\s+const\\s+(\\w+)\\s*=\\s*defineAction\\s*\\(/g;\n let actionMatch;\n\n // Compute modulePath: relative path from src/ to parent dir\n const relFromSrc = relative(srcDir, dirname(file)).replace(/\\\\/g, '/');\n const modulePath = relFromSrc || '.';\n\n while ((actionMatch = actionExportRegex.exec(content)) !== null) {\n const actionName = actionMatch[1];\n const actionKey = `${actionName}_${shortHash(modulePath)}`;\n actionRegistry.set(actionKey, { modulePath, actionName });\n }\n }\n }\n\n // Convert paths to bundler input entries\n // CSS files\n for (const cssPath of allCssPaths) {\n // Remove leading /src/ and convert to relative path\n const relativePath = cssPath.startsWith('/src/')\n ? cssPath.substring(1) // Remove leading /\n : cssPath.startsWith('/')\n ? cssPath.substring(1)\n : cssPath;\n\n const absolutePath = resolve(rootDir, relativePath);\n\n // src/global.css is already a dedicated convention entry. Keeping one\n // Separate input entries avoid collisions if a shared layout also calls useCss().\n if (globalStyleInput && resolve(absolutePath) === resolve(globalStyleInput)) {\n continue;\n }\n\n // Only add if file exists\n if (!existsSync(absolutePath)) {\n console.warn(`[l5e] CSS file not found: ${absolutePath} (from ${cssPath})`);\n continue;\n }\n\n // Generate entry name from path (e.g., /src/views/home/home.css -> views-home-home)\n const entryName = relativePath\n .replace(/^src\\//, '')\n .replace(/\\.css$/, '')\n .replace(/\\//g, '-')\n .replace(/\\\\/g, '-');\n\n input[entryName] = absolutePath;\n }\n\n // JS/TS files\n for (const jsPath of allJsPaths) {\n const relativePath = jsPath.startsWith('/src/')\n ? jsPath.substring(1)\n : jsPath.startsWith('/')\n ? jsPath.substring(1)\n : jsPath;\n\n const absolutePath = resolve(rootDir, relativePath);\n\n // Only add if file exists\n if (!existsSync(absolutePath)) {\n console.warn(`[l5e] JS/TS file not found: ${absolutePath} (from ${jsPath})`);\n continue;\n }\n\n // Generate entry name from path\n const entryName = relativePath\n .replace(/^src\\//, '')\n .replace(/\\.(ts|tsx|js|jsx)$/, '')\n .replace(/\\//g, '-')\n .replace(/\\\\/g, '-');\n\n input[entryName] = absolutePath;\n }\n\n // Add island component files to the bundler input so they appear in the manifest.\n // server.ts looks up manifest at runtime to resolve per-page island URLs.\n for (const [key, src] of keyToSrc) {\n const absolutePath = resolve(rootDir, src);\n input[`island-${key}`] = absolutePath;\n }\n\n if (islandRegistry.size > 0) {\n console.log(`[l5e] Detected ${islandRegistry.size} island(s)`);\n }\n if (actionRegistry.size > 0) {\n console.log(`[l5e] Detected ${actionRegistry.size} action(s)`);\n }\n } catch (error) {\n // Silently fail if directory doesn't exist or other errors\n console.warn('[l5e] Failed to discover bundler input:', error);\n }\n\n return { input, islandRegistry, pathToKey, keyToSrc, actionRegistry };\n}\n\n/**\n * Inject __key prop into ClientIsland calls\n * Use anchor-based approach to avoid fragile regex with nested objects\n */\nfunction injectIslandKeys(\n code: string,\n fileId: string,\n rootDir: string,\n pathToKey: Map<string, string>,\n keyToSrc: Map<string, string>,\n): string {\n // After esbuild, code has form:\n // jsxFactory(ClientIsland, { from: \"./react/Counter\", props: { n: 5 } })\n // ^anchor ^find from here\n\n const result: string[] = [];\n let lastIndex = 0;\n\n // Find each position \"ClientIsland,\" (anchor)\n const anchorRegex = /ClientIsland\\s*,\\s*\\{/g;\n let anchorMatch;\n\n while ((anchorMatch = anchorRegex.exec(code)) !== null) {\n const searchStart = anchorMatch.index + anchorMatch[0].length;\n\n // Scan for from: \"...\" in window ~500 chars after anchor\n const window = code.substring(searchStart, searchStart + 500);\n const fromMatch = /from:\\s*\"([^\"]+)\"/.exec(window);\n\n if (!fromMatch) continue;\n\n const fromPath = fromMatch[1];\n\n // Resolve path (handle ~/ alias)\n let resolved: string;\n if (fromPath.startsWith('~/')) {\n resolved = '/src/' + fromPath.substring(2);\n } else if (fromPath.startsWith('/src/')) {\n resolved = fromPath;\n } else if (fromPath.startsWith('./') || fromPath.startsWith('../')) {\n const abs = resolve(fileId, '..', fromPath);\n resolved = '/' + relative(rootDir, abs).replace(/\\\\/g, '/');\n } else {\n resolved = fromPath;\n }\n\n const key = pathToKey.get(resolved);\n if (!key) continue;\n\n const src = keyToSrc.get(key);\n if (!src) continue;\n\n // Inject __key and __src right after from: \"...\"\n const insertPos = searchStart + fromMatch.index + fromMatch[0].length;\n result.push(code.substring(lastIndex, insertPos));\n result.push(`, __key: \"${key}\", __src: \"${src}\"`);\n lastIndex = insertPos;\n }\n\n result.push(code.substring(lastIndex));\n return result.join('');\n}\n\nexport function coreVite(options: CoreViteOptions = {}): Plugin {\n let rootDir: string = process.cwd();\n let clientBuild = false;\n const planner = options.chunking === false ? null : createChunkPlanner(options.chunking);\n let islandRegistry = new Map<string, string>();\n let pathToKey = new Map<string, string>();\n let keyToSrc = new Map<string, string>();\n let actionRegistry = new Map<string, { modulePath: string; actionName: string }>();\n\n return {\n name: 'l5e-jsx-classic',\n enforce: 'pre',\n\n configResolved(resolvedConfig) {\n // Store root directory for later use\n rootDir = resolvedConfig.root || process.cwd();\n clientBuild = resolvedConfig.command === 'build' && !resolvedConfig.build.ssr;\n },\n\n async buildStart() {\n if (clientBuild && planner) {\n await planner.resolve(rootDir, async (id, importer) => {\n const resolved = await this.resolve(id, importer);\n return resolved && !resolved.external ? resolved.id : null;\n });\n }\n },\n\n generateBundle(_options, bundle) {\n if (clientBuild && planner) {\n this.emitFile({\n type: 'asset',\n fileName: '.vite/l5e-chunks.json',\n source: JSON.stringify(planner.report(bundle), null, 2),\n });\n }\n },\n\n handleHotUpdate({ file, server }) {\n const relPath = relative(rootDir, file);\n\n // Re-scan action registry when an actions file changes\n if (/actions\\.(ts|tsx)$/.test(file)) {\n const discovered = discoverBundlerInput(rootDir);\n actionRegistry = discovered.actionRegistry;\n // Invalidate the virtual:l5e-actions module so server picks up new registry\n const mod = server.moduleGraph.getModuleById('\\0' + VIRTUAL_L5E_ACTIONS);\n if (mod) {\n server.moduleGraph.invalidateModule(mod);\n }\n console.log(\n `[l5e] Action file changed: ${relPath} — re-scanned ${actionRegistry.size} action(s)`,\n );\n }\n\n // Allow Vite's default HMR for CSS and client-side JS files\n if (file.endsWith('.css')) {\n console.log(`[l5e] CSS changed: ${relPath} - using Vite HMR`);\n return; // Let Vite handle CSS HMR\n }\n\n if (file.includes('client.ts')) {\n console.log(`[l5e] Client JS changed: ${relPath} - using Vite HMR`);\n return; // Let Vite handle client JS HMR\n }\n\n // Trigger full page reload for SSR-related file changes (components, loaders, routes)\n // This ensures that server-side rendered components update properly\n if (file.includes('/src/') || file.includes('\\\\src\\\\')) {\n console.log(`[l5e] SSR file changed: ${relPath} - triggering full reload`);\n server.ws.send({\n type: 'full-reload',\n path: '*',\n });\n return []; // Prevent Vite's default HMR behavior\n }\n },\n\n buildEnd(error) {\n if (!error && clientBuild && planner) {\n const modules = [...this.getModuleIds()]\n .map((id) => this.getModuleInfo(id))\n .filter((mod) => mod !== null);\n for (const warning of planner.analyze(modules)) this.warn(`[l5e chunking] ${warning}`);\n }\n // Cleanup temporary files after build\n const tempDir = join(rootDir, '.l5e-temp');\n if (existsSync(tempDir)) {\n try {\n rmSync(tempDir, { recursive: true, force: true });\n console.log('[l5e] Cleaned up temporary files');\n } catch (error) {\n console.warn('[l5e] Failed to cleanup temporary files:', error);\n }\n }\n },\n\n writeBundle(_options, _bundle) {\n // Emit action registry JSON for production server\n if (actionRegistry.size > 0) {\n const outDir = join(rootDir, 'dist', 'server');\n if (!existsSync(outDir)) {\n mkdirSync(outDir, { recursive: true });\n }\n const registryObj = Object.fromEntries(actionRegistry);\n writeFileSync(join(outDir, 'action-registry.json'), JSON.stringify(registryObj), 'utf-8');\n console.log(`[l5e] Wrote action-registry.json (${actionRegistry.size} actions)`);\n }\n },\n\n config(userConfig) {\n // Auto-discover bundler input from useCss and useClientJs\n const projectRoot = userConfig.root || process.cwd();\n const output = userConfig.build?.rolldownOptions?.output;\n const configureChunks = !userConfig.build?.ssr && planner !== null;\n if (\n configureChunks &&\n (Array.isArray(output) || output?.manualChunks || output?.codeSplitting !== undefined)\n ) {\n throw new Error(\n '[l5e chunking] Use coreVite({ chunking: { shared: [...] } }) or set chunking: false when configuring raw Rolldown chunk placement.',\n );\n }\n const discovered = discoverBundlerInput(projectRoot);\n\n // Store island registries for use in other hooks\n islandRegistry = discovered.islandRegistry;\n pathToKey = discovered.pathToKey;\n keyToSrc = discovered.keyToSrc;\n actionRegistry = discovered.actionRegistry;\n\n // Merge with existing rolldownOptions.input if any\n const existingInput = userConfig.build?.rolldownOptions?.input || {};\n const mergedInput =\n typeof existingInput === 'object' && !Array.isArray(existingInput)\n ? { ...discovered.input, ...existingInput }\n : discovered.input;\n if (options.chunking && options.chunking.mode === 'compact') {\n mergedInput['l5e-compact-renderer'] = VIRTUAL_L5E_COMPACT_RENDERER;\n }\n\n return {\n build: {\n ...(options.chunking && options.chunking.mode === 'compact'\n ? {\n modulePreload: {\n resolveDependencies: (\n _filename: string,\n dependencies: string[],\n context: { hostType: 'html' | 'js' },\n ) =>\n context.hostType === 'html'\n ? dependencies.filter(\n (dependency) => !/\\.[cm]?js(?:\\?|$)/.test(dependency),\n )\n : dependencies,\n },\n }\n : {}),\n rolldownOptions: {\n ...userConfig.build?.rolldownOptions,\n input: Object.keys(mergedInput).length > 0 ? mergedInput : undefined,\n // Preserve exports for island component entries — without this,\n // The bundler tree-shakes their exports since nothing imports them\n // (they're loaded at runtime via dynamic import from the island runtime).\n preserveEntrySignatures: configureChunks ? 'allow-extension' : 'exports-only',\n ...(configureChunks\n ? {\n output: {\n ...output,\n strictExecutionOrder: true,\n codeSplitting: { groups: planner!.groups() },\n entryFileNames: (chunk) => {\n const source = chunk.facadeModuleId?.replace(/\\\\/g, '/') || '';\n if (source.endsWith('/src/client.global.ts'))\n return 'assets/global-[hash].js';\n if (/\\/react\\//.test(source))\n return chunk.name.startsWith('island-')\n ? 'assets/[name]-[hash].js'\n : 'assets/island-[name]-[hash].js';\n return 'assets/bundle-[name]-[hash].js';\n },\n chunkFileNames: (chunk) =>\n chunk.name.startsWith('shared-')\n ? 'assets/[name]-[hash].js'\n : chunk.name === 'shared'\n ? 'assets/shared-[hash].js'\n : chunk.name === 'lazy-react-runtime'\n ? 'assets/lazy-react-runtime-[hash].js'\n : chunk.isDynamicEntry\n ? 'assets/bundle-[name]-[hash].js'\n : 'assets/shared-[name]-[hash].js',\n },\n }\n : {}),\n },\n },\n } satisfies UserConfig;\n },\n\n resolveId(id) {\n if (id === VIRTUAL_L5E_VIEWS) {\n return '\\0' + VIRTUAL_L5E_VIEWS;\n }\n if (id === VIRTUAL_L5E_ROUTE) {\n return '\\0' + VIRTUAL_L5E_ROUTE;\n }\n if (id === VIRTUAL_L5E_SSR_ENTRY) {\n return '\\0' + VIRTUAL_L5E_SSR_ENTRY;\n }\n if (id === VIRTUAL_L5E_GLOBAL_LOADER) {\n return '\\0' + VIRTUAL_L5E_GLOBAL_LOADER;\n }\n if (id === VIRTUAL_L5E_ISLAND_STRATEGIES) {\n return '\\0' + VIRTUAL_L5E_ISLAND_STRATEGIES;\n }\n if (id === VIRTUAL_L5E_ISLANDS) {\n return '\\0' + VIRTUAL_L5E_ISLANDS;\n }\n if (id === VIRTUAL_L5E_COMPACT_RENDERER) {\n return '\\0' + VIRTUAL_L5E_COMPACT_RENDERER;\n }\n if (id === VIRTUAL_L5E_ACTIONS) {\n return '\\0' + VIRTUAL_L5E_ACTIONS;\n }\n if (id === VIRTUAL_L5E_MIDDLEWARE) {\n return '\\0' + VIRTUAL_L5E_MIDDLEWARE;\n }\n return null;\n },\n\n async transform(code, id, transformOptions) {\n // Auto-inject island runtime into client.global.ts so it's always loaded globally\n if (id.replace(/\\\\/g, '/').endsWith('src/client.global.ts') && !transformOptions?.ssr) {\n return {\n code: `import '@withl5e/l5e/island/${options.chunking && options.chunking.mode === 'compact' ? 'compact-runtime' : 'runtime'}';\\n${code}`,\n map: null,\n };\n }\n\n // Client-side action transform: replace defineAction exports with fetch stubs\n // Supports actions anywhere under src/ (e.g., src/views/*, src/features/*, etc.)\n if (!transformOptions?.ssr) {\n const normalizedId = id.replace(/\\\\/g, '/');\n const actionMatch = normalizedId.match(/\\/src\\/(.+)\\/actions\\.(ts|tsx)$/);\n if (actionMatch) {\n const modulePath = actionMatch[1];\n\n // Parse exported action names\n const exportRegex = /export\\s+const\\s+(\\w+)\\s*=\\s*defineAction\\s*\\(/g;\n const actions: Array<{ name: string; method: string }> = [];\n let m;\n while ((m = exportRegex.exec(code)) !== null) {\n const name = m[1];\n // Find method for this action — scan from the defineAction( position\n const chunk = code.substring(m.index, m.index + 500);\n const methodMatch = chunk.match(/method:\\s*['\"](\\w+)['\"]/);\n const method = methodMatch ? methodMatch[1].toUpperCase() : 'GET';\n actions.push({ name, method });\n }\n\n if (actions.length > 0) {\n const stubs = actions.map(({ name, method }) => {\n const actionKey = `${name}_${shortHash(modulePath)}`;\n if (method === 'GET') {\n return `export async function ${name}(params) {\n const res = await fetch('/_l5e/action/${actionKey}?' + new URLSearchParams(params));\n if (!res.ok) throw Object.assign(new Error('HTTP ' + res.status), { status: res.status });\n return res;\n}`;\n }\n return `export async function ${name}(body) {\n const res = await fetch('/_l5e/action/${actionKey}', {\n method: '${method}',\n headers: { 'Content-Type': 'application/json' },\n body: JSON.stringify(body),\n });\n if (!res.ok) throw Object.assign(new Error('HTTP ' + res.status), { status: res.status });\n return res;\n}`;\n });\n\n return {\n code: stubs.join('\\n\\n'),\n map: null,\n };\n }\n }\n }\n\n // Skip node_modules\n if (id.includes('node_modules')) {\n return null;\n }\n\n // Skip files in /react/ directories\n if (id.includes('/react/') || id.includes('\\\\react\\\\')) {\n return null;\n }\n\n // Check if this is a JSX/TSX file that needs L5E JSX transformation\n const isJsxFile = /\\.(tsx|jsx)$/.test(id);\n\n if (isJsxFile) {\n try {\n const injected = `import { Fragment as __Fragment, jsxFactory } from \"@withl5e/l5e/jsx-runtime\"\\n${code}`;\n\n // Transform JSX using esbuild with L5E's JSX runtime (async)\n const result = await transform(injected, {\n loader: id.endsWith('.tsx') ? 'tsx' : 'jsx',\n jsx: 'transform',\n jsxFactory: 'jsxFactory',\n jsxFragment: '__Fragment',\n sourcemap: true,\n sourcefile: id,\n target: 'es2020',\n });\n\n let transformedCode = result.code;\n\n // Inject __key and __src for ALL ClientIsland calls\n if (transformedCode.includes('ClientIsland')) {\n transformedCode = injectIslandKeys(transformedCode, id, rootDir, pathToKey, keyToSrc);\n }\n\n return {\n code: transformedCode,\n map: result.map || null,\n };\n } catch (error) {\n // Log error but let Vite handle it\n console.error(`[l5e] Failed to transform JSX in ${id}:`, error);\n throw error;\n }\n }\n\n // Transform import.meta.env thành process.env ở server side\n // Server side có thể access tất cả env variables\n // Client side chỉ access được VITE_ env variables\n // Transform này chạy ở runtime khi module được load trong SSR context\n if (transformOptions?.ssr) {\n let transformedCode = code;\n let hasChanges = false;\n\n // Thay thế import.meta.env.VARIABLE_NAME thành process.env.VARIABLE_NAME\n // Match: import.meta.env.VITE_EVENT_CATEGORY_SLUG\n transformedCode = transformedCode.replace(\n /import\\.meta\\.env\\.([a-zA-Z_][a-zA-Z0-9_]*)/g,\n (match, varName) => {\n // Leave Vite's built-in env vars for Vite to handle.\n if (VITE_RESERVED_ENV.has(varName)) return match;\n hasChanges = true;\n return `process.env.${varName}`;\n },\n );\n\n // Thay thế import.meta.env['VARIABLE_NAME'] hoặc import.meta.env[\"VARIABLE_NAME\"]\n // thành process.env['VARIABLE_NAME'] hoặc process.env[\"VARIABLE_NAME\"]\n // Match: import.meta.env['VITE_EVENT_CATEGORY_SLUG'] hoặc import.meta.env[\"VITE_EVENT_CATEGORY_SLUG\"]\n transformedCode = transformedCode.replace(\n /import\\.meta\\.env\\[(['\"`])([^'\"`]+)\\1\\]/g,\n (match, quote, varName) => {\n // Leave Vite's built-in env vars for Vite to handle.\n if (VITE_RESERVED_ENV.has(varName)) return match;\n hasChanges = true;\n return `process.env[${quote}${varName}${quote}]`;\n },\n );\n\n if (hasChanges) {\n return {\n code: transformedCode,\n map: null, // Không cần source map cho env transform\n };\n }\n }\n return null;\n },\n\n load(id) {\n // Virtual module: l5e-views\n if (id === '\\0' + VIRTUAL_L5E_VIEWS) {\n return `\nexport const viewLoaders = import.meta.glob('/src/views/*/loader.{ts,tsx}');\nexport const viewComponents = import.meta.glob('/src/views/*/index.tsx');\n`;\n }\n\n // Virtual module: l5e-route\n if (id === '\\0' + VIRTUAL_L5E_ROUTE) {\n // Load /src/route.ts LAZILY (dynamic import inside the handler) rather\n // than via a static `export { default } from '/src/route.ts'`.\n //\n // A static re-export drags the user's route module — and everything it\n // imports — into entry-server's *static* SSR graph. Route files commonly\n // import the `@withl5e/l5e` barrel (for RedirectException, types, ...),\n // and that barrel re-exports `render` from entry-server. That closes a\n // static import cycle:\n // entry-server → virtual:l5e-route → /src/route.ts → @withl5e/l5e → entry-server\n // On the first dev request Vite can begin evaluating entry-server while\n // it is still suspended awaiting this very import, so `render()` runs\n // before `const __vite_ssr_import_N__ = await import('virtual:l5e-route')`\n // has been assigned — throwing \"Cannot access '__vite_ssr_import_N__'\n // before initialization\". A page reload \"fixes\" it only because the graph\n // is fully warm the second time.\n //\n // Importing lazily removes /src/route.ts from the static graph: entry-server\n // finishes initializing first, and the route module (with its barrel import\n // back to a now-complete entry-server) is pulled only on the first render()\n // call. No manual caching — Vite/ESM caches the evaluated module and later\n // imports still observe HMR invalidations of route.ts.\n return `export default function routeHandler(requestInfo) {\n return import('/src/route.ts').then((mod) => mod.default(requestInfo));\n}`;\n }\n\n // Virtual module: l5e-ssr-entry\n if (id === '\\0' + VIRTUAL_L5E_SSR_ENTRY) {\n return `export { render } from '@withl5e/l5e/entry-server';\nexport { viewActions } from 'virtual:l5e-actions';`;\n }\n\n // Virtual module: l5e-global-loader\n if (id === '\\0' + VIRTUAL_L5E_GLOBAL_LOADER) {\n return `export const globalLoader = import.meta.glob('/src/global-loader.{ts,tsx}', { eager: false });`;\n }\n\n // Virtual module: l5e-actions\n if (id === '\\0' + VIRTUAL_L5E_ACTIONS) {\n const registryObj = Object.fromEntries(actionRegistry);\n return `export const viewActions = import.meta.glob('/src/**/actions.{ts,tsx}');\nexport const actionRegistry = ${JSON.stringify(registryObj)};`;\n }\n\n // Virtual module: l5e-middleware\n if (id === '\\0' + VIRTUAL_L5E_MIDDLEWARE) {\n return `\nconst middlewareModules = import.meta.glob([\n '/src/middleware.{ts,tsx,js,jsx}',\n '/src/middleware/index.{ts,tsx,js,jsx}',\n]);\n\nconst middlewarePaths = [\n '/src/middleware.ts',\n '/src/middleware.tsx',\n '/src/middleware.js',\n '/src/middleware.jsx',\n '/src/middleware/index.ts',\n '/src/middleware/index.tsx',\n '/src/middleware/index.js',\n '/src/middleware/index.jsx',\n];\n\nexport async function loadMiddleware() {\n const middlewarePath = middlewarePaths.find((path) => middlewareModules[path]);\n if (!middlewarePath) return undefined;\n\n const mod = await middlewareModules[middlewarePath]();\n return mod.onRequest;\n}\n`;\n }\n\n // Virtual module: l5e-islands\n // Lazy glob of all React island components so the SSR entry can import a\n // component by its __src path and renderToString() it. Non-eager → only\n // islands actually present on a page (with ssr) get imported at runtime.\n if (id === '\\0' + VIRTUAL_L5E_ISLANDS) {\n return `export const islandModules = import.meta.glob('/src/**/react/*.{tsx,jsx}');`;\n }\n if (id === '\\0' + VIRTUAL_L5E_COMPACT_RENDERER) {\n return `export * as reactDomClient from 'react-dom/client'; export { createElement } from 'react';`;\n }\n\n // Virtual module: l5e-island-strategies\n if (id === '\\0' + VIRTUAL_L5E_ISLAND_STRATEGIES) {\n // Check if src/island-strategies.ts exists\n const strategiesFile = join(rootDir, 'src', 'island-strategies.ts');\n if (existsSync(strategiesFile)) {\n // Re-export user's file → Vite will build this file\n return `import '/src/island-strategies.ts';`;\n }\n // No file → empty module, no error\n return `/* no custom island strategies */`;\n }\n\n return null;\n },\n };\n}\n\nexport default coreVite;\n"],"mappings":";;;;;;;AA+BA,IAAM,KAAa,MAAe,EAAG,QAAQ,OAAO,GAAG,GACjD,KAAU,MAAkB,EAAW,QAAQ,CAAC,CAAC,OAAO,CAAK,CAAC,CAAC,OAAO,KAAK,CAAC,CAAC,MAAM,GAAG,CAAC;AAG7F,SAAS,EAAY,GAAgC;CACnD,IAAM,IAAS,EAAU,CAAE,CAAC,CAAC,MAAM,gBAAgB,CAAC,CAAC,GAAG,EAAE;CAC1D,IAAI,MAAW,EAAU,CAAE,GAAG;CAC9B,IAAM,IAAQ,EAAQ,MAAM,GAAG;CAC/B,OAAO,EAAM,EAAE,CAAC,WAAW,GAAG,IAAI,EAAM,MAAM,GAAG,CAAC,CAAC,CAAC,KAAK,GAAG,IAAI,EAAM;AACxE;AAKA,SAAgB,EAAmB,IAA2B,CAAC,GAAG;CAChE,IAAM,IAAQ,EAAQ,UAAU,CAAC,GAC3B,IAAoB,EAAQ;CAClC,IACE,KACA,CAAC,EAAkB,UAAU,UAC7B,CAAC,EAAkB,SAAS,QAE5B,MAAU,MAAM,yDAAyD;CAE3E,IAAI,EAAQ,SAAS,aAAa,EAAM,SAAS,GAC/C,MAAU,MAAM,iEAAiE;CAEnF,IAAM,oBAAQ,IAAI,IAAY;CAC9B,KAAK,IAAM,KAAQ,GAAO;EACxB,IAAI,CAAC,8BAA8B,KAAK,EAAK,IAAI,KAAK,EAAM,IAAI,EAAK,IAAI,GACvE,MAAU,MAAM,qDAAqD,EAAK,MAAM;EAElF,IAAI,CAAC,EAAK,UAAU,UAAU,CAAC,EAAK,SAAS,QAC3C,MAAU,MAAM,wBAAwB,EAAK,KAAK,4BAA4B;EAEhF,IAAI,EAAK,YAAY,KAAA,MAAc,CAAC,OAAO,SAAS,EAAK,OAAO,KAAK,EAAK,WAAW,IACnF,MAAU,MAAM,sCAAsC,EAAK,MAAM;EAEnE,IAAI,EAAQ,SAAS,aAAa,EAAK,YAAY,KAAA,GACjD,MAAU,MACR,sDAAsD,EAAK,KAAK,4CAClE;EAEF,EAAM,IAAI,EAAK,IAAI;CACrB;CACA,IAAI,IAAO,IACL,oBAAgB,IAAI,IAAmC,GACzD,oBAAwB,IAAI,IAAY,GACtC,oBAAY,IAAI,IAAsB,GACtC,oBAAW,IAAI,IAAY,GAC3B,KAAY,MACJ,EAAY,CAClB,IAAU,OAAO,EAAU,CAAE,CAAC,CAAC,MAAM,gBAAgB,CAAC,CAAC,GAAG,EAAE,MAC3D,EAAU,EAAK,SAAS,GAAM,CAAE,CAAC;CAG1C,OAAO;EACL,MAAM,QACJ,GACA,GACA;GAKA,AAJA,IAAO,GACP,EAAc,MAAM,GACpB,oBAAwB,IAAI,IAAI,GAChC,EAAU,MAAM,GAChB,EAAS,MAAM;GACf,KAAK,IAAM,KAAQ,GAAO;IACxB,IAAM,oBAAM,IAAI,IAAY;IAC5B,KAAK,IAAM,KAAa,EAAK,WAAW,CAAC,GAAG;KAC1C,IAAM,IAAK,MAAM,EAAU,GAAW,EAAK,KAAK,GAAM,YAAY,CAAC;KACnE,IAAI,CAAC,GAAI,MAAU,MAAM,iCAAiC,EAAU,MAAM,EAAK,MAAM;KACrF,EAAI,IAAI,CAAE;IACZ;IACA,EAAc,IAAI,GAAM,CAAG;GAC7B;GACA,IAAI,GACF,KAAK,IAAM,KAAa,EAAkB,WAAW,CAAC,GAAG;IACvD,IAAM,IAAK,MAAM,EAAU,GAAW,EAAK,KAAK,GAAM,YAAY,CAAC;IACnE,IAAI,CAAC,GAAI,MAAU,MAAM,iCAAiC,EAAU,kBAAkB;IACtF,EAAsB,IAAI,CAAE;GAC9B;EAEJ;EACA,QAAQ,GAAuB;GAC7B,EAAU,MAAM;GAChB,IAAM,IAAQ,IAAI,IAAI,EAAQ,KAAK,MAAQ,CAAC,EAAI,IAAI,CAAG,CAAC,CAAC;GACzD,IAAI,EAAQ,SAAS,WAAW;IAC9B,IAAM,oBAAe,IAAI,IAAkC;IAC3D,KAAK,IAAM,KAAS,EAAQ,QAAQ,MAAQ,EAAI,OAAO,GAAG;KACxD,IAAM,KAAS,GAAY,MAAkB;MAC3C,IAAM,IAAS,EAAa,IAAI,CAAE,qBAAK,IAAI,IAAqB,GAC1D,IAAW,EAAO,IAAI,EAAM,EAAE;MACpC,IAAI,MAAa,MAAS,MAAa,GAAM;MAE7C,AADA,EAAO,IAAI,EAAM,IAAI,CAAI,GACzB,EAAa,IAAI,GAAI,CAAM;MAC3B,IAAM,IAAS,EAAM,IAAI,CAAE;MACtB,MACL,EAAO,YAAY,SAAS,MAAe,EAAM,GAAY,CAAI,CAAC,GAClE,EAAO,uBAAuB,SAAS,MAAe,EAAM,GAAY,EAAI,CAAC;KAC/E;KACA,EAAM,EAAM,IAAI,EAAK;IACvB;IACA,IAAM,IAAc,EAAQ,MACzB,MAAQ,EAAI,WAAW,EAAU,EAAI,EAAE,CAAC,CAAC,SAAS,uBAAuB,CAC5E;IACA,IAAI,GACG;UAAA,IAAM,CAAC,GAAI,MAAW,GACzB,IACE,CAAC,gBAAgB,KAAK,EAAU,CAAE,CAAC,KACnC,EAAO,IAAI,EAAY,EAAE,MAAM,MAC/B,CAAC,GAAG,EAAO,KAAK,CAAC,CAAC,CAAC,MAAM,MAAU,MAAU,EAAY,EAAE,GAE3D,MAAU,MACR,4EAA4E,EAAS,CAAE,EAAE,kFAC3F;IAAA;GAIR;GACA,IAAM,IAAQ,EAAQ,QAAQ,MAAQ,EAAI,WAAW,EAAI,iBAAiB,SAAS,CAAC,GAC9E,oBAAY,IAAI,IAAyB;GAC/C,KAAK,IAAM,KAAS,GAAO;IACzB,IAAM,oBAAU,IAAI,IAAY,GAC1B,KAAS,MAAe;KAC5B,IAAI,EAAQ,IAAI,CAAE,GAAG;KACrB,EAAQ,IAAI,CAAE;KACd,IAAM,IAAM,EAAM,IAAI,CAAE;KACxB,IAAI,CAAC,GAAK;KACV,IAAM,IAAQ,EAAU,IAAI,CAAE,qBAAK,IAAI,IAAY;KAGnD,AAFA,EAAM,IAAI,EAAM,EAAE,GAClB,EAAU,IAAI,GAAI,CAAK,GACvB,EAAI,YAAY,QAAQ,CAAK;IAC/B;IACA,EAAM,EAAM,EAAE;GAChB;GACA,IAAM,KAAQ,MACA,EAAM,IAAI,CACf,CAAC,CAAC,UACL,EAAU,CAAE,CAAC,CAAC,SAAS,uBAAuB,IAAU,IACxD,EAAU,CAAE,CAAC,CAAC,SAAS,8BAA8B,KACrD,YAAY,KAAK,EAAU,CAAE,CAAC,KAAK,CAAC,EAAY,CAAE,IAAU,IACzD,IAJkB,GAMrB,oBAAU,IAAI,IAAsB;GAC1C,KAAK,IAAM,KAAO,GAAS;IACzB,IAAM,IAAQ,CAAC,GAAI,EAAU,IAAI,EAAI,EAAE,KAAK,CAAC,CAAE,CAAC,CAAC,KAAK,GAChD,IAAS,EAAM,IAAI,CAAQ,CAAC,CAAC,KAAK,GAClC,IAAU,EACb,QACE,MACC,EAAc,IAAI,CAAI,CAAC,EAAE,IAAI,EAAI,EAAE,KACnC,EAAK,UAAU,SAAS,EAAY,EAAI,EAAE,KAAK,EAAE,CACrD,CAAC,CACA,MAAM,GAAG,OAAO,EAAE,YAAY,MAAM,EAAE,YAAY,EAAE;IAEvD,AADA,EAAQ,SAAS,MAAS,EAAQ,IAAI,CAAI,CAAC,GACvC,EAAQ,SAAS,KACnB,EAAS,IACP,GAAG,EAAS,EAAI,EAAE,EAAE,WAAW,EAAQ,KAAK,MAAM,EAAE,IAAI,CAAC,CAAC,KAAK,IAAI,EAAE,UAAU,EAAQ,EAAE,CAAC,KAAK,EACjG;IACF,IAAI,IAAuB,MACvB,IAAS,8DACP,IAAM,EAAY,EAAI,EAAE,GACxB,IACJ,EAAsB,IAAI,EAAI,EAAE,KAChC,GAAmB,UAAU,SAAS,KAAO,EAAE,MAAM;IACvD,IACE,EAAQ,SAAS,aACjB,EAAU,EAAI,EAAE,CAAC,CAAC,SAAS,8BAA8B,GAGzD,AADA,IAAQ,sBACR,IAAS;SACJ,IACL,EAAQ,SAAS,aACjB,CAAC,EAAI,YACJ,MAAQ,WAAW,MAAQ,eAAe,MAAQ,gBACnD,EAAM,SAAS,KACf,EAAM,OAAO,MAAO,EAAK,CAAE,KAAK,CAAC,GAGjC,AADA,IAAQ,sBACR,IAAS;SACJ,IAAI,CAAC,EAAI,WAAW,EAAM,UAAU,EAAQ,QAAQ;KAIzD,IAAM,IAAO,KAAK,IAAI,GAAG,EAAM,IAAI,CAAI,CAAC,GAClC,IACJ,MAAS,IACL,QAAQ,EAAO,KAAK,UAAU,CAAM,CAAC,MACrC;MAAC;MAAU;MAAQ;KAAQ,CAAC,CAAC;KAEnC,AADA,IAAQ,EAAQ,SAAS,YAAY,WAAW,UAAU,EAAQ,EAAE,CAAC,KAAK,GAAG,KAC7E,IAAS,oBAAoB,EAAQ,EAAE,CAAC,KAAK,eAAe,EAAW;IACzE,OAAO,AAAI,EAAQ,SAAS,aAAa,CAAC,EAAI,WAAW,KACvD,IAAQ,sBACR,IAAS,oFAET,EAAQ,SAAS,aACjB,CAAC,EAAI,WACL,EAAM,MAAM,MAAO,EAAK,CAAE,MAAM,CAAC,KACjC,EAAM,MAAM,MAAO,EAAK,CAAE,IAAI,CAAC,KAE/B,IAAQ,gBACR,IAAS,8EACA,EAAQ,SAAS,aAAa,CAAC,EAAI,WAAW,EAAM,SAAS,MACtE,IAAQ,eAAe,EAAO,KAAK,UAAU,CAAM,CAAC,KACpD,IAAS;IAEX,EAAU,IAAI,EAAI,IAAI;KAAE;KAAO,MAAM,EAAQ,EAAE,EAAE;KAAM,WAAW;KAAQ;IAAO,CAAC;GACpF;GACA,KAAK,IAAM,KAAQ,GACjB,AAAK,EAAQ,IAAI,CAAI,KACnB,EAAS,IAAI,SAAS,EAAK,KAAK,0CAA0C;GAE9E,OAAO,CAAC,GAAG,CAAQ;EACrB;EACA,SAA+B;GAC7B,OAAO;IACL,GAAG,EAAM,KAAK,OAAU;KACtB,OAAO,MAAe;MACpB,IAAM,IAAW,EAAU,IAAI,CAAE;MACjC,OAAO,GAAU,SAAS,EAAK,OAAO,EAAS,QAAQ;KACzD;KACA,SAAS,EAAK;KACd,gCAAgC,EAAQ,SAAS;IACnD,EAAE;IACF;KACE,OAAO,MACL,EAAU,IAAI,CAAE,CAAC,EAAE,UAAU,uBAAuB,uBAAuB;KAC7E,gCAAgC;IAClC;IACA;KACE,OAAO,MAAe;MACpB,IAAM,IAAQ,EAAU,IAAI,CAAE,CAAC,EAAE;MACjC,OAAO,MAAU,uBAAuB,OAAO,KAAS;KAC1D;KACA,gCAAgC;IAClC;GACF;EACF;EACA,OAAO,GAAsB;GAC3B,OAAO;IACL,SAAS;IACT,MAAM,EAAQ,QAAQ;IACtB,UAAU,CAAC,GAAG,CAAQ;IACtB,QAAQ,OAAO,OAAO,CAAM,CAAC,CAAC,SAAS,MAAU;KAC/C,IAAI,EAAM,SAAS,SAAS,OAAO,CAAC;KACpC,IAAM,IAAS,EAAM,iBAAiB,EAAS,EAAM,cAAc,IAAI,MACjE,IACJ,MAAW,yBACP,WACA,KAAU,kBAAkB,KAAK,CAAM,IACrC,WACA,EAAM,WAAW,EAAM,iBACrB,SACA;KACV,OAAO,CACL;MACE,MAAM,EAAM;MACZ;MACA,iBAAiB,EAAQ,SAAS,aAAa,EAAM,SAAS;MAC9D,iBAAiB,EAAQ,SAAS,aAAa,EAAM,SAAS;MAC9D;MACA,OAAO,OAAO,WAAW,EAAM,IAAI;MACnC,SAAS,EAAM;MACf,gBAAgB,EAAM;MACtB,SAAS,OAAO,KAAK,EAAM,OAAO,CAAC,CAAC,KAAK,OAAQ;OAC/C,IAAI,EAAS,CAAE;OACf,GAAG,EAAU,IAAI,CAAE;MACrB,EAAE;KACJ,CACF;IACF,CAAC;GACH;EACF;CACF;AACF;;;ACjSA,IAAM,IAAoB,qBACpB,IAAoB,qBACpB,IAAwB,yBACxB,IAA4B,6BAC5B,IAAgC,iCAChC,IAAsB,uBACtB,IAA+B,gCAC/B,IAAsB,uBACtB,IAAyB,0BASzB,oBAAoB,IAAI,IAAI;CAAC;CAAQ;CAAY;CAAQ;CAAO;CAAO;AAAQ,CAAC;AAKtF,SAAS,EAAY,GAAa,IAAqB,CAAC,GAAa;CACnE,IAAM,IAAQ,EAAY,CAAG;CAE7B,KAAK,IAAM,KAAQ,GAAO;EACxB,IAAM,IAAWA,EAAK,GAAK,CAAI;EAG/B,IAFa,EAAS,CAEf,CAAC,CAAC,YAAY,GAAG;GAEtB,IAAI,MAAS,kBAAkB,MAAS,UAAU,MAAS,QACzD;GAEF,EAAY,GAAU,CAAQ;EAChC,OAAO,CAAI,EAAK,SAAS,MAAM,KAAK,EAAK,SAAS,KAAK,MACrD,EAAS,KAAK,CAAQ;CAE1B;CAEA,OAAO;AACT;AAKA,SAAS,EAAU,GAAqB;CACtC,IAAI,IAAO;CACX,KAAK,IAAI,IAAI,GAAG,IAAI,EAAI,QAAQ,KAE9B,AADA,KAAQ,KAAQ,KAAK,IAAO,EAAI,WAAW,CAAC,GAC5C,KAAc;CAEhB,OAAO,KAAK,IAAI,CAAI,CAAC,CAAC,SAAS,EAAE,CAAC,CAAC,MAAM,GAAG,CAAC;AAC/C;AAKA,SAAS,EAAoB,GAA0B;CACrD,IAAM,IAAW,EAAS,MAAM,GAAG,GAC/B,IAAW,EAAS,EAAS,SAAS;CAG1C,OADA,IAAW,EAAS,QAAQ,kBAAkB,EAAE,GACzC;AACT;AAKA,SAAS,EAAc,GAA8B;CAEnD,OAAO,GADM,EAAoB,CACpB,EAAE,GAAG,EAAU,CAAY;AAC1C;AAOA,SAAS,EAAqB,GAAsB,GAAgC;CAElF,IAAM,IAAU,EAAa,QAAQ,OAAO,EAAE,GACxC,IAAU,EAAQ,GAAS,CAAO;CAGxC,KAAK,IAAM,KAAO;EAAC;EAAQ;EAAO;EAAQ;CAAK,GAC7C,IAAI,EAAW,IAAU,CAAG,GAC1B,OAAO,IAAU;CAOrB,OAHI,EAAW,CAAO,IACb,IAEF;AACT;AAKA,SAAS,EACP,GACA,GAC8E;CAC9E,IAAM,IAAU,EAAa,GAAU,OAAO,GACxC,IAAwF,CAAC,GAIzF,IAAQ,8CAER,oBAAO,IAAI,IAAY,GACzB;CAEJ,QAAQ,IAAQ,EAAM,KAAK,CAAO,OAAO,OAAM;EAC7C,IAAM,IAAW,EAAM,IAGnB;EACJ,IAAI,EAAS,WAAW,IAAI,GAE1B,IAAe,UAAU,EAAS,UAAU,CAAC;OACxC,IAAI,EAAS,WAAW,OAAO,GACpC,IAAe;OACV,IAAI,EAAS,WAAW,IAAI,KAAK,EAAS,WAAW,KAAK,GAAG;GAClE,IAAM,IAAM,EAAQ,GAAU,MAAM,CAAQ;GAC5C,IAAe,MAAM,EAAS,GAAS,CAAG,CAAC,CAAC,QAAQ,OAAO,GAAG;EAChE,OACE,IAAe;EAIjB,IAAM,IAAM,EAAqB,GAAc,CAAO;EACtD,IAAI,CAAC,GAAK;GACR,QAAQ,KACN,qCAAqC,EAAa,SAAS,EAAS,MAAM,EAAS,EACrF;GACA;EACF;EAEA,IAAM,IAAM,EAAc,CAAY;EACtC,AAAK,EAAK,IAAI,CAAG,MACf,EAAK,IAAI,CAAG,GACZ,EAAQ,KAAK;GACX,WAAW,EAAoB,CAAY;GAC3C;GACA;GACA;EACF,CAAC;CAEL;CACA,OAAO;AACT;AAKA,SAAS,EAAqB,GAAkB,GAAkD;CAChG,IAAM,IAAU,EAAa,GAAU,OAAO,GACxC,IAAgB,CAAC,GACjB,IAAe,CAAC,GAIhB,IAAgB,6CAChB,IAAqB,kDAEvB;CAGJ,QAAQ,IAAQ,EAAc,KAAK,CAAO,OAAO,OAAM;EACrD,IAAM,IAAO,EAAM;EAEnB,IAAI,EAAK,WAAW,OAAO,GACzB,EAAI,KAAK,CAAI;OACR,IAAI,EAAK,WAAW,IAAI,KAAK,EAAK,WAAW,KAAK,GAAG;GAE1D,IAAM,IAAe,EAAQ,GAAU,MAAM,CAAI,GAC3C,IAAe,MAAM,EAAS,GAAS,CAAY,CAAC,CAAC,QAAQ,OAAO,GAAG;GAC7E,EAAI,KAAK,CAAY;EACvB,OACE,EAAI,KAAK,CAAI;CAEjB;CAGA,QAAQ,IAAQ,EAAmB,KAAK,CAAO,OAAO,OAAM;EAC1D,IAAM,IAAO,EAAM;EACnB,IAAI,EAAK,WAAW,OAAO,GACzB,EAAG,KAAK,CAAI;OACP,IAAI,EAAK,WAAW,IAAI,KAAK,EAAK,WAAW,KAAK,GAAG;GAC1D,IAAM,IAAe,EAAQ,GAAU,MAAM,CAAI,GAC3C,IAAe,MAAM,EAAS,GAAS,CAAY,CAAC,CAAC,QAAQ,OAAO,GAAG;GAC7E,EAAG,KAAK,CAAY;EACtB,OACE,EAAG,KAAK,CAAI;CAEhB;CAEA,OAAO;EAAE;EAAK;CAAG;AACnB;AAKA,SAAS,EAAqB,GAM5B;CACA,IAAM,IAAgC,CAAC,GACjC,IAASA,EAAK,GAAS,KAAK,GAG5B,oBAAiB,IAAI,IAAoB,GACzC,oBAAY,IAAI,IAAoB,GACpC,oBAAW,IAAI,IAAoB,GAGnC,oBAAiB,IAAI,IAAwD;CAEnF,IAAI;EAEF,IAAI,CAAC,EAAS,CAAM,CAAC,CAAC,YAAY,GAChC,OAAO;GAAE;GAAO;GAAgB;GAAW;GAAU;EAAe;EAItE,IAAM,IAAeA,EAAK,GAAS,OAAO,kBAAkB;EAC5D,AAAI,EAAW,CAAY,MACzB,EAAM,SAAY,GAClB,QAAQ,IAAI,wDAAwD;EAGtE,IAAM,IAAmB,EAAqB,CAAO;EACrD,AAAI,MACF,EAAM,kBAAkB,GACxB,QAAQ,IAAI,8DAA8D;EAI5E,IAAM,IAAU,EAAY,CAAM,GAG5B,oBAAc,IAAI,IAAY,GAC9B,oBAAa,IAAI,IAAY;EAEnC,KAAK,IAAM,KAAQ,GAAS;GAC1B,IAAM,EAAE,QAAK,UAAO,EAAqB,GAAM,CAAO;GAEtD,AADA,EAAI,SAAS,MAAS,EAAY,IAAI,CAAI,CAAC,GAC3C,EAAG,SAAS,MAAS,EAAW,IAAI,CAAI,CAAC;GAGzC,IAAM,IAAgB,EAAqB,GAAM,CAAO;GACxD,KAAK,IAAM,KAAS,GAGlB,AAFA,EAAe,IAAI,EAAM,KAAK,EAAM,YAAY,GAChD,EAAU,IAAI,EAAM,cAAc,EAAM,GAAG,GAC3C,EAAS,IAAI,EAAM,KAAK,EAAM,GAAG;GAInC,IAAM,IAAiB,EAAK,QAAQ,OAAO,GAAG;GAC9C,IAAI,uBAAuB,KAAK,CAAc,GAAG;IAC/C,IAAM,IAAU,EAAa,GAAM,OAAO,GACpC,IAAoB,mDACtB,GAIE,IADa,EAAS,GAAQ,EAAQ,CAAI,CAAC,CAAC,CAAC,QAAQ,OAAO,GACtC,KAAK;IAEjC,QAAQ,IAAc,EAAkB,KAAK,CAAO,OAAO,OAAM;KAC/D,IAAM,IAAa,EAAY,IACzB,IAAY,GAAG,EAAW,GAAG,EAAU,CAAU;KACvD,EAAe,IAAI,GAAW;MAAE;MAAY;KAAW,CAAC;IAC1D;GACF;EACF;EAIA,KAAK,IAAM,KAAW,GAAa;GAEjC,IAAM,IAAe,EAAQ,WAAW,OAAO,KAE3C,EAAQ,WAAW,GAAG,IADtB,EAAQ,UAAU,CAAC,IAGjB,GAEA,IAAe,EAAQ,GAAS,CAAY;GAIlD,IAAI,KAAoB,EAAQ,CAAY,MAAM,EAAQ,CAAgB,GACxE;GAIF,IAAI,CAAC,EAAW,CAAY,GAAG;IAC7B,QAAQ,KAAK,6BAA6B,EAAa,SAAS,EAAQ,EAAE;IAC1E;GACF;GAGA,IAAM,IAAY,EACf,QAAQ,UAAU,EAAE,CAAC,CACrB,QAAQ,UAAU,EAAE,CAAC,CACrB,QAAQ,OAAO,GAAG,CAAC,CACnB,QAAQ,OAAO,GAAG;GAErB,EAAM,KAAa;EACrB;EAGA,KAAK,IAAM,KAAU,GAAY;GAC/B,IAAM,IAAe,EAAO,WAAW,OAAO,KAE1C,EAAO,WAAW,GAAG,IADrB,EAAO,UAAU,CAAC,IAGhB,GAEA,IAAe,EAAQ,GAAS,CAAY;GAGlD,IAAI,CAAC,EAAW,CAAY,GAAG;IAC7B,QAAQ,KAAK,+BAA+B,EAAa,SAAS,EAAO,EAAE;IAC3E;GACF;GAGA,IAAM,IAAY,EACf,QAAQ,UAAU,EAAE,CAAC,CACrB,QAAQ,sBAAsB,EAAE,CAAC,CACjC,QAAQ,OAAO,GAAG,CAAC,CACnB,QAAQ,OAAO,GAAG;GAErB,EAAM,KAAa;EACrB;EAIA,KAAK,IAAM,CAAC,GAAK,MAAQ,GAAU;GACjC,IAAM,IAAe,EAAQ,GAAS,CAAG;GACzC,EAAM,UAAU,OAAS;EAC3B;EAKA,AAHI,EAAe,OAAO,KACxB,QAAQ,IAAI,kBAAkB,EAAe,KAAK,WAAW,GAE3D,EAAe,OAAO,KACxB,QAAQ,IAAI,kBAAkB,EAAe,KAAK,WAAW;CAEjE,SAAS,GAAO;EAEd,QAAQ,KAAK,2CAA2C,CAAK;CAC/D;CAEA,OAAO;EAAE;EAAO;EAAgB;EAAW;EAAU;CAAe;AACtE;AAMA,SAAS,EACP,GACA,GACA,GACA,GACA,GACQ;CAKR,IAAM,IAAmB,CAAC,GACtB,IAAY,GAGV,IAAc,0BAChB;CAEJ,QAAQ,IAAc,EAAY,KAAK,CAAI,OAAO,OAAM;EACtD,IAAM,IAAc,EAAY,QAAQ,EAAY,EAAE,CAAC,QAGjD,IAAS,EAAK,UAAU,GAAa,IAAc,GAAG,GACtD,IAAY,oBAAoB,KAAK,CAAM;EAEjD,IAAI,CAAC,GAAW;EAEhB,IAAM,IAAW,EAAU,IAGvB;EACJ,IAAI,EAAS,WAAW,IAAI,GAC1B,IAAW,UAAU,EAAS,UAAU,CAAC;OACpC,IAAI,EAAS,WAAW,OAAO,GACpC,IAAW;OACN,IAAI,EAAS,WAAW,IAAI,KAAK,EAAS,WAAW,KAAK,GAAG;GAClE,IAAM,IAAM,EAAQ,GAAQ,MAAM,CAAQ;GAC1C,IAAW,MAAM,EAAS,GAAS,CAAG,CAAC,CAAC,QAAQ,OAAO,GAAG;EAC5D,OACE,IAAW;EAGb,IAAM,IAAM,EAAU,IAAI,CAAQ;EAClC,IAAI,CAAC,GAAK;EAEV,IAAM,IAAM,EAAS,IAAI,CAAG;EAC5B,IAAI,CAAC,GAAK;EAGV,IAAM,IAAY,IAAc,EAAU,QAAQ,EAAU,EAAE,CAAC;EAG/D,AAFA,EAAO,KAAK,EAAK,UAAU,GAAW,CAAS,CAAC,GAChD,EAAO,KAAK,aAAa,EAAI,aAAa,EAAI,EAAE,GAChD,IAAY;CACd;CAGA,OADA,EAAO,KAAK,EAAK,UAAU,CAAS,CAAC,GAC9B,EAAO,KAAK,EAAE;AACvB;AAEA,SAAgB,EAAS,IAA2B,CAAC,GAAW;CAC9D,IAAI,IAAkB,QAAQ,IAAI,GAC9B,IAAc,IACZ,IAAU,EAAQ,aAAa,KAAQ,OAAO,EAAmB,EAAQ,QAAQ,GAEnF,oBAAY,IAAI,IAAoB,GACpC,oBAAW,IAAI,IAAoB,GACnC,oBAAiB,IAAI,IAAwD;CAEjF,OAAO;EACL,MAAM;EACN,SAAS;EAET,eAAe,GAAgB;GAG7B,AADA,IAAU,EAAe,QAAQ,QAAQ,IAAI,GAC7C,IAAc,EAAe,YAAY,WAAW,CAAC,EAAe,MAAM;EAC5E;EAEA,MAAM,aAAa;GACjB,AAAI,KAAe,KACjB,MAAM,EAAQ,QAAQ,GAAS,OAAO,GAAI,MAAa;IACrD,IAAM,IAAW,MAAM,KAAK,QAAQ,GAAI,CAAQ;IAChD,OAAO,KAAY,CAAC,EAAS,WAAW,EAAS,KAAK;GACxD,CAAC;EAEL;EAEA,eAAe,GAAU,GAAQ;GAC/B,AAAI,KAAe,KACjB,KAAK,SAAS;IACZ,MAAM;IACN,UAAU;IACV,QAAQ,KAAK,UAAU,EAAQ,OAAO,CAAM,GAAG,MAAM,CAAC;GACxD,CAAC;EAEL;EAEA,gBAAgB,EAAE,SAAM,aAAU;GAChC,IAAM,IAAU,EAAS,GAAS,CAAI;GAGtC,IAAI,qBAAqB,KAAK,CAAI,GAAG;IAEnC,IADmB,EAAqB,CACd,CAAC,CAAC;IAE5B,IAAM,IAAM,EAAO,YAAY,cAAc,uBAA0B;IAIvE,AAHI,KACF,EAAO,YAAY,iBAAiB,CAAG,GAEzC,QAAQ,IACN,8BAA8B,EAAQ,kBAAkB,EAAe,KAAK,WAC9E;GACF;GAGA,IAAI,EAAK,SAAS,MAAM,GAAG;IACzB,QAAQ,IAAI,sBAAsB,EAAQ,kBAAkB;IAC5D;GACF;GAEA,IAAI,EAAK,SAAS,WAAW,GAAG;IAC9B,QAAQ,IAAI,4BAA4B,EAAQ,kBAAkB;IAClE;GACF;GAIA,IAAI,EAAK,SAAS,OAAO,KAAK,EAAK,SAAS,SAAS,GAMnD,OALA,QAAQ,IAAI,2BAA2B,EAAQ,0BAA0B,GACzE,EAAO,GAAG,KAAK;IACb,MAAM;IACN,MAAM;GACR,CAAC,GACM,CAAC;EAEZ;EAEA,SAAS,GAAO;GACd,IAAI,CAAC,KAAS,KAAe,GAAS;IACpC,IAAM,IAAU,CAAC,GAAG,KAAK,aAAa,CAAC,CAAC,CACrC,KAAK,MAAO,KAAK,cAAc,CAAE,CAAC,CAAC,CACnC,QAAQ,MAAQ,MAAQ,IAAI;IAC/B,KAAK,IAAM,KAAW,EAAQ,QAAQ,CAAO,GAAG,KAAK,KAAK,kBAAkB,GAAS;GACvF;GAEA,IAAM,IAAUA,EAAK,GAAS,WAAW;GACzC,IAAI,EAAW,CAAO,GACpB,IAAI;IAEF,AADA,EAAO,GAAS;KAAE,WAAW;KAAM,OAAO;IAAK,CAAC,GAChD,QAAQ,IAAI,kCAAkC;GAChD,SAAS,GAAO;IACd,QAAQ,KAAK,4CAA4C,CAAK;GAChE;EAEJ;EAEA,YAAY,GAAU,GAAS;GAE7B,IAAI,EAAe,OAAO,GAAG;IAC3B,IAAM,IAASA,EAAK,GAAS,QAAQ,QAAQ;IAC7C,AAAK,EAAW,CAAM,KACpB,EAAU,GAAQ,EAAE,WAAW,GAAK,CAAC;IAEvC,IAAM,IAAc,OAAO,YAAY,CAAc;IAErD,AADA,EAAcA,EAAK,GAAQ,sBAAsB,GAAG,KAAK,UAAU,CAAW,GAAG,OAAO,GACxF,QAAQ,IAAI,qCAAqC,EAAe,KAAK,UAAU;GACjF;EACF;EAEA,OAAO,GAAY;GAEjB,IAAM,IAAc,EAAW,QAAQ,QAAQ,IAAI,GAC7C,IAAS,EAAW,OAAO,iBAAiB,QAC5C,IAAkB,CAAC,EAAW,OAAO,OAAO,MAAY;GAC9D,IACE,MACC,MAAM,QAAQ,CAAM,KAAK,GAAQ,gBAAgB,GAAQ,kBAAkB,KAAA,IAE5E,MAAU,MACR,oIACF;GAEF,IAAM,IAAa,EAAqB,CAAW;GAMnD,AAHA,EAA4B,gBAC5B,IAAY,EAAW,WACvB,IAAW,EAAW,UACtB,IAAiB,EAAW;GAG5B,IAAM,IAAgB,EAAW,OAAO,iBAAiB,SAAS,CAAC,GAC7D,IACJ,OAAO,KAAkB,YAAY,CAAC,MAAM,QAAQ,CAAa,IAC7D;IAAE,GAAG,EAAW;IAAO,GAAG;GAAc,IACxC,EAAW;GAKjB,OAJI,EAAQ,YAAY,EAAQ,SAAS,SAAS,cAChD,EAAY,0BAA0B,IAGjC,EACL,OAAO;IACL,GAAI,EAAQ,YAAY,EAAQ,SAAS,SAAS,YAC9C,EACE,eAAe,EACb,sBACE,GACA,GACA,MAEA,EAAQ,aAAa,SACjB,EAAa,QACV,MAAe,CAAC,oBAAoB,KAAK,CAAU,CACtD,IACA,EACR,EACF,IACA,CAAC;IACL,iBAAiB;KACf,GAAG,EAAW,OAAO;KACrB,OAAO,OAAO,KAAK,CAAW,CAAC,CAAC,SAAS,IAAI,IAAc,KAAA;KAI3D,yBAAyB,IAAkB,oBAAoB;KAC/D,GAAI,IACA,EACE,QAAQ;MACN,GAAG;MACH,sBAAsB;MACtB,eAAe,EAAE,QAAQ,EAAS,OAAO,EAAE;MAC3C,iBAAiB,MAAU;OACzB,IAAM,IAAS,EAAM,gBAAgB,QAAQ,OAAO,GAAG,KAAK;OAO5D,OANI,EAAO,SAAS,uBAAuB,IAClC,4BACL,YAAY,KAAK,CAAM,IAClB,EAAM,KAAK,WAAW,SAAS,IAClC,4BACA,mCACC;MACT;MACA,iBAAiB,MACf,EAAM,KAAK,WAAW,SAAS,IAC3B,4BACA,EAAM,SAAS,WACb,4BACA,EAAM,SAAS,uBACb,wCACJ,EAAM,iBACJ,mCACA;KACV,EACF,IACA,CAAC;IACP;GACF,EACF;EACF;EAEA,UAAU,GAAI;GA4BZ,OA3BI,MAAO,IACF,wBAEL,MAAO,IACF,wBAEL,MAAO,IACF,4BAEL,MAAO,IACF,gCAEL,MAAO,IACF,oCAEL,MAAO,IACF,0BAEL,MAAO,IACF,mCAEL,MAAO,IACF,0BAEL,MAAO,IACF,6BAEF;EACT;EAEA,MAAM,UAAU,GAAM,GAAI,GAAkB;GAE1C,IAAI,EAAG,QAAQ,OAAO,GAAG,CAAC,CAAC,SAAS,sBAAsB,KAAK,CAAC,GAAkB,KAChF,OAAO;IACL,MAAM,+BAA+B,EAAQ,YAAY,EAAQ,SAAS,SAAS,YAAY,oBAAoB,UAAU,MAAM;IACnI,KAAK;GACP;GAKF,IAAI,CAAC,GAAkB,KAAK;IAE1B,IAAM,IADe,EAAG,QAAQ,OAAO,GACR,CAAC,CAAC,MAAM,iCAAiC;IACxE,IAAI,GAAa;KACf,IAAM,IAAa,EAAY,IAGzB,IAAc,mDACd,IAAmD,CAAC,GACtD;KACJ,QAAQ,IAAI,EAAY,KAAK,CAAI,OAAO,OAAM;MAC5C,IAAM,IAAO,EAAE,IAGT,IADQ,EAAK,UAAU,EAAE,OAAO,EAAE,QAAQ,GACxB,CAAC,CAAC,MAAM,yBAAyB,GACnD,IAAS,IAAc,EAAY,EAAE,CAAC,YAAY,IAAI;MAC5D,EAAQ,KAAK;OAAE;OAAM;MAAO,CAAC;KAC/B;KAEA,IAAI,EAAQ,SAAS,GAqBnB,OAAO;MACL,MArBY,EAAQ,KAAK,EAAE,SAAM,gBAAa;OAC9C,IAAM,IAAY,GAAG,EAAK,GAAG,EAAU,CAAU;OAQjD,OAPI,MAAW,QACN,yBAAyB,EAAK;0CACX,EAAU;;;KAK/B,yBAAyB,EAAK;0CACT,EAAU;eACrC,EAAO;;;;;;;MAOV,CAGY,CAAC,CAAC,KAAK,MAAM;MACvB,KAAK;KACP;IAEJ;GACF;GAQA,IALI,EAAG,SAAS,cAAc,KAK1B,EAAG,SAAS,SAAS,KAAK,EAAG,SAAS,WAAW,GACnD,OAAO;GAMT,IAFkB,eAAe,KAAK,CAE1B,GACV,IAAI;IACF,IAAM,IAAW,kFAAkF,KAG7F,IAAS,MAAM,EAAU,GAAU;KACvC,QAAQ,EAAG,SAAS,MAAM,IAAI,QAAQ;KACtC,KAAK;KACL,YAAY;KACZ,aAAa;KACb,WAAW;KACX,YAAY;KACZ,QAAQ;IACV,CAAC,GAEG,IAAkB,EAAO;IAO7B,OAJI,EAAgB,SAAS,cAAc,MACzC,IAAkB,EAAiB,GAAiB,GAAI,GAAS,GAAW,CAAQ,IAG/E;KACL,MAAM;KACN,KAAK,EAAO,OAAO;IACrB;GACF,SAAS,GAAO;IAGd,MADA,QAAQ,MAAM,oCAAoC,EAAG,IAAI,CAAK,GACxD;GACR;GAOF,IAAI,GAAkB,KAAK;IACzB,IAAI,IAAkB,GAClB,IAAa;IA2BjB,IAvBA,IAAkB,EAAgB,QAChC,iDACC,GAAO,MAEF,EAAkB,IAAI,CAAO,IAAU,KAC3C,IAAa,IACN,eAAe,IAE1B,GAKA,IAAkB,EAAgB,QAChC,6CACC,GAAO,GAAO,MAET,EAAkB,IAAI,CAAO,IAAU,KAC3C,IAAa,IACN,eAAe,IAAQ,IAAU,EAAM,GAElD,GAEI,GACF,OAAO;KACL,MAAM;KACN,KAAK;IACP;GAEJ;GACA,OAAO;EACT;EAEA,KAAK,GAAI;GAEP,IAAI,MAAO,uBACT,OAAO;GAOT,IAAI,MAAO,uBAsBT,OAAO;GAMT,IAAI,MAAO,2BACT,OAAO;GAKT,IAAI,MAAO,+BACT,OAAO;GAIT,IAAI,MAAO,yBAA4B;IACrC,IAAM,IAAc,OAAO,YAAY,CAAc;IACrD,OAAO;gCACiB,KAAK,UAAU,CAAW,EAAE;GACtD;GAGA,IAAI,MAAO,4BACT,OAAO;GA+BT,IAAI,MAAO,yBACT,OAAO;GAET,IAAI,MAAO,kCACT,OAAO;GAIT,IAAI,MAAO,mCAAsC;IAE/C,IAAM,IAAiBA,EAAK,GAAS,OAAO,sBAAsB;IAMlE,OALI,EAAW,CAAc,IAEpB,wCAGF;GACT;GAEA,OAAO;EACT;CACF;AACF"}