vite-plugin-htjs-pages 1.3.4 → 1.3.5
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/index.js +15 -113
- package/dist/index.js.map +1 -1
- package/package.json +1 -1
- package/src/plugin.ts +9 -24
package/dist/index.js
CHANGED
|
@@ -1,5 +1,4 @@
|
|
|
1
1
|
// src/plugin.ts
|
|
2
|
-
import path4 from "path";
|
|
3
2
|
import { pathToFileURL } from "url";
|
|
4
3
|
import pLimit from "p-limit";
|
|
5
4
|
|
|
@@ -334,96 +333,6 @@ async function buildPageIndex(args) {
|
|
|
334
333
|
return pages;
|
|
335
334
|
}
|
|
336
335
|
|
|
337
|
-
// src/render-bundle.ts
|
|
338
|
-
import path3 from "path";
|
|
339
|
-
import fs from "fs/promises";
|
|
340
|
-
import { createHash } from "crypto";
|
|
341
|
-
|
|
342
|
-
// src/manifest.ts
|
|
343
|
-
function js(value) {
|
|
344
|
-
return JSON.stringify(value);
|
|
345
|
-
}
|
|
346
|
-
function createManifestModule(entries) {
|
|
347
|
-
const imports = entries.map((page, i) => `import * as page${i} from ${js(page.entryPath)};`).join("\n");
|
|
348
|
-
const records = entries.map(
|
|
349
|
-
(page, i) => `{
|
|
350
|
-
page: ${js(page)},
|
|
351
|
-
mod: page${i}
|
|
352
|
-
}`
|
|
353
|
-
).join(",\n");
|
|
354
|
-
return `${imports}
|
|
355
|
-
|
|
356
|
-
export const manifest = [
|
|
357
|
-
${records}
|
|
358
|
-
];
|
|
359
|
-
`;
|
|
360
|
-
}
|
|
361
|
-
|
|
362
|
-
// src/render-bundle.ts
|
|
363
|
-
async function createRenderBundleHash(entries, manifestSource) {
|
|
364
|
-
const hash = createHash("sha256");
|
|
365
|
-
hash.update(manifestSource);
|
|
366
|
-
for (const entry of entries) {
|
|
367
|
-
hash.update(entry.entryPath);
|
|
368
|
-
const source = await fs.readFile(entry.entryPath, "utf8");
|
|
369
|
-
hash.update(source);
|
|
370
|
-
}
|
|
371
|
-
return hash.digest("hex").slice(0, 12);
|
|
372
|
-
}
|
|
373
|
-
async function buildRenderBundle(args) {
|
|
374
|
-
const { entries, cacheDir, ssrPlugins = [] } = args;
|
|
375
|
-
const [{ rollup }, { nodeResolve }] = await Promise.all([
|
|
376
|
-
import("rollup"),
|
|
377
|
-
import("@rollup/plugin-node-resolve")
|
|
378
|
-
]);
|
|
379
|
-
const manifestSource = createManifestModule(entries);
|
|
380
|
-
const hash = await createRenderBundleHash(entries, manifestSource);
|
|
381
|
-
const bundlePath = path3.join(cacheDir, `render-${hash}.mjs`);
|
|
382
|
-
await fs.mkdir(cacheDir, { recursive: true });
|
|
383
|
-
try {
|
|
384
|
-
await fs.access(bundlePath);
|
|
385
|
-
return bundlePath;
|
|
386
|
-
} catch {
|
|
387
|
-
}
|
|
388
|
-
const bundle = await rollup({
|
|
389
|
-
input: VIRTUAL_MANIFEST_ID,
|
|
390
|
-
plugins: [
|
|
391
|
-
{
|
|
392
|
-
name: `${PLUGIN_NAME}:virtual-manifest`,
|
|
393
|
-
resolveId(id) {
|
|
394
|
-
return id === VIRTUAL_MANIFEST_ID ? id : null;
|
|
395
|
-
},
|
|
396
|
-
load(id) {
|
|
397
|
-
return id === VIRTUAL_MANIFEST_ID ? manifestSource : null;
|
|
398
|
-
}
|
|
399
|
-
},
|
|
400
|
-
nodeResolve({
|
|
401
|
-
preferBuiltins: true,
|
|
402
|
-
exportConditions: ["node"]
|
|
403
|
-
}),
|
|
404
|
-
...ssrPlugins
|
|
405
|
-
],
|
|
406
|
-
treeshake: true
|
|
407
|
-
});
|
|
408
|
-
try {
|
|
409
|
-
const { output } = await bundle.generate({
|
|
410
|
-
format: "esm",
|
|
411
|
-
exports: "named",
|
|
412
|
-
inlineDynamicImports: true
|
|
413
|
-
});
|
|
414
|
-
const chunk = output.find((item) => item.type === "chunk");
|
|
415
|
-
if (!chunk || chunk.type !== "chunk") {
|
|
416
|
-
throw new Error(
|
|
417
|
-
`[${PLUGIN_NAME}] Failed to generate HT pages render bundle.`
|
|
418
|
-
);
|
|
419
|
-
}
|
|
420
|
-
await fs.writeFile(bundlePath, chunk.code, "utf8");
|
|
421
|
-
return bundlePath;
|
|
422
|
-
} finally {
|
|
423
|
-
await bundle.close();
|
|
424
|
-
}
|
|
425
|
-
}
|
|
426
|
-
|
|
427
336
|
// src/plugin.ts
|
|
428
337
|
function chunkArray(items, size) {
|
|
429
338
|
const out = [];
|
|
@@ -432,9 +341,9 @@ function chunkArray(items, size) {
|
|
|
432
341
|
}
|
|
433
342
|
return out;
|
|
434
343
|
}
|
|
435
|
-
async function
|
|
436
|
-
const mod = await import(pathToFileURL(
|
|
437
|
-
return mod
|
|
344
|
+
async function importPageModule(entryPath) {
|
|
345
|
+
const mod = await import(pathToFileURL(entryPath).href + `?t=${Date.now()}`);
|
|
346
|
+
return mod;
|
|
438
347
|
}
|
|
439
348
|
function htPages(options = {}) {
|
|
440
349
|
let root = process.cwd();
|
|
@@ -474,24 +383,17 @@ function htPages(options = {}) {
|
|
|
474
383
|
}
|
|
475
384
|
async function buildPagesPipeline() {
|
|
476
385
|
const entries = await discoverEntryPages(root, options);
|
|
477
|
-
const cacheDir = path4.join(root, CACHE_DIR_NAME);
|
|
478
|
-
const bundlePath = await buildRenderBundle({
|
|
479
|
-
entries,
|
|
480
|
-
cacheDir,
|
|
481
|
-
ssrPlugins: options.ssrPlugins
|
|
482
|
-
});
|
|
483
|
-
logDebug(options.debug, "render bundle", bundlePath);
|
|
484
|
-
const manifest = await importManifest(bundlePath);
|
|
485
386
|
const modulesByEntry = /* @__PURE__ */ new Map();
|
|
486
|
-
for (const
|
|
487
|
-
|
|
387
|
+
for (const entry of entries) {
|
|
388
|
+
const mod = await importPageModule(entry.entryPath);
|
|
389
|
+
modulesByEntry.set(entry.entryPath, mod);
|
|
488
390
|
}
|
|
489
391
|
const pages = await buildPageIndex({
|
|
490
392
|
entries,
|
|
491
393
|
modulesByEntry,
|
|
492
394
|
cleanUrls
|
|
493
395
|
});
|
|
494
|
-
return { entries,
|
|
396
|
+
return { entries, modulesByEntry, pages };
|
|
495
397
|
}
|
|
496
398
|
return {
|
|
497
399
|
name: PLUGIN_NAME,
|
|
@@ -632,9 +534,9 @@ ${rssItems}
|
|
|
632
534
|
}
|
|
633
535
|
|
|
634
536
|
// src/fetch-cache.ts
|
|
635
|
-
import
|
|
636
|
-
import
|
|
637
|
-
import { createHash
|
|
537
|
+
import fs from "fs/promises";
|
|
538
|
+
import path3 from "path";
|
|
539
|
+
import { createHash } from "crypto";
|
|
638
540
|
function createDefaultCacheKey(input, init) {
|
|
639
541
|
const raw = JSON.stringify({
|
|
640
542
|
url: String(input),
|
|
@@ -642,10 +544,10 @@ function createDefaultCacheKey(input, init) {
|
|
|
642
544
|
headers: init?.headers ?? {},
|
|
643
545
|
body: init?.body ?? null
|
|
644
546
|
});
|
|
645
|
-
return
|
|
547
|
+
return createHash("sha256").update(raw).digest("hex");
|
|
646
548
|
}
|
|
647
549
|
function getCacheFilePath(cacheKey) {
|
|
648
|
-
return
|
|
550
|
+
return path3.join(process.cwd(), CACHE_DIR_NAME, "fetch", `${cacheKey}.json`);
|
|
649
551
|
}
|
|
650
552
|
async function fetchAndCache(input, init, options = {}) {
|
|
651
553
|
const maxAge = options.maxAge ?? 60 * 60;
|
|
@@ -655,10 +557,10 @@ async function fetchAndCache(input, init, options = {}) {
|
|
|
655
557
|
}
|
|
656
558
|
const cacheKey = options.cacheKey ?? createDefaultCacheKey(input, init);
|
|
657
559
|
const filePath = getCacheFilePath(cacheKey);
|
|
658
|
-
await
|
|
560
|
+
await fs.mkdir(path3.dirname(filePath), { recursive: true });
|
|
659
561
|
if (!options.forceRefresh) {
|
|
660
562
|
try {
|
|
661
|
-
const raw = await
|
|
563
|
+
const raw = await fs.readFile(filePath, "utf8");
|
|
662
564
|
const cached = JSON.parse(raw);
|
|
663
565
|
const ageSeconds = (Date.now() - cached.timestamp) / 1e3;
|
|
664
566
|
if (ageSeconds <= maxAge) {
|
|
@@ -680,7 +582,7 @@ async function fetchAndCache(input, init, options = {}) {
|
|
|
680
582
|
headers: [...res.headers.entries()],
|
|
681
583
|
body
|
|
682
584
|
};
|
|
683
|
-
await
|
|
585
|
+
await fs.writeFile(filePath, JSON.stringify(record), "utf8");
|
|
684
586
|
return new Response(body, {
|
|
685
587
|
status: res.status,
|
|
686
588
|
statusText: res.statusText,
|
package/dist/index.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../src/plugin.ts","../src/discover.ts","../src/path-utils.ts","../src/route-utils.ts","../src/constants.ts","../src/errors.ts","../src/render-runtime.ts","../src/dev-server.ts","../src/page-index.ts","../src/render-bundle.ts","../src/manifest.ts","../src/fetch-cache.ts"],"sourcesContent":["import path from 'node:path';\nimport { pathToFileURL } from 'node:url';\nimport pLimit from 'p-limit';\nimport type { Plugin, ViteDevServer } from 'vite';\n\nimport { discoverEntryPages } from './discover';\nimport { installDevServer } from './dev-server';\nimport { buildPageIndex } from './page-index';\nimport { buildRenderBundle } from './render-bundle';\nimport { renderPage } from './render-runtime';\n\nimport type { HtPageInfo, HtPageModule, HtPagesPluginOptions } from './types';\nimport {\n PLUGIN_NAME,\n VIRTUAL_BUILD_ENTRY_ID,\n CACHE_DIR_NAME,\n} from './constants';\n\nfunction chunkArray<T>(items: T[], size: number): T[][] {\n const out: T[][] = [];\n for (let i = 0; i < items.length; i += size) {\n out.push(items.slice(i, i + size));\n }\n return out;\n}\n\nasync function importManifest(\n bundlePath: string,\n): Promise<Array<{ page: HtPageInfo; mod: HtPageModule }>> {\n const mod = await import(pathToFileURL(bundlePath).href + `?t=${Date.now()}`);\n return mod.manifest as Array<{ page: HtPageInfo; mod: HtPageModule }>;\n}\n\nexport function htPages(options: HtPagesPluginOptions = {}): Plugin {\n let root = process.cwd();\n let server: ViteDevServer | null = null;\n let devPages: HtPageInfo[] = [];\n\n const cleanUrls = options.cleanUrls ?? true;\n\n function logDebug(enabled: boolean | undefined, ...args: unknown[]) {\n if (!enabled) return;\n console.log(`[${PLUGIN_NAME}]`, ...args);\n }\n\n async function loadDevPages(): Promise<HtPageInfo[]> {\n const entries = await discoverEntryPages(root, options);\n const modulesByEntry = new Map<string, HtPageModule>();\n\n logDebug(\n options.debug,\n 'discovered entries',\n entries.map((e) => e.relativePath),\n );\n\n if (!server) return [];\n\n for (const entry of entries) {\n const mod = (await server.ssrLoadModule(\n `/${entry.relativePath}`,\n )) as HtPageModule;\n\n modulesByEntry.set(entry.entryPath, mod);\n }\n\n devPages = await buildPageIndex({\n entries,\n modulesByEntry,\n cleanUrls,\n });\n\n logDebug(\n options.debug,\n 'dev pages',\n devPages.map((p) => `${p.routePath} -> ${p.relativePath}`),\n );\n\n return devPages;\n }\n\n async function buildPagesPipeline() {\n const entries = await discoverEntryPages(root, options);\n const cacheDir = path.join(root, CACHE_DIR_NAME);\n\n const bundlePath = await buildRenderBundle({\n entries,\n cacheDir,\n ssrPlugins: options.ssrPlugins,\n });\n\n logDebug(options.debug, 'render bundle', bundlePath);\n\n const manifest = await importManifest(bundlePath);\n const modulesByEntry = new Map<string, HtPageModule>();\n\n for (const rec of manifest) {\n modulesByEntry.set(rec.page.entryPath, rec.mod);\n }\n\n const pages = await buildPageIndex({\n entries,\n modulesByEntry,\n cleanUrls,\n });\n\n return { entries, bundlePath, modulesByEntry, pages };\n }\n\n return {\n name: PLUGIN_NAME,\n\n config(userConfig, env) {\n if (env.command !== 'build') return;\n\n const hasExplicitInput = userConfig.build?.rollupOptions?.input != null;\n if (hasExplicitInput) return;\n\n return {\n build: {\n rollupOptions: {\n input: VIRTUAL_BUILD_ENTRY_ID,\n },\n },\n };\n },\n\n resolveId(id) {\n if (id === VIRTUAL_BUILD_ENTRY_ID) return id;\n return null;\n },\n\n load(id) {\n if (id === VIRTUAL_BUILD_ENTRY_ID) {\n return 'export default {};';\n }\n return null;\n },\n\n configResolved(resolved) {\n root = resolved.root;\n },\n\n async buildStart() {\n const entries = await discoverEntryPages(root, options);\n\n for (const entry of entries) {\n this.addWatchFile(entry.entryPath);\n }\n },\n\n configureServer(_server) {\n server = _server;\n\n installDevServer({\n server,\n getPages: async () => {\n if (devPages.length > 0) return devPages;\n return loadDevPages();\n },\n getEntries: async () => discoverEntryPages(root, options),\n });\n\n loadDevPages().catch((error) => {\n server?.config.logger.error(\n `[${PLUGIN_NAME}] loadDevPages failed: ${\n error instanceof Error ? error.stack ?? error.message : String(error)\n }`,\n );\n });\n },\n\n async handleHotUpdate(ctx) {\n if (!server) return;\n\n if (!ctx.file.endsWith('.ht.js')) {\n return;\n }\n\n logDebug(options.debug, 'page updated', ctx.file);\n\n await loadDevPages();\n return undefined;\n },\n\n async generateBundle(_, bundle) {\n const { modulesByEntry, pages } = await buildPagesPipeline();\n\n logDebug(\n options.debug,\n 'emitting pages',\n pages.map((p) => p.fileName),\n );\n\n const limit = pLimit(options.renderConcurrency ?? 8);\n const batchSize =\n options.renderBatchSize ??\n Math.max(options.renderConcurrency ?? 8, 32);\n\n for (const batch of chunkArray(pages, batchSize)) {\n await Promise.all(\n batch.map((page) =>\n limit(async () => {\n const mod = modulesByEntry.get(page.entryPath);\n if (!mod) {\n throw new Error(\n `[${PLUGIN_NAME}] Missing module for page entry: ${page.entryPath}`,\n );\n }\n\n const html = await renderPage(page, mod, false);\n\n this.emitFile({\n type: 'asset',\n fileName: options.mapOutputPath?.(page) ?? page.fileName,\n source: html,\n });\n }),\n ),\n );\n }\n\n const sitemapBase = options.site ?? '';\n const sitemapRoutes = [...new Set(pages.map((p) => p.routePath))].filter(\n (route) => !route.includes(':') && !route.includes('*'),\n );\n\n if (sitemapRoutes.length > 0) {\n const sitemap = `<?xml version=\"1.0\" encoding=\"UTF-8\"?>\\n<urlset xmlns=\"http://www.sitemaps.org/schemas/sitemap/0.9\">\\n${sitemapRoutes\n .map((route) => ` <url><loc>${sitemapBase}${route}</loc></url>`)\n .join('\\n')}\\n</urlset>\\n`;\n\n this.emitFile({\n type: 'asset',\n fileName: 'sitemap.xml',\n source: sitemap,\n });\n }\n\n if (options.rss?.site) {\n const routePrefix = options.rss.routePrefix ?? '/blog';\n\n const rssItems = pages\n .filter((page) => page.routePath.startsWith(routePrefix))\n .map((page) => {\n const url = `${options.rss!.site}${page.routePath}`;\n return ` <item>\\n <title>${page.routePath}</title>\\n <link>${url}</link>\\n <guid>${url}</guid>\\n </item>`;\n })\n .join('\\n');\n\n const rss = `<?xml version=\"1.0\" encoding=\"UTF-8\"?>\\n<rss version=\"2.0\">\\n<channel>\\n <title>${options.rss.title ?? PLUGIN_NAME}</title>\\n <link>${options.rss.site}</link>\\n <description>${options.rss.description ?? 'RSS feed'}</description>\\n${rssItems}\\n</channel>\\n</rss>\\n`;\n\n this.emitFile({\n type: 'asset',\n fileName: 'rss.xml',\n source: rss,\n });\n }\n\n for (const [fileName, output] of Object.entries(bundle)) {\n if (\n output.type === 'chunk' &&\n output.facadeModuleId === VIRTUAL_BUILD_ENTRY_ID\n ) {\n delete bundle[fileName];\n }\n }\n },\n };\n}\n","import path from 'node:path';\nimport { normalizeFsPath, toPosix } from './path-utils';\nimport { getParamNames, isDynamicPage, toRoutePattern } from './route-utils';\nimport type { HtPageInfo, HtPagesPluginOptions } from './types';\nimport { PLUGIN_NAME } from './constants';\n\nexport async function discoverEntryPages(\n root: string,\n options: HtPagesPluginOptions,\n): Promise<HtPageInfo[]> {\n const fgModule = await import('fast-glob');\n const fg = (fgModule.default ?? fgModule) as typeof import('fast-glob');\n\n const include = Array.isArray(options.include)\n ? options.include\n : [options.include ?? 'src/**/*.ht.js'];\n\n const exclude = Array.isArray(options.exclude)\n ? options.exclude\n : options.exclude\n ? [options.exclude]\n : [];\n\n const pagesDir = options.pagesDir ?? 'src';\n const pagesRoot = normalizeFsPath(path.join(root, pagesDir));\n\n const files = await fg.glob(include, {\n cwd: root,\n ignore: exclude,\n absolute: true,\n });\n\n return files\n .sort()\n .map((absolutePath) => {\n const entryPath = normalizeFsPath(absolutePath);\n const relativePath = toPosix(path.relative(root, entryPath));\n const relativeFromPagesDir = toPosix(path.relative(pagesRoot, entryPath));\n\n if (\n relativeFromPagesDir.startsWith('../') ||\n relativeFromPagesDir === '..'\n ) {\n throw new Error(\n `[${PLUGIN_NAME}] Page is outside pagesDir: ${entryPath} (pagesDir: ${pagesDir})`,\n );\n }\n\n const dynamic = isDynamicPage(relativeFromPagesDir);\n const routePattern = toRoutePattern(relativeFromPagesDir);\n\n return {\n id: entryPath,\n entryPath,\n absolutePath: entryPath,\n relativePath,\n routePattern,\n routePath: routePattern,\n fileName: '',\n dynamic,\n paramNames: getParamNames(relativeFromPagesDir),\n params: {},\n } satisfies HtPageInfo;\n });\n}","import path from 'node:path';\n\nexport function toPosix(p: string): string {\n return p.split(path.sep).join('/');\n}\n\nexport function stripHtSuffix(file: string): string {\n return file.replace(/\\.ht\\.js$/i, '');\n}\n\nexport function normalizeRoutePath(p: string): string {\n let out = p.startsWith('/') ? p : `/${p}`;\n out = out.replace(/\\/+/g, '/');\n if (out !== '/' && out.endsWith('/')) out = out.slice(0, -1);\n return out;\n}\n\nexport function normalizeFsPath(p: string): string {\n return toPosix(path.resolve(p));\n}","import { normalizeRoutePath, stripHtSuffix, toPosix } from './path-utils';\nimport type { HtPageInfo, StaticParamRecord } from './types';\n\nfunction safeDecodeURIComponent(str: string): string {\n try {\n return decodeURIComponent(str);\n } catch {\n return str;\n }\n}\n\nconst DYNAMIC_SEGMENT_RE = /\\[([A-Za-z0-9_]+)\\]/g;\nconst CATCH_ALL_SEGMENT_RE = /\\[\\.\\.\\.([A-Za-z0-9_]+)\\]/g;\nconst OPTIONAL_CATCH_ALL_SEGMENT_RE = /\\[\\.\\.\\.([A-Za-z0-9_]+)\\]\\?/g;\nconst ANY_PARAM_RE = /\\[(?:\\.\\.\\.)?([A-Za-z0-9_]+)\\]\\??/g;\nconst ROUTE_GROUP_RE = /(^|\\/)\\(([^)]+)\\)(?=\\/|$)/g;\n\nexport function getParamNames(relativeFromPagesDir: string): string[] {\n return [...relativeFromPagesDir.matchAll(ANY_PARAM_RE)].map((m) => m[1]);\n}\n\nexport function isDynamicPage(relativeFromPagesDir: string): boolean {\n return /\\[(?:\\.\\.\\.)?[A-Za-z0-9_]+\\]\\??/.test(relativeFromPagesDir);\n}\n\nexport function toRoutePattern(relativeFromPagesDir: string): string {\n const noExt = stripHtSuffix(toPosix(relativeFromPagesDir));\n\n const withoutGroups = noExt.replace(ROUTE_GROUP_RE, '$1');\n const withoutIndex = withoutGroups.replace(/\\/index$/i, '').replace(/^index$/i, '');\n\n const raw = withoutIndex\n .replace(OPTIONAL_CATCH_ALL_SEGMENT_RE, '*?:$1')\n .replace(CATCH_ALL_SEGMENT_RE, '*:$1')\n .replace(DYNAMIC_SEGMENT_RE, ':$1');\n\n return normalizeRoutePath(raw || '/');\n}\n\nexport function fillParams(\n pattern: string,\n params: Record<string, string>,\n): string {\n const result = pattern\n .replace(/\\*\\?:([A-Za-z0-9_]+)/g, (_, key) => {\n const value = params[key];\n if (value == null || value === '') {\n return '';\n }\n\n return String(value)\n .split('/')\n .map((part) => encodeURIComponent(part))\n .join('/');\n })\n .replace(/\\*:([A-Za-z0-9_]+)/g, (_, key) => {\n if (!(key in params)) {\n throw new Error(`Missing catch-all route param \"${key}\"`);\n }\n\n return String(params[key])\n .split('/')\n .map((part) => encodeURIComponent(part))\n .join('/');\n })\n .replace(/:([A-Za-z0-9_]+)/g, (_, key) => {\n if (!(key in params)) {\n throw new Error(`Missing route param \"${key}\"`);\n }\n\n return encodeURIComponent(params[key]);\n });\n\n return normalizeRoutePath(result || '/');\n}\n\nexport function fileNameFromRoute(\n routePath: string,\n cleanUrls: boolean,\n): string {\n const normalized = normalizeRoutePath(routePath);\n\n if (normalized === '/') return 'index.html';\n\n const base = normalized.slice(1);\n return cleanUrls ? `${base}/index.html` : `${base}.html`;\n}\n\nexport function expandStaticPaths(\n basePage: Omit<HtPageInfo, 'routePath' | 'fileName' | 'params'>,\n rows: StaticParamRecord[],\n cleanUrls: boolean,\n): HtPageInfo[] {\n return rows.map((row) => {\n const params = Object.fromEntries(\n Object.entries(row).map(([k, v]) => [k, String(v)]),\n );\n\n const routePath = fillParams(basePage.routePattern, params);\n\n return {\n ...basePage,\n routePath,\n fileName: fileNameFromRoute(routePath, cleanUrls),\n params,\n };\n });\n}\n\nexport function routeMatch(\n pattern: string,\n urlPath: string,\n): Record<string, string> | null {\n const a = normalizeRoutePath(pattern).split('/').filter(Boolean);\n const b = normalizeRoutePath(urlPath).split('/').filter(Boolean);\n const params: Record<string, string> = {};\n\n for (let i = 0; i < a.length; i++) {\n const patternSeg = a[i];\n const urlSeg = b[i];\n\n if (patternSeg.startsWith('*?:')) {\n params[patternSeg.slice(3)] =\n i < b.length ? b.slice(i).map(safeDecodeURIComponent).join('/') : '';\n return params;\n }\n\n if (patternSeg.startsWith('*:')) {\n const rest = b.slice(i);\n if (rest.length === 0) return null;\n\n params[patternSeg.slice(2)] = rest.map(safeDecodeURIComponent).join('/');\n return params;\n }\n\n if (!urlSeg) return null;\n\n if (patternSeg.startsWith(':')) {\n params[patternSeg.slice(1)] = safeDecodeURIComponent(urlSeg);\n continue;\n }\n\n if (patternSeg !== urlSeg) return null;\n }\n\n return a.length === b.length ? params : null;\n}\n\nexport function compareRoutePriority(a: string, b: string): number {\n const aSegs = normalizeRoutePath(a).split('/').filter(Boolean);\n const bSegs = normalizeRoutePath(b).split('/').filter(Boolean);\n const len = Math.max(aSegs.length, bSegs.length);\n\n for (let i = 0; i < len; i++) {\n const aa = aSegs[i];\n const bb = bSegs[i];\n\n if (aa == null) return 1;\n if (bb == null) return -1;\n\n const aOptionalCatchAll = aa.startsWith('*?:');\n const bOptionalCatchAll = bb.startsWith('*?:');\n if (aOptionalCatchAll !== bOptionalCatchAll) {\n return aOptionalCatchAll ? 1 : -1;\n }\n\n const aCatchAll = aa.startsWith('*:');\n const bCatchAll = bb.startsWith('*:');\n if (aCatchAll !== bCatchAll) {\n return aCatchAll ? 1 : -1;\n }\n\n const aDynamic = aa.startsWith(':');\n const bDynamic = bb.startsWith(':');\n if (aDynamic !== bDynamic) {\n return aDynamic ? 1 : -1;\n }\n }\n\n // More specific / longer routes first when otherwise equal\n return bSegs.length - aSegs.length;\n}","export const PLUGIN_NAME = 'vite-plugin-htjs-pages';\nexport const VIRTUAL_BUILD_ENTRY_ID = `\\0${PLUGIN_NAME}:build-entry`;\nexport const VIRTUAL_MANIFEST_ID = `\\0virtual:${PLUGIN_NAME}-manifest`;\nexport const CACHE_DIR_NAME = `node_modules/.cache/${PLUGIN_NAME}`;","import type { HtPageInfo } from './types';\nimport { PLUGIN_NAME } from './constants';\nexport function invalidHtmlReturn(\n page: HtPageInfo,\n value: unknown,\n): Error {\n return new Error(\n `[${PLUGIN_NAME}] Page \"${page.relativePath}\" must resolve to an HTML string, got ${typeof value}`,\n );\n}\n\nexport function missingDefaultExport(page: HtPageInfo): Error {\n return new Error(\n `[${PLUGIN_NAME}] Page \"${page.relativePath}\" does not export a default renderer`,\n );\n}\n\nexport function pageError(page: HtPageInfo, cause: unknown): Error {\n const message = `[${PLUGIN_NAME}] Failed to render \"${page.relativePath}\" at route \"${page.routePath}\"`;\n\n if (cause instanceof Error) {\n const err = new Error(`${message}: ${cause.message}`);\n\n if (cause.stack) {\n err.stack = `${err.stack}\\nCaused by:\\n${cause.stack}`;\n }\n\n return err;\n }\n\n return new Error(`${message}: ${String(cause)}`);\n}","import { invalidHtmlReturn, pageError, missingDefaultExport } from './errors';\nimport type { HtPageInfo, HtPageModule, HtPageRenderContext } from './types';\n\nexport async function renderPage(\n page: HtPageInfo,\n mod: HtPageModule,\n dev = false,\n): Promise<string> {\n const ctx: HtPageRenderContext = {\n page,\n params: page.params,\n dev,\n };\n\n try {\n if (typeof mod.data === 'function') {\n ctx.data = await mod.data(ctx);\n }\n\n const entry = mod.default;\n\n if (entry == null) {\n throw missingDefaultExport(page);\n }\n\n const html = typeof entry === 'function' ? await entry(ctx) : entry;\n\n if (typeof html !== 'string') {\n throw invalidHtmlReturn(page, html);\n }\n\n return html;\n } catch (error) {\n throw pageError(page, error);\n }\n}","import type { ViteDevServer } from 'vite';\nimport { renderPage } from './render-runtime';\nimport { routeMatch } from './route-utils';\nimport type { HtPageInfo, HtPageModule } from './types';\n\nfunction isDynamicOnly(mod: HtPageModule): boolean {\n return mod.dynamic === true || mod.prerender === false;\n}\n\nexport function installDevServer(args: {\n server: ViteDevServer;\n getPages: () => Promise<HtPageInfo[]>;\n getEntries: () => Promise<HtPageInfo[]>;\n}): void {\n const { server, getPages, getEntries } = args;\n\n server.middlewares.use(async (req, res, next) => {\n try {\n if (!req.url || req.method !== 'GET') return next();\n\n const pathname = req.url.split('?')[0];\n\n const pages = await getPages();\n const staticPage = pages.find((p) => p.routePath === pathname);\n\n if (staticPage) {\n const mod = (await server.ssrLoadModule(\n `/${staticPage.relativePath}`,\n )) as HtPageModule;\n\n const html = await renderPage(staticPage, mod, true);\n\n res.statusCode = 200;\n res.setHeader('Content-Type', 'text/html; charset=utf-8');\n res.end(html);\n return;\n }\n\n const entries = await getEntries();\n\n for (const entry of entries) {\n const mod = (await server.ssrLoadModule(\n `/${entry.relativePath}`,\n )) as HtPageModule;\n\n if (!isDynamicOnly(mod)) continue;\n\n const params = routeMatch(entry.routePattern, pathname);\n if (!params) continue;\n\n const page: HtPageInfo = {\n ...entry,\n routePath: pathname,\n fileName: '',\n params,\n };\n\n const html = await renderPage(page, mod, true);\n\n res.statusCode = 200;\n res.setHeader('Content-Type', 'text/html; charset=utf-8');\n res.end(html);\n return;\n }\n\n next();\n } catch (error) {\n next(error);\n }\n });\n}","import {\n compareRoutePriority,\n expandStaticPaths,\n fileNameFromRoute,\n} from './route-utils';\nimport type { HtPageInfo, HtPageModule, StaticParamRecord } from './types';\nimport { PLUGIN_NAME } from './constants';\nexport async function buildPageIndex(args: {\n entries: HtPageInfo[];\n modulesByEntry: Map<string, HtPageModule>;\n cleanUrls: boolean;\n}): Promise<HtPageInfo[]> {\n const { entries, modulesByEntry, cleanUrls } = args;\n const pages: HtPageInfo[] = [];\n\n for (const entry of entries) {\n const mod = modulesByEntry.get(entry.entryPath) ?? {};\n\n if (entry.dynamic) {\n const rows =\n (mod.generateStaticParams\n ? await mod.generateStaticParams()\n : []) ?? [];\n\n pages.push(\n ...expandStaticPaths(\n {\n id: entry.id,\n entryPath: entry.entryPath,\n absolutePath: entry.absolutePath,\n relativePath: entry.relativePath,\n routePattern: entry.routePattern,\n dynamic: entry.dynamic,\n paramNames: entry.paramNames,\n } as Omit<HtPageInfo, 'routePath' | 'fileName' | 'params'>,\n Array.isArray(rows) ? rows : [],\n cleanUrls,\n ),\n );\n } else {\n pages.push({\n ...entry,\n routePath: entry.routePattern,\n fileName: fileNameFromRoute(entry.routePattern, cleanUrls),\n params: {},\n });\n }\n }\n\n pages.sort((a, b) => compareRoutePriority(a.routePattern, b.routePattern));\n\n const seenRoutes = new Map<string, HtPageInfo>();\n\n for (const page of pages) {\n const existing = seenRoutes.get(page.routePath);\n\n if (existing) {\n throw new Error(\n `[${PLUGIN_NAME}] Duplicate route generated: \"${page.routePath}\" from \"${existing.relativePath}\" and \"${page.relativePath}\"`,\n );\n }\n\n seenRoutes.set(page.routePath, page);\n }\n\n return pages;\n}","import path from 'node:path';\nimport fs from 'node:fs/promises';\nimport { createHash } from 'node:crypto';\nimport type { Plugin as RollupPlugin } from 'rollup';\n\nimport { createManifestModule } from './manifest';\nimport type { HtPageInfo } from './types';\nimport { PLUGIN_NAME, VIRTUAL_MANIFEST_ID } from './constants';\n\nasync function createRenderBundleHash(\n entries: HtPageInfo[],\n manifestSource: string,\n): Promise<string> {\n const hash = createHash('sha256');\n hash.update(manifestSource);\n\n for (const entry of entries) {\n hash.update(entry.entryPath);\n const source = await fs.readFile(entry.entryPath, 'utf8');\n hash.update(source);\n }\n\n return hash.digest('hex').slice(0, 12);\n}\n\nexport async function buildRenderBundle(args: {\n entries: HtPageInfo[];\n cacheDir: string;\n ssrPlugins?: RollupPlugin[];\n}): Promise<string> {\n const { entries, cacheDir, ssrPlugins = [] } = args;\n\n const [{ rollup }, { nodeResolve }] = await Promise.all([\n import('rollup'),\n import('@rollup/plugin-node-resolve'),\n ]);\n\n const manifestSource = createManifestModule(entries);\n const hash = await createRenderBundleHash(entries, manifestSource);\n const bundlePath = path.join(cacheDir, `render-${hash}.mjs`);\n\n await fs.mkdir(cacheDir, { recursive: true });\n\n try {\n await fs.access(bundlePath);\n return bundlePath;\n } catch {\n // cache miss\n }\n\n const bundle = await rollup({\n input: VIRTUAL_MANIFEST_ID,\n plugins: [\n {\n name: `${PLUGIN_NAME}:virtual-manifest`,\n resolveId(id) {\n return id === VIRTUAL_MANIFEST_ID ? id : null;\n },\n load(id) {\n return id === VIRTUAL_MANIFEST_ID ? manifestSource : null;\n },\n },\n nodeResolve({\n preferBuiltins: true,\n exportConditions: ['node'],\n }),\n ...ssrPlugins,\n ],\n treeshake: true,\n });\n\n try {\n const { output } = await bundle.generate({\n format: 'esm',\n exports: 'named',\n inlineDynamicImports: true,\n });\n\n const chunk = output.find((item) => item.type === 'chunk');\n\n if (!chunk || chunk.type !== 'chunk') {\n throw new Error(\n `[${PLUGIN_NAME}] Failed to generate HT pages render bundle.`,\n );\n }\n\n await fs.writeFile(bundlePath, chunk.code, 'utf8');\n return bundlePath;\n } finally {\n await bundle.close();\n }\n}","import type { HtPageInfo } from './types';\n\nfunction js(value: unknown): string {\n return JSON.stringify(value);\n}\n\nexport function createManifestModule(entries: HtPageInfo[]): string {\n const imports = entries\n .map((page, i) => `import * as page${i} from ${js(page.entryPath)};`)\n .join('\\n');\n\n const records = entries\n .map(\n (page, i) => `{\n page: ${js(page)},\n mod: page${i}\n}`,\n )\n .join(',\\n');\n\n return `${imports}\n\nexport const manifest = [\n${records}\n];\n`;\n}","import fs from 'node:fs/promises';\nimport path from 'node:path';\nimport { createHash } from 'node:crypto';\nimport { CACHE_DIR_NAME } from './constants';\n\nexport interface FetchAndCacheOptions {\n maxAge?: number;\n cacheKey?: string;\n forceRefresh?: boolean;\n}\n\ntype CachedResponseRecord = {\n timestamp: number;\n status: number;\n statusText: string;\n headers: [string, string][];\n body: string;\n};\n\nfunction createDefaultCacheKey(\n input: RequestInfo | URL,\n init?: RequestInit,\n): string {\n const raw = JSON.stringify({\n url: String(input),\n method: init?.method ?? 'GET',\n headers: init?.headers ?? {},\n body: init?.body ?? null,\n });\n\n return createHash('sha256').update(raw).digest('hex');\n}\n\nfunction getCacheFilePath(cacheKey: string): string {\n return path.join(process.cwd(), CACHE_DIR_NAME, 'fetch', `${cacheKey}.json`);\n}\n\nexport async function fetchAndCache(\n input: RequestInfo | URL,\n init?: RequestInit,\n options: FetchAndCacheOptions = {},\n): Promise<Response> {\n const maxAge = options.maxAge ?? 60 * 60;\n const method = (init?.method ?? 'GET').toUpperCase();\n\n if (method !== 'GET' && !options.cacheKey) {\n return fetch(input, init);\n }\n\n const cacheKey = options.cacheKey ?? createDefaultCacheKey(input, init);\n const filePath = getCacheFilePath(cacheKey);\n\n await fs.mkdir(path.dirname(filePath), { recursive: true });\n\n if (!options.forceRefresh) {\n try {\n const raw = await fs.readFile(filePath, 'utf8');\n const cached = JSON.parse(raw) as CachedResponseRecord;\n\n const ageSeconds = (Date.now() - cached.timestamp) / 1000;\n\n if (ageSeconds <= maxAge) {\n return new Response(cached.body, {\n status: cached.status,\n statusText: cached.statusText,\n headers: cached.headers,\n });\n }\n } catch {\n // cache miss or invalid cache; fetch fresh\n }\n }\n\n const res = await fetch(input, init);\n const body = await res.text();\n\n const record: CachedResponseRecord = {\n timestamp: Date.now(),\n status: res.status,\n statusText: res.statusText,\n headers: [...res.headers.entries()],\n body,\n };\n\n await fs.writeFile(filePath, JSON.stringify(record), 'utf8');\n\n return new Response(body, {\n status: res.status,\n statusText: res.statusText,\n headers: res.headers,\n });\n}\n"],"mappings":";AAAA,OAAOA,WAAU;AACjB,SAAS,qBAAqB;AAC9B,OAAO,YAAY;;;ACFnB,OAAOC,WAAU;;;ACAjB,OAAO,UAAU;AAEV,SAAS,QAAQ,GAAmB;AACzC,SAAO,EAAE,MAAM,KAAK,GAAG,EAAE,KAAK,GAAG;AACnC;AAEO,SAAS,cAAc,MAAsB;AAClD,SAAO,KAAK,QAAQ,cAAc,EAAE;AACtC;AAEO,SAAS,mBAAmB,GAAmB;AACpD,MAAI,MAAM,EAAE,WAAW,GAAG,IAAI,IAAI,IAAI,CAAC;AACvC,QAAM,IAAI,QAAQ,QAAQ,GAAG;AAC7B,MAAI,QAAQ,OAAO,IAAI,SAAS,GAAG,EAAG,OAAM,IAAI,MAAM,GAAG,EAAE;AAC3D,SAAO;AACT;AAEO,SAAS,gBAAgB,GAAmB;AACjD,SAAO,QAAQ,KAAK,QAAQ,CAAC,CAAC;AAChC;;;AChBA,SAAS,uBAAuB,KAAqB;AACnD,MAAI;AACF,WAAO,mBAAmB,GAAG;AAAA,EAC/B,QAAQ;AACN,WAAO;AAAA,EACT;AACF;AAEA,IAAM,qBAAqB;AAC3B,IAAM,uBAAuB;AAC7B,IAAM,gCAAgC;AACtC,IAAM,eAAe;AACrB,IAAM,iBAAiB;AAEhB,SAAS,cAAc,sBAAwC;AACpE,SAAO,CAAC,GAAG,qBAAqB,SAAS,YAAY,CAAC,EAAE,IAAI,CAAC,MAAM,EAAE,CAAC,CAAC;AACzE;AAEO,SAAS,cAAc,sBAAuC;AACnE,SAAO,kCAAkC,KAAK,oBAAoB;AACpE;AAEO,SAAS,eAAe,sBAAsC;AACnE,QAAM,QAAQ,cAAc,QAAQ,oBAAoB,CAAC;AAEzD,QAAM,gBAAgB,MAAM,QAAQ,gBAAgB,IAAI;AACxD,QAAM,eAAe,cAAc,QAAQ,aAAa,EAAE,EAAE,QAAQ,YAAY,EAAE;AAElF,QAAM,MAAM,aACT,QAAQ,+BAA+B,OAAO,EAC9C,QAAQ,sBAAsB,MAAM,EACpC,QAAQ,oBAAoB,KAAK;AAEpC,SAAO,mBAAmB,OAAO,GAAG;AACtC;AAEO,SAAS,WACd,SACA,QACQ;AACR,QAAM,SAAS,QACZ,QAAQ,yBAAyB,CAAC,GAAG,QAAQ;AAC5C,UAAM,QAAQ,OAAO,GAAG;AACxB,QAAI,SAAS,QAAQ,UAAU,IAAI;AACjC,aAAO;AAAA,IACT;AAEA,WAAO,OAAO,KAAK,EAChB,MAAM,GAAG,EACT,IAAI,CAAC,SAAS,mBAAmB,IAAI,CAAC,EACtC,KAAK,GAAG;AAAA,EACb,CAAC,EACA,QAAQ,uBAAuB,CAAC,GAAG,QAAQ;AAC1C,QAAI,EAAE,OAAO,SAAS;AACpB,YAAM,IAAI,MAAM,kCAAkC,GAAG,GAAG;AAAA,IAC1D;AAEA,WAAO,OAAO,OAAO,GAAG,CAAC,EACtB,MAAM,GAAG,EACT,IAAI,CAAC,SAAS,mBAAmB,IAAI,CAAC,EACtC,KAAK,GAAG;AAAA,EACb,CAAC,EACA,QAAQ,qBAAqB,CAAC,GAAG,QAAQ;AACxC,QAAI,EAAE,OAAO,SAAS;AACpB,YAAM,IAAI,MAAM,wBAAwB,GAAG,GAAG;AAAA,IAChD;AAEA,WAAO,mBAAmB,OAAO,GAAG,CAAC;AAAA,EACvC,CAAC;AAEH,SAAO,mBAAmB,UAAU,GAAG;AACzC;AAEO,SAAS,kBACd,WACA,WACQ;AACR,QAAM,aAAa,mBAAmB,SAAS;AAE/C,MAAI,eAAe,IAAK,QAAO;AAE/B,QAAM,OAAO,WAAW,MAAM,CAAC;AAC/B,SAAO,YAAY,GAAG,IAAI,gBAAgB,GAAG,IAAI;AACnD;AAEO,SAAS,kBACd,UACA,MACA,WACc;AACd,SAAO,KAAK,IAAI,CAAC,QAAQ;AACvB,UAAM,SAAS,OAAO;AAAA,MACpB,OAAO,QAAQ,GAAG,EAAE,IAAI,CAAC,CAAC,GAAG,CAAC,MAAM,CAAC,GAAG,OAAO,CAAC,CAAC,CAAC;AAAA,IACpD;AAEA,UAAM,YAAY,WAAW,SAAS,cAAc,MAAM;AAE1D,WAAO;AAAA,MACL,GAAG;AAAA,MACH;AAAA,MACA,UAAU,kBAAkB,WAAW,SAAS;AAAA,MAChD;AAAA,IACF;AAAA,EACF,CAAC;AACH;AAEO,SAAS,WACd,SACA,SAC+B;AAC/B,QAAM,IAAI,mBAAmB,OAAO,EAAE,MAAM,GAAG,EAAE,OAAO,OAAO;AAC/D,QAAM,IAAI,mBAAmB,OAAO,EAAE,MAAM,GAAG,EAAE,OAAO,OAAO;AAC/D,QAAM,SAAiC,CAAC;AAExC,WAAS,IAAI,GAAG,IAAI,EAAE,QAAQ,KAAK;AACjC,UAAM,aAAa,EAAE,CAAC;AACtB,UAAM,SAAS,EAAE,CAAC;AAElB,QAAI,WAAW,WAAW,KAAK,GAAG;AAChC,aAAO,WAAW,MAAM,CAAC,CAAC,IACxB,IAAI,EAAE,SAAS,EAAE,MAAM,CAAC,EAAE,IAAI,sBAAsB,EAAE,KAAK,GAAG,IAAI;AACpE,aAAO;AAAA,IACT;AAEA,QAAI,WAAW,WAAW,IAAI,GAAG;AAC/B,YAAM,OAAO,EAAE,MAAM,CAAC;AACtB,UAAI,KAAK,WAAW,EAAG,QAAO;AAE9B,aAAO,WAAW,MAAM,CAAC,CAAC,IAAI,KAAK,IAAI,sBAAsB,EAAE,KAAK,GAAG;AACvE,aAAO;AAAA,IACT;AAEA,QAAI,CAAC,OAAQ,QAAO;AAEpB,QAAI,WAAW,WAAW,GAAG,GAAG;AAC9B,aAAO,WAAW,MAAM,CAAC,CAAC,IAAI,uBAAuB,MAAM;AAC3D;AAAA,IACF;AAEA,QAAI,eAAe,OAAQ,QAAO;AAAA,EACpC;AAEA,SAAO,EAAE,WAAW,EAAE,SAAS,SAAS;AAC1C;AAEO,SAAS,qBAAqB,GAAW,GAAmB;AACjE,QAAM,QAAQ,mBAAmB,CAAC,EAAE,MAAM,GAAG,EAAE,OAAO,OAAO;AAC7D,QAAM,QAAQ,mBAAmB,CAAC,EAAE,MAAM,GAAG,EAAE,OAAO,OAAO;AAC7D,QAAM,MAAM,KAAK,IAAI,MAAM,QAAQ,MAAM,MAAM;AAE/C,WAAS,IAAI,GAAG,IAAI,KAAK,KAAK;AAC5B,UAAM,KAAK,MAAM,CAAC;AAClB,UAAM,KAAK,MAAM,CAAC;AAElB,QAAI,MAAM,KAAM,QAAO;AACvB,QAAI,MAAM,KAAM,QAAO;AAEvB,UAAM,oBAAoB,GAAG,WAAW,KAAK;AAC7C,UAAM,oBAAoB,GAAG,WAAW,KAAK;AAC7C,QAAI,sBAAsB,mBAAmB;AAC3C,aAAO,oBAAoB,IAAI;AAAA,IACjC;AAEA,UAAM,YAAY,GAAG,WAAW,IAAI;AACpC,UAAM,YAAY,GAAG,WAAW,IAAI;AACpC,QAAI,cAAc,WAAW;AAC3B,aAAO,YAAY,IAAI;AAAA,IACzB;AAEA,UAAM,WAAW,GAAG,WAAW,GAAG;AAClC,UAAM,WAAW,GAAG,WAAW,GAAG;AAClC,QAAI,aAAa,UAAU;AACzB,aAAO,WAAW,IAAI;AAAA,IACxB;AAAA,EACF;AAGA,SAAO,MAAM,SAAS,MAAM;AAC9B;;;ACrLO,IAAM,cAAc;AACpB,IAAM,yBAAyB,KAAK,WAAW;AAC/C,IAAM,sBAAsB,aAAa,WAAW;AACpD,IAAM,iBAAiB,uBAAuB,WAAW;;;AHGhE,eAAsB,mBACpB,MACA,SACuB;AACvB,QAAM,WAAW,MAAM,OAAO,WAAW;AACzC,QAAM,KAAM,SAAS,WAAW;AAEhC,QAAM,UAAU,MAAM,QAAQ,QAAQ,OAAO,IACzC,QAAQ,UACR,CAAC,QAAQ,WAAW,gBAAgB;AAExC,QAAM,UAAU,MAAM,QAAQ,QAAQ,OAAO,IACzC,QAAQ,UACR,QAAQ,UACN,CAAC,QAAQ,OAAO,IAChB,CAAC;AAEP,QAAM,WAAW,QAAQ,YAAY;AACrC,QAAM,YAAY,gBAAgBC,MAAK,KAAK,MAAM,QAAQ,CAAC;AAE3D,QAAM,QAAQ,MAAM,GAAG,KAAK,SAAS;AAAA,IACnC,KAAK;AAAA,IACL,QAAQ;AAAA,IACR,UAAU;AAAA,EACZ,CAAC;AAED,SAAO,MACJ,KAAK,EACL,IAAI,CAAC,iBAAiB;AACrB,UAAM,YAAY,gBAAgB,YAAY;AAC9C,UAAM,eAAe,QAAQA,MAAK,SAAS,MAAM,SAAS,CAAC;AAC3D,UAAM,uBAAuB,QAAQA,MAAK,SAAS,WAAW,SAAS,CAAC;AAExE,QACE,qBAAqB,WAAW,KAAK,KACrC,yBAAyB,MACzB;AACA,YAAM,IAAI;AAAA,QACR,IAAI,WAAW,+BAA+B,SAAS,eAAe,QAAQ;AAAA,MAChF;AAAA,IACF;AAEA,UAAM,UAAU,cAAc,oBAAoB;AAClD,UAAM,eAAe,eAAe,oBAAoB;AAExD,WAAO;AAAA,MACL,IAAI;AAAA,MACJ;AAAA,MACA,cAAc;AAAA,MACd;AAAA,MACA;AAAA,MACA,WAAW;AAAA,MACX,UAAU;AAAA,MACV;AAAA,MACA,YAAY,cAAc,oBAAoB;AAAA,MAC9C,QAAQ,CAAC;AAAA,IACX;AAAA,EACF,CAAC;AACL;;;AI9DO,SAAS,kBACd,MACA,OACO;AACP,SAAO,IAAI;AAAA,IACT,IAAI,WAAW,WAAW,KAAK,YAAY,yCAAyC,OAAO,KAAK;AAAA,EAClG;AACF;AAEO,SAAS,qBAAqB,MAAyB;AAC5D,SAAO,IAAI;AAAA,IACT,IAAI,WAAW,WAAW,KAAK,YAAY;AAAA,EAC7C;AACF;AAEO,SAAS,UAAU,MAAkB,OAAuB;AACjE,QAAM,UAAU,IAAI,WAAW,uBAAuB,KAAK,YAAY,eAAe,KAAK,SAAS;AAEpG,MAAI,iBAAiB,OAAO;AAC1B,UAAM,MAAM,IAAI,MAAM,GAAG,OAAO,KAAK,MAAM,OAAO,EAAE;AAEpD,QAAI,MAAM,OAAO;AACf,UAAI,QAAQ,GAAG,IAAI,KAAK;AAAA;AAAA,EAAiB,MAAM,KAAK;AAAA,IACtD;AAEA,WAAO;AAAA,EACT;AAEA,SAAO,IAAI,MAAM,GAAG,OAAO,KAAK,OAAO,KAAK,CAAC,EAAE;AACjD;;;AC5BA,eAAsB,WACpB,MACA,KACA,MAAM,OACW;AACjB,QAAM,MAA2B;AAAA,IAC/B;AAAA,IACA,QAAQ,KAAK;AAAA,IACb;AAAA,EACF;AAEA,MAAI;AACF,QAAI,OAAO,IAAI,SAAS,YAAY;AAClC,UAAI,OAAO,MAAM,IAAI,KAAK,GAAG;AAAA,IAC/B;AAEA,UAAM,QAAQ,IAAI;AAElB,QAAI,SAAS,MAAM;AACjB,YAAM,qBAAqB,IAAI;AAAA,IACjC;AAEA,UAAM,OAAO,OAAO,UAAU,aAAa,MAAM,MAAM,GAAG,IAAI;AAE9D,QAAI,OAAO,SAAS,UAAU;AAC5B,YAAM,kBAAkB,MAAM,IAAI;AAAA,IACpC;AAEA,WAAO;AAAA,EACT,SAAS,OAAO;AACd,UAAM,UAAU,MAAM,KAAK;AAAA,EAC7B;AACF;;;AC9BA,SAAS,cAAc,KAA4B;AACjD,SAAO,IAAI,YAAY,QAAQ,IAAI,cAAc;AACnD;AAEO,SAAS,iBAAiB,MAIxB;AACP,QAAM,EAAE,QAAQ,UAAU,WAAW,IAAI;AAEzC,SAAO,YAAY,IAAI,OAAO,KAAK,KAAK,SAAS;AAC/C,QAAI;AACF,UAAI,CAAC,IAAI,OAAO,IAAI,WAAW,MAAO,QAAO,KAAK;AAElD,YAAM,WAAW,IAAI,IAAI,MAAM,GAAG,EAAE,CAAC;AAErC,YAAM,QAAQ,MAAM,SAAS;AAC7B,YAAM,aAAa,MAAM,KAAK,CAAC,MAAM,EAAE,cAAc,QAAQ;AAE7D,UAAI,YAAY;AACd,cAAM,MAAO,MAAM,OAAO;AAAA,UACxB,IAAI,WAAW,YAAY;AAAA,QAC7B;AAEA,cAAM,OAAO,MAAM,WAAW,YAAY,KAAK,IAAI;AAEnD,YAAI,aAAa;AACjB,YAAI,UAAU,gBAAgB,0BAA0B;AACxD,YAAI,IAAI,IAAI;AACZ;AAAA,MACF;AAEA,YAAM,UAAU,MAAM,WAAW;AAEjC,iBAAW,SAAS,SAAS;AAC3B,cAAM,MAAO,MAAM,OAAO;AAAA,UACxB,IAAI,MAAM,YAAY;AAAA,QACxB;AAEA,YAAI,CAAC,cAAc,GAAG,EAAG;AAEzB,cAAM,SAAS,WAAW,MAAM,cAAc,QAAQ;AACtD,YAAI,CAAC,OAAQ;AAEb,cAAM,OAAmB;AAAA,UACvB,GAAG;AAAA,UACH,WAAW;AAAA,UACX,UAAU;AAAA,UACV;AAAA,QACF;AAEA,cAAM,OAAO,MAAM,WAAW,MAAM,KAAK,IAAI;AAE7C,YAAI,aAAa;AACjB,YAAI,UAAU,gBAAgB,0BAA0B;AACxD,YAAI,IAAI,IAAI;AACZ;AAAA,MACF;AAEA,WAAK;AAAA,IACP,SAAS,OAAO;AACd,WAAK,KAAK;AAAA,IACZ;AAAA,EACF,CAAC;AACH;;;AC/DA,eAAsB,eAAe,MAIX;AACxB,QAAM,EAAE,SAAS,gBAAgB,UAAU,IAAI;AAC/C,QAAM,QAAsB,CAAC;AAE7B,aAAW,SAAS,SAAS;AAC3B,UAAM,MAAM,eAAe,IAAI,MAAM,SAAS,KAAK,CAAC;AAEpD,QAAI,MAAM,SAAS;AACjB,YAAM,QACH,IAAI,uBACD,MAAM,IAAI,qBAAqB,IAC/B,CAAC,MAAM,CAAC;AAEd,YAAM;AAAA,QACJ,GAAG;AAAA,UACD;AAAA,YACE,IAAI,MAAM;AAAA,YACV,WAAW,MAAM;AAAA,YACjB,cAAc,MAAM;AAAA,YACpB,cAAc,MAAM;AAAA,YACpB,cAAc,MAAM;AAAA,YACpB,SAAS,MAAM;AAAA,YACf,YAAY,MAAM;AAAA,UACpB;AAAA,UACA,MAAM,QAAQ,IAAI,IAAI,OAAO,CAAC;AAAA,UAC9B;AAAA,QACF;AAAA,MACF;AAAA,IACF,OAAO;AACL,YAAM,KAAK;AAAA,QACT,GAAG;AAAA,QACH,WAAW,MAAM;AAAA,QACjB,UAAU,kBAAkB,MAAM,cAAc,SAAS;AAAA,QACzD,QAAQ,CAAC;AAAA,MACX,CAAC;AAAA,IACH;AAAA,EACF;AAEA,QAAM,KAAK,CAAC,GAAG,MAAM,qBAAqB,EAAE,cAAc,EAAE,YAAY,CAAC;AAEzE,QAAM,aAAa,oBAAI,IAAwB;AAE/C,aAAW,QAAQ,OAAO;AACxB,UAAM,WAAW,WAAW,IAAI,KAAK,SAAS;AAE9C,QAAI,UAAU;AACZ,YAAM,IAAI;AAAA,QACR,IAAI,WAAW,iCAAiC,KAAK,SAAS,WAAW,SAAS,YAAY,UAAU,KAAK,YAAY;AAAA,MAC3H;AAAA,IACF;AAEA,eAAW,IAAI,KAAK,WAAW,IAAI;AAAA,EACrC;AAEA,SAAO;AACT;;;AClEA,OAAOC,WAAU;AACjB,OAAO,QAAQ;AACf,SAAS,kBAAkB;;;ACA3B,SAAS,GAAG,OAAwB;AAClC,SAAO,KAAK,UAAU,KAAK;AAC7B;AAEO,SAAS,qBAAqB,SAA+B;AAClE,QAAM,UAAU,QACb,IAAI,CAAC,MAAM,MAAM,mBAAmB,CAAC,SAAS,GAAG,KAAK,SAAS,CAAC,GAAG,EACnE,KAAK,IAAI;AAEZ,QAAM,UAAU,QACb;AAAA,IACC,CAAC,MAAM,MAAM;AAAA,UACT,GAAG,IAAI,CAAC;AAAA,aACL,CAAC;AAAA;AAAA,EAEV,EACC,KAAK,KAAK;AAEb,SAAO,GAAG,OAAO;AAAA;AAAA;AAAA,EAGjB,OAAO;AAAA;AAAA;AAGT;;;ADjBA,eAAe,uBACb,SACA,gBACiB;AACjB,QAAM,OAAO,WAAW,QAAQ;AAChC,OAAK,OAAO,cAAc;AAE1B,aAAW,SAAS,SAAS;AAC3B,SAAK,OAAO,MAAM,SAAS;AAC3B,UAAM,SAAS,MAAM,GAAG,SAAS,MAAM,WAAW,MAAM;AACxD,SAAK,OAAO,MAAM;AAAA,EACpB;AAEA,SAAO,KAAK,OAAO,KAAK,EAAE,MAAM,GAAG,EAAE;AACvC;AAEA,eAAsB,kBAAkB,MAIpB;AAClB,QAAM,EAAE,SAAS,UAAU,aAAa,CAAC,EAAE,IAAI;AAE/C,QAAM,CAAC,EAAE,OAAO,GAAG,EAAE,YAAY,CAAC,IAAI,MAAM,QAAQ,IAAI;AAAA,IACtD,OAAO,QAAQ;AAAA,IACf,OAAO,6BAA6B;AAAA,EACtC,CAAC;AAED,QAAM,iBAAiB,qBAAqB,OAAO;AACnD,QAAM,OAAO,MAAM,uBAAuB,SAAS,cAAc;AACjE,QAAM,aAAaC,MAAK,KAAK,UAAU,UAAU,IAAI,MAAM;AAE3D,QAAM,GAAG,MAAM,UAAU,EAAE,WAAW,KAAK,CAAC;AAE5C,MAAI;AACF,UAAM,GAAG,OAAO,UAAU;AAC1B,WAAO;AAAA,EACT,QAAQ;AAAA,EAER;AAEA,QAAM,SAAS,MAAM,OAAO;AAAA,IAC1B,OAAO;AAAA,IACP,SAAS;AAAA,MACP;AAAA,QACE,MAAM,GAAG,WAAW;AAAA,QACpB,UAAU,IAAI;AACZ,iBAAO,OAAO,sBAAsB,KAAK;AAAA,QAC3C;AAAA,QACA,KAAK,IAAI;AACP,iBAAO,OAAO,sBAAsB,iBAAiB;AAAA,QACvD;AAAA,MACF;AAAA,MACA,YAAY;AAAA,QACV,gBAAgB;AAAA,QAChB,kBAAkB,CAAC,MAAM;AAAA,MAC3B,CAAC;AAAA,MACD,GAAG;AAAA,IACL;AAAA,IACA,WAAW;AAAA,EACb,CAAC;AAED,MAAI;AACF,UAAM,EAAE,OAAO,IAAI,MAAM,OAAO,SAAS;AAAA,MACvC,QAAQ;AAAA,MACR,SAAS;AAAA,MACT,sBAAsB;AAAA,IACxB,CAAC;AAED,UAAM,QAAQ,OAAO,KAAK,CAAC,SAAS,KAAK,SAAS,OAAO;AAEzD,QAAI,CAAC,SAAS,MAAM,SAAS,SAAS;AACpC,YAAM,IAAI;AAAA,QACR,IAAI,WAAW;AAAA,MACjB;AAAA,IACF;AAEA,UAAM,GAAG,UAAU,YAAY,MAAM,MAAM,MAAM;AACjD,WAAO;AAAA,EACT,UAAE;AACA,UAAM,OAAO,MAAM;AAAA,EACrB;AACF;;;ATzEA,SAAS,WAAc,OAAY,MAAqB;AACtD,QAAM,MAAa,CAAC;AACpB,WAAS,IAAI,GAAG,IAAI,MAAM,QAAQ,KAAK,MAAM;AAC3C,QAAI,KAAK,MAAM,MAAM,GAAG,IAAI,IAAI,CAAC;AAAA,EACnC;AACA,SAAO;AACT;AAEA,eAAe,eACb,YACyD;AACzD,QAAM,MAAM,MAAM,OAAO,cAAc,UAAU,EAAE,OAAO,MAAM,KAAK,IAAI,CAAC;AAC1E,SAAO,IAAI;AACb;AAEO,SAAS,QAAQ,UAAgC,CAAC,GAAW;AAClE,MAAI,OAAO,QAAQ,IAAI;AACvB,MAAI,SAA+B;AACnC,MAAI,WAAyB,CAAC;AAE9B,QAAM,YAAY,QAAQ,aAAa;AAEvC,WAAS,SAAS,YAAiC,MAAiB;AAClE,QAAI,CAAC,QAAS;AACd,YAAQ,IAAI,IAAI,WAAW,KAAK,GAAG,IAAI;AAAA,EACzC;AAEA,iBAAe,eAAsC;AACnD,UAAM,UAAU,MAAM,mBAAmB,MAAM,OAAO;AACtD,UAAM,iBAAiB,oBAAI,IAA0B;AAErD;AAAA,MACE,QAAQ;AAAA,MACR;AAAA,MACA,QAAQ,IAAI,CAAC,MAAM,EAAE,YAAY;AAAA,IACnC;AAEA,QAAI,CAAC,OAAQ,QAAO,CAAC;AAErB,eAAW,SAAS,SAAS;AAC3B,YAAM,MAAO,MAAM,OAAO;AAAA,QACxB,IAAI,MAAM,YAAY;AAAA,MACxB;AAEA,qBAAe,IAAI,MAAM,WAAW,GAAG;AAAA,IACzC;AAEA,eAAW,MAAM,eAAe;AAAA,MAC9B;AAAA,MACA;AAAA,MACA;AAAA,IACF,CAAC;AAED;AAAA,MACE,QAAQ;AAAA,MACR;AAAA,MACA,SAAS,IAAI,CAAC,MAAM,GAAG,EAAE,SAAS,OAAO,EAAE,YAAY,EAAE;AAAA,IAC3D;AAEA,WAAO;AAAA,EACT;AAEA,iBAAe,qBAAqB;AAClC,UAAM,UAAU,MAAM,mBAAmB,MAAM,OAAO;AACtD,UAAM,WAAWC,MAAK,KAAK,MAAM,cAAc;AAE/C,UAAM,aAAa,MAAM,kBAAkB;AAAA,MACzC;AAAA,MACA;AAAA,MACA,YAAY,QAAQ;AAAA,IACtB,CAAC;AAED,aAAS,QAAQ,OAAO,iBAAiB,UAAU;AAEnD,UAAM,WAAW,MAAM,eAAe,UAAU;AAChD,UAAM,iBAAiB,oBAAI,IAA0B;AAErD,eAAW,OAAO,UAAU;AAC1B,qBAAe,IAAI,IAAI,KAAK,WAAW,IAAI,GAAG;AAAA,IAChD;AAEA,UAAM,QAAQ,MAAM,eAAe;AAAA,MACjC;AAAA,MACA;AAAA,MACA;AAAA,IACF,CAAC;AAED,WAAO,EAAE,SAAS,YAAY,gBAAgB,MAAM;AAAA,EACtD;AAEA,SAAO;AAAA,IACL,MAAM;AAAA,IAEN,OAAO,YAAY,KAAK;AACtB,UAAI,IAAI,YAAY,QAAS;AAE7B,YAAM,mBAAmB,WAAW,OAAO,eAAe,SAAS;AACnE,UAAI,iBAAkB;AAEtB,aAAO;AAAA,QACL,OAAO;AAAA,UACL,eAAe;AAAA,YACb,OAAO;AAAA,UACT;AAAA,QACF;AAAA,MACF;AAAA,IACF;AAAA,IAEA,UAAU,IAAI;AACZ,UAAI,OAAO,uBAAwB,QAAO;AAC1C,aAAO;AAAA,IACT;AAAA,IAEA,KAAK,IAAI;AACP,UAAI,OAAO,wBAAwB;AACjC,eAAO;AAAA,MACT;AACA,aAAO;AAAA,IACT;AAAA,IAEA,eAAe,UAAU;AACvB,aAAO,SAAS;AAAA,IAClB;AAAA,IAEA,MAAM,aAAa;AACjB,YAAM,UAAU,MAAM,mBAAmB,MAAM,OAAO;AAEtD,iBAAW,SAAS,SAAS;AAC3B,aAAK,aAAa,MAAM,SAAS;AAAA,MACnC;AAAA,IACF;AAAA,IAEA,gBAAgB,SAAS;AACvB,eAAS;AAET,uBAAiB;AAAA,QACf;AAAA,QACA,UAAU,YAAY;AACpB,cAAI,SAAS,SAAS,EAAG,QAAO;AAChC,iBAAO,aAAa;AAAA,QACtB;AAAA,QACA,YAAY,YAAY,mBAAmB,MAAM,OAAO;AAAA,MAC1D,CAAC;AAED,mBAAa,EAAE,MAAM,CAAC,UAAU;AAC9B,gBAAQ,OAAO,OAAO;AAAA,UACpB,IAAI,WAAW,0BACb,iBAAiB,QAAQ,MAAM,SAAS,MAAM,UAAU,OAAO,KAAK,CACtE;AAAA,QACF;AAAA,MACF,CAAC;AAAA,IACH;AAAA,IAEA,MAAM,gBAAgB,KAAK;AACzB,UAAI,CAAC,OAAQ;AAEb,UAAI,CAAC,IAAI,KAAK,SAAS,QAAQ,GAAG;AAChC;AAAA,MACF;AAEA,eAAS,QAAQ,OAAO,gBAAgB,IAAI,IAAI;AAEhD,YAAM,aAAa;AACnB,aAAO;AAAA,IACT;AAAA,IAEA,MAAM,eAAe,GAAG,QAAQ;AAC9B,YAAM,EAAE,gBAAgB,MAAM,IAAI,MAAM,mBAAmB;AAE3D;AAAA,QACE,QAAQ;AAAA,QACR;AAAA,QACA,MAAM,IAAI,CAAC,MAAM,EAAE,QAAQ;AAAA,MAC7B;AAEA,YAAM,QAAQ,OAAO,QAAQ,qBAAqB,CAAC;AACnD,YAAM,YACJ,QAAQ,mBACR,KAAK,IAAI,QAAQ,qBAAqB,GAAG,EAAE;AAE7C,iBAAW,SAAS,WAAW,OAAO,SAAS,GAAG;AAChD,cAAM,QAAQ;AAAA,UACZ,MAAM;AAAA,YAAI,CAAC,SACT,MAAM,YAAY;AAChB,oBAAM,MAAM,eAAe,IAAI,KAAK,SAAS;AAC7C,kBAAI,CAAC,KAAK;AACR,sBAAM,IAAI;AAAA,kBACR,IAAI,WAAW,oCAAoC,KAAK,SAAS;AAAA,gBACnE;AAAA,cACF;AAEA,oBAAM,OAAO,MAAM,WAAW,MAAM,KAAK,KAAK;AAE9C,mBAAK,SAAS;AAAA,gBACZ,MAAM;AAAA,gBACN,UAAU,QAAQ,gBAAgB,IAAI,KAAK,KAAK;AAAA,gBAChD,QAAQ;AAAA,cACV,CAAC;AAAA,YACH,CAAC;AAAA,UACH;AAAA,QACF;AAAA,MACF;AAEA,YAAM,cAAc,QAAQ,QAAQ;AACpC,YAAM,gBAAgB,CAAC,GAAG,IAAI,IAAI,MAAM,IAAI,CAAC,MAAM,EAAE,SAAS,CAAC,CAAC,EAAE;AAAA,QAChE,CAAC,UAAU,CAAC,MAAM,SAAS,GAAG,KAAK,CAAC,MAAM,SAAS,GAAG;AAAA,MACxD;AAEA,UAAI,cAAc,SAAS,GAAG;AAC5B,cAAM,UAAU;AAAA;AAAA,EAAyG,cACtH,IAAI,CAAC,UAAU,eAAe,WAAW,GAAG,KAAK,cAAc,EAC/D,KAAK,IAAI,CAAC;AAAA;AAAA;AAEb,aAAK,SAAS;AAAA,UACZ,MAAM;AAAA,UACN,UAAU;AAAA,UACV,QAAQ;AAAA,QACV,CAAC;AAAA,MACH;AAEA,UAAI,QAAQ,KAAK,MAAM;AACrB,cAAM,cAAc,QAAQ,IAAI,eAAe;AAE/C,cAAM,WAAW,MACd,OAAO,CAAC,SAAS,KAAK,UAAU,WAAW,WAAW,CAAC,EACvD,IAAI,CAAC,SAAS;AACb,gBAAM,MAAM,GAAG,QAAQ,IAAK,IAAI,GAAG,KAAK,SAAS;AACjD,iBAAO;AAAA,aAAwB,KAAK,SAAS;AAAA,YAAuB,GAAG;AAAA,YAAsB,GAAG;AAAA;AAAA,QAClG,CAAC,EACA,KAAK,IAAI;AAEZ,cAAM,MAAM;AAAA;AAAA;AAAA,WAAoF,QAAQ,IAAI,SAAS,WAAW;AAAA,UAAqB,QAAQ,IAAI,IAAI;AAAA,iBAA2B,QAAQ,IAAI,eAAe,UAAU;AAAA,EAAmB,QAAQ;AAAA;AAAA;AAAA;AAEhQ,aAAK,SAAS;AAAA,UACZ,MAAM;AAAA,UACN,UAAU;AAAA,UACV,QAAQ;AAAA,QACV,CAAC;AAAA,MACH;AAEA,iBAAW,CAAC,UAAU,MAAM,KAAK,OAAO,QAAQ,MAAM,GAAG;AACvD,YACE,OAAO,SAAS,WAChB,OAAO,mBAAmB,wBAC1B;AACA,iBAAO,OAAO,QAAQ;AAAA,QACxB;AAAA,MACF;AAAA,IACF;AAAA,EACF;AACF;;;AW5QA,OAAOC,SAAQ;AACf,OAAOC,WAAU;AACjB,SAAS,cAAAC,mBAAkB;AAiB3B,SAAS,sBACP,OACA,MACQ;AACR,QAAM,MAAM,KAAK,UAAU;AAAA,IACzB,KAAK,OAAO,KAAK;AAAA,IACjB,QAAQ,MAAM,UAAU;AAAA,IACxB,SAAS,MAAM,WAAW,CAAC;AAAA,IAC3B,MAAM,MAAM,QAAQ;AAAA,EACtB,CAAC;AAED,SAAOC,YAAW,QAAQ,EAAE,OAAO,GAAG,EAAE,OAAO,KAAK;AACtD;AAEA,SAAS,iBAAiB,UAA0B;AAClD,SAAOC,MAAK,KAAK,QAAQ,IAAI,GAAG,gBAAgB,SAAS,GAAG,QAAQ,OAAO;AAC7E;AAEA,eAAsB,cACpB,OACA,MACA,UAAgC,CAAC,GACd;AACnB,QAAM,SAAS,QAAQ,UAAU,KAAK;AACtC,QAAM,UAAU,MAAM,UAAU,OAAO,YAAY;AAEnD,MAAI,WAAW,SAAS,CAAC,QAAQ,UAAU;AACzC,WAAO,MAAM,OAAO,IAAI;AAAA,EAC1B;AAEA,QAAM,WAAW,QAAQ,YAAY,sBAAsB,OAAO,IAAI;AACtE,QAAM,WAAW,iBAAiB,QAAQ;AAE1C,QAAMC,IAAG,MAAMD,MAAK,QAAQ,QAAQ,GAAG,EAAE,WAAW,KAAK,CAAC;AAE1D,MAAI,CAAC,QAAQ,cAAc;AACzB,QAAI;AACF,YAAM,MAAM,MAAMC,IAAG,SAAS,UAAU,MAAM;AAC9C,YAAM,SAAS,KAAK,MAAM,GAAG;AAE7B,YAAM,cAAc,KAAK,IAAI,IAAI,OAAO,aAAa;AAErD,UAAI,cAAc,QAAQ;AACxB,eAAO,IAAI,SAAS,OAAO,MAAM;AAAA,UAC/B,QAAQ,OAAO;AAAA,UACf,YAAY,OAAO;AAAA,UACnB,SAAS,OAAO;AAAA,QAClB,CAAC;AAAA,MACH;AAAA,IACF,QAAQ;AAAA,IAER;AAAA,EACF;AAEA,QAAM,MAAM,MAAM,MAAM,OAAO,IAAI;AACnC,QAAM,OAAO,MAAM,IAAI,KAAK;AAE5B,QAAM,SAA+B;AAAA,IACnC,WAAW,KAAK,IAAI;AAAA,IACpB,QAAQ,IAAI;AAAA,IACZ,YAAY,IAAI;AAAA,IAChB,SAAS,CAAC,GAAG,IAAI,QAAQ,QAAQ,CAAC;AAAA,IAClC;AAAA,EACF;AAEA,QAAMA,IAAG,UAAU,UAAU,KAAK,UAAU,MAAM,GAAG,MAAM;AAE3D,SAAO,IAAI,SAAS,MAAM;AAAA,IACxB,QAAQ,IAAI;AAAA,IACZ,YAAY,IAAI;AAAA,IAChB,SAAS,IAAI;AAAA,EACf,CAAC;AACH;","names":["path","path","path","path","path","path","fs","path","createHash","createHash","path","fs"]}
|
|
1
|
+
{"version":3,"sources":["../src/plugin.ts","../src/discover.ts","../src/path-utils.ts","../src/route-utils.ts","../src/constants.ts","../src/errors.ts","../src/render-runtime.ts","../src/dev-server.ts","../src/page-index.ts","../src/fetch-cache.ts"],"sourcesContent":["// import path from 'node:path';\nimport { pathToFileURL } from 'node:url';\nimport pLimit from 'p-limit';\nimport type { Plugin, ViteDevServer } from 'vite';\n\nimport { discoverEntryPages } from './discover';\nimport { installDevServer } from './dev-server';\nimport { buildPageIndex } from './page-index';\nimport { renderPage } from './render-runtime';\n\nimport type { HtPageInfo, HtPageModule, HtPagesPluginOptions } from './types';\nimport {\n PLUGIN_NAME,\n VIRTUAL_BUILD_ENTRY_ID,\n} from './constants';\n\nfunction chunkArray<T>(items: T[], size: number): T[][] {\n const out: T[][] = [];\n for (let i = 0; i < items.length; i += size) {\n out.push(items.slice(i, i + size));\n }\n return out;\n}\n\nasync function importPageModule(entryPath: string): Promise<HtPageModule> {\n const mod = await import(pathToFileURL(entryPath).href + `?t=${Date.now()}`);\n return mod as HtPageModule;\n}\n\nexport function htPages(options: HtPagesPluginOptions = {}): Plugin {\n let root = process.cwd();\n let server: ViteDevServer | null = null;\n let devPages: HtPageInfo[] = [];\n\n const cleanUrls = options.cleanUrls ?? true;\n\n function logDebug(enabled: boolean | undefined, ...args: unknown[]) {\n if (!enabled) return;\n console.log(`[${PLUGIN_NAME}]`, ...args);\n }\n\n async function loadDevPages(): Promise<HtPageInfo[]> {\n const entries = await discoverEntryPages(root, options);\n const modulesByEntry = new Map<string, HtPageModule>();\n\n logDebug(\n options.debug,\n 'discovered entries',\n entries.map((e) => e.relativePath),\n );\n\n if (!server) return [];\n\n for (const entry of entries) {\n const mod = (await server.ssrLoadModule(\n `/${entry.relativePath}`,\n )) as HtPageModule;\n\n modulesByEntry.set(entry.entryPath, mod);\n }\n\n devPages = await buildPageIndex({\n entries,\n modulesByEntry,\n cleanUrls,\n });\n\n logDebug(\n options.debug,\n 'dev pages',\n devPages.map((p) => `${p.routePath} -> ${p.relativePath}`),\n );\n\n return devPages;\n }\n\n async function buildPagesPipeline() {\n const entries = await discoverEntryPages(root, options);\n const modulesByEntry = new Map<string, HtPageModule>();\n\n for (const entry of entries) {\n const mod = await importPageModule(entry.entryPath);\n modulesByEntry.set(entry.entryPath, mod);\n }\n\n const pages = await buildPageIndex({\n entries,\n modulesByEntry,\n cleanUrls,\n });\n\n return { entries, modulesByEntry, pages };\n }\n\n return {\n name: PLUGIN_NAME,\n\n config(userConfig, env) {\n if (env.command !== 'build') return;\n\n const hasExplicitInput = userConfig.build?.rollupOptions?.input != null;\n if (hasExplicitInput) return;\n\n return {\n build: {\n rollupOptions: {\n input: VIRTUAL_BUILD_ENTRY_ID,\n },\n },\n };\n },\n\n resolveId(id) {\n if (id === VIRTUAL_BUILD_ENTRY_ID) return id;\n return null;\n },\n\n load(id) {\n if (id === VIRTUAL_BUILD_ENTRY_ID) {\n return 'export default {};';\n }\n return null;\n },\n\n configResolved(resolved) {\n root = resolved.root;\n },\n\n async buildStart() {\n const entries = await discoverEntryPages(root, options);\n\n for (const entry of entries) {\n this.addWatchFile(entry.entryPath);\n }\n },\n\n configureServer(_server) {\n server = _server;\n\n installDevServer({\n server,\n getPages: async () => {\n if (devPages.length > 0) return devPages;\n return loadDevPages();\n },\n getEntries: async () => discoverEntryPages(root, options),\n });\n\n loadDevPages().catch((error) => {\n server?.config.logger.error(\n `[${PLUGIN_NAME}] loadDevPages failed: ${\n error instanceof Error ? error.stack ?? error.message : String(error)\n }`,\n );\n });\n },\n\n async handleHotUpdate(ctx) {\n if (!server) return;\n\n if (!ctx.file.endsWith('.ht.js')) {\n return;\n }\n\n logDebug(options.debug, 'page updated', ctx.file);\n await loadDevPages();\n return undefined;\n },\n\n async generateBundle(_, bundle) {\n const { modulesByEntry, pages } = await buildPagesPipeline();\n\n logDebug(\n options.debug,\n 'emitting pages',\n pages.map((p) => p.fileName),\n );\n\n const limit = pLimit(options.renderConcurrency ?? 8);\n const batchSize =\n options.renderBatchSize ??\n Math.max(options.renderConcurrency ?? 8, 32);\n\n for (const batch of chunkArray(pages, batchSize)) {\n await Promise.all(\n batch.map((page) =>\n limit(async () => {\n const mod = modulesByEntry.get(page.entryPath);\n if (!mod) {\n throw new Error(\n `[${PLUGIN_NAME}] Missing module for page entry: ${page.entryPath}`,\n );\n }\n\n const html = await renderPage(page, mod, false);\n\n this.emitFile({\n type: 'asset',\n fileName: options.mapOutputPath?.(page) ?? page.fileName,\n source: html,\n });\n }),\n ),\n );\n }\n\n const sitemapBase = options.site ?? '';\n const sitemapRoutes = [...new Set(pages.map((p) => p.routePath))].filter(\n (route) => !route.includes(':') && !route.includes('*'),\n );\n\n if (sitemapRoutes.length > 0) {\n const sitemap = `<?xml version=\"1.0\" encoding=\"UTF-8\"?>\\n<urlset xmlns=\"http://www.sitemaps.org/schemas/sitemap/0.9\">\\n${sitemapRoutes\n .map((route) => ` <url><loc>${sitemapBase}${route}</loc></url>`)\n .join('\\n')}\\n</urlset>\\n`;\n\n this.emitFile({\n type: 'asset',\n fileName: 'sitemap.xml',\n source: sitemap,\n });\n }\n\n if (options.rss?.site) {\n const routePrefix = options.rss.routePrefix ?? '/blog';\n\n const rssItems = pages\n .filter((page) => page.routePath.startsWith(routePrefix))\n .map((page) => {\n const url = `${options.rss!.site}${page.routePath}`;\n return ` <item>\\n <title>${page.routePath}</title>\\n <link>${url}</link>\\n <guid>${url}</guid>\\n </item>`;\n })\n .join('\\n');\n\n const rss = `<?xml version=\"1.0\" encoding=\"UTF-8\"?>\\n<rss version=\"2.0\">\\n<channel>\\n <title>${options.rss.title ?? PLUGIN_NAME}</title>\\n <link>${options.rss.site}</link>\\n <description>${options.rss.description ?? 'RSS feed'}</description>\\n${rssItems}\\n</channel>\\n</rss>\\n`;\n\n this.emitFile({\n type: 'asset',\n fileName: 'rss.xml',\n source: rss,\n });\n }\n\n for (const [fileName, output] of Object.entries(bundle)) {\n if (\n output.type === 'chunk' &&\n output.facadeModuleId === VIRTUAL_BUILD_ENTRY_ID\n ) {\n delete bundle[fileName];\n }\n }\n },\n };\n}","import path from 'node:path';\nimport { normalizeFsPath, toPosix } from './path-utils';\nimport { getParamNames, isDynamicPage, toRoutePattern } from './route-utils';\nimport type { HtPageInfo, HtPagesPluginOptions } from './types';\nimport { PLUGIN_NAME } from './constants';\n\nexport async function discoverEntryPages(\n root: string,\n options: HtPagesPluginOptions,\n): Promise<HtPageInfo[]> {\n const fgModule = await import('fast-glob');\n const fg = (fgModule.default ?? fgModule) as typeof import('fast-glob');\n\n const include = Array.isArray(options.include)\n ? options.include\n : [options.include ?? 'src/**/*.ht.js'];\n\n const exclude = Array.isArray(options.exclude)\n ? options.exclude\n : options.exclude\n ? [options.exclude]\n : [];\n\n const pagesDir = options.pagesDir ?? 'src';\n const pagesRoot = normalizeFsPath(path.join(root, pagesDir));\n\n const files = await fg.glob(include, {\n cwd: root,\n ignore: exclude,\n absolute: true,\n });\n\n return files\n .sort()\n .map((absolutePath) => {\n const entryPath = normalizeFsPath(absolutePath);\n const relativePath = toPosix(path.relative(root, entryPath));\n const relativeFromPagesDir = toPosix(path.relative(pagesRoot, entryPath));\n\n if (\n relativeFromPagesDir.startsWith('../') ||\n relativeFromPagesDir === '..'\n ) {\n throw new Error(\n `[${PLUGIN_NAME}] Page is outside pagesDir: ${entryPath} (pagesDir: ${pagesDir})`,\n );\n }\n\n const dynamic = isDynamicPage(relativeFromPagesDir);\n const routePattern = toRoutePattern(relativeFromPagesDir);\n\n return {\n id: entryPath,\n entryPath,\n absolutePath: entryPath,\n relativePath,\n routePattern,\n routePath: routePattern,\n fileName: '',\n dynamic,\n paramNames: getParamNames(relativeFromPagesDir),\n params: {},\n } satisfies HtPageInfo;\n });\n}","import path from 'node:path';\n\nexport function toPosix(p: string): string {\n return p.split(path.sep).join('/');\n}\n\nexport function stripHtSuffix(file: string): string {\n return file.replace(/\\.ht\\.js$/i, '');\n}\n\nexport function normalizeRoutePath(p: string): string {\n let out = p.startsWith('/') ? p : `/${p}`;\n out = out.replace(/\\/+/g, '/');\n if (out !== '/' && out.endsWith('/')) out = out.slice(0, -1);\n return out;\n}\n\nexport function normalizeFsPath(p: string): string {\n return toPosix(path.resolve(p));\n}","import { normalizeRoutePath, stripHtSuffix, toPosix } from './path-utils';\nimport type { HtPageInfo, StaticParamRecord } from './types';\n\nfunction safeDecodeURIComponent(str: string): string {\n try {\n return decodeURIComponent(str);\n } catch {\n return str;\n }\n}\n\nconst DYNAMIC_SEGMENT_RE = /\\[([A-Za-z0-9_]+)\\]/g;\nconst CATCH_ALL_SEGMENT_RE = /\\[\\.\\.\\.([A-Za-z0-9_]+)\\]/g;\nconst OPTIONAL_CATCH_ALL_SEGMENT_RE = /\\[\\.\\.\\.([A-Za-z0-9_]+)\\]\\?/g;\nconst ANY_PARAM_RE = /\\[(?:\\.\\.\\.)?([A-Za-z0-9_]+)\\]\\??/g;\nconst ROUTE_GROUP_RE = /(^|\\/)\\(([^)]+)\\)(?=\\/|$)/g;\n\nexport function getParamNames(relativeFromPagesDir: string): string[] {\n return [...relativeFromPagesDir.matchAll(ANY_PARAM_RE)].map((m) => m[1]);\n}\n\nexport function isDynamicPage(relativeFromPagesDir: string): boolean {\n return /\\[(?:\\.\\.\\.)?[A-Za-z0-9_]+\\]\\??/.test(relativeFromPagesDir);\n}\n\nexport function toRoutePattern(relativeFromPagesDir: string): string {\n const noExt = stripHtSuffix(toPosix(relativeFromPagesDir));\n\n const withoutGroups = noExt.replace(ROUTE_GROUP_RE, '$1');\n const withoutIndex = withoutGroups.replace(/\\/index$/i, '').replace(/^index$/i, '');\n\n const raw = withoutIndex\n .replace(OPTIONAL_CATCH_ALL_SEGMENT_RE, '*?:$1')\n .replace(CATCH_ALL_SEGMENT_RE, '*:$1')\n .replace(DYNAMIC_SEGMENT_RE, ':$1');\n\n return normalizeRoutePath(raw || '/');\n}\n\nexport function fillParams(\n pattern: string,\n params: Record<string, string>,\n): string {\n const result = pattern\n .replace(/\\*\\?:([A-Za-z0-9_]+)/g, (_, key) => {\n const value = params[key];\n if (value == null || value === '') {\n return '';\n }\n\n return String(value)\n .split('/')\n .map((part) => encodeURIComponent(part))\n .join('/');\n })\n .replace(/\\*:([A-Za-z0-9_]+)/g, (_, key) => {\n if (!(key in params)) {\n throw new Error(`Missing catch-all route param \"${key}\"`);\n }\n\n return String(params[key])\n .split('/')\n .map((part) => encodeURIComponent(part))\n .join('/');\n })\n .replace(/:([A-Za-z0-9_]+)/g, (_, key) => {\n if (!(key in params)) {\n throw new Error(`Missing route param \"${key}\"`);\n }\n\n return encodeURIComponent(params[key]);\n });\n\n return normalizeRoutePath(result || '/');\n}\n\nexport function fileNameFromRoute(\n routePath: string,\n cleanUrls: boolean,\n): string {\n const normalized = normalizeRoutePath(routePath);\n\n if (normalized === '/') return 'index.html';\n\n const base = normalized.slice(1);\n return cleanUrls ? `${base}/index.html` : `${base}.html`;\n}\n\nexport function expandStaticPaths(\n basePage: Omit<HtPageInfo, 'routePath' | 'fileName' | 'params'>,\n rows: StaticParamRecord[],\n cleanUrls: boolean,\n): HtPageInfo[] {\n return rows.map((row) => {\n const params = Object.fromEntries(\n Object.entries(row).map(([k, v]) => [k, String(v)]),\n );\n\n const routePath = fillParams(basePage.routePattern, params);\n\n return {\n ...basePage,\n routePath,\n fileName: fileNameFromRoute(routePath, cleanUrls),\n params,\n };\n });\n}\n\nexport function routeMatch(\n pattern: string,\n urlPath: string,\n): Record<string, string> | null {\n const a = normalizeRoutePath(pattern).split('/').filter(Boolean);\n const b = normalizeRoutePath(urlPath).split('/').filter(Boolean);\n const params: Record<string, string> = {};\n\n for (let i = 0; i < a.length; i++) {\n const patternSeg = a[i];\n const urlSeg = b[i];\n\n if (patternSeg.startsWith('*?:')) {\n params[patternSeg.slice(3)] =\n i < b.length ? b.slice(i).map(safeDecodeURIComponent).join('/') : '';\n return params;\n }\n\n if (patternSeg.startsWith('*:')) {\n const rest = b.slice(i);\n if (rest.length === 0) return null;\n\n params[patternSeg.slice(2)] = rest.map(safeDecodeURIComponent).join('/');\n return params;\n }\n\n if (!urlSeg) return null;\n\n if (patternSeg.startsWith(':')) {\n params[patternSeg.slice(1)] = safeDecodeURIComponent(urlSeg);\n continue;\n }\n\n if (patternSeg !== urlSeg) return null;\n }\n\n return a.length === b.length ? params : null;\n}\n\nexport function compareRoutePriority(a: string, b: string): number {\n const aSegs = normalizeRoutePath(a).split('/').filter(Boolean);\n const bSegs = normalizeRoutePath(b).split('/').filter(Boolean);\n const len = Math.max(aSegs.length, bSegs.length);\n\n for (let i = 0; i < len; i++) {\n const aa = aSegs[i];\n const bb = bSegs[i];\n\n if (aa == null) return 1;\n if (bb == null) return -1;\n\n const aOptionalCatchAll = aa.startsWith('*?:');\n const bOptionalCatchAll = bb.startsWith('*?:');\n if (aOptionalCatchAll !== bOptionalCatchAll) {\n return aOptionalCatchAll ? 1 : -1;\n }\n\n const aCatchAll = aa.startsWith('*:');\n const bCatchAll = bb.startsWith('*:');\n if (aCatchAll !== bCatchAll) {\n return aCatchAll ? 1 : -1;\n }\n\n const aDynamic = aa.startsWith(':');\n const bDynamic = bb.startsWith(':');\n if (aDynamic !== bDynamic) {\n return aDynamic ? 1 : -1;\n }\n }\n\n // More specific / longer routes first when otherwise equal\n return bSegs.length - aSegs.length;\n}","export const PLUGIN_NAME = 'vite-plugin-htjs-pages';\nexport const VIRTUAL_BUILD_ENTRY_ID = `\\0${PLUGIN_NAME}:build-entry`;\nexport const VIRTUAL_MANIFEST_ID = `\\0virtual:${PLUGIN_NAME}-manifest`;\nexport const CACHE_DIR_NAME = `node_modules/.cache/${PLUGIN_NAME}`;","import type { HtPageInfo } from './types';\nimport { PLUGIN_NAME } from './constants';\nexport function invalidHtmlReturn(\n page: HtPageInfo,\n value: unknown,\n): Error {\n return new Error(\n `[${PLUGIN_NAME}] Page \"${page.relativePath}\" must resolve to an HTML string, got ${typeof value}`,\n );\n}\n\nexport function missingDefaultExport(page: HtPageInfo): Error {\n return new Error(\n `[${PLUGIN_NAME}] Page \"${page.relativePath}\" does not export a default renderer`,\n );\n}\n\nexport function pageError(page: HtPageInfo, cause: unknown): Error {\n const message = `[${PLUGIN_NAME}] Failed to render \"${page.relativePath}\" at route \"${page.routePath}\"`;\n\n if (cause instanceof Error) {\n const err = new Error(`${message}: ${cause.message}`);\n\n if (cause.stack) {\n err.stack = `${err.stack}\\nCaused by:\\n${cause.stack}`;\n }\n\n return err;\n }\n\n return new Error(`${message}: ${String(cause)}`);\n}","import { invalidHtmlReturn, pageError, missingDefaultExport } from './errors';\nimport type { HtPageInfo, HtPageModule, HtPageRenderContext } from './types';\n\nexport async function renderPage(\n page: HtPageInfo,\n mod: HtPageModule,\n dev = false,\n): Promise<string> {\n const ctx: HtPageRenderContext = {\n page,\n params: page.params,\n dev,\n };\n\n try {\n if (typeof mod.data === 'function') {\n ctx.data = await mod.data(ctx);\n }\n\n const entry = mod.default;\n\n if (entry == null) {\n throw missingDefaultExport(page);\n }\n\n const html = typeof entry === 'function' ? await entry(ctx) : entry;\n\n if (typeof html !== 'string') {\n throw invalidHtmlReturn(page, html);\n }\n\n return html;\n } catch (error) {\n throw pageError(page, error);\n }\n}","import type { ViteDevServer } from 'vite';\nimport { renderPage } from './render-runtime';\nimport { routeMatch } from './route-utils';\nimport type { HtPageInfo, HtPageModule } from './types';\n\nfunction isDynamicOnly(mod: HtPageModule): boolean {\n return mod.dynamic === true || mod.prerender === false;\n}\n\nexport function installDevServer(args: {\n server: ViteDevServer;\n getPages: () => Promise<HtPageInfo[]>;\n getEntries: () => Promise<HtPageInfo[]>;\n}): void {\n const { server, getPages, getEntries } = args;\n\n server.middlewares.use(async (req, res, next) => {\n try {\n if (!req.url || req.method !== 'GET') return next();\n\n const pathname = req.url.split('?')[0];\n\n const pages = await getPages();\n const staticPage = pages.find((p) => p.routePath === pathname);\n\n if (staticPage) {\n const mod = (await server.ssrLoadModule(\n `/${staticPage.relativePath}`,\n )) as HtPageModule;\n\n const html = await renderPage(staticPage, mod, true);\n\n res.statusCode = 200;\n res.setHeader('Content-Type', 'text/html; charset=utf-8');\n res.end(html);\n return;\n }\n\n const entries = await getEntries();\n\n for (const entry of entries) {\n const mod = (await server.ssrLoadModule(\n `/${entry.relativePath}`,\n )) as HtPageModule;\n\n if (!isDynamicOnly(mod)) continue;\n\n const params = routeMatch(entry.routePattern, pathname);\n if (!params) continue;\n\n const page: HtPageInfo = {\n ...entry,\n routePath: pathname,\n fileName: '',\n params,\n };\n\n const html = await renderPage(page, mod, true);\n\n res.statusCode = 200;\n res.setHeader('Content-Type', 'text/html; charset=utf-8');\n res.end(html);\n return;\n }\n\n next();\n } catch (error) {\n next(error);\n }\n });\n}","import {\n compareRoutePriority,\n expandStaticPaths,\n fileNameFromRoute,\n} from './route-utils';\nimport type { HtPageInfo, HtPageModule, StaticParamRecord } from './types';\nimport { PLUGIN_NAME } from './constants';\nexport async function buildPageIndex(args: {\n entries: HtPageInfo[];\n modulesByEntry: Map<string, HtPageModule>;\n cleanUrls: boolean;\n}): Promise<HtPageInfo[]> {\n const { entries, modulesByEntry, cleanUrls } = args;\n const pages: HtPageInfo[] = [];\n\n for (const entry of entries) {\n const mod = modulesByEntry.get(entry.entryPath) ?? {};\n\n if (entry.dynamic) {\n const rows =\n (mod.generateStaticParams\n ? await mod.generateStaticParams()\n : []) ?? [];\n\n pages.push(\n ...expandStaticPaths(\n {\n id: entry.id,\n entryPath: entry.entryPath,\n absolutePath: entry.absolutePath,\n relativePath: entry.relativePath,\n routePattern: entry.routePattern,\n dynamic: entry.dynamic,\n paramNames: entry.paramNames,\n } as Omit<HtPageInfo, 'routePath' | 'fileName' | 'params'>,\n Array.isArray(rows) ? rows : [],\n cleanUrls,\n ),\n );\n } else {\n pages.push({\n ...entry,\n routePath: entry.routePattern,\n fileName: fileNameFromRoute(entry.routePattern, cleanUrls),\n params: {},\n });\n }\n }\n\n pages.sort((a, b) => compareRoutePriority(a.routePattern, b.routePattern));\n\n const seenRoutes = new Map<string, HtPageInfo>();\n\n for (const page of pages) {\n const existing = seenRoutes.get(page.routePath);\n\n if (existing) {\n throw new Error(\n `[${PLUGIN_NAME}] Duplicate route generated: \"${page.routePath}\" from \"${existing.relativePath}\" and \"${page.relativePath}\"`,\n );\n }\n\n seenRoutes.set(page.routePath, page);\n }\n\n return pages;\n}","import fs from 'node:fs/promises';\nimport path from 'node:path';\nimport { createHash } from 'node:crypto';\nimport { CACHE_DIR_NAME } from './constants';\n\nexport interface FetchAndCacheOptions {\n maxAge?: number;\n cacheKey?: string;\n forceRefresh?: boolean;\n}\n\ntype CachedResponseRecord = {\n timestamp: number;\n status: number;\n statusText: string;\n headers: [string, string][];\n body: string;\n};\n\nfunction createDefaultCacheKey(\n input: RequestInfo | URL,\n init?: RequestInit,\n): string {\n const raw = JSON.stringify({\n url: String(input),\n method: init?.method ?? 'GET',\n headers: init?.headers ?? {},\n body: init?.body ?? null,\n });\n\n return createHash('sha256').update(raw).digest('hex');\n}\n\nfunction getCacheFilePath(cacheKey: string): string {\n return path.join(process.cwd(), CACHE_DIR_NAME, 'fetch', `${cacheKey}.json`);\n}\n\nexport async function fetchAndCache(\n input: RequestInfo | URL,\n init?: RequestInit,\n options: FetchAndCacheOptions = {},\n): Promise<Response> {\n const maxAge = options.maxAge ?? 60 * 60;\n const method = (init?.method ?? 'GET').toUpperCase();\n\n if (method !== 'GET' && !options.cacheKey) {\n return fetch(input, init);\n }\n\n const cacheKey = options.cacheKey ?? createDefaultCacheKey(input, init);\n const filePath = getCacheFilePath(cacheKey);\n\n await fs.mkdir(path.dirname(filePath), { recursive: true });\n\n if (!options.forceRefresh) {\n try {\n const raw = await fs.readFile(filePath, 'utf8');\n const cached = JSON.parse(raw) as CachedResponseRecord;\n\n const ageSeconds = (Date.now() - cached.timestamp) / 1000;\n\n if (ageSeconds <= maxAge) {\n return new Response(cached.body, {\n status: cached.status,\n statusText: cached.statusText,\n headers: cached.headers,\n });\n }\n } catch {\n // cache miss or invalid cache; fetch fresh\n }\n }\n\n const res = await fetch(input, init);\n const body = await res.text();\n\n const record: CachedResponseRecord = {\n timestamp: Date.now(),\n status: res.status,\n statusText: res.statusText,\n headers: [...res.headers.entries()],\n body,\n };\n\n await fs.writeFile(filePath, JSON.stringify(record), 'utf8');\n\n return new Response(body, {\n status: res.status,\n statusText: res.statusText,\n headers: res.headers,\n });\n}\n"],"mappings":"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","names":["path","path","path","path"]}
|
package/package.json
CHANGED
package/src/plugin.ts
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import path from 'node:path';
|
|
1
|
+
// import path from 'node:path';
|
|
2
2
|
import { pathToFileURL } from 'node:url';
|
|
3
3
|
import pLimit from 'p-limit';
|
|
4
4
|
import type { Plugin, ViteDevServer } from 'vite';
|
|
@@ -6,14 +6,12 @@ import type { Plugin, ViteDevServer } from 'vite';
|
|
|
6
6
|
import { discoverEntryPages } from './discover';
|
|
7
7
|
import { installDevServer } from './dev-server';
|
|
8
8
|
import { buildPageIndex } from './page-index';
|
|
9
|
-
import { buildRenderBundle } from './render-bundle';
|
|
10
9
|
import { renderPage } from './render-runtime';
|
|
11
10
|
|
|
12
11
|
import type { HtPageInfo, HtPageModule, HtPagesPluginOptions } from './types';
|
|
13
12
|
import {
|
|
14
13
|
PLUGIN_NAME,
|
|
15
14
|
VIRTUAL_BUILD_ENTRY_ID,
|
|
16
|
-
CACHE_DIR_NAME,
|
|
17
15
|
} from './constants';
|
|
18
16
|
|
|
19
17
|
function chunkArray<T>(items: T[], size: number): T[][] {
|
|
@@ -24,11 +22,9 @@ function chunkArray<T>(items: T[], size: number): T[][] {
|
|
|
24
22
|
return out;
|
|
25
23
|
}
|
|
26
24
|
|
|
27
|
-
async function
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
const mod = await import(pathToFileURL(bundlePath).href + `?t=${Date.now()}`);
|
|
31
|
-
return mod.manifest as Array<{ page: HtPageInfo; mod: HtPageModule }>;
|
|
25
|
+
async function importPageModule(entryPath: string): Promise<HtPageModule> {
|
|
26
|
+
const mod = await import(pathToFileURL(entryPath).href + `?t=${Date.now()}`);
|
|
27
|
+
return mod as HtPageModule;
|
|
32
28
|
}
|
|
33
29
|
|
|
34
30
|
export function htPages(options: HtPagesPluginOptions = {}): Plugin {
|
|
@@ -80,21 +76,11 @@ export function htPages(options: HtPagesPluginOptions = {}): Plugin {
|
|
|
80
76
|
|
|
81
77
|
async function buildPagesPipeline() {
|
|
82
78
|
const entries = await discoverEntryPages(root, options);
|
|
83
|
-
const cacheDir = path.join(root, CACHE_DIR_NAME);
|
|
84
|
-
|
|
85
|
-
const bundlePath = await buildRenderBundle({
|
|
86
|
-
entries,
|
|
87
|
-
cacheDir,
|
|
88
|
-
ssrPlugins: options.ssrPlugins,
|
|
89
|
-
});
|
|
90
|
-
|
|
91
|
-
logDebug(options.debug, 'render bundle', bundlePath);
|
|
92
|
-
|
|
93
|
-
const manifest = await importManifest(bundlePath);
|
|
94
79
|
const modulesByEntry = new Map<string, HtPageModule>();
|
|
95
80
|
|
|
96
|
-
for (const
|
|
97
|
-
|
|
81
|
+
for (const entry of entries) {
|
|
82
|
+
const mod = await importPageModule(entry.entryPath);
|
|
83
|
+
modulesByEntry.set(entry.entryPath, mod);
|
|
98
84
|
}
|
|
99
85
|
|
|
100
86
|
const pages = await buildPageIndex({
|
|
@@ -103,7 +89,7 @@ export function htPages(options: HtPagesPluginOptions = {}): Plugin {
|
|
|
103
89
|
cleanUrls,
|
|
104
90
|
});
|
|
105
91
|
|
|
106
|
-
return { entries,
|
|
92
|
+
return { entries, modulesByEntry, pages };
|
|
107
93
|
}
|
|
108
94
|
|
|
109
95
|
return {
|
|
@@ -177,7 +163,6 @@ export function htPages(options: HtPagesPluginOptions = {}): Plugin {
|
|
|
177
163
|
}
|
|
178
164
|
|
|
179
165
|
logDebug(options.debug, 'page updated', ctx.file);
|
|
180
|
-
|
|
181
166
|
await loadDevPages();
|
|
182
167
|
return undefined;
|
|
183
168
|
},
|
|
@@ -266,4 +251,4 @@ export function htPages(options: HtPagesPluginOptions = {}): Plugin {
|
|
|
266
251
|
}
|
|
267
252
|
},
|
|
268
253
|
};
|
|
269
|
-
}
|
|
254
|
+
}
|