@alepha/react 0.10.4 → 0.10.6
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/index.browser.js +5 -6
- package/dist/index.browser.js.map +1 -1
- package/dist/index.d.ts +28 -28
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +5 -6
- package/dist/index.js.map +1 -1
- package/package.json +12 -12
- package/src/providers/ReactBrowserProvider.ts +8 -1
- package/src/providers/ReactPageProvider.ts +3 -6
package/dist/index.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.js","names":["subs: Function[]","state","timing","envSchema","NestedView","context: Record<string, any>","stack: Array<RouterStackItem>","route","config: Record<string, any>","context","element: ReactNode | Redirection | undefined","children","envSchema","entry: Partial<ReactRouterState>","target: PageRoute | undefined","element","hydrationData: ReactHydrationState","entry: Partial<ReactRouterState>","query: Record<string, string>","previous: PreviousLayerData[]","query: Record<string, string>","options: UseActiveOptions","queryParams","opts: FetchOptions","schema"],"sources":["../src/descriptors/$page.ts","../src/components/ClientOnly.tsx","../src/components/ErrorViewer.tsx","../src/contexts/RouterLayerContext.ts","../src/errors/Redirection.ts","../src/contexts/AlephaContext.ts","../src/hooks/useAlepha.ts","../src/hooks/useRouterEvents.ts","../src/hooks/useStore.ts","../src/hooks/useRouterState.ts","../src/components/ErrorBoundary.tsx","../src/components/NestedView.tsx","../src/components/NotFound.tsx","../src/providers/ReactPageProvider.ts","../src/providers/ReactServerProvider.ts","../src/providers/ReactBrowserRouterProvider.ts","../src/providers/ReactBrowserProvider.ts","../src/services/ReactRouter.ts","../src/hooks/useInject.ts","../src/hooks/useRouter.ts","../src/components/Link.tsx","../src/hooks/useActive.ts","../src/hooks/useClient.ts","../src/hooks/useQueryParams.ts","../src/hooks/useSchema.ts","../src/index.ts"],"sourcesContent":["import {\n\tAlephaError,\n\ttype Async,\n\tcreateDescriptor,\n\tDescriptor,\n\tKIND,\n\ttype Static,\n\ttype TSchema,\n} from \"@alepha/core\";\nimport type { ServerRequest } from \"@alepha/server\";\nimport type { ServerRouteCache } from \"@alepha/server-cache\";\nimport type { FC, ReactNode } from \"react\";\nimport type { ClientOnlyProps } from \"../components/ClientOnly.tsx\";\nimport type { Redirection } from \"../errors/Redirection.ts\";\nimport type { ReactRouterState } from \"../providers/ReactPageProvider.ts\";\n\n/**\n * Main descriptor for defining a React route in the application.\n *\n * The $page descriptor is the core building block for creating type-safe, SSR-enabled React routes.\n * It provides a declarative way to define pages with powerful features:\n *\n * **Routing & Navigation**\n * - URL pattern matching with parameters (e.g., `/users/:id`)\n * - Nested routing with parent-child relationships\n * - Type-safe URL parameter and query string validation\n *\n * **Data Loading**\n * - Server-side data fetching with the `resolve` function\n * - Automatic serialization and hydration for SSR\n * - Access to request context, URL params, and parent data\n *\n * **Component Loading**\n * - Direct component rendering or lazy loading for code splitting\n * - Client-only rendering when browser APIs are needed\n * - Automatic fallback handling during hydration\n *\n * **Performance Optimization**\n * - Static generation for pre-rendered pages at build time\n * - Server-side caching with configurable TTL and providers\n * - Code splitting through lazy component loading\n *\n * **Error Handling**\n * - Custom error handlers with support for redirects\n * - Hierarchical error handling (child → parent)\n * - HTTP status code handling (404, 401, etc.)\n *\n * **Page Animations**\n * - CSS-based enter/exit animations\n * - Dynamic animations based on page state\n * - Custom timing and easing functions\n *\n * **Lifecycle Management**\n * - Server response hooks for headers and status codes\n * - Page leave handlers for cleanup (browser only)\n * - Permission-based access control\n *\n * @example Simple page with data fetching\n * ```typescript\n * const userProfile = $page({\n * path: \"/users/:id\",\n * schema: {\n * params: t.object({ id: t.int() }),\n * query: t.object({ tab: t.optional(t.text()) })\n * },\n * resolve: async ({ params }) => {\n * const user = await userApi.getUser(params.id);\n * return { user };\n * },\n * lazy: () => import(\"./UserProfile.tsx\")\n * });\n * ```\n *\n * @example Nested routing with error handling\n * ```typescript\n * const projectSection = $page({\n * path: \"/projects/:id\",\n * children: () => [projectBoard, projectSettings],\n * resolve: async ({ params }) => {\n * const project = await projectApi.get(params.id);\n * return { project };\n * },\n * errorHandler: (error) => {\n * if (HttpError.is(error, 404)) {\n * return <ProjectNotFound />;\n * }\n * }\n * });\n * ```\n *\n * @example Static generation with caching\n * ```typescript\n * const blogPost = $page({\n * path: \"/blog/:slug\",\n * static: {\n * entries: posts.map(p => ({ params: { slug: p.slug } }))\n * },\n * resolve: async ({ params }) => {\n * const post = await loadPost(params.slug);\n * return { post };\n * }\n * });\n * ```\n */\nexport const $page = <\n\tTConfig extends PageConfigSchema = PageConfigSchema,\n\tTProps extends object = TPropsDefault,\n\tTPropsParent extends object = TPropsParentDefault,\n>(\n\toptions: PageDescriptorOptions<TConfig, TProps, TPropsParent>,\n): PageDescriptor<TConfig, TProps, TPropsParent> => {\n\treturn createDescriptor(\n\t\tPageDescriptor<TConfig, TProps, TPropsParent>,\n\t\toptions,\n\t);\n};\n\n// ---------------------------------------------------------------------------------------------------------------------\n\nexport interface PageDescriptorOptions<\n\tTConfig extends PageConfigSchema = PageConfigSchema,\n\tTProps extends object = TPropsDefault,\n\tTPropsParent extends object = TPropsParentDefault,\n> {\n\t/**\n\t * Name your page.\n\t *\n\t * @default Descriptor key\n\t */\n\tname?: string;\n\n\t/**\n\t * Optional description of the page.\n\t */\n\tdescription?: string;\n\n\t/**\n\t * Add a pathname to the page.\n\t *\n\t * Pathname can contain parameters, like `/post/:slug`.\n\t *\n\t * @default \"\"\n\t */\n\tpath?: string;\n\n\t/**\n\t * Add an input schema to define:\n\t * - `params`: parameters from the pathname.\n\t * - `query`: query parameters from the URL.\n\t */\n\tschema?: TConfig;\n\n\t/**\n\t * Load data before rendering the page.\n\t *\n\t * This function receives\n\t * - the request context and\n\t * - the parent props (if page has a parent)\n\t *\n\t * In SSR, the returned data will be serialized and sent to the client, then reused during the client-side hydration.\n\t *\n\t * Resolve can be stopped by throwing an error, which will be handled by the `errorHandler` function.\n\t * It's common to throw a `NotFoundError` to display a 404 page.\n\t *\n\t * RedirectError can be thrown to redirect the user to another page.\n\t */\n\tresolve?: (context: PageResolve<TConfig, TPropsParent>) => Async<TProps>;\n\n\t/**\n\t * The component to render when the page is loaded.\n\t *\n\t * If `lazy` is defined, this will be ignored.\n\t * Prefer using `lazy` to improve the initial loading time.\n\t */\n\tcomponent?: FC<TProps & TPropsParent>;\n\n\t/**\n\t * Lazy load the component when the page is loaded.\n\t *\n\t * It's recommended to use this for components to improve the initial loading time\n\t * and enable code-splitting.\n\t */\n\tlazy?: () => Promise<{ default: FC<TProps & TPropsParent> }>;\n\n\t/**\n\t * Set some children pages and make the page a parent page.\n\t *\n\t * /!\\ Parent page can't be rendered directly. /!\\\n\t *\n\t * If you still want to render at this pathname, add a child page with an empty path.\n\t */\n\tchildren?: Array<PageDescriptor> | (() => Array<PageDescriptor>);\n\n\tparent?: PageDescriptor<PageConfigSchema, TPropsParent>;\n\n\tcan?: () => boolean;\n\n\t/**\n\t * Catch any error from the `resolve` function or during `rendering`.\n\t *\n\t * Expected to return one of the following:\n\t * - a ReactNode to render an error page\n\t * - a Redirection to redirect the user\n\t * - undefined to let the error propagate\n\t *\n\t * If not defined, the error will be thrown and handled by the server or client error handler.\n\t * If a leaf $page does not define an error handler, the error can be caught by parent pages.\n\t *\n\t * @example Catch a 404 from API and render a custom not found component:\n\t * ```ts\n\t * resolve: async ({ params, query }) => {\n\t * api.fetch(\"/api/resource\", { params, query });\n\t * },\n\t * errorHandler: (error, context) => {\n\t * if (HttpError.is(error, 404)) {\n\t * return <ResourceNotFound />;\n\t * }\n\t * }\n\t * ```\n\t *\n\t * @example Catch an 401 error and redirect the user to the login page:\n\t * ```ts\n\t * resolve: async ({ params, query }) => {\n\t * // but the user is not authenticated\n\t * api.fetch(\"/api/resource\", { params, query });\n\t * },\n\t * errorHandler: (error, context) => {\n\t * if (HttpError.is(error, 401)) {\n\t * // throwing a Redirection is also valid!\n\t * return new Redirection(\"/login\");\n\t * }\n\t * }\n\t * ```\n\t */\n\terrorHandler?: ErrorHandler;\n\n\t/**\n\t * If true, the page will be considered as a static page, immutable and cacheable.\n\t * Replace boolean by an object to define static entries. (e.g. list of params/query)\n\t *\n\t * For now, it only works with `@alepha/vite` which can pre-render the page at build time.\n\t *\n\t * It will act as timeless cached page server-side. You can use `cache` to configure the cache behavior.\n\t */\n\tstatic?:\n\t\t| boolean\n\t\t| {\n\t\t\t\tentries?: Array<Partial<PageRequestConfig<TConfig>>>;\n\t\t };\n\n\tcache?: ServerRouteCache;\n\n\t/**\n\t * If true, force the page to be rendered only on the client-side.\n\t * It uses the `<ClientOnly/>` component to render the page.\n\t */\n\tclient?: boolean | ClientOnlyProps;\n\n\t/**\n\t * Called before the server response is sent to the client.\n\t */\n\tonServerResponse?: (request: ServerRequest) => any;\n\n\t/**\n\t * Called when user leaves the page. (browser only)\n\t */\n\tonLeave?: () => void;\n\n\t/**\n\t * @experimental\n\t *\n\t * Add a css animation when the page is loaded or unloaded.\n\t * It uses CSS animations, so you need to define the keyframes in your CSS.\n\t *\n\t * @example Simple animation name\n\t * ```ts\n\t * animation: \"fadeIn\"\n\t * ```\n\t *\n\t * CSS example:\n\t * ```css\n\t * @keyframes fadeIn {\n\t * from { opacity: 0; }\n\t * to { opacity: 1; }\n\t * }\n\t * ```\n\t *\n\t * @example Detailed animation\n\t * ```ts\n\t * animation: {\n\t * enter: { name: \"fadeIn\", duration: 300 },\n\t * exit: { name: \"fadeOut\", duration: 200, timing: \"ease-in-out\" },\n\t * }\n\t * ```\n\t *\n\t * @example Only exit animation\n\t * ```ts\n\t * animation: {\n\t * exit: \"fadeOut\"\n\t * }\n\t * ```\n\t *\n\t * @example With custom timing function\n\t * ```ts\n\t * animation: {\n\t * enter: { name: \"fadeIn\", duration: 300, timing: \"cubic-bezier(0.4, 0, 0.2, 1)\" },\n\t * exit: { name: \"fadeOut\", duration: 200, timing: \"ease-in-out\" },\n\t * }\n\t * ```\n\t */\n\tanimation?: PageAnimation;\n}\n\nexport type ErrorHandler = (\n\terror: Error,\n\tstate: ReactRouterState,\n) => ReactNode | Redirection | undefined;\n\nexport class PageDescriptor<\n\tTConfig extends PageConfigSchema = PageConfigSchema,\n\tTProps extends object = TPropsDefault,\n\tTPropsParent extends object = TPropsParentDefault,\n> extends Descriptor<PageDescriptorOptions<TConfig, TProps, TPropsParent>> {\n\tprotected onInit() {\n\t\tif (this.options.static) {\n\t\t\tthis.options.cache ??= {\n\t\t\t\tprovider: \"memory\",\n\t\t\t\tttl: [1, \"week\"],\n\t\t\t};\n\t\t}\n\t}\n\n\tpublic get name(): string {\n\t\treturn this.options.name ?? this.config.propertyKey;\n\t}\n\n\t/**\n\t * For testing or build purposes, this will render the page (with or without the HTML layout) and return the HTML and context.\n\t * Only valid for server-side rendering, it will throw an error if called on the client-side.\n\t */\n\tpublic async render(\n\t\toptions?: PageDescriptorRenderOptions,\n\t): Promise<PageDescriptorRenderResult> {\n\t\tthrow new AlephaError(\n\t\t\t\"render() method is not implemented in this environment\",\n\t\t);\n\t}\n\n\tpublic async fetch(options?: PageDescriptorRenderOptions): Promise<{\n\t\thtml: string;\n\t\tresponse: Response;\n\t}> {\n\t\tthrow new AlephaError(\n\t\t\t\"fetch() method is not implemented in this environment\",\n\t\t);\n\t}\n\n\tpublic match(url: string): boolean {\n\t\t// TODO: Implement a way to match the URL against the pathname\n\t\treturn false;\n\t}\n\n\tpublic pathname(config: any) {\n\t\t// TODO: Implement a way to generate the pathname based on the config\n\t\treturn this.options.path || \"\";\n\t}\n}\n\n$page[KIND] = PageDescriptor;\n\n// ---------------------------------------------------------------------------------------------------------------------\n\nexport interface PageConfigSchema {\n\tquery?: TSchema;\n\tparams?: TSchema;\n}\n\nexport type TPropsDefault = any;\n\nexport type TPropsParentDefault = {};\n\nexport interface PageDescriptorRenderOptions {\n\tparams?: Record<string, string>;\n\tquery?: Record<string, string>;\n\n\t/**\n\t * If true, the HTML layout will be included in the response.\n\t * If false, only the page content will be returned.\n\t *\n\t * @default true\n\t */\n\thtml?: boolean;\n\thydration?: boolean;\n}\n\nexport interface PageDescriptorRenderResult {\n\thtml: string;\n\tstate: ReactRouterState;\n\tredirect?: string;\n}\n\nexport interface PageRequestConfig<\n\tTConfig extends PageConfigSchema = PageConfigSchema,\n> {\n\tparams: TConfig[\"params\"] extends TSchema\n\t\t? Static<TConfig[\"params\"]>\n\t\t: Record<string, string>;\n\n\tquery: TConfig[\"query\"] extends TSchema\n\t\t? Static<TConfig[\"query\"]>\n\t\t: Record<string, string>;\n}\n\nexport type PageResolve<\n\tTConfig extends PageConfigSchema = PageConfigSchema,\n\tTPropsParent extends object = TPropsParentDefault,\n> = PageRequestConfig<TConfig> &\n\tTPropsParent &\n\tOmit<ReactRouterState, \"layers\" | \"onError\">;\n\nexport type PageAnimation =\n\t| PageAnimationObject\n\t| ((state: ReactRouterState) => PageAnimationObject | undefined);\n\ntype PageAnimationObject =\n\t| CssAnimationName\n\t| {\n\t\t\tenter?: CssAnimation | CssAnimationName;\n\t\t\texit?: CssAnimation | CssAnimationName;\n\t };\n\ntype CssAnimationName = string;\n\ntype CssAnimation = {\n\tname: string;\n\tduration?: number;\n\ttiming?: string;\n};\n","import {\n\ttype PropsWithChildren,\n\ttype ReactNode,\n\tuseEffect,\n\tuseState,\n} from \"react\";\n\nexport interface ClientOnlyProps {\n\tfallback?: ReactNode;\n\tdisabled?: boolean;\n}\n\n/**\n * A small utility component that renders its children only on the client side.\n *\n * Optionally, you can provide a fallback React node that will be rendered.\n *\n * You should use this component when\n * - you have code that relies on browser-specific APIs\n * - you want to avoid server-side rendering for a specific part of your application\n * - you want to prevent pre-rendering of a component\n */\nconst ClientOnly = (props: PropsWithChildren<ClientOnlyProps>) => {\n\tconst [mounted, setMounted] = useState(false);\n\n\tuseEffect(() => setMounted(true), []);\n\n\tif (props.disabled) {\n\t\treturn props.children;\n\t}\n\n\treturn mounted ? props.children : props.fallback;\n};\n\nexport default ClientOnly;\n","import type { Alepha } from \"@alepha/core\";\nimport { useState } from \"react\";\n\ninterface ErrorViewerProps {\n\terror: Error;\n\talepha: Alepha;\n}\n\n// TODO: design this better\n\nconst ErrorViewer = ({ error, alepha }: ErrorViewerProps) => {\n\tconst [expanded, setExpanded] = useState(false);\n\tconst isProduction = alepha.isProduction();\n\t// const status = isHttpError(error) ? error.status : 500;\n\n\tif (isProduction) {\n\t\treturn <ErrorViewerProduction />;\n\t}\n\n\tconst stackLines = error.stack?.split(\"\\n\") ?? [];\n\tconst previewLines = stackLines.slice(0, 5);\n\tconst hiddenLineCount = stackLines.length - previewLines.length;\n\n\tconst copyToClipboard = (text: string) => {\n\t\tnavigator.clipboard.writeText(text).catch((err) => {\n\t\t\tconsole.error(\"Clipboard error:\", err);\n\t\t});\n\t};\n\n\tconst styles = {\n\t\tcontainer: {\n\t\t\tpadding: \"24px\",\n\t\t\tbackgroundColor: \"#FEF2F2\",\n\t\t\tcolor: \"#7F1D1D\",\n\t\t\tborder: \"1px solid #FECACA\",\n\t\t\tborderRadius: \"16px\",\n\t\t\tboxShadow: \"0 8px 24px rgba(0,0,0,0.05)\",\n\t\t\tfontFamily: \"monospace\",\n\t\t\tmaxWidth: \"768px\",\n\t\t\tmargin: \"40px auto\",\n\t\t},\n\t\theading: {\n\t\t\tfontSize: \"20px\",\n\t\t\tfontWeight: \"bold\",\n\t\t\tmarginBottom: \"10px\",\n\t\t},\n\t\tname: {\n\t\t\tfontSize: \"16px\",\n\t\t\tfontWeight: 600,\n\t\t},\n\t\tmessage: {\n\t\t\tfontSize: \"14px\",\n\t\t\tmarginBottom: \"16px\",\n\t\t},\n\t\tsectionHeader: {\n\t\t\tdisplay: \"flex\",\n\t\t\tjustifyContent: \"space-between\",\n\t\t\talignItems: \"center\",\n\t\t\tfontSize: \"12px\",\n\t\t\tmarginBottom: \"4px\",\n\t\t\tcolor: \"#991B1B\",\n\t\t},\n\t\tcopyButton: {\n\t\t\tfontSize: \"12px\",\n\t\t\tcolor: \"#DC2626\",\n\t\t\tbackground: \"none\",\n\t\t\tborder: \"none\",\n\t\t\tcursor: \"pointer\",\n\t\t\ttextDecoration: \"underline\",\n\t\t},\n\t\tstackContainer: {\n\t\t\tbackgroundColor: \"#FEE2E2\",\n\t\t\tpadding: \"12px\",\n\t\t\tborderRadius: \"8px\",\n\t\t\tfontSize: \"13px\",\n\t\t\tlineHeight: \"1.4\",\n\t\t\toverflowX: \"auto\" as const,\n\t\t\twhiteSpace: \"pre-wrap\" as const,\n\t\t},\n\t\texpandLine: {\n\t\t\tcolor: \"#F87171\",\n\t\t\tcursor: \"pointer\",\n\t\t\tmarginTop: \"8px\",\n\t\t},\n\t};\n\n\treturn (\n\t\t<div style={styles.container}>\n\t\t\t<div>\n\t\t\t\t<div style={styles.heading}>🔥 Error</div>\n\t\t\t\t<div style={styles.name}>{error.name}</div>\n\t\t\t\t<div style={styles.message}>{error.message}</div>\n\t\t\t</div>\n\n\t\t\t{stackLines.length > 0 && (\n\t\t\t\t<div>\n\t\t\t\t\t<div style={styles.sectionHeader}>\n\t\t\t\t\t\t<span>Stack trace</span>\n\t\t\t\t\t\t<button\n\t\t\t\t\t\t\tonClick={() => copyToClipboard(error.stack!)}\n\t\t\t\t\t\t\tstyle={styles.copyButton}\n\t\t\t\t\t\t>\n\t\t\t\t\t\t\tCopy all\n\t\t\t\t\t\t</button>\n\t\t\t\t\t</div>\n\t\t\t\t\t<pre style={styles.stackContainer}>\n\t\t\t\t\t\t{(expanded ? stackLines : previewLines).map((line, i) => (\n\t\t\t\t\t\t\t<div key={i}>{line}</div>\n\t\t\t\t\t\t))}\n\t\t\t\t\t\t{!expanded && hiddenLineCount > 0 && (\n\t\t\t\t\t\t\t<div style={styles.expandLine} onClick={() => setExpanded(true)}>\n\t\t\t\t\t\t\t\t+ {hiddenLineCount} more lines...\n\t\t\t\t\t\t\t</div>\n\t\t\t\t\t\t)}\n\t\t\t\t\t</pre>\n\t\t\t\t</div>\n\t\t\t)}\n\t\t</div>\n\t);\n};\n\nexport default ErrorViewer;\n\nconst ErrorViewerProduction = () => {\n\tconst styles = {\n\t\tcontainer: {\n\t\t\tpadding: \"24px\",\n\t\t\tbackgroundColor: \"#FEF2F2\",\n\t\t\tcolor: \"#7F1D1D\",\n\t\t\tborder: \"1px solid #FECACA\",\n\t\t\tborderRadius: \"16px\",\n\t\t\tboxShadow: \"0 8px 24px rgba(0,0,0,0.05)\",\n\t\t\tfontFamily: \"monospace\",\n\t\t\tmaxWidth: \"768px\",\n\t\t\tmargin: \"40px auto\",\n\t\t\ttextAlign: \"center\" as const,\n\t\t},\n\t\theading: {\n\t\t\tfontSize: \"20px\",\n\t\t\tfontWeight: \"bold\",\n\t\t\tmarginBottom: \"8px\",\n\t\t},\n\t\tname: {\n\t\t\tfontSize: \"16px\",\n\t\t\tfontWeight: 600,\n\t\t\tmarginBottom: \"4px\",\n\t\t},\n\t\tmessage: {\n\t\t\tfontSize: \"14px\",\n\t\t\topacity: 0.85,\n\t\t},\n\t};\n\n\treturn (\n\t\t<div style={styles.container}>\n\t\t\t<div style={styles.heading}>🚨 An error occurred</div>\n\t\t\t<div style={styles.message}>\n\t\t\t\tSomething went wrong. Please try again later.\n\t\t\t</div>\n\t\t</div>\n\t);\n};\n","import { createContext } from \"react\";\n\nexport interface RouterLayerContextValue {\n\tindex: number;\n\tpath: string;\n}\n\nexport const RouterLayerContext = createContext<\n\tRouterLayerContextValue | undefined\n>(undefined);\n","/**\n * Used for Redirection during the page loading.\n *\n * Depends on the context, it can be thrown or just returned.\n */\nexport class Redirection extends Error {\n\tpublic readonly redirect: string;\n\n\tconstructor(redirect: string) {\n\t\tsuper(\"Redirection\");\n\t\tthis.redirect = redirect;\n\t}\n}\n","import type { Alepha } from \"@alepha/core\";\nimport { createContext } from \"react\";\n\nexport const AlephaContext = createContext<Alepha | undefined>(undefined);\n","import { type Alepha, AlephaError } from \"@alepha/core\";\nimport { useContext } from \"react\";\nimport { AlephaContext } from \"../contexts/AlephaContext.ts\";\n\n/**\n * Main Alepha hook.\n *\n * It provides access to the Alepha instance within a React component.\n *\n * With Alepha, you can access the core functionalities of the framework:\n *\n * - alepha.state() for state management\n * - alepha.inject() for dependency injection\n * - alepha.events.emit() for event handling\n * etc...\n */\nexport const useAlepha = (): Alepha => {\n\tconst alepha = useContext(AlephaContext);\n\tif (!alepha) {\n\t\tthrow new AlephaError(\n\t\t\t\"Hook 'useAlepha()' must be used within an AlephaContext.Provider\",\n\t\t);\n\t}\n\n\treturn alepha;\n};\n","import type { Hooks } from \"@alepha/core\";\nimport { useEffect } from \"react\";\nimport { useAlepha } from \"./useAlepha.ts\";\n\ntype Hook<T extends keyof Hooks> =\n\t| ((ev: Hooks[T]) => void)\n\t| {\n\t\t\tpriority?: \"first\" | \"last\";\n\t\t\tcallback: (ev: Hooks[T]) => void;\n\t };\n\n/**\n * Subscribe to various router events.\n */\nexport const useRouterEvents = (\n\topts: {\n\t\tonBegin?: Hook<\"react:transition:begin\">;\n\t\tonError?: Hook<\"react:transition:error\">;\n\t\tonEnd?: Hook<\"react:transition:end\">;\n\t\tonSuccess?: Hook<\"react:transition:success\">;\n\t} = {},\n\tdeps: any[] = [],\n) => {\n\tconst alepha = useAlepha();\n\n\tuseEffect(() => {\n\t\tif (!alepha.isBrowser()) {\n\t\t\treturn;\n\t\t}\n\n\t\tconst cb = <T extends keyof Hooks>(callback: Hook<T>) => {\n\t\t\tif (typeof callback === \"function\") {\n\t\t\t\treturn { callback };\n\t\t\t}\n\t\t\treturn callback;\n\t\t};\n\n\t\tconst subs: Function[] = [];\n\t\tconst onBegin = opts.onBegin;\n\t\tconst onEnd = opts.onEnd;\n\t\tconst onError = opts.onError;\n\t\tconst onSuccess = opts.onSuccess;\n\n\t\tif (onBegin) {\n\t\t\tsubs.push(alepha.events.on(\"react:transition:begin\", cb(onBegin)));\n\t\t}\n\n\t\tif (onEnd) {\n\t\t\tsubs.push(alepha.events.on(\"react:transition:end\", cb(onEnd)));\n\t\t}\n\n\t\tif (onError) {\n\t\t\tsubs.push(alepha.events.on(\"react:transition:error\", cb(onError)));\n\t\t}\n\n\t\tif (onSuccess) {\n\t\t\tsubs.push(alepha.events.on(\"react:transition:success\", cb(onSuccess)));\n\t\t}\n\n\t\treturn () => {\n\t\t\tfor (const sub of subs) {\n\t\t\t\tsub();\n\t\t\t}\n\t\t};\n\t}, deps);\n};\n","import type { State } from \"@alepha/core\";\nimport { useEffect, useMemo, useState } from \"react\";\nimport { useAlepha } from \"./useAlepha.ts\";\n\n/**\n * Hook to access and mutate the Alepha state.\n */\nexport const useStore = <Key extends keyof State>(\n\tkey: Key,\n\tdefaultValue?: State[Key],\n): [State[Key], (value: State[Key]) => void] => {\n\tconst alepha = useAlepha();\n\n\tuseMemo(() => {\n\t\tif (defaultValue != null && alepha.state.get(key) == null) {\n\t\t\talepha.state.set(key, defaultValue);\n\t\t}\n\t}, [defaultValue]);\n\n\tconst [state, setState] = useState(alepha.state.get(key));\n\n\tuseEffect(() => {\n\t\tif (!alepha.isBrowser()) {\n\t\t\treturn;\n\t\t}\n\n\t\treturn alepha.events.on(\"state:mutate\", (ev) => {\n\t\t\tif (ev.key === key) {\n\t\t\t\tsetState(ev.value);\n\t\t\t}\n\t\t});\n\t}, []);\n\n\treturn [\n\t\tstate,\n\t\t(value: State[Key]) => {\n\t\t\talepha.state.set(key, value);\n\t\t},\n\t] as const;\n};\n","import { AlephaError } from \"@alepha/core\";\nimport type { ReactRouterState } from \"../providers/ReactPageProvider.ts\";\nimport { useStore } from \"./useStore.ts\";\n\nexport const useRouterState = (): ReactRouterState => {\n\tconst [state] = useStore(\"react.router.state\");\n\tif (!state) {\n\t\tthrow new AlephaError(\"Missing react router state\");\n\t}\n\treturn state;\n};\n","import React, {\n\ttype ErrorInfo,\n\ttype PropsWithChildren,\n\ttype ReactNode,\n} from \"react\";\n\n/**\n * Props for the ErrorBoundary component.\n */\nexport interface ErrorBoundaryProps {\n\t/**\n\t * Fallback React node to render when an error is caught.\n\t * If not provided, a default error message will be shown.\n\t */\n\tfallback: (error: Error) => ReactNode;\n\n\t/**\n\t * Optional callback that receives the error and error info.\n\t * Use this to log errors to a monitoring service.\n\t */\n\tonError?: (error: Error, info: ErrorInfo) => void;\n}\n\n/**\n * State of the ErrorBoundary component.\n */\ninterface ErrorBoundaryState {\n\terror?: Error;\n}\n\n/**\n * A reusable error boundary for catching rendering errors\n * in any part of the React component tree.\n */\nexport class ErrorBoundary extends React.Component<\n\tPropsWithChildren<ErrorBoundaryProps>,\n\tErrorBoundaryState\n> {\n\tconstructor(props: ErrorBoundaryProps) {\n\t\tsuper(props);\n\t\tthis.state = {};\n\t}\n\n\t/**\n\t * Update state so the next render shows the fallback UI.\n\t */\n\tstatic getDerivedStateFromError(error: Error): ErrorBoundaryState {\n\t\treturn {\n\t\t\terror,\n\t\t};\n\t}\n\n\t/**\n\t * Lifecycle method called when an error is caught.\n\t * You can log the error or perform side effects here.\n\t */\n\tcomponentDidCatch(error: Error, info: ErrorInfo): void {\n\t\tif (this.props.onError) {\n\t\t\tthis.props.onError(error, info);\n\t\t}\n\t}\n\n\trender(): ReactNode {\n\t\tif (this.state.error) {\n\t\t\treturn this.props.fallback(this.state.error);\n\t\t}\n\n\t\treturn this.props.children;\n\t}\n}\n\nexport default ErrorBoundary;\n","import { memo, type ReactNode, use, useRef, useState } from \"react\";\nimport { RouterLayerContext } from \"../contexts/RouterLayerContext.ts\";\nimport type { PageAnimation } from \"../descriptors/$page.ts\";\nimport { Redirection } from \"../errors/Redirection.ts\";\nimport { useRouterEvents } from \"../hooks/useRouterEvents.ts\";\nimport { useRouterState } from \"../hooks/useRouterState.ts\";\nimport type { ReactRouterState } from \"../providers/ReactPageProvider.ts\";\nimport ErrorBoundary from \"./ErrorBoundary.tsx\";\n\nexport interface NestedViewProps {\n\tchildren?: ReactNode;\n\terrorBoundary?: false | ((error: Error) => ReactNode);\n}\n\n/**\n * A component that renders the current view of the nested router layer.\n *\n * To be simple, it renders the `element` of the current child page of a parent page.\n *\n * @example\n * ```tsx\n * import { NestedView } from \"alepha/react\";\n *\n * class App {\n * parent = $page({\n * component: () => <NestedView />,\n * });\n *\n * child = $page({\n * parent: this.root,\n * component: () => <div>Child Page</div>,\n * });\n * }\n * ```\n */\nconst NestedView = (props: NestedViewProps) => {\n\tconst index = use(RouterLayerContext)?.index ?? 0;\n\tconst state = useRouterState();\n\n\tconst [view, setView] = useState<ReactNode | undefined>(\n\t\tstate.layers[index]?.element,\n\t);\n\n\tconst [animation, setAnimation] = useState(\"\");\n\tconst animationExitDuration = useRef<number>(0);\n\tconst animationExitNow = useRef<number>(0);\n\n\tuseRouterEvents(\n\t\t{\n\t\t\tonBegin: async ({ previous, state }) => {\n\t\t\t\t// --------- Animations Begin ---------\n\t\t\t\tconst layer = previous.layers[index];\n\t\t\t\tif (`${state.url.pathname}/`.startsWith(`${layer?.path}/`)) {\n\t\t\t\t\treturn;\n\t\t\t\t}\n\n\t\t\t\tconst animationExit = parseAnimation(\n\t\t\t\t\tlayer.route?.animation,\n\t\t\t\t\tstate,\n\t\t\t\t\t\"exit\",\n\t\t\t\t);\n\n\t\t\t\tif (animationExit) {\n\t\t\t\t\tconst duration = animationExit.duration || 200;\n\t\t\t\t\tanimationExitNow.current = Date.now();\n\t\t\t\t\tanimationExitDuration.current = duration;\n\t\t\t\t\tsetAnimation(animationExit.animation);\n\t\t\t\t} else {\n\t\t\t\t\tanimationExitNow.current = 0;\n\t\t\t\t\tanimationExitDuration.current = 0;\n\t\t\t\t\tsetAnimation(\"\");\n\t\t\t\t}\n\t\t\t\t// --------- Animations End ---------\n\t\t\t},\n\t\t\tonEnd: async ({ state }) => {\n\t\t\t\tconst layer = state.layers[index];\n\n\t\t\t\t// --------- Animations Begin ---------\n\t\t\t\tif (animationExitNow.current) {\n\t\t\t\t\tconst duration = animationExitDuration.current;\n\t\t\t\t\tconst diff = Date.now() - animationExitNow.current;\n\t\t\t\t\tif (diff < duration) {\n\t\t\t\t\t\tawait new Promise((resolve) =>\n\t\t\t\t\t\t\tsetTimeout(resolve, duration - diff),\n\t\t\t\t\t\t);\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t\t// --------- Animations End ---------\n\n\t\t\t\tif (!layer?.cache) {\n\t\t\t\t\tsetView(layer?.element);\n\n\t\t\t\t\t// --------- Animations Begin ---------\n\t\t\t\t\tconst animationEnter = parseAnimation(\n\t\t\t\t\t\tlayer?.route?.animation,\n\t\t\t\t\t\tstate,\n\t\t\t\t\t\t\"enter\",\n\t\t\t\t\t);\n\n\t\t\t\t\tif (animationEnter) {\n\t\t\t\t\t\tsetAnimation(animationEnter.animation);\n\t\t\t\t\t} else {\n\t\t\t\t\t\tsetAnimation(\"\");\n\t\t\t\t\t}\n\t\t\t\t\t// --------- Animations End ---------\n\t\t\t\t}\n\t\t\t},\n\t\t},\n\t\t[],\n\t);\n\n\tlet element = view ?? props.children ?? null;\n\n\t// --------- Animations Begin ---------\n\tif (animation) {\n\t\telement = (\n\t\t\t<div\n\t\t\t\tstyle={{\n\t\t\t\t\tdisplay: \"flex\",\n\t\t\t\t\tflex: 1,\n\t\t\t\t\theight: \"100%\",\n\t\t\t\t\twidth: \"100%\",\n\t\t\t\t\tposition: \"relative\",\n\t\t\t\t\toverflow: \"hidden\",\n\t\t\t\t}}\n\t\t\t>\n\t\t\t\t<div\n\t\t\t\t\tstyle={{ height: \"100%\", width: \"100%\", display: \"flex\", animation }}\n\t\t\t\t>\n\t\t\t\t\t{element}\n\t\t\t\t</div>\n\t\t\t</div>\n\t\t);\n\t}\n\t// --------- Animations End ---------\n\n\tif (props.errorBoundary === false) {\n\t\treturn <>{element}</>;\n\t}\n\n\tif (props.errorBoundary) {\n\t\treturn (\n\t\t\t<ErrorBoundary fallback={props.errorBoundary}>{element}</ErrorBoundary>\n\t\t);\n\t}\n\n\treturn (\n\t\t<ErrorBoundary\n\t\t\tfallback={(error) => {\n\t\t\t\tconst result = state.onError(error, state); // TODO: onError is not refreshed\n\t\t\t\tif (result instanceof Redirection) {\n\t\t\t\t\treturn \"Redirection inside ErrorBoundary is not allowed.\";\n\t\t\t\t}\n\t\t\t\treturn result as ReactNode;\n\t\t\t}}\n\t\t>\n\t\t\t{element}\n\t\t</ErrorBoundary>\n\t);\n};\n\nexport default memo(NestedView);\n\nfunction parseAnimation(\n\tanimationLike: PageAnimation | undefined,\n\tstate: ReactRouterState,\n\ttype: \"enter\" | \"exit\" = \"enter\",\n):\n\t| {\n\t\t\tduration: number;\n\t\t\tanimation: string;\n\t }\n\t| undefined {\n\tif (!animationLike) {\n\t\treturn undefined;\n\t}\n\n\tconst DEFAULT_DURATION = 300;\n\n\tconst animation =\n\t\ttypeof animationLike === \"function\" ? animationLike(state) : animationLike;\n\n\tif (typeof animation === \"string\") {\n\t\tif (type === \"exit\") {\n\t\t\treturn;\n\t\t}\n\t\treturn {\n\t\t\tduration: DEFAULT_DURATION,\n\t\t\tanimation: `${DEFAULT_DURATION}ms ${animation}`,\n\t\t};\n\t}\n\n\tif (typeof animation === \"object\") {\n\t\tconst anim = animation[type];\n\t\tconst duration =\n\t\t\ttypeof anim === \"object\"\n\t\t\t\t? (anim.duration ?? DEFAULT_DURATION)\n\t\t\t\t: DEFAULT_DURATION;\n\t\tconst name = typeof anim === \"object\" ? anim.name : anim;\n\n\t\tif (type === \"exit\") {\n\t\t\tconst timing = typeof anim === \"object\" ? (anim.timing ?? \"\") : \"\";\n\t\t\treturn {\n\t\t\t\tduration,\n\t\t\t\tanimation: `${duration}ms ${timing} ${name}`,\n\t\t\t};\n\t\t}\n\n\t\tconst timing = typeof anim === \"object\" ? (anim.timing ?? \"\") : \"\";\n\n\t\treturn {\n\t\t\tduration,\n\t\t\tanimation: `${duration}ms ${timing} ${name}`,\n\t\t};\n\t}\n\n\treturn undefined;\n}\n","import type { CSSProperties } from \"react\";\n\nexport default function NotFoundPage(props: { style?: CSSProperties }) {\n\treturn (\n\t\t<div\n\t\t\tstyle={{\n\t\t\t\theight: \"100vh\",\n\t\t\t\tdisplay: \"flex\",\n\t\t\t\tflexDirection: \"column\",\n\t\t\t\tjustifyContent: \"center\",\n\t\t\t\talignItems: \"center\",\n\t\t\t\ttextAlign: \"center\",\n\t\t\t\tfontFamily: \"sans-serif\",\n\t\t\t\tpadding: \"1rem\",\n\t\t\t\t...props.style,\n\t\t\t}}\n\t\t>\n\t\t\t<h1 style={{ fontSize: \"1rem\", marginBottom: \"0.5rem\" }}>\n\t\t\t\t404 - This page does not exist\n\t\t\t</h1>\n\t\t</div>\n\t);\n}\n","import {\n\t$env,\n\t$hook,\n\t$inject,\n\tAlepha,\n\ttype Static,\n\ttype TSchema,\n\tt,\n} from \"@alepha/core\";\nimport { $logger } from \"@alepha/logger\";\nimport { createElement, type ReactNode, StrictMode } from \"react\";\nimport ClientOnly from \"../components/ClientOnly.tsx\";\nimport ErrorViewer from \"../components/ErrorViewer.tsx\";\nimport NestedView from \"../components/NestedView.tsx\";\nimport NotFoundPage from \"../components/NotFound.tsx\";\nimport { AlephaContext } from \"../contexts/AlephaContext.ts\";\nimport { RouterLayerContext } from \"../contexts/RouterLayerContext.ts\";\nimport {\n\t$page,\n\ttype ErrorHandler,\n\ttype PageDescriptor,\n\ttype PageDescriptorOptions,\n} from \"../descriptors/$page.ts\";\nimport { Redirection } from \"../errors/Redirection.ts\";\n\nconst envSchema = t.object({\n\tREACT_STRICT_MODE: t.boolean({ default: true }),\n});\n\ndeclare module \"@alepha/core\" {\n\texport interface Env extends Partial<Static<typeof envSchema>> {}\n}\n\nexport class ReactPageProvider {\n\tprotected readonly log = $logger();\n\tprotected readonly env = $env(envSchema);\n\tprotected readonly alepha = $inject(Alepha);\n\tprotected readonly pages: PageRoute[] = [];\n\n\tpublic getPages(): PageRoute[] {\n\t\treturn this.pages;\n\t}\n\n\tpublic page(name: string): PageRoute {\n\t\tfor (const page of this.pages) {\n\t\t\tif (page.name === name) {\n\t\t\t\treturn page;\n\t\t\t}\n\t\t}\n\n\t\tthrow new Error(`Page ${name} not found`);\n\t}\n\n\tpublic pathname(\n\t\tname: string,\n\t\toptions: {\n\t\t\tparams?: Record<string, string>;\n\t\t\tquery?: Record<string, string>;\n\t\t} = {},\n\t) {\n\t\tconst page = this.page(name);\n\t\tif (!page) {\n\t\t\tthrow new Error(`Page ${name} not found`);\n\t\t}\n\n\t\tlet url = page.path ?? \"\";\n\t\tlet parent = page.parent;\n\t\twhile (parent) {\n\t\t\turl = `${parent.path ?? \"\"}/${url}`;\n\t\t\tparent = parent.parent;\n\t\t}\n\n\t\turl = this.compile(url, options.params ?? {});\n\n\t\tif (options.query) {\n\t\t\tconst query = new URLSearchParams(options.query);\n\t\t\tif (query.toString()) {\n\t\t\t\turl += `?${query.toString()}`;\n\t\t\t}\n\t\t}\n\n\t\treturn url.replace(/\\/\\/+/g, \"/\") || \"/\";\n\t}\n\n\tpublic url(\n\t\tname: string,\n\t\toptions: { params?: Record<string, string>; host?: string } = {},\n\t): URL {\n\t\treturn new URL(\n\t\t\tthis.pathname(name, options),\n\t\t\t// use provided base or default to http://localhost\n\t\t\toptions.host ?? `http://localhost`,\n\t\t);\n\t}\n\n\tpublic root(state: ReactRouterState): ReactNode {\n\t\tconst root = createElement(\n\t\t\tAlephaContext.Provider,\n\t\t\t{ value: this.alepha },\n\t\t\tcreateElement(NestedView, {}, state.layers[0]?.element),\n\t\t);\n\n\t\tif (this.env.REACT_STRICT_MODE) {\n\t\t\treturn createElement(StrictMode, {}, root);\n\t\t}\n\n\t\treturn root;\n\t}\n\n\tprotected convertStringObjectToObject = (\n\t\tschema?: TSchema,\n\t\tvalue?: any,\n\t): any => {\n\t\tif (t.schema.isObject(schema) && typeof value === \"object\") {\n\t\t\tfor (const key in schema.properties) {\n\t\t\t\tif (\n\t\t\t\t\tt.schema.isObject(schema.properties[key]) &&\n\t\t\t\t\ttypeof value[key] === \"string\"\n\t\t\t\t) {\n\t\t\t\t\ttry {\n\t\t\t\t\t\tvalue[key] = this.alepha.parse(\n\t\t\t\t\t\t\tschema.properties[key],\n\t\t\t\t\t\t\tdecodeURIComponent(value[key]),\n\t\t\t\t\t\t);\n\t\t\t\t\t} catch (e) {\n\t\t\t\t\t\t// ignore\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t\treturn value;\n\t};\n\n\t/**\n\t * Create a new RouterState based on a given route and request.\n\t * This method resolves the layers for the route, applying any query and params schemas defined in the route.\n\t * It also handles errors and redirects.\n\t */\n\tpublic async createLayers(\n\t\troute: PageRoute,\n\t\tstate: ReactRouterState,\n\t\tprevious: PreviousLayerData[] = [],\n\t): Promise<CreateLayersResult> {\n\t\tlet context: Record<string, any> = {}; // all props\n\t\tconst stack: Array<RouterStackItem> = [{ route }]; // stack of routes\n\n\t\tlet parent = route.parent;\n\t\twhile (parent) {\n\t\t\tstack.unshift({ route: parent });\n\t\t\tparent = parent.parent;\n\t\t}\n\n\t\tlet forceRefresh = false;\n\n\t\tfor (let i = 0; i < stack.length; i++) {\n\t\t\tconst it = stack[i];\n\t\t\tconst route = it.route;\n\t\t\tconst config: Record<string, any> = {};\n\n\t\t\ttry {\n\t\t\t\tthis.convertStringObjectToObject(route.schema?.query, state.query);\n\t\t\t\tconfig.query = route.schema?.query\n\t\t\t\t\t? this.alepha.parse(route.schema.query, state.query)\n\t\t\t\t\t: {};\n\t\t\t} catch (e) {\n\t\t\t\tit.error = e as Error;\n\t\t\t\tbreak;\n\t\t\t}\n\n\t\t\ttry {\n\t\t\t\tconfig.params = route.schema?.params\n\t\t\t\t\t? this.alepha.parse(route.schema.params, state.params)\n\t\t\t\t\t: {};\n\t\t\t} catch (e) {\n\t\t\t\tit.error = e as Error;\n\t\t\t\tbreak;\n\t\t\t}\n\n\t\t\t// save config\n\t\t\tit.config = {\n\t\t\t\t...config,\n\t\t\t};\n\n\t\t\t// check if previous layer is the same, reuse if possible\n\t\t\tif (previous?.[i] && !forceRefresh && previous[i].name === route.name) {\n\t\t\t\tconst url = (str?: string) => (str ? str.replace(/\\/\\/+/g, \"/\") : \"/\");\n\n\t\t\t\tconst prev = JSON.stringify({\n\t\t\t\t\tpart: url(previous[i].part),\n\t\t\t\t\tparams: previous[i].config?.params ?? {},\n\t\t\t\t});\n\n\t\t\t\tconst curr = JSON.stringify({\n\t\t\t\t\tpart: url(route.path),\n\t\t\t\t\tparams: config.params ?? {},\n\t\t\t\t});\n\n\t\t\t\tif (prev === curr) {\n\t\t\t\t\t// part is the same, reuse previous layer\n\t\t\t\t\tit.props = previous[i].props;\n\t\t\t\t\tit.error = previous[i].error;\n\t\t\t\t\tit.cache = true;\n\t\t\t\t\tcontext = {\n\t\t\t\t\t\t...context,\n\t\t\t\t\t\t...it.props,\n\t\t\t\t\t};\n\t\t\t\t\tcontinue;\n\t\t\t\t}\n\n\t\t\t\t// part is different, force refresh of next layers\n\t\t\t\tforceRefresh = true;\n\t\t\t}\n\n\t\t\t// no resolve, render a basic view by default\n\t\t\tif (!route.resolve) {\n\t\t\t\tcontinue;\n\t\t\t}\n\n\t\t\ttry {\n\t\t\t\tconst props =\n\t\t\t\t\t(await route.resolve?.({\n\t\t\t\t\t\t...state, // request\n\t\t\t\t\t\t...config, // params, query\n\t\t\t\t\t\t...context, // previous props\n\t\t\t\t\t} as any)) ?? {};\n\n\t\t\t\t// save props\n\t\t\t\tit.props = {\n\t\t\t\t\t...props,\n\t\t\t\t};\n\n\t\t\t\t// add props to context\n\t\t\t\tcontext = {\n\t\t\t\t\t...context,\n\t\t\t\t\t...props,\n\t\t\t\t};\n\t\t\t} catch (e) {\n\t\t\t\t// check if we need to redirect\n\t\t\t\tif (e instanceof Redirection) {\n\t\t\t\t\treturn {\n\t\t\t\t\t\tredirect: e.redirect,\n\t\t\t\t\t};\n\t\t\t\t}\n\n\t\t\t\tthis.log.error(\"Page resolver has failed\", e);\n\n\t\t\t\tit.error = e as Error;\n\t\t\t\tbreak;\n\t\t\t}\n\t\t}\n\n\t\tlet acc = \"\";\n\t\tfor (let i = 0; i < stack.length; i++) {\n\t\t\tconst it = stack[i];\n\t\t\tconst props = it.props ?? {};\n\n\t\t\tconst params = { ...it.config?.params };\n\t\t\tfor (const key of Object.keys(params)) {\n\t\t\t\tparams[key] = String(params[key]);\n\t\t\t}\n\n\t\t\tacc += \"/\";\n\t\t\tacc += it.route.path ? this.compile(it.route.path, params) : \"\";\n\t\t\tconst path = acc.replace(/\\/+/, \"/\");\n\t\t\tconst localErrorHandler = this.getErrorHandler(it.route);\n\t\t\tif (localErrorHandler) {\n\t\t\t\tconst onErrorParent = state.onError;\n\t\t\t\tstate.onError = (error, context) => {\n\t\t\t\t\tconst result = localErrorHandler(error, context);\n\t\t\t\t\t// if nothing happen, call the parent\n\t\t\t\t\tif (result === undefined) {\n\t\t\t\t\t\treturn onErrorParent(error, context);\n\t\t\t\t\t}\n\t\t\t\t\treturn result;\n\t\t\t\t};\n\t\t\t}\n\n\t\t\t// normal use case\n\t\t\tif (!it.error) {\n\t\t\t\ttry {\n\t\t\t\t\tconst element = await this.createElement(it.route, {\n\t\t\t\t\t\t...props,\n\t\t\t\t\t\t...context,\n\t\t\t\t\t});\n\n\t\t\t\t\tstate.layers.push({\n\t\t\t\t\t\tname: it.route.name,\n\t\t\t\t\t\tprops,\n\t\t\t\t\t\tpart: it.route.path,\n\t\t\t\t\t\tconfig: it.config,\n\t\t\t\t\t\telement: this.renderView(i + 1, path, element, it.route),\n\t\t\t\t\t\tindex: i + 1,\n\t\t\t\t\t\tpath,\n\t\t\t\t\t\troute: it.route,\n\t\t\t\t\t\tcache: it.cache,\n\t\t\t\t\t});\n\t\t\t\t} catch (e) {\n\t\t\t\t\tit.error = e as Error;\n\t\t\t\t}\n\t\t\t}\n\n\t\t\t// handler has thrown an error, render an error view\n\t\t\tif (it.error) {\n\t\t\t\ttry {\n\t\t\t\t\tlet element: ReactNode | Redirection | undefined =\n\t\t\t\t\t\tawait state.onError(it.error, state);\n\n\t\t\t\t\tif (element === undefined) {\n\t\t\t\t\t\tthrow it.error;\n\t\t\t\t\t}\n\n\t\t\t\t\tif (element instanceof Redirection) {\n\t\t\t\t\t\treturn {\n\t\t\t\t\t\t\tredirect: element.redirect,\n\t\t\t\t\t\t};\n\t\t\t\t\t}\n\n\t\t\t\t\tif (element === null) {\n\t\t\t\t\t\telement = this.renderError(it.error);\n\t\t\t\t\t}\n\n\t\t\t\t\tstate.layers.push({\n\t\t\t\t\t\tprops,\n\t\t\t\t\t\terror: it.error,\n\t\t\t\t\t\tname: it.route.name,\n\t\t\t\t\t\tpart: it.route.path,\n\t\t\t\t\t\tconfig: it.config,\n\t\t\t\t\t\telement: this.renderView(i + 1, path, element, it.route),\n\t\t\t\t\t\tindex: i + 1,\n\t\t\t\t\t\tpath,\n\t\t\t\t\t\troute: it.route,\n\t\t\t\t\t});\n\t\t\t\t\tbreak;\n\t\t\t\t} catch (e) {\n\t\t\t\t\tif (e instanceof Redirection) {\n\t\t\t\t\t\treturn {\n\t\t\t\t\t\t\tredirect: e.redirect,\n\t\t\t\t\t\t};\n\t\t\t\t\t}\n\t\t\t\t\tthrow e;\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\n\t\treturn { state };\n\t}\n\n\tprotected createRedirectionLayer(redirect: string): CreateLayersResult {\n\t\treturn {\n\t\t\tredirect,\n\t\t};\n\t}\n\n\tprotected getErrorHandler(route: PageRoute): ErrorHandler | undefined {\n\t\tif (route.errorHandler) return route.errorHandler;\n\t\tlet parent = route.parent;\n\t\twhile (parent) {\n\t\t\tif (parent.errorHandler) return parent.errorHandler;\n\t\t\tparent = parent.parent;\n\t\t}\n\t}\n\n\tprotected async createElement(\n\t\tpage: PageRoute,\n\t\tprops: Record<string, any>,\n\t): Promise<ReactNode> {\n\t\tif (page.lazy && page.component) {\n\t\t\tthis.log.warn(\n\t\t\t\t`Page ${page.name} has both lazy and component options, lazy will be used`,\n\t\t\t);\n\t\t}\n\n\t\tif (page.lazy) {\n\t\t\tconst component = await page.lazy(); // load component\n\t\t\treturn createElement(component.default, props);\n\t\t}\n\n\t\tif (page.component) {\n\t\t\treturn createElement(page.component, props);\n\t\t}\n\n\t\treturn undefined;\n\t}\n\n\tpublic renderError(error: Error): ReactNode {\n\t\treturn createElement(ErrorViewer, { error, alepha: this.alepha });\n\t}\n\n\tpublic renderEmptyView(): ReactNode {\n\t\treturn createElement(NestedView, {});\n\t}\n\n\tpublic href(\n\t\tpage: { options: { name?: string } },\n\t\tparams: Record<string, any> = {},\n\t): string {\n\t\tconst found = this.pages.find((it) => it.name === page.options.name);\n\t\tif (!found) {\n\t\t\tthrow new Error(`Page ${page.options.name} not found`);\n\t\t}\n\n\t\tlet url = found.path ?? \"\";\n\t\tlet parent = found.parent;\n\t\twhile (parent) {\n\t\t\turl = `${parent.path ?? \"\"}/${url}`;\n\t\t\tparent = parent.parent;\n\t\t}\n\n\t\turl = this.compile(url, params);\n\n\t\treturn url.replace(/\\/\\/+/g, \"/\") || \"/\";\n\t}\n\n\tpublic compile(path: string, params: Record<string, string> = {}) {\n\t\tfor (const [key, value] of Object.entries(params)) {\n\t\t\tpath = path.replace(`:${key}`, value);\n\t\t}\n\t\treturn path;\n\t}\n\n\tprotected renderView(\n\t\tindex: number,\n\t\tpath: string,\n\t\tview: ReactNode | undefined,\n\t\tpage: PageRoute,\n\t): ReactNode {\n\t\tview ??= this.renderEmptyView();\n\n\t\tconst element = page.client\n\t\t\t? createElement(\n\t\t\t\t\tClientOnly,\n\t\t\t\t\ttypeof page.client === \"object\" ? page.client : {},\n\t\t\t\t\tview,\n\t\t\t\t)\n\t\t\t: view;\n\n\t\treturn createElement(\n\t\t\tRouterLayerContext.Provider,\n\t\t\t{\n\t\t\t\tvalue: {\n\t\t\t\t\tindex,\n\t\t\t\t\tpath,\n\t\t\t\t},\n\t\t\t},\n\t\t\telement,\n\t\t);\n\t}\n\n\tprotected readonly configure = $hook({\n\t\ton: \"configure\",\n\t\thandler: () => {\n\t\t\tlet hasNotFoundHandler = false;\n\t\t\tconst pages = this.alepha.descriptors($page);\n\n\t\t\tconst hasParent = (it: PageDescriptor) => {\n\t\t\t\tif (it.options.parent) {\n\t\t\t\t\treturn true;\n\t\t\t\t}\n\n\t\t\t\tfor (const page of pages) {\n\t\t\t\t\tconst children = page.options.children\n\t\t\t\t\t\t? Array.isArray(page.options.children)\n\t\t\t\t\t\t\t? page.options.children\n\t\t\t\t\t\t\t: page.options.children()\n\t\t\t\t\t\t: [];\n\t\t\t\t\tif (children.includes(it)) {\n\t\t\t\t\t\treturn true;\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t};\n\n\t\t\tfor (const page of pages) {\n\t\t\t\tif (page.options.path === \"/*\") {\n\t\t\t\t\thasNotFoundHandler = true;\n\t\t\t\t}\n\n\t\t\t\t// skip children, we only want root pages\n\t\t\t\tif (hasParent(page)) {\n\t\t\t\t\tcontinue;\n\t\t\t\t}\n\n\t\t\t\tthis.add(this.map(pages, page));\n\t\t\t}\n\n\t\t\tif (!hasNotFoundHandler && pages.length > 0) {\n\t\t\t\t// add a default 404 page if not already defined\n\t\t\t\tthis.add({\n\t\t\t\t\tpath: \"/*\",\n\t\t\t\t\tname: \"notFound\",\n\t\t\t\t\tcache: true,\n\t\t\t\t\tcomponent: NotFoundPage,\n\t\t\t\t\tonServerResponse: ({ reply }) => {\n\t\t\t\t\t\treply.status = 404;\n\t\t\t\t\t},\n\t\t\t\t});\n\t\t\t}\n\t\t},\n\t});\n\n\tprotected map(\n\t\tpages: Array<PageDescriptor>,\n\t\ttarget: PageDescriptor,\n\t): PageRouteEntry {\n\t\tconst children = target.options.children\n\t\t\t? Array.isArray(target.options.children)\n\t\t\t\t? target.options.children\n\t\t\t\t: target.options.children()\n\t\t\t: [];\n\n\t\tconst getChildrenFromParent = (it: PageDescriptor): PageDescriptor[] => {\n\t\t\tconst children = [];\n\t\t\tfor (const page of pages) {\n\t\t\t\tif (page.options.parent === it) {\n\t\t\t\t\tchildren.push(page);\n\t\t\t\t}\n\t\t\t}\n\t\t\treturn children;\n\t\t};\n\n\t\tchildren.push(...getChildrenFromParent(target));\n\n\t\treturn {\n\t\t\t...target.options,\n\t\t\tname: target.name,\n\t\t\tparent: undefined,\n\t\t\tchildren: children.map((it) => this.map(pages, it)),\n\t\t} as PageRoute;\n\t}\n\n\tpublic add(entry: PageRouteEntry) {\n\t\tif (this.alepha.isReady()) {\n\t\t\tthrow new Error(\"Router is already initialized\");\n\t\t}\n\n\t\tentry.name ??= this.nextId();\n\t\tconst page = entry as PageRoute;\n\n\t\tpage.match = this.createMatch(page);\n\t\tthis.pages.push(page);\n\n\t\tif (page.children) {\n\t\t\tfor (const child of page.children) {\n\t\t\t\t(child as PageRoute).parent = page;\n\t\t\t\tthis.add(child);\n\t\t\t}\n\t\t}\n\t}\n\n\tprotected createMatch(page: PageRoute): string {\n\t\tlet url = page.path ?? \"/\";\n\t\tlet target = page.parent;\n\t\twhile (target) {\n\t\t\turl = `${target.path ?? \"\"}/${url}`;\n\t\t\ttarget = target.parent;\n\t\t}\n\n\t\tlet path = url.replace(/\\/\\/+/g, \"/\");\n\n\t\tif (path.endsWith(\"/\") && path !== \"/\") {\n\t\t\t// remove trailing slash\n\t\t\tpath = path.slice(0, -1);\n\t\t}\n\n\t\treturn path;\n\t}\n\n\tprotected _next = 0;\n\n\tprotected nextId(): string {\n\t\tthis._next += 1;\n\t\treturn `P${this._next}`;\n\t}\n}\n\nexport const isPageRoute = (it: any): it is PageRoute => {\n\treturn (\n\t\tit &&\n\t\ttypeof it === \"object\" &&\n\t\ttypeof it.path === \"string\" &&\n\t\ttypeof it.page === \"object\"\n\t);\n};\n\nexport interface PageRouteEntry\n\textends Omit<PageDescriptorOptions, \"children\" | \"parent\"> {\n\tchildren?: PageRouteEntry[];\n}\n\nexport interface PageRoute extends PageRouteEntry {\n\ttype: \"page\";\n\tname: string;\n\tparent?: PageRoute;\n\tmatch: string;\n}\n\nexport interface Layer {\n\tconfig?: {\n\t\tquery?: Record<string, any>;\n\t\tparams?: Record<string, any>;\n\t\t// stack of resolved props\n\t\tcontext?: Record<string, any>;\n\t};\n\n\tname: string;\n\tprops?: Record<string, any>;\n\terror?: Error;\n\tpart?: string;\n\telement: ReactNode;\n\tindex: number;\n\tpath: string;\n\troute?: PageRoute;\n\tcache?: boolean;\n}\n\nexport type PreviousLayerData = Omit<Layer, \"element\" | \"index\" | \"path\">;\n\nexport interface AnchorProps {\n\thref: string;\n\tonClick: (ev?: any) => any;\n}\n\nexport interface ReactRouterState {\n\t/**\n\t * Stack of layers for the current page.\n\t */\n\tlayers: Array<Layer>;\n\n\t/**\n\t * URL of the current page.\n\t */\n\turl: URL;\n\n\t/**\n\t * Error handler for the current page.\n\t */\n\tonError: ErrorHandler;\n\n\t/**\n\t * Params extracted from the URL for the current page.\n\t */\n\tparams: Record<string, any>;\n\n\t/**\n\t * Query parameters extracted from the URL for the current page.\n\t */\n\tquery: Record<string, string>;\n\n\t/**\n\t * Optional meta information associated with the current page.\n\t */\n\tmeta: Record<string, any>;\n}\n\nexport interface RouterStackItem {\n\troute: PageRoute;\n\tconfig?: Record<string, any>;\n\tprops?: Record<string, any>;\n\terror?: Error;\n\tcache?: boolean;\n}\n\nexport interface TransitionOptions {\n\tprevious?: PreviousLayerData[];\n}\n\nexport interface CreateLayersResult {\n\tredirect?: string;\n\tstate?: ReactRouterState;\n}\n","import { existsSync } from \"node:fs\";\nimport { join } from \"node:path\";\nimport {\n\t$env,\n\t$hook,\n\t$inject,\n\tAlepha,\n\tAlephaError,\n\ttype Static,\n\tt,\n} from \"@alepha/core\";\nimport { $logger } from \"@alepha/logger\";\nimport {\n\ttype ServerHandler,\n\tServerProvider,\n\tServerRouterProvider,\n\tServerTimingProvider,\n} from \"@alepha/server\";\nimport { ServerLinksProvider } from \"@alepha/server-links\";\nimport { ServerStaticProvider } from \"@alepha/server-static\";\nimport { renderToString } from \"react-dom/server\";\nimport {\n\t$page,\n\ttype PageDescriptorRenderOptions,\n\ttype PageDescriptorRenderResult,\n} from \"../descriptors/$page.ts\";\nimport { Redirection } from \"../errors/Redirection.ts\";\nimport type { ReactHydrationState } from \"./ReactBrowserProvider.ts\";\nimport {\n\ttype PageRoute,\n\tReactPageProvider,\n\ttype ReactRouterState,\n} from \"./ReactPageProvider.ts\";\n\nconst envSchema = t.object({\n\tREACT_SERVER_DIST: t.text({ default: \"public\" }),\n\tREACT_SERVER_PREFIX: t.text({ default: \"\" }),\n\tREACT_SSR_ENABLED: t.optional(t.boolean()),\n\tREACT_ROOT_ID: t.text({ default: \"root\" }),\n\tREACT_SERVER_TEMPLATE: t.optional(\n\t\tt.text({\n\t\t\tsize: \"rich\",\n\t\t}),\n\t),\n});\n\ndeclare module \"@alepha/core\" {\n\tinterface Env extends Partial<Static<typeof envSchema>> {}\n\tinterface State {\n\t\t\"react.server.ssr\"?: boolean;\n\t}\n}\n\nexport class ReactServerProvider {\n\tprotected readonly log = $logger();\n\tprotected readonly alepha = $inject(Alepha);\n\tprotected readonly pageApi = $inject(ReactPageProvider);\n\tprotected readonly serverProvider = $inject(ServerProvider);\n\tprotected readonly serverStaticProvider = $inject(ServerStaticProvider);\n\tprotected readonly serverRouterProvider = $inject(ServerRouterProvider);\n\tprotected readonly serverTimingProvider = $inject(ServerTimingProvider);\n\tprotected readonly env = $env(envSchema);\n\tprotected readonly ROOT_DIV_REGEX = new RegExp(\n\t\t`<div([^>]*)\\\\s+id=[\"']${this.env.REACT_ROOT_ID}[\"']([^>]*)>(.*?)<\\\\/div>`,\n\t\t\"is\",\n\t);\n\tprotected preprocessedTemplate: PreprocessedTemplate | null = null;\n\n\tpublic readonly onConfigure = $hook({\n\t\ton: \"configure\",\n\t\thandler: async () => {\n\t\t\tconst pages = this.alepha.descriptors($page);\n\n\t\t\tconst ssrEnabled =\n\t\t\t\tpages.length > 0 && this.env.REACT_SSR_ENABLED !== false;\n\n\t\t\tthis.alepha.state.set(\"react.server.ssr\", ssrEnabled);\n\n\t\t\tfor (const page of pages) {\n\t\t\t\tpage.render = this.createRenderFunction(page.name);\n\t\t\t\tpage.fetch = async (options) => {\n\t\t\t\t\tconst response = await fetch(\n\t\t\t\t\t\t`${this.serverProvider.hostname}/${page.pathname(options)}`,\n\t\t\t\t\t);\n\t\t\t\t\tconst html = await response.text();\n\t\t\t\t\tif (options?.html) return { html, response };\n\t\t\t\t\t// take only text inside the root div\n\t\t\t\t\tconst match = html.match(this.ROOT_DIV_REGEX);\n\t\t\t\t\tif (match) {\n\t\t\t\t\t\treturn { html: match[3], response };\n\t\t\t\t\t}\n\t\t\t\t\tthrow new AlephaError(\"Invalid HTML response\");\n\t\t\t\t};\n\t\t\t}\n\n\t\t\t// development mode\n\t\t\tif (this.alepha.isServerless() === \"vite\") {\n\t\t\t\tawait this.configureVite(ssrEnabled);\n\t\t\t\treturn;\n\t\t\t}\n\n\t\t\t// production mode\n\t\t\tlet root = \"\";\n\n\t\t\t// non-serverless mode only -> serve static files\n\t\t\tif (!this.alepha.isServerless()) {\n\t\t\t\troot = this.getPublicDirectory();\n\t\t\t\tif (!root) {\n\t\t\t\t\tthis.log.warn(\n\t\t\t\t\t\t\"Missing static files, static file server will be disabled\",\n\t\t\t\t\t);\n\t\t\t\t} else {\n\t\t\t\t\tthis.log.debug(`Using static files from: ${root}`);\n\t\t\t\t\tawait this.configureStaticServer(root);\n\t\t\t\t}\n\t\t\t}\n\n\t\t\tif (ssrEnabled) {\n\t\t\t\tawait this.registerPages(async () => this.template);\n\t\t\t\tthis.log.info(\"SSR OK\");\n\t\t\t\treturn;\n\t\t\t}\n\n\t\t\t// no SSR enabled, serve index.html for all unmatched routes\n\t\t\tthis.log.info(\"SSR is disabled, use History API fallback\");\n\t\t\tthis.serverRouterProvider.createRoute({\n\t\t\t\tpath: \"*\",\n\t\t\t\thandler: async ({ url, reply }) => {\n\t\t\t\t\tif (url.pathname.includes(\".\")) {\n\t\t\t\t\t\t// If the request is for a file (e.g., /style.css), do not fallback\n\t\t\t\t\t\treply.headers[\"content-type\"] = \"text/plain\";\n\t\t\t\t\t\treply.body = \"Not Found\";\n\t\t\t\t\t\treply.status = 404;\n\t\t\t\t\t\treturn;\n\t\t\t\t\t}\n\n\t\t\t\t\treply.headers[\"content-type\"] = \"text/html\";\n\n\t\t\t\t\t// serve index.html for all unmatched routes\n\t\t\t\t\treturn this.template;\n\t\t\t\t},\n\t\t\t});\n\t\t},\n\t});\n\n\tpublic get template() {\n\t\treturn (\n\t\t\tthis.alepha.env.REACT_SERVER_TEMPLATE ??\n\t\t\t\"<!DOCTYPE html><html lang='en'><head></head><body></body></html>\"\n\t\t);\n\t}\n\n\tprotected async registerPages(templateLoader: TemplateLoader) {\n\t\t// Preprocess template once\n\t\tconst template = await templateLoader();\n\t\tif (template) {\n\t\t\tthis.preprocessedTemplate = this.preprocessTemplate(template);\n\t\t}\n\n\t\tfor (const page of this.pageApi.getPages()) {\n\t\t\tif (page.children?.length) {\n\t\t\t\tcontinue;\n\t\t\t}\n\n\t\t\tthis.log.debug(`+ ${page.match} -> ${page.name}`);\n\n\t\t\tthis.serverRouterProvider.createRoute({\n\t\t\t\t...page,\n\t\t\t\tschema: undefined, // schema is handled by the page descriptor provider for now (shared by browser and server)\n\t\t\t\tmethod: \"GET\",\n\t\t\t\tpath: page.match,\n\t\t\t\thandler: this.createHandler(page, templateLoader),\n\t\t\t});\n\t\t}\n\t}\n\n\tprotected getPublicDirectory(): string {\n\t\tconst maybe = [\n\t\t\tjoin(process.cwd(), `dist/${this.env.REACT_SERVER_DIST}`),\n\t\t\tjoin(process.cwd(), this.env.REACT_SERVER_DIST),\n\t\t];\n\n\t\tfor (const it of maybe) {\n\t\t\tif (existsSync(it)) {\n\t\t\t\treturn it;\n\t\t\t}\n\t\t}\n\n\t\treturn \"\";\n\t}\n\n\tprotected async configureStaticServer(root: string) {\n\t\tawait this.serverStaticProvider.createStaticServer({\n\t\t\troot,\n\t\t\tpath: this.env.REACT_SERVER_PREFIX,\n\t\t});\n\t}\n\n\tprotected async configureVite(ssrEnabled: boolean) {\n\t\tif (!ssrEnabled) {\n\t\t\t// do nothing, vite will handle everything for us\n\t\t\treturn;\n\t\t}\n\n\t\tthis.log.info(\"SSR (vite) OK\");\n\n\t\tconst url = `http://${process.env.SERVER_HOST}:${process.env.SERVER_PORT}`;\n\n\t\tawait this.registerPages(() =>\n\t\t\tfetch(`${url}/index.html`)\n\t\t\t\t.then((it) => it.text())\n\t\t\t\t.catch(() => undefined),\n\t\t);\n\t}\n\n\t/**\n\t * For testing purposes, creates a render function that can be used.\n\t */\n\tprotected createRenderFunction(name: string, withIndex = false) {\n\t\treturn async (\n\t\t\toptions: PageDescriptorRenderOptions = {},\n\t\t): Promise<PageDescriptorRenderResult> => {\n\t\t\tconst page = this.pageApi.page(name);\n\t\t\tconst url = new URL(this.pageApi.url(name, options));\n\n\t\t\tconst entry: Partial<ReactRouterState> = {\n\t\t\t\turl,\n\t\t\t\tparams: options.params ?? {},\n\t\t\t\tquery: options.query ?? {},\n\t\t\t\tonError: () => null,\n\t\t\t\tlayers: [],\n\t\t\t\tmeta: {},\n\t\t\t};\n\n\t\t\tconst state = entry as ReactRouterState;\n\n\t\t\tthis.log.trace(\"Rendering\", {\n\t\t\t\turl,\n\t\t\t});\n\n\t\t\tawait this.alepha.events.emit(\"react:server:render:begin\", {\n\t\t\t\tstate,\n\t\t\t});\n\n\t\t\tconst { redirect } = await this.pageApi.createLayers(\n\t\t\t\tpage,\n\t\t\t\tstate as ReactRouterState,\n\t\t\t);\n\n\t\t\tif (redirect) {\n\t\t\t\treturn { state, html: \"\", redirect };\n\t\t\t}\n\n\t\t\tif (!withIndex && !options.html) {\n\t\t\t\tthis.alepha.state.set(\"react.router.state\", state);\n\n\t\t\t\treturn {\n\t\t\t\t\tstate,\n\t\t\t\t\thtml: renderToString(this.pageApi.root(state)),\n\t\t\t\t};\n\t\t\t}\n\n\t\t\tconst template = this.template ?? \"\";\n\t\t\tconst html = this.renderToHtml(template, state, options.hydration);\n\n\t\t\tif (html instanceof Redirection) {\n\t\t\t\treturn { state, html: \"\", redirect };\n\t\t\t}\n\n\t\t\tconst result = {\n\t\t\t\tstate,\n\t\t\t\thtml,\n\t\t\t};\n\n\t\t\tawait this.alepha.events.emit(\"react:server:render:end\", result);\n\n\t\t\treturn result;\n\t\t};\n\t}\n\n\tprotected createHandler(\n\t\troute: PageRoute,\n\t\ttemplateLoader: TemplateLoader,\n\t): ServerHandler {\n\t\treturn async (serverRequest) => {\n\t\t\tconst { url, reply, query, params } = serverRequest;\n\t\t\tconst template = await templateLoader();\n\t\t\tif (!template) {\n\t\t\t\tthrow new Error(\"Template not found\");\n\t\t\t}\n\n\t\t\tthis.log.trace(\"Rendering page\", {\n\t\t\t\tname: route.name,\n\t\t\t});\n\n\t\t\tconst entry: Partial<ReactRouterState> = {\n\t\t\t\turl,\n\t\t\t\tparams,\n\t\t\t\tquery,\n\t\t\t\tonError: () => null,\n\t\t\t\tlayers: [],\n\t\t\t};\n\n\t\t\tconst state = entry as ReactRouterState;\n\n\t\t\tif (this.alepha.has(ServerLinksProvider)) {\n\t\t\t\tthis.alepha.state.set(\n\t\t\t\t\t\"api\",\n\t\t\t\t\tawait this.alepha.inject(ServerLinksProvider).getUserApiLinks({\n\t\t\t\t\t\tuser: (serverRequest as any).user, // TODO: fix type\n\t\t\t\t\t\tauthorization: serverRequest.headers.authorization,\n\t\t\t\t\t}),\n\t\t\t\t);\n\t\t\t}\n\n\t\t\tlet target: PageRoute | undefined = route; // TODO: move to PageDescriptorProvider\n\t\t\twhile (target) {\n\t\t\t\tif (route.can && !route.can()) {\n\t\t\t\t\t// if the page is not accessible, return 403\n\t\t\t\t\treply.status = 403;\n\t\t\t\t\treply.headers[\"content-type\"] = \"text/plain\";\n\t\t\t\t\treturn \"Forbidden\";\n\t\t\t\t}\n\t\t\t\ttarget = target.parent;\n\t\t\t}\n\n\t\t\t// TODO: SSR strategies\n\t\t\t// - only when googlebot\n\t\t\t// - only child pages\n\t\t\t// if (page.client) {\n\t\t\t// \t// if the page is a client-only page, return 404\n\t\t\t// \treply.status = 200;\n\t\t\t// \treply.headers[\"content-type\"] = \"text/html\";\n\t\t\t// \treply.body = template;\n\t\t\t// \treturn;\n\t\t\t// }\n\n\t\t\tawait this.alepha.events.emit(\"react:server:render:begin\", {\n\t\t\t\trequest: serverRequest,\n\t\t\t\tstate,\n\t\t\t});\n\n\t\t\tthis.serverTimingProvider.beginTiming(\"createLayers\");\n\n\t\t\tconst { redirect } = await this.pageApi.createLayers(route, state);\n\n\t\t\tthis.serverTimingProvider.endTiming(\"createLayers\");\n\n\t\t\tif (redirect) {\n\t\t\t\treturn reply.redirect(redirect);\n\t\t\t}\n\n\t\t\treply.headers[\"content-type\"] = \"text/html\";\n\n\t\t\t// by default, disable caching for SSR responses\n\t\t\t// some plugins may override this\n\t\t\treply.headers[\"cache-control\"] =\n\t\t\t\t\"no-store, no-cache, must-revalidate, proxy-revalidate\";\n\t\t\treply.headers.pragma = \"no-cache\";\n\t\t\treply.headers.expires = \"0\";\n\n\t\t\tconst html = this.renderToHtml(template, state);\n\t\t\tif (html instanceof Redirection) {\n\t\t\t\treply.redirect(\n\t\t\t\t\ttypeof html.redirect === \"string\"\n\t\t\t\t\t\t? html.redirect\n\t\t\t\t\t\t: this.pageApi.href(html.redirect),\n\t\t\t\t);\n\t\t\t\treturn;\n\t\t\t}\n\n\t\t\tconst event = {\n\t\t\t\trequest: serverRequest,\n\t\t\t\tstate,\n\t\t\t\thtml,\n\t\t\t};\n\n\t\t\tawait this.alepha.events.emit(\"react:server:render:end\", event);\n\n\t\t\troute.onServerResponse?.(serverRequest);\n\n\t\t\tthis.log.trace(\"Page rendered\", {\n\t\t\t\tname: route.name,\n\t\t\t});\n\n\t\t\treturn event.html;\n\t\t};\n\t}\n\n\tpublic renderToHtml(\n\t\ttemplate: string,\n\t\tstate: ReactRouterState,\n\t\thydration = true,\n\t): string | Redirection {\n\t\tconst element = this.pageApi.root(state);\n\n\t\t// attach react router state to the http request context\n\t\tthis.alepha.state.set(\"react.router.state\", state);\n\n\t\tthis.serverTimingProvider.beginTiming(\"renderToString\");\n\t\tlet app = \"\";\n\t\ttry {\n\t\t\tapp = renderToString(element);\n\t\t} catch (error) {\n\t\t\tthis.log.error(\n\t\t\t\t\"renderToString has failed, fallback to error handler\",\n\t\t\t\terror,\n\t\t\t);\n\t\t\tconst element = state.onError(error as Error, state);\n\t\t\tif (element instanceof Redirection) {\n\t\t\t\t// if the error is a redirection, return the redirection URL\n\t\t\t\treturn element;\n\t\t\t}\n\n\t\t\tapp = renderToString(element);\n\t\t\tthis.log.debug(\"Error handled successfully with fallback\");\n\t\t}\n\t\tthis.serverTimingProvider.endTiming(\"renderToString\");\n\n\t\tconst response = {\n\t\t\thtml: template,\n\t\t};\n\n\t\tif (hydration) {\n\t\t\tconst { request, context, ...store } =\n\t\t\t\tthis.alepha.context.als?.getStore() ?? {}; /// TODO: als must be protected, find a way to iterate on alepha.state\n\n\t\t\tconst hydrationData: ReactHydrationState = {\n\t\t\t\t...store,\n\t\t\t\t// map react.router.state to the hydration state\n\t\t\t\t\"react.router.state\": undefined,\n\t\t\t\tlayers: state.layers.map((it) => ({\n\t\t\t\t\t...it,\n\t\t\t\t\terror: it.error\n\t\t\t\t\t\t? {\n\t\t\t\t\t\t\t\t...it.error,\n\t\t\t\t\t\t\t\tname: it.error.name,\n\t\t\t\t\t\t\t\tmessage: it.error.message,\n\t\t\t\t\t\t\t\tstack: !this.alepha.isProduction() ? it.error.stack : undefined,\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t: undefined,\n\t\t\t\t\tindex: undefined,\n\t\t\t\t\tpath: undefined,\n\t\t\t\t\telement: undefined,\n\t\t\t\t\troute: undefined,\n\t\t\t\t})),\n\t\t\t};\n\n\t\t\t// create hydration data\n\t\t\tconst script = `<script>window.__ssr=${JSON.stringify(hydrationData)}</script>`;\n\n\t\t\t// inject app into template\n\t\t\tthis.fillTemplate(response, app, script);\n\t\t}\n\n\t\treturn response.html;\n\t}\n\n\tprotected preprocessTemplate(template: string): PreprocessedTemplate {\n\t\t// Find the body close tag for script injection\n\t\tconst bodyCloseMatch = template.match(/<\\/body>/i);\n\t\tconst bodyCloseIndex = bodyCloseMatch?.index ?? template.length;\n\n\t\tconst beforeScript = template.substring(0, bodyCloseIndex);\n\t\tconst afterScript = template.substring(bodyCloseIndex);\n\n\t\t// Check if there's an existing root div\n\t\tconst rootDivMatch = beforeScript.match(this.ROOT_DIV_REGEX);\n\n\t\tif (rootDivMatch) {\n\t\t\t// Split around the existing root div content\n\t\t\tconst beforeDiv = beforeScript.substring(0, rootDivMatch.index!);\n\t\t\tconst afterDivStart = rootDivMatch.index! + rootDivMatch[0].length;\n\t\t\tconst afterDiv = beforeScript.substring(afterDivStart);\n\n\t\t\tconst beforeApp = `${beforeDiv}<div${rootDivMatch[1]} id=\"${this.env.REACT_ROOT_ID}\"${rootDivMatch[2]}>`;\n\t\t\tconst afterApp = `</div>${afterDiv}`;\n\n\t\t\treturn { beforeApp, afterApp, beforeScript: \"\", afterScript };\n\t\t}\n\n\t\t// No existing root div, find body tag to inject new div\n\t\tconst bodyMatch = beforeScript.match(/<body([^>]*)>/i);\n\t\tif (bodyMatch) {\n\t\t\tconst beforeBody = beforeScript.substring(\n\t\t\t\t0,\n\t\t\t\tbodyMatch.index! + bodyMatch[0].length,\n\t\t\t);\n\t\t\tconst afterBody = beforeScript.substring(\n\t\t\t\tbodyMatch.index! + bodyMatch[0].length,\n\t\t\t);\n\n\t\t\tconst beforeApp = `${beforeBody}<div id=\"${this.env.REACT_ROOT_ID}\">`;\n\t\t\tconst afterApp = `</div>${afterBody}`;\n\n\t\t\treturn { beforeApp, afterApp, beforeScript: \"\", afterScript };\n\t\t}\n\n\t\t// Fallback: no body tag found, just wrap everything\n\t\treturn {\n\t\t\tbeforeApp: `<div id=\"${this.env.REACT_ROOT_ID}\">`,\n\t\t\tafterApp: `</div>`,\n\t\t\tbeforeScript,\n\t\t\tafterScript,\n\t\t};\n\t}\n\n\tprotected fillTemplate(\n\t\tresponse: { html: string },\n\t\tapp: string,\n\t\tscript: string,\n\t) {\n\t\tif (!this.preprocessedTemplate) {\n\t\t\t// Fallback to old logic if preprocessing failed\n\t\t\tthis.preprocessedTemplate = this.preprocessTemplate(response.html);\n\t\t}\n\n\t\t// Pure concatenation - no regex replacements needed\n\t\tresponse.html =\n\t\t\tthis.preprocessedTemplate.beforeApp +\n\t\t\tapp +\n\t\t\tthis.preprocessedTemplate.afterApp +\n\t\t\tscript +\n\t\t\tthis.preprocessedTemplate.afterScript;\n\t}\n}\n\ntype TemplateLoader = () => Promise<string | undefined>;\n\ninterface PreprocessedTemplate {\n\tbeforeApp: string;\n\tafterApp: string;\n\tbeforeScript: string;\n\tafterScript: string;\n}\n","import { $hook, $inject, Alepha } from \"@alepha/core\";\nimport { $logger } from \"@alepha/logger\";\nimport { type Route, RouterProvider } from \"@alepha/router\";\nimport { createElement, type ReactNode } from \"react\";\nimport NotFoundPage from \"../components/NotFound.tsx\";\nimport {\n\tisPageRoute,\n\ttype PageRoute,\n\ttype PageRouteEntry,\n\ttype PreviousLayerData,\n\tReactPageProvider,\n\ttype ReactRouterState,\n} from \"./ReactPageProvider.ts\";\n\nexport interface BrowserRoute extends Route {\n\tpage: PageRoute;\n}\n\nexport class ReactBrowserRouterProvider extends RouterProvider<BrowserRoute> {\n\tprotected readonly log = $logger();\n\tprotected readonly alepha = $inject(Alepha);\n\tprotected readonly pageApi = $inject(ReactPageProvider);\n\n\tpublic add(entry: PageRouteEntry) {\n\t\tthis.pageApi.add(entry);\n\t}\n\n\tprotected readonly configure = $hook({\n\t\ton: \"configure\",\n\t\thandler: async () => {\n\t\t\tfor (const page of this.pageApi.getPages()) {\n\t\t\t\t// mount only if a view is provided\n\t\t\t\tif (page.component || page.lazy) {\n\t\t\t\t\tthis.push({\n\t\t\t\t\t\tpath: page.match,\n\t\t\t\t\t\tpage,\n\t\t\t\t\t});\n\t\t\t\t}\n\t\t\t}\n\t\t},\n\t});\n\n\tpublic async transition(\n\t\turl: URL,\n\t\tprevious: PreviousLayerData[] = [],\n\t\tmeta = {},\n\t): Promise<string | void> {\n\t\tconst { pathname, search } = url;\n\n\t\tconst entry: Partial<ReactRouterState> = {\n\t\t\turl,\n\t\t\tquery: {},\n\t\t\tparams: {},\n\t\t\tlayers: [],\n\t\t\tonError: () => null,\n\t\t\tmeta,\n\t\t};\n\n\t\tconst state = entry as ReactRouterState;\n\n\t\tawait this.alepha.events.emit(\"react:transition:begin\", {\n\t\t\tprevious: this.alepha.state.get(\"react.router.state\")!,\n\t\t\tstate,\n\t\t});\n\n\t\ttry {\n\t\t\tconst { route, params } = this.match(pathname);\n\n\t\t\tconst query: Record<string, string> = {};\n\t\t\tif (search) {\n\t\t\t\tfor (const [key, value] of new URLSearchParams(search).entries()) {\n\t\t\t\t\tquery[key] = String(value);\n\t\t\t\t}\n\t\t\t}\n\n\t\t\tstate.query = query;\n\t\t\tstate.params = params ?? {};\n\n\t\t\tif (isPageRoute(route)) {\n\t\t\t\tconst { redirect } = await this.pageApi.createLayers(\n\t\t\t\t\troute.page,\n\t\t\t\t\tstate,\n\t\t\t\t\tprevious,\n\t\t\t\t);\n\t\t\t\tif (redirect) {\n\t\t\t\t\treturn redirect;\n\t\t\t\t}\n\t\t\t}\n\n\t\t\tif (state.layers.length === 0) {\n\t\t\t\tstate.layers.push({\n\t\t\t\t\tname: \"not-found\",\n\t\t\t\t\telement: createElement(NotFoundPage),\n\t\t\t\t\tindex: 0,\n\t\t\t\t\tpath: \"/\",\n\t\t\t\t});\n\t\t\t}\n\n\t\t\tawait this.alepha.events.emit(\"react:transition:success\", { state });\n\t\t} catch (e) {\n\t\t\tthis.log.error(\"Transition has failed\", e);\n\t\t\tstate.layers = [\n\t\t\t\t{\n\t\t\t\t\tname: \"error\",\n\t\t\t\t\telement: this.pageApi.renderError(e as Error),\n\t\t\t\t\tindex: 0,\n\t\t\t\t\tpath: \"/\",\n\t\t\t\t},\n\t\t\t];\n\n\t\t\tawait this.alepha.events.emit(\"react:transition:error\", {\n\t\t\t\terror: e as Error,\n\t\t\t\tstate,\n\t\t\t});\n\t\t}\n\n\t\t// [feature]: local hook for leaving a page\n\t\tif (previous) {\n\t\t\tfor (let i = 0; i < previous.length; i++) {\n\t\t\t\tconst layer = previous[i];\n\t\t\t\tif (state.layers[i]?.name !== layer.name) {\n\t\t\t\t\tthis.pageApi.page(layer.name)?.onLeave?.();\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\n\t\tthis.alepha.state.set(\"react.router.state\", state);\n\n\t\tawait this.alepha.events.emit(\"react:transition:end\", {\n\t\t\tstate,\n\t\t});\n\t}\n\n\tpublic root(state: ReactRouterState): ReactNode {\n\t\treturn this.pageApi.root(state);\n\t}\n}\n","import {\n\t$env,\n\t$hook,\n\t$inject,\n\tAlepha,\n\ttype State,\n\ttype Static,\n\tt,\n} from \"@alepha/core\";\nimport { DateTimeProvider } from \"@alepha/datetime\";\nimport { $logger } from \"@alepha/logger\";\nimport { LinkProvider } from \"@alepha/server-links\";\nimport { ReactBrowserRouterProvider } from \"./ReactBrowserRouterProvider.ts\";\nimport type {\n\tPreviousLayerData,\n\tReactRouterState,\n\tTransitionOptions,\n} from \"./ReactPageProvider.ts\";\n\nconst envSchema = t.object({\n\tREACT_ROOT_ID: t.text({ default: \"root\" }),\n});\n\ndeclare module \"@alepha/core\" {\n\tinterface Env extends Partial<Static<typeof envSchema>> {}\n}\n\nexport interface ReactBrowserRendererOptions {\n\tscrollRestoration?: \"top\" | \"manual\";\n}\n\nexport class ReactBrowserProvider {\n\tprotected readonly env = $env(envSchema);\n\tprotected readonly log = $logger();\n\tprotected readonly client = $inject(LinkProvider);\n\tprotected readonly alepha = $inject(Alepha);\n\tprotected readonly router = $inject(ReactBrowserRouterProvider);\n\tprotected readonly dateTimeProvider = $inject(DateTimeProvider);\n\n\tpublic options: ReactBrowserRendererOptions = {\n\t\tscrollRestoration: \"top\",\n\t};\n\n\tprotected getRootElement() {\n\t\tconst root = this.document.getElementById(this.env.REACT_ROOT_ID);\n\t\tif (root) {\n\t\t\treturn root;\n\t\t}\n\n\t\tconst div = this.document.createElement(\"div\");\n\t\tdiv.id = this.env.REACT_ROOT_ID;\n\n\t\tthis.document.body.prepend(div);\n\n\t\treturn div;\n\t}\n\n\tpublic transitioning?: {\n\t\tto: string;\n\t\tfrom?: string;\n\t};\n\n\tpublic get state(): ReactRouterState {\n\t\treturn this.alepha.state.get(\"react.router.state\")!;\n\t}\n\n\t/**\n\t * Accessor for Document DOM API.\n\t */\n\tpublic get document() {\n\t\treturn window.document;\n\t}\n\n\t/**\n\t * Accessor for History DOM API.\n\t */\n\tpublic get history() {\n\t\treturn window.history;\n\t}\n\n\t/**\n\t * Accessor for Location DOM API.\n\t */\n\tpublic get location() {\n\t\treturn window.location;\n\t}\n\n\tpublic get base() {\n\t\tconst base = import.meta.env?.BASE_URL;\n\t\tif (!base || base === \"/\") {\n\t\t\treturn \"\";\n\t\t}\n\n\t\treturn base;\n\t}\n\n\tpublic get url(): string {\n\t\tconst url = this.location.pathname + this.location.search;\n\t\tif (this.base) {\n\t\t\treturn url.replace(this.base, \"\");\n\t\t}\n\t\treturn url;\n\t}\n\n\tpublic pushState(path: string, replace?: boolean) {\n\t\tconst url = this.base + path;\n\n\t\tif (replace) {\n\t\t\tthis.history.replaceState({}, \"\", url);\n\t\t} else {\n\t\t\tthis.history.pushState({}, \"\", url);\n\t\t}\n\t}\n\n\tpublic async invalidate(props?: Record<string, any>) {\n\t\tconst previous: PreviousLayerData[] = [];\n\n\t\tthis.log.trace(\"Invalidating layers\");\n\n\t\tif (props) {\n\t\t\tconst [key] = Object.keys(props);\n\t\t\tconst value = props[key];\n\n\t\t\tfor (const layer of this.state.layers) {\n\t\t\t\tif (layer.props?.[key]) {\n\t\t\t\t\tprevious.push({\n\t\t\t\t\t\t...layer,\n\t\t\t\t\t\tprops: {\n\t\t\t\t\t\t\t...layer.props,\n\t\t\t\t\t\t\t[key]: value,\n\t\t\t\t\t\t},\n\t\t\t\t\t});\n\t\t\t\t\tbreak;\n\t\t\t\t}\n\t\t\t\tprevious.push(layer);\n\t\t\t}\n\t\t}\n\n\t\tawait this.render({ previous });\n\t}\n\n\tpublic async go(url: string, options: RouterGoOptions = {}): Promise<void> {\n\t\tthis.log.trace(`Going to ${url}`, {\n\t\t\turl,\n\t\t\toptions,\n\t\t});\n\n\t\tawait this.render({\n\t\t\turl,\n\t\t\tprevious: options.force ? [] : this.state.layers,\n\t\t\tmeta: options.meta,\n\t\t});\n\n\t\t// when redirecting in browser\n\t\tif (this.state.url.pathname + this.state.url.search !== url) {\n\t\t\tthis.pushState(this.state.url.pathname + this.state.url.search);\n\t\t\treturn;\n\t\t}\n\n\t\tthis.pushState(url, options.replace);\n\t}\n\n\tprotected async render(options: RouterRenderOptions = {}): Promise<void> {\n\t\tconst previous = options.previous ?? this.state.layers;\n\t\tconst url = options.url ?? this.url;\n\t\tconst start = this.dateTimeProvider.now();\n\n\t\tthis.transitioning = {\n\t\t\tto: url,\n\t\t\tfrom: this.state?.url.pathname,\n\t\t};\n\n\t\tthis.log.debug(\"Transitioning...\", {\n\t\t\tto: url,\n\t\t});\n\n\t\tconst redirect = await this.router.transition(\n\t\t\tnew URL(`http://localhost${url}`),\n\t\t\tprevious,\n\t\t\toptions.meta,\n\t\t);\n\n\t\tif (redirect) {\n\t\t\tthis.log.info(\"Redirecting to\", {\n\t\t\t\tredirect,\n\t\t\t});\n\t\t\treturn await this.render({ url: redirect });\n\t\t}\n\n\t\tconst ms = this.dateTimeProvider.now().diff(start);\n\t\tthis.log.info(`Transition OK [${ms}ms]`, this.transitioning);\n\n\t\tthis.transitioning = undefined;\n\t}\n\n\t/**\n\t * Get embedded layers from the server.\n\t */\n\tprotected getHydrationState(): ReactHydrationState | undefined {\n\t\ttry {\n\t\t\tif (\"__ssr\" in window && typeof window.__ssr === \"object\") {\n\t\t\t\treturn window.__ssr as ReactHydrationState;\n\t\t\t}\n\t\t} catch (error) {\n\t\t\tconsole.error(error);\n\t\t}\n\t}\n\n\t// -------------------------------------------------------------------------------------------------------------------\n\n\tprotected readonly onTransitionEnd = $hook({\n\t\ton: \"react:transition:end\",\n\t\thandler: () => {\n\t\t\tif (\n\t\t\t\tthis.options.scrollRestoration === \"top\" &&\n\t\t\t\ttypeof window !== \"undefined\" &&\n\t\t\t\t!this.alepha.isTest()\n\t\t\t) {\n\t\t\t\tthis.log.trace(\"Restoring scroll position to top\");\n\t\t\t\twindow.scrollTo(0, 0);\n\t\t\t}\n\t\t},\n\t});\n\n\tpublic readonly ready = $hook({\n\t\ton: \"ready\",\n\t\thandler: async () => {\n\t\t\tconst hydration = this.getHydrationState();\n\t\t\tconst previous = hydration?.layers ?? [];\n\n\t\t\tif (hydration) {\n\t\t\t\t// low budget, but works for now\n\t\t\t\tfor (const [key, value] of Object.entries(hydration)) {\n\t\t\t\t\tif (key !== \"layers\") {\n\t\t\t\t\t\tthis.alepha.state.set(key as keyof State, value);\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\n\t\t\tawait this.render({ previous });\n\n\t\t\tconst element = this.router.root(this.state);\n\n\t\t\tawait this.alepha.events.emit(\"react:browser:render\", {\n\t\t\t\telement,\n\t\t\t\troot: this.getRootElement(),\n\t\t\t\thydration,\n\t\t\t\tstate: this.state,\n\t\t\t});\n\n\t\t\twindow.addEventListener(\"popstate\", () => {\n\t\t\t\t// when you update silently queryParams or hash, skip rendering\n\t\t\t\t// if you want to force a rendering, use #go()\n\t\t\t\tif (this.base + this.state.url.pathname === this.location.pathname) {\n\t\t\t\t\treturn;\n\t\t\t\t}\n\n\t\t\t\tthis.log.debug(\"Popstate event triggered - rendering new state\", {\n\t\t\t\t\turl: this.location.pathname + this.location.search,\n\t\t\t\t});\n\n\t\t\t\tthis.render();\n\t\t\t});\n\t\t},\n\t});\n}\n\n// ---------------------------------------------------------------------------------------------------------------------\n\nexport interface RouterGoOptions {\n\treplace?: boolean;\n\tmatch?: TransitionOptions;\n\tparams?: Record<string, string>;\n\tquery?: Record<string, string>;\n\tmeta?: Record<string, any>;\n\n\t/**\n\t * Recreate the whole page, ignoring the current state.\n\t */\n\tforce?: boolean;\n}\n\nexport type ReactHydrationState = {\n\tlayers?: Array<PreviousLayerData>;\n} & {\n\t[key: string]: any;\n};\n\nexport interface RouterRenderOptions {\n\turl?: string;\n\tprevious?: PreviousLayerData[];\n\tmeta?: Record<string, any>;\n}\n","import { $inject, Alepha } from \"@alepha/core\";\nimport type { PageDescriptor } from \"../descriptors/$page.ts\";\nimport {\n\tReactBrowserProvider,\n\ttype RouterGoOptions,\n} from \"../providers/ReactBrowserProvider.ts\";\nimport {\n\ttype AnchorProps,\n\tReactPageProvider,\n\ttype ReactRouterState,\n} from \"../providers/ReactPageProvider.ts\";\n\nexport class ReactRouter<T extends object> {\n\tprotected readonly alepha = $inject(Alepha);\n\tprotected readonly pageApi = $inject(ReactPageProvider);\n\n\tpublic get state(): ReactRouterState {\n\t\treturn this.alepha.state.get(\"react.router.state\")!;\n\t}\n\n\tpublic get pages() {\n\t\treturn this.pageApi.getPages();\n\t}\n\n\tpublic get browser(): ReactBrowserProvider | undefined {\n\t\tif (this.alepha.isBrowser()) {\n\t\t\treturn this.alepha.inject(ReactBrowserProvider);\n\t\t}\n\t\t// server-side\n\t\treturn undefined;\n\t}\n\n\tpublic path(\n\t\tname: keyof VirtualRouter<T>,\n\t\tconfig: {\n\t\t\tparams?: Record<string, any>;\n\t\t\tquery?: Record<string, any>;\n\t\t} = {},\n\t): string {\n\t\treturn this.pageApi.pathname(name as string, {\n\t\t\tparams: {\n\t\t\t\t...this.state.params,\n\t\t\t\t...config.params,\n\t\t\t},\n\t\t\tquery: config.query,\n\t\t});\n\t}\n\n\t/**\n\t * Reload the current page.\n\t * This is equivalent to calling `go()` with the current pathname and search.\n\t */\n\tpublic async reload() {\n\t\tif (!this.browser) {\n\t\t\treturn;\n\t\t}\n\n\t\tawait this.go(this.location.pathname + this.location.search, {\n\t\t\treplace: true,\n\t\t\tforce: true,\n\t\t});\n\t}\n\n\tpublic getURL(): URL {\n\t\tif (!this.browser) {\n\t\t\treturn this.state.url;\n\t\t}\n\n\t\treturn new URL(this.location.href);\n\t}\n\n\tpublic get location(): Location {\n\t\tif (!this.browser) {\n\t\t\tthrow new Error(\"Browser is required\");\n\t\t}\n\n\t\treturn this.browser.location;\n\t}\n\n\tpublic get current(): ReactRouterState {\n\t\treturn this.state;\n\t}\n\n\tpublic get pathname(): string {\n\t\treturn this.state.url.pathname;\n\t}\n\n\tpublic get query(): Record<string, string> {\n\t\tconst query: Record<string, string> = {};\n\n\t\tfor (const [key, value] of new URLSearchParams(\n\t\t\tthis.state.url.search,\n\t\t).entries()) {\n\t\t\tquery[key] = String(value);\n\t\t}\n\n\t\treturn query;\n\t}\n\n\tpublic async back() {\n\t\tthis.browser?.history.back();\n\t}\n\n\tpublic async forward() {\n\t\tthis.browser?.history.forward();\n\t}\n\n\tpublic async invalidate(props?: Record<string, any>) {\n\t\tawait this.browser?.invalidate(props);\n\t}\n\n\tpublic async go(path: string, options?: RouterGoOptions): Promise<void>;\n\tpublic async go(\n\t\tpath: keyof VirtualRouter<T>,\n\t\toptions?: RouterGoOptions,\n\t): Promise<void>;\n\tpublic async go(\n\t\tpath: string | keyof VirtualRouter<T>,\n\t\toptions?: RouterGoOptions,\n\t): Promise<void> {\n\t\tfor (const page of this.pages) {\n\t\t\tif (page.name === path) {\n\t\t\t\tawait this.browser?.go(\n\t\t\t\t\tthis.path(path as keyof VirtualRouter<T>, options),\n\t\t\t\t\toptions,\n\t\t\t\t);\n\t\t\t\treturn;\n\t\t\t}\n\t\t}\n\n\t\tawait this.browser?.go(path as string, options);\n\t}\n\n\tpublic anchor(path: string, options?: RouterGoOptions): AnchorProps;\n\tpublic anchor(\n\t\tpath: keyof VirtualRouter<T>,\n\t\toptions?: RouterGoOptions,\n\t): AnchorProps;\n\tpublic anchor(\n\t\tpath: string | keyof VirtualRouter<T>,\n\t\toptions: RouterGoOptions = {},\n\t): AnchorProps {\n\t\tlet href = path as string;\n\n\t\tfor (const page of this.pages) {\n\t\t\tif (page.name === path) {\n\t\t\t\thref = this.path(path as keyof VirtualRouter<T>, options);\n\t\t\t\tbreak;\n\t\t\t}\n\t\t}\n\n\t\treturn {\n\t\t\thref: this.base(href),\n\t\t\tonClick: (ev: any) => {\n\t\t\t\tev.stopPropagation();\n\t\t\t\tev.preventDefault();\n\n\t\t\t\tthis.go(href, options).catch(console.error);\n\t\t\t},\n\t\t};\n\t}\n\n\tpublic base(path: string): string {\n\t\tconst base = import.meta.env?.BASE_URL;\n\t\tif (!base || base === \"/\") {\n\t\t\treturn path;\n\t\t}\n\n\t\treturn base + path;\n\t}\n\n\t/**\n\t * Set query params.\n\t *\n\t * @param record\n\t * @param options\n\t */\n\tpublic setQueryParams(\n\t\trecord:\n\t\t\t| Record<string, any>\n\t\t\t| ((queryParams: Record<string, any>) => Record<string, any>),\n\t\toptions: {\n\t\t\t/**\n\t\t\t * If true, this will add a new entry to the history stack.\n\t\t\t */\n\t\t\tpush?: boolean;\n\t\t} = {},\n\t) {\n\t\tconst func = typeof record === \"function\" ? record : () => record;\n\t\tconst search = new URLSearchParams(func(this.query)).toString();\n\t\tconst state = search ? `${this.pathname}?${search}` : this.pathname;\n\n\t\tif (options.push) {\n\t\t\twindow.history.pushState({}, \"\", state);\n\t\t} else {\n\t\t\twindow.history.replaceState({}, \"\", state);\n\t\t}\n\t}\n}\n\nexport type VirtualRouter<T> = {\n\t[K in keyof T as T[K] extends PageDescriptor ? K : never]: T[K];\n};\n","import type { Service } from \"@alepha/core\";\nimport { useMemo } from \"react\";\nimport { useAlepha } from \"./useAlepha.ts\";\n\n/**\n * Hook to inject a service instance.\n * It's a wrapper of `useAlepha().inject(service)` with a memoization.\n */\nexport const useInject = <T extends object>(service: Service<T>): T => {\n\tconst alepha = useAlepha();\n\treturn useMemo(() => alepha.inject(service), []);\n};\n","import { ReactRouter } from \"../services/ReactRouter.ts\";\nimport { useInject } from \"./useInject.ts\";\n\n/**\n * Use this hook to access the React Router instance.\n *\n * You can add a type parameter to specify the type of your application.\n * This will allow you to use the router in a typesafe way.\n *\n * @example\n * class App {\n * home = $page();\n * }\n *\n * const router = useRouter<App>();\n * router.go(\"home\"); // typesafe\n */\nexport const useRouter = <T extends object = any>(): ReactRouter<T> => {\n\treturn useInject(ReactRouter<T>);\n};\n","import type { AnchorHTMLAttributes } from \"react\";\nimport { useRouter } from \"../hooks/useRouter.ts\";\n\nexport interface LinkProps extends AnchorHTMLAttributes<HTMLAnchorElement> {\n\thref: string;\n}\n\nconst Link = (props: LinkProps) => {\n\tconst router = useRouter();\n\n\treturn (\n\t\t<a {...props} {...router.anchor(props.href)}>\n\t\t\t{props.children}\n\t\t</a>\n\t);\n};\n\nexport default Link;\n","import { useState } from \"react\";\nimport type { AnchorProps } from \"../providers/ReactPageProvider.ts\";\nimport { useRouter } from \"./useRouter.ts\";\nimport { useRouterState } from \"./useRouterState.ts\";\n\nexport interface UseActiveOptions {\n\thref: string;\n\tstartWith?: boolean;\n}\n\nexport const useActive = (args: string | UseActiveOptions): UseActiveHook => {\n\tconst router = useRouter();\n\tconst [isPending, setPending] = useState(false);\n\tconst state = useRouterState();\n\tconst current = state.url.pathname;\n\n\tconst options: UseActiveOptions =\n\t\ttypeof args === \"string\" ? { href: args } : { ...args, href: args.href };\n\tconst href = options.href;\n\n\tlet isActive =\n\t\tcurrent === href || current === `${href}/` || `${current}/` === href;\n\n\tif (options.startWith && !isActive) {\n\t\tisActive = current.startsWith(href);\n\t}\n\n\treturn {\n\t\tisPending,\n\t\tisActive,\n\t\tanchorProps: {\n\t\t\thref: router.base(href),\n\t\t\tonClick: async (ev?: any) => {\n\t\t\t\tev?.stopPropagation();\n\t\t\t\tev?.preventDefault();\n\t\t\t\tif (isActive) return;\n\t\t\t\tif (isPending) return;\n\n\t\t\t\tsetPending(true);\n\t\t\t\ttry {\n\t\t\t\t\tawait router.go(href);\n\t\t\t\t} finally {\n\t\t\t\t\tsetPending(false);\n\t\t\t\t}\n\t\t\t},\n\t\t},\n\t};\n};\n\nexport interface UseActiveHook {\n\tisActive: boolean;\n\tanchorProps: AnchorProps;\n\tisPending: boolean;\n}\n","import {\n\ttype ClientScope,\n\ttype HttpVirtualClient,\n\tLinkProvider,\n} from \"@alepha/server-links\";\nimport { useInject } from \"./useInject.ts\";\n\n/**\n * Hook to get a virtual client for the specified scope.\n *\n * It's the React-hook version of `$client()`, from `AlephaServerLinks` module.\n */\nexport const useClient = <T extends object>(\n\tscope?: ClientScope,\n): HttpVirtualClient<T> => {\n\treturn useInject(LinkProvider).client<T>(scope);\n};\n","import type { Alepha, Static, TObject } from \"@alepha/core\";\nimport { useEffect, useState } from \"react\";\nimport { useAlepha } from \"./useAlepha.ts\";\nimport { useRouter } from \"./useRouter.ts\";\n\n/**\n * Not well tested. Use with caution.\n */\nexport const useQueryParams = <T extends TObject>(\n\tschema: T,\n\toptions: UseQueryParamsHookOptions = {},\n): [Partial<Static<T>>, (data: Static<T>) => void] => {\n\tconst alepha = useAlepha();\n\n\tconst key = options.key ?? \"q\";\n\tconst router = useRouter();\n\tconst querystring = router.query[key];\n\n\tconst [queryParams = {}, setQueryParams] = useState<Static<T> | undefined>(\n\t\tdecode(alepha, schema, router.query[key]),\n\t);\n\n\tuseEffect(() => {\n\t\tsetQueryParams(decode(alepha, schema, querystring));\n\t}, [querystring]);\n\n\treturn [\n\t\tqueryParams,\n\t\t(queryParams: Static<T>) => {\n\t\t\tsetQueryParams(queryParams);\n\t\t\trouter.setQueryParams((data) => {\n\t\t\t\treturn { ...data, [key]: encode(alepha, schema, queryParams) };\n\t\t\t});\n\t\t},\n\t];\n};\n\n// ---------------------------------------------------------------------------------------------------------------------\n\nexport interface UseQueryParamsHookOptions {\n\tformat?: \"base64\" | \"querystring\";\n\tkey?: string;\n\tpush?: boolean;\n}\n\nconst encode = (alepha: Alepha, schema: TObject, data: any) => {\n\treturn btoa(JSON.stringify(alepha.parse(schema, data)));\n};\n\nconst decode = <T extends TObject>(\n\talepha: Alepha,\n\tschema: T,\n\tdata: any,\n): Static<T> | undefined => {\n\ttry {\n\t\treturn alepha.parse(schema, JSON.parse(atob(decodeURIComponent(data))));\n\t} catch {\n\t\treturn;\n\t}\n};\n","import type { Alepha } from \"@alepha/core\";\nimport {\n\ttype FetchOptions,\n\tHttpClient,\n\ttype RequestConfigSchema,\n} from \"@alepha/server\";\nimport { LinkProvider, type VirtualAction } from \"@alepha/server-links\";\nimport { useEffect, useState } from \"react\";\nimport { useAlepha } from \"./useAlepha.ts\";\nimport { useInject } from \"./useInject.ts\";\n\nexport const useSchema = <TConfig extends RequestConfigSchema>(\n\taction: VirtualAction<TConfig>,\n): UseSchemaReturn<TConfig> => {\n\tconst name = action.name;\n\tconst alepha = useAlepha();\n\tconst httpClient = useInject(HttpClient);\n\tconst [schema, setSchema] = useState<UseSchemaReturn<TConfig>>(\n\t\tssrSchemaLoading(alepha, name) as UseSchemaReturn<TConfig>,\n\t);\n\n\tuseEffect(() => {\n\t\tif (!schema.loading) {\n\t\t\treturn;\n\t\t}\n\n\t\tconst opts: FetchOptions = {\n\t\t\tcache: true,\n\t\t};\n\n\t\thttpClient\n\t\t\t.fetch(`${LinkProvider.path.apiLinks}/${name}/schema`, {}, opts)\n\t\t\t.then((it) => setSchema(it.data as UseSchemaReturn<TConfig>));\n\t}, [name]);\n\n\treturn schema;\n};\n\nexport type UseSchemaReturn<TConfig extends RequestConfigSchema> = TConfig & {\n\tloading: boolean;\n};\n\n// ---------------------------------------------------------------------------------------------------------------------\n\n/**\n * Get an action schema during server-side rendering (SSR) or client-side rendering (CSR).\n */\nexport const ssrSchemaLoading = (alepha: Alepha, name: string) => {\n\t// server-side rendering (SSR) context\n\tif (!alepha.isBrowser()) {\n\t\t// get user links\n\t\tconst linkProvider = alepha.inject(LinkProvider);\n\n\t\t// check if user can access the link\n\t\tconst can = linkProvider\n\t\t\t.getServerLinks()\n\t\t\t.find((link) => link.name === name);\n\n\t\t// yes!\n\t\tif (can) {\n\t\t\t// user-links have no schema, so we need to get it from the provider\n\t\t\tconst schema = linkProvider.links.find((it) => it.name === name)?.schema;\n\n\t\t\t// oh, we have a schema!\n\t\t\tif (schema) {\n\t\t\t\t// attach to user link, it will be used in the client during hydration\n\t\t\t\tcan.schema = schema;\n\t\t\t\treturn schema;\n\t\t\t}\n\t\t}\n\n\t\treturn { loading: true };\n\t}\n\n\t// browser side rendering (CSR) context\n\t// check if we have the schema already loaded\n\tconst schema = alepha\n\t\t.inject(LinkProvider)\n\t\t.links.find((it) => it.name === name)?.schema;\n\n\t// yes!\n\tif (schema) {\n\t\treturn schema;\n\t}\n\n\t// no, we need to load it\n\treturn { loading: true };\n};\n","import { $module } from \"@alepha/core\";\nimport { AlephaServer, type ServerRequest } from \"@alepha/server\";\nimport { AlephaServerCache } from \"@alepha/server-cache\";\nimport { AlephaServerLinks } from \"@alepha/server-links\";\nimport type { ReactNode } from \"react\";\nimport { $page, type PageAnimation } from \"./descriptors/$page.ts\";\nimport type { ReactHydrationState } from \"./providers/ReactBrowserProvider.ts\";\nimport {\n\tReactPageProvider,\n\ttype ReactRouterState,\n} from \"./providers/ReactPageProvider.ts\";\nimport { ReactServerProvider } from \"./providers/ReactServerProvider.ts\";\nimport { ReactRouter } from \"./services/ReactRouter.ts\";\n\n// ---------------------------------------------------------------------------------------------------------------------\n\nexport * from \"./index.shared.ts\";\nexport * from \"./providers/ReactBrowserProvider.ts\";\nexport * from \"./providers/ReactPageProvider.ts\";\nexport * from \"./providers/ReactServerProvider.ts\";\n\n// ---------------------------------------------------------------------------------------------------------------------\n\ndeclare module \"@alepha/core\" {\n\tinterface State {\n\t\t\"react.router.state\"?: ReactRouterState;\n\t}\n\n\tinterface Hooks {\n\t\t\"react:server:render:begin\": {\n\t\t\trequest?: ServerRequest;\n\t\t\tstate: ReactRouterState;\n\t\t};\n\t\t\"react:server:render:end\": {\n\t\t\trequest?: ServerRequest;\n\t\t\tstate: ReactRouterState;\n\t\t\thtml: string;\n\t\t};\n\t\t// -----------------------------------------------------------------------------------------------------------------\n\t\t\"react:browser:render\": {\n\t\t\troot: HTMLDivElement;\n\t\t\telement: ReactNode;\n\t\t\tstate: ReactRouterState;\n\t\t\thydration?: ReactHydrationState;\n\t\t};\n\t\t\"react:transition:begin\": {\n\t\t\tprevious: ReactRouterState;\n\t\t\tstate: ReactRouterState;\n\t\t\tanimation?: PageAnimation;\n\t\t};\n\t\t\"react:transition:success\": {\n\t\t\tstate: ReactRouterState;\n\t\t};\n\t\t\"react:transition:error\": {\n\t\t\tstate: ReactRouterState;\n\t\t\terror: Error;\n\t\t};\n\t\t\"react:transition:end\": {\n\t\t\tstate: ReactRouterState;\n\t\t};\n\t}\n}\n\n// ---------------------------------------------------------------------------------------------------------------------\n\n/**\n * Provides full-stack React development with declarative routing, server-side rendering, and client-side hydration.\n *\n * The React module enables building modern React applications using the `$page` descriptor on class properties.\n * It delivers seamless server-side rendering, automatic code splitting, and client-side navigation with full\n * type safety and schema validation for route parameters and data.\n *\n * @see {@link $page}\n * @module alepha.react\n */\nexport const AlephaReact = $module({\n\tname: \"alepha.react\",\n\tdescriptors: [$page],\n\tservices: [ReactServerProvider, ReactPageProvider, ReactRouter],\n\tregister: (alepha) =>\n\t\talepha\n\t\t\t.with(AlephaServer)\n\t\t\t.with(AlephaServerCache)\n\t\t\t.with(AlephaServerLinks)\n\t\t\t.with(ReactServerProvider)\n\t\t\t.with(ReactPageProvider)\n\t\t\t.with(ReactRouter),\n});\n"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"index.js","names":["subs: Function[]","state","timing","envSchema","NestedView","context: Record<string, any>","stack: Array<RouterStackItem>","route","config: Record<string, any>","context","element: ReactNode | Redirection | undefined","children","envSchema","entry: Partial<ReactRouterState>","target: PageRoute | undefined","element","hydrationData: ReactHydrationState","entry: Partial<ReactRouterState>","query: Record<string, string>","previous: PreviousLayerData[]","query: Record<string, string>","options: UseActiveOptions","queryParams","opts: FetchOptions","schema"],"sources":["../src/descriptors/$page.ts","../src/components/ClientOnly.tsx","../src/components/ErrorViewer.tsx","../src/contexts/RouterLayerContext.ts","../src/errors/Redirection.ts","../src/contexts/AlephaContext.ts","../src/hooks/useAlepha.ts","../src/hooks/useRouterEvents.ts","../src/hooks/useStore.ts","../src/hooks/useRouterState.ts","../src/components/ErrorBoundary.tsx","../src/components/NestedView.tsx","../src/components/NotFound.tsx","../src/providers/ReactPageProvider.ts","../src/providers/ReactServerProvider.ts","../src/providers/ReactBrowserRouterProvider.ts","../src/providers/ReactBrowserProvider.ts","../src/services/ReactRouter.ts","../src/hooks/useInject.ts","../src/hooks/useRouter.ts","../src/components/Link.tsx","../src/hooks/useActive.ts","../src/hooks/useClient.ts","../src/hooks/useQueryParams.ts","../src/hooks/useSchema.ts","../src/index.ts"],"sourcesContent":["import {\n\tAlephaError,\n\ttype Async,\n\tcreateDescriptor,\n\tDescriptor,\n\tKIND,\n\ttype Static,\n\ttype TSchema,\n} from \"@alepha/core\";\nimport type { ServerRequest } from \"@alepha/server\";\nimport type { ServerRouteCache } from \"@alepha/server-cache\";\nimport type { FC, ReactNode } from \"react\";\nimport type { ClientOnlyProps } from \"../components/ClientOnly.tsx\";\nimport type { Redirection } from \"../errors/Redirection.ts\";\nimport type { ReactRouterState } from \"../providers/ReactPageProvider.ts\";\n\n/**\n * Main descriptor for defining a React route in the application.\n *\n * The $page descriptor is the core building block for creating type-safe, SSR-enabled React routes.\n * It provides a declarative way to define pages with powerful features:\n *\n * **Routing & Navigation**\n * - URL pattern matching with parameters (e.g., `/users/:id`)\n * - Nested routing with parent-child relationships\n * - Type-safe URL parameter and query string validation\n *\n * **Data Loading**\n * - Server-side data fetching with the `resolve` function\n * - Automatic serialization and hydration for SSR\n * - Access to request context, URL params, and parent data\n *\n * **Component Loading**\n * - Direct component rendering or lazy loading for code splitting\n * - Client-only rendering when browser APIs are needed\n * - Automatic fallback handling during hydration\n *\n * **Performance Optimization**\n * - Static generation for pre-rendered pages at build time\n * - Server-side caching with configurable TTL and providers\n * - Code splitting through lazy component loading\n *\n * **Error Handling**\n * - Custom error handlers with support for redirects\n * - Hierarchical error handling (child → parent)\n * - HTTP status code handling (404, 401, etc.)\n *\n * **Page Animations**\n * - CSS-based enter/exit animations\n * - Dynamic animations based on page state\n * - Custom timing and easing functions\n *\n * **Lifecycle Management**\n * - Server response hooks for headers and status codes\n * - Page leave handlers for cleanup (browser only)\n * - Permission-based access control\n *\n * @example Simple page with data fetching\n * ```typescript\n * const userProfile = $page({\n * path: \"/users/:id\",\n * schema: {\n * params: t.object({ id: t.int() }),\n * query: t.object({ tab: t.optional(t.text()) })\n * },\n * resolve: async ({ params }) => {\n * const user = await userApi.getUser(params.id);\n * return { user };\n * },\n * lazy: () => import(\"./UserProfile.tsx\")\n * });\n * ```\n *\n * @example Nested routing with error handling\n * ```typescript\n * const projectSection = $page({\n * path: \"/projects/:id\",\n * children: () => [projectBoard, projectSettings],\n * resolve: async ({ params }) => {\n * const project = await projectApi.get(params.id);\n * return { project };\n * },\n * errorHandler: (error) => {\n * if (HttpError.is(error, 404)) {\n * return <ProjectNotFound />;\n * }\n * }\n * });\n * ```\n *\n * @example Static generation with caching\n * ```typescript\n * const blogPost = $page({\n * path: \"/blog/:slug\",\n * static: {\n * entries: posts.map(p => ({ params: { slug: p.slug } }))\n * },\n * resolve: async ({ params }) => {\n * const post = await loadPost(params.slug);\n * return { post };\n * }\n * });\n * ```\n */\nexport const $page = <\n\tTConfig extends PageConfigSchema = PageConfigSchema,\n\tTProps extends object = TPropsDefault,\n\tTPropsParent extends object = TPropsParentDefault,\n>(\n\toptions: PageDescriptorOptions<TConfig, TProps, TPropsParent>,\n): PageDescriptor<TConfig, TProps, TPropsParent> => {\n\treturn createDescriptor(\n\t\tPageDescriptor<TConfig, TProps, TPropsParent>,\n\t\toptions,\n\t);\n};\n\n// ---------------------------------------------------------------------------------------------------------------------\n\nexport interface PageDescriptorOptions<\n\tTConfig extends PageConfigSchema = PageConfigSchema,\n\tTProps extends object = TPropsDefault,\n\tTPropsParent extends object = TPropsParentDefault,\n> {\n\t/**\n\t * Name your page.\n\t *\n\t * @default Descriptor key\n\t */\n\tname?: string;\n\n\t/**\n\t * Optional description of the page.\n\t */\n\tdescription?: string;\n\n\t/**\n\t * Add a pathname to the page.\n\t *\n\t * Pathname can contain parameters, like `/post/:slug`.\n\t *\n\t * @default \"\"\n\t */\n\tpath?: string;\n\n\t/**\n\t * Add an input schema to define:\n\t * - `params`: parameters from the pathname.\n\t * - `query`: query parameters from the URL.\n\t */\n\tschema?: TConfig;\n\n\t/**\n\t * Load data before rendering the page.\n\t *\n\t * This function receives\n\t * - the request context and\n\t * - the parent props (if page has a parent)\n\t *\n\t * In SSR, the returned data will be serialized and sent to the client, then reused during the client-side hydration.\n\t *\n\t * Resolve can be stopped by throwing an error, which will be handled by the `errorHandler` function.\n\t * It's common to throw a `NotFoundError` to display a 404 page.\n\t *\n\t * RedirectError can be thrown to redirect the user to another page.\n\t */\n\tresolve?: (context: PageResolve<TConfig, TPropsParent>) => Async<TProps>;\n\n\t/**\n\t * The component to render when the page is loaded.\n\t *\n\t * If `lazy` is defined, this will be ignored.\n\t * Prefer using `lazy` to improve the initial loading time.\n\t */\n\tcomponent?: FC<TProps & TPropsParent>;\n\n\t/**\n\t * Lazy load the component when the page is loaded.\n\t *\n\t * It's recommended to use this for components to improve the initial loading time\n\t * and enable code-splitting.\n\t */\n\tlazy?: () => Promise<{ default: FC<TProps & TPropsParent> }>;\n\n\t/**\n\t * Set some children pages and make the page a parent page.\n\t *\n\t * /!\\ Parent page can't be rendered directly. /!\\\n\t *\n\t * If you still want to render at this pathname, add a child page with an empty path.\n\t */\n\tchildren?: Array<PageDescriptor> | (() => Array<PageDescriptor>);\n\n\tparent?: PageDescriptor<PageConfigSchema, TPropsParent>;\n\n\tcan?: () => boolean;\n\n\t/**\n\t * Catch any error from the `resolve` function or during `rendering`.\n\t *\n\t * Expected to return one of the following:\n\t * - a ReactNode to render an error page\n\t * - a Redirection to redirect the user\n\t * - undefined to let the error propagate\n\t *\n\t * If not defined, the error will be thrown and handled by the server or client error handler.\n\t * If a leaf $page does not define an error handler, the error can be caught by parent pages.\n\t *\n\t * @example Catch a 404 from API and render a custom not found component:\n\t * ```ts\n\t * resolve: async ({ params, query }) => {\n\t * api.fetch(\"/api/resource\", { params, query });\n\t * },\n\t * errorHandler: (error, context) => {\n\t * if (HttpError.is(error, 404)) {\n\t * return <ResourceNotFound />;\n\t * }\n\t * }\n\t * ```\n\t *\n\t * @example Catch an 401 error and redirect the user to the login page:\n\t * ```ts\n\t * resolve: async ({ params, query }) => {\n\t * // but the user is not authenticated\n\t * api.fetch(\"/api/resource\", { params, query });\n\t * },\n\t * errorHandler: (error, context) => {\n\t * if (HttpError.is(error, 401)) {\n\t * // throwing a Redirection is also valid!\n\t * return new Redirection(\"/login\");\n\t * }\n\t * }\n\t * ```\n\t */\n\terrorHandler?: ErrorHandler;\n\n\t/**\n\t * If true, the page will be considered as a static page, immutable and cacheable.\n\t * Replace boolean by an object to define static entries. (e.g. list of params/query)\n\t *\n\t * For now, it only works with `@alepha/vite` which can pre-render the page at build time.\n\t *\n\t * It will act as timeless cached page server-side. You can use `cache` to configure the cache behavior.\n\t */\n\tstatic?:\n\t\t| boolean\n\t\t| {\n\t\t\t\tentries?: Array<Partial<PageRequestConfig<TConfig>>>;\n\t\t };\n\n\tcache?: ServerRouteCache;\n\n\t/**\n\t * If true, force the page to be rendered only on the client-side.\n\t * It uses the `<ClientOnly/>` component to render the page.\n\t */\n\tclient?: boolean | ClientOnlyProps;\n\n\t/**\n\t * Called before the server response is sent to the client.\n\t */\n\tonServerResponse?: (request: ServerRequest) => any;\n\n\t/**\n\t * Called when user leaves the page. (browser only)\n\t */\n\tonLeave?: () => void;\n\n\t/**\n\t * @experimental\n\t *\n\t * Add a css animation when the page is loaded or unloaded.\n\t * It uses CSS animations, so you need to define the keyframes in your CSS.\n\t *\n\t * @example Simple animation name\n\t * ```ts\n\t * animation: \"fadeIn\"\n\t * ```\n\t *\n\t * CSS example:\n\t * ```css\n\t * @keyframes fadeIn {\n\t * from { opacity: 0; }\n\t * to { opacity: 1; }\n\t * }\n\t * ```\n\t *\n\t * @example Detailed animation\n\t * ```ts\n\t * animation: {\n\t * enter: { name: \"fadeIn\", duration: 300 },\n\t * exit: { name: \"fadeOut\", duration: 200, timing: \"ease-in-out\" },\n\t * }\n\t * ```\n\t *\n\t * @example Only exit animation\n\t * ```ts\n\t * animation: {\n\t * exit: \"fadeOut\"\n\t * }\n\t * ```\n\t *\n\t * @example With custom timing function\n\t * ```ts\n\t * animation: {\n\t * enter: { name: \"fadeIn\", duration: 300, timing: \"cubic-bezier(0.4, 0, 0.2, 1)\" },\n\t * exit: { name: \"fadeOut\", duration: 200, timing: \"ease-in-out\" },\n\t * }\n\t * ```\n\t */\n\tanimation?: PageAnimation;\n}\n\nexport type ErrorHandler = (\n\terror: Error,\n\tstate: ReactRouterState,\n) => ReactNode | Redirection | undefined;\n\nexport class PageDescriptor<\n\tTConfig extends PageConfigSchema = PageConfigSchema,\n\tTProps extends object = TPropsDefault,\n\tTPropsParent extends object = TPropsParentDefault,\n> extends Descriptor<PageDescriptorOptions<TConfig, TProps, TPropsParent>> {\n\tprotected onInit() {\n\t\tif (this.options.static) {\n\t\t\tthis.options.cache ??= {\n\t\t\t\tprovider: \"memory\",\n\t\t\t\tttl: [1, \"week\"],\n\t\t\t};\n\t\t}\n\t}\n\n\tpublic get name(): string {\n\t\treturn this.options.name ?? this.config.propertyKey;\n\t}\n\n\t/**\n\t * For testing or build purposes, this will render the page (with or without the HTML layout) and return the HTML and context.\n\t * Only valid for server-side rendering, it will throw an error if called on the client-side.\n\t */\n\tpublic async render(\n\t\toptions?: PageDescriptorRenderOptions,\n\t): Promise<PageDescriptorRenderResult> {\n\t\tthrow new AlephaError(\n\t\t\t\"render() method is not implemented in this environment\",\n\t\t);\n\t}\n\n\tpublic async fetch(options?: PageDescriptorRenderOptions): Promise<{\n\t\thtml: string;\n\t\tresponse: Response;\n\t}> {\n\t\tthrow new AlephaError(\n\t\t\t\"fetch() method is not implemented in this environment\",\n\t\t);\n\t}\n\n\tpublic match(url: string): boolean {\n\t\t// TODO: Implement a way to match the URL against the pathname\n\t\treturn false;\n\t}\n\n\tpublic pathname(config: any) {\n\t\t// TODO: Implement a way to generate the pathname based on the config\n\t\treturn this.options.path || \"\";\n\t}\n}\n\n$page[KIND] = PageDescriptor;\n\n// ---------------------------------------------------------------------------------------------------------------------\n\nexport interface PageConfigSchema {\n\tquery?: TSchema;\n\tparams?: TSchema;\n}\n\nexport type TPropsDefault = any;\n\nexport type TPropsParentDefault = {};\n\nexport interface PageDescriptorRenderOptions {\n\tparams?: Record<string, string>;\n\tquery?: Record<string, string>;\n\n\t/**\n\t * If true, the HTML layout will be included in the response.\n\t * If false, only the page content will be returned.\n\t *\n\t * @default true\n\t */\n\thtml?: boolean;\n\thydration?: boolean;\n}\n\nexport interface PageDescriptorRenderResult {\n\thtml: string;\n\tstate: ReactRouterState;\n\tredirect?: string;\n}\n\nexport interface PageRequestConfig<\n\tTConfig extends PageConfigSchema = PageConfigSchema,\n> {\n\tparams: TConfig[\"params\"] extends TSchema\n\t\t? Static<TConfig[\"params\"]>\n\t\t: Record<string, string>;\n\n\tquery: TConfig[\"query\"] extends TSchema\n\t\t? Static<TConfig[\"query\"]>\n\t\t: Record<string, string>;\n}\n\nexport type PageResolve<\n\tTConfig extends PageConfigSchema = PageConfigSchema,\n\tTPropsParent extends object = TPropsParentDefault,\n> = PageRequestConfig<TConfig> &\n\tTPropsParent &\n\tOmit<ReactRouterState, \"layers\" | \"onError\">;\n\nexport type PageAnimation =\n\t| PageAnimationObject\n\t| ((state: ReactRouterState) => PageAnimationObject | undefined);\n\ntype PageAnimationObject =\n\t| CssAnimationName\n\t| {\n\t\t\tenter?: CssAnimation | CssAnimationName;\n\t\t\texit?: CssAnimation | CssAnimationName;\n\t };\n\ntype CssAnimationName = string;\n\ntype CssAnimation = {\n\tname: string;\n\tduration?: number;\n\ttiming?: string;\n};\n","import {\n\ttype PropsWithChildren,\n\ttype ReactNode,\n\tuseEffect,\n\tuseState,\n} from \"react\";\n\nexport interface ClientOnlyProps {\n\tfallback?: ReactNode;\n\tdisabled?: boolean;\n}\n\n/**\n * A small utility component that renders its children only on the client side.\n *\n * Optionally, you can provide a fallback React node that will be rendered.\n *\n * You should use this component when\n * - you have code that relies on browser-specific APIs\n * - you want to avoid server-side rendering for a specific part of your application\n * - you want to prevent pre-rendering of a component\n */\nconst ClientOnly = (props: PropsWithChildren<ClientOnlyProps>) => {\n\tconst [mounted, setMounted] = useState(false);\n\n\tuseEffect(() => setMounted(true), []);\n\n\tif (props.disabled) {\n\t\treturn props.children;\n\t}\n\n\treturn mounted ? props.children : props.fallback;\n};\n\nexport default ClientOnly;\n","import type { Alepha } from \"@alepha/core\";\nimport { useState } from \"react\";\n\ninterface ErrorViewerProps {\n\terror: Error;\n\talepha: Alepha;\n}\n\n// TODO: design this better\n\nconst ErrorViewer = ({ error, alepha }: ErrorViewerProps) => {\n\tconst [expanded, setExpanded] = useState(false);\n\tconst isProduction = alepha.isProduction();\n\t// const status = isHttpError(error) ? error.status : 500;\n\n\tif (isProduction) {\n\t\treturn <ErrorViewerProduction />;\n\t}\n\n\tconst stackLines = error.stack?.split(\"\\n\") ?? [];\n\tconst previewLines = stackLines.slice(0, 5);\n\tconst hiddenLineCount = stackLines.length - previewLines.length;\n\n\tconst copyToClipboard = (text: string) => {\n\t\tnavigator.clipboard.writeText(text).catch((err) => {\n\t\t\tconsole.error(\"Clipboard error:\", err);\n\t\t});\n\t};\n\n\tconst styles = {\n\t\tcontainer: {\n\t\t\tpadding: \"24px\",\n\t\t\tbackgroundColor: \"#FEF2F2\",\n\t\t\tcolor: \"#7F1D1D\",\n\t\t\tborder: \"1px solid #FECACA\",\n\t\t\tborderRadius: \"16px\",\n\t\t\tboxShadow: \"0 8px 24px rgba(0,0,0,0.05)\",\n\t\t\tfontFamily: \"monospace\",\n\t\t\tmaxWidth: \"768px\",\n\t\t\tmargin: \"40px auto\",\n\t\t},\n\t\theading: {\n\t\t\tfontSize: \"20px\",\n\t\t\tfontWeight: \"bold\",\n\t\t\tmarginBottom: \"10px\",\n\t\t},\n\t\tname: {\n\t\t\tfontSize: \"16px\",\n\t\t\tfontWeight: 600,\n\t\t},\n\t\tmessage: {\n\t\t\tfontSize: \"14px\",\n\t\t\tmarginBottom: \"16px\",\n\t\t},\n\t\tsectionHeader: {\n\t\t\tdisplay: \"flex\",\n\t\t\tjustifyContent: \"space-between\",\n\t\t\talignItems: \"center\",\n\t\t\tfontSize: \"12px\",\n\t\t\tmarginBottom: \"4px\",\n\t\t\tcolor: \"#991B1B\",\n\t\t},\n\t\tcopyButton: {\n\t\t\tfontSize: \"12px\",\n\t\t\tcolor: \"#DC2626\",\n\t\t\tbackground: \"none\",\n\t\t\tborder: \"none\",\n\t\t\tcursor: \"pointer\",\n\t\t\ttextDecoration: \"underline\",\n\t\t},\n\t\tstackContainer: {\n\t\t\tbackgroundColor: \"#FEE2E2\",\n\t\t\tpadding: \"12px\",\n\t\t\tborderRadius: \"8px\",\n\t\t\tfontSize: \"13px\",\n\t\t\tlineHeight: \"1.4\",\n\t\t\toverflowX: \"auto\" as const,\n\t\t\twhiteSpace: \"pre-wrap\" as const,\n\t\t},\n\t\texpandLine: {\n\t\t\tcolor: \"#F87171\",\n\t\t\tcursor: \"pointer\",\n\t\t\tmarginTop: \"8px\",\n\t\t},\n\t};\n\n\treturn (\n\t\t<div style={styles.container}>\n\t\t\t<div>\n\t\t\t\t<div style={styles.heading}>🔥 Error</div>\n\t\t\t\t<div style={styles.name}>{error.name}</div>\n\t\t\t\t<div style={styles.message}>{error.message}</div>\n\t\t\t</div>\n\n\t\t\t{stackLines.length > 0 && (\n\t\t\t\t<div>\n\t\t\t\t\t<div style={styles.sectionHeader}>\n\t\t\t\t\t\t<span>Stack trace</span>\n\t\t\t\t\t\t<button\n\t\t\t\t\t\t\tonClick={() => copyToClipboard(error.stack!)}\n\t\t\t\t\t\t\tstyle={styles.copyButton}\n\t\t\t\t\t\t>\n\t\t\t\t\t\t\tCopy all\n\t\t\t\t\t\t</button>\n\t\t\t\t\t</div>\n\t\t\t\t\t<pre style={styles.stackContainer}>\n\t\t\t\t\t\t{(expanded ? stackLines : previewLines).map((line, i) => (\n\t\t\t\t\t\t\t<div key={i}>{line}</div>\n\t\t\t\t\t\t))}\n\t\t\t\t\t\t{!expanded && hiddenLineCount > 0 && (\n\t\t\t\t\t\t\t<div style={styles.expandLine} onClick={() => setExpanded(true)}>\n\t\t\t\t\t\t\t\t+ {hiddenLineCount} more lines...\n\t\t\t\t\t\t\t</div>\n\t\t\t\t\t\t)}\n\t\t\t\t\t</pre>\n\t\t\t\t</div>\n\t\t\t)}\n\t\t</div>\n\t);\n};\n\nexport default ErrorViewer;\n\nconst ErrorViewerProduction = () => {\n\tconst styles = {\n\t\tcontainer: {\n\t\t\tpadding: \"24px\",\n\t\t\tbackgroundColor: \"#FEF2F2\",\n\t\t\tcolor: \"#7F1D1D\",\n\t\t\tborder: \"1px solid #FECACA\",\n\t\t\tborderRadius: \"16px\",\n\t\t\tboxShadow: \"0 8px 24px rgba(0,0,0,0.05)\",\n\t\t\tfontFamily: \"monospace\",\n\t\t\tmaxWidth: \"768px\",\n\t\t\tmargin: \"40px auto\",\n\t\t\ttextAlign: \"center\" as const,\n\t\t},\n\t\theading: {\n\t\t\tfontSize: \"20px\",\n\t\t\tfontWeight: \"bold\",\n\t\t\tmarginBottom: \"8px\",\n\t\t},\n\t\tname: {\n\t\t\tfontSize: \"16px\",\n\t\t\tfontWeight: 600,\n\t\t\tmarginBottom: \"4px\",\n\t\t},\n\t\tmessage: {\n\t\t\tfontSize: \"14px\",\n\t\t\topacity: 0.85,\n\t\t},\n\t};\n\n\treturn (\n\t\t<div style={styles.container}>\n\t\t\t<div style={styles.heading}>🚨 An error occurred</div>\n\t\t\t<div style={styles.message}>\n\t\t\t\tSomething went wrong. Please try again later.\n\t\t\t</div>\n\t\t</div>\n\t);\n};\n","import { createContext } from \"react\";\n\nexport interface RouterLayerContextValue {\n\tindex: number;\n\tpath: string;\n}\n\nexport const RouterLayerContext = createContext<\n\tRouterLayerContextValue | undefined\n>(undefined);\n","/**\n * Used for Redirection during the page loading.\n *\n * Depends on the context, it can be thrown or just returned.\n */\nexport class Redirection extends Error {\n\tpublic readonly redirect: string;\n\n\tconstructor(redirect: string) {\n\t\tsuper(\"Redirection\");\n\t\tthis.redirect = redirect;\n\t}\n}\n","import type { Alepha } from \"@alepha/core\";\nimport { createContext } from \"react\";\n\nexport const AlephaContext = createContext<Alepha | undefined>(undefined);\n","import { type Alepha, AlephaError } from \"@alepha/core\";\nimport { useContext } from \"react\";\nimport { AlephaContext } from \"../contexts/AlephaContext.ts\";\n\n/**\n * Main Alepha hook.\n *\n * It provides access to the Alepha instance within a React component.\n *\n * With Alepha, you can access the core functionalities of the framework:\n *\n * - alepha.state() for state management\n * - alepha.inject() for dependency injection\n * - alepha.events.emit() for event handling\n * etc...\n */\nexport const useAlepha = (): Alepha => {\n\tconst alepha = useContext(AlephaContext);\n\tif (!alepha) {\n\t\tthrow new AlephaError(\n\t\t\t\"Hook 'useAlepha()' must be used within an AlephaContext.Provider\",\n\t\t);\n\t}\n\n\treturn alepha;\n};\n","import type { Hooks } from \"@alepha/core\";\nimport { useEffect } from \"react\";\nimport { useAlepha } from \"./useAlepha.ts\";\n\ntype Hook<T extends keyof Hooks> =\n\t| ((ev: Hooks[T]) => void)\n\t| {\n\t\t\tpriority?: \"first\" | \"last\";\n\t\t\tcallback: (ev: Hooks[T]) => void;\n\t };\n\n/**\n * Subscribe to various router events.\n */\nexport const useRouterEvents = (\n\topts: {\n\t\tonBegin?: Hook<\"react:transition:begin\">;\n\t\tonError?: Hook<\"react:transition:error\">;\n\t\tonEnd?: Hook<\"react:transition:end\">;\n\t\tonSuccess?: Hook<\"react:transition:success\">;\n\t} = {},\n\tdeps: any[] = [],\n) => {\n\tconst alepha = useAlepha();\n\n\tuseEffect(() => {\n\t\tif (!alepha.isBrowser()) {\n\t\t\treturn;\n\t\t}\n\n\t\tconst cb = <T extends keyof Hooks>(callback: Hook<T>) => {\n\t\t\tif (typeof callback === \"function\") {\n\t\t\t\treturn { callback };\n\t\t\t}\n\t\t\treturn callback;\n\t\t};\n\n\t\tconst subs: Function[] = [];\n\t\tconst onBegin = opts.onBegin;\n\t\tconst onEnd = opts.onEnd;\n\t\tconst onError = opts.onError;\n\t\tconst onSuccess = opts.onSuccess;\n\n\t\tif (onBegin) {\n\t\t\tsubs.push(alepha.events.on(\"react:transition:begin\", cb(onBegin)));\n\t\t}\n\n\t\tif (onEnd) {\n\t\t\tsubs.push(alepha.events.on(\"react:transition:end\", cb(onEnd)));\n\t\t}\n\n\t\tif (onError) {\n\t\t\tsubs.push(alepha.events.on(\"react:transition:error\", cb(onError)));\n\t\t}\n\n\t\tif (onSuccess) {\n\t\t\tsubs.push(alepha.events.on(\"react:transition:success\", cb(onSuccess)));\n\t\t}\n\n\t\treturn () => {\n\t\t\tfor (const sub of subs) {\n\t\t\t\tsub();\n\t\t\t}\n\t\t};\n\t}, deps);\n};\n","import type { State } from \"@alepha/core\";\nimport { useEffect, useMemo, useState } from \"react\";\nimport { useAlepha } from \"./useAlepha.ts\";\n\n/**\n * Hook to access and mutate the Alepha state.\n */\nexport const useStore = <Key extends keyof State>(\n\tkey: Key,\n\tdefaultValue?: State[Key],\n): [State[Key], (value: State[Key]) => void] => {\n\tconst alepha = useAlepha();\n\n\tuseMemo(() => {\n\t\tif (defaultValue != null && alepha.state.get(key) == null) {\n\t\t\talepha.state.set(key, defaultValue);\n\t\t}\n\t}, [defaultValue]);\n\n\tconst [state, setState] = useState(alepha.state.get(key));\n\n\tuseEffect(() => {\n\t\tif (!alepha.isBrowser()) {\n\t\t\treturn;\n\t\t}\n\n\t\treturn alepha.events.on(\"state:mutate\", (ev) => {\n\t\t\tif (ev.key === key) {\n\t\t\t\tsetState(ev.value);\n\t\t\t}\n\t\t});\n\t}, []);\n\n\treturn [\n\t\tstate,\n\t\t(value: State[Key]) => {\n\t\t\talepha.state.set(key, value);\n\t\t},\n\t] as const;\n};\n","import { AlephaError } from \"@alepha/core\";\nimport type { ReactRouterState } from \"../providers/ReactPageProvider.ts\";\nimport { useStore } from \"./useStore.ts\";\n\nexport const useRouterState = (): ReactRouterState => {\n\tconst [state] = useStore(\"react.router.state\");\n\tif (!state) {\n\t\tthrow new AlephaError(\"Missing react router state\");\n\t}\n\treturn state;\n};\n","import React, {\n\ttype ErrorInfo,\n\ttype PropsWithChildren,\n\ttype ReactNode,\n} from \"react\";\n\n/**\n * Props for the ErrorBoundary component.\n */\nexport interface ErrorBoundaryProps {\n\t/**\n\t * Fallback React node to render when an error is caught.\n\t * If not provided, a default error message will be shown.\n\t */\n\tfallback: (error: Error) => ReactNode;\n\n\t/**\n\t * Optional callback that receives the error and error info.\n\t * Use this to log errors to a monitoring service.\n\t */\n\tonError?: (error: Error, info: ErrorInfo) => void;\n}\n\n/**\n * State of the ErrorBoundary component.\n */\ninterface ErrorBoundaryState {\n\terror?: Error;\n}\n\n/**\n * A reusable error boundary for catching rendering errors\n * in any part of the React component tree.\n */\nexport class ErrorBoundary extends React.Component<\n\tPropsWithChildren<ErrorBoundaryProps>,\n\tErrorBoundaryState\n> {\n\tconstructor(props: ErrorBoundaryProps) {\n\t\tsuper(props);\n\t\tthis.state = {};\n\t}\n\n\t/**\n\t * Update state so the next render shows the fallback UI.\n\t */\n\tstatic getDerivedStateFromError(error: Error): ErrorBoundaryState {\n\t\treturn {\n\t\t\terror,\n\t\t};\n\t}\n\n\t/**\n\t * Lifecycle method called when an error is caught.\n\t * You can log the error or perform side effects here.\n\t */\n\tcomponentDidCatch(error: Error, info: ErrorInfo): void {\n\t\tif (this.props.onError) {\n\t\t\tthis.props.onError(error, info);\n\t\t}\n\t}\n\n\trender(): ReactNode {\n\t\tif (this.state.error) {\n\t\t\treturn this.props.fallback(this.state.error);\n\t\t}\n\n\t\treturn this.props.children;\n\t}\n}\n\nexport default ErrorBoundary;\n","import { memo, type ReactNode, use, useRef, useState } from \"react\";\nimport { RouterLayerContext } from \"../contexts/RouterLayerContext.ts\";\nimport type { PageAnimation } from \"../descriptors/$page.ts\";\nimport { Redirection } from \"../errors/Redirection.ts\";\nimport { useRouterEvents } from \"../hooks/useRouterEvents.ts\";\nimport { useRouterState } from \"../hooks/useRouterState.ts\";\nimport type { ReactRouterState } from \"../providers/ReactPageProvider.ts\";\nimport ErrorBoundary from \"./ErrorBoundary.tsx\";\n\nexport interface NestedViewProps {\n\tchildren?: ReactNode;\n\terrorBoundary?: false | ((error: Error) => ReactNode);\n}\n\n/**\n * A component that renders the current view of the nested router layer.\n *\n * To be simple, it renders the `element` of the current child page of a parent page.\n *\n * @example\n * ```tsx\n * import { NestedView } from \"alepha/react\";\n *\n * class App {\n * parent = $page({\n * component: () => <NestedView />,\n * });\n *\n * child = $page({\n * parent: this.root,\n * component: () => <div>Child Page</div>,\n * });\n * }\n * ```\n */\nconst NestedView = (props: NestedViewProps) => {\n\tconst index = use(RouterLayerContext)?.index ?? 0;\n\tconst state = useRouterState();\n\n\tconst [view, setView] = useState<ReactNode | undefined>(\n\t\tstate.layers[index]?.element,\n\t);\n\n\tconst [animation, setAnimation] = useState(\"\");\n\tconst animationExitDuration = useRef<number>(0);\n\tconst animationExitNow = useRef<number>(0);\n\n\tuseRouterEvents(\n\t\t{\n\t\t\tonBegin: async ({ previous, state }) => {\n\t\t\t\t// --------- Animations Begin ---------\n\t\t\t\tconst layer = previous.layers[index];\n\t\t\t\tif (`${state.url.pathname}/`.startsWith(`${layer?.path}/`)) {\n\t\t\t\t\treturn;\n\t\t\t\t}\n\n\t\t\t\tconst animationExit = parseAnimation(\n\t\t\t\t\tlayer.route?.animation,\n\t\t\t\t\tstate,\n\t\t\t\t\t\"exit\",\n\t\t\t\t);\n\n\t\t\t\tif (animationExit) {\n\t\t\t\t\tconst duration = animationExit.duration || 200;\n\t\t\t\t\tanimationExitNow.current = Date.now();\n\t\t\t\t\tanimationExitDuration.current = duration;\n\t\t\t\t\tsetAnimation(animationExit.animation);\n\t\t\t\t} else {\n\t\t\t\t\tanimationExitNow.current = 0;\n\t\t\t\t\tanimationExitDuration.current = 0;\n\t\t\t\t\tsetAnimation(\"\");\n\t\t\t\t}\n\t\t\t\t// --------- Animations End ---------\n\t\t\t},\n\t\t\tonEnd: async ({ state }) => {\n\t\t\t\tconst layer = state.layers[index];\n\n\t\t\t\t// --------- Animations Begin ---------\n\t\t\t\tif (animationExitNow.current) {\n\t\t\t\t\tconst duration = animationExitDuration.current;\n\t\t\t\t\tconst diff = Date.now() - animationExitNow.current;\n\t\t\t\t\tif (diff < duration) {\n\t\t\t\t\t\tawait new Promise((resolve) =>\n\t\t\t\t\t\t\tsetTimeout(resolve, duration - diff),\n\t\t\t\t\t\t);\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t\t// --------- Animations End ---------\n\n\t\t\t\tif (!layer?.cache) {\n\t\t\t\t\tsetView(layer?.element);\n\n\t\t\t\t\t// --------- Animations Begin ---------\n\t\t\t\t\tconst animationEnter = parseAnimation(\n\t\t\t\t\t\tlayer?.route?.animation,\n\t\t\t\t\t\tstate,\n\t\t\t\t\t\t\"enter\",\n\t\t\t\t\t);\n\n\t\t\t\t\tif (animationEnter) {\n\t\t\t\t\t\tsetAnimation(animationEnter.animation);\n\t\t\t\t\t} else {\n\t\t\t\t\t\tsetAnimation(\"\");\n\t\t\t\t\t}\n\t\t\t\t\t// --------- Animations End ---------\n\t\t\t\t}\n\t\t\t},\n\t\t},\n\t\t[],\n\t);\n\n\tlet element = view ?? props.children ?? null;\n\n\t// --------- Animations Begin ---------\n\tif (animation) {\n\t\telement = (\n\t\t\t<div\n\t\t\t\tstyle={{\n\t\t\t\t\tdisplay: \"flex\",\n\t\t\t\t\tflex: 1,\n\t\t\t\t\theight: \"100%\",\n\t\t\t\t\twidth: \"100%\",\n\t\t\t\t\tposition: \"relative\",\n\t\t\t\t\toverflow: \"hidden\",\n\t\t\t\t}}\n\t\t\t>\n\t\t\t\t<div\n\t\t\t\t\tstyle={{ height: \"100%\", width: \"100%\", display: \"flex\", animation }}\n\t\t\t\t>\n\t\t\t\t\t{element}\n\t\t\t\t</div>\n\t\t\t</div>\n\t\t);\n\t}\n\t// --------- Animations End ---------\n\n\tif (props.errorBoundary === false) {\n\t\treturn <>{element}</>;\n\t}\n\n\tif (props.errorBoundary) {\n\t\treturn (\n\t\t\t<ErrorBoundary fallback={props.errorBoundary}>{element}</ErrorBoundary>\n\t\t);\n\t}\n\n\treturn (\n\t\t<ErrorBoundary\n\t\t\tfallback={(error) => {\n\t\t\t\tconst result = state.onError(error, state); // TODO: onError is not refreshed\n\t\t\t\tif (result instanceof Redirection) {\n\t\t\t\t\treturn \"Redirection inside ErrorBoundary is not allowed.\";\n\t\t\t\t}\n\t\t\t\treturn result as ReactNode;\n\t\t\t}}\n\t\t>\n\t\t\t{element}\n\t\t</ErrorBoundary>\n\t);\n};\n\nexport default memo(NestedView);\n\nfunction parseAnimation(\n\tanimationLike: PageAnimation | undefined,\n\tstate: ReactRouterState,\n\ttype: \"enter\" | \"exit\" = \"enter\",\n):\n\t| {\n\t\t\tduration: number;\n\t\t\tanimation: string;\n\t }\n\t| undefined {\n\tif (!animationLike) {\n\t\treturn undefined;\n\t}\n\n\tconst DEFAULT_DURATION = 300;\n\n\tconst animation =\n\t\ttypeof animationLike === \"function\" ? animationLike(state) : animationLike;\n\n\tif (typeof animation === \"string\") {\n\t\tif (type === \"exit\") {\n\t\t\treturn;\n\t\t}\n\t\treturn {\n\t\t\tduration: DEFAULT_DURATION,\n\t\t\tanimation: `${DEFAULT_DURATION}ms ${animation}`,\n\t\t};\n\t}\n\n\tif (typeof animation === \"object\") {\n\t\tconst anim = animation[type];\n\t\tconst duration =\n\t\t\ttypeof anim === \"object\"\n\t\t\t\t? (anim.duration ?? DEFAULT_DURATION)\n\t\t\t\t: DEFAULT_DURATION;\n\t\tconst name = typeof anim === \"object\" ? anim.name : anim;\n\n\t\tif (type === \"exit\") {\n\t\t\tconst timing = typeof anim === \"object\" ? (anim.timing ?? \"\") : \"\";\n\t\t\treturn {\n\t\t\t\tduration,\n\t\t\t\tanimation: `${duration}ms ${timing} ${name}`,\n\t\t\t};\n\t\t}\n\n\t\tconst timing = typeof anim === \"object\" ? (anim.timing ?? \"\") : \"\";\n\n\t\treturn {\n\t\t\tduration,\n\t\t\tanimation: `${duration}ms ${timing} ${name}`,\n\t\t};\n\t}\n\n\treturn undefined;\n}\n","import type { CSSProperties } from \"react\";\n\nexport default function NotFoundPage(props: { style?: CSSProperties }) {\n\treturn (\n\t\t<div\n\t\t\tstyle={{\n\t\t\t\theight: \"100vh\",\n\t\t\t\tdisplay: \"flex\",\n\t\t\t\tflexDirection: \"column\",\n\t\t\t\tjustifyContent: \"center\",\n\t\t\t\talignItems: \"center\",\n\t\t\t\ttextAlign: \"center\",\n\t\t\t\tfontFamily: \"sans-serif\",\n\t\t\t\tpadding: \"1rem\",\n\t\t\t\t...props.style,\n\t\t\t}}\n\t\t>\n\t\t\t<h1 style={{ fontSize: \"1rem\", marginBottom: \"0.5rem\" }}>\n\t\t\t\t404 - This page does not exist\n\t\t\t</h1>\n\t\t</div>\n\t);\n}\n","import {\n\t$env,\n\t$hook,\n\t$inject,\n\tAlepha,\n\ttype Static,\n\ttype TSchema,\n\tt,\n} from \"@alepha/core\";\nimport { $logger } from \"@alepha/logger\";\nimport { createElement, type ReactNode, StrictMode } from \"react\";\nimport ClientOnly from \"../components/ClientOnly.tsx\";\nimport ErrorViewer from \"../components/ErrorViewer.tsx\";\nimport NestedView from \"../components/NestedView.tsx\";\nimport NotFoundPage from \"../components/NotFound.tsx\";\nimport { AlephaContext } from \"../contexts/AlephaContext.ts\";\nimport { RouterLayerContext } from \"../contexts/RouterLayerContext.ts\";\nimport {\n\t$page,\n\ttype ErrorHandler,\n\ttype PageDescriptor,\n\ttype PageDescriptorOptions,\n} from \"../descriptors/$page.ts\";\nimport { Redirection } from \"../errors/Redirection.ts\";\n\nconst envSchema = t.object({\n\tREACT_STRICT_MODE: t.boolean({ default: true }),\n});\n\ndeclare module \"@alepha/core\" {\n\texport interface Env extends Partial<Static<typeof envSchema>> {}\n}\n\nexport class ReactPageProvider {\n\tprotected readonly log = $logger();\n\tprotected readonly env = $env(envSchema);\n\tprotected readonly alepha = $inject(Alepha);\n\tprotected readonly pages: PageRoute[] = [];\n\n\tpublic getPages(): PageRoute[] {\n\t\treturn this.pages;\n\t}\n\n\tpublic page(name: string): PageRoute {\n\t\tfor (const page of this.pages) {\n\t\t\tif (page.name === name) {\n\t\t\t\treturn page;\n\t\t\t}\n\t\t}\n\n\t\tthrow new Error(`Page ${name} not found`);\n\t}\n\n\tpublic pathname(\n\t\tname: string,\n\t\toptions: {\n\t\t\tparams?: Record<string, string>;\n\t\t\tquery?: Record<string, string>;\n\t\t} = {},\n\t) {\n\t\tconst page = this.page(name);\n\t\tif (!page) {\n\t\t\tthrow new Error(`Page ${name} not found`);\n\t\t}\n\n\t\tlet url = page.path ?? \"\";\n\t\tlet parent = page.parent;\n\t\twhile (parent) {\n\t\t\turl = `${parent.path ?? \"\"}/${url}`;\n\t\t\tparent = parent.parent;\n\t\t}\n\n\t\turl = this.compile(url, options.params ?? {});\n\n\t\tif (options.query) {\n\t\t\tconst query = new URLSearchParams(options.query);\n\t\t\tif (query.toString()) {\n\t\t\t\turl += `?${query.toString()}`;\n\t\t\t}\n\t\t}\n\n\t\treturn url.replace(/\\/\\/+/g, \"/\") || \"/\";\n\t}\n\n\tpublic url(\n\t\tname: string,\n\t\toptions: { params?: Record<string, string>; host?: string } = {},\n\t): URL {\n\t\treturn new URL(\n\t\t\tthis.pathname(name, options),\n\t\t\t// use provided base or default to http://localhost\n\t\t\toptions.host ?? `http://localhost`,\n\t\t);\n\t}\n\n\tpublic root(state: ReactRouterState): ReactNode {\n\t\tconst root = createElement(\n\t\t\tAlephaContext.Provider,\n\t\t\t{ value: this.alepha },\n\t\t\tcreateElement(NestedView, {}, state.layers[0]?.element),\n\t\t);\n\n\t\tif (this.env.REACT_STRICT_MODE) {\n\t\t\treturn createElement(StrictMode, {}, root);\n\t\t}\n\n\t\treturn root;\n\t}\n\n\tprotected convertStringObjectToObject = (\n\t\tschema?: TSchema,\n\t\tvalue?: any,\n\t): any => {\n\t\tif (t.schema.isObject(schema) && typeof value === \"object\") {\n\t\t\tfor (const key in schema.properties) {\n\t\t\t\tif (\n\t\t\t\t\tt.schema.isObject(schema.properties[key]) &&\n\t\t\t\t\ttypeof value[key] === \"string\"\n\t\t\t\t) {\n\t\t\t\t\ttry {\n\t\t\t\t\t\tvalue[key] = this.alepha.parse(\n\t\t\t\t\t\t\tschema.properties[key],\n\t\t\t\t\t\t\tdecodeURIComponent(value[key]),\n\t\t\t\t\t\t);\n\t\t\t\t\t} catch (e) {\n\t\t\t\t\t\t// ignore\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t\treturn value;\n\t};\n\n\t/**\n\t * Create a new RouterState based on a given route and request.\n\t * This method resolves the layers for the route, applying any query and params schemas defined in the route.\n\t * It also handles errors and redirects.\n\t */\n\tpublic async createLayers(\n\t\troute: PageRoute,\n\t\tstate: ReactRouterState,\n\t\tprevious: PreviousLayerData[] = [],\n\t): Promise<CreateLayersResult> {\n\t\tlet context: Record<string, any> = {}; // all props\n\t\tconst stack: Array<RouterStackItem> = [{ route }]; // stack of routes\n\n\t\tlet parent = route.parent;\n\t\twhile (parent) {\n\t\t\tstack.unshift({ route: parent });\n\t\t\tparent = parent.parent;\n\t\t}\n\n\t\tlet forceRefresh = false;\n\n\t\tfor (let i = 0; i < stack.length; i++) {\n\t\t\tconst it = stack[i];\n\t\t\tconst route = it.route;\n\t\t\tconst config: Record<string, any> = {};\n\n\t\t\ttry {\n\t\t\t\tthis.convertStringObjectToObject(route.schema?.query, state.query);\n\t\t\t\tconfig.query = route.schema?.query\n\t\t\t\t\t? this.alepha.parse(route.schema.query, state.query)\n\t\t\t\t\t: {};\n\t\t\t} catch (e) {\n\t\t\t\tit.error = e as Error;\n\t\t\t\tbreak;\n\t\t\t}\n\n\t\t\ttry {\n\t\t\t\tconfig.params = route.schema?.params\n\t\t\t\t\t? this.alepha.parse(route.schema.params, state.params)\n\t\t\t\t\t: {};\n\t\t\t} catch (e) {\n\t\t\t\tit.error = e as Error;\n\t\t\t\tbreak;\n\t\t\t}\n\n\t\t\t// save config\n\t\t\tit.config = {\n\t\t\t\t...config,\n\t\t\t};\n\n\t\t\t// check if previous layer is the same, reuse if possible\n\t\t\tif (previous?.[i] && !forceRefresh && previous[i].name === route.name) {\n\t\t\t\tconst url = (str?: string) => (str ? str.replace(/\\/\\/+/g, \"/\") : \"/\");\n\n\t\t\t\tconst prev = JSON.stringify({\n\t\t\t\t\tpart: url(previous[i].part),\n\t\t\t\t\tparams: previous[i].config?.params ?? {},\n\t\t\t\t});\n\n\t\t\t\tconst curr = JSON.stringify({\n\t\t\t\t\tpart: url(route.path),\n\t\t\t\t\tparams: config.params ?? {},\n\t\t\t\t});\n\n\t\t\t\tif (prev === curr) {\n\t\t\t\t\t// part is the same, reuse previous layer\n\t\t\t\t\tit.props = previous[i].props;\n\t\t\t\t\tit.error = previous[i].error;\n\t\t\t\t\tit.cache = true;\n\t\t\t\t\tcontext = {\n\t\t\t\t\t\t...context,\n\t\t\t\t\t\t...it.props,\n\t\t\t\t\t};\n\t\t\t\t\tcontinue;\n\t\t\t\t}\n\n\t\t\t\t// part is different, force refresh of next layers\n\t\t\t\tforceRefresh = true;\n\t\t\t}\n\n\t\t\t// no resolve, render a basic view by default\n\t\t\tif (!route.resolve) {\n\t\t\t\tcontinue;\n\t\t\t}\n\n\t\t\ttry {\n\t\t\t\tconst args = Object.create(state);\n\t\t\t\tObject.assign(args, config, context);\n\t\t\t\tconst props = (await route.resolve?.(args)) ?? {};\n\n\t\t\t\t// save props\n\t\t\t\tit.props = {\n\t\t\t\t\t...props,\n\t\t\t\t};\n\n\t\t\t\t// add props to context\n\t\t\t\tcontext = {\n\t\t\t\t\t...context,\n\t\t\t\t\t...props,\n\t\t\t\t};\n\t\t\t} catch (e) {\n\t\t\t\t// check if we need to redirect\n\t\t\t\tif (e instanceof Redirection) {\n\t\t\t\t\treturn {\n\t\t\t\t\t\tredirect: e.redirect,\n\t\t\t\t\t};\n\t\t\t\t}\n\n\t\t\t\tthis.log.error(\"Page resolver has failed\", e);\n\n\t\t\t\tit.error = e as Error;\n\t\t\t\tbreak;\n\t\t\t}\n\t\t}\n\n\t\tlet acc = \"\";\n\t\tfor (let i = 0; i < stack.length; i++) {\n\t\t\tconst it = stack[i];\n\t\t\tconst props = it.props ?? {};\n\n\t\t\tconst params = { ...it.config?.params };\n\t\t\tfor (const key of Object.keys(params)) {\n\t\t\t\tparams[key] = String(params[key]);\n\t\t\t}\n\n\t\t\tacc += \"/\";\n\t\t\tacc += it.route.path ? this.compile(it.route.path, params) : \"\";\n\t\t\tconst path = acc.replace(/\\/+/, \"/\");\n\t\t\tconst localErrorHandler = this.getErrorHandler(it.route);\n\t\t\tif (localErrorHandler) {\n\t\t\t\tconst onErrorParent = state.onError;\n\t\t\t\tstate.onError = (error, context) => {\n\t\t\t\t\tconst result = localErrorHandler(error, context);\n\t\t\t\t\t// if nothing happen, call the parent\n\t\t\t\t\tif (result === undefined) {\n\t\t\t\t\t\treturn onErrorParent(error, context);\n\t\t\t\t\t}\n\t\t\t\t\treturn result;\n\t\t\t\t};\n\t\t\t}\n\n\t\t\t// normal use case\n\t\t\tif (!it.error) {\n\t\t\t\ttry {\n\t\t\t\t\tconst element = await this.createElement(it.route, {\n\t\t\t\t\t\t...props,\n\t\t\t\t\t\t...context,\n\t\t\t\t\t});\n\n\t\t\t\t\tstate.layers.push({\n\t\t\t\t\t\tname: it.route.name,\n\t\t\t\t\t\tprops,\n\t\t\t\t\t\tpart: it.route.path,\n\t\t\t\t\t\tconfig: it.config,\n\t\t\t\t\t\telement: this.renderView(i + 1, path, element, it.route),\n\t\t\t\t\t\tindex: i + 1,\n\t\t\t\t\t\tpath,\n\t\t\t\t\t\troute: it.route,\n\t\t\t\t\t\tcache: it.cache,\n\t\t\t\t\t});\n\t\t\t\t} catch (e) {\n\t\t\t\t\tit.error = e as Error;\n\t\t\t\t}\n\t\t\t}\n\n\t\t\t// handler has thrown an error, render an error view\n\t\t\tif (it.error) {\n\t\t\t\ttry {\n\t\t\t\t\tlet element: ReactNode | Redirection | undefined =\n\t\t\t\t\t\tawait state.onError(it.error, state);\n\n\t\t\t\t\tif (element === undefined) {\n\t\t\t\t\t\tthrow it.error;\n\t\t\t\t\t}\n\n\t\t\t\t\tif (element instanceof Redirection) {\n\t\t\t\t\t\treturn {\n\t\t\t\t\t\t\tredirect: element.redirect,\n\t\t\t\t\t\t};\n\t\t\t\t\t}\n\n\t\t\t\t\tif (element === null) {\n\t\t\t\t\t\telement = this.renderError(it.error);\n\t\t\t\t\t}\n\n\t\t\t\t\tstate.layers.push({\n\t\t\t\t\t\tprops,\n\t\t\t\t\t\terror: it.error,\n\t\t\t\t\t\tname: it.route.name,\n\t\t\t\t\t\tpart: it.route.path,\n\t\t\t\t\t\tconfig: it.config,\n\t\t\t\t\t\telement: this.renderView(i + 1, path, element, it.route),\n\t\t\t\t\t\tindex: i + 1,\n\t\t\t\t\t\tpath,\n\t\t\t\t\t\troute: it.route,\n\t\t\t\t\t});\n\t\t\t\t\tbreak;\n\t\t\t\t} catch (e) {\n\t\t\t\t\tif (e instanceof Redirection) {\n\t\t\t\t\t\treturn {\n\t\t\t\t\t\t\tredirect: e.redirect,\n\t\t\t\t\t\t};\n\t\t\t\t\t}\n\t\t\t\t\tthrow e;\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\n\t\treturn { state };\n\t}\n\n\tprotected createRedirectionLayer(redirect: string): CreateLayersResult {\n\t\treturn {\n\t\t\tredirect,\n\t\t};\n\t}\n\n\tprotected getErrorHandler(route: PageRoute): ErrorHandler | undefined {\n\t\tif (route.errorHandler) return route.errorHandler;\n\t\tlet parent = route.parent;\n\t\twhile (parent) {\n\t\t\tif (parent.errorHandler) return parent.errorHandler;\n\t\t\tparent = parent.parent;\n\t\t}\n\t}\n\n\tprotected async createElement(\n\t\tpage: PageRoute,\n\t\tprops: Record<string, any>,\n\t): Promise<ReactNode> {\n\t\tif (page.lazy && page.component) {\n\t\t\tthis.log.warn(\n\t\t\t\t`Page ${page.name} has both lazy and component options, lazy will be used`,\n\t\t\t);\n\t\t}\n\n\t\tif (page.lazy) {\n\t\t\tconst component = await page.lazy(); // load component\n\t\t\treturn createElement(component.default, props);\n\t\t}\n\n\t\tif (page.component) {\n\t\t\treturn createElement(page.component, props);\n\t\t}\n\n\t\treturn undefined;\n\t}\n\n\tpublic renderError(error: Error): ReactNode {\n\t\treturn createElement(ErrorViewer, { error, alepha: this.alepha });\n\t}\n\n\tpublic renderEmptyView(): ReactNode {\n\t\treturn createElement(NestedView, {});\n\t}\n\n\tpublic href(\n\t\tpage: { options: { name?: string } },\n\t\tparams: Record<string, any> = {},\n\t): string {\n\t\tconst found = this.pages.find((it) => it.name === page.options.name);\n\t\tif (!found) {\n\t\t\tthrow new Error(`Page ${page.options.name} not found`);\n\t\t}\n\n\t\tlet url = found.path ?? \"\";\n\t\tlet parent = found.parent;\n\t\twhile (parent) {\n\t\t\turl = `${parent.path ?? \"\"}/${url}`;\n\t\t\tparent = parent.parent;\n\t\t}\n\n\t\turl = this.compile(url, params);\n\n\t\treturn url.replace(/\\/\\/+/g, \"/\") || \"/\";\n\t}\n\n\tpublic compile(path: string, params: Record<string, string> = {}) {\n\t\tfor (const [key, value] of Object.entries(params)) {\n\t\t\tpath = path.replace(`:${key}`, value);\n\t\t}\n\t\treturn path;\n\t}\n\n\tprotected renderView(\n\t\tindex: number,\n\t\tpath: string,\n\t\tview: ReactNode | undefined,\n\t\tpage: PageRoute,\n\t): ReactNode {\n\t\tview ??= this.renderEmptyView();\n\n\t\tconst element = page.client\n\t\t\t? createElement(\n\t\t\t\t\tClientOnly,\n\t\t\t\t\ttypeof page.client === \"object\" ? page.client : {},\n\t\t\t\t\tview,\n\t\t\t\t)\n\t\t\t: view;\n\n\t\treturn createElement(\n\t\t\tRouterLayerContext.Provider,\n\t\t\t{\n\t\t\t\tvalue: {\n\t\t\t\t\tindex,\n\t\t\t\t\tpath,\n\t\t\t\t},\n\t\t\t},\n\t\t\telement,\n\t\t);\n\t}\n\n\tprotected readonly configure = $hook({\n\t\ton: \"configure\",\n\t\thandler: () => {\n\t\t\tlet hasNotFoundHandler = false;\n\t\t\tconst pages = this.alepha.descriptors($page);\n\n\t\t\tconst hasParent = (it: PageDescriptor) => {\n\t\t\t\tif (it.options.parent) {\n\t\t\t\t\treturn true;\n\t\t\t\t}\n\n\t\t\t\tfor (const page of pages) {\n\t\t\t\t\tconst children = page.options.children\n\t\t\t\t\t\t? Array.isArray(page.options.children)\n\t\t\t\t\t\t\t? page.options.children\n\t\t\t\t\t\t\t: page.options.children()\n\t\t\t\t\t\t: [];\n\t\t\t\t\tif (children.includes(it)) {\n\t\t\t\t\t\treturn true;\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t};\n\n\t\t\tfor (const page of pages) {\n\t\t\t\tif (page.options.path === \"/*\") {\n\t\t\t\t\thasNotFoundHandler = true;\n\t\t\t\t}\n\n\t\t\t\t// skip children, we only want root pages\n\t\t\t\tif (hasParent(page)) {\n\t\t\t\t\tcontinue;\n\t\t\t\t}\n\n\t\t\t\tthis.add(this.map(pages, page));\n\t\t\t}\n\n\t\t\tif (!hasNotFoundHandler && pages.length > 0) {\n\t\t\t\t// add a default 404 page if not already defined\n\t\t\t\tthis.add({\n\t\t\t\t\tpath: \"/*\",\n\t\t\t\t\tname: \"notFound\",\n\t\t\t\t\tcache: true,\n\t\t\t\t\tcomponent: NotFoundPage,\n\t\t\t\t\tonServerResponse: ({ reply }) => {\n\t\t\t\t\t\treply.status = 404;\n\t\t\t\t\t},\n\t\t\t\t});\n\t\t\t}\n\t\t},\n\t});\n\n\tprotected map(\n\t\tpages: Array<PageDescriptor>,\n\t\ttarget: PageDescriptor,\n\t): PageRouteEntry {\n\t\tconst children = target.options.children\n\t\t\t? Array.isArray(target.options.children)\n\t\t\t\t? target.options.children\n\t\t\t\t: target.options.children()\n\t\t\t: [];\n\n\t\tconst getChildrenFromParent = (it: PageDescriptor): PageDescriptor[] => {\n\t\t\tconst children = [];\n\t\t\tfor (const page of pages) {\n\t\t\t\tif (page.options.parent === it) {\n\t\t\t\t\tchildren.push(page);\n\t\t\t\t}\n\t\t\t}\n\t\t\treturn children;\n\t\t};\n\n\t\tchildren.push(...getChildrenFromParent(target));\n\n\t\treturn {\n\t\t\t...target.options,\n\t\t\tname: target.name,\n\t\t\tparent: undefined,\n\t\t\tchildren: children.map((it) => this.map(pages, it)),\n\t\t} as PageRoute;\n\t}\n\n\tpublic add(entry: PageRouteEntry) {\n\t\tif (this.alepha.isReady()) {\n\t\t\tthrow new Error(\"Router is already initialized\");\n\t\t}\n\n\t\tentry.name ??= this.nextId();\n\t\tconst page = entry as PageRoute;\n\n\t\tpage.match = this.createMatch(page);\n\t\tthis.pages.push(page);\n\n\t\tif (page.children) {\n\t\t\tfor (const child of page.children) {\n\t\t\t\t(child as PageRoute).parent = page;\n\t\t\t\tthis.add(child);\n\t\t\t}\n\t\t}\n\t}\n\n\tprotected createMatch(page: PageRoute): string {\n\t\tlet url = page.path ?? \"/\";\n\t\tlet target = page.parent;\n\t\twhile (target) {\n\t\t\turl = `${target.path ?? \"\"}/${url}`;\n\t\t\ttarget = target.parent;\n\t\t}\n\n\t\tlet path = url.replace(/\\/\\/+/g, \"/\");\n\n\t\tif (path.endsWith(\"/\") && path !== \"/\") {\n\t\t\t// remove trailing slash\n\t\t\tpath = path.slice(0, -1);\n\t\t}\n\n\t\treturn path;\n\t}\n\n\tprotected _next = 0;\n\n\tprotected nextId(): string {\n\t\tthis._next += 1;\n\t\treturn `P${this._next}`;\n\t}\n}\n\nexport const isPageRoute = (it: any): it is PageRoute => {\n\treturn (\n\t\tit &&\n\t\ttypeof it === \"object\" &&\n\t\ttypeof it.path === \"string\" &&\n\t\ttypeof it.page === \"object\"\n\t);\n};\n\nexport interface PageRouteEntry\n\textends Omit<PageDescriptorOptions, \"children\" | \"parent\"> {\n\tchildren?: PageRouteEntry[];\n}\n\nexport interface PageRoute extends PageRouteEntry {\n\ttype: \"page\";\n\tname: string;\n\tparent?: PageRoute;\n\tmatch: string;\n}\n\nexport interface Layer {\n\tconfig?: {\n\t\tquery?: Record<string, any>;\n\t\tparams?: Record<string, any>;\n\t\t// stack of resolved props\n\t\tcontext?: Record<string, any>;\n\t};\n\n\tname: string;\n\tprops?: Record<string, any>;\n\terror?: Error;\n\tpart?: string;\n\telement: ReactNode;\n\tindex: number;\n\tpath: string;\n\troute?: PageRoute;\n\tcache?: boolean;\n}\n\nexport type PreviousLayerData = Omit<Layer, \"element\" | \"index\" | \"path\">;\n\nexport interface AnchorProps {\n\thref: string;\n\tonClick: (ev?: any) => any;\n}\n\nexport interface ReactRouterState {\n\t/**\n\t * Stack of layers for the current page.\n\t */\n\tlayers: Array<Layer>;\n\n\t/**\n\t * URL of the current page.\n\t */\n\turl: URL;\n\n\t/**\n\t * Error handler for the current page.\n\t */\n\tonError: ErrorHandler;\n\n\t/**\n\t * Params extracted from the URL for the current page.\n\t */\n\tparams: Record<string, any>;\n\n\t/**\n\t * Query parameters extracted from the URL for the current page.\n\t */\n\tquery: Record<string, string>;\n\n\t/**\n\t * Optional meta information associated with the current page.\n\t */\n\tmeta: Record<string, any>;\n}\n\nexport interface RouterStackItem {\n\troute: PageRoute;\n\tconfig?: Record<string, any>;\n\tprops?: Record<string, any>;\n\terror?: Error;\n\tcache?: boolean;\n}\n\nexport interface TransitionOptions {\n\tprevious?: PreviousLayerData[];\n}\n\nexport interface CreateLayersResult {\n\tredirect?: string;\n\tstate?: ReactRouterState;\n}\n","import { existsSync } from \"node:fs\";\nimport { join } from \"node:path\";\nimport {\n\t$env,\n\t$hook,\n\t$inject,\n\tAlepha,\n\tAlephaError,\n\ttype Static,\n\tt,\n} from \"@alepha/core\";\nimport { $logger } from \"@alepha/logger\";\nimport {\n\ttype ServerHandler,\n\tServerProvider,\n\tServerRouterProvider,\n\tServerTimingProvider,\n} from \"@alepha/server\";\nimport { ServerLinksProvider } from \"@alepha/server-links\";\nimport { ServerStaticProvider } from \"@alepha/server-static\";\nimport { renderToString } from \"react-dom/server\";\nimport {\n\t$page,\n\ttype PageDescriptorRenderOptions,\n\ttype PageDescriptorRenderResult,\n} from \"../descriptors/$page.ts\";\nimport { Redirection } from \"../errors/Redirection.ts\";\nimport type { ReactHydrationState } from \"./ReactBrowserProvider.ts\";\nimport {\n\ttype PageRoute,\n\tReactPageProvider,\n\ttype ReactRouterState,\n} from \"./ReactPageProvider.ts\";\n\nconst envSchema = t.object({\n\tREACT_SERVER_DIST: t.text({ default: \"public\" }),\n\tREACT_SERVER_PREFIX: t.text({ default: \"\" }),\n\tREACT_SSR_ENABLED: t.optional(t.boolean()),\n\tREACT_ROOT_ID: t.text({ default: \"root\" }),\n\tREACT_SERVER_TEMPLATE: t.optional(\n\t\tt.text({\n\t\t\tsize: \"rich\",\n\t\t}),\n\t),\n});\n\ndeclare module \"@alepha/core\" {\n\tinterface Env extends Partial<Static<typeof envSchema>> {}\n\tinterface State {\n\t\t\"react.server.ssr\"?: boolean;\n\t}\n}\n\nexport class ReactServerProvider {\n\tprotected readonly log = $logger();\n\tprotected readonly alepha = $inject(Alepha);\n\tprotected readonly pageApi = $inject(ReactPageProvider);\n\tprotected readonly serverProvider = $inject(ServerProvider);\n\tprotected readonly serverStaticProvider = $inject(ServerStaticProvider);\n\tprotected readonly serverRouterProvider = $inject(ServerRouterProvider);\n\tprotected readonly serverTimingProvider = $inject(ServerTimingProvider);\n\tprotected readonly env = $env(envSchema);\n\tprotected readonly ROOT_DIV_REGEX = new RegExp(\n\t\t`<div([^>]*)\\\\s+id=[\"']${this.env.REACT_ROOT_ID}[\"']([^>]*)>(.*?)<\\\\/div>`,\n\t\t\"is\",\n\t);\n\tprotected preprocessedTemplate: PreprocessedTemplate | null = null;\n\n\tpublic readonly onConfigure = $hook({\n\t\ton: \"configure\",\n\t\thandler: async () => {\n\t\t\tconst pages = this.alepha.descriptors($page);\n\n\t\t\tconst ssrEnabled =\n\t\t\t\tpages.length > 0 && this.env.REACT_SSR_ENABLED !== false;\n\n\t\t\tthis.alepha.state.set(\"react.server.ssr\", ssrEnabled);\n\n\t\t\tfor (const page of pages) {\n\t\t\t\tpage.render = this.createRenderFunction(page.name);\n\t\t\t\tpage.fetch = async (options) => {\n\t\t\t\t\tconst response = await fetch(\n\t\t\t\t\t\t`${this.serverProvider.hostname}/${page.pathname(options)}`,\n\t\t\t\t\t);\n\t\t\t\t\tconst html = await response.text();\n\t\t\t\t\tif (options?.html) return { html, response };\n\t\t\t\t\t// take only text inside the root div\n\t\t\t\t\tconst match = html.match(this.ROOT_DIV_REGEX);\n\t\t\t\t\tif (match) {\n\t\t\t\t\t\treturn { html: match[3], response };\n\t\t\t\t\t}\n\t\t\t\t\tthrow new AlephaError(\"Invalid HTML response\");\n\t\t\t\t};\n\t\t\t}\n\n\t\t\t// development mode\n\t\t\tif (this.alepha.isServerless() === \"vite\") {\n\t\t\t\tawait this.configureVite(ssrEnabled);\n\t\t\t\treturn;\n\t\t\t}\n\n\t\t\t// production mode\n\t\t\tlet root = \"\";\n\n\t\t\t// non-serverless mode only -> serve static files\n\t\t\tif (!this.alepha.isServerless()) {\n\t\t\t\troot = this.getPublicDirectory();\n\t\t\t\tif (!root) {\n\t\t\t\t\tthis.log.warn(\n\t\t\t\t\t\t\"Missing static files, static file server will be disabled\",\n\t\t\t\t\t);\n\t\t\t\t} else {\n\t\t\t\t\tthis.log.debug(`Using static files from: ${root}`);\n\t\t\t\t\tawait this.configureStaticServer(root);\n\t\t\t\t}\n\t\t\t}\n\n\t\t\tif (ssrEnabled) {\n\t\t\t\tawait this.registerPages(async () => this.template);\n\t\t\t\tthis.log.info(\"SSR OK\");\n\t\t\t\treturn;\n\t\t\t}\n\n\t\t\t// no SSR enabled, serve index.html for all unmatched routes\n\t\t\tthis.log.info(\"SSR is disabled, use History API fallback\");\n\t\t\tthis.serverRouterProvider.createRoute({\n\t\t\t\tpath: \"*\",\n\t\t\t\thandler: async ({ url, reply }) => {\n\t\t\t\t\tif (url.pathname.includes(\".\")) {\n\t\t\t\t\t\t// If the request is for a file (e.g., /style.css), do not fallback\n\t\t\t\t\t\treply.headers[\"content-type\"] = \"text/plain\";\n\t\t\t\t\t\treply.body = \"Not Found\";\n\t\t\t\t\t\treply.status = 404;\n\t\t\t\t\t\treturn;\n\t\t\t\t\t}\n\n\t\t\t\t\treply.headers[\"content-type\"] = \"text/html\";\n\n\t\t\t\t\t// serve index.html for all unmatched routes\n\t\t\t\t\treturn this.template;\n\t\t\t\t},\n\t\t\t});\n\t\t},\n\t});\n\n\tpublic get template() {\n\t\treturn (\n\t\t\tthis.alepha.env.REACT_SERVER_TEMPLATE ??\n\t\t\t\"<!DOCTYPE html><html lang='en'><head></head><body></body></html>\"\n\t\t);\n\t}\n\n\tprotected async registerPages(templateLoader: TemplateLoader) {\n\t\t// Preprocess template once\n\t\tconst template = await templateLoader();\n\t\tif (template) {\n\t\t\tthis.preprocessedTemplate = this.preprocessTemplate(template);\n\t\t}\n\n\t\tfor (const page of this.pageApi.getPages()) {\n\t\t\tif (page.children?.length) {\n\t\t\t\tcontinue;\n\t\t\t}\n\n\t\t\tthis.log.debug(`+ ${page.match} -> ${page.name}`);\n\n\t\t\tthis.serverRouterProvider.createRoute({\n\t\t\t\t...page,\n\t\t\t\tschema: undefined, // schema is handled by the page descriptor provider for now (shared by browser and server)\n\t\t\t\tmethod: \"GET\",\n\t\t\t\tpath: page.match,\n\t\t\t\thandler: this.createHandler(page, templateLoader),\n\t\t\t});\n\t\t}\n\t}\n\n\tprotected getPublicDirectory(): string {\n\t\tconst maybe = [\n\t\t\tjoin(process.cwd(), `dist/${this.env.REACT_SERVER_DIST}`),\n\t\t\tjoin(process.cwd(), this.env.REACT_SERVER_DIST),\n\t\t];\n\n\t\tfor (const it of maybe) {\n\t\t\tif (existsSync(it)) {\n\t\t\t\treturn it;\n\t\t\t}\n\t\t}\n\n\t\treturn \"\";\n\t}\n\n\tprotected async configureStaticServer(root: string) {\n\t\tawait this.serverStaticProvider.createStaticServer({\n\t\t\troot,\n\t\t\tpath: this.env.REACT_SERVER_PREFIX,\n\t\t});\n\t}\n\n\tprotected async configureVite(ssrEnabled: boolean) {\n\t\tif (!ssrEnabled) {\n\t\t\t// do nothing, vite will handle everything for us\n\t\t\treturn;\n\t\t}\n\n\t\tthis.log.info(\"SSR (vite) OK\");\n\n\t\tconst url = `http://${process.env.SERVER_HOST}:${process.env.SERVER_PORT}`;\n\n\t\tawait this.registerPages(() =>\n\t\t\tfetch(`${url}/index.html`)\n\t\t\t\t.then((it) => it.text())\n\t\t\t\t.catch(() => undefined),\n\t\t);\n\t}\n\n\t/**\n\t * For testing purposes, creates a render function that can be used.\n\t */\n\tprotected createRenderFunction(name: string, withIndex = false) {\n\t\treturn async (\n\t\t\toptions: PageDescriptorRenderOptions = {},\n\t\t): Promise<PageDescriptorRenderResult> => {\n\t\t\tconst page = this.pageApi.page(name);\n\t\t\tconst url = new URL(this.pageApi.url(name, options));\n\n\t\t\tconst entry: Partial<ReactRouterState> = {\n\t\t\t\turl,\n\t\t\t\tparams: options.params ?? {},\n\t\t\t\tquery: options.query ?? {},\n\t\t\t\tonError: () => null,\n\t\t\t\tlayers: [],\n\t\t\t\tmeta: {},\n\t\t\t};\n\n\t\t\tconst state = entry as ReactRouterState;\n\n\t\t\tthis.log.trace(\"Rendering\", {\n\t\t\t\turl,\n\t\t\t});\n\n\t\t\tawait this.alepha.events.emit(\"react:server:render:begin\", {\n\t\t\t\tstate,\n\t\t\t});\n\n\t\t\tconst { redirect } = await this.pageApi.createLayers(\n\t\t\t\tpage,\n\t\t\t\tstate as ReactRouterState,\n\t\t\t);\n\n\t\t\tif (redirect) {\n\t\t\t\treturn { state, html: \"\", redirect };\n\t\t\t}\n\n\t\t\tif (!withIndex && !options.html) {\n\t\t\t\tthis.alepha.state.set(\"react.router.state\", state);\n\n\t\t\t\treturn {\n\t\t\t\t\tstate,\n\t\t\t\t\thtml: renderToString(this.pageApi.root(state)),\n\t\t\t\t};\n\t\t\t}\n\n\t\t\tconst template = this.template ?? \"\";\n\t\t\tconst html = this.renderToHtml(template, state, options.hydration);\n\n\t\t\tif (html instanceof Redirection) {\n\t\t\t\treturn { state, html: \"\", redirect };\n\t\t\t}\n\n\t\t\tconst result = {\n\t\t\t\tstate,\n\t\t\t\thtml,\n\t\t\t};\n\n\t\t\tawait this.alepha.events.emit(\"react:server:render:end\", result);\n\n\t\t\treturn result;\n\t\t};\n\t}\n\n\tprotected createHandler(\n\t\troute: PageRoute,\n\t\ttemplateLoader: TemplateLoader,\n\t): ServerHandler {\n\t\treturn async (serverRequest) => {\n\t\t\tconst { url, reply, query, params } = serverRequest;\n\t\t\tconst template = await templateLoader();\n\t\t\tif (!template) {\n\t\t\t\tthrow new Error(\"Template not found\");\n\t\t\t}\n\n\t\t\tthis.log.trace(\"Rendering page\", {\n\t\t\t\tname: route.name,\n\t\t\t});\n\n\t\t\tconst entry: Partial<ReactRouterState> = {\n\t\t\t\turl,\n\t\t\t\tparams,\n\t\t\t\tquery,\n\t\t\t\tonError: () => null,\n\t\t\t\tlayers: [],\n\t\t\t};\n\n\t\t\tconst state = entry as ReactRouterState;\n\n\t\t\tif (this.alepha.has(ServerLinksProvider)) {\n\t\t\t\tthis.alepha.state.set(\n\t\t\t\t\t\"api\",\n\t\t\t\t\tawait this.alepha.inject(ServerLinksProvider).getUserApiLinks({\n\t\t\t\t\t\tuser: (serverRequest as any).user, // TODO: fix type\n\t\t\t\t\t\tauthorization: serverRequest.headers.authorization,\n\t\t\t\t\t}),\n\t\t\t\t);\n\t\t\t}\n\n\t\t\tlet target: PageRoute | undefined = route; // TODO: move to PageDescriptorProvider\n\t\t\twhile (target) {\n\t\t\t\tif (route.can && !route.can()) {\n\t\t\t\t\t// if the page is not accessible, return 403\n\t\t\t\t\treply.status = 403;\n\t\t\t\t\treply.headers[\"content-type\"] = \"text/plain\";\n\t\t\t\t\treturn \"Forbidden\";\n\t\t\t\t}\n\t\t\t\ttarget = target.parent;\n\t\t\t}\n\n\t\t\t// TODO: SSR strategies\n\t\t\t// - only when googlebot\n\t\t\t// - only child pages\n\t\t\t// if (page.client) {\n\t\t\t// \t// if the page is a client-only page, return 404\n\t\t\t// \treply.status = 200;\n\t\t\t// \treply.headers[\"content-type\"] = \"text/html\";\n\t\t\t// \treply.body = template;\n\t\t\t// \treturn;\n\t\t\t// }\n\n\t\t\tawait this.alepha.events.emit(\"react:server:render:begin\", {\n\t\t\t\trequest: serverRequest,\n\t\t\t\tstate,\n\t\t\t});\n\n\t\t\tthis.serverTimingProvider.beginTiming(\"createLayers\");\n\n\t\t\tconst { redirect } = await this.pageApi.createLayers(route, state);\n\n\t\t\tthis.serverTimingProvider.endTiming(\"createLayers\");\n\n\t\t\tif (redirect) {\n\t\t\t\treturn reply.redirect(redirect);\n\t\t\t}\n\n\t\t\treply.headers[\"content-type\"] = \"text/html\";\n\n\t\t\t// by default, disable caching for SSR responses\n\t\t\t// some plugins may override this\n\t\t\treply.headers[\"cache-control\"] =\n\t\t\t\t\"no-store, no-cache, must-revalidate, proxy-revalidate\";\n\t\t\treply.headers.pragma = \"no-cache\";\n\t\t\treply.headers.expires = \"0\";\n\n\t\t\tconst html = this.renderToHtml(template, state);\n\t\t\tif (html instanceof Redirection) {\n\t\t\t\treply.redirect(\n\t\t\t\t\ttypeof html.redirect === \"string\"\n\t\t\t\t\t\t? html.redirect\n\t\t\t\t\t\t: this.pageApi.href(html.redirect),\n\t\t\t\t);\n\t\t\t\treturn;\n\t\t\t}\n\n\t\t\tconst event = {\n\t\t\t\trequest: serverRequest,\n\t\t\t\tstate,\n\t\t\t\thtml,\n\t\t\t};\n\n\t\t\tawait this.alepha.events.emit(\"react:server:render:end\", event);\n\n\t\t\troute.onServerResponse?.(serverRequest);\n\n\t\t\tthis.log.trace(\"Page rendered\", {\n\t\t\t\tname: route.name,\n\t\t\t});\n\n\t\t\treturn event.html;\n\t\t};\n\t}\n\n\tpublic renderToHtml(\n\t\ttemplate: string,\n\t\tstate: ReactRouterState,\n\t\thydration = true,\n\t): string | Redirection {\n\t\tconst element = this.pageApi.root(state);\n\n\t\t// attach react router state to the http request context\n\t\tthis.alepha.state.set(\"react.router.state\", state);\n\n\t\tthis.serverTimingProvider.beginTiming(\"renderToString\");\n\t\tlet app = \"\";\n\t\ttry {\n\t\t\tapp = renderToString(element);\n\t\t} catch (error) {\n\t\t\tthis.log.error(\n\t\t\t\t\"renderToString has failed, fallback to error handler\",\n\t\t\t\terror,\n\t\t\t);\n\t\t\tconst element = state.onError(error as Error, state);\n\t\t\tif (element instanceof Redirection) {\n\t\t\t\t// if the error is a redirection, return the redirection URL\n\t\t\t\treturn element;\n\t\t\t}\n\n\t\t\tapp = renderToString(element);\n\t\t\tthis.log.debug(\"Error handled successfully with fallback\");\n\t\t}\n\t\tthis.serverTimingProvider.endTiming(\"renderToString\");\n\n\t\tconst response = {\n\t\t\thtml: template,\n\t\t};\n\n\t\tif (hydration) {\n\t\t\tconst { request, context, ...store } =\n\t\t\t\tthis.alepha.context.als?.getStore() ?? {}; /// TODO: als must be protected, find a way to iterate on alepha.state\n\n\t\t\tconst hydrationData: ReactHydrationState = {\n\t\t\t\t...store,\n\t\t\t\t// map react.router.state to the hydration state\n\t\t\t\t\"react.router.state\": undefined,\n\t\t\t\tlayers: state.layers.map((it) => ({\n\t\t\t\t\t...it,\n\t\t\t\t\terror: it.error\n\t\t\t\t\t\t? {\n\t\t\t\t\t\t\t\t...it.error,\n\t\t\t\t\t\t\t\tname: it.error.name,\n\t\t\t\t\t\t\t\tmessage: it.error.message,\n\t\t\t\t\t\t\t\tstack: !this.alepha.isProduction() ? it.error.stack : undefined,\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t: undefined,\n\t\t\t\t\tindex: undefined,\n\t\t\t\t\tpath: undefined,\n\t\t\t\t\telement: undefined,\n\t\t\t\t\troute: undefined,\n\t\t\t\t})),\n\t\t\t};\n\n\t\t\t// create hydration data\n\t\t\tconst script = `<script>window.__ssr=${JSON.stringify(hydrationData)}</script>`;\n\n\t\t\t// inject app into template\n\t\t\tthis.fillTemplate(response, app, script);\n\t\t}\n\n\t\treturn response.html;\n\t}\n\n\tprotected preprocessTemplate(template: string): PreprocessedTemplate {\n\t\t// Find the body close tag for script injection\n\t\tconst bodyCloseMatch = template.match(/<\\/body>/i);\n\t\tconst bodyCloseIndex = bodyCloseMatch?.index ?? template.length;\n\n\t\tconst beforeScript = template.substring(0, bodyCloseIndex);\n\t\tconst afterScript = template.substring(bodyCloseIndex);\n\n\t\t// Check if there's an existing root div\n\t\tconst rootDivMatch = beforeScript.match(this.ROOT_DIV_REGEX);\n\n\t\tif (rootDivMatch) {\n\t\t\t// Split around the existing root div content\n\t\t\tconst beforeDiv = beforeScript.substring(0, rootDivMatch.index!);\n\t\t\tconst afterDivStart = rootDivMatch.index! + rootDivMatch[0].length;\n\t\t\tconst afterDiv = beforeScript.substring(afterDivStart);\n\n\t\t\tconst beforeApp = `${beforeDiv}<div${rootDivMatch[1]} id=\"${this.env.REACT_ROOT_ID}\"${rootDivMatch[2]}>`;\n\t\t\tconst afterApp = `</div>${afterDiv}`;\n\n\t\t\treturn { beforeApp, afterApp, beforeScript: \"\", afterScript };\n\t\t}\n\n\t\t// No existing root div, find body tag to inject new div\n\t\tconst bodyMatch = beforeScript.match(/<body([^>]*)>/i);\n\t\tif (bodyMatch) {\n\t\t\tconst beforeBody = beforeScript.substring(\n\t\t\t\t0,\n\t\t\t\tbodyMatch.index! + bodyMatch[0].length,\n\t\t\t);\n\t\t\tconst afterBody = beforeScript.substring(\n\t\t\t\tbodyMatch.index! + bodyMatch[0].length,\n\t\t\t);\n\n\t\t\tconst beforeApp = `${beforeBody}<div id=\"${this.env.REACT_ROOT_ID}\">`;\n\t\t\tconst afterApp = `</div>${afterBody}`;\n\n\t\t\treturn { beforeApp, afterApp, beforeScript: \"\", afterScript };\n\t\t}\n\n\t\t// Fallback: no body tag found, just wrap everything\n\t\treturn {\n\t\t\tbeforeApp: `<div id=\"${this.env.REACT_ROOT_ID}\">`,\n\t\t\tafterApp: `</div>`,\n\t\t\tbeforeScript,\n\t\t\tafterScript,\n\t\t};\n\t}\n\n\tprotected fillTemplate(\n\t\tresponse: { html: string },\n\t\tapp: string,\n\t\tscript: string,\n\t) {\n\t\tif (!this.preprocessedTemplate) {\n\t\t\t// Fallback to old logic if preprocessing failed\n\t\t\tthis.preprocessedTemplate = this.preprocessTemplate(response.html);\n\t\t}\n\n\t\t// Pure concatenation - no regex replacements needed\n\t\tresponse.html =\n\t\t\tthis.preprocessedTemplate.beforeApp +\n\t\t\tapp +\n\t\t\tthis.preprocessedTemplate.afterApp +\n\t\t\tscript +\n\t\t\tthis.preprocessedTemplate.afterScript;\n\t}\n}\n\ntype TemplateLoader = () => Promise<string | undefined>;\n\ninterface PreprocessedTemplate {\n\tbeforeApp: string;\n\tafterApp: string;\n\tbeforeScript: string;\n\tafterScript: string;\n}\n","import { $hook, $inject, Alepha } from \"@alepha/core\";\nimport { $logger } from \"@alepha/logger\";\nimport { type Route, RouterProvider } from \"@alepha/router\";\nimport { createElement, type ReactNode } from \"react\";\nimport NotFoundPage from \"../components/NotFound.tsx\";\nimport {\n\tisPageRoute,\n\ttype PageRoute,\n\ttype PageRouteEntry,\n\ttype PreviousLayerData,\n\tReactPageProvider,\n\ttype ReactRouterState,\n} from \"./ReactPageProvider.ts\";\n\nexport interface BrowserRoute extends Route {\n\tpage: PageRoute;\n}\n\nexport class ReactBrowserRouterProvider extends RouterProvider<BrowserRoute> {\n\tprotected readonly log = $logger();\n\tprotected readonly alepha = $inject(Alepha);\n\tprotected readonly pageApi = $inject(ReactPageProvider);\n\n\tpublic add(entry: PageRouteEntry) {\n\t\tthis.pageApi.add(entry);\n\t}\n\n\tprotected readonly configure = $hook({\n\t\ton: \"configure\",\n\t\thandler: async () => {\n\t\t\tfor (const page of this.pageApi.getPages()) {\n\t\t\t\t// mount only if a view is provided\n\t\t\t\tif (page.component || page.lazy) {\n\t\t\t\t\tthis.push({\n\t\t\t\t\t\tpath: page.match,\n\t\t\t\t\t\tpage,\n\t\t\t\t\t});\n\t\t\t\t}\n\t\t\t}\n\t\t},\n\t});\n\n\tpublic async transition(\n\t\turl: URL,\n\t\tprevious: PreviousLayerData[] = [],\n\t\tmeta = {},\n\t): Promise<string | void> {\n\t\tconst { pathname, search } = url;\n\n\t\tconst entry: Partial<ReactRouterState> = {\n\t\t\turl,\n\t\t\tquery: {},\n\t\t\tparams: {},\n\t\t\tlayers: [],\n\t\t\tonError: () => null,\n\t\t\tmeta,\n\t\t};\n\n\t\tconst state = entry as ReactRouterState;\n\n\t\tawait this.alepha.events.emit(\"react:transition:begin\", {\n\t\t\tprevious: this.alepha.state.get(\"react.router.state\")!,\n\t\t\tstate,\n\t\t});\n\n\t\ttry {\n\t\t\tconst { route, params } = this.match(pathname);\n\n\t\t\tconst query: Record<string, string> = {};\n\t\t\tif (search) {\n\t\t\t\tfor (const [key, value] of new URLSearchParams(search).entries()) {\n\t\t\t\t\tquery[key] = String(value);\n\t\t\t\t}\n\t\t\t}\n\n\t\t\tstate.query = query;\n\t\t\tstate.params = params ?? {};\n\n\t\t\tif (isPageRoute(route)) {\n\t\t\t\tconst { redirect } = await this.pageApi.createLayers(\n\t\t\t\t\troute.page,\n\t\t\t\t\tstate,\n\t\t\t\t\tprevious,\n\t\t\t\t);\n\t\t\t\tif (redirect) {\n\t\t\t\t\treturn redirect;\n\t\t\t\t}\n\t\t\t}\n\n\t\t\tif (state.layers.length === 0) {\n\t\t\t\tstate.layers.push({\n\t\t\t\t\tname: \"not-found\",\n\t\t\t\t\telement: createElement(NotFoundPage),\n\t\t\t\t\tindex: 0,\n\t\t\t\t\tpath: \"/\",\n\t\t\t\t});\n\t\t\t}\n\n\t\t\tawait this.alepha.events.emit(\"react:transition:success\", { state });\n\t\t} catch (e) {\n\t\t\tthis.log.error(\"Transition has failed\", e);\n\t\t\tstate.layers = [\n\t\t\t\t{\n\t\t\t\t\tname: \"error\",\n\t\t\t\t\telement: this.pageApi.renderError(e as Error),\n\t\t\t\t\tindex: 0,\n\t\t\t\t\tpath: \"/\",\n\t\t\t\t},\n\t\t\t];\n\n\t\t\tawait this.alepha.events.emit(\"react:transition:error\", {\n\t\t\t\terror: e as Error,\n\t\t\t\tstate,\n\t\t\t});\n\t\t}\n\n\t\t// [feature]: local hook for leaving a page\n\t\tif (previous) {\n\t\t\tfor (let i = 0; i < previous.length; i++) {\n\t\t\t\tconst layer = previous[i];\n\t\t\t\tif (state.layers[i]?.name !== layer.name) {\n\t\t\t\t\tthis.pageApi.page(layer.name)?.onLeave?.();\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\n\t\tthis.alepha.state.set(\"react.router.state\", state);\n\n\t\tawait this.alepha.events.emit(\"react:transition:end\", {\n\t\t\tstate,\n\t\t});\n\t}\n\n\tpublic root(state: ReactRouterState): ReactNode {\n\t\treturn this.pageApi.root(state);\n\t}\n}\n","import {\n\t$env,\n\t$hook,\n\t$inject,\n\tAlepha,\n\ttype State,\n\ttype Static,\n\tt,\n} from \"@alepha/core\";\nimport { DateTimeProvider } from \"@alepha/datetime\";\nimport { $logger } from \"@alepha/logger\";\nimport { LinkProvider } from \"@alepha/server-links\";\nimport { ReactBrowserRouterProvider } from \"./ReactBrowserRouterProvider.ts\";\nimport type {\n\tPreviousLayerData,\n\tReactRouterState,\n\tTransitionOptions,\n} from \"./ReactPageProvider.ts\";\n\nconst envSchema = t.object({\n\tREACT_ROOT_ID: t.text({ default: \"root\" }),\n});\n\ndeclare module \"@alepha/core\" {\n\tinterface Env extends Partial<Static<typeof envSchema>> {}\n}\n\nexport interface ReactBrowserRendererOptions {\n\tscrollRestoration?: \"top\" | \"manual\";\n}\n\nexport class ReactBrowserProvider {\n\tprotected readonly env = $env(envSchema);\n\tprotected readonly log = $logger();\n\tprotected readonly client = $inject(LinkProvider);\n\tprotected readonly alepha = $inject(Alepha);\n\tprotected readonly router = $inject(ReactBrowserRouterProvider);\n\tprotected readonly dateTimeProvider = $inject(DateTimeProvider);\n\n\tpublic options: ReactBrowserRendererOptions = {\n\t\tscrollRestoration: \"top\",\n\t};\n\n\tprotected getRootElement() {\n\t\tconst root = this.document.getElementById(this.env.REACT_ROOT_ID);\n\t\tif (root) {\n\t\t\treturn root;\n\t\t}\n\n\t\tconst div = this.document.createElement(\"div\");\n\t\tdiv.id = this.env.REACT_ROOT_ID;\n\n\t\tthis.document.body.prepend(div);\n\n\t\treturn div;\n\t}\n\n\tpublic transitioning?: {\n\t\tto: string;\n\t\tfrom?: string;\n\t};\n\n\tpublic get state(): ReactRouterState {\n\t\treturn this.alepha.state.get(\"react.router.state\")!;\n\t}\n\n\t/**\n\t * Accessor for Document DOM API.\n\t */\n\tpublic get document() {\n\t\treturn window.document;\n\t}\n\n\t/**\n\t * Accessor for History DOM API.\n\t */\n\tpublic get history() {\n\t\treturn window.history;\n\t}\n\n\t/**\n\t * Accessor for Location DOM API.\n\t */\n\tpublic get location() {\n\t\treturn window.location;\n\t}\n\n\tpublic get base() {\n\t\tconst base = import.meta.env?.BASE_URL;\n\t\tif (!base || base === \"/\") {\n\t\t\treturn \"\";\n\t\t}\n\n\t\treturn base;\n\t}\n\n\tpublic get url(): string {\n\t\tconst url = this.location.pathname + this.location.search;\n\t\tif (this.base) {\n\t\t\treturn url.replace(this.base, \"\");\n\t\t}\n\t\treturn url;\n\t}\n\n\tpublic pushState(path: string, replace?: boolean) {\n\t\tconst url = this.base + path;\n\n\t\tif (replace) {\n\t\t\tthis.history.replaceState({}, \"\", url);\n\t\t} else {\n\t\t\tthis.history.pushState({}, \"\", url);\n\t\t}\n\t}\n\n\tpublic async invalidate(props?: Record<string, any>) {\n\t\tconst previous: PreviousLayerData[] = [];\n\n\t\tthis.log.trace(\"Invalidating layers\");\n\n\t\tif (props) {\n\t\t\tconst [key] = Object.keys(props);\n\t\t\tconst value = props[key];\n\n\t\t\tfor (const layer of this.state.layers) {\n\t\t\t\tif (layer.props?.[key]) {\n\t\t\t\t\tprevious.push({\n\t\t\t\t\t\t...layer,\n\t\t\t\t\t\tprops: {\n\t\t\t\t\t\t\t...layer.props,\n\t\t\t\t\t\t\t[key]: value,\n\t\t\t\t\t\t},\n\t\t\t\t\t});\n\t\t\t\t\tbreak;\n\t\t\t\t}\n\t\t\t\tprevious.push(layer);\n\t\t\t}\n\t\t}\n\n\t\tawait this.render({ previous });\n\t}\n\n\tpublic async go(url: string, options: RouterGoOptions = {}): Promise<void> {\n\t\tthis.log.trace(`Going to ${url}`, {\n\t\t\turl,\n\t\t\toptions,\n\t\t});\n\n\t\tawait this.render({\n\t\t\turl,\n\t\t\tprevious: options.force ? [] : this.state.layers,\n\t\t\tmeta: options.meta,\n\t\t});\n\n\t\t// when redirecting in browser\n\t\tif (this.state.url.pathname + this.state.url.search !== url) {\n\t\t\tthis.pushState(this.state.url.pathname + this.state.url.search);\n\t\t\treturn;\n\t\t}\n\n\t\tthis.pushState(url, options.replace);\n\t}\n\n\tprotected async render(options: RouterRenderOptions = {}): Promise<void> {\n\t\tconst previous = options.previous ?? this.state.layers;\n\t\tconst url = options.url ?? this.url;\n\t\tconst start = this.dateTimeProvider.now();\n\n\t\tthis.transitioning = {\n\t\t\tto: url,\n\t\t\tfrom: this.state?.url.pathname,\n\t\t};\n\n\t\tthis.log.debug(\"Transitioning...\", {\n\t\t\tto: url,\n\t\t});\n\n\t\tconst redirect = await this.router.transition(\n\t\t\tnew URL(`http://localhost${url}`),\n\t\t\tprevious,\n\t\t\toptions.meta,\n\t\t);\n\n\t\tif (redirect) {\n\t\t\tthis.log.info(\"Redirecting to\", {\n\t\t\t\tredirect,\n\t\t\t});\n\n\t\t\t// if redirect is an absolute URL, use window.location.href (full page reload)\n\t\t\tif (redirect.startsWith(\"http\")) {\n\t\t\t\twindow.location.href = redirect;\n\t\t\t} else {\n\t\t\t\t// if redirect is a relative URL, use render() (single page app)\n\t\t\t\treturn await this.render({ url: redirect });\n\t\t\t}\n\t\t}\n\n\t\tconst ms = this.dateTimeProvider.now().diff(start);\n\t\tthis.log.info(`Transition OK [${ms}ms]`, this.transitioning);\n\n\t\tthis.transitioning = undefined;\n\t}\n\n\t/**\n\t * Get embedded layers from the server.\n\t */\n\tprotected getHydrationState(): ReactHydrationState | undefined {\n\t\ttry {\n\t\t\tif (\"__ssr\" in window && typeof window.__ssr === \"object\") {\n\t\t\t\treturn window.__ssr as ReactHydrationState;\n\t\t\t}\n\t\t} catch (error) {\n\t\t\tconsole.error(error);\n\t\t}\n\t}\n\n\t// -------------------------------------------------------------------------------------------------------------------\n\n\tprotected readonly onTransitionEnd = $hook({\n\t\ton: \"react:transition:end\",\n\t\thandler: () => {\n\t\t\tif (\n\t\t\t\tthis.options.scrollRestoration === \"top\" &&\n\t\t\t\ttypeof window !== \"undefined\" &&\n\t\t\t\t!this.alepha.isTest()\n\t\t\t) {\n\t\t\t\tthis.log.trace(\"Restoring scroll position to top\");\n\t\t\t\twindow.scrollTo(0, 0);\n\t\t\t}\n\t\t},\n\t});\n\n\tpublic readonly ready = $hook({\n\t\ton: \"ready\",\n\t\thandler: async () => {\n\t\t\tconst hydration = this.getHydrationState();\n\t\t\tconst previous = hydration?.layers ?? [];\n\n\t\t\tif (hydration) {\n\t\t\t\t// low budget, but works for now\n\t\t\t\tfor (const [key, value] of Object.entries(hydration)) {\n\t\t\t\t\tif (key !== \"layers\") {\n\t\t\t\t\t\tthis.alepha.state.set(key as keyof State, value);\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\n\t\t\tawait this.render({ previous });\n\n\t\t\tconst element = this.router.root(this.state);\n\n\t\t\tawait this.alepha.events.emit(\"react:browser:render\", {\n\t\t\t\telement,\n\t\t\t\troot: this.getRootElement(),\n\t\t\t\thydration,\n\t\t\t\tstate: this.state,\n\t\t\t});\n\n\t\t\twindow.addEventListener(\"popstate\", () => {\n\t\t\t\t// when you update silently queryParams or hash, skip rendering\n\t\t\t\t// if you want to force a rendering, use #go()\n\t\t\t\tif (this.base + this.state.url.pathname === this.location.pathname) {\n\t\t\t\t\treturn;\n\t\t\t\t}\n\n\t\t\t\tthis.log.debug(\"Popstate event triggered - rendering new state\", {\n\t\t\t\t\turl: this.location.pathname + this.location.search,\n\t\t\t\t});\n\n\t\t\t\tthis.render();\n\t\t\t});\n\t\t},\n\t});\n}\n\n// ---------------------------------------------------------------------------------------------------------------------\n\nexport interface RouterGoOptions {\n\treplace?: boolean;\n\tmatch?: TransitionOptions;\n\tparams?: Record<string, string>;\n\tquery?: Record<string, string>;\n\tmeta?: Record<string, any>;\n\n\t/**\n\t * Recreate the whole page, ignoring the current state.\n\t */\n\tforce?: boolean;\n}\n\nexport type ReactHydrationState = {\n\tlayers?: Array<PreviousLayerData>;\n} & {\n\t[key: string]: any;\n};\n\nexport interface RouterRenderOptions {\n\turl?: string;\n\tprevious?: PreviousLayerData[];\n\tmeta?: Record<string, any>;\n}\n","import { $inject, Alepha } from \"@alepha/core\";\nimport type { PageDescriptor } from \"../descriptors/$page.ts\";\nimport {\n\tReactBrowserProvider,\n\ttype RouterGoOptions,\n} from \"../providers/ReactBrowserProvider.ts\";\nimport {\n\ttype AnchorProps,\n\tReactPageProvider,\n\ttype ReactRouterState,\n} from \"../providers/ReactPageProvider.ts\";\n\nexport class ReactRouter<T extends object> {\n\tprotected readonly alepha = $inject(Alepha);\n\tprotected readonly pageApi = $inject(ReactPageProvider);\n\n\tpublic get state(): ReactRouterState {\n\t\treturn this.alepha.state.get(\"react.router.state\")!;\n\t}\n\n\tpublic get pages() {\n\t\treturn this.pageApi.getPages();\n\t}\n\n\tpublic get browser(): ReactBrowserProvider | undefined {\n\t\tif (this.alepha.isBrowser()) {\n\t\t\treturn this.alepha.inject(ReactBrowserProvider);\n\t\t}\n\t\t// server-side\n\t\treturn undefined;\n\t}\n\n\tpublic path(\n\t\tname: keyof VirtualRouter<T>,\n\t\tconfig: {\n\t\t\tparams?: Record<string, any>;\n\t\t\tquery?: Record<string, any>;\n\t\t} = {},\n\t): string {\n\t\treturn this.pageApi.pathname(name as string, {\n\t\t\tparams: {\n\t\t\t\t...this.state.params,\n\t\t\t\t...config.params,\n\t\t\t},\n\t\t\tquery: config.query,\n\t\t});\n\t}\n\n\t/**\n\t * Reload the current page.\n\t * This is equivalent to calling `go()` with the current pathname and search.\n\t */\n\tpublic async reload() {\n\t\tif (!this.browser) {\n\t\t\treturn;\n\t\t}\n\n\t\tawait this.go(this.location.pathname + this.location.search, {\n\t\t\treplace: true,\n\t\t\tforce: true,\n\t\t});\n\t}\n\n\tpublic getURL(): URL {\n\t\tif (!this.browser) {\n\t\t\treturn this.state.url;\n\t\t}\n\n\t\treturn new URL(this.location.href);\n\t}\n\n\tpublic get location(): Location {\n\t\tif (!this.browser) {\n\t\t\tthrow new Error(\"Browser is required\");\n\t\t}\n\n\t\treturn this.browser.location;\n\t}\n\n\tpublic get current(): ReactRouterState {\n\t\treturn this.state;\n\t}\n\n\tpublic get pathname(): string {\n\t\treturn this.state.url.pathname;\n\t}\n\n\tpublic get query(): Record<string, string> {\n\t\tconst query: Record<string, string> = {};\n\n\t\tfor (const [key, value] of new URLSearchParams(\n\t\t\tthis.state.url.search,\n\t\t).entries()) {\n\t\t\tquery[key] = String(value);\n\t\t}\n\n\t\treturn query;\n\t}\n\n\tpublic async back() {\n\t\tthis.browser?.history.back();\n\t}\n\n\tpublic async forward() {\n\t\tthis.browser?.history.forward();\n\t}\n\n\tpublic async invalidate(props?: Record<string, any>) {\n\t\tawait this.browser?.invalidate(props);\n\t}\n\n\tpublic async go(path: string, options?: RouterGoOptions): Promise<void>;\n\tpublic async go(\n\t\tpath: keyof VirtualRouter<T>,\n\t\toptions?: RouterGoOptions,\n\t): Promise<void>;\n\tpublic async go(\n\t\tpath: string | keyof VirtualRouter<T>,\n\t\toptions?: RouterGoOptions,\n\t): Promise<void> {\n\t\tfor (const page of this.pages) {\n\t\t\tif (page.name === path) {\n\t\t\t\tawait this.browser?.go(\n\t\t\t\t\tthis.path(path as keyof VirtualRouter<T>, options),\n\t\t\t\t\toptions,\n\t\t\t\t);\n\t\t\t\treturn;\n\t\t\t}\n\t\t}\n\n\t\tawait this.browser?.go(path as string, options);\n\t}\n\n\tpublic anchor(path: string, options?: RouterGoOptions): AnchorProps;\n\tpublic anchor(\n\t\tpath: keyof VirtualRouter<T>,\n\t\toptions?: RouterGoOptions,\n\t): AnchorProps;\n\tpublic anchor(\n\t\tpath: string | keyof VirtualRouter<T>,\n\t\toptions: RouterGoOptions = {},\n\t): AnchorProps {\n\t\tlet href = path as string;\n\n\t\tfor (const page of this.pages) {\n\t\t\tif (page.name === path) {\n\t\t\t\thref = this.path(path as keyof VirtualRouter<T>, options);\n\t\t\t\tbreak;\n\t\t\t}\n\t\t}\n\n\t\treturn {\n\t\t\thref: this.base(href),\n\t\t\tonClick: (ev: any) => {\n\t\t\t\tev.stopPropagation();\n\t\t\t\tev.preventDefault();\n\n\t\t\t\tthis.go(href, options).catch(console.error);\n\t\t\t},\n\t\t};\n\t}\n\n\tpublic base(path: string): string {\n\t\tconst base = import.meta.env?.BASE_URL;\n\t\tif (!base || base === \"/\") {\n\t\t\treturn path;\n\t\t}\n\n\t\treturn base + path;\n\t}\n\n\t/**\n\t * Set query params.\n\t *\n\t * @param record\n\t * @param options\n\t */\n\tpublic setQueryParams(\n\t\trecord:\n\t\t\t| Record<string, any>\n\t\t\t| ((queryParams: Record<string, any>) => Record<string, any>),\n\t\toptions: {\n\t\t\t/**\n\t\t\t * If true, this will add a new entry to the history stack.\n\t\t\t */\n\t\t\tpush?: boolean;\n\t\t} = {},\n\t) {\n\t\tconst func = typeof record === \"function\" ? record : () => record;\n\t\tconst search = new URLSearchParams(func(this.query)).toString();\n\t\tconst state = search ? `${this.pathname}?${search}` : this.pathname;\n\n\t\tif (options.push) {\n\t\t\twindow.history.pushState({}, \"\", state);\n\t\t} else {\n\t\t\twindow.history.replaceState({}, \"\", state);\n\t\t}\n\t}\n}\n\nexport type VirtualRouter<T> = {\n\t[K in keyof T as T[K] extends PageDescriptor ? K : never]: T[K];\n};\n","import type { Service } from \"@alepha/core\";\nimport { useMemo } from \"react\";\nimport { useAlepha } from \"./useAlepha.ts\";\n\n/**\n * Hook to inject a service instance.\n * It's a wrapper of `useAlepha().inject(service)` with a memoization.\n */\nexport const useInject = <T extends object>(service: Service<T>): T => {\n\tconst alepha = useAlepha();\n\treturn useMemo(() => alepha.inject(service), []);\n};\n","import { ReactRouter } from \"../services/ReactRouter.ts\";\nimport { useInject } from \"./useInject.ts\";\n\n/**\n * Use this hook to access the React Router instance.\n *\n * You can add a type parameter to specify the type of your application.\n * This will allow you to use the router in a typesafe way.\n *\n * @example\n * class App {\n * home = $page();\n * }\n *\n * const router = useRouter<App>();\n * router.go(\"home\"); // typesafe\n */\nexport const useRouter = <T extends object = any>(): ReactRouter<T> => {\n\treturn useInject(ReactRouter<T>);\n};\n","import type { AnchorHTMLAttributes } from \"react\";\nimport { useRouter } from \"../hooks/useRouter.ts\";\n\nexport interface LinkProps extends AnchorHTMLAttributes<HTMLAnchorElement> {\n\thref: string;\n}\n\nconst Link = (props: LinkProps) => {\n\tconst router = useRouter();\n\n\treturn (\n\t\t<a {...props} {...router.anchor(props.href)}>\n\t\t\t{props.children}\n\t\t</a>\n\t);\n};\n\nexport default Link;\n","import { useState } from \"react\";\nimport type { AnchorProps } from \"../providers/ReactPageProvider.ts\";\nimport { useRouter } from \"./useRouter.ts\";\nimport { useRouterState } from \"./useRouterState.ts\";\n\nexport interface UseActiveOptions {\n\thref: string;\n\tstartWith?: boolean;\n}\n\nexport const useActive = (args: string | UseActiveOptions): UseActiveHook => {\n\tconst router = useRouter();\n\tconst [isPending, setPending] = useState(false);\n\tconst state = useRouterState();\n\tconst current = state.url.pathname;\n\n\tconst options: UseActiveOptions =\n\t\ttypeof args === \"string\" ? { href: args } : { ...args, href: args.href };\n\tconst href = options.href;\n\n\tlet isActive =\n\t\tcurrent === href || current === `${href}/` || `${current}/` === href;\n\n\tif (options.startWith && !isActive) {\n\t\tisActive = current.startsWith(href);\n\t}\n\n\treturn {\n\t\tisPending,\n\t\tisActive,\n\t\tanchorProps: {\n\t\t\thref: router.base(href),\n\t\t\tonClick: async (ev?: any) => {\n\t\t\t\tev?.stopPropagation();\n\t\t\t\tev?.preventDefault();\n\t\t\t\tif (isActive) return;\n\t\t\t\tif (isPending) return;\n\n\t\t\t\tsetPending(true);\n\t\t\t\ttry {\n\t\t\t\t\tawait router.go(href);\n\t\t\t\t} finally {\n\t\t\t\t\tsetPending(false);\n\t\t\t\t}\n\t\t\t},\n\t\t},\n\t};\n};\n\nexport interface UseActiveHook {\n\tisActive: boolean;\n\tanchorProps: AnchorProps;\n\tisPending: boolean;\n}\n","import {\n\ttype ClientScope,\n\ttype HttpVirtualClient,\n\tLinkProvider,\n} from \"@alepha/server-links\";\nimport { useInject } from \"./useInject.ts\";\n\n/**\n * Hook to get a virtual client for the specified scope.\n *\n * It's the React-hook version of `$client()`, from `AlephaServerLinks` module.\n */\nexport const useClient = <T extends object>(\n\tscope?: ClientScope,\n): HttpVirtualClient<T> => {\n\treturn useInject(LinkProvider).client<T>(scope);\n};\n","import type { Alepha, Static, TObject } from \"@alepha/core\";\nimport { useEffect, useState } from \"react\";\nimport { useAlepha } from \"./useAlepha.ts\";\nimport { useRouter } from \"./useRouter.ts\";\n\n/**\n * Not well tested. Use with caution.\n */\nexport const useQueryParams = <T extends TObject>(\n\tschema: T,\n\toptions: UseQueryParamsHookOptions = {},\n): [Partial<Static<T>>, (data: Static<T>) => void] => {\n\tconst alepha = useAlepha();\n\n\tconst key = options.key ?? \"q\";\n\tconst router = useRouter();\n\tconst querystring = router.query[key];\n\n\tconst [queryParams = {}, setQueryParams] = useState<Static<T> | undefined>(\n\t\tdecode(alepha, schema, router.query[key]),\n\t);\n\n\tuseEffect(() => {\n\t\tsetQueryParams(decode(alepha, schema, querystring));\n\t}, [querystring]);\n\n\treturn [\n\t\tqueryParams,\n\t\t(queryParams: Static<T>) => {\n\t\t\tsetQueryParams(queryParams);\n\t\t\trouter.setQueryParams((data) => {\n\t\t\t\treturn { ...data, [key]: encode(alepha, schema, queryParams) };\n\t\t\t});\n\t\t},\n\t];\n};\n\n// ---------------------------------------------------------------------------------------------------------------------\n\nexport interface UseQueryParamsHookOptions {\n\tformat?: \"base64\" | \"querystring\";\n\tkey?: string;\n\tpush?: boolean;\n}\n\nconst encode = (alepha: Alepha, schema: TObject, data: any) => {\n\treturn btoa(JSON.stringify(alepha.parse(schema, data)));\n};\n\nconst decode = <T extends TObject>(\n\talepha: Alepha,\n\tschema: T,\n\tdata: any,\n): Static<T> | undefined => {\n\ttry {\n\t\treturn alepha.parse(schema, JSON.parse(atob(decodeURIComponent(data))));\n\t} catch {\n\t\treturn;\n\t}\n};\n","import type { Alepha } from \"@alepha/core\";\nimport {\n\ttype FetchOptions,\n\tHttpClient,\n\ttype RequestConfigSchema,\n} from \"@alepha/server\";\nimport { LinkProvider, type VirtualAction } from \"@alepha/server-links\";\nimport { useEffect, useState } from \"react\";\nimport { useAlepha } from \"./useAlepha.ts\";\nimport { useInject } from \"./useInject.ts\";\n\nexport const useSchema = <TConfig extends RequestConfigSchema>(\n\taction: VirtualAction<TConfig>,\n): UseSchemaReturn<TConfig> => {\n\tconst name = action.name;\n\tconst alepha = useAlepha();\n\tconst httpClient = useInject(HttpClient);\n\tconst [schema, setSchema] = useState<UseSchemaReturn<TConfig>>(\n\t\tssrSchemaLoading(alepha, name) as UseSchemaReturn<TConfig>,\n\t);\n\n\tuseEffect(() => {\n\t\tif (!schema.loading) {\n\t\t\treturn;\n\t\t}\n\n\t\tconst opts: FetchOptions = {\n\t\t\tcache: true,\n\t\t};\n\n\t\thttpClient\n\t\t\t.fetch(`${LinkProvider.path.apiLinks}/${name}/schema`, {}, opts)\n\t\t\t.then((it) => setSchema(it.data as UseSchemaReturn<TConfig>));\n\t}, [name]);\n\n\treturn schema;\n};\n\nexport type UseSchemaReturn<TConfig extends RequestConfigSchema> = TConfig & {\n\tloading: boolean;\n};\n\n// ---------------------------------------------------------------------------------------------------------------------\n\n/**\n * Get an action schema during server-side rendering (SSR) or client-side rendering (CSR).\n */\nexport const ssrSchemaLoading = (alepha: Alepha, name: string) => {\n\t// server-side rendering (SSR) context\n\tif (!alepha.isBrowser()) {\n\t\t// get user links\n\t\tconst linkProvider = alepha.inject(LinkProvider);\n\n\t\t// check if user can access the link\n\t\tconst can = linkProvider\n\t\t\t.getServerLinks()\n\t\t\t.find((link) => link.name === name);\n\n\t\t// yes!\n\t\tif (can) {\n\t\t\t// user-links have no schema, so we need to get it from the provider\n\t\t\tconst schema = linkProvider.links.find((it) => it.name === name)?.schema;\n\n\t\t\t// oh, we have a schema!\n\t\t\tif (schema) {\n\t\t\t\t// attach to user link, it will be used in the client during hydration\n\t\t\t\tcan.schema = schema;\n\t\t\t\treturn schema;\n\t\t\t}\n\t\t}\n\n\t\treturn { loading: true };\n\t}\n\n\t// browser side rendering (CSR) context\n\t// check if we have the schema already loaded\n\tconst schema = alepha\n\t\t.inject(LinkProvider)\n\t\t.links.find((it) => it.name === name)?.schema;\n\n\t// yes!\n\tif (schema) {\n\t\treturn schema;\n\t}\n\n\t// no, we need to load it\n\treturn { loading: true };\n};\n","import { $module } from \"@alepha/core\";\nimport { AlephaServer, type ServerRequest } from \"@alepha/server\";\nimport { AlephaServerCache } from \"@alepha/server-cache\";\nimport { AlephaServerLinks } from \"@alepha/server-links\";\nimport type { ReactNode } from \"react\";\nimport { $page, type PageAnimation } from \"./descriptors/$page.ts\";\nimport type { ReactHydrationState } from \"./providers/ReactBrowserProvider.ts\";\nimport {\n\tReactPageProvider,\n\ttype ReactRouterState,\n} from \"./providers/ReactPageProvider.ts\";\nimport { ReactServerProvider } from \"./providers/ReactServerProvider.ts\";\nimport { ReactRouter } from \"./services/ReactRouter.ts\";\n\n// ---------------------------------------------------------------------------------------------------------------------\n\nexport * from \"./index.shared.ts\";\nexport * from \"./providers/ReactBrowserProvider.ts\";\nexport * from \"./providers/ReactPageProvider.ts\";\nexport * from \"./providers/ReactServerProvider.ts\";\n\n// ---------------------------------------------------------------------------------------------------------------------\n\ndeclare module \"@alepha/core\" {\n\tinterface State {\n\t\t\"react.router.state\"?: ReactRouterState;\n\t}\n\n\tinterface Hooks {\n\t\t\"react:server:render:begin\": {\n\t\t\trequest?: ServerRequest;\n\t\t\tstate: ReactRouterState;\n\t\t};\n\t\t\"react:server:render:end\": {\n\t\t\trequest?: ServerRequest;\n\t\t\tstate: ReactRouterState;\n\t\t\thtml: string;\n\t\t};\n\t\t// -----------------------------------------------------------------------------------------------------------------\n\t\t\"react:browser:render\": {\n\t\t\troot: HTMLDivElement;\n\t\t\telement: ReactNode;\n\t\t\tstate: ReactRouterState;\n\t\t\thydration?: ReactHydrationState;\n\t\t};\n\t\t\"react:transition:begin\": {\n\t\t\tprevious: ReactRouterState;\n\t\t\tstate: ReactRouterState;\n\t\t\tanimation?: PageAnimation;\n\t\t};\n\t\t\"react:transition:success\": {\n\t\t\tstate: ReactRouterState;\n\t\t};\n\t\t\"react:transition:error\": {\n\t\t\tstate: ReactRouterState;\n\t\t\terror: Error;\n\t\t};\n\t\t\"react:transition:end\": {\n\t\t\tstate: ReactRouterState;\n\t\t};\n\t}\n}\n\n// ---------------------------------------------------------------------------------------------------------------------\n\n/**\n * Provides full-stack React development with declarative routing, server-side rendering, and client-side hydration.\n *\n * The React module enables building modern React applications using the `$page` descriptor on class properties.\n * It delivers seamless server-side rendering, automatic code splitting, and client-side navigation with full\n * type safety and schema validation for route parameters and data.\n *\n * @see {@link $page}\n * @module alepha.react\n */\nexport const AlephaReact = $module({\n\tname: \"alepha.react\",\n\tdescriptors: [$page],\n\tservices: [ReactServerProvider, ReactPageProvider, ReactRouter],\n\tregister: (alepha) =>\n\t\talepha\n\t\t\t.with(AlephaServer)\n\t\t\t.with(AlephaServerCache)\n\t\t\t.with(AlephaServerLinks)\n\t\t\t.with(ReactServerProvider)\n\t\t\t.with(ReactPageProvider)\n\t\t\t.with(ReactRouter),\n});\n"],"mappings":"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"}
|