@blinkk/root 1.0.3 → 1.0.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.
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../src/node/load-config.ts","../src/utils/fsutils.ts","../src/node/vite.ts"],"sourcesContent":["import path from 'node:path';\nimport {bundleRequire} from 'bundle-require';\nimport {build} from 'esbuild';\nimport {RootConfig} from '../core/config.js';\nimport {fileExists, loadJson} from '../utils/fsutils.js';\n\nexport interface ConfigOptions {\n command: string;\n}\n\nexport async function loadRootConfig(\n rootDir: string,\n options: ConfigOptions\n): Promise<RootConfig> {\n const configPath = path.resolve(rootDir, 'root.config.ts');\n const exists = await fileExists(configPath);\n if (!exists) {\n throw new Error(`${configPath} does not exist`);\n }\n const configBundle = await bundleRequire({\n filepath: configPath,\n });\n let config = configBundle.mod.default || {};\n if (typeof config === 'function') {\n config = (await config(options)) || {};\n }\n return Object.assign({}, config, {rootDir});\n}\n\n/**\n * Compiles a root.config.ts file to root.config.js.\n */\nexport async function bundleRootConfig(rootDir: string, outPath: string) {\n const configPath = path.resolve(rootDir, 'root.config.ts');\n const configExists = await fileExists(configPath);\n if (!configExists) {\n throw new Error(`${configPath} does not exist`);\n }\n\n const packageJsonPath = path.resolve(rootDir, 'package.json');\n const packageJson = await loadPackageJson(packageJsonPath);\n const allDeps = {\n ...packageJson.peerDependencies,\n ...packageJson.dependencies,\n };\n\n function getPackageName(id: string): string {\n const segments = id.split('/');\n if (segments.length > 1) {\n // Check if package is an org path like `@blinkk/root`.\n if (segments[0].startsWith('@') && segments[0].length > 1) {\n return `${segments[0]}/${segments[1]}`;\n }\n // For imports like `my-package/subpackage`, return `my-package`.\n return segments[0];\n }\n return id;\n }\n\n await build({\n entryPoints: [configPath],\n bundle: true,\n minify: true,\n platform: 'node',\n outfile: outPath,\n sourcemap: 'inline',\n metafile: true,\n format: 'esm',\n plugins: [\n // Externalizes deps that are in package.json.\n {\n name: 'externalize-package-json-deps',\n setup(build) {\n build.onResolve({filter: /.*/}, (args) => {\n const id = args.path;\n if (id[0] !== '.' && !id.startsWith('@/')) {\n const packageName = getPackageName(id);\n if (packageName in allDeps) {\n return {\n external: true,\n };\n }\n }\n return null;\n });\n },\n },\n ],\n });\n}\n\n/**\n * Loads a pre-bundled config file from dist/root.config.js.\n */\nexport async function loadBundledConfig(\n rootDir: string,\n options: ConfigOptions\n): Promise<RootConfig> {\n const configPath = path.resolve(rootDir, 'dist/root.config.js');\n const exists = await fileExists(configPath);\n if (!exists) {\n throw new Error(`${configPath} does not exist`);\n }\n const module = await import(configPath);\n let config = module.default || {};\n if (typeof config === 'function') {\n config = (await config(options)) || {};\n }\n return Object.assign({}, config, {rootDir});\n}\n\nexport async function loadPackageJson(filepath: string): Promise<any> {\n try {\n const packageJson = await loadJson(filepath);\n return packageJson || {};\n } catch (err) {\n return {};\n }\n}\n","import {promises as fs} from 'node:fs';\nimport path from 'node:path';\n\nimport fsExtra from 'fs-extra';\nimport glob from 'tiny-glob';\n\nexport function isJsFile(filename: string) {\n return !!filename.match(/\\.(j|t)sx?$/);\n}\n\nexport async function writeFile(filepath: string, content: string) {\n const dirPath = path.dirname(filepath);\n await makeDir(dirPath);\n await fs.writeFile(filepath, content);\n}\n\nexport async function makeDir(dirpath: string) {\n try {\n await fs.access(dirpath);\n } catch (e) {\n await fs.mkdir(dirpath, {recursive: true});\n }\n}\n\nexport async function copyDir(srcdir: string, dstdir: string) {\n if (!fsExtra.existsSync(srcdir)) {\n return;\n }\n fsExtra.copySync(srcdir, dstdir, {overwrite: true});\n}\n\n/**\n * Copies a glob of files from one directory to another.\n *\n * Example:\n *\n * ```\n * await copyGlob('*.css', 'src/styles', 'dist/html/styles');\n * ```\n */\nexport async function copyGlob(\n pattern: string,\n srcdir: string,\n dstdir: string\n) {\n const files = await glob(pattern, {cwd: srcdir});\n if (files.length > 0) {\n await makeDir(dstdir);\n }\n files.forEach((file) => {\n fsExtra.copySync(path.resolve(srcdir, file), path.resolve(dstdir, file));\n });\n}\n\nexport async function rmDir(dirpath: string) {\n await fs.rm(dirpath, {recursive: true, force: true});\n}\n\nexport async function loadJson<T = unknown>(filepath: string): Promise<T> {\n const content = await fs.readFile(filepath, 'utf-8');\n return JSON.parse(content);\n}\n\nexport async function writeJson(filepath: string, data: any) {\n const content = JSON.stringify(data, null, 2);\n await writeFile(filepath, content);\n}\n\nexport async function isDirectory(dirpath: string) {\n return fs\n .stat(dirpath)\n .then((fsStat) => {\n return fsStat.isDirectory();\n })\n .catch((err) => {\n if (err.code === 'ENOENT') {\n return false;\n }\n throw err;\n });\n}\n\nexport function fileExists(filepath: string): Promise<boolean> {\n return fs\n .access(filepath)\n .then(() => true)\n .catch(() => false);\n}\n\nexport async function dirExists(dirpath: string): Promise<boolean> {\n try {\n const stat = await fs.stat(dirpath);\n return stat.isDirectory();\n } catch (error) {\n if (error.code === 'ENOENT') {\n return false;\n }\n throw error;\n }\n}\n\nexport async function directoryContains(\n dirpath: string,\n subpath: string\n): Promise<boolean> {\n const outer = await fs.realpath(dirpath);\n const inner = await fs.realpath(subpath);\n const rel = path.relative(outer, inner);\n return !rel.startsWith('..');\n}\n\nexport async function listFilesRecursive(dirPath: string): Promise<string[]> {\n const files: string[] = [];\n const entries = await fs.readdir(dirPath, {withFileTypes: true});\n for (const entry of entries) {\n const fullPath = path.join(dirPath, entry.name);\n if (entry.isDirectory()) {\n const subFiles = await listFilesRecursive(fullPath);\n files.push(...subFiles);\n } else {\n files.push(fullPath);\n }\n }\n return files;\n}\n","import {createServer, ViteDevServer} from 'vite';\nimport {RootConfig} from '../core/config.js';\nimport {getVitePlugins} from '../core/plugin.js';\n\nexport interface CreateViteServerOptions {\n /** Override HMR settings. */\n hmr?: boolean;\n /** The port the server will run on. */\n port?: number;\n /** List of files to include in the optimizeDeps.include config. */\n optimizeDeps?: string[];\n}\n\n/**\n * Returns a vite dev server.\n */\nexport async function createViteServer(\n rootConfig: RootConfig,\n options?: CreateViteServerOptions\n): Promise<ViteDevServer> {\n const rootDir = rootConfig.rootDir;\n const viteConfig = rootConfig.vite || {};\n\n let hmrOptions = viteConfig.server?.hmr;\n if (options?.hmr === false) {\n hmrOptions = false;\n } else if (typeof hmrOptions === 'undefined' && options?.port) {\n // Automatically set the HMR port to `port + 10`. This allows multiple\n // root.js dev servers to run without conflicts.\n hmrOptions = {port: options.port + 10};\n }\n\n const viteServer = await createServer({\n ...viteConfig,\n mode: 'development',\n root: rootDir,\n // publicDir is disabled from the vite dev server since it's handled by the\n // root dev server directly, which allows user middlewares to override\n // files in the public dir.\n publicDir: false,\n server: {\n ...(viteConfig.server || {}),\n middlewareMode: true,\n hmr: hmrOptions,\n },\n appType: 'custom',\n optimizeDeps: {\n // As of vite v5 / esbuild v19, experimentalDecorators need to be\n // explicitly set, and for some reason this option isn't read from the\n // project's tsconfig.json file by default.\n // See: https://vitejs.dev/blog/announcing-vite5\n esbuildOptions: {\n tsconfigRaw: {\n compilerOptions: {\n target: 'esnext',\n experimentalDecorators: true,\n useDefineForClassFields: false,\n },\n },\n },\n ...(viteConfig.optimizeDeps || {}),\n include: [\n ...(options?.optimizeDeps || []),\n ...(viteConfig.optimizeDeps?.include || []),\n ],\n extensions: [...(viteConfig.optimizeDeps?.extensions || []), '.tsx'],\n },\n ssr: {\n ...(viteConfig.ssr || {}),\n noExternal: ['@blinkk/root', '@blinkk/root-cms/richtext'],\n },\n esbuild: {\n ...(viteConfig.esbuild || {}),\n jsx: 'automatic',\n jsxImportSource: 'preact',\n },\n plugins: [\n ...(viteConfig.plugins || []),\n ...getVitePlugins(rootConfig.plugins || []),\n ],\n });\n return viteServer;\n}\n\n/**\n * Shortcut `viteServer.ssrLoadModule()` without starting an actual dev server.\n */\nexport async function viteSsrLoadModule(\n rootConfig: RootConfig,\n file: string\n): Promise<Record<string, any>> {\n const viteServer = await createViteServer(rootConfig, {hmr: false});\n const module = await viteServer.ssrLoadModule(file);\n await viteServer.close();\n return module;\n}\n"],"mappings":"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","names":["path","path","build"]}
package/dist/cli.js CHANGED
@@ -8,11 +8,11 @@ import {
8
8
  dev,
9
9
  preview,
10
10
  start
11
- } from "./chunk-FANTUKAU.js";
12
- import "./chunk-TZAHHHA4.js";
13
- import "./chunk-CKQSZDR6.js";
14
- import "./chunk-WHB5IDWW.js";
15
- import "./chunk-IUQLRDFW.js";
11
+ } from "./chunk-U2COJCIX.js";
12
+ import "./chunk-MLPPFGKW.js";
13
+ import "./chunk-YKQ4SVXX.js";
14
+ import "./chunk-6JZGMQBR.js";
15
+ import "./chunk-5YDJSEDK.js";
16
16
  export {
17
17
  CliRunner,
18
18
  build,
package/dist/core.js CHANGED
@@ -1,14 +1,14 @@
1
1
  import {
2
2
  configureServerPlugins,
3
3
  getVitePlugins
4
- } from "./chunk-WHB5IDWW.js";
4
+ } from "./chunk-6JZGMQBR.js";
5
5
  import {
6
6
  HTML_CONTEXT,
7
7
  Html,
8
8
  getTranslations,
9
9
  useI18nContext,
10
10
  useRequestContext
11
- } from "./chunk-7IDJ3PBT.js";
11
+ } from "./chunk-FKTS7ME3.js";
12
12
 
13
13
  // src/core/config.ts
14
14
  function defineConfig(config) {
package/dist/core.js.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"sources":["../src/core/config.ts","../src/core/components/Body.tsx","../src/core/components/Head.ts","../src/core/components/Script.ts","../src/core/hooks/useTranslations.ts"],"sourcesContent":["import {UserConfig as ViteUserConfig} from 'vite';\n\nimport {HtmlMinifyOptions} from '../render/html-minify';\nimport {HtmlPrettyOptions} from '../render/html-pretty';\n\nimport {Plugin} from './plugin';\nimport {RequestMiddleware} from './types';\n\nexport interface RootUserConfig {\n /**\n * Canonical domain the website will serve on. Useful for things like the\n * sitemap, SEO tags, etc.\n */\n domain?: string;\n\n /**\n * The base URL path that the site will serve on. Defaults to `/`;\n */\n base?: string;\n\n /**\n * Config for auto-injecting custom element dependencies.\n */\n elements?: {\n /**\n * A list of directories to use to look for custom elements. The dir path\n * should be relative to the project dir, e.g. \"path/to/elements\".\n */\n include?: string[];\n\n /**\n * A list of RegEx patterns to exclude. The string passed to the RegEx is\n * the file URL relative to the project root, e.g. \"/elements/foo/foo.ts\".\n */\n exclude?: RegExp[];\n };\n\n /**\n * Config options for localization and internationalization.\n */\n i18n?: RootI18nConfig;\n\n /**\n * Config options for the Root.js express server.\n */\n server?: RootServerConfig;\n\n /**\n * Vite config.\n * @see {@link https://vitejs.dev/config/} for more information.\n */\n vite?: ViteUserConfig;\n\n /**\n * Whether to automatically minify HTML output. This is enabled by default,\n * in order to disable, pass `minifyHtml: false` to root.config.ts.\n */\n minifyHtml?: boolean;\n\n /**\n * Options to pass to html-minifier-terser.\n */\n minifyHtmlOptions?: HtmlMinifyOptions;\n\n /**\n * Whether to pretty print HTML output.\n */\n prettyHtml?: boolean;\n\n /**\n * Options to pass to js-beautify.\n */\n prettyHtmlOptions?: HtmlPrettyOptions;\n\n /**\n * Whether to include a sitemap.xml file to the build output.\n */\n sitemap?: boolean;\n\n /**\n * Plugins.\n */\n plugins?: Plugin[];\n}\n\nexport type RootConfig = RootUserConfig & {\n rootDir: string;\n};\n\nexport interface LocaleGroup {\n label?: string;\n locales: string[];\n}\n\nexport interface RootI18nConfig {\n /**\n * Locales enabled for the site.\n */\n locales?: string[];\n\n /**\n * The default locale to use. Defaults is `en`.\n */\n defaultLocale?: string;\n\n /**\n * URL format for localized content. Default is `/[locale]/[base]/[path]`.\n */\n urlFormat?: string;\n\n /**\n * Localization groups, to help UIs (like Root.js CMS) logically group\n * locales.\n */\n groups?: Record<string, LocaleGroup>;\n}\n\nexport interface RootRedirectConfig {\n source: string;\n destination: string;\n type?: number;\n}\n\nexport interface RootHeaderConfig {\n /** A glob pattern match (regex not supported yet). */\n source: string;\n headers: Array<{\n key: string;\n value: string;\n }>;\n}\n\nexport interface ContentSecurityPolicyConfig {\n directives?: Record<string, string[]>;\n reportOnly?: boolean;\n}\n\nexport interface XFrameOptionsConfig {\n action: 'DENY' | 'SAMEORIGIN';\n}\n\nexport interface RootSecurityConfig {\n /**\n * Content-Security-Policy config. If enabled, a nonce is auto-generated\n * for every request and appended to script and stylesheet tags. You can\n * validate your CSP headers using a tool like {@link https://csp-evaluator.withgoogle.com/}.\n *\n * @see {@link https://developer.mozilla.org/en-US/docs/Web/HTTP/CSP}\n */\n contentSecurityPolicy?: ContentSecurityPolicyConfig | boolean;\n\n /**\n * Strict-Transport-Security config. When enabled, the header value is set\n * to `Strict-Transport-Security: max-age=63072000; includeSubDomains; preload`.\n */\n strictTransportSecurity?: boolean;\n\n /**\n * X-Content-Type-Options config. When enabled, the header value is set to\n * `X-Content-Type-Options: nosniff`.\n */\n xContentTypeOptions?: boolean;\n\n /**\n * X-Frame-Options config. Setting this value to `true` will default the\n * header value to `X-Frame-Options: SAMEORIGIN`.\n *\n * @see {@link https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/X-Frame-Options}\n */\n xFrameOptions?: 'DENY' | 'SAMEORIGIN' | boolean;\n\n /**\n * X-XSS-Protection config. When enabled, the header value is set to\n * `X-XSS-Protection: 1; mode=block`.\n */\n xXssProtection?: boolean;\n}\n\nexport interface RootServerConfig {\n /**\n * An array of middleware to add to the express server. These middleware are\n * added to the beginning of the express app.\n */\n middlewares?: RequestMiddleware[];\n\n /**\n * The `trailingSlash` config allows you to control how the server handles\n * trailing slashes. This config only affects URLs that do not have a file\n * extension (i.e. HTML paths).\n *\n * - When `true`, the server redirects URLs to add a trailing slash\n * - When `false`, the server redirects URLs to remove a trailing slash\n * - When unspecified, the server allows URLs with and without trailing slash\n */\n trailingSlash?: boolean;\n\n /**\n * Cookie secret for the session middleware.\n */\n sessionCookieSecret?: string | string[];\n\n /**\n * List of redirects.\n */\n redirects?: RootRedirectConfig[];\n\n /**\n * HTTP headers to add to a response.\n */\n headers?: RootHeaderConfig[];\n\n /**\n * HTTP security settings. By default, all security settings are enabled with\n * commonly used default values.\n */\n security?: RootSecurityConfig;\n}\n\nexport function defineConfig(config: RootUserConfig): RootUserConfig {\n return config;\n}\n","import {ComponentChildren, FunctionalComponent} from 'preact';\nimport {useContext} from 'preact/hooks';\n\nimport {HTML_CONTEXT} from './Html';\n\nexport type BodyProps = preact.JSX.HTMLAttributes<HTMLBodyElement> & {\n children?: ComponentChildren;\n};\n\n/**\n * The `<Body>` component can be used to update attrs in the `<body>` tag.\n *\n * Usage:\n *\n * ```tsx\n * <Body className=\"body\">\n * <h1>Hello world</h1>\n * </Body>\n * ```\n *\n * Output:\n *\n * ```html\n * <body class=\"body\">\n * <h1>Hello world</h1>\n * </body>\n */\nexport const Body: FunctionalComponent<BodyProps> = ({children, ...attrs}) => {\n const context = useContext(HTML_CONTEXT);\n if (!context) {\n throw new Error(\n 'HTML_CONTEXT not found, double-check usage of the <Body> component'\n );\n }\n context.bodyAttrs = attrs;\n return <>{children}</>;\n};\n","import {ComponentChildren, FunctionalComponent} from 'preact';\nimport {useContext} from 'preact/hooks';\n\nimport {HTML_CONTEXT} from './Html';\n\nexport type HeadProps = preact.JSX.HTMLAttributes<HTMLHeadElement> & {\n children?: ComponentChildren;\n};\n\n/**\n * The <Head> component can be used for injecting elements into the HTML head\n * tag from any part of a page. The <Head> can be added via any component or\n * sub-component and will automatically be hoisted to the `<head>` element.\n *\n * Usage:\n *\n * ```tsx\n * <Head>\n * <link rel=\"preconnect\" href=\"https://fonts.googleapis.com\" />\n * </Head>\n * ```\n */\nexport const Head: FunctionalComponent<HeadProps> = ({children, ...attrs}) => {\n const context = useContext(HTML_CONTEXT);\n if (!context) {\n throw new Error(\n 'HTML_CONTEXT not found, double-check usage of the <Head> component'\n );\n }\n context.headComponents.push(children);\n context.headAttrs = attrs;\n return null;\n};\n","import {FunctionalComponent} from 'preact';\nimport {useContext} from 'preact/hooks';\n\nimport {HTML_CONTEXT} from './Html';\n\nexport type ScriptProps = preact.JSX.HTMLAttributes<HTMLScriptElement>;\n\n/**\n * The <Script> component is used for rendering any custom script modules. At\n * the moment, the system only pre-renders and bundles files that are in the\n * `/bundles` folder at the root of the project.\n *\n * Usage:\n *\n * ```tsx\n * <Script src=\"/bundles/main.ts\" />\n * ```\n */\nexport const Script: FunctionalComponent<ScriptProps> = (props) => {\n const context = useContext(HTML_CONTEXT);\n if (!context) {\n throw new Error(\n 'HTML_CONTEXT not found, double-check usage of the <Script> component'\n );\n }\n context.scriptDeps.push(props);\n return null;\n};\n","import {I18nContext, useI18nContext} from './useI18nContext';\n\n/**\n * A hook that returns a function that can be used to translate a string, and\n * optionally replace any parameterized values that are surrounded in curly\n * braces.\n *\n * Usage:\n *\n * ```ts\n * const t = useTranslations();\n * t('Hello {name}', {name: 'Bob'});\n * // => 'Bounjour Bob'\n */\nexport function useTranslations() {\n // Ignore I18nContext not found error when used with client-side rehydration.\n let i18nContext: I18nContext | null = null;\n try {\n i18nContext = useI18nContext();\n } catch (err) {\n console.warn('I18nContext not found');\n }\n const translations = i18nContext?.translations || {};\n const t = (str: string, params?: Record<string, string | number>) => {\n const key = normalizeString(str);\n let translation = translations[key] ?? key ?? '';\n if (params) {\n for (const param of Object.keys(params)) {\n const val = String(params[param] ?? '');\n translation = translation.replaceAll(`{${param}}`, val);\n }\n }\n return translation;\n };\n return t;\n}\n\n/**\n * Cleans a string that's used for translations. Performs the following:\n * - Removes any leading/trailing whitespace\n * - Removes spaces at the end of any line\n */\nexport function normalizeString(str: string) {\n const lines = String(str)\n .trim()\n .split('\\n')\n .map((line) => line.trimEnd());\n return lines.join('\\n');\n}\n"],"mappings":";;;;;;;;;;;;;AA0NO,SAAS,aAAa,QAAwC;AACnE,SAAO;AACT;;;AC3NA,SAAQ,kBAAiB;AAkChB;AARF,IAAM,OAAuC,CAAC,EAAC,UAAU,GAAG,MAAK,MAAM;AAC5E,QAAM,UAAU,WAAW,YAAY;AACvC,MAAI,CAAC,SAAS;AACZ,UAAM,IAAI;AAAA,MACR;AAAA,IACF;AAAA,EACF;AACA,UAAQ,YAAY;AACpB,SAAO,gCAAG,UAAS;AACrB;;;ACnCA,SAAQ,cAAAA,mBAAiB;AAqBlB,IAAM,OAAuC,CAAC,EAAC,UAAU,GAAG,MAAK,MAAM;AAC5E,QAAM,UAAUC,YAAW,YAAY;AACvC,MAAI,CAAC,SAAS;AACZ,UAAM,IAAI;AAAA,MACR;AAAA,IACF;AAAA,EACF;AACA,UAAQ,eAAe,KAAK,QAAQ;AACpC,UAAQ,YAAY;AACpB,SAAO;AACT;;;AC/BA,SAAQ,cAAAC,mBAAiB;AAiBlB,IAAM,SAA2C,CAAC,UAAU;AACjE,QAAM,UAAUC,YAAW,YAAY;AACvC,MAAI,CAAC,SAAS;AACZ,UAAM,IAAI;AAAA,MACR;AAAA,IACF;AAAA,EACF;AACA,UAAQ,WAAW,KAAK,KAAK;AAC7B,SAAO;AACT;;;ACbO,SAAS,kBAAkB;AAEhC,MAAI,cAAkC;AACtC,MAAI;AACF,kBAAc,eAAe;AAAA,EAC/B,SAAS,KAAK;AACZ,YAAQ,KAAK,uBAAuB;AAAA,EACtC;AACA,QAAM,eAAe,aAAa,gBAAgB,CAAC;AACnD,QAAM,IAAI,CAAC,KAAa,WAA6C;AACnE,UAAM,MAAM,gBAAgB,GAAG;AAC/B,QAAI,cAAc,aAAa,GAAG,KAAK,OAAO;AAC9C,QAAI,QAAQ;AACV,iBAAW,SAAS,OAAO,KAAK,MAAM,GAAG;AACvC,cAAM,MAAM,OAAO,OAAO,KAAK,KAAK,EAAE;AACtC,sBAAc,YAAY,WAAW,IAAI,KAAK,KAAK,GAAG;AAAA,MACxD;AAAA,IACF;AACA,WAAO;AAAA,EACT;AACA,SAAO;AACT;AAOO,SAAS,gBAAgB,KAAa;AAC3C,QAAM,QAAQ,OAAO,GAAG,EACrB,KAAK,EACL,MAAM,IAAI,EACV,IAAI,CAAC,SAAS,KAAK,QAAQ,CAAC;AAC/B,SAAO,MAAM,KAAK,IAAI;AACxB;","names":["useContext","useContext","useContext","useContext"]}
1
+ {"version":3,"sources":["../src/core/config.ts","../src/core/components/Body.tsx","../src/core/components/Head.ts","../src/core/components/Script.ts","../src/core/hooks/useTranslations.ts"],"sourcesContent":["import {UserConfig as ViteUserConfig} from 'vite';\nimport {HtmlMinifyOptions} from '../render/html-minify.js';\nimport {HtmlPrettyOptions} from '../render/html-pretty.js';\nimport {Plugin} from './plugin.js';\nimport {RequestMiddleware} from './types.js';\n\nexport interface RootUserConfig {\n /**\n * Canonical domain the website will serve on. Useful for things like the\n * sitemap, SEO tags, etc.\n */\n domain?: string;\n\n /**\n * The base URL path that the site will serve on. Defaults to `/`;\n */\n base?: string;\n\n /**\n * Config for auto-injecting custom element dependencies.\n */\n elements?: {\n /**\n * A list of directories to use to look for custom elements. The dir path\n * should be relative to the project dir, e.g. \"path/to/elements\".\n */\n include?: string[];\n\n /**\n * A list of RegEx patterns to exclude. The string passed to the RegEx is\n * the file URL relative to the project root, e.g. \"/elements/foo/foo.ts\".\n */\n exclude?: RegExp[];\n };\n\n /**\n * Config options for localization and internationalization.\n */\n i18n?: RootI18nConfig;\n\n /**\n * Config options for the Root.js express server.\n */\n server?: RootServerConfig;\n\n /**\n * Vite config.\n * @see {@link https://vitejs.dev/config/} for more information.\n */\n vite?: ViteUserConfig;\n\n /**\n * Whether to automatically minify HTML output. This is enabled by default,\n * in order to disable, pass `minifyHtml: false` to root.config.ts.\n */\n minifyHtml?: boolean;\n\n /**\n * Options to pass to html-minifier-terser.\n */\n minifyHtmlOptions?: HtmlMinifyOptions;\n\n /**\n * Whether to pretty print HTML output.\n */\n prettyHtml?: boolean;\n\n /**\n * Options to pass to js-beautify.\n */\n prettyHtmlOptions?: HtmlPrettyOptions;\n\n /**\n * Whether to include a sitemap.xml file to the build output.\n */\n sitemap?: boolean;\n\n /**\n * Plugins.\n */\n plugins?: Plugin[];\n}\n\nexport type RootConfig = RootUserConfig & {\n rootDir: string;\n};\n\nexport interface LocaleGroup {\n label?: string;\n locales: string[];\n}\n\nexport interface RootI18nConfig {\n /**\n * Locales enabled for the site.\n */\n locales?: string[];\n\n /**\n * The default locale to use. Defaults is `en`.\n */\n defaultLocale?: string;\n\n /**\n * URL format for localized content. Default is `/[locale]/[base]/[path]`.\n */\n urlFormat?: string;\n\n /**\n * Localization groups, to help UIs (like Root.js CMS) logically group\n * locales.\n */\n groups?: Record<string, LocaleGroup>;\n}\n\nexport interface RootRedirectConfig {\n source: string;\n destination: string;\n type?: number;\n}\n\nexport interface RootHeaderConfig {\n /** A glob pattern match (regex not supported yet). */\n source: string;\n headers: Array<{\n key: string;\n value: string;\n }>;\n}\n\nexport interface ContentSecurityPolicyConfig {\n directives?: Record<string, string[]>;\n reportOnly?: boolean;\n}\n\nexport interface XFrameOptionsConfig {\n action: 'DENY' | 'SAMEORIGIN';\n}\n\nexport interface RootSecurityConfig {\n /**\n * Content-Security-Policy config. If enabled, a nonce is auto-generated\n * for every request and appended to script and stylesheet tags. You can\n * validate your CSP headers using a tool like {@link https://csp-evaluator.withgoogle.com/}.\n *\n * @see {@link https://developer.mozilla.org/en-US/docs/Web/HTTP/CSP}\n */\n contentSecurityPolicy?: ContentSecurityPolicyConfig | boolean;\n\n /**\n * Strict-Transport-Security config. When enabled, the header value is set\n * to `Strict-Transport-Security: max-age=63072000; includeSubDomains; preload`.\n */\n strictTransportSecurity?: boolean;\n\n /**\n * X-Content-Type-Options config. When enabled, the header value is set to\n * `X-Content-Type-Options: nosniff`.\n */\n xContentTypeOptions?: boolean;\n\n /**\n * X-Frame-Options config. Setting this value to `true` will default the\n * header value to `X-Frame-Options: SAMEORIGIN`.\n *\n * @see {@link https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/X-Frame-Options}\n */\n xFrameOptions?: 'DENY' | 'SAMEORIGIN' | boolean;\n\n /**\n * X-XSS-Protection config. When enabled, the header value is set to\n * `X-XSS-Protection: 1; mode=block`.\n */\n xXssProtection?: boolean;\n}\n\nexport interface RootServerConfig {\n /**\n * An array of middleware to add to the express server. These middleware are\n * added to the beginning of the express app.\n */\n middlewares?: RequestMiddleware[];\n\n /**\n * The `trailingSlash` config allows you to control how the server handles\n * trailing slashes. This config only affects URLs that do not have a file\n * extension (i.e. HTML paths).\n *\n * - When `true`, the server redirects URLs to add a trailing slash\n * - When `false`, the server redirects URLs to remove a trailing slash\n * - When unspecified, the server allows URLs with and without trailing slash\n */\n trailingSlash?: boolean;\n\n /**\n * Cookie secret for the session middleware.\n */\n sessionCookieSecret?: string | string[];\n\n /**\n * List of redirects.\n */\n redirects?: RootRedirectConfig[];\n\n /**\n * HTTP headers to add to a response.\n */\n headers?: RootHeaderConfig[];\n\n /**\n * HTTP security settings. By default, all security settings are enabled with\n * commonly used default values.\n */\n security?: RootSecurityConfig;\n}\n\nexport function defineConfig(config: RootUserConfig): RootUserConfig {\n return config;\n}\n","import {ComponentChildren, FunctionalComponent} from 'preact';\nimport {useContext} from 'preact/hooks';\nimport {HTML_CONTEXT} from './Html.js';\n\nexport type BodyProps = preact.JSX.HTMLAttributes<HTMLBodyElement> & {\n children?: ComponentChildren;\n};\n\n/**\n * The `<Body>` component can be used to update attrs in the `<body>` tag.\n *\n * Usage:\n *\n * ```tsx\n * <Body className=\"body\">\n * <h1>Hello world</h1>\n * </Body>\n * ```\n *\n * Output:\n *\n * ```html\n * <body class=\"body\">\n * <h1>Hello world</h1>\n * </body>\n */\nexport const Body: FunctionalComponent<BodyProps> = ({children, ...attrs}) => {\n const context = useContext(HTML_CONTEXT);\n if (!context) {\n throw new Error(\n 'HTML_CONTEXT not found, double-check usage of the <Body> component'\n );\n }\n context.bodyAttrs = attrs;\n return <>{children}</>;\n};\n","import {ComponentChildren, FunctionalComponent} from 'preact';\nimport {useContext} from 'preact/hooks';\nimport {HTML_CONTEXT} from './Html.js';\n\nexport type HeadProps = preact.JSX.HTMLAttributes<HTMLHeadElement> & {\n children?: ComponentChildren;\n};\n\n/**\n * The <Head> component can be used for injecting elements into the HTML head\n * tag from any part of a page. The <Head> can be added via any component or\n * sub-component and will automatically be hoisted to the `<head>` element.\n *\n * Usage:\n *\n * ```tsx\n * <Head>\n * <link rel=\"preconnect\" href=\"https://fonts.googleapis.com\" />\n * </Head>\n * ```\n */\nexport const Head: FunctionalComponent<HeadProps> = ({children, ...attrs}) => {\n const context = useContext(HTML_CONTEXT);\n if (!context) {\n throw new Error(\n 'HTML_CONTEXT not found, double-check usage of the <Head> component'\n );\n }\n context.headComponents.push(children);\n context.headAttrs = attrs;\n return null;\n};\n","import {FunctionalComponent} from 'preact';\nimport {useContext} from 'preact/hooks';\nimport {HTML_CONTEXT} from './Html.js';\n\nexport type ScriptProps = preact.JSX.HTMLAttributes<HTMLScriptElement>;\n\n/**\n * The <Script> component is used for rendering any custom script modules. At\n * the moment, the system only pre-renders and bundles files that are in the\n * `/bundles` folder at the root of the project.\n *\n * Usage:\n *\n * ```tsx\n * <Script src=\"/bundles/main.ts\" />\n * ```\n */\nexport const Script: FunctionalComponent<ScriptProps> = (props) => {\n const context = useContext(HTML_CONTEXT);\n if (!context) {\n throw new Error(\n 'HTML_CONTEXT not found, double-check usage of the <Script> component'\n );\n }\n context.scriptDeps.push(props);\n return null;\n};\n","import {I18nContext, useI18nContext} from './useI18nContext.js';\n\n/**\n * A hook that returns a function that can be used to translate a string, and\n * optionally replace any parameterized values that are surrounded in curly\n * braces.\n *\n * Usage:\n *\n * ```ts\n * const t = useTranslations();\n * t('Hello {name}', {name: 'Bob'});\n * // => 'Bounjour Bob'\n */\nexport function useTranslations() {\n // Ignore I18nContext not found error when used with client-side rehydration.\n let i18nContext: I18nContext | null = null;\n try {\n i18nContext = useI18nContext();\n } catch (err) {\n console.warn('I18nContext not found');\n }\n const translations = i18nContext?.translations || {};\n const t = (str: string, params?: Record<string, string | number>) => {\n const key = normalizeString(str);\n let translation = translations[key] ?? key ?? '';\n if (params) {\n for (const param of Object.keys(params)) {\n const val = String(params[param] ?? '');\n translation = translation.replaceAll(`{${param}}`, val);\n }\n }\n return translation;\n };\n return t;\n}\n\n/**\n * Cleans a string that's used for translations. Performs the following:\n * - Removes any leading/trailing whitespace\n * - Removes spaces at the end of any line\n */\nexport function normalizeString(str: string) {\n const lines = String(str)\n .trim()\n .split('\\n')\n .map((line) => line.trimEnd());\n return lines.join('\\n');\n}\n"],"mappings":";;;;;;;;;;;;;AAwNO,SAAS,aAAa,QAAwC;AACnE,SAAO;AACT;;;ACzNA,SAAQ,kBAAiB;AAiChB;AARF,IAAM,OAAuC,CAAC,EAAC,UAAU,GAAG,MAAK,MAAM;AAC5E,QAAM,UAAU,WAAW,YAAY;AACvC,MAAI,CAAC,SAAS;AACZ,UAAM,IAAI;AAAA,MACR;AAAA,IACF;AAAA,EACF;AACA,UAAQ,YAAY;AACpB,SAAO,gCAAG,UAAS;AACrB;;;AClCA,SAAQ,cAAAA,mBAAiB;AAoBlB,IAAM,OAAuC,CAAC,EAAC,UAAU,GAAG,MAAK,MAAM;AAC5E,QAAM,UAAUC,YAAW,YAAY;AACvC,MAAI,CAAC,SAAS;AACZ,UAAM,IAAI;AAAA,MACR;AAAA,IACF;AAAA,EACF;AACA,UAAQ,eAAe,KAAK,QAAQ;AACpC,UAAQ,YAAY;AACpB,SAAO;AACT;;;AC9BA,SAAQ,cAAAC,mBAAiB;AAgBlB,IAAM,SAA2C,CAAC,UAAU;AACjE,QAAM,UAAUC,YAAW,YAAY;AACvC,MAAI,CAAC,SAAS;AACZ,UAAM,IAAI;AAAA,MACR;AAAA,IACF;AAAA,EACF;AACA,UAAQ,WAAW,KAAK,KAAK;AAC7B,SAAO;AACT;;;ACZO,SAAS,kBAAkB;AAEhC,MAAI,cAAkC;AACtC,MAAI;AACF,kBAAc,eAAe;AAAA,EAC/B,SAAS,KAAK;AACZ,YAAQ,KAAK,uBAAuB;AAAA,EACtC;AACA,QAAM,eAAe,aAAa,gBAAgB,CAAC;AACnD,QAAM,IAAI,CAAC,KAAa,WAA6C;AACnE,UAAM,MAAM,gBAAgB,GAAG;AAC/B,QAAI,cAAc,aAAa,GAAG,KAAK,OAAO;AAC9C,QAAI,QAAQ;AACV,iBAAW,SAAS,OAAO,KAAK,MAAM,GAAG;AACvC,cAAM,MAAM,OAAO,OAAO,KAAK,KAAK,EAAE;AACtC,sBAAc,YAAY,WAAW,IAAI,KAAK,KAAK,GAAG;AAAA,MACxD;AAAA,IACF;AACA,WAAO;AAAA,EACT;AACA,SAAO;AACT;AAOO,SAAS,gBAAgB,KAAa;AAC3C,QAAM,QAAQ,OAAO,GAAG,EACrB,KAAK,EACL,MAAM,IAAI,EACV,IAAI,CAAC,SAAS,KAAK,QAAQ,CAAC;AAC/B,SAAO,MAAM,KAAK,IAAI;AACxB;","names":["useContext","useContext","useContext","useContext"]}
package/dist/functions.js CHANGED
@@ -1,11 +1,11 @@
1
1
  import {
2
2
  createPreviewServer,
3
3
  createProdServer
4
- } from "./chunk-FANTUKAU.js";
5
- import "./chunk-TZAHHHA4.js";
6
- import "./chunk-CKQSZDR6.js";
7
- import "./chunk-WHB5IDWW.js";
8
- import "./chunk-IUQLRDFW.js";
4
+ } from "./chunk-U2COJCIX.js";
5
+ import "./chunk-MLPPFGKW.js";
6
+ import "./chunk-YKQ4SVXX.js";
7
+ import "./chunk-6JZGMQBR.js";
8
+ import "./chunk-5YDJSEDK.js";
9
9
 
10
10
  // src/functions/server.ts
11
11
  import path from "node:path";
@@ -1 +1 @@
1
- {"version":3,"sources":["../src/functions/server.ts"],"sourcesContent":["import path from 'node:path';\nimport {HttpsOptions, onRequest} from 'firebase-functions/v2/https';\nimport {createPreviewServer, createProdServer} from '../cli/cli';\nimport {Server} from '../core/types';\n\nexport interface ProdServerOptions {\n rootDir?: string;\n mode?: 'preview' | 'production';\n httpsOptions?: HttpsOptions;\n}\n\n/**\n * Firebase Function that runs a Root.js server running in SSR mode.\n */\nexport function server(options?: ProdServerOptions) {\n let rootServer: Server;\n const rootDir = path.resolve(options?.rootDir || process.cwd());\n return onRequest(options?.httpsOptions || {}, async (req, res) => {\n if (!rootServer) {\n if (options?.mode === 'preview') {\n rootServer = await createPreviewServer({rootDir});\n } else {\n rootServer = await createProdServer({rootDir});\n }\n }\n await rootServer(req, res);\n });\n}\n"],"mappings":";;;;;;;;;;AAAA,OAAO,UAAU;AACjB,SAAsB,iBAAgB;AAa/B,SAAS,OAAO,SAA6B;AAClD,MAAI;AACJ,QAAM,UAAU,KAAK,QAAQ,SAAS,WAAW,QAAQ,IAAI,CAAC;AAC9D,SAAO,UAAU,SAAS,gBAAgB,CAAC,GAAG,OAAO,KAAK,QAAQ;AAChE,QAAI,CAAC,YAAY;AACf,UAAI,SAAS,SAAS,WAAW;AAC/B,qBAAa,MAAM,oBAAoB,EAAC,QAAO,CAAC;AAAA,MAClD,OAAO;AACL,qBAAa,MAAM,iBAAiB,EAAC,QAAO,CAAC;AAAA,MAC/C;AAAA,IACF;AACA,UAAM,WAAW,KAAK,GAAG;AAAA,EAC3B,CAAC;AACH;","names":[]}
1
+ {"version":3,"sources":["../src/functions/server.ts"],"sourcesContent":["import path from 'node:path';\nimport {HttpsOptions, onRequest} from 'firebase-functions/v2/https';\nimport {createPreviewServer, createProdServer} from '../cli/cli.js';\nimport {Server} from '../core/types.js';\n\nexport interface ProdServerOptions {\n rootDir?: string;\n mode?: 'preview' | 'production';\n httpsOptions?: HttpsOptions;\n}\n\n/**\n * Firebase Function that runs a Root.js server running in SSR mode.\n */\nexport function server(options?: ProdServerOptions) {\n let rootServer: Server;\n const rootDir = path.resolve(options?.rootDir || process.cwd());\n return onRequest(options?.httpsOptions || {}, async (req, res) => {\n if (!rootServer) {\n if (options?.mode === 'preview') {\n rootServer = await createPreviewServer({rootDir});\n } else {\n rootServer = await createProdServer({rootDir});\n }\n }\n await rootServer(req, res);\n });\n}\n"],"mappings":";;;;;;;;;;AAAA,OAAO,UAAU;AACjB,SAAsB,iBAAgB;AAa/B,SAAS,OAAO,SAA6B;AAClD,MAAI;AACJ,QAAM,UAAU,KAAK,QAAQ,SAAS,WAAW,QAAQ,IAAI,CAAC;AAC9D,SAAO,UAAU,SAAS,gBAAgB,CAAC,GAAG,OAAO,KAAK,QAAQ;AAChE,QAAI,CAAC,YAAY;AACf,UAAI,SAAS,SAAS,WAAW;AAC/B,qBAAa,MAAM,oBAAoB,EAAC,QAAO,CAAC;AAAA,MAClD,OAAO;AACL,qBAAa,MAAM,iBAAiB,EAAC,QAAO,CAAC;AAAA,MAC/C;AAAA,IACF;AACA,UAAM,WAAW,KAAK,GAAG;AAAA,EAC3B,CAAC;AACH;","names":[]}
@@ -6,7 +6,7 @@ import {
6
6
  rootProjectMiddleware,
7
7
  sessionMiddleware,
8
8
  trailingSlashMiddleware
9
- } from "./chunk-TZAHHHA4.js";
9
+ } from "./chunk-MLPPFGKW.js";
10
10
  export {
11
11
  SESSION_COOKIE,
12
12
  Session,
package/dist/node.js CHANGED
@@ -5,8 +5,8 @@ import {
5
5
  loadPackageJson,
6
6
  loadRootConfig,
7
7
  viteSsrLoadModule
8
- } from "./chunk-CKQSZDR6.js";
9
- import "./chunk-WHB5IDWW.js";
8
+ } from "./chunk-YKQ4SVXX.js";
9
+ import "./chunk-6JZGMQBR.js";
10
10
  export {
11
11
  bundleRootConfig,
12
12
  createViteServer,
package/dist/render.js CHANGED
@@ -3,20 +3,20 @@ import {
3
3
  I18N_CONTEXT,
4
4
  REQUEST_CONTEXT,
5
5
  getTranslations
6
- } from "./chunk-7IDJ3PBT.js";
6
+ } from "./chunk-FKTS7ME3.js";
7
7
  import {
8
8
  RouteTrie,
9
9
  htmlMinify,
10
10
  htmlPretty,
11
11
  parseTagNames
12
- } from "./chunk-IUQLRDFW.js";
12
+ } from "./chunk-5YDJSEDK.js";
13
13
 
14
14
  // src/render/render.tsx
15
15
  import crypto from "node:crypto";
16
16
  import {
17
17
  options as preactOptions
18
18
  } from "preact";
19
- import renderToString from "preact-render-to-string";
19
+ import { renderToString } from "preact-render-to-string";
20
20
 
21
21
  // src/core/pages/ErrorPage.tsx
22
22
  import { Fragment, jsx, jsxs } from "preact/jsx-runtime";
@@ -341,6 +341,8 @@ var ROUTES_FILES = import.meta.glob(
341
341
  { eager: true }
342
342
  );
343
343
  var Router = class {
344
+ rootConfig;
345
+ routeTrie;
344
346
  constructor(rootConfig) {
345
347
  this.rootConfig = rootConfig;
346
348
  this.routeTrie = this.initRouteTrie();
@@ -503,6 +505,11 @@ function toSquareBrackets(str) {
503
505
  // src/render/render.tsx
504
506
  import { jsx as jsx4, jsxs as jsxs4 } from "preact/jsx-runtime";
505
507
  var Renderer = class {
508
+ rootConfig;
509
+ // private routes: RouteTrie<Route>;
510
+ assetMap;
511
+ elementGraph;
512
+ router;
506
513
  constructor(rootConfig, options) {
507
514
  this.rootConfig = rootConfig;
508
515
  this.assetMap = options.assetMap;
@@ -634,7 +641,7 @@ var Renderer = class {
634
641
  };
635
642
  const vdom = /* @__PURE__ */ jsx4(REQUEST_CONTEXT.Provider, { value: ctx, children: /* @__PURE__ */ jsx4(I18N_CONTEXT.Provider, { value: { locale, translations }, children: /* @__PURE__ */ jsx4(HTML_CONTEXT.Provider, { value: htmlContext, children: /* @__PURE__ */ jsx4(Component, { ...props }) }) }) });
636
643
  const preactHook = preactOptions.vnode;
637
- let mainHtml;
644
+ let mainHtml = "";
638
645
  try {
639
646
  preactOptions.vnode = (vnode) => {
640
647
  if (vnode && vnode.type === "script") {
@@ -1 +1 @@
1
- {"version":3,"sources":["../src/render/render.tsx","../src/core/pages/ErrorPage.tsx","../src/core/pages/DevErrorPage.tsx","../src/core/pages/DevNotFoundPage.tsx","../src/render/accept-language.ts","../src/render/i18n-fallbacks.ts","../src/render/router.ts"],"sourcesContent":["import crypto from 'node:crypto';\nimport {\n ComponentChildren,\n ComponentType,\n VNode,\n options as preactOptions,\n} from 'preact';\nimport renderToString from 'preact-render-to-string';\nimport {HtmlContext, HTML_CONTEXT} from '../core/components/Html';\nimport {RootConfig, RootSecurityConfig} from '../core/config';\nimport {getTranslations, I18N_CONTEXT} from '../core/hooks/useI18nContext';\nimport {RequestContext, REQUEST_CONTEXT} from '../core/hooks/useRequestContext';\nimport {DevErrorPage} from '../core/pages/DevErrorPage';\nimport {DevNotFoundPage} from '../core/pages/DevNotFoundPage';\nimport {ErrorPage} from '../core/pages/ErrorPage';\nimport {\n Request,\n Response,\n NextFunction,\n HandlerContext,\n RouteParams,\n Route,\n HandlerRenderFn,\n HandlerRenderOptions,\n} from '../core/types';\nimport type {ElementGraph} from '../node/element-graph';\nimport {parseTagNames} from '../utils/elements';\nimport {AssetMap} from './asset-map/asset-map';\nimport {htmlMinify} from './html-minify';\nimport {htmlPretty} from './html-pretty';\nimport {getFallbackLocales} from './i18n-fallbacks';\nimport {replaceParams, Router} from './router';\n\ninterface RenderHtmlOptions {\n /** Attrs passed to the <html> tag, e.g. `{lang: 'en'}`. */\n htmlAttrs?: preact.JSX.HTMLAttributes<HTMLHtmlElement>;\n /** Attrs passed to the <head> tag. */\n headAttrs?: preact.JSX.HTMLAttributes<HTMLHeadElement>;\n /** Child components for the <head> tag. */\n headComponents?: ComponentChildren[];\n /** Attrs passed to the <body> tag. */\n bodyAttrs?: preact.JSX.HTMLAttributes<HTMLBodyElement>;\n}\n\nexport class Renderer {\n private rootConfig: RootConfig;\n // private routes: RouteTrie<Route>;\n private assetMap: AssetMap;\n private elementGraph: ElementGraph;\n private router: Router;\n\n constructor(\n rootConfig: RootConfig,\n options: {assetMap: AssetMap; elementGraph: ElementGraph}\n ) {\n this.rootConfig = rootConfig;\n // this.routes = getRoutes(this.rootConfig);\n this.assetMap = options.assetMap;\n this.elementGraph = options.elementGraph;\n this.router = new Router(rootConfig);\n }\n\n async handle(req: Request, res: Response, next: NextFunction) {\n const url = req.path;\n const [route, routeParams] = this.router.get(url);\n if (!route) {\n next();\n return;\n }\n if (route.locale) {\n routeParams.$locale = route.locale;\n }\n\n const fallbackLocales = route.isDefaultLocale\n ? getFallbackLocales(req)\n : [route.locale];\n const getPreferredLocale = (availableLocales: string[]) => {\n const lowerLocales = availableLocales.map((l) => l.toLowerCase());\n for (const fallbackLocale of fallbackLocales) {\n if (lowerLocales.includes(fallbackLocale.toLowerCase())) {\n return fallbackLocale;\n }\n }\n return req.rootConfig?.i18n?.defaultLocale || 'en';\n };\n\n const render404 = async () => {\n // Calling next() will allow the dev server or prod server handle the 404\n // page as appropriate for the env.\n next();\n };\n\n const render: HandlerRenderFn = async (\n props: any,\n options?: HandlerRenderOptions\n ) => {\n if (!route.module.default) {\n console.error(`no default component exported in route: ${route.src}`);\n render404();\n return;\n }\n const securityConfig = this.getSecurityConfig();\n const cspEnabled = !!securityConfig.contentSecurityPolicy;\n const currentPath = req.path;\n const locale = options?.locale || route.locale;\n const translations = options?.translations;\n const nonce = cspEnabled ? this.generateNonce() : undefined;\n const output = await this.renderComponent(route.module.default, props, {\n currentPath,\n route,\n routeParams,\n locale,\n translations,\n nonce,\n });\n let html = output.html;\n if (this.rootConfig.prettyHtml) {\n html = await htmlPretty(html, this.rootConfig.prettyHtmlOptions);\n } else if (this.rootConfig.minifyHtml !== false) {\n html = await htmlMinify(html, this.rootConfig.minifyHtmlOptions);\n }\n if (req.viteServer) {\n html = await req.viteServer.transformIndexHtml(currentPath, html);\n if (nonce) {\n html = html.replace(\n '<script type=\"module\" src=\"/@vite/client\"></script>',\n `<script type=\"module\" src=\"/@vite/client\" nonce=\"${nonce}\"></script>`\n );\n }\n }\n // Override the status code for 404 and 500 routes, which are defined at\n // routes/404.tsx and routes/500.tsx respectively.\n let statusCode = 200;\n if (route.src === 'routes/404.tsx') {\n statusCode = 404;\n } else if (route.src === 'routes/500.tsx') {\n statusCode = 500;\n }\n req.hooks.trigger('preRender');\n res.status(statusCode);\n res.set({'Content-Type': 'text/html'});\n this.setSecurityHeaders(res, {\n securityConfig: securityConfig,\n nonce: nonce,\n });\n res.end(html);\n };\n\n if (route.module.handle) {\n const handlerContext: HandlerContext = {\n route: route,\n params: routeParams,\n i18nFallbackLocales: fallbackLocales,\n getPreferredLocale: getPreferredLocale,\n render: render,\n render404: render404,\n };\n req.handlerContext = handlerContext;\n return route.module.handle(req, res, next);\n }\n\n let props = {};\n if (route.module.getStaticProps) {\n const propsData = await route.module.getStaticProps({\n rootConfig: this.rootConfig,\n params: routeParams,\n });\n if (propsData.notFound) {\n return render404();\n }\n if (propsData.props) {\n props = propsData.props;\n }\n }\n await render(props);\n }\n\n private async renderComponent(\n Component: ComponentType,\n props: any,\n options: {\n currentPath: string;\n route: Route;\n routeParams: RouteParams;\n locale: string;\n translations?: Record<string, string>;\n nonce?: string;\n }\n ) {\n const {currentPath, route, routeParams, nonce} = options;\n const locale = options.locale;\n const translations = {\n ...getTranslations(locale),\n ...(options.translations || {}),\n };\n const ctx: RequestContext = {\n currentPath,\n route,\n props,\n routeParams,\n locale,\n translations,\n nonce,\n };\n const htmlContext: HtmlContext = {\n htmlAttrs: {},\n headAttrs: {},\n headComponents: [],\n bodyAttrs: {},\n scriptDeps: [],\n };\n const vdom = (\n <REQUEST_CONTEXT.Provider value={ctx}>\n <I18N_CONTEXT.Provider value={{locale, translations}}>\n <HTML_CONTEXT.Provider value={htmlContext}>\n <Component {...props} />\n </HTML_CONTEXT.Provider>\n </I18N_CONTEXT.Provider>\n </REQUEST_CONTEXT.Provider>\n );\n\n // Create a hook to auto-inject nonce values.\n // https://preactjs.com/guide/v10/options/\n const preactHook = preactOptions.vnode;\n let mainHtml: string;\n try {\n preactOptions.vnode = (vnode: VNode<any>) => {\n // Inject nonce to `<script>` tags.\n if (vnode && vnode.type === 'script') {\n vnode.props.nonce = nonce;\n }\n // Inject nonce to `<style>` tags.\n if (vnode && vnode.type === 'style') {\n vnode.props.nonce = nonce;\n }\n // Inject nonce to `<link rel=\"stylesheet\">` tags.\n if (\n vnode &&\n vnode.type === 'link' &&\n vnode.props.rel === 'stylesheet'\n ) {\n vnode.props.nonce = nonce;\n }\n // Call the normal preact hook.\n if (preactHook) {\n preactHook(vnode);\n }\n };\n mainHtml = renderToString(vdom);\n preactOptions.vnode = preactHook;\n } catch (err) {\n preactOptions.vnode = preactHook;\n throw err;\n }\n\n const jsDeps = new Set<string>();\n const cssDeps = new Set<string>();\n\n // Walk the route's dependency tree for CSS dependencies that are added via\n // `import 'foo.scss'` or `import 'foo.module.scss'`.\n const routeAsset = await this.assetMap.get(route.src);\n if (routeAsset) {\n const routeCssDeps = await routeAsset.getCssDeps();\n routeCssDeps.forEach((dep) => {\n // Ignore ?inline css deps.\n if (dep.endsWith('?inline')) {\n return;\n }\n cssDeps.add(dep);\n });\n }\n\n // Parse the HTML for custom elements that are found within the project\n // and automatically inject the script deps for them.\n await this.collectElementDeps(mainHtml, jsDeps, cssDeps);\n\n // Add user defined scripts added via the `<Script>` component.\n await Promise.all(\n htmlContext.scriptDeps.map(async (scriptDep) => {\n if (!scriptDep.src) {\n return;\n }\n const assetId = String(scriptDep.src).slice(1);\n const scriptAsset = await this.assetMap.get(assetId);\n if (scriptAsset) {\n jsDeps.add(scriptAsset.assetUrl);\n const scriptJsDeps = await scriptAsset.getJsDeps();\n scriptJsDeps.forEach((dep) => jsDeps.add(dep));\n }\n })\n );\n\n const styleTags = Array.from(cssDeps).map((cssUrl) => {\n return <link rel=\"stylesheet\" href={cssUrl} nonce={nonce} />;\n });\n const scriptTags = Array.from(jsDeps).map((jsUrls) => {\n return <script type=\"module\" src={jsUrls} nonce={nonce} />;\n });\n\n const html = await this.renderHtml(mainHtml, {\n htmlAttrs: htmlContext.htmlAttrs,\n headAttrs: htmlContext.headAttrs,\n bodyAttrs: htmlContext.bodyAttrs,\n headComponents: [\n ...htmlContext.headComponents,\n ...styleTags,\n ...scriptTags,\n ],\n });\n return {html};\n }\n\n /** SSG renders a route. */\n async renderRoute(\n route: Route,\n options: {routeParams: Record<string, string>}\n ): Promise<{html?: string; notFound?: boolean}> {\n const routeParams = options.routeParams;\n if (route.locale) {\n routeParams.$locale = route.locale;\n }\n const Component = route.module.default;\n if (!Component) {\n throw new Error(\n 'unable to render route. the route should have a default export that renders a jsx component.'\n );\n }\n let props = {};\n let locale = route.locale;\n let translations = undefined;\n if (route.module.getStaticProps) {\n const propsData = await route.module.getStaticProps({\n rootConfig: this.rootConfig,\n params: routeParams,\n });\n if (propsData.notFound) {\n return {notFound: true};\n }\n if (propsData.props) {\n props = propsData.props;\n }\n if (propsData.locale) {\n locale = propsData.locale;\n }\n if (propsData.translations) {\n translations = propsData.translations;\n }\n }\n const routePath = route.isDefaultLocale\n ? route.routePath\n : route.localeRoutePath;\n const currentPath = replaceParams(routePath, {\n ...routeParams,\n locale: locale,\n });\n return this.renderComponent(Component, props, {\n currentPath,\n route,\n routeParams,\n locale,\n translations,\n });\n }\n\n async getSitemap(): Promise<\n Record<string, {route: Route; params: Record<string, string>}>\n > {\n const sitemap: Record<\n string,\n {route: Route; params: Record<string, string>}\n > = {};\n await this.router.walk(async (urlPath: string, route: Route) => {\n const routePaths = await this.router.getAllPathsForRoute(urlPath, route);\n routePaths.forEach((routePath) => {\n sitemap[routePath.urlPath] = {\n route,\n params: routePath.params,\n };\n });\n });\n return sitemap;\n }\n\n private async renderHtml(html: string, options?: RenderHtmlOptions) {\n const htmlAttrs = options?.htmlAttrs || {};\n const headAttrs = options?.headAttrs || {};\n const bodyAttrs = options?.bodyAttrs || {};\n const page = (\n <html {...htmlAttrs}>\n <head {...headAttrs}>\n <meta charSet=\"utf-8\" />\n {options?.headComponents}\n </head>\n <body {...bodyAttrs} dangerouslySetInnerHTML={{__html: html}} />\n </html>\n );\n return `<!doctype html>\\n${renderToString(page)}\\n`;\n }\n\n async render404(options?: {currentPath?: string}) {\n const currentPath = options?.currentPath || '/404';\n const [route, routeParams] = this.router.get('/404');\n if (route && route.src === 'routes/404.tsx' && route.module.default) {\n const Component = route.module.default;\n return this.renderComponent(\n Component,\n {},\n {currentPath, route, routeParams, locale: 'en'}\n );\n }\n\n const mainHtml = renderToString(\n <ErrorPage\n code={404}\n title=\"Not found\"\n message=\"Double-check the URL entered and try again.\"\n align=\"center\"\n />\n );\n const html = await this.renderHtml(mainHtml, {\n headComponents: [\n <title>404 Not Found</title>,\n <meta\n name=\"viewport\"\n content=\"width=device-width, initial-scale=1.0\"\n />,\n ],\n });\n return {html};\n }\n\n async renderError(err: any, options?: {currentPath?: string}) {\n const currentPath = options?.currentPath || '/500';\n const [route, routeParams] = this.router.get('/500');\n if (route && route.src === 'routes/500.tsx' && route.module.default) {\n const Component = route.module.default;\n return this.renderComponent(\n Component,\n {error: err},\n {currentPath, route, routeParams, locale: 'en'}\n );\n }\n\n const mainHtml = renderToString(\n <ErrorPage\n code={500}\n title=\"Something went wrong\"\n message=\"An unknown error occurred.\"\n align=\"center\"\n />\n );\n const html = await this.renderHtml(mainHtml, {\n headComponents: [\n <title>500 Error</title>,\n <meta\n name=\"viewport\"\n content=\"width=device-width, initial-scale=1.0\"\n />,\n ],\n });\n return {html};\n }\n\n async renderDevServer404(req: Request) {\n const sitemap = await this.getSitemap();\n const mainHtml = renderToString(\n <DevNotFoundPage req={req} sitemap={sitemap} />\n );\n const html = await this.renderHtml(mainHtml, {\n headComponents: [<title>404 Not found | Root.js</title>],\n });\n return {html};\n }\n\n async renderDevServer500(req: Request, error: unknown) {\n const [route, routeParams] = this.router.get(req.path);\n const mainHtml = renderToString(\n <DevErrorPage\n req={req}\n route={route}\n routeParams={routeParams}\n error={error}\n />\n );\n const html = await this.renderHtml(mainHtml, {\n headComponents: [<title>500 Error | Root.js</title>],\n });\n return {html};\n }\n\n /**\n * Parses rendered HTML for custom element tags used on the page and\n * automatically adds the JS/CSS deps to the page.\n */\n private async collectElementDeps(\n html: string,\n jsDeps: Set<string>,\n cssDeps: Set<string>\n ): Promise<{jsDeps: Set<string>; cssDeps: Set<string>}> {\n const elementsMap = this.elementGraph.sourceFiles;\n const assetMap = this.assetMap;\n\n const tagNames = new Set<string>();\n for (const tagName of parseTagNames(html)) {\n if (tagName && tagName in elementsMap) {\n tagNames.add(tagName);\n for (const depTagName of this.elementGraph.getDeps(tagName)) {\n tagNames.add(depTagName);\n }\n }\n }\n\n await Promise.all(\n Array.from(tagNames).map(async (tagName: string) => {\n const elementModule = elementsMap[tagName];\n const asset = await assetMap.get(elementModule.relPath);\n if (!asset) {\n return;\n }\n const assetJsDeps = await asset.getJsDeps();\n assetJsDeps.forEach((dep) => jsDeps.add(dep));\n const assetCssDeps = await asset.getCssDeps();\n assetCssDeps.forEach((dep) => {\n // Ignore ?inline css deps.\n if (dep.endsWith('?inline')) {\n return;\n }\n cssDeps.add(dep);\n });\n })\n );\n\n return {jsDeps, cssDeps};\n }\n\n /**\n * Returns the `security` config value with default values inserted wherever\n * a user config value is blank or set to `true`.\n */\n private getSecurityConfig() {\n const userConfig: Partial<RootSecurityConfig> =\n this.rootConfig.server?.security || {};\n const securityConfig: Partial<RootSecurityConfig> = {};\n\n if (isTrueOrUndefined(userConfig.contentSecurityPolicy)) {\n // CSP default values from:\n // https://csp.withgoogle.com/docs/strict-csp.html\n securityConfig.contentSecurityPolicy = {\n directives: {\n 'base-uri': [\"'none'\"],\n 'object-src': [\"'none'\"],\n // NOTE: nonce is automatically added to this list.\n 'script-src': [\n \"'unsafe-inline'\",\n \"'unsafe-eval'\",\n \"'strict-dynamic' https: http:\",\n ],\n },\n reportOnly: true,\n };\n } else {\n securityConfig.contentSecurityPolicy = userConfig.contentSecurityPolicy;\n }\n\n if (isTrueOrUndefined(userConfig.xFrameOptions)) {\n securityConfig.xFrameOptions = 'SAMEORIGIN';\n } else {\n securityConfig.xFrameOptions = userConfig.xFrameOptions;\n }\n\n securityConfig.strictTransportSecurity =\n userConfig.strictTransportSecurity ?? true;\n securityConfig.xContentTypeOptions = userConfig.xContentTypeOptions ?? true;\n securityConfig.xXssProtection = userConfig.xXssProtection ?? true;\n\n return securityConfig as Required<RootSecurityConfig>;\n }\n\n /**\n * Generates a random string that can be used as the \"nonce\" value for CSP.\n */\n private generateNonce() {\n return crypto.randomBytes(16).toString('base64');\n }\n\n /**\n * Sets security-related HTTP headers.\n */\n private setSecurityHeaders(\n res: Response,\n options: {securityConfig: Required<RootSecurityConfig>; nonce?: string}\n ) {\n const securityConfig = options.securityConfig;\n\n // Content-Security-Policy.\n const contentSecurityPolicy = securityConfig.contentSecurityPolicy;\n if (typeof contentSecurityPolicy === 'object') {\n const directives = contentSecurityPolicy.directives || {};\n if (options.nonce) {\n if (!directives['script-src']) {\n directives['script-src'] = [\n \"'unsafe-inline'\",\n \"'unsafe-eval'\",\n \"'strict-dynamic' https: http:\",\n ];\n }\n directives['script-src'].push(`'nonce-${options.nonce}'`);\n }\n const headerSegments: string[] = [];\n Object.entries(directives).forEach(([key, values]) => {\n headerSegments.push([key, ...values].join(' '));\n });\n const csp = headerSegments.join('; ');\n if (contentSecurityPolicy.reportOnly === false) {\n res.setHeader('content-security-policy', csp);\n } else {\n res.setHeader('content-security-policy-report-only', csp);\n }\n }\n\n // X-Frame-Options.\n if (typeof securityConfig.xFrameOptions === 'string') {\n res.setHeader('x-frame-options', securityConfig.xFrameOptions);\n }\n\n // Strict-Transport-Security.\n if (securityConfig.strictTransportSecurity) {\n res.setHeader(\n 'strict-transport-security',\n 'max-age=63072000; includeSubdomains; preload'\n );\n }\n\n // X-Content-Type-Options.\n if (securityConfig.xContentTypeOptions) {\n res.setHeader('x-content-type-options', 'nosniff');\n }\n\n // X-XSS-Protection.\n if (securityConfig.xXssProtection) {\n res.setHeader('x-xss-protection', '1; mode=block');\n }\n }\n}\n\nfunction isTrueOrUndefined(value: any) {\n return value === true || value === undefined;\n}\n","import {ComponentChildren} from 'preact';\n\nconst STYLES = `\n@import url('https://fonts.googleapis.com/css2?family=Inter:wght@400;700&display=swap');\n\n:root {\n --font-family-text: \"Inter\", sans-serif;\n}\n\nbody {\n font-family: var(--font-family-text);\n background: #F5F5F5;\n padding: 40px 16px;\n}\n\n.root {\n max-width: 1200px;\n margin: 0 auto;\n}\n\n.root.align-center {\n text-align: center;\n}\n\nh1.title {\n margin-top: 0;\n margin-bottom: 24px;\n}\n\np.message {\n margin-top: 0;\n margin-bottom: 0;\n}\n\n.box {\n font-size: 16px;\n line-height: 1.5;\n padding: 16px;\n border-radius: 12px;\n background: #ffffff;\n}\n\npre.box {\n white-space: pre-wrap;\n}\n\n@media (min-width: 500px) {\n body {\n padding: 40px;\n }\n\n .box {\n padding: 24px;\n }\n}\n\n@media (min-width: 1024px) {\n body {\n padding: 100px;\n }\n}\n`;\n\nexport interface ErrorPageProps {\n code: number;\n title?: string;\n message?: string;\n children?: ComponentChildren;\n align?: 'center';\n}\n\nexport function ErrorPage(props: ErrorPageProps) {\n const {code, message} = props;\n const title = props.title || code;\n return (\n <>\n <style dangerouslySetInnerHTML={{__html: STYLES}}></style>\n <div className={`root align-${props.align || 'left'}`}>\n <h1 className=\"title\">{title}</h1>\n {message && <p className=\"message\">{message}</p>}\n {props.children}\n </div>\n </>\n );\n}\n","import {Request, Route, RouteParams} from '../types';\n\nimport {ErrorPage} from './ErrorPage';\n\ninterface DevErrorPageProps {\n req: Request;\n route?: Route;\n routeParams?: RouteParams;\n error: any;\n}\n\nexport function DevErrorPage(props: DevErrorPageProps) {\n const req = props.req;\n const err = props.error;\n const route = props.route;\n const routeParams = props.routeParams;\n\n let errMsg = String(err);\n if (err && err.stack) {\n // Obfuscate some user info from the stack trace so that when people send\n // error reports and screenshots, less identifiable information is sent.\n errMsg = err.stack\n .replace(/\\(.*node_modules/g, '(node_modules')\n .replace(/at \\/.*node_modules/g, 'at node_modules');\n if (req.rootConfig?.rootDir) {\n errMsg = errMsg.replaceAll(req.rootConfig.rootDir, '<root>');\n }\n if (process.env.HOME) {\n errMsg = errMsg.replaceAll(process.env.HOME, '$HOME');\n }\n }\n return (\n <ErrorPage code={500} title=\"Something went wrong\">\n {errMsg && (\n <>\n <h2>Error</h2>\n <pre className=\"box\">\n <code>{errMsg}</code>\n </pre>\n </>\n )}\n <h2>Debug Info</h2>\n <pre className=\"box\">\n <code>{`url: ${req.originalUrl}\nroute: ${route?.src || 'null'}\nrouteParams: ${(routeParams && JSON.stringify(routeParams)) || 'null'}`}</code>\n </pre>\n </ErrorPage>\n );\n}\n","import {Request, Route} from '../types';\n\nimport {ErrorPage} from './ErrorPage';\n\ninterface DevNotFoundPageProps {\n req: Request;\n sitemap: Record<string, {route: Route; params: Record<string, string>}>;\n}\n\ninterface RoutesListMap {\n [src: string]: Array<RouteURLPath>;\n}\n\ninterface RouteURLPath {\n route: Route;\n urlPath: string;\n}\n\nexport function DevNotFoundPage(props: DevNotFoundPageProps) {\n const req = props.req;\n const routesListMap: RoutesListMap = {};\n let srcMaxLength = 0;\n Object.keys(props.sitemap).forEach((urlPath) => {\n const route = props.sitemap[urlPath].route;\n routesListMap[route.src] ??= [];\n routesListMap[route.src].push({route, urlPath});\n if (route.src.length > srcMaxLength) {\n srcMaxLength = route.src.length;\n }\n });\n const routeSrcs = Object.keys(routesListMap).sort(sortRouteFiles);\n const lines: string[] = [];\n routeSrcs.forEach((routeSrc) => {\n const routeUrls = routesListMap[routeSrc].sort(sortRouteURLs);\n routeUrls.forEach((routeUrl, i) => {\n const urlPath = routeUrl.urlPath;\n if (i === 0) {\n lines.push(`${routeSrc.padEnd(srcMaxLength, ' ')} => ${urlPath}`);\n } else {\n lines.push(`${''.padEnd(srcMaxLength, ' ')} => ${urlPath}`);\n }\n });\n });\n const routesListString = lines.join('\\n');\n // const routesListString = routesList\n // .map((route) => {\n // return `${route.urlPath.padEnd(srcMaxLength, ' ')} => ${route.src}`;\n // })\n // .join('\\n');\n return (\n <ErrorPage code={404} title=\"Not found\">\n <h2>Routes</h2>\n {Object.keys(routesListMap).length > 0 ? (\n <pre className=\"box\">\n <code>{routesListString}</code>\n </pre>\n ) : (\n <div className=\"box\">\n Add your first route at <code>/routes/index.tsx</code>\n </div>\n )}\n\n <h2>Debug Info</h2>\n <pre className=\"box\">\n <code>{`url: ${req.originalUrl}`}</code>\n </pre>\n </ErrorPage>\n );\n}\n\nfunction sortRouteFiles(a: string, b: string): number {\n if (a === 'routes/index.tsx') {\n return -1;\n }\n if (b === 'routes/index.tsx') {\n return 1;\n }\n return a.localeCompare(b);\n}\n\nfunction sortRouteURLs(a: RouteURLPath, b: RouteURLPath): number {\n if (a.route.isDefaultLocale && !b.route.isDefaultLocale) {\n return -1;\n }\n if (!a.route.isDefaultLocale && b.route.isDefaultLocale) {\n return 1;\n }\n return a.urlPath.localeCompare(b.urlPath);\n}\n","export const ACCEPT_LANG_RE =\n /((([a-zA-Z]+(-[a-zA-Z0-9]+){0,2})|\\*)(;q=[0-1](\\.[0-9]+)?)?)*/g;\n\nexport interface AcceptLanguage {\n code: string;\n script?: string;\n region?: string;\n quality: number;\n}\n\nexport function parseAcceptLanguage(value: string): AcceptLanguage[] {\n const matches = String(value).match(ACCEPT_LANG_RE);\n if (!matches) {\n return [];\n }\n const results: AcceptLanguage[] = [];\n matches.forEach((m) => {\n if (!m) {\n return;\n }\n\n const parts = m.split(';');\n const ietf = parts[0].split('-');\n const hasScript = ietf.length === 3;\n\n results.push({\n code: ietf[0],\n script: hasScript ? ietf[1] : undefined,\n region: hasScript ? ietf[2] : ietf[1],\n quality: parts[1] ? parseFloat(parts[1].split('=')[1]) : 1.0,\n });\n });\n results.sort((a, b) => b.quality - a.quality);\n return results;\n}\n","/**\n * Utility functions for handling requests that mimic the Firebase Hosting i18n\n * fallback logic.\n * https://firebase.google.com/docs/hosting/i18n-rewrites\n */\n\nimport {Request} from '../core/types';\nimport {parseAcceptLanguage} from './accept-language';\n\nexport const UNKNOWN_COUNTRY = 'zz';\nexport const ES_419_COUNTRIES = [\n 'ar', // Argentina\n 'bo', // Bolivia\n 'cl', // Chile\n 'co', // Colombia\n 'cr', // Costa Rica\n 'cu', // Cuba\n 'do', // Dominican Republic\n 'ec', // Ecuador\n 'sv', // El Salvador\n 'gt', // Guatemala\n 'hn', // Honduras\n 'mx', // Mexico\n 'ni', // Nicaragua\n 'pa', // Panama\n 'py', // Paraguay\n 'pe', // Peru\n 'pr', // Puerto Rico\n 'uy', // Uruguay\n 've', // Venezuela\n];\n\nexport function getFallbackLocales(req: Request): string[] {\n const hl = getFirstQueryParam(req, 'hl');\n const countryCode = getCountry(req);\n\n // Web crawlers should only use the default locale.\n if (isWebCrawler(req)) {\n const defaultLocale = req.rootConfig?.i18n?.defaultLocale || 'en';\n if (hl && hl !== defaultLocale) {\n return [hl, defaultLocale];\n }\n return [defaultLocale];\n }\n\n const locales = new Set<string>();\n\n // Add locales from ?hl= query parameter.\n if (hl) {\n const langCode = hl;\n locales.add(`${langCode}_${countryCode}`);\n locales.add(`${langCode}_ALL`);\n locales.add(langCode);\n }\n\n const langs = getFallbackLanguages(req);\n\n // Add `{lang}_{country}` locales.\n langs.forEach((langCode) => {\n locales.add(`${langCode}_${countryCode}`);\n });\n\n // Add ALL_{country} locale.\n locales.add(`ALL_${countryCode}`);\n\n // Add `{lang}_ALL` and `{lang}` locales.\n const isEs419Country = test419Country(countryCode);\n langs.forEach((langCode) => {\n // For Spanish-speaking LATAM countries, also add es-419.\n if (langCode === 'es' && isEs419Country) {\n locales.add('es-419_ALL');\n locales.add('es-419');\n }\n locales.add(`${langCode}_ALL`);\n locales.add(langCode);\n });\n\n return Array.from(locales) as string[];\n}\n\nexport function getCountry(req: Request) {\n const normalize = (countryCode: string) => String(countryCode).toLowerCase();\n // Check the ?gl= query param.\n const gl = getFirstQueryParam(req, 'gl');\n if (gl) {\n return normalize(gl);\n }\n const gaeCountry =\n req.get('x-country-code') || req.get('x-appengine-country');\n if (gaeCountry) {\n return normalize(gaeCountry);\n }\n return UNKNOWN_COUNTRY;\n}\n\nfunction getFallbackLanguages(req: Request): string[] {\n const langs = new Set<string>();\n // Add languages from the Accept-Language header.\n const acceptLangHeader = req.get('accept-language') || '';\n if (acceptLangHeader) {\n parseAcceptLanguage(acceptLangHeader).forEach((lang) => {\n // For a lang like `en-US`, add both `en-US` and `en`.\n if (lang.region) {\n langs.add(`${lang.code}-${lang.region}`);\n // For Spanish-speaking LATAM countries, also add es-419.\n if (lang.code === 'es' && test419Country(lang.region)) {\n langs.add('es-419');\n }\n }\n langs.add(lang.code);\n });\n }\n // Fall back to \"en\" as a last resort.\n langs.add('en');\n return Array.from(langs);\n}\n\n/**\n * Returns the first query param value in a given request.\n *\n * For example, for a URL like `/?foo=bar&foo=baz`, calling\n * `getFirstQueryParam(req, 'foo')` would return `\"bar\"`.\n */\nfunction getFirstQueryParam(req: Request, key: string): string | null {\n const val = req.query[key];\n if (val === null || val === undefined) {\n return null;\n }\n if (Array.isArray(val)) {\n if (val.length === 0) {\n return null;\n }\n return String(val[0]);\n }\n return String(val);\n}\n\nfunction isWebCrawler(req: Request): boolean {\n const userAgentHeader = req.get('User-Agent');\n if (!userAgentHeader) {\n return false;\n }\n const userAgent = userAgentHeader.toLowerCase();\n return (\n userAgent.includes('googlebot') ||\n userAgent.includes('bingbot') ||\n userAgent.includes('twitterbot')\n );\n}\n\nexport function test419Country(countryCode: string) {\n return ES_419_COUNTRIES.includes(countryCode);\n}\n","import path from 'node:path';\nimport {RootConfig} from '../core/config';\nimport {Route, RouteModule} from '../core/types';\nimport {RouteTrie} from './route-trie';\n\nconst ROUTES_FILES = import.meta.glob<RouteModule>(\n ['/routes/*.ts', '/routes/**/*.ts', '/routes/*.tsx', '/routes/**/*.tsx'],\n {eager: true}\n);\n\nexport class Router {\n private rootConfig: RootConfig;\n private routeTrie: RouteTrie<Route>;\n\n constructor(rootConfig: RootConfig) {\n this.rootConfig = rootConfig;\n this.routeTrie = this.initRouteTrie();\n }\n\n get(url: string) {\n return this.routeTrie.get(url);\n }\n\n async walk(cb: (urlPath: string, route: Route) => void | Promise<void>) {\n await this.routeTrie.walk(cb);\n }\n\n private initRouteTrie() {\n const locales = this.rootConfig.i18n?.locales || [];\n const basePath = this.rootConfig.base || '/';\n const defaultLocale = this.rootConfig.i18n?.defaultLocale || 'en';\n\n const trie = new RouteTrie<Route>();\n Object.keys(ROUTES_FILES).forEach((modulePath) => {\n const src = modulePath.slice(1);\n let relativeRoutePath = modulePath.replace(/^\\/routes/, '');\n const parts = path.parse(relativeRoutePath);\n if (parts.name.startsWith('_')) {\n return;\n }\n if (parts.name === 'index') {\n relativeRoutePath = parts.dir;\n } else {\n relativeRoutePath = path.join(parts.dir, parts.name);\n }\n\n const urlFormat = '/[base]/[path]';\n const i18nUrlFormat = toSquareBrackets(\n this.rootConfig.i18n?.urlFormat || '/[locale]/[base]/[path]'\n );\n const placeholders = {\n base: removeSlashes(basePath),\n path: removeSlashes(relativeRoutePath),\n };\n\n const formatUrl = (format: string) => {\n const url = format\n .replaceAll('[base]', placeholders.base)\n .replaceAll('[path]', placeholders.path);\n return normalizeUrlPath(url, {\n trailingSlash: this.rootConfig.server?.trailingSlash,\n });\n };\n\n const routePath = formatUrl(urlFormat);\n const localeRoutePath = formatUrl(i18nUrlFormat);\n\n trie.add(routePath, {\n src,\n module: ROUTES_FILES[modulePath],\n locale: defaultLocale,\n isDefaultLocale: true,\n routePath: routePath,\n localeRoutePath: localeRoutePath,\n });\n\n // At the moment, all routes are assumed to use the site-wide i18n config.\n // TODO(stevenle): provide routes with a way to override the default\n // i18n serving behavior.\n if (i18nUrlFormat.includes('[locale]')) {\n locales.forEach((locale) => {\n const localePath = localeRoutePath.replace('[locale]', locale);\n if (localePath !== relativeRoutePath) {\n trie.add(localePath, {\n src,\n module: ROUTES_FILES[modulePath],\n locale: locale,\n isDefaultLocale: false,\n routePath,\n localeRoutePath,\n });\n }\n });\n }\n });\n return trie;\n }\n\n async getAllPathsForRoute(\n urlPathFormat: string,\n route: Route\n ): Promise<Array<{urlPath: string; params: Record<string, string>}>> {\n const routeModule = route.module;\n if (!routeModule.default) {\n return [];\n }\n\n const urlPaths: Array<{urlPath: string; params: Record<string, string>}> =\n [];\n if (routeModule.getStaticPaths) {\n const staticPaths = await routeModule.getStaticPaths({\n rootConfig: this.rootConfig,\n });\n if (staticPaths.paths) {\n staticPaths.paths.forEach(\n (pathParams: {params: Record<string, string>}) => {\n const urlPath = replaceParams(\n urlPathFormat,\n pathParams.params || {}\n );\n if (pathContainsPlaceholders(urlPath)) {\n console.warn(\n `path contains placeholders: ${urlPathFormat}, double check getStaticPaths() and ensure all params are returned. more info: https://rootjs.dev/guide/routes#getStaticPaths`\n );\n } else {\n urlPaths.push({\n urlPath: normalizeUrlPath(urlPath),\n params: pathParams.params || {},\n });\n }\n }\n );\n }\n } else if (\n routeModule.getStaticProps &&\n !pathContainsPlaceholders(urlPathFormat)\n ) {\n urlPaths.push({urlPath: normalizeUrlPath(urlPathFormat), params: {}});\n } else if (\n !routeModule.handle &&\n !pathContainsPlaceholders(urlPathFormat)\n ) {\n urlPaths.push({urlPath: normalizeUrlPath(urlPathFormat), params: {}});\n } else if (\n pathContainsPlaceholders(urlPathFormat) &&\n !routeModule.handle &&\n !routeModule.getStaticPaths\n ) {\n console.warn(\n [\n `warning: path contains placeholders: ${urlPathFormat}.`,\n `define either ssg getStaticPaths() or ssr handle() for route: ${route.src}.`,\n 'more info: https://rootjs.dev/guide/routes',\n ].join('\\n')\n );\n }\n\n return urlPaths;\n }\n}\n\nexport function replaceParams(\n urlPathFormat: string,\n params: Record<string, string>\n) {\n const urlPath = urlPathFormat.replaceAll(\n /\\[\\[?(\\.\\.\\.)?([\\w\\-_]*)\\]?\\]/g,\n (match: string, _wildcard: string, key: string) => {\n const val = params[key];\n if (!val) {\n throw new Error(`unreplaced param ${match} in url: ${urlPathFormat}`);\n }\n return val;\n }\n );\n return urlPath;\n}\n\nexport function normalizeUrlPath(\n urlPath: string,\n options?: {trailingSlash?: boolean}\n) {\n // Collapse multiple slashes, e.g. `/foo//bar` => `/foo/bar`;\n urlPath = urlPath.replace(/\\/+/g, '/');\n // Remove trailing slash.\n if (\n options?.trailingSlash === false &&\n urlPath !== '/' &&\n urlPath.endsWith('/')\n ) {\n urlPath = urlPath.replace(/\\/*$/g, '');\n }\n // Convert `/index` to `/`.\n if (urlPath.endsWith('/index')) {\n urlPath = urlPath.slice(0, -6);\n }\n // Add leading slash if needed.\n if (!urlPath.startsWith('/')) {\n urlPath = `/${urlPath}`;\n }\n return urlPath;\n}\n\nfunction pathContainsPlaceholders(urlPath: string) {\n const segments = urlPath.split('/');\n return segments.some((segment) => {\n return segment.startsWith('[') && segment.endsWith(']');\n });\n}\n\nfunction removeSlashes(str: string) {\n return str.replace(/^\\/*/g, '').replace(/\\/*$/g, '');\n}\n\n/**\n * Older path formats used `/{locale}/{path}` and should be converted to\n * `/[locale]/[base]/[path]`.\n */\nfunction toSquareBrackets(str: string) {\n if (str.includes('{') || str.includes('}')) {\n const val = str.replaceAll('{', '[').replaceAll('}', ']');\n console.warn(`\"${str}\" is a deprecated format, please switch to \"${val}\"`);\n return val;\n }\n return str;\n}\n"],"mappings":"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","names":["Fragment","jsx","jsxs","jsx","jsxs","jsx","jsxs","props"]}
1
+ {"version":3,"sources":["../src/render/render.tsx","../src/core/pages/ErrorPage.tsx","../src/core/pages/DevErrorPage.tsx","../src/core/pages/DevNotFoundPage.tsx","../src/render/accept-language.ts","../src/render/i18n-fallbacks.ts","../src/render/router.ts"],"sourcesContent":["import crypto from 'node:crypto';\nimport {\n ComponentChildren,\n ComponentType,\n VNode,\n options as preactOptions,\n} from 'preact';\nimport {renderToString} from 'preact-render-to-string';\nimport {HtmlContext, HTML_CONTEXT} from '../core/components/Html.js';\nimport {RootConfig, RootSecurityConfig} from '../core/config.js';\nimport {getTranslations, I18N_CONTEXT} from '../core/hooks/useI18nContext.js';\nimport {\n RequestContext,\n REQUEST_CONTEXT,\n} from '../core/hooks/useRequestContext.js';\nimport {DevErrorPage} from '../core/pages/DevErrorPage.js';\nimport {DevNotFoundPage} from '../core/pages/DevNotFoundPage.js';\nimport {ErrorPage} from '../core/pages/ErrorPage.js';\nimport {\n Request,\n Response,\n NextFunction,\n HandlerContext,\n RouteParams,\n Route,\n HandlerRenderFn,\n HandlerRenderOptions,\n} from '../core/types.js';\nimport type {ElementGraph} from '../node/element-graph.js';\nimport {parseTagNames} from '../utils/elements.js';\nimport {AssetMap} from './asset-map/asset-map.js';\nimport {htmlMinify} from './html-minify.js';\nimport {htmlPretty} from './html-pretty.js';\nimport {getFallbackLocales} from './i18n-fallbacks.js';\nimport {replaceParams, Router} from './router.js';\n\ninterface RenderHtmlOptions {\n /** Attrs passed to the <html> tag, e.g. `{lang: 'en'}`. */\n htmlAttrs?: preact.JSX.HTMLAttributes<HTMLHtmlElement>;\n /** Attrs passed to the <head> tag. */\n headAttrs?: preact.JSX.HTMLAttributes<HTMLHeadElement>;\n /** Child components for the <head> tag. */\n headComponents?: ComponentChildren[];\n /** Attrs passed to the <body> tag. */\n bodyAttrs?: preact.JSX.HTMLAttributes<HTMLBodyElement>;\n}\n\nexport class Renderer {\n private rootConfig: RootConfig;\n // private routes: RouteTrie<Route>;\n private assetMap: AssetMap;\n private elementGraph: ElementGraph;\n private router: Router;\n\n constructor(\n rootConfig: RootConfig,\n options: {assetMap: AssetMap; elementGraph: ElementGraph}\n ) {\n this.rootConfig = rootConfig;\n // this.routes = getRoutes(this.rootConfig);\n this.assetMap = options.assetMap;\n this.elementGraph = options.elementGraph;\n this.router = new Router(rootConfig);\n }\n\n async handle(req: Request, res: Response, next: NextFunction) {\n const url = req.path;\n const [route, routeParams] = this.router.get(url);\n if (!route) {\n next();\n return;\n }\n if (route.locale) {\n routeParams.$locale = route.locale;\n }\n\n const fallbackLocales = route.isDefaultLocale\n ? getFallbackLocales(req)\n : [route.locale];\n const getPreferredLocale = (availableLocales: string[]) => {\n const lowerLocales = availableLocales.map((l) => l.toLowerCase());\n for (const fallbackLocale of fallbackLocales) {\n if (lowerLocales.includes(fallbackLocale.toLowerCase())) {\n return fallbackLocale;\n }\n }\n return req.rootConfig?.i18n?.defaultLocale || 'en';\n };\n\n const render404 = async () => {\n // Calling next() will allow the dev server or prod server handle the 404\n // page as appropriate for the env.\n next();\n };\n\n const render: HandlerRenderFn = async (\n props: any,\n options?: HandlerRenderOptions\n ) => {\n if (!route.module.default) {\n console.error(`no default component exported in route: ${route.src}`);\n render404();\n return;\n }\n const securityConfig = this.getSecurityConfig();\n const cspEnabled = !!securityConfig.contentSecurityPolicy;\n const currentPath = req.path;\n const locale = options?.locale || route.locale;\n const translations = options?.translations;\n const nonce = cspEnabled ? this.generateNonce() : undefined;\n const output = await this.renderComponent(route.module.default, props, {\n currentPath,\n route,\n routeParams,\n locale,\n translations,\n nonce,\n });\n let html = output.html;\n if (this.rootConfig.prettyHtml) {\n html = await htmlPretty(html, this.rootConfig.prettyHtmlOptions);\n } else if (this.rootConfig.minifyHtml !== false) {\n html = await htmlMinify(html, this.rootConfig.minifyHtmlOptions);\n }\n if (req.viteServer) {\n html = await req.viteServer.transformIndexHtml(currentPath, html);\n if (nonce) {\n html = html.replace(\n '<script type=\"module\" src=\"/@vite/client\"></script>',\n `<script type=\"module\" src=\"/@vite/client\" nonce=\"${nonce}\"></script>`\n );\n }\n }\n // Override the status code for 404 and 500 routes, which are defined at\n // routes/404.tsx and routes/500.tsx respectively.\n let statusCode = 200;\n if (route.src === 'routes/404.tsx') {\n statusCode = 404;\n } else if (route.src === 'routes/500.tsx') {\n statusCode = 500;\n }\n req.hooks.trigger('preRender');\n res.status(statusCode);\n res.set({'Content-Type': 'text/html'});\n this.setSecurityHeaders(res, {\n securityConfig: securityConfig,\n nonce: nonce,\n });\n res.end(html);\n };\n\n if (route.module.handle) {\n const handlerContext: HandlerContext = {\n route: route,\n params: routeParams,\n i18nFallbackLocales: fallbackLocales,\n getPreferredLocale: getPreferredLocale,\n render: render,\n render404: render404,\n };\n req.handlerContext = handlerContext;\n return route.module.handle(req, res, next);\n }\n\n let props = {};\n if (route.module.getStaticProps) {\n const propsData = await route.module.getStaticProps({\n rootConfig: this.rootConfig,\n params: routeParams,\n });\n if (propsData.notFound) {\n return render404();\n }\n if (propsData.props) {\n props = propsData.props;\n }\n }\n await render(props);\n }\n\n private async renderComponent(\n Component: ComponentType,\n props: any,\n options: {\n currentPath: string;\n route: Route;\n routeParams: RouteParams;\n locale: string;\n translations?: Record<string, string>;\n nonce?: string;\n }\n ) {\n const {currentPath, route, routeParams, nonce} = options;\n const locale = options.locale;\n const translations = {\n ...getTranslations(locale),\n ...(options.translations || {}),\n };\n const ctx: RequestContext = {\n currentPath,\n route,\n props,\n routeParams,\n locale,\n translations,\n nonce,\n };\n const htmlContext: HtmlContext = {\n htmlAttrs: {},\n headAttrs: {},\n headComponents: [],\n bodyAttrs: {},\n scriptDeps: [],\n };\n const vdom = (\n <REQUEST_CONTEXT.Provider value={ctx}>\n <I18N_CONTEXT.Provider value={{locale, translations}}>\n <HTML_CONTEXT.Provider value={htmlContext}>\n <Component {...props} />\n </HTML_CONTEXT.Provider>\n </I18N_CONTEXT.Provider>\n </REQUEST_CONTEXT.Provider>\n );\n\n // Create a hook to auto-inject nonce values.\n // https://preactjs.com/guide/v10/options/\n const preactHook = preactOptions.vnode;\n let mainHtml = '';\n try {\n preactOptions.vnode = (vnode: VNode<any>) => {\n // Inject nonce to `<script>` tags.\n if (vnode && vnode.type === 'script') {\n vnode.props.nonce = nonce;\n }\n // Inject nonce to `<style>` tags.\n if (vnode && vnode.type === 'style') {\n vnode.props.nonce = nonce;\n }\n // Inject nonce to `<link rel=\"stylesheet\">` tags.\n if (\n vnode &&\n vnode.type === 'link' &&\n vnode.props.rel === 'stylesheet'\n ) {\n vnode.props.nonce = nonce;\n }\n // Call the normal preact hook.\n if (preactHook) {\n preactHook(vnode);\n }\n };\n mainHtml = renderToString(vdom);\n preactOptions.vnode = preactHook;\n } catch (err) {\n preactOptions.vnode = preactHook;\n throw err;\n }\n\n const jsDeps = new Set<string>();\n const cssDeps = new Set<string>();\n\n // Walk the route's dependency tree for CSS dependencies that are added via\n // `import 'foo.scss'` or `import 'foo.module.scss'`.\n const routeAsset = await this.assetMap.get(route.src);\n if (routeAsset) {\n const routeCssDeps = await routeAsset.getCssDeps();\n routeCssDeps.forEach((dep) => {\n // Ignore ?inline css deps.\n if (dep.endsWith('?inline')) {\n return;\n }\n cssDeps.add(dep);\n });\n }\n\n // Parse the HTML for custom elements that are found within the project\n // and automatically inject the script deps for them.\n await this.collectElementDeps(mainHtml, jsDeps, cssDeps);\n\n // Add user defined scripts added via the `<Script>` component.\n await Promise.all(\n htmlContext.scriptDeps.map(async (scriptDep) => {\n if (!scriptDep.src) {\n return;\n }\n const assetId = String(scriptDep.src).slice(1);\n const scriptAsset = await this.assetMap.get(assetId);\n if (scriptAsset) {\n jsDeps.add(scriptAsset.assetUrl);\n const scriptJsDeps = await scriptAsset.getJsDeps();\n scriptJsDeps.forEach((dep) => jsDeps.add(dep));\n }\n })\n );\n\n const styleTags = Array.from(cssDeps).map((cssUrl) => {\n return <link rel=\"stylesheet\" href={cssUrl} nonce={nonce} />;\n });\n const scriptTags = Array.from(jsDeps).map((jsUrls) => {\n return <script type=\"module\" src={jsUrls} nonce={nonce} />;\n });\n\n const html = await this.renderHtml(mainHtml, {\n htmlAttrs: htmlContext.htmlAttrs,\n headAttrs: htmlContext.headAttrs,\n bodyAttrs: htmlContext.bodyAttrs,\n headComponents: [\n ...htmlContext.headComponents,\n ...styleTags,\n ...scriptTags,\n ],\n });\n return {html};\n }\n\n /** SSG renders a route. */\n async renderRoute(\n route: Route,\n options: {routeParams: Record<string, string>}\n ): Promise<{html?: string; notFound?: boolean}> {\n const routeParams = options.routeParams;\n if (route.locale) {\n routeParams.$locale = route.locale;\n }\n const Component = route.module.default;\n if (!Component) {\n throw new Error(\n 'unable to render route. the route should have a default export that renders a jsx component.'\n );\n }\n let props = {};\n let locale = route.locale;\n let translations = undefined;\n if (route.module.getStaticProps) {\n const propsData = await route.module.getStaticProps({\n rootConfig: this.rootConfig,\n params: routeParams,\n });\n if (propsData.notFound) {\n return {notFound: true};\n }\n if (propsData.props) {\n props = propsData.props;\n }\n if (propsData.locale) {\n locale = propsData.locale;\n }\n if (propsData.translations) {\n translations = propsData.translations;\n }\n }\n const routePath = route.isDefaultLocale\n ? route.routePath\n : route.localeRoutePath;\n const currentPath = replaceParams(routePath, {\n ...routeParams,\n locale: locale,\n });\n return this.renderComponent(Component, props, {\n currentPath,\n route,\n routeParams,\n locale,\n translations,\n });\n }\n\n async getSitemap(): Promise<\n Record<string, {route: Route; params: Record<string, string>}>\n > {\n const sitemap: Record<\n string,\n {route: Route; params: Record<string, string>}\n > = {};\n await this.router.walk(async (urlPath: string, route: Route) => {\n const routePaths = await this.router.getAllPathsForRoute(urlPath, route);\n routePaths.forEach((routePath) => {\n sitemap[routePath.urlPath] = {\n route,\n params: routePath.params,\n };\n });\n });\n return sitemap;\n }\n\n private async renderHtml(html: string, options?: RenderHtmlOptions) {\n const htmlAttrs = options?.htmlAttrs || {};\n const headAttrs = options?.headAttrs || {};\n const bodyAttrs = options?.bodyAttrs || {};\n const page = (\n <html {...htmlAttrs}>\n <head {...headAttrs}>\n <meta charSet=\"utf-8\" />\n {options?.headComponents}\n </head>\n <body {...bodyAttrs} dangerouslySetInnerHTML={{__html: html}} />\n </html>\n );\n return `<!doctype html>\\n${renderToString(page)}\\n`;\n }\n\n async render404(options?: {currentPath?: string}) {\n const currentPath = options?.currentPath || '/404';\n const [route, routeParams] = this.router.get('/404');\n if (route && route.src === 'routes/404.tsx' && route.module.default) {\n const Component = route.module.default;\n return this.renderComponent(\n Component,\n {},\n {currentPath, route, routeParams, locale: 'en'}\n );\n }\n\n const mainHtml = renderToString(\n <ErrorPage\n code={404}\n title=\"Not found\"\n message=\"Double-check the URL entered and try again.\"\n align=\"center\"\n />\n );\n const html = await this.renderHtml(mainHtml, {\n headComponents: [\n <title>404 Not Found</title>,\n <meta\n name=\"viewport\"\n content=\"width=device-width, initial-scale=1.0\"\n />,\n ],\n });\n return {html};\n }\n\n async renderError(err: any, options?: {currentPath?: string}) {\n const currentPath = options?.currentPath || '/500';\n const [route, routeParams] = this.router.get('/500');\n if (route && route.src === 'routes/500.tsx' && route.module.default) {\n const Component = route.module.default;\n return this.renderComponent(\n Component,\n {error: err},\n {currentPath, route, routeParams, locale: 'en'}\n );\n }\n\n const mainHtml = renderToString(\n <ErrorPage\n code={500}\n title=\"Something went wrong\"\n message=\"An unknown error occurred.\"\n align=\"center\"\n />\n );\n const html = await this.renderHtml(mainHtml, {\n headComponents: [\n <title>500 Error</title>,\n <meta\n name=\"viewport\"\n content=\"width=device-width, initial-scale=1.0\"\n />,\n ],\n });\n return {html};\n }\n\n async renderDevServer404(req: Request) {\n const sitemap = await this.getSitemap();\n const mainHtml = renderToString(\n <DevNotFoundPage req={req} sitemap={sitemap} />\n );\n const html = await this.renderHtml(mainHtml, {\n headComponents: [<title>404 Not found | Root.js</title>],\n });\n return {html};\n }\n\n async renderDevServer500(req: Request, error: unknown) {\n const [route, routeParams] = this.router.get(req.path);\n const mainHtml = renderToString(\n <DevErrorPage\n req={req}\n route={route}\n routeParams={routeParams}\n error={error}\n />\n );\n const html = await this.renderHtml(mainHtml, {\n headComponents: [<title>500 Error | Root.js</title>],\n });\n return {html};\n }\n\n /**\n * Parses rendered HTML for custom element tags used on the page and\n * automatically adds the JS/CSS deps to the page.\n */\n private async collectElementDeps(\n html: string,\n jsDeps: Set<string>,\n cssDeps: Set<string>\n ): Promise<{jsDeps: Set<string>; cssDeps: Set<string>}> {\n const elementsMap = this.elementGraph.sourceFiles;\n const assetMap = this.assetMap;\n\n const tagNames = new Set<string>();\n for (const tagName of parseTagNames(html)) {\n if (tagName && tagName in elementsMap) {\n tagNames.add(tagName);\n for (const depTagName of this.elementGraph.getDeps(tagName)) {\n tagNames.add(depTagName);\n }\n }\n }\n\n await Promise.all(\n Array.from(tagNames).map(async (tagName: string) => {\n const elementModule = elementsMap[tagName];\n const asset = await assetMap.get(elementModule.relPath);\n if (!asset) {\n return;\n }\n const assetJsDeps = await asset.getJsDeps();\n assetJsDeps.forEach((dep) => jsDeps.add(dep));\n const assetCssDeps = await asset.getCssDeps();\n assetCssDeps.forEach((dep) => {\n // Ignore ?inline css deps.\n if (dep.endsWith('?inline')) {\n return;\n }\n cssDeps.add(dep);\n });\n })\n );\n\n return {jsDeps, cssDeps};\n }\n\n /**\n * Returns the `security` config value with default values inserted wherever\n * a user config value is blank or set to `true`.\n */\n private getSecurityConfig() {\n const userConfig: Partial<RootSecurityConfig> =\n this.rootConfig.server?.security || {};\n const securityConfig: Partial<RootSecurityConfig> = {};\n\n if (isTrueOrUndefined(userConfig.contentSecurityPolicy)) {\n // CSP default values from:\n // https://csp.withgoogle.com/docs/strict-csp.html\n securityConfig.contentSecurityPolicy = {\n directives: {\n 'base-uri': [\"'none'\"],\n 'object-src': [\"'none'\"],\n // NOTE: nonce is automatically added to this list.\n 'script-src': [\n \"'unsafe-inline'\",\n \"'unsafe-eval'\",\n \"'strict-dynamic' https: http:\",\n ],\n },\n reportOnly: true,\n };\n } else {\n securityConfig.contentSecurityPolicy = userConfig.contentSecurityPolicy;\n }\n\n if (isTrueOrUndefined(userConfig.xFrameOptions)) {\n securityConfig.xFrameOptions = 'SAMEORIGIN';\n } else {\n securityConfig.xFrameOptions = userConfig.xFrameOptions;\n }\n\n securityConfig.strictTransportSecurity =\n userConfig.strictTransportSecurity ?? true;\n securityConfig.xContentTypeOptions = userConfig.xContentTypeOptions ?? true;\n securityConfig.xXssProtection = userConfig.xXssProtection ?? true;\n\n return securityConfig as Required<RootSecurityConfig>;\n }\n\n /**\n * Generates a random string that can be used as the \"nonce\" value for CSP.\n */\n private generateNonce() {\n return crypto.randomBytes(16).toString('base64');\n }\n\n /**\n * Sets security-related HTTP headers.\n */\n private setSecurityHeaders(\n res: Response,\n options: {securityConfig: Required<RootSecurityConfig>; nonce?: string}\n ) {\n const securityConfig = options.securityConfig;\n\n // Content-Security-Policy.\n const contentSecurityPolicy = securityConfig.contentSecurityPolicy;\n if (typeof contentSecurityPolicy === 'object') {\n const directives = contentSecurityPolicy.directives || {};\n if (options.nonce) {\n if (!directives['script-src']) {\n directives['script-src'] = [\n \"'unsafe-inline'\",\n \"'unsafe-eval'\",\n \"'strict-dynamic' https: http:\",\n ];\n }\n directives['script-src'].push(`'nonce-${options.nonce}'`);\n }\n const headerSegments: string[] = [];\n Object.entries(directives).forEach(([key, values]) => {\n headerSegments.push([key, ...values].join(' '));\n });\n const csp = headerSegments.join('; ');\n if (contentSecurityPolicy.reportOnly === false) {\n res.setHeader('content-security-policy', csp);\n } else {\n res.setHeader('content-security-policy-report-only', csp);\n }\n }\n\n // X-Frame-Options.\n if (typeof securityConfig.xFrameOptions === 'string') {\n res.setHeader('x-frame-options', securityConfig.xFrameOptions);\n }\n\n // Strict-Transport-Security.\n if (securityConfig.strictTransportSecurity) {\n res.setHeader(\n 'strict-transport-security',\n 'max-age=63072000; includeSubdomains; preload'\n );\n }\n\n // X-Content-Type-Options.\n if (securityConfig.xContentTypeOptions) {\n res.setHeader('x-content-type-options', 'nosniff');\n }\n\n // X-XSS-Protection.\n if (securityConfig.xXssProtection) {\n res.setHeader('x-xss-protection', '1; mode=block');\n }\n }\n}\n\nfunction isTrueOrUndefined(value: any) {\n return value === true || value === undefined;\n}\n","import {ComponentChildren} from 'preact';\n\nconst STYLES = `\n@import url('https://fonts.googleapis.com/css2?family=Inter:wght@400;700&display=swap');\n\n:root {\n --font-family-text: \"Inter\", sans-serif;\n}\n\nbody {\n font-family: var(--font-family-text);\n background: #F5F5F5;\n padding: 40px 16px;\n}\n\n.root {\n max-width: 1200px;\n margin: 0 auto;\n}\n\n.root.align-center {\n text-align: center;\n}\n\nh1.title {\n margin-top: 0;\n margin-bottom: 24px;\n}\n\np.message {\n margin-top: 0;\n margin-bottom: 0;\n}\n\n.box {\n font-size: 16px;\n line-height: 1.5;\n padding: 16px;\n border-radius: 12px;\n background: #ffffff;\n}\n\npre.box {\n white-space: pre-wrap;\n}\n\n@media (min-width: 500px) {\n body {\n padding: 40px;\n }\n\n .box {\n padding: 24px;\n }\n}\n\n@media (min-width: 1024px) {\n body {\n padding: 100px;\n }\n}\n`;\n\nexport interface ErrorPageProps {\n code: number;\n title?: string;\n message?: string;\n children?: ComponentChildren;\n align?: 'center';\n}\n\nexport function ErrorPage(props: ErrorPageProps) {\n const {code, message} = props;\n const title = props.title || code;\n return (\n <>\n <style dangerouslySetInnerHTML={{__html: STYLES}}></style>\n <div className={`root align-${props.align || 'left'}`}>\n <h1 className=\"title\">{title}</h1>\n {message && <p className=\"message\">{message}</p>}\n {props.children}\n </div>\n </>\n );\n}\n","import {Request, Route, RouteParams} from '../types.js';\nimport {ErrorPage} from './ErrorPage.js';\n\ninterface DevErrorPageProps {\n req: Request;\n route?: Route;\n routeParams?: RouteParams;\n error: any;\n}\n\nexport function DevErrorPage(props: DevErrorPageProps) {\n const req = props.req;\n const err = props.error;\n const route = props.route;\n const routeParams = props.routeParams;\n\n let errMsg = String(err);\n if (err && err.stack) {\n // Obfuscate some user info from the stack trace so that when people send\n // error reports and screenshots, less identifiable information is sent.\n errMsg = err.stack\n .replace(/\\(.*node_modules/g, '(node_modules')\n .replace(/at \\/.*node_modules/g, 'at node_modules');\n if (req.rootConfig?.rootDir) {\n errMsg = errMsg.replaceAll(req.rootConfig.rootDir, '<root>');\n }\n if (process.env.HOME) {\n errMsg = errMsg.replaceAll(process.env.HOME, '$HOME');\n }\n }\n return (\n <ErrorPage code={500} title=\"Something went wrong\">\n {errMsg && (\n <>\n <h2>Error</h2>\n <pre className=\"box\">\n <code>{errMsg}</code>\n </pre>\n </>\n )}\n <h2>Debug Info</h2>\n <pre className=\"box\">\n <code>{`url: ${req.originalUrl}\nroute: ${route?.src || 'null'}\nrouteParams: ${(routeParams && JSON.stringify(routeParams)) || 'null'}`}</code>\n </pre>\n </ErrorPage>\n );\n}\n","import {Request, Route} from '../types.js';\nimport {ErrorPage} from './ErrorPage.js';\n\ninterface DevNotFoundPageProps {\n req: Request;\n sitemap: Record<string, {route: Route; params: Record<string, string>}>;\n}\n\ninterface RoutesListMap {\n [src: string]: Array<RouteURLPath>;\n}\n\ninterface RouteURLPath {\n route: Route;\n urlPath: string;\n}\n\nexport function DevNotFoundPage(props: DevNotFoundPageProps) {\n const req = props.req;\n const routesListMap: RoutesListMap = {};\n let srcMaxLength = 0;\n Object.keys(props.sitemap).forEach((urlPath) => {\n const route = props.sitemap[urlPath].route;\n routesListMap[route.src] ??= [];\n routesListMap[route.src].push({route, urlPath});\n if (route.src.length > srcMaxLength) {\n srcMaxLength = route.src.length;\n }\n });\n const routeSrcs = Object.keys(routesListMap).sort(sortRouteFiles);\n const lines: string[] = [];\n routeSrcs.forEach((routeSrc) => {\n const routeUrls = routesListMap[routeSrc].sort(sortRouteURLs);\n routeUrls.forEach((routeUrl, i) => {\n const urlPath = routeUrl.urlPath;\n if (i === 0) {\n lines.push(`${routeSrc.padEnd(srcMaxLength, ' ')} => ${urlPath}`);\n } else {\n lines.push(`${''.padEnd(srcMaxLength, ' ')} => ${urlPath}`);\n }\n });\n });\n const routesListString = lines.join('\\n');\n // const routesListString = routesList\n // .map((route) => {\n // return `${route.urlPath.padEnd(srcMaxLength, ' ')} => ${route.src}`;\n // })\n // .join('\\n');\n return (\n <ErrorPage code={404} title=\"Not found\">\n <h2>Routes</h2>\n {Object.keys(routesListMap).length > 0 ? (\n <pre className=\"box\">\n <code>{routesListString}</code>\n </pre>\n ) : (\n <div className=\"box\">\n Add your first route at <code>/routes/index.tsx</code>\n </div>\n )}\n\n <h2>Debug Info</h2>\n <pre className=\"box\">\n <code>{`url: ${req.originalUrl}`}</code>\n </pre>\n </ErrorPage>\n );\n}\n\nfunction sortRouteFiles(a: string, b: string): number {\n if (a === 'routes/index.tsx') {\n return -1;\n }\n if (b === 'routes/index.tsx') {\n return 1;\n }\n return a.localeCompare(b);\n}\n\nfunction sortRouteURLs(a: RouteURLPath, b: RouteURLPath): number {\n if (a.route.isDefaultLocale && !b.route.isDefaultLocale) {\n return -1;\n }\n if (!a.route.isDefaultLocale && b.route.isDefaultLocale) {\n return 1;\n }\n return a.urlPath.localeCompare(b.urlPath);\n}\n","export const ACCEPT_LANG_RE =\n /((([a-zA-Z]+(-[a-zA-Z0-9]+){0,2})|\\*)(;q=[0-1](\\.[0-9]+)?)?)*/g;\n\nexport interface AcceptLanguage {\n code: string;\n script?: string;\n region?: string;\n quality: number;\n}\n\nexport function parseAcceptLanguage(value: string): AcceptLanguage[] {\n const matches = String(value).match(ACCEPT_LANG_RE);\n if (!matches) {\n return [];\n }\n const results: AcceptLanguage[] = [];\n matches.forEach((m) => {\n if (!m) {\n return;\n }\n\n const parts = m.split(';');\n const ietf = parts[0].split('-');\n const hasScript = ietf.length === 3;\n\n results.push({\n code: ietf[0],\n script: hasScript ? ietf[1] : undefined,\n region: hasScript ? ietf[2] : ietf[1],\n quality: parts[1] ? parseFloat(parts[1].split('=')[1]) : 1.0,\n });\n });\n results.sort((a, b) => b.quality - a.quality);\n return results;\n}\n","/**\n * Utility functions for handling requests that mimic the Firebase Hosting i18n\n * fallback logic.\n * https://firebase.google.com/docs/hosting/i18n-rewrites\n */\n\nimport {Request} from '../core/types.js';\nimport {parseAcceptLanguage} from './accept-language.js';\n\nexport const UNKNOWN_COUNTRY = 'zz';\nexport const ES_419_COUNTRIES = [\n 'ar', // Argentina\n 'bo', // Bolivia\n 'cl', // Chile\n 'co', // Colombia\n 'cr', // Costa Rica\n 'cu', // Cuba\n 'do', // Dominican Republic\n 'ec', // Ecuador\n 'sv', // El Salvador\n 'gt', // Guatemala\n 'hn', // Honduras\n 'mx', // Mexico\n 'ni', // Nicaragua\n 'pa', // Panama\n 'py', // Paraguay\n 'pe', // Peru\n 'pr', // Puerto Rico\n 'uy', // Uruguay\n 've', // Venezuela\n];\n\nexport function getFallbackLocales(req: Request): string[] {\n const hl = getFirstQueryParam(req, 'hl');\n const countryCode = getCountry(req);\n\n // Web crawlers should only use the default locale.\n if (isWebCrawler(req)) {\n const defaultLocale = req.rootConfig?.i18n?.defaultLocale || 'en';\n if (hl && hl !== defaultLocale) {\n return [hl, defaultLocale];\n }\n return [defaultLocale];\n }\n\n const locales = new Set<string>();\n\n // Add locales from ?hl= query parameter.\n if (hl) {\n const langCode = hl;\n locales.add(`${langCode}_${countryCode}`);\n locales.add(`${langCode}_ALL`);\n locales.add(langCode);\n }\n\n const langs = getFallbackLanguages(req);\n\n // Add `{lang}_{country}` locales.\n langs.forEach((langCode) => {\n locales.add(`${langCode}_${countryCode}`);\n });\n\n // Add ALL_{country} locale.\n locales.add(`ALL_${countryCode}`);\n\n // Add `{lang}_ALL` and `{lang}` locales.\n const isEs419Country = test419Country(countryCode);\n langs.forEach((langCode) => {\n // For Spanish-speaking LATAM countries, also add es-419.\n if (langCode === 'es' && isEs419Country) {\n locales.add('es-419_ALL');\n locales.add('es-419');\n }\n locales.add(`${langCode}_ALL`);\n locales.add(langCode);\n });\n\n return Array.from(locales) as string[];\n}\n\nexport function getCountry(req: Request) {\n const normalize = (countryCode: string) => String(countryCode).toLowerCase();\n // Check the ?gl= query param.\n const gl = getFirstQueryParam(req, 'gl');\n if (gl) {\n return normalize(gl);\n }\n const gaeCountry =\n req.get('x-country-code') || req.get('x-appengine-country');\n if (gaeCountry) {\n return normalize(gaeCountry);\n }\n return UNKNOWN_COUNTRY;\n}\n\nfunction getFallbackLanguages(req: Request): string[] {\n const langs = new Set<string>();\n // Add languages from the Accept-Language header.\n const acceptLangHeader = req.get('accept-language') || '';\n if (acceptLangHeader) {\n parseAcceptLanguage(acceptLangHeader).forEach((lang) => {\n // For a lang like `en-US`, add both `en-US` and `en`.\n if (lang.region) {\n langs.add(`${lang.code}-${lang.region}`);\n // For Spanish-speaking LATAM countries, also add es-419.\n if (lang.code === 'es' && test419Country(lang.region)) {\n langs.add('es-419');\n }\n }\n langs.add(lang.code);\n });\n }\n // Fall back to \"en\" as a last resort.\n langs.add('en');\n return Array.from(langs);\n}\n\n/**\n * Returns the first query param value in a given request.\n *\n * For example, for a URL like `/?foo=bar&foo=baz`, calling\n * `getFirstQueryParam(req, 'foo')` would return `\"bar\"`.\n */\nfunction getFirstQueryParam(req: Request, key: string): string | null {\n const val = req.query[key];\n if (val === null || val === undefined) {\n return null;\n }\n if (Array.isArray(val)) {\n if (val.length === 0) {\n return null;\n }\n return String(val[0]);\n }\n return String(val);\n}\n\nfunction isWebCrawler(req: Request): boolean {\n const userAgentHeader = req.get('User-Agent');\n if (!userAgentHeader) {\n return false;\n }\n const userAgent = userAgentHeader.toLowerCase();\n return (\n userAgent.includes('googlebot') ||\n userAgent.includes('bingbot') ||\n userAgent.includes('twitterbot')\n );\n}\n\nexport function test419Country(countryCode: string) {\n return ES_419_COUNTRIES.includes(countryCode);\n}\n","import path from 'node:path';\nimport {RootConfig} from '../core/config.js';\nimport {Route, RouteModule} from '../core/types.js';\nimport {RouteTrie} from './route-trie.js';\n\nconst ROUTES_FILES = import.meta.glob<RouteModule>(\n ['/routes/*.ts', '/routes/**/*.ts', '/routes/*.tsx', '/routes/**/*.tsx'],\n {eager: true}\n);\n\nexport class Router {\n private rootConfig: RootConfig;\n private routeTrie: RouteTrie<Route>;\n\n constructor(rootConfig: RootConfig) {\n this.rootConfig = rootConfig;\n this.routeTrie = this.initRouteTrie();\n }\n\n get(url: string) {\n return this.routeTrie.get(url);\n }\n\n async walk(cb: (urlPath: string, route: Route) => void | Promise<void>) {\n await this.routeTrie.walk(cb);\n }\n\n private initRouteTrie() {\n const locales = this.rootConfig.i18n?.locales || [];\n const basePath = this.rootConfig.base || '/';\n const defaultLocale = this.rootConfig.i18n?.defaultLocale || 'en';\n\n const trie = new RouteTrie<Route>();\n Object.keys(ROUTES_FILES).forEach((modulePath) => {\n const src = modulePath.slice(1);\n let relativeRoutePath = modulePath.replace(/^\\/routes/, '');\n const parts = path.parse(relativeRoutePath);\n if (parts.name.startsWith('_')) {\n return;\n }\n if (parts.name === 'index') {\n relativeRoutePath = parts.dir;\n } else {\n relativeRoutePath = path.join(parts.dir, parts.name);\n }\n\n const urlFormat = '/[base]/[path]';\n const i18nUrlFormat = toSquareBrackets(\n this.rootConfig.i18n?.urlFormat || '/[locale]/[base]/[path]'\n );\n const placeholders = {\n base: removeSlashes(basePath),\n path: removeSlashes(relativeRoutePath),\n };\n\n const formatUrl = (format: string) => {\n const url = format\n .replaceAll('[base]', placeholders.base)\n .replaceAll('[path]', placeholders.path);\n return normalizeUrlPath(url, {\n trailingSlash: this.rootConfig.server?.trailingSlash,\n });\n };\n\n const routePath = formatUrl(urlFormat);\n const localeRoutePath = formatUrl(i18nUrlFormat);\n\n trie.add(routePath, {\n src,\n module: ROUTES_FILES[modulePath],\n locale: defaultLocale,\n isDefaultLocale: true,\n routePath: routePath,\n localeRoutePath: localeRoutePath,\n });\n\n // At the moment, all routes are assumed to use the site-wide i18n config.\n // TODO(stevenle): provide routes with a way to override the default\n // i18n serving behavior.\n if (i18nUrlFormat.includes('[locale]')) {\n locales.forEach((locale) => {\n const localePath = localeRoutePath.replace('[locale]', locale);\n if (localePath !== relativeRoutePath) {\n trie.add(localePath, {\n src,\n module: ROUTES_FILES[modulePath],\n locale: locale,\n isDefaultLocale: false,\n routePath,\n localeRoutePath,\n });\n }\n });\n }\n });\n return trie;\n }\n\n async getAllPathsForRoute(\n urlPathFormat: string,\n route: Route\n ): Promise<Array<{urlPath: string; params: Record<string, string>}>> {\n const routeModule = route.module;\n if (!routeModule.default) {\n return [];\n }\n\n const urlPaths: Array<{urlPath: string; params: Record<string, string>}> =\n [];\n if (routeModule.getStaticPaths) {\n const staticPaths = await routeModule.getStaticPaths({\n rootConfig: this.rootConfig,\n });\n if (staticPaths.paths) {\n staticPaths.paths.forEach(\n (pathParams: {params: Record<string, string>}) => {\n const urlPath = replaceParams(\n urlPathFormat,\n pathParams.params || {}\n );\n if (pathContainsPlaceholders(urlPath)) {\n console.warn(\n `path contains placeholders: ${urlPathFormat}, double check getStaticPaths() and ensure all params are returned. more info: https://rootjs.dev/guide/routes#getStaticPaths`\n );\n } else {\n urlPaths.push({\n urlPath: normalizeUrlPath(urlPath),\n params: pathParams.params || {},\n });\n }\n }\n );\n }\n } else if (\n routeModule.getStaticProps &&\n !pathContainsPlaceholders(urlPathFormat)\n ) {\n urlPaths.push({urlPath: normalizeUrlPath(urlPathFormat), params: {}});\n } else if (\n !routeModule.handle &&\n !pathContainsPlaceholders(urlPathFormat)\n ) {\n urlPaths.push({urlPath: normalizeUrlPath(urlPathFormat), params: {}});\n } else if (\n pathContainsPlaceholders(urlPathFormat) &&\n !routeModule.handle &&\n !routeModule.getStaticPaths\n ) {\n console.warn(\n [\n `warning: path contains placeholders: ${urlPathFormat}.`,\n `define either ssg getStaticPaths() or ssr handle() for route: ${route.src}.`,\n 'more info: https://rootjs.dev/guide/routes',\n ].join('\\n')\n );\n }\n\n return urlPaths;\n }\n}\n\nexport function replaceParams(\n urlPathFormat: string,\n params: Record<string, string>\n) {\n const urlPath = urlPathFormat.replaceAll(\n /\\[\\[?(\\.\\.\\.)?([\\w\\-_]*)\\]?\\]/g,\n (match: string, _wildcard: string, key: string) => {\n const val = params[key];\n if (!val) {\n throw new Error(`unreplaced param ${match} in url: ${urlPathFormat}`);\n }\n return val;\n }\n );\n return urlPath;\n}\n\nexport function normalizeUrlPath(\n urlPath: string,\n options?: {trailingSlash?: boolean}\n) {\n // Collapse multiple slashes, e.g. `/foo//bar` => `/foo/bar`;\n urlPath = urlPath.replace(/\\/+/g, '/');\n // Remove trailing slash.\n if (\n options?.trailingSlash === false &&\n urlPath !== '/' &&\n urlPath.endsWith('/')\n ) {\n urlPath = urlPath.replace(/\\/*$/g, '');\n }\n // Convert `/index` to `/`.\n if (urlPath.endsWith('/index')) {\n urlPath = urlPath.slice(0, -6);\n }\n // Add leading slash if needed.\n if (!urlPath.startsWith('/')) {\n urlPath = `/${urlPath}`;\n }\n return urlPath;\n}\n\nfunction pathContainsPlaceholders(urlPath: string) {\n const segments = urlPath.split('/');\n return segments.some((segment) => {\n return segment.startsWith('[') && segment.endsWith(']');\n });\n}\n\nfunction removeSlashes(str: string) {\n return str.replace(/^\\/*/g, '').replace(/\\/*$/g, '');\n}\n\n/**\n * Older path formats used `/{locale}/{path}` and should be converted to\n * `/[locale]/[base]/[path]`.\n */\nfunction toSquareBrackets(str: string) {\n if (str.includes('{') || str.includes('}')) {\n const val = str.replaceAll('{', '[').replaceAll('}', ']');\n console.warn(`\"${str}\" is a deprecated format, please switch to \"${val}\"`);\n return val;\n }\n return str;\n}\n"],"mappings":"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","names":["Fragment","jsx","jsxs","jsx","jsxs","jsx","jsxs","props"]}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@blinkk/root",
3
- "version": "1.0.3",
3
+ "version": "1.0.5",
4
4
  "author": "s@blinkk.com",
5
5
  "license": "MIT",
6
6
  "engines": {
@@ -70,6 +70,7 @@
70
70
  "micromatch": "4.0.5",
71
71
  "sass": "1.69.3",
72
72
  "sirv": "2.0.3",
73
+ "source-map-support": "0.5.21",
73
74
  "tiny-glob": "0.2.9",
74
75
  "vite": "5.0.8"
75
76
  },
@@ -1 +0,0 @@
1
- {"version":3,"sources":["../src/core/components/Html.tsx","../src/core/hooks/useI18nContext.ts","../src/core/hooks/useRequestContext.ts"],"sourcesContent":["import {ComponentChildren, FunctionalComponent, createContext} from 'preact';\nimport {useContext} from 'preact/hooks';\n\nexport interface HtmlContext {\n htmlAttrs: preact.JSX.HTMLAttributes<HTMLHtmlElement>;\n headAttrs: preact.JSX.HTMLAttributes<HTMLHeadElement>;\n headComponents: ComponentChildren[];\n bodyAttrs: preact.JSX.HTMLAttributes<HTMLBodyElement>;\n scriptDeps: Array<preact.JSX.HTMLAttributes<HTMLScriptElement>>;\n}\n\nexport const HTML_CONTEXT = createContext<HtmlContext | null>(null);\n\nexport type HtmlProps = preact.JSX.HTMLAttributes<HTMLHtmlElement> & {\n children?: ComponentChildren;\n};\n\n/**\n * The `<Html>` component can be used to update attrs in the `<html>` tag.\n *\n * Usage:\n *\n * ```tsx\n * <Html lang=\"en-US\">\n * <h1>Hello world</h1>\n * </Html>\n * ```\n */\nexport const Html: FunctionalComponent<HtmlProps> = ({children, ...attrs}) => {\n const context = useContext(HTML_CONTEXT);\n if (!context) {\n throw new Error(\n 'HTML_CONTEXT not found, double-check usage of the <Html> component'\n );\n }\n context.htmlAttrs = attrs;\n return <>{children}</>;\n};\n","import path from 'node:path';\n\nimport {createContext} from 'preact';\nimport {useContext} from 'preact/hooks';\n\nexport const I18N_CONTEXT = createContext<I18nContext | null>(null);\n\nexport interface I18nContext {\n locale: string;\n translations: Record<string, string>;\n}\n\n/**\n * A hook that returns information about the current i18n context, including the\n * locale for the given route and a map of translations for that locale.\n */\nexport function useI18nContext() {\n const context = useContext(I18N_CONTEXT);\n if (!context) {\n throw new Error('I18N_CONTEXT not found');\n }\n return context;\n}\n\nexport function getTranslations(locale: string): Record<string, string> {\n const translations: Record<string, Record<string, string>> = {};\n const translationsFiles = import.meta.glob(['/translations/*.json'], {\n eager: true,\n }) as Record<string, {default?: Record<string, string>}>;\n Object.keys(translationsFiles).forEach((translationPath) => {\n const parts = path.parse(translationPath);\n const locale = parts.name;\n const module = translationsFiles[translationPath];\n if (module && module.default) {\n translations[locale] = module.default;\n }\n });\n return translations[locale] || {};\n}\n","import {createContext} from 'preact';\nimport {useContext} from 'preact/hooks';\n\nimport {Route} from '../types';\n\nexport interface RequestContext {\n /**\n * The current request path, e.g. `/foo/bar` (default route path) or\n * `/{locale}/foo/bar` (localized route path).\n */\n currentPath: string;\n /** The route file. */\n route: Route;\n /**\n * Route param values. E.g. for a route like `routes/blog/[slug].tsx`,\n * visiting `/blog/foo` will pass {slug: 'foo'} here.\n */\n routeParams: Record<string, string>;\n /** Props passed to the route's server component. */\n props: any;\n /** The current locale. */\n locale: string;\n /** Translations map for the current locale. */\n translations: Record<string, string>;\n /** CSP nonce value. */\n nonce?: string;\n}\n\nexport const REQUEST_CONTEXT = createContext<RequestContext | null>(null);\n\n/**\n * A hook that returns information about the current route.\n *\n * Usage:\n *\n * ```ts\n * const ctx = useRequestContext();\n * ctx.route.src;\n * // => 'routes/index.tsx'\n * ```\n */\nexport function useRequestContext() {\n const context = useContext(REQUEST_CONTEXT);\n if (!context) {\n throw new Error('REQUEST_CONTEXT not found');\n }\n return context;\n}\n"],"mappings":";AAAA,SAAgD,qBAAoB;AACpE,SAAQ,kBAAiB;AAmChB;AAzBF,IAAM,eAAe,cAAkC,IAAI;AAiB3D,IAAM,OAAuC,CAAC,EAAC,UAAU,GAAG,MAAK,MAAM;AAC5E,QAAM,UAAU,WAAW,YAAY;AACvC,MAAI,CAAC,SAAS;AACZ,UAAM,IAAI;AAAA,MACR;AAAA,IACF;AAAA,EACF;AACA,UAAQ,YAAY;AACpB,SAAO,gCAAG,UAAS;AACrB;;;ACrCA,OAAO,UAAU;AAEjB,SAAQ,iBAAAA,sBAAoB;AAC5B,SAAQ,cAAAC,mBAAiB;AAElB,IAAM,eAAeD,eAAkC,IAAI;AAW3D,SAAS,iBAAiB;AAC/B,QAAM,UAAUC,YAAW,YAAY;AACvC,MAAI,CAAC,SAAS;AACZ,UAAM,IAAI,MAAM,wBAAwB;AAAA,EAC1C;AACA,SAAO;AACT;AAEO,SAAS,gBAAgB,QAAwC;AACtE,QAAM,eAAuD,CAAC;AAC9D,QAAM,oBAAoB,YAAY,KAAK,CAAC,sBAAsB,GAAG;AAAA,IACnE,OAAO;AAAA,EACT,CAAC;AACD,SAAO,KAAK,iBAAiB,EAAE,QAAQ,CAAC,oBAAoB;AAC1D,UAAM,QAAQ,KAAK,MAAM,eAAe;AACxC,UAAMC,UAAS,MAAM;AACrB,UAAM,SAAS,kBAAkB,eAAe;AAChD,QAAI,UAAU,OAAO,SAAS;AAC5B,mBAAaA,OAAM,IAAI,OAAO;AAAA,IAChC;AAAA,EACF,CAAC;AACD,SAAO,aAAa,MAAM,KAAK,CAAC;AAClC;;;ACtCA,SAAQ,iBAAAC,sBAAoB;AAC5B,SAAQ,cAAAC,mBAAiB;AA2BlB,IAAM,kBAAkBD,eAAqC,IAAI;AAajE,SAAS,oBAAoB;AAClC,QAAM,UAAUC,YAAW,eAAe;AAC1C,MAAI,CAAC,SAAS;AACZ,UAAM,IAAI,MAAM,2BAA2B;AAAA,EAC7C;AACA,SAAO;AACT;","names":["createContext","useContext","locale","createContext","useContext"]}
@@ -1 +0,0 @@
1
- {"version":3,"sources":["../src/node/load-config.ts","../src/utils/fsutils.ts","../src/node/vite.ts"],"sourcesContent":["import path from 'node:path';\nimport {bundleRequire} from 'bundle-require';\nimport {build} from 'esbuild';\nimport {RootConfig} from '../core/config';\nimport {fileExists, loadJson} from '../utils/fsutils';\n\nexport interface ConfigOptions {\n command: string;\n}\n\nexport async function loadRootConfig(\n rootDir: string,\n options: ConfigOptions\n): Promise<RootConfig> {\n const configPath = path.resolve(rootDir, 'root.config.ts');\n const exists = await fileExists(configPath);\n if (!exists) {\n throw new Error(`${configPath} does not exist`);\n }\n const configBundle = await bundleRequire({\n filepath: configPath,\n });\n let config = configBundle.mod.default || {};\n if (typeof config === 'function') {\n config = (await config(options)) || {};\n }\n return Object.assign({}, config, {rootDir});\n}\n\n/**\n * Compiles a root.config.ts file to root.config.js.\n */\nexport async function bundleRootConfig(rootDir: string, outPath: string) {\n const configPath = path.resolve(rootDir, 'root.config.ts');\n const configExists = await fileExists(configPath);\n if (!configExists) {\n throw new Error(`${configPath} does not exist`);\n }\n\n const packageJsonPath = path.resolve(rootDir, 'package.json');\n const packageJson = await loadPackageJson(packageJsonPath);\n const allDeps = {\n ...packageJson.peerDependencies,\n ...packageJson.dependencies,\n };\n\n function getPackageName(id: string): string {\n const segments = id.split('/');\n if (segments.length > 1) {\n // Check if package is an org path like `@blinkk/root`.\n if (segments[0].startsWith('@') && segments[0].length > 1) {\n return `${segments[0]}/${segments[1]}`;\n }\n // For imports like `my-package/subpackage`, return `my-package`.\n return segments[0];\n }\n return id;\n }\n\n await build({\n entryPoints: [configPath],\n bundle: true,\n minify: true,\n platform: 'node',\n outfile: outPath,\n sourcemap: 'inline',\n metafile: true,\n format: 'esm',\n plugins: [\n // Externalizes deps that are in package.json.\n {\n name: 'externalize-package-json-deps',\n setup(build) {\n build.onResolve({filter: /.*/}, (args) => {\n const id = args.path;\n if (id[0] !== '.' && !id.startsWith('@/')) {\n const packageName = getPackageName(id);\n if (packageName in allDeps) {\n return {\n external: true,\n };\n }\n }\n return null;\n });\n },\n },\n ],\n });\n}\n\n/**\n * Loads a pre-bundled config file from dist/root.config.js.\n */\nexport async function loadBundledConfig(\n rootDir: string,\n options: ConfigOptions\n): Promise<RootConfig> {\n const configPath = path.resolve(rootDir, 'dist/root.config.js');\n const exists = await fileExists(configPath);\n if (!exists) {\n throw new Error(`${configPath} does not exist`);\n }\n const module = await import(configPath);\n let config = module.default || {};\n if (typeof config === 'function') {\n config = (await config(options)) || {};\n }\n return Object.assign({}, config, {rootDir});\n}\n\nexport async function loadPackageJson(filepath: string): Promise<any> {\n try {\n const packageJson = await loadJson(filepath);\n return packageJson || {};\n } catch (err) {\n return {};\n }\n}\n","import {promises as fs} from 'node:fs';\nimport path from 'node:path';\n\nimport fsExtra from 'fs-extra';\nimport glob from 'tiny-glob';\n\nexport function isJsFile(filename: string) {\n return !!filename.match(/\\.(j|t)sx?$/);\n}\n\nexport async function writeFile(filepath: string, content: string) {\n const dirPath = path.dirname(filepath);\n await makeDir(dirPath);\n await fs.writeFile(filepath, content);\n}\n\nexport async function makeDir(dirpath: string) {\n try {\n await fs.access(dirpath);\n } catch (e) {\n await fs.mkdir(dirpath, {recursive: true});\n }\n}\n\nexport async function copyDir(srcdir: string, dstdir: string) {\n if (!fsExtra.existsSync(srcdir)) {\n return;\n }\n fsExtra.copySync(srcdir, dstdir, {overwrite: true});\n}\n\n/**\n * Copies a glob of files from one directory to another.\n *\n * Example:\n *\n * ```\n * await copyGlob('*.css', 'src/styles', 'dist/html/styles');\n * ```\n */\nexport async function copyGlob(\n pattern: string,\n srcdir: string,\n dstdir: string\n) {\n const files = await glob(pattern, {cwd: srcdir});\n if (files.length > 0) {\n await makeDir(dstdir);\n }\n files.forEach((file) => {\n fsExtra.copySync(path.resolve(srcdir, file), path.resolve(dstdir, file));\n });\n}\n\nexport async function rmDir(dirpath: string) {\n await fs.rm(dirpath, {recursive: true, force: true});\n}\n\nexport async function loadJson<T = unknown>(filepath: string): Promise<T> {\n const content = await fs.readFile(filepath, 'utf-8');\n return JSON.parse(content);\n}\n\nexport async function writeJson(filepath: string, data: any) {\n const content = JSON.stringify(data, null, 2);\n await writeFile(filepath, content);\n}\n\nexport async function isDirectory(dirpath: string) {\n return fs\n .stat(dirpath)\n .then((fsStat) => {\n return fsStat.isDirectory();\n })\n .catch((err) => {\n if (err.code === 'ENOENT') {\n return false;\n }\n throw err;\n });\n}\n\nexport function fileExists(filepath: string): Promise<boolean> {\n return fs\n .access(filepath)\n .then(() => true)\n .catch(() => false);\n}\n\nexport async function dirExists(dirpath: string): Promise<boolean> {\n try {\n const stat = await fs.stat(dirpath);\n return stat.isDirectory();\n } catch (error) {\n if (error.code === 'ENOENT') {\n return false;\n }\n throw error;\n }\n}\n\nexport async function directoryContains(\n dirpath: string,\n subpath: string\n): Promise<boolean> {\n const outer = await fs.realpath(dirpath);\n const inner = await fs.realpath(subpath);\n const rel = path.relative(outer, inner);\n return !rel.startsWith('..');\n}\n\nexport async function listFilesRecursive(dirPath: string): Promise<string[]> {\n const files: string[] = [];\n const entries = await fs.readdir(dirPath, {withFileTypes: true});\n for (const entry of entries) {\n const fullPath = path.join(dirPath, entry.name);\n if (entry.isDirectory()) {\n const subFiles = await listFilesRecursive(fullPath);\n files.push(...subFiles);\n } else {\n files.push(fullPath);\n }\n }\n return files;\n}\n","import path from 'node:path';\n\nimport {createServer, ViteDevServer} from 'vite';\n\nimport {RootConfig} from '../core/config.js';\nimport {getVitePlugins} from '../core/plugin.js';\n\nexport interface CreateViteServerOptions {\n /** Override HMR settings. */\n hmr?: boolean;\n /** The port the server will run on. */\n port?: number;\n /** List of files to include in the optimizeDeps.include config. */\n optimizeDeps?: string[];\n}\n\n/**\n * Returns a vite dev server.\n */\nexport async function createViteServer(\n rootConfig: RootConfig,\n options?: CreateViteServerOptions\n): Promise<ViteDevServer> {\n const rootDir = rootConfig.rootDir;\n const viteConfig = rootConfig.vite || {};\n\n let hmrOptions = viteConfig.server?.hmr;\n if (options?.hmr === false) {\n hmrOptions = false;\n } else if (typeof hmrOptions === 'undefined' && options?.port) {\n // Automatically set the HMR port to `port + 10`. This allows multiple\n // root.js dev servers to run without conflicts.\n hmrOptions = {port: options.port + 10};\n }\n\n const viteServer = await createServer({\n ...viteConfig,\n mode: 'development',\n root: rootDir,\n // publicDir is disabled from the vite dev server since it's handled by the\n // root dev server directly, which allows user middlewares to override\n // files in the public dir.\n publicDir: false,\n server: {\n ...(viteConfig.server || {}),\n middlewareMode: true,\n hmr: hmrOptions,\n },\n appType: 'custom',\n optimizeDeps: {\n // As of vite v5 / esbuild v19, experimentalDecorators need to be\n // explicitly set, and for some reason this option isn't read from the\n // project's tsconfig.json file by default.\n // See: https://vitejs.dev/blog/announcing-vite5\n esbuildOptions: {\n tsconfigRaw: {\n compilerOptions: {\n target: 'esnext',\n experimentalDecorators: true,\n useDefineForClassFields: false,\n },\n },\n },\n ...(viteConfig.optimizeDeps || {}),\n include: [\n ...(options?.optimizeDeps || []),\n ...(viteConfig.optimizeDeps?.include || []),\n ],\n extensions: [...(viteConfig.optimizeDeps?.extensions || []), '.tsx'],\n },\n ssr: {\n ...(viteConfig.ssr || {}),\n noExternal: ['@blinkk/root', '@blinkk/root-cms/richtext'],\n },\n esbuild: {\n ...(viteConfig.esbuild || {}),\n jsx: 'automatic',\n jsxImportSource: 'preact',\n },\n plugins: [\n ...(viteConfig.plugins || []),\n ...getVitePlugins(rootConfig.plugins || []),\n ],\n });\n return viteServer;\n}\n\n/**\n * Shortcut `viteServer.ssrLoadModule()` without starting an actual dev server.\n */\nexport async function viteSsrLoadModule(\n rootConfig: RootConfig,\n file: string\n): Promise<Record<string, any>> {\n const viteServer = await createViteServer(rootConfig, {hmr: false});\n const module = await viteServer.ssrLoadModule(file);\n await viteServer.close();\n return module;\n}\n"],"mappings":"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","names":["path","path","build"]}