@devlusoft/devix 0.1.0

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.
Files changed (109) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +216 -0
  3. package/bin/devix.js +2 -0
  4. package/dist/cli/build.d.ts +1 -0
  5. package/dist/cli/build.js +286 -0
  6. package/dist/cli/build.js.map +7 -0
  7. package/dist/cli/dev.d.ts +1 -0
  8. package/dist/cli/dev.js +361 -0
  9. package/dist/cli/dev.js.map +7 -0
  10. package/dist/cli/generate.d.ts +1 -0
  11. package/dist/cli/generate.js +389 -0
  12. package/dist/cli/generate.js.map +7 -0
  13. package/dist/cli/index.d.ts +2 -0
  14. package/dist/cli/index.js +649 -0
  15. package/dist/cli/index.js.map +7 -0
  16. package/dist/cli/start.d.ts +1 -0
  17. package/dist/cli/start.js +78 -0
  18. package/dist/cli/start.js.map +7 -0
  19. package/dist/config.d.ts +21 -0
  20. package/dist/config.js +17 -0
  21. package/dist/config.js.map +7 -0
  22. package/dist/runtime/api-context.d.ts +20 -0
  23. package/dist/runtime/api-context.js +18 -0
  24. package/dist/runtime/api-context.js.map +7 -0
  25. package/dist/runtime/client-router.d.ts +13 -0
  26. package/dist/runtime/client-router.js +59 -0
  27. package/dist/runtime/client-router.js.map +7 -0
  28. package/dist/runtime/context.d.ts +27 -0
  29. package/dist/runtime/context.js +15 -0
  30. package/dist/runtime/context.js.map +7 -0
  31. package/dist/runtime/error-boundary.d.ts +19 -0
  32. package/dist/runtime/error-boundary.js +37 -0
  33. package/dist/runtime/error-boundary.js.map +7 -0
  34. package/dist/runtime/head.d.ts +3 -0
  35. package/dist/runtime/head.js +69 -0
  36. package/dist/runtime/head.js.map +7 -0
  37. package/dist/runtime/index.d.ts +5 -0
  38. package/dist/runtime/index.js +300 -0
  39. package/dist/runtime/index.js.map +7 -0
  40. package/dist/runtime/link.d.ts +8 -0
  41. package/dist/runtime/link.js +43 -0
  42. package/dist/runtime/link.js.map +7 -0
  43. package/dist/runtime/metadata.d.ts +10 -0
  44. package/dist/runtime/metadata.js +22 -0
  45. package/dist/runtime/metadata.js.map +7 -0
  46. package/dist/runtime/router-provider.d.ts +22 -0
  47. package/dist/runtime/router-provider.js +259 -0
  48. package/dist/runtime/router-provider.js.map +7 -0
  49. package/dist/server/api-router.d.ts +21 -0
  50. package/dist/server/api-router.js +64 -0
  51. package/dist/server/api-router.js.map +7 -0
  52. package/dist/server/api.d.ts +2 -0
  53. package/dist/server/api.js +123 -0
  54. package/dist/server/api.js.map +7 -0
  55. package/dist/server/collect-css.d.ts +2 -0
  56. package/dist/server/collect-css.js +15 -0
  57. package/dist/server/collect-css.js.map +7 -0
  58. package/dist/server/index.d.ts +6 -0
  59. package/dist/server/index.js +133 -0
  60. package/dist/server/index.js.map +7 -0
  61. package/dist/server/pages-router.d.ts +21 -0
  62. package/dist/server/pages-router.js +64 -0
  63. package/dist/server/pages-router.js.map +7 -0
  64. package/dist/server/render.d.ts +34 -0
  65. package/dist/server/render.js +306 -0
  66. package/dist/server/render.js.map +7 -0
  67. package/dist/server/routes.d.ts +11 -0
  68. package/dist/server/routes.js +42 -0
  69. package/dist/server/routes.js.map +7 -0
  70. package/dist/server/types.d.ts +49 -0
  71. package/dist/server/types.js +1 -0
  72. package/dist/server/types.js.map +7 -0
  73. package/dist/types.d.ts +35 -0
  74. package/dist/types.js +1 -0
  75. package/dist/types.js.map +7 -0
  76. package/dist/utils/async.d.ts +1 -0
  77. package/dist/utils/async.js +14 -0
  78. package/dist/utils/async.js.map +7 -0
  79. package/dist/utils/banner.d.ts +1 -0
  80. package/dist/utils/banner.js +34 -0
  81. package/dist/utils/banner.js.map +7 -0
  82. package/dist/utils/duration.d.ts +1 -0
  83. package/dist/utils/duration.js +22 -0
  84. package/dist/utils/duration.js.map +7 -0
  85. package/dist/utils/html.d.ts +2 -0
  86. package/dist/utils/html.js +12 -0
  87. package/dist/utils/html.js.map +7 -0
  88. package/dist/utils/patterns.d.ts +1 -0
  89. package/dist/utils/patterns.js +8 -0
  90. package/dist/utils/patterns.js.map +7 -0
  91. package/dist/vite/codegen/api.d.ts +6 -0
  92. package/dist/vite/codegen/api.js +23 -0
  93. package/dist/vite/codegen/api.js.map +7 -0
  94. package/dist/vite/codegen/client-routes.d.ts +6 -0
  95. package/dist/vite/codegen/client-routes.js +36 -0
  96. package/dist/vite/codegen/client-routes.js.map +7 -0
  97. package/dist/vite/codegen/context.d.ts +1 -0
  98. package/dist/vite/codegen/context.js +10 -0
  99. package/dist/vite/codegen/context.js.map +7 -0
  100. package/dist/vite/codegen/entry-client.d.ts +5 -0
  101. package/dist/vite/codegen/entry-client.js +64 -0
  102. package/dist/vite/codegen/entry-client.js.map +7 -0
  103. package/dist/vite/codegen/render.d.ts +6 -0
  104. package/dist/vite/codegen/render.js +31 -0
  105. package/dist/vite/codegen/render.js.map +7 -0
  106. package/dist/vite/index.d.ts +3 -0
  107. package/dist/vite/index.js +225 -0
  108. package/dist/vite/index.js.map +7 -0
  109. package/package.json +77 -0
@@ -0,0 +1,7 @@
1
+ {
2
+ "version": 3,
3
+ "sources": ["../../src/server/render.tsx", "../../src/runtime/head.tsx", "../../src/utils/patterns.ts", "../../src/server/pages-router.ts", "../../src/runtime/metadata.ts", "../../src/runtime/context.tsx", "../../src/utils/html.ts", "../../src/utils/async.ts"],
4
+ "sourcesContent": ["import {ComponentType, createElement, ReactElement} from 'react'\nimport {renderToString, renderToStaticMarkup} from 'react-dom/server'\nimport {buildHeadNodes} from '../runtime/head'\nimport {buildPages, matchPage, collectLayoutChain} from './pages-router'\nimport {resolveMetadata, mergeMetadata} from '../runtime/metadata'\nimport {RouteDataContext} from '../runtime/context'\nimport type {PageModule, LayoutModule, PageGlob} from './types'\nimport type {Manifest} from \"vite\";\nimport {escapeAttr, safeJsonStringify} from \"../utils/html\";\nimport {withTimeout} from \"../utils/async\";\n\nconst DEV_CLIENT_ENTRY = '/@id/virtual:devix/entry-client'\n\nasync function resolvePageData(pathname: string, request: Request, glob: PageGlob, timeout: number) {\n const {pages, layouts} = buildPages(Object.keys(glob.pages), Object.keys(glob.layouts), glob.pagesDir)\n const matched = matchPage(pathname, pages)\n if (!matched) return null\n\n const {page, params} = matched\n const layoutChain = collectLayoutChain(page.key, layouts)\n const ctx = {params, request}\n\n const pageMod = await glob.pages[page.key]() as PageModule\n\n if (pageMod.guard) {\n const redirect = await pageMod.guard(ctx)\n if (redirect) return {redirect}\n }\n\n const loaderData = pageMod.loader\n ? await withTimeout(pageMod.loader(ctx) as Promise<unknown>, timeout)\n : null\n\n const layoutMods = await Promise.all(\n layoutChain.map(l => glob.layouts[l.key]() as Promise<LayoutModule>)\n )\n const layoutsData = await withTimeout(\n Promise.all(layoutMods.map(mod => mod.loader ? mod.loader(ctx) : null)),\n timeout\n )\n\n const pageMeta = await resolveMetadata(pageMod, {...ctx, loaderData})\n const layoutsMeta = await Promise.all(\n layoutMods.map((mod, i) => resolveMetadata(mod, {...ctx, loaderData: layoutsData[i]}))\n )\n\n const metadata = mergeMetadata(...layoutsMeta.map(m => m.metadata), pageMeta.metadata)\n const viewport = pageMeta.viewport ?? layoutsMeta.findLast(m => m.viewport)?.viewport\n\n const rootLayoutMod = layoutMods[0]\n const lang = rootLayoutMod?.generateLang\n ? await rootLayoutMod.generateLang({...ctx, loaderData})\n : rootLayoutMod?.lang ?? 'en'\n\n return {pageMod, layoutMods, params, loaderData, layoutsData, metadata, viewport, lang}\n}\n\nexport async function runLoader(url: string, request: Request, glob: PageGlob, options?: { loaderTimeout?: number }) {\n const {pathname} = new URL(url, 'http://localhost')\n let result: Awaited<ReturnType<typeof resolvePageData>>\n try {\n const timeout = options?.loaderTimeout ?? 10_000\n result = await resolvePageData(pathname, request, glob, timeout)\n } catch (err) {\n console.error('[devix] render error:', err)\n return {loaderData: null, params: {}, layouts: [], metadata: null, viewport: undefined}\n }\n\n if (!result || 'redirect' in result) {\n return {loaderData: null, params: {}, layouts: [], metadata: null, viewport: undefined}\n }\n\n const {loaderData, params, layoutsData, metadata, viewport} = result\n return {\n loaderData,\n params,\n layouts: layoutsData.map(loaderData => ({loaderData})),\n metadata,\n viewport,\n }\n}\n\nexport async function render(\n url: string,\n request: Request,\n glob: PageGlob,\n options?: { manifest?: Manifest, loaderTimeout?: number },\n) {\n const clientEntry = options?.manifest\n ? `/${Object.values(options.manifest).find(chunk => chunk.isEntry)?.file}`\n : DEV_CLIENT_ENTRY\n\n const cssFiles = options?.manifest\n ? (Object.values(options.manifest).find(chunk => chunk.isEntry)?.css ?? [])\n : []\n const cssLinks = cssFiles.map(f => `<link rel=\"stylesheet\" href=\"/${f}\">`).join('')\n\n const {pathname} = new URL(url, 'http://localhost')\n\n let result: Awaited<ReturnType<typeof resolvePageData>>\n try {\n const timeout = options?.loaderTimeout ?? 10_000\n result = await resolvePageData(pathname, request, glob, timeout)\n } catch (err) {\n console.error('[devix] render error:', err)\n const html = `<html lang=\"en\"><head><meta charset=\"utf-8\">${cssLinks}</head><body><script>window.__DEVIX__=null;window.__LOADER_DATA__=null;window.__LAYOUTS_DATA__=[];</script><script type=\"module\" src=\"${clientEntry}\"></script><div id=\"devix-root\"></div></body></html>`\n return {html, statusCode: 500, headers: {}}\n }\n\n if (!result) {\n const dataScript = `<script>window.__DEVIX__=${safeJsonStringify({\n metadata: null,\n viewport: undefined,\n clientEntry\n })};window.__LOADER_DATA__=null;window.__LAYOUTS_DATA__=[];</script>`\n const clientScript = `<script type=\"module\" src=\"${clientEntry}\"></script>`\n const html = `<html lang=\"en\"><head><meta charset=\"utf-8\">${cssLinks}${dataScript}</head><body><div id=\"devix-root\"></div>${clientScript}</body></html>`\n return {html, statusCode: 404, headers: {}}\n }\n\n if ('redirect' in result) {\n return {html: '', statusCode: 302, headers: {Location: result.redirect}}\n }\n\n const {pageMod, layoutMods, params, loaderData, layoutsData, metadata, viewport, lang} = result\n\n let tree: ReactElement = createElement(\n RouteDataContext as any,\n {value: {loaderData, params}},\n createElement(pageMod.default, {data: loaderData, params, url: pathname})\n )\n\n for (let i = layoutMods.length - 1; i >= 0; i--) {\n const layoutData = layoutsData[i]\n tree = createElement(\n RouteDataContext as any,\n {value: {loaderData: layoutData, params}},\n createElement(layoutMods[i].default as ComponentType<any>, {data: layoutData, params}, tree),\n )\n }\n\n const content = renderToString(tree)\n const headTags = metadata ? renderToStaticMarkup(buildHeadNodes(metadata, viewport) as any) : ''\n\n const dataScript = `<script>window.__DEVIX__=${safeJsonStringify({\n metadata,\n viewport,\n clientEntry\n })};window.__LOADER_DATA__=${safeJsonStringify(loaderData)};window.__LAYOUTS_DATA__=${safeJsonStringify(layoutsData)};</script>`\n const clientScript = `<script type=\"module\" src=\"${clientEntry}\"></script>`\n const customHeaders: Record<string, string> = pageMod.headers ?? {}\n\n const html = `<html lang=\"${escapeAttr(lang)}\"><head><meta charset=\"utf-8\">${headTags}${cssLinks}${dataScript}</head><body><div id=\"devix-root\">${content}</div>${clientScript}</body></html>`\n\n return {html, statusCode: 200, headers: customHeaders}\n}\n\nexport async function getStaticRoutes(glob: PageGlob): Promise<string[]> {\n const {pages} = buildPages(Object.keys(glob.pages), Object.keys(glob.layouts), glob.pagesDir)\n const urls: string[] = []\n\n for (const page of pages) {\n if (page.params.length === 0) {\n urls.push(page.path)\n } else {\n const mod = await glob.pages[page.key]() as PageModule\n if (!mod.generateStaticParams) continue\n const paramSets = await mod.generateStaticParams()\n for (const params of paramSets) {\n let url = page.path\n for (const [key, value] of Object.entries(params)) {\n url = url.replace(`:${key}`, encodeURIComponent(value))\n }\n urls.push(url)\n }\n }\n }\n\n return urls\n}\n\n", "import {Metadata, Viewport} from \"../types\";\nimport {ReactNode} from \"react\";\n\ntype MetaTag =\n | { tag: 'title'; children: string }\n | { tag: 'meta'; name?: string; property?: string; content: string }\n | { tag: 'link'; rel: string; href: string; hrefLang?: string }\n\nfunction collectTags(metadata: Metadata, viewport?: Viewport): MetaTag[] {\n const tags: MetaTag[] = []\n\n if (metadata.title)\n tags.push({tag: 'title', children: metadata.title})\n if (metadata.description)\n tags.push({tag: 'meta', name: 'description', content: metadata.description})\n if (metadata.keywords?.length)\n tags.push({tag: 'meta', name: 'keywords', content: metadata.keywords.join(', ')})\n\n const ogTitle = metadata.og?.title ?? metadata.title\n if (ogTitle) tags.push({tag: 'meta', property: 'og:title', content: ogTitle})\n const ogDesc = metadata.og?.description ?? metadata.description\n if (ogDesc) tags.push({tag: 'meta', property: 'og:description', content: ogDesc})\n if (metadata.og?.image) tags.push({tag: 'meta', property: 'og:image', content: metadata.og.image})\n if (metadata.og?.type) tags.push({tag: 'meta', property: 'og:type', content: metadata.og.type})\n if (metadata.og?.url) tags.push({tag: 'meta', property: 'og:url', content: metadata.og.url})\n\n const twTitle = metadata.twitter?.title ?? metadata.title\n if (twTitle) tags.push({tag: 'meta', name: 'twitter:title', content: twTitle})\n const twDesc = metadata.twitter?.description ?? metadata.description\n if (twDesc) tags.push({tag: 'meta', name: 'twitter:description', content: twDesc})\n if (metadata.twitter?.card) tags.push({\n tag: 'meta', name: 'twitter:card', content:\n metadata.twitter.card\n })\n if (metadata.twitter?.image) tags.push({\n tag: 'meta', name: 'twitter:image', content:\n metadata.twitter.image\n })\n if (metadata.twitter?.creator) tags.push({\n tag: 'meta', name: 'twitter:creator', content:\n metadata.twitter.creator\n })\n\n if (metadata.canonical) tags.push({tag: 'link', rel: 'canonical', href: metadata.canonical})\n if (metadata.robots) tags.push({tag: 'meta', name: 'robots', content: metadata.robots})\n if (metadata.alternates) {\n for (const [lang, href] of Object.entries(metadata.alternates))\n tags.push({tag: 'link', rel: 'alternate', href, hrefLang: lang})\n }\n\n if (viewport) {\n const parts: string[] = []\n if (viewport.width !== undefined) parts.push(`width=${viewport.width}`)\n if (viewport.initialScale !== undefined) parts.push(`initial-scale=${viewport.initialScale}`)\n if (viewport.maximumScale !== undefined) parts.push(`maximum-scale=${viewport.maximumScale}`)\n if (viewport.userScalable !== undefined) parts.push(`user-scalable=${viewport.userScalable ? 'yes' :\n 'no'}`)\n if (parts.length) tags.push({tag: 'meta', name: 'viewport', content: parts.join(', ')})\n if (viewport.themeColor) tags.push({\n tag: 'meta', name: 'theme-color', content: viewport.themeColor\n })\n }\n\n return tags\n}\n\nexport function buildHeadNodes(metadata: Metadata, viewport?: Viewport): ReactNode {\n const tags = collectTags(metadata, viewport)\n\n return <>\n {tags.map((t, i) => {\n if (t.tag === 'title') return <title key={i}>{t.children}</title>\n if (t.tag === 'link') return <link key={i} rel={t.rel} href={t.href} hrefLang={t.hrefLang}/>\n return <meta key={i} name={t.name} property={t.property} content={t.content}/>\n })}\n </>\n}", "export function routePattern(rel: string): string {\n return rel\n .replace(/\\.(tsx|ts|jsx|js)$/, '')\n .replace(/\\(.*?\\)\\//g, '')\n .replace(/^index$|\\/index$/, '')\n .replace(/\\[([^\\]]+)]/g, ':$1')\n || '/'\n}", "import {routePattern} from \"../utils/patterns\";\n\nexport interface Page {\n path: string\n key: string\n params: string[]\n regex: RegExp\n}\n\nexport interface Layout {\n dir: string\n key: string\n}\n\nexport interface PagesResult {\n pages: Page[]\n layouts: Layout[]\n}\n\nfunction keyToRoutePattern(key: string, pagesDir: string): string {\n const rel = key.slice(pagesDir.length + 1).replace(/\\\\/g, '/')\n const pattern = routePattern(rel)\n return pattern === \"/\" ? \"/\" : `/${pattern}`\n}\n\nfunction keyToDir(key: string): string {\n return key.slice(0, key.lastIndexOf('/'))\n}\n\nlet cache: PagesResult | null = null\n\nexport function invalidatePagesCache() {\n cache = null\n}\n\nexport function buildPages(pageKeys: string[], layoutKeys: string[], pagesDir: string): PagesResult {\n if (cache) return cache\n\n const pages: Page[] = []\n const layouts: Layout[] = []\n\n for (const key of layoutKeys) {\n layouts.push({dir: keyToDir(key), key})\n }\n\n for (const key of pageKeys) {\n const pattern = keyToRoutePattern(key, pagesDir)\n const params = [...pattern.matchAll(/:([^/]+)/g)].map(m => m[1])\n const regexStr = pattern\n .replace(/:[^/]+/g, '([^/]+)')\n .replace(/\\//g, '\\\\/')\n pages.push({path: pattern, key, params, regex: new RegExp(`^${regexStr}$`)})\n }\n\n pages.sort((a, b) => {\n const aScore = (a.path.match(/:/g) || []).length\n const bScore = (b.path.match(/:/g) || []).length\n if (aScore !== bScore) return aScore - bScore\n return b.path.length - a.path.length\n })\n\n cache = {pages, layouts}\n return cache\n}\n\nexport function collectLayoutChain(pageKey: string, layouts: Layout[]): Layout[] {\n const pageDir = keyToDir(pageKey)\n\n return layouts\n .filter(layout => pageDir.startsWith(layout.dir))\n .sort((a, b) => a.dir.split('/').length - b.dir.split('/').length)\n}\n\nexport function matchPage(pathname: string, pages: Page[]): {\n page: Page\n params: Record<string, string>\n} | null {\n for (const page of pages) {\n const match = pathname.match(page.regex)\n if (match) {\n const params: Record<string, string> = {}\n page.params.forEach((name, i) => {\n params[name] = decodeURIComponent(match[i + 1])\n })\n return {page, params}\n }\n }\n return null\n}\n", "import {LayoutModule, PageModule} from \"../server\";\nimport {LoaderContext, Metadata, Viewport} from \"../types\"\n\nexport interface ResolvedMeta {\n metadata: Metadata\n viewport?: Viewport\n}\n\nexport async function resolveMetadata(module: PageModule | LayoutModule, ctx: LoaderContext & {\n loaderData: unknown\n}): Promise<ResolvedMeta> {\n const metadata = module.generateMetadata\n ? await module.generateMetadata(ctx)\n : module.metadata ?? {}\n\n const viewport = module.generateViewport\n ? await module.generateViewport(ctx)\n : module.viewport\n\n return {metadata, viewport}\n}\n\nexport function mergeMetadata(...sources: (Metadata | null | undefined)[]): Metadata {\n const result: Metadata = {}\n\n for (const source of sources) {\n if (!source) continue\n const { og, twitter, ...rest } = source\n Object.assign(result, rest)\n if (og) result.og = { ...result.og, ...og }\n if (twitter) result.twitter = { ...result.twitter, ...twitter }\n }\n\n return result\n}", "import {createContext, Context, ComponentType} from \"react\";\nimport {Metadata, Viewport} from \"../types\";\nimport {LayoutProps, PageProps} from \"../server/types\";\n\nexport interface RouterContextValue {\n pathname: string\n params: Record<string, string>\n loaderData: unknown\n layoutsData: unknown[]\n Page: ComponentType<PageProps>\n layouts: ComponentType<LayoutProps>[]\n metadata: Metadata | null\n viewport?: Viewport\n navigate: (to: string) => void\n isNavigating: boolean\n}\n\nexport interface PageMetaContextValue {\n metadata: Metadata | null\n viewport?: Viewport\n clientEntry?: string\n}\n\nexport interface RouteDataContextValue {\n loaderData: unknown\n params: Record<string, string>\n}\n\nconst g = globalThis as any\n\ng.__devix_RouterContext__ ??= createContext<RouterContextValue | null>(null)\nexport const RouterContext: Context<RouterContextValue | null> = g.__devix_RouterContext__\n\ng.__devix_PageMetaContext__ ??= createContext<PageMetaContextValue | null>(null)\ng.__devix_RouteDataContext__ ??= createContext<RouteDataContextValue | null>(null)\n\nexport const PageMetaContext: Context<PageMetaContextValue | null> = g.__devix_PageMetaContext__\nexport const RouteDataContext: Context<RouteDataContextValue | null> = g.__devix_RouteDataContext__\n\n", "export function safeJsonStringify(value: unknown): string {\n return JSON.stringify(value).replace(/<\\/script>/gi, '<\\\\/script>')\n}\n\nexport function escapeAttr(value: string): string {\n return value.replace(/\"/g, '&quot;')\n}", "export function withTimeout<T>(promise: Promise<T>, ms: number): Promise<T> {\n let timer: ReturnType<typeof setTimeout>\n return Promise.race([\n promise.finally(() => clearTimeout(timer)),\n new Promise<never>((_, reject) => {\n timer = setTimeout(() => reject(new Error(`timed out after ${ms}ms`)), ms)\n })\n ])\n}"],
5
+ "mappings": ";AAAA,SAAuB,qBAAkC;AACzD,SAAQ,gBAAgB,4BAA2B;;;ACoExC,mBAE+B,WAF/B;AA7DX,SAAS,YAAY,UAAoB,UAAgC;AACrE,QAAM,OAAkB,CAAC;AAEzB,MAAI,SAAS;AACT,SAAK,KAAK,EAAC,KAAK,SAAS,UAAU,SAAS,MAAK,CAAC;AACtD,MAAI,SAAS;AACT,SAAK,KAAK,EAAC,KAAK,QAAQ,MAAM,eAAe,SAAS,SAAS,YAAW,CAAC;AAC/E,MAAI,SAAS,UAAU;AACnB,SAAK,KAAK,EAAC,KAAK,QAAQ,MAAM,YAAY,SAAS,SAAS,SAAS,KAAK,IAAI,EAAC,CAAC;AAEpF,QAAM,UAAU,SAAS,IAAI,SAAS,SAAS;AAC/C,MAAI,QAAS,MAAK,KAAK,EAAC,KAAK,QAAQ,UAAU,YAAY,SAAS,QAAO,CAAC;AAC5E,QAAM,SAAS,SAAS,IAAI,eAAe,SAAS;AACpD,MAAI,OAAQ,MAAK,KAAK,EAAC,KAAK,QAAQ,UAAU,kBAAkB,SAAS,OAAM,CAAC;AAChF,MAAI,SAAS,IAAI,MAAO,MAAK,KAAK,EAAC,KAAK,QAAQ,UAAU,YAAY,SAAS,SAAS,GAAG,MAAK,CAAC;AACjG,MAAI,SAAS,IAAI,KAAM,MAAK,KAAK,EAAC,KAAK,QAAQ,UAAU,WAAW,SAAS,SAAS,GAAG,KAAI,CAAC;AAC9F,MAAI,SAAS,IAAI,IAAK,MAAK,KAAK,EAAC,KAAK,QAAQ,UAAU,UAAU,SAAS,SAAS,GAAG,IAAG,CAAC;AAE3F,QAAM,UAAU,SAAS,SAAS,SAAS,SAAS;AACpD,MAAI,QAAS,MAAK,KAAK,EAAC,KAAK,QAAQ,MAAM,iBAAiB,SAAS,QAAO,CAAC;AAC7E,QAAM,SAAS,SAAS,SAAS,eAAe,SAAS;AACzD,MAAI,OAAQ,MAAK,KAAK,EAAC,KAAK,QAAQ,MAAM,uBAAuB,SAAS,OAAM,CAAC;AACjF,MAAI,SAAS,SAAS,KAAM,MAAK,KAAK;AAAA,IAClC,KAAK;AAAA,IAAQ,MAAM;AAAA,IAAgB,SACnC,SAAS,QAAQ;AAAA,EACrB,CAAC;AACD,MAAI,SAAS,SAAS,MAAO,MAAK,KAAK;AAAA,IACnC,KAAK;AAAA,IAAQ,MAAM;AAAA,IAAiB,SACpC,SAAS,QAAQ;AAAA,EACrB,CAAC;AACD,MAAI,SAAS,SAAS,QAAS,MAAK,KAAK;AAAA,IACrC,KAAK;AAAA,IAAQ,MAAM;AAAA,IAAmB,SACtC,SAAS,QAAQ;AAAA,EACrB,CAAC;AAED,MAAI,SAAS,UAAW,MAAK,KAAK,EAAC,KAAK,QAAQ,KAAK,aAAa,MAAM,SAAS,UAAS,CAAC;AAC3F,MAAI,SAAS,OAAQ,MAAK,KAAK,EAAC,KAAK,QAAQ,MAAM,UAAU,SAAS,SAAS,OAAM,CAAC;AACtF,MAAI,SAAS,YAAY;AACrB,eAAW,CAAC,MAAM,IAAI,KAAK,OAAO,QAAQ,SAAS,UAAU;AACzD,WAAK,KAAK,EAAC,KAAK,QAAQ,KAAK,aAAa,MAAM,UAAU,KAAI,CAAC;AAAA,EACvE;AAEA,MAAI,UAAU;AACV,UAAM,QAAkB,CAAC;AACzB,QAAI,SAAS,UAAU,OAAW,OAAM,KAAK,SAAS,SAAS,KAAK,EAAE;AACtE,QAAI,SAAS,iBAAiB,OAAW,OAAM,KAAK,iBAAiB,SAAS,YAAY,EAAE;AAC5F,QAAI,SAAS,iBAAiB,OAAW,OAAM,KAAK,iBAAiB,SAAS,YAAY,EAAE;AAC5F,QAAI,SAAS,iBAAiB,OAAW,OAAM,KAAK,iBAAiB,SAAS,eAAe,QACzF,IAAI,EAAE;AACV,QAAI,MAAM,OAAQ,MAAK,KAAK,EAAC,KAAK,QAAQ,MAAM,YAAY,SAAS,MAAM,KAAK,IAAI,EAAC,CAAC;AACtF,QAAI,SAAS,WAAY,MAAK,KAAK;AAAA,MAC/B,KAAK;AAAA,MAAQ,MAAM;AAAA,MAAe,SAAS,SAAS;AAAA,IACxD,CAAC;AAAA,EACL;AAEA,SAAO;AACX;AAEO,SAAS,eAAe,UAAoB,UAAgC;AAC/E,QAAM,OAAO,YAAY,UAAU,QAAQ;AAE3C,SAAO,gCACF,eAAK,IAAI,CAAC,GAAG,MAAM;AAChB,QAAI,EAAE,QAAQ,QAAS,QAAO,oBAAC,WAAe,YAAE,YAAN,CAAe;AACzD,QAAI,EAAE,QAAQ,OAAQ,QAAO,oBAAC,UAAa,KAAK,EAAE,KAAK,MAAM,EAAE,MAAM,UAAU,EAAE,YAAzC,CAAkD;AAC1F,WAAO,oBAAC,UAAa,MAAM,EAAE,MAAM,UAAU,EAAE,UAAU,SAAS,EAAE,WAAlD,CAA0D;AAAA,EAChF,CAAC,GACL;AACJ;;;AC5EO,SAAS,aAAa,KAAqB;AAC9C,SAAO,IACE,QAAQ,sBAAsB,EAAE,EAChC,QAAQ,cAAc,EAAE,EACxB,QAAQ,oBAAoB,EAAE,EAC9B,QAAQ,gBAAgB,KAAK,KAC/B;AACX;;;ACYA,SAAS,kBAAkB,KAAa,UAA0B;AAC9D,QAAM,MAAM,IAAI,MAAM,SAAS,SAAS,CAAC,EAAE,QAAQ,OAAO,GAAG;AAC7D,QAAM,UAAU,aAAa,GAAG;AAChC,SAAO,YAAY,MAAM,MAAM,IAAI,OAAO;AAC9C;AAEA,SAAS,SAAS,KAAqB;AACnC,SAAO,IAAI,MAAM,GAAG,IAAI,YAAY,GAAG,CAAC;AAC5C;AAEA,IAAI,QAA4B;AAMzB,SAAS,WAAW,UAAoB,YAAsB,UAA+B;AAChG,MAAI,MAAO,QAAO;AAElB,QAAM,QAAgB,CAAC;AACvB,QAAM,UAAoB,CAAC;AAE3B,aAAW,OAAO,YAAY;AAC1B,YAAQ,KAAK,EAAC,KAAK,SAAS,GAAG,GAAG,IAAG,CAAC;AAAA,EAC1C;AAEA,aAAW,OAAO,UAAU;AACxB,UAAM,UAAU,kBAAkB,KAAK,QAAQ;AAC/C,UAAM,SAAS,CAAC,GAAG,QAAQ,SAAS,WAAW,CAAC,EAAE,IAAI,OAAK,EAAE,CAAC,CAAC;AAC/D,UAAM,WAAW,QACZ,QAAQ,WAAW,SAAS,EAC5B,QAAQ,OAAO,KAAK;AACzB,UAAM,KAAK,EAAC,MAAM,SAAS,KAAK,QAAQ,OAAO,IAAI,OAAO,IAAI,QAAQ,GAAG,EAAC,CAAC;AAAA,EAC/E;AAEA,QAAM,KAAK,CAAC,GAAG,MAAM;AACjB,UAAM,UAAU,EAAE,KAAK,MAAM,IAAI,KAAK,CAAC,GAAG;AAC1C,UAAM,UAAU,EAAE,KAAK,MAAM,IAAI,KAAK,CAAC,GAAG;AAC1C,QAAI,WAAW,OAAQ,QAAO,SAAS;AACvC,WAAO,EAAE,KAAK,SAAS,EAAE,KAAK;AAAA,EAClC,CAAC;AAED,UAAQ,EAAC,OAAO,QAAO;AACvB,SAAO;AACX;AAEO,SAAS,mBAAmB,SAAiB,SAA6B;AAC7E,QAAM,UAAU,SAAS,OAAO;AAEhC,SAAO,QACF,OAAO,YAAU,QAAQ,WAAW,OAAO,GAAG,CAAC,EAC/C,KAAK,CAAC,GAAG,MAAM,EAAE,IAAI,MAAM,GAAG,EAAE,SAAS,EAAE,IAAI,MAAM,GAAG,EAAE,MAAM;AACzE;AAEO,SAAS,UAAU,UAAkB,OAGnC;AACL,aAAW,QAAQ,OAAO;AACtB,UAAM,QAAQ,SAAS,MAAM,KAAK,KAAK;AACvC,QAAI,OAAO;AACP,YAAM,SAAiC,CAAC;AACxC,WAAK,OAAO,QAAQ,CAAC,MAAM,MAAM;AAC7B,eAAO,IAAI,IAAI,mBAAmB,MAAM,IAAI,CAAC,CAAC;AAAA,MAClD,CAAC;AACD,aAAO,EAAC,MAAM,OAAM;AAAA,IACxB;AAAA,EACJ;AACA,SAAO;AACX;;;AChFA,eAAsB,gBAAgB,QAAmC,KAE/C;AACtB,QAAM,WAAW,OAAO,mBAClB,MAAM,OAAO,iBAAiB,GAAG,IACjC,OAAO,YAAY,CAAC;AAE1B,QAAM,WAAW,OAAO,mBAClB,MAAM,OAAO,iBAAiB,GAAG,IACjC,OAAO;AAEb,SAAO,EAAC,UAAU,SAAQ;AAC9B;AAEO,SAAS,iBAAiB,SAAoD;AACjF,QAAM,SAAmB,CAAC;AAE1B,aAAW,UAAU,SAAS;AAC1B,QAAI,CAAC,OAAQ;AACb,UAAM,EAAE,IAAI,SAAS,GAAG,KAAK,IAAI;AACjC,WAAO,OAAO,QAAQ,IAAI;AAC1B,QAAI,GAAI,QAAO,KAAK,EAAE,GAAG,OAAO,IAAI,GAAG,GAAG;AAC1C,QAAI,QAAS,QAAO,UAAU,EAAE,GAAG,OAAO,SAAS,GAAG,QAAQ;AAAA,EAClE;AAEA,SAAO;AACX;;;AClCA,SAAQ,qBAA4C;AA4BpD,IAAM,IAAI;AAEV,EAAE,4BAA4B,cAAyC,IAAI;AACpE,IAAM,gBAAoD,EAAE;AAEnE,EAAE,8BAA8B,cAA2C,IAAI;AAC/E,EAAE,+BAA+B,cAA4C,IAAI;AAE1E,IAAM,kBAAwD,EAAE;AAChE,IAAM,mBAA0D,EAAE;;;ACrClE,SAAS,kBAAkB,OAAwB;AACtD,SAAO,KAAK,UAAU,KAAK,EAAE,QAAQ,gBAAgB,aAAa;AACtE;AAEO,SAAS,WAAW,OAAuB;AAC9C,SAAO,MAAM,QAAQ,MAAM,QAAQ;AACvC;;;ACNO,SAAS,YAAe,SAAqB,IAAwB;AACxE,MAAI;AACJ,SAAO,QAAQ,KAAK;AAAA,IAChB,QAAQ,QAAQ,MAAM,aAAa,KAAK,CAAC;AAAA,IACzC,IAAI,QAAe,CAAC,GAAG,WAAW;AAC9B,cAAQ,WAAW,MAAM,OAAO,IAAI,MAAM,mBAAmB,EAAE,IAAI,CAAC,GAAG,EAAE;AAAA,IAC7E,CAAC;AAAA,EACL,CAAC;AACL;;;APGA,IAAM,mBAAmB;AAEzB,eAAe,gBAAgB,UAAkB,SAAkB,MAAgB,SAAiB;AAChG,QAAM,EAAC,OAAO,QAAO,IAAI,WAAW,OAAO,KAAK,KAAK,KAAK,GAAG,OAAO,KAAK,KAAK,OAAO,GAAG,KAAK,QAAQ;AACrG,QAAM,UAAU,UAAU,UAAU,KAAK;AACzC,MAAI,CAAC,QAAS,QAAO;AAErB,QAAM,EAAC,MAAM,OAAM,IAAI;AACvB,QAAM,cAAc,mBAAmB,KAAK,KAAK,OAAO;AACxD,QAAM,MAAM,EAAC,QAAQ,QAAO;AAE5B,QAAM,UAAU,MAAM,KAAK,MAAM,KAAK,GAAG,EAAE;AAE3C,MAAI,QAAQ,OAAO;AACf,UAAM,WAAW,MAAM,QAAQ,MAAM,GAAG;AACxC,QAAI,SAAU,QAAO,EAAC,SAAQ;AAAA,EAClC;AAEA,QAAM,aAAa,QAAQ,SACrB,MAAM,YAAY,QAAQ,OAAO,GAAG,GAAuB,OAAO,IAClE;AAEN,QAAM,aAAa,MAAM,QAAQ;AAAA,IAC7B,YAAY,IAAI,OAAK,KAAK,QAAQ,EAAE,GAAG,EAAE,CAA0B;AAAA,EACvE;AACA,QAAM,cAAc,MAAM;AAAA,IACtB,QAAQ,IAAI,WAAW,IAAI,SAAO,IAAI,SAAS,IAAI,OAAO,GAAG,IAAI,IAAI,CAAC;AAAA,IACtE;AAAA,EACJ;AAEA,QAAM,WAAW,MAAM,gBAAgB,SAAS,EAAC,GAAG,KAAK,WAAU,CAAC;AACpE,QAAM,cAAc,MAAM,QAAQ;AAAA,IAC9B,WAAW,IAAI,CAAC,KAAK,MAAM,gBAAgB,KAAK,EAAC,GAAG,KAAK,YAAY,YAAY,CAAC,EAAC,CAAC,CAAC;AAAA,EACzF;AAEA,QAAM,WAAW,cAAc,GAAG,YAAY,IAAI,OAAK,EAAE,QAAQ,GAAG,SAAS,QAAQ;AACrF,QAAM,WAAW,SAAS,YAAY,YAAY,SAAS,OAAK,EAAE,QAAQ,GAAG;AAE7E,QAAM,gBAAgB,WAAW,CAAC;AAClC,QAAM,OAAO,eAAe,eACtB,MAAM,cAAc,aAAa,EAAC,GAAG,KAAK,WAAU,CAAC,IACrD,eAAe,QAAQ;AAE7B,SAAO,EAAC,SAAS,YAAY,QAAQ,YAAY,aAAa,UAAU,UAAU,KAAI;AAC1F;AAEA,eAAsB,UAAU,KAAa,SAAkB,MAAgB,SAAsC;AACjH,QAAM,EAAC,SAAQ,IAAI,IAAI,IAAI,KAAK,kBAAkB;AAClD,MAAI;AACJ,MAAI;AACA,UAAM,UAAU,SAAS,iBAAiB;AAC1C,aAAS,MAAM,gBAAgB,UAAU,SAAS,MAAM,OAAO;AAAA,EACnE,SAAS,KAAK;AACV,YAAQ,MAAM,yBAAyB,GAAG;AAC1C,WAAO,EAAC,YAAY,MAAM,QAAQ,CAAC,GAAG,SAAS,CAAC,GAAG,UAAU,MAAM,UAAU,OAAS;AAAA,EAC1F;AAEA,MAAI,CAAC,UAAU,cAAc,QAAQ;AACjC,WAAO,EAAC,YAAY,MAAM,QAAQ,CAAC,GAAG,SAAS,CAAC,GAAG,UAAU,MAAM,UAAU,OAAS;AAAA,EAC1F;AAEA,QAAM,EAAC,YAAY,QAAQ,aAAa,UAAU,SAAQ,IAAI;AAC9D,SAAO;AAAA,IACH;AAAA,IACA;AAAA,IACA,SAAS,YAAY,IAAI,CAAAA,iBAAe,EAAC,YAAAA,YAAU,EAAE;AAAA,IACrD;AAAA,IACA;AAAA,EACJ;AACJ;AAEA,eAAsB,OAClB,KACA,SACA,MACA,SACF;AACE,QAAM,cAAc,SAAS,WACvB,IAAI,OAAO,OAAO,QAAQ,QAAQ,EAAE,KAAK,WAAS,MAAM,OAAO,GAAG,IAAI,KACtE;AAEN,QAAM,WAAW,SAAS,WACnB,OAAO,OAAO,QAAQ,QAAQ,EAAE,KAAK,WAAS,MAAM,OAAO,GAAG,OAAO,CAAC,IACvE,CAAC;AACP,QAAM,WAAW,SAAS,IAAI,OAAK,iCAAiC,CAAC,IAAI,EAAE,KAAK,EAAE;AAElF,QAAM,EAAC,SAAQ,IAAI,IAAI,IAAI,KAAK,kBAAkB;AAElD,MAAI;AACJ,MAAI;AACA,UAAM,UAAU,SAAS,iBAAiB;AAC1C,aAAS,MAAM,gBAAgB,UAAU,SAAS,MAAM,OAAO;AAAA,EACnE,SAAS,KAAK;AACV,YAAQ,MAAM,yBAAyB,GAAG;AAC1C,UAAMC,QAAO,+CAA+C,QAAQ,yIAAyI,WAAW;AACxN,WAAO,EAAC,MAAAA,OAAM,YAAY,KAAK,SAAS,CAAC,EAAC;AAAA,EAC9C;AAEA,MAAI,CAAC,QAAQ;AACT,UAAMC,cAAa,4BAA4B,kBAAkB;AAAA,MAC7D,UAAU;AAAA,MACV,UAAU;AAAA,MACV;AAAA,IACJ,CAAC,CAAC;AACF,UAAMC,gBAAe,8BAA8B,WAAW;AAC9D,UAAMF,QAAO,+CAA+C,QAAQ,GAAGC,WAAU,2CAA2CC,aAAY;AACxI,WAAO,EAAC,MAAAF,OAAM,YAAY,KAAK,SAAS,CAAC,EAAC;AAAA,EAC9C;AAEA,MAAI,cAAc,QAAQ;AACtB,WAAO,EAAC,MAAM,IAAI,YAAY,KAAK,SAAS,EAAC,UAAU,OAAO,SAAQ,EAAC;AAAA,EAC3E;AAEA,QAAM,EAAC,SAAS,YAAY,QAAQ,YAAY,aAAa,UAAU,UAAU,KAAI,IAAI;AAEzF,MAAI,OAAqB;AAAA,IACrB;AAAA,IACA,EAAC,OAAO,EAAC,YAAY,OAAM,EAAC;AAAA,IAC5B,cAAc,QAAQ,SAAS,EAAC,MAAM,YAAY,QAAQ,KAAK,SAAQ,CAAC;AAAA,EAC5E;AAEA,WAAS,IAAI,WAAW,SAAS,GAAG,KAAK,GAAG,KAAK;AAC7C,UAAM,aAAa,YAAY,CAAC;AAChC,WAAO;AAAA,MACH;AAAA,MACA,EAAC,OAAO,EAAC,YAAY,YAAY,OAAM,EAAC;AAAA,MACxC,cAAc,WAAW,CAAC,EAAE,SAA+B,EAAC,MAAM,YAAY,OAAM,GAAG,IAAI;AAAA,IAC/F;AAAA,EACJ;AAEA,QAAM,UAAU,eAAe,IAAI;AACnC,QAAM,WAAW,WAAW,qBAAqB,eAAe,UAAU,QAAQ,CAAQ,IAAI;AAE9F,QAAM,aAAa,4BAA4B,kBAAkB;AAAA,IAC7D;AAAA,IACA;AAAA,IACA;AAAA,EACJ,CAAC,CAAC,2BAA2B,kBAAkB,UAAU,CAAC,4BAA4B,kBAAkB,WAAW,CAAC;AACpH,QAAM,eAAe,8BAA8B,WAAW;AAC9D,QAAM,gBAAwC,QAAQ,WAAW,CAAC;AAElE,QAAM,OAAO,eAAe,WAAW,IAAI,CAAC,iCAAiC,QAAQ,GAAG,QAAQ,GAAG,UAAU,qCAAqC,OAAO,SAAS,YAAY;AAE9K,SAAO,EAAC,MAAM,YAAY,KAAK,SAAS,cAAa;AACzD;AAEA,eAAsB,gBAAgB,MAAmC;AACrE,QAAM,EAAC,MAAK,IAAI,WAAW,OAAO,KAAK,KAAK,KAAK,GAAG,OAAO,KAAK,KAAK,OAAO,GAAG,KAAK,QAAQ;AAC5F,QAAM,OAAiB,CAAC;AAExB,aAAW,QAAQ,OAAO;AACtB,QAAI,KAAK,OAAO,WAAW,GAAG;AAC1B,WAAK,KAAK,KAAK,IAAI;AAAA,IACvB,OAAO;AACH,YAAM,MAAM,MAAM,KAAK,MAAM,KAAK,GAAG,EAAE;AACvC,UAAI,CAAC,IAAI,qBAAsB;AAC/B,YAAM,YAAY,MAAM,IAAI,qBAAqB;AACjD,iBAAW,UAAU,WAAW;AAC5B,YAAI,MAAM,KAAK;AACf,mBAAW,CAAC,KAAK,KAAK,KAAK,OAAO,QAAQ,MAAM,GAAG;AAC/C,gBAAM,IAAI,QAAQ,IAAI,GAAG,IAAI,mBAAmB,KAAK,CAAC;AAAA,QAC1D;AACA,aAAK,KAAK,GAAG;AAAA,MACjB;AAAA,IACJ;AAAA,EACJ;AAEA,SAAO;AACX;",
6
+ "names": ["loaderData", "html", "dataScript", "clientScript"]
7
+ }
@@ -0,0 +1,11 @@
1
+ import type { Hono } from 'hono';
2
+ import type { Manifest } from 'vite';
3
+ interface ServerOptions {
4
+ renderModule: any;
5
+ apiModule: any;
6
+ manifest?: Manifest;
7
+ loaderTimeout?: number;
8
+ }
9
+ export declare function registerApiRoutes(app: Hono, { apiModule, renderModule, loaderTimeout }: ServerOptions): void;
10
+ export declare function registerSsrRoute(app: Hono, { renderModule, manifest, loaderTimeout }: ServerOptions): void;
11
+ export {};
@@ -0,0 +1,42 @@
1
+ // src/server/routes.ts
2
+ function registerApiRoutes(app, { apiModule, renderModule, loaderTimeout }) {
3
+ app.all("/api/*", async (c) => {
4
+ try {
5
+ return await apiModule.handleApiRequest(c.req.url, c.req.raw);
6
+ } catch (e) {
7
+ console.error(e);
8
+ return c.json({ error: "internal error" }, 500);
9
+ }
10
+ });
11
+ app.get("/_data/*", async (c) => {
12
+ try {
13
+ const { pathname, search } = new URL(c.req.url, "http://localhost");
14
+ const url = pathname.replace(/^\/_data/, "") + search;
15
+ const data = await renderModule.runLoader(url, c.req.raw, { loaderTimeout });
16
+ return c.json(data);
17
+ } catch (e) {
18
+ console.error(e);
19
+ return c.json({ error: "internal error" }, 500);
20
+ }
21
+ });
22
+ }
23
+ function registerSsrRoute(app, { renderModule, manifest, loaderTimeout }) {
24
+ app.get("*", async (c) => {
25
+ try {
26
+ const { html, statusCode, headers } = await renderModule.render(c.req.url, c.req.raw, { manifest, loaderTimeout });
27
+ const res = c.html(`<!DOCTYPE html>${html}`, statusCode);
28
+ for (const [key, value] of Object.entries(headers)) {
29
+ res.headers.set(key, value);
30
+ }
31
+ return res;
32
+ } catch (e) {
33
+ console.error(e);
34
+ return c.text("Internal Server Error", 500);
35
+ }
36
+ });
37
+ }
38
+ export {
39
+ registerApiRoutes,
40
+ registerSsrRoute
41
+ };
42
+ //# sourceMappingURL=routes.js.map
@@ -0,0 +1,7 @@
1
+ {
2
+ "version": 3,
3
+ "sources": ["../../src/server/routes.ts"],
4
+ "sourcesContent": ["import type {Hono} from 'hono'\nimport type {Manifest} from 'vite'\n\ninterface ServerOptions {\n renderModule: any\n apiModule: any\n manifest?: Manifest\n loaderTimeout?: number\n}\n\nexport function registerApiRoutes(app: Hono, {apiModule, renderModule, loaderTimeout}: ServerOptions) {\n app.all('/api/*', async (c) => {\n try {\n return await apiModule.handleApiRequest(c.req.url, c.req.raw)\n } catch (e) {\n console.error(e)\n return c.json({error: 'internal error'}, 500)\n }\n })\n\n app.get('/_data/*', async (c) => {\n try {\n const {pathname, search} = new URL(c.req.url, 'http://localhost')\n const url = pathname.replace(/^\\/_data/, '') + search\n\n const data = await renderModule.runLoader(url, c.req.raw, {loaderTimeout})\n return c.json(data)\n } catch (e) {\n console.error(e)\n return c.json({error: 'internal error'}, 500)\n }\n })\n}\n\nexport function registerSsrRoute(app: Hono, {renderModule, manifest, loaderTimeout}: ServerOptions) {\n app.get('*', async (c) => {\n try {\n const {html, statusCode, headers} = await renderModule.render(c.req.url, c.req.raw, {manifest, loaderTimeout})\n const res = c.html(`<!DOCTYPE html>${html}`, statusCode)\n for (const [key, value] of Object.entries(headers as Record<string, string>)) {\n res.headers.set(key, value)\n }\n return res\n } catch (e) {\n console.error(e)\n return c.text('Internal Server Error', 500)\n }\n })\n}"],
5
+ "mappings": ";AAUO,SAAS,kBAAkB,KAAW,EAAC,WAAW,cAAc,cAAa,GAAkB;AAClG,MAAI,IAAI,UAAU,OAAO,MAAM;AAC3B,QAAI;AACA,aAAO,MAAM,UAAU,iBAAiB,EAAE,IAAI,KAAK,EAAE,IAAI,GAAG;AAAA,IAChE,SAAS,GAAG;AACR,cAAQ,MAAM,CAAC;AACf,aAAO,EAAE,KAAK,EAAC,OAAO,iBAAgB,GAAG,GAAG;AAAA,IAChD;AAAA,EACJ,CAAC;AAED,MAAI,IAAI,YAAY,OAAO,MAAM;AAC7B,QAAI;AACA,YAAM,EAAC,UAAU,OAAM,IAAI,IAAI,IAAI,EAAE,IAAI,KAAK,kBAAkB;AAChE,YAAM,MAAM,SAAS,QAAQ,YAAY,EAAE,IAAI;AAE/C,YAAM,OAAO,MAAM,aAAa,UAAU,KAAK,EAAE,IAAI,KAAK,EAAC,cAAa,CAAC;AACzE,aAAO,EAAE,KAAK,IAAI;AAAA,IACtB,SAAS,GAAG;AACR,cAAQ,MAAM,CAAC;AACf,aAAO,EAAE,KAAK,EAAC,OAAO,iBAAgB,GAAG,GAAG;AAAA,IAChD;AAAA,EACJ,CAAC;AACL;AAEO,SAAS,iBAAiB,KAAW,EAAC,cAAc,UAAU,cAAa,GAAkB;AAChG,MAAI,IAAI,KAAK,OAAO,MAAM;AACtB,QAAI;AACA,YAAM,EAAC,MAAM,YAAY,QAAO,IAAI,MAAM,aAAa,OAAO,EAAE,IAAI,KAAK,EAAE,IAAI,KAAK,EAAC,UAAU,cAAa,CAAC;AAC7G,YAAM,MAAM,EAAE,KAAK,kBAAkB,IAAI,IAAI,UAAU;AACvD,iBAAW,CAAC,KAAK,KAAK,KAAK,OAAO,QAAQ,OAAiC,GAAG;AAC1E,YAAI,QAAQ,IAAI,KAAK,KAAK;AAAA,MAC9B;AACA,aAAO;AAAA,IACX,SAAS,GAAG;AACR,cAAQ,MAAM,CAAC;AACf,aAAO,EAAE,KAAK,yBAAyB,GAAG;AAAA,IAC9C;AAAA,EACJ,CAAC;AACL;",
6
+ "names": []
7
+ }
@@ -0,0 +1,49 @@
1
+ import type React from "react";
2
+ import { LoaderContext, Metadata, Viewport } from "../types";
3
+ export interface PageProps<TData = unknown, TParams = Record<string, string>> {
4
+ data: TData;
5
+ params: TParams;
6
+ url: string;
7
+ }
8
+ export interface LayoutProps<TData = unknown, TParams = Record<string, string>> {
9
+ children: React.ReactNode;
10
+ data: TData;
11
+ params: TParams;
12
+ }
13
+ export interface ErrorProps {
14
+ statusCode: number;
15
+ message?: string;
16
+ }
17
+ export interface PageGlob {
18
+ pages: Record<string, () => Promise<unknown>>;
19
+ layouts: Record<string, () => Promise<unknown>>;
20
+ pagesDir: string;
21
+ }
22
+ export interface ApiGlob {
23
+ routes: Record<string, () => Promise<unknown>>;
24
+ middlewares: Record<string, () => Promise<unknown>>;
25
+ apiDir: string;
26
+ }
27
+ interface BaseModule<TData, TParams> {
28
+ loader?: (ctx: LoaderContext<TParams>) => Promise<TData> | TData;
29
+ guard?: (ctx: LoaderContext<TParams>) => Promise<string | null> | string | null;
30
+ metadata?: Metadata;
31
+ generateMetadata?: (ctx: LoaderContext<TParams> & {
32
+ loaderData: TData;
33
+ }) => Promise<Metadata> | Metadata;
34
+ viewport?: Viewport;
35
+ generateViewport?: (ctx: LoaderContext<TParams>) => Promise<Viewport> | Viewport;
36
+ headers?: Record<string, string>;
37
+ }
38
+ export interface PageModule<TData = unknown, TParams = Record<string, string>> extends BaseModule<TData, TParams> {
39
+ default: React.ComponentType<PageProps<TData, TParams>>;
40
+ generateStaticParams?: () => Promise<Record<string, string>[]> | Record<string, string>[];
41
+ }
42
+ export interface LayoutModule<TData = unknown, TParams = Record<string, string>> extends BaseModule<TData, TParams> {
43
+ default: React.ComponentType<LayoutProps<TData, TParams>>;
44
+ lang?: string;
45
+ generateLang?: (ctx: LoaderContext<TParams> & {
46
+ loaderData: TData;
47
+ }) => Promise<string> | string;
48
+ }
49
+ export {};
@@ -0,0 +1 @@
1
+ //# sourceMappingURL=types.js.map
@@ -0,0 +1,7 @@
1
+ {
2
+ "version": 3,
3
+ "sources": [],
4
+ "sourcesContent": [],
5
+ "mappings": "",
6
+ "names": []
7
+ }
@@ -0,0 +1,35 @@
1
+ export interface Metadata {
2
+ title?: string;
3
+ description?: string;
4
+ keywords?: string[];
5
+ og?: {
6
+ title?: string;
7
+ description?: string;
8
+ image?: string;
9
+ type?: 'website' | 'article' | 'product';
10
+ url?: string;
11
+ };
12
+ twitter?: {
13
+ card?: 'summary' | 'summary_large_image';
14
+ title?: string;
15
+ description?: string;
16
+ image?: string;
17
+ creator?: string;
18
+ };
19
+ canonical?: string;
20
+ robots?: string;
21
+ alternates?: Record<string, string>;
22
+ }
23
+ export interface Viewport {
24
+ width?: string | number;
25
+ initialScale?: number;
26
+ maximumScale?: number;
27
+ userScalable?: boolean;
28
+ themeColor?: string;
29
+ }
30
+ export interface LoaderContext<TParams = Record<string, string>> {
31
+ params: TParams;
32
+ request: Request;
33
+ }
34
+ export type LoaderFunction<TData = unknown, TParams = Record<string, string>> = (ctx: LoaderContext<TParams>) => Promise<TData> | TData;
35
+ export type GuardFunction<TParams = Record<string, string>> = (ctx: LoaderContext<TParams>) => Promise<string | null> | string | null;
package/dist/types.js ADDED
@@ -0,0 +1 @@
1
+ //# sourceMappingURL=types.js.map
@@ -0,0 +1,7 @@
1
+ {
2
+ "version": 3,
3
+ "sources": [],
4
+ "sourcesContent": [],
5
+ "mappings": "",
6
+ "names": []
7
+ }
@@ -0,0 +1 @@
1
+ export declare function withTimeout<T>(promise: Promise<T>, ms: number): Promise<T>;
@@ -0,0 +1,14 @@
1
+ // src/utils/async.ts
2
+ function withTimeout(promise, ms) {
3
+ let timer;
4
+ return Promise.race([
5
+ promise.finally(() => clearTimeout(timer)),
6
+ new Promise((_, reject) => {
7
+ timer = setTimeout(() => reject(new Error(`timed out after ${ms}ms`)), ms);
8
+ })
9
+ ]);
10
+ }
11
+ export {
12
+ withTimeout
13
+ };
14
+ //# sourceMappingURL=async.js.map
@@ -0,0 +1,7 @@
1
+ {
2
+ "version": 3,
3
+ "sources": ["../../src/utils/async.ts"],
4
+ "sourcesContent": ["export function withTimeout<T>(promise: Promise<T>, ms: number): Promise<T> {\n let timer: ReturnType<typeof setTimeout>\n return Promise.race([\n promise.finally(() => clearTimeout(timer)),\n new Promise<never>((_, reject) => {\n timer = setTimeout(() => reject(new Error(`timed out after ${ms}ms`)), ms)\n })\n ])\n}"],
5
+ "mappings": ";AAAO,SAAS,YAAe,SAAqB,IAAwB;AACxE,MAAI;AACJ,SAAO,QAAQ,KAAK;AAAA,IAChB,QAAQ,QAAQ,MAAM,aAAa,KAAK,CAAC;AAAA,IACzC,IAAI,QAAe,CAAC,GAAG,WAAW;AAC9B,cAAQ,WAAW,MAAM,OAAO,IAAI,MAAM,mBAAmB,EAAE,IAAI,CAAC,GAAG,EAAE;AAAA,IAC7E,CAAC;AAAA,EACL,CAAC;AACL;",
6
+ "names": []
7
+ }
@@ -0,0 +1 @@
1
+ export declare function printDevBanner(port: number): void;
@@ -0,0 +1,34 @@
1
+ // src/utils/banner.ts
2
+ import pc from "picocolors";
3
+ import { networkInterfaces } from "node:os";
4
+ import { createRequire } from "node:module";
5
+ function getNetworkUrl(port) {
6
+ const nets = networkInterfaces();
7
+ for (const interfaces of Object.values(nets)) {
8
+ for (const net of interfaces ?? []) {
9
+ if (net.family === "IPv4" && !net.internal) {
10
+ return `http://${net.address}:${port}/`;
11
+ }
12
+ }
13
+ }
14
+ return null;
15
+ }
16
+ function printDevBanner(port) {
17
+ const req = createRequire(import.meta.url);
18
+ const version = req("../../package.json").version;
19
+ const networkUrl = getNetworkUrl(port);
20
+ console.log();
21
+ console.log(` ${pc.bold(pc.yellow("devix"))} ${pc.dim(`v${version}`)}`);
22
+ console.log();
23
+ console.log(` ${pc.green("\u279C")} ${pc.bold("Local:")} ${pc.cyan(`http://localhost:${port}/`)}`);
24
+ if (networkUrl) {
25
+ console.log(` ${pc.green("\u279C")} ${pc.bold("Network:")} ${pc.cyan(networkUrl)}`);
26
+ } else {
27
+ console.log(` ${pc.green("\u279C")} ${pc.bold("Network:")} ${pc.dim("use --host to expose")}`);
28
+ }
29
+ console.log();
30
+ }
31
+ export {
32
+ printDevBanner
33
+ };
34
+ //# sourceMappingURL=banner.js.map
@@ -0,0 +1,7 @@
1
+ {
2
+ "version": 3,
3
+ "sources": ["../../src/utils/banner.ts"],
4
+ "sourcesContent": ["import pc from 'picocolors'\nimport {networkInterfaces} from 'node:os'\nimport {createRequire} from 'node:module'\n\nfunction getNetworkUrl(port: number): string | null {\n const nets = networkInterfaces()\n for (const interfaces of Object.values(nets)) {\n for (const net of interfaces ?? []) {\n if (net.family === 'IPv4' && !net.internal) {\n return `http://${net.address}:${port}/`\n }\n }\n }\n return null\n}\n\nexport function printDevBanner(port: number) {\n const req = createRequire(import.meta.url)\n const version = req('../../package.json').version\n const networkUrl = getNetworkUrl(port)\n\n console.log()\n console.log(` ${pc.bold(pc.yellow('devix'))} ${pc.dim(`v${version}`)}`)\n console.log()\n console.log(` ${pc.green('\u279C')} ${pc.bold('Local:')} ${pc.cyan(`http://localhost:${port}/`)}`)\n if (networkUrl) {\n console.log(` ${pc.green('\u279C')} ${pc.bold('Network:')} ${pc.cyan(networkUrl)}`)\n } else {\n console.log(` ${pc.green('\u279C')} ${pc.bold('Network:')} ${pc.dim('use --host to expose')}`)\n }\n console.log()\n}"],
5
+ "mappings": ";AAAA,OAAO,QAAQ;AACf,SAAQ,yBAAwB;AAChC,SAAQ,qBAAoB;AAE5B,SAAS,cAAc,MAA6B;AAChD,QAAM,OAAO,kBAAkB;AAC/B,aAAW,cAAc,OAAO,OAAO,IAAI,GAAG;AAC1C,eAAW,OAAO,cAAc,CAAC,GAAG;AAChC,UAAI,IAAI,WAAW,UAAU,CAAC,IAAI,UAAU;AACxC,eAAO,UAAU,IAAI,OAAO,IAAI,IAAI;AAAA,MACxC;AAAA,IACJ;AAAA,EACJ;AACA,SAAO;AACX;AAEO,SAAS,eAAe,MAAc;AACzC,QAAM,MAAM,cAAc,YAAY,GAAG;AACzC,QAAM,UAAU,IAAI,oBAAoB,EAAE;AAC1C,QAAM,aAAa,cAAc,IAAI;AAErC,UAAQ,IAAI;AACZ,UAAQ,IAAI,KAAK,GAAG,KAAK,GAAG,OAAO,OAAO,CAAC,CAAC,IAAI,GAAG,IAAI,IAAI,OAAO,EAAE,CAAC,EAAE;AACvE,UAAQ,IAAI;AACZ,UAAQ,IAAI,KAAK,GAAG,MAAM,QAAG,CAAC,KAAK,GAAG,KAAK,QAAQ,CAAC,MAAM,GAAG,KAAK,oBAAoB,IAAI,GAAG,CAAC,EAAE;AAChG,MAAI,YAAY;AACZ,YAAQ,IAAI,KAAK,GAAG,MAAM,QAAG,CAAC,KAAK,GAAG,KAAK,UAAU,CAAC,IAAI,GAAG,KAAK,UAAU,CAAC,EAAE;AAAA,EACnF,OAAO;AACH,YAAQ,IAAI,KAAK,GAAG,MAAM,QAAG,CAAC,KAAK,GAAG,KAAK,UAAU,CAAC,IAAI,GAAG,IAAI,sBAAsB,CAAC,EAAE;AAAA,EAC9F;AACA,UAAQ,IAAI;AAChB;",
6
+ "names": []
7
+ }
@@ -0,0 +1 @@
1
+ export declare function parseDuration(value: number | string): number;
@@ -0,0 +1,22 @@
1
+ // src/utils/duration.ts
2
+ function parseDuration(value) {
3
+ if (typeof value === "number") return value;
4
+ const match = value.trim().match(/^(\d+(?:\.\d+)?)\s*(ms|s|m|h)?$/);
5
+ if (!match) throw new Error(`[devix] Invalid duration: "${value}". Use a number (ms) or a string like "5s", "2m", "500ms".`);
6
+ const n = parseFloat(match[1]);
7
+ switch (match[2]) {
8
+ case "h":
9
+ return n * 36e5;
10
+ case "m":
11
+ return n * 6e4;
12
+ case "s":
13
+ return n * 1e3;
14
+ case "ms":
15
+ default:
16
+ return n;
17
+ }
18
+ }
19
+ export {
20
+ parseDuration
21
+ };
22
+ //# sourceMappingURL=duration.js.map
@@ -0,0 +1,7 @@
1
+ {
2
+ "version": 3,
3
+ "sources": ["../../src/utils/duration.ts"],
4
+ "sourcesContent": ["export function parseDuration(value: number | string): number {\n if (typeof value === 'number') return value\n const match = value.trim().match(/^(\\d+(?:\\.\\d+)?)\\s*(ms|s|m|h)?$/)\n if (!match) throw new Error(`[devix] Invalid duration: \"${value}\". Use a number (ms) or a string like \"5s\", \"2m\", \"500ms\".`)\n const n = parseFloat(match[1])\n switch (match[2]) {\n case 'h': return n * 3_600_000\n case 'm': return n * 60_000\n case 's': return n * 1_000\n case 'ms':\n default: return n\n }\n}\n"],
5
+ "mappings": ";AAAO,SAAS,cAAc,OAAgC;AAC1D,MAAI,OAAO,UAAU,SAAU,QAAO;AACtC,QAAM,QAAQ,MAAM,KAAK,EAAE,MAAM,iCAAiC;AAClE,MAAI,CAAC,MAAO,OAAM,IAAI,MAAM,8BAA8B,KAAK,4DAA4D;AAC3H,QAAM,IAAI,WAAW,MAAM,CAAC,CAAC;AAC7B,UAAQ,MAAM,CAAC,GAAG;AAAA,IACd,KAAK;AAAM,aAAO,IAAI;AAAA,IACtB,KAAK;AAAM,aAAO,IAAI;AAAA,IACtB,KAAK;AAAM,aAAO,IAAI;AAAA,IACtB,KAAK;AAAA,IACL;AAAW,aAAO;AAAA,EACtB;AACJ;",
6
+ "names": []
7
+ }
@@ -0,0 +1,2 @@
1
+ export declare function safeJsonStringify(value: unknown): string;
2
+ export declare function escapeAttr(value: string): string;
@@ -0,0 +1,12 @@
1
+ // src/utils/html.ts
2
+ function safeJsonStringify(value) {
3
+ return JSON.stringify(value).replace(/<\/script>/gi, "<\\/script>");
4
+ }
5
+ function escapeAttr(value) {
6
+ return value.replace(/"/g, "&quot;");
7
+ }
8
+ export {
9
+ escapeAttr,
10
+ safeJsonStringify
11
+ };
12
+ //# sourceMappingURL=html.js.map
@@ -0,0 +1,7 @@
1
+ {
2
+ "version": 3,
3
+ "sources": ["../../src/utils/html.ts"],
4
+ "sourcesContent": ["export function safeJsonStringify(value: unknown): string {\n return JSON.stringify(value).replace(/<\\/script>/gi, '<\\\\/script>')\n}\n\nexport function escapeAttr(value: string): string {\n return value.replace(/\"/g, '&quot;')\n}"],
5
+ "mappings": ";AAAO,SAAS,kBAAkB,OAAwB;AACtD,SAAO,KAAK,UAAU,KAAK,EAAE,QAAQ,gBAAgB,aAAa;AACtE;AAEO,SAAS,WAAW,OAAuB;AAC9C,SAAO,MAAM,QAAQ,MAAM,QAAQ;AACvC;",
6
+ "names": []
7
+ }
@@ -0,0 +1 @@
1
+ export declare function routePattern(rel: string): string;
@@ -0,0 +1,8 @@
1
+ // src/utils/patterns.ts
2
+ function routePattern(rel) {
3
+ return rel.replace(/\.(tsx|ts|jsx|js)$/, "").replace(/\(.*?\)\//g, "").replace(/^index$|\/index$/, "").replace(/\[([^\]]+)]/g, ":$1") || "/";
4
+ }
5
+ export {
6
+ routePattern
7
+ };
8
+ //# sourceMappingURL=patterns.js.map
@@ -0,0 +1,7 @@
1
+ {
2
+ "version": 3,
3
+ "sources": ["../../src/utils/patterns.ts"],
4
+ "sourcesContent": ["export function routePattern(rel: string): string {\n return rel\n .replace(/\\.(tsx|ts|jsx|js)$/, '')\n .replace(/\\(.*?\\)\\//g, '')\n .replace(/^index$|\\/index$/, '')\n .replace(/\\[([^\\]]+)]/g, ':$1')\n || '/'\n}"],
5
+ "mappings": ";AAAO,SAAS,aAAa,KAAqB;AAC9C,SAAO,IACE,QAAQ,sBAAsB,EAAE,EAChC,QAAQ,cAAc,EAAE,EACxB,QAAQ,oBAAoB,EAAE,EAC9B,QAAQ,gBAAgB,KAAK,KAC/B;AACX;",
6
+ "names": []
7
+ }
@@ -0,0 +1,6 @@
1
+ interface ApiOptions {
2
+ apiPath: string;
3
+ appDir: string;
4
+ }
5
+ export declare function generateApi({ apiPath, appDir }: ApiOptions): string;
6
+ export {};
@@ -0,0 +1,23 @@
1
+ // src/vite/codegen/api.ts
2
+ function generateApi({ apiPath, appDir }) {
3
+ return `
4
+ import { handleApiRequest as _handleApiRequest } from '${apiPath}'
5
+
6
+ const _routes = import.meta.glob(['/${appDir}/api/**/*.ts', '!**/middleware.ts'])
7
+ const _middlewares = import.meta.glob('/${appDir}/api/**/middleware.ts')
8
+
9
+ const _glob = {
10
+ routes: _routes,
11
+ middlewares: _middlewares,
12
+ apiDir: '/${appDir}/api',
13
+ }
14
+
15
+ export function handleApiRequest(url, request) {
16
+ return _handleApiRequest(url, request, _glob)
17
+ }
18
+ `;
19
+ }
20
+ export {
21
+ generateApi
22
+ };
23
+ //# sourceMappingURL=api.js.map
@@ -0,0 +1,7 @@
1
+ {
2
+ "version": 3,
3
+ "sources": ["../../../src/vite/codegen/api.ts"],
4
+ "sourcesContent": ["interface ApiOptions {\n apiPath: string\n appDir: string\n}\n\nexport function generateApi({apiPath, appDir}: ApiOptions): string {\n return `\nimport { handleApiRequest as _handleApiRequest } from '${apiPath}'\n\nconst _routes = import.meta.glob(['/${appDir}/api/**/*.ts', '!**/middleware.ts'])\nconst _middlewares = import.meta.glob('/${appDir}/api/**/middleware.ts')\n\nconst _glob = {\n routes: _routes,\n middlewares: _middlewares,\n apiDir: '/${appDir}/api',\n}\n\nexport function handleApiRequest(url, request) {\n return _handleApiRequest(url, request, _glob)\n}\n`\n}\n"],
5
+ "mappings": ";AAKO,SAAS,YAAY,EAAC,SAAS,OAAM,GAAuB;AAC/D,SAAO;AAAA,yDAC8C,OAAO;AAAA;AAAA,sCAE1B,MAAM;AAAA,0CACF,MAAM;AAAA;AAAA;AAAA;AAAA;AAAA,gBAKhC,MAAM;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAOtB;",
6
+ "names": []
7
+ }
@@ -0,0 +1,6 @@
1
+ interface ClientRoutesOptions {
2
+ pagesDir: string;
3
+ matcherPath: string;
4
+ }
5
+ export declare function generateClientRoutes({ pagesDir, matcherPath }: ClientRoutesOptions): string;
6
+ export {};
@@ -0,0 +1,36 @@
1
+ // src/vite/codegen/client-routes.ts
2
+ function generateClientRoutes({ pagesDir, matcherPath }) {
3
+ return `
4
+ import React from 'react'
5
+ import { createMatcher } from '${matcherPath}'
6
+ const pageFiles = import.meta.glob(['/${pagesDir}/**/*.tsx', '!**/error.tsx', '!**/layout.tsx'])
7
+ const layoutFiles = import.meta.glob('/${pagesDir}/**/layout.tsx')
8
+ const errorFiles = import.meta.glob('/${pagesDir}/**/error.tsx')
9
+
10
+ export const matchClientRoute = createMatcher(pageFiles, layoutFiles)
11
+
12
+ export async function loadErrorPage() {
13
+ const key = Object.keys(errorFiles)[0]
14
+ if (!key) return null
15
+ const mod = await errorFiles[key]()
16
+ return mod?.default ?? null
17
+ }
18
+
19
+ export function getDefaultErrorPage() {
20
+ return function DefaultError({ statusCode, message }) {
21
+ return React.createElement('main', {
22
+ style: { minHeight: '100dvh', display: 'flex', flexDirection: 'column',
23
+ alignItems: 'center', justifyContent: 'center', gap: '8px',
24
+ fontFamily: 'system-ui, sans-serif' }
25
+ },
26
+ React.createElement('h1', {style: {fontSize: '4rem', fontWeight: 700}}, statusCode),
27
+ React.createElement('p', {style: {color: '#666'}}, message ?? 'An unexpected error occurred'),
28
+ )
29
+ }
30
+ }
31
+ `;
32
+ }
33
+ export {
34
+ generateClientRoutes
35
+ };
36
+ //# sourceMappingURL=client-routes.js.map
@@ -0,0 +1,7 @@
1
+ {
2
+ "version": 3,
3
+ "sources": ["../../../src/vite/codegen/client-routes.ts"],
4
+ "sourcesContent": ["interface ClientRoutesOptions {\n pagesDir: string\n matcherPath: string\n}\n\nexport function generateClientRoutes({pagesDir, matcherPath}: ClientRoutesOptions) {\n return `\nimport React from 'react'\nimport { createMatcher } from '${matcherPath}'\nconst pageFiles = import.meta.glob(['/${pagesDir}/**/*.tsx', '!**/error.tsx', '!**/layout.tsx'])\nconst layoutFiles = import.meta.glob('/${pagesDir}/**/layout.tsx')\nconst errorFiles = import.meta.glob('/${pagesDir}/**/error.tsx')\n\nexport const matchClientRoute = createMatcher(pageFiles, layoutFiles)\n\nexport async function loadErrorPage() {\n const key = Object.keys(errorFiles)[0]\n if (!key) return null\n const mod = await errorFiles[key]()\n return mod?.default ?? null\n}\n\nexport function getDefaultErrorPage() {\n return function DefaultError({ statusCode, message }) {\n return React.createElement('main', {\n style: { minHeight: '100dvh', display: 'flex', flexDirection: 'column', \n alignItems: 'center', justifyContent: 'center', gap: '8px',\n fontFamily: 'system-ui, sans-serif' }\n },\n React.createElement('h1', {style: {fontSize: '4rem', fontWeight: 700}}, statusCode),\n React.createElement('p', {style: {color: '#666'}}, message ?? 'An unexpected error occurred'),\n )\n }\n}\n`\n}"],
5
+ "mappings": ";AAKO,SAAS,qBAAqB,EAAC,UAAU,YAAW,GAAwB;AAC/E,SAAO;AAAA;AAAA,iCAEsB,WAAW;AAAA,wCACJ,QAAQ;AAAA,yCACP,QAAQ;AAAA,wCACT,QAAQ;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAwBhD;",
6
+ "names": []
7
+ }
@@ -0,0 +1 @@
1
+ export declare function generateContext(): string;
@@ -0,0 +1,10 @@
1
+ // src/vite/codegen/context.ts
2
+ function generateContext() {
3
+ return `
4
+ export {RouterContext} from '@devlusoft/devix/runtime/context'
5
+ `;
6
+ }
7
+ export {
8
+ generateContext
9
+ };
10
+ //# sourceMappingURL=context.js.map
@@ -0,0 +1,7 @@
1
+ {
2
+ "version": 3,
3
+ "sources": ["../../../src/vite/codegen/context.ts"],
4
+ "sourcesContent": ["export function generateContext(): string {\n return `\nexport {RouterContext} from '@devlusoft/devix/runtime/context'\n`\n}"],
5
+ "mappings": ";AAAO,SAAS,kBAA0B;AACtC,SAAO;AAAA;AAAA;AAGX;",
6
+ "names": []
7
+ }
@@ -0,0 +1,5 @@
1
+ interface EntryClientOptions {
2
+ cssUrls: string[];
3
+ }
4
+ export declare function generateEntryClient({ cssUrls }: EntryClientOptions): string;
5
+ export {};
@@ -0,0 +1,64 @@
1
+ // src/vite/codegen/entry-client.ts
2
+ function generateEntryClient({ cssUrls }) {
3
+ const cssImports = cssUrls.map((u) => `import '${u}'`).join("\n");
4
+ return `
5
+ ${cssImports}
6
+ import "@vitejs/plugin-react/preamble"
7
+ import React from "react"
8
+ import {hydrateRoot, createRoot} from 'react-dom/client'
9
+ import {matchClientRoute, loadErrorPage, getDefaultErrorPage} from 'virtual:devix/client-routes'
10
+ import {RouterProvider} from '@devlusoft/devix'
11
+
12
+ const root = document.getElementById('devix-root')
13
+
14
+ if (!window.__DEVIX__) {
15
+ const ErrorPage = getDefaultErrorPage()
16
+ createRoot(root).render(React.createElement(ErrorPage, {statusCode: 500, message: 'Server error'}))
17
+ } else {
18
+ const {metadata, viewport, clientEntry} = window.__DEVIX__
19
+ const loaderData = window.__LOADER_DATA__
20
+ const layoutsData = window.__LAYOUTS_DATA__ ?? []
21
+
22
+ const matched = matchClientRoute(window.location.pathname)
23
+
24
+ if (matched) {
25
+ const [pageMod, ...layoutMods] = await Promise.all([
26
+ matched.load(),
27
+ ...matched.loadLayouts.map(l => l()),
28
+ ])
29
+ hydrateRoot(
30
+ root,
31
+ React.createElement(RouterProvider, {
32
+ clientEntry,
33
+ initialData: loaderData,
34
+ initialParams: matched.params,
35
+ initialPage: pageMod.default,
36
+ initialLayouts: layoutMods.map(m => m.default),
37
+ initialLayoutsData: layoutsData,
38
+ initialMeta: metadata,
39
+ initialViewport: viewport,
40
+ })
41
+ )
42
+ } else {
43
+ const ErrorPage = await loadErrorPage() ?? getDefaultErrorPage()
44
+ createRoot(root).render(
45
+ React.createElement(RouterProvider, {
46
+ clientEntry,
47
+ initialData: null,
48
+ initialParams: {},
49
+ initialPage: () => null,
50
+ initialLayouts: [],
51
+ initialLayoutsData: [],
52
+ initialMeta: null,
53
+ initialError: {statusCode: 404, message: 'Not found'},
54
+ initialErrorPage: ErrorPage,
55
+ })
56
+ )
57
+ }
58
+ }
59
+ `;
60
+ }
61
+ export {
62
+ generateEntryClient
63
+ };
64
+ //# sourceMappingURL=entry-client.js.map
@@ -0,0 +1,7 @@
1
+ {
2
+ "version": 3,
3
+ "sources": ["../../../src/vite/codegen/entry-client.ts"],
4
+ "sourcesContent": ["interface EntryClientOptions {\n cssUrls: string[]\n}\n\nexport function generateEntryClient({cssUrls}: EntryClientOptions): string {\n const cssImports = cssUrls.map(u => `import '${u}'`).join('\\n')\n\n return `\n${cssImports}\nimport \"@vitejs/plugin-react/preamble\"\nimport React from \"react\"\nimport {hydrateRoot, createRoot} from 'react-dom/client'\nimport {matchClientRoute, loadErrorPage, getDefaultErrorPage} from 'virtual:devix/client-routes'\nimport {RouterProvider} from '@devlusoft/devix'\n\nconst root = document.getElementById('devix-root')\n\nif (!window.__DEVIX__) {\n const ErrorPage = getDefaultErrorPage()\n createRoot(root).render(React.createElement(ErrorPage, {statusCode: 500, message: 'Server error'}))\n} else {\n const {metadata, viewport, clientEntry} = window.__DEVIX__\n const loaderData = window.__LOADER_DATA__\n const layoutsData = window.__LAYOUTS_DATA__ ?? []\n\n const matched = matchClientRoute(window.location.pathname)\n\n if (matched) {\n const [pageMod, ...layoutMods] = await Promise.all([\n matched.load(),\n ...matched.loadLayouts.map(l => l()),\n ])\n hydrateRoot(\n root,\n React.createElement(RouterProvider, {\n clientEntry,\n initialData: loaderData,\n initialParams: matched.params,\n initialPage: pageMod.default,\n initialLayouts: layoutMods.map(m => m.default),\n initialLayoutsData: layoutsData,\n initialMeta: metadata,\n initialViewport: viewport,\n })\n )\n } else {\n const ErrorPage = await loadErrorPage() ?? getDefaultErrorPage()\n createRoot(root).render(\n React.createElement(RouterProvider, {\n clientEntry,\n initialData: null,\n initialParams: {},\n initialPage: () => null,\n initialLayouts: [],\n initialLayoutsData: [],\n initialMeta: null,\n initialError: {statusCode: 404, message: 'Not found'},\n initialErrorPage: ErrorPage,\n })\n )\n }\n}\n`\n}"],
5
+ "mappings": ";AAIO,SAAS,oBAAoB,EAAC,QAAO,GAA+B;AACvE,QAAM,aAAa,QAAQ,IAAI,OAAK,WAAW,CAAC,GAAG,EAAE,KAAK,IAAI;AAE9D,SAAO;AAAA,EACT,UAAU;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAuDZ;",
6
+ "names": []
7
+ }
@@ -0,0 +1,6 @@
1
+ interface RenderOptions {
2
+ pagesDir: string;
3
+ renderPath: string;
4
+ }
5
+ export declare function generateRender({ pagesDir, renderPath }: RenderOptions): string;
6
+ export {};