@alepha/react 0.10.6 → 0.10.7
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 +27 -42
- package/dist/index.browser.js.map +1 -1
- package/dist/index.d.ts +48 -48
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +35 -57
- package/dist/index.js.map +1 -1
- package/package.json +10 -10
- package/src/components/ClientOnly.tsx +12 -12
- package/src/components/ErrorBoundary.tsx +43 -43
- package/src/components/ErrorViewer.tsx +140 -140
- package/src/components/Link.tsx +7 -7
- package/src/components/NestedView.tsx +177 -177
- package/src/components/NotFound.tsx +19 -19
- package/src/contexts/RouterLayerContext.ts +3 -3
- package/src/descriptors/$page.ts +292 -290
- package/src/errors/Redirection.ts +5 -5
- package/src/hooks/useActive.ts +41 -41
- package/src/hooks/useAlepha.ts +7 -7
- package/src/hooks/useClient.ts +5 -5
- package/src/hooks/useInject.ts +2 -2
- package/src/hooks/useQueryParams.ts +37 -37
- package/src/hooks/useRouter.ts +1 -1
- package/src/hooks/useRouterEvents.ts +46 -46
- package/src/hooks/useRouterState.ts +5 -5
- package/src/hooks/useSchema.ts +55 -55
- package/src/hooks/useStore.ts +25 -25
- package/src/index.browser.ts +18 -18
- package/src/index.ts +49 -49
- package/src/providers/ReactBrowserProvider.ts +268 -268
- package/src/providers/ReactBrowserRendererProvider.ts +15 -15
- package/src/providers/ReactBrowserRouterProvider.ts +124 -124
- package/src/providers/ReactPageProvider.ts +616 -615
- package/src/providers/ReactServerProvider.ts +505 -505
- package/src/services/ReactRouter.ts +191 -191
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 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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"}
|
|
1
|
+
{"version":3,"file":"index.js","names":["subs: Function[]","state","ErrorBoundary","envSchema","NestedView","context: Record<string, any>","stack: Array<RouterStackItem>","route","config: Record<string, any>","context","element: ReactNode | Redirection | undefined","ErrorViewer","ClientOnly","children","envSchema","target: PageRoute | undefined","element","hydrationData: ReactHydrationState","query: Record<string, string>","previous: PreviousLayerData[]","query: Record<string, string>","options: UseActiveOptions","queryParams","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 AlephaError,\n type Async,\n createDescriptor,\n Descriptor,\n KIND,\n type Static,\n type 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 TConfig extends PageConfigSchema = PageConfigSchema,\n TProps extends object = TPropsDefault,\n TPropsParent extends object = TPropsParentDefault,\n>(\n options: PageDescriptorOptions<TConfig, TProps, TPropsParent>,\n): PageDescriptor<TConfig, TProps, TPropsParent> => {\n return createDescriptor(\n PageDescriptor<TConfig, TProps, TPropsParent>,\n options,\n );\n};\n\n// ---------------------------------------------------------------------------------------------------------------------\n\nexport interface PageDescriptorOptions<\n TConfig extends PageConfigSchema = PageConfigSchema,\n TProps extends object = TPropsDefault,\n TPropsParent extends object = TPropsParentDefault,\n> {\n /**\n * Name your page.\n *\n * @default Descriptor key\n */\n name?: string;\n\n /**\n * Optional description of the page.\n */\n description?: string;\n\n /**\n * Add a pathname to the page.\n *\n * Pathname can contain parameters, like `/post/:slug`.\n *\n * @default \"\"\n */\n path?: string;\n\n /**\n * Add an input schema to define:\n * - `params`: parameters from the pathname.\n * - `query`: query parameters from the URL.\n */\n schema?: TConfig;\n\n /**\n * Load data before rendering the page.\n *\n * This function receives\n * - the request context and\n * - the parent props (if page has a parent)\n *\n * In SSR, the returned data will be serialized and sent to the client, then reused during the client-side hydration.\n *\n * Resolve can be stopped by throwing an error, which will be handled by the `errorHandler` function.\n * It's common to throw a `NotFoundError` to display a 404 page.\n *\n * RedirectError can be thrown to redirect the user to another page.\n */\n resolve?: (context: PageResolve<TConfig, TPropsParent>) => Async<TProps>;\n\n /**\n * The component to render when the page is loaded.\n *\n * If `lazy` is defined, this will be ignored.\n * Prefer using `lazy` to improve the initial loading time.\n */\n component?: FC<TProps & TPropsParent>;\n\n /**\n * Lazy load the component when the page is loaded.\n *\n * It's recommended to use this for components to improve the initial loading time\n * and enable code-splitting.\n */\n lazy?: () => Promise<{ default: FC<TProps & TPropsParent> }>;\n\n /**\n * Set some children pages and make the page a parent page.\n *\n * /!\\ Parent page can't be rendered directly. /!\\\n *\n * If you still want to render at this pathname, add a child page with an empty path.\n */\n children?: Array<PageDescriptor> | (() => Array<PageDescriptor>);\n\n parent?: PageDescriptor<PageConfigSchema, TPropsParent>;\n\n can?: () => boolean;\n\n /**\n * Catch any error from the `resolve` function or during `rendering`.\n *\n * Expected to return one of the following:\n * - a ReactNode to render an error page\n * - a Redirection to redirect the user\n * - undefined to let the error propagate\n *\n * If not defined, the error will be thrown and handled by the server or client error handler.\n * If a leaf $page does not define an error handler, the error can be caught by parent pages.\n *\n * @example Catch a 404 from API and render a custom not found component:\n * ```ts\n * resolve: async ({ params, query }) => {\n * api.fetch(\"/api/resource\", { params, query });\n * },\n * errorHandler: (error, context) => {\n * if (HttpError.is(error, 404)) {\n * return <ResourceNotFound />;\n * }\n * }\n * ```\n *\n * @example Catch an 401 error and redirect the user to the login page:\n * ```ts\n * resolve: async ({ params, query }) => {\n * // but the user is not authenticated\n * api.fetch(\"/api/resource\", { params, query });\n * },\n * errorHandler: (error, context) => {\n * if (HttpError.is(error, 401)) {\n * // throwing a Redirection is also valid!\n * return new Redirection(\"/login\");\n * }\n * }\n * ```\n */\n errorHandler?: ErrorHandler;\n\n /**\n * If true, the page will be considered as a static page, immutable and cacheable.\n * Replace boolean by an object to define static entries. (e.g. list of params/query)\n *\n * For now, it only works with `@alepha/vite` which can pre-render the page at build time.\n *\n * It will act as timeless cached page server-side. You can use `cache` to configure the cache behavior.\n */\n static?:\n | boolean\n | {\n entries?: Array<Partial<PageRequestConfig<TConfig>>>;\n };\n\n cache?: ServerRouteCache;\n\n /**\n * If true, force the page to be rendered only on the client-side.\n * It uses the `<ClientOnly/>` component to render the page.\n */\n client?: boolean | ClientOnlyProps;\n\n /**\n * Called before the server response is sent to the client.\n */\n onServerResponse?: (request: ServerRequest) => any;\n\n /**\n * Called when user leaves the page. (browser only)\n */\n onLeave?: () => void;\n\n /**\n * @experimental\n *\n * Add a css animation when the page is loaded or unloaded.\n * It uses CSS animations, so you need to define the keyframes in your CSS.\n *\n * @example Simple animation name\n * ```ts\n * animation: \"fadeIn\"\n * ```\n *\n * CSS example:\n * ```css\n * @keyframes fadeIn {\n * from { opacity: 0; }\n * to { opacity: 1; }\n * }\n * ```\n *\n * @example Detailed animation\n * ```ts\n * animation: {\n * enter: { name: \"fadeIn\", duration: 300 },\n * exit: { name: \"fadeOut\", duration: 200, timing: \"ease-in-out\" },\n * }\n * ```\n *\n * @example Only exit animation\n * ```ts\n * animation: {\n * exit: \"fadeOut\"\n * }\n * ```\n *\n * @example With custom timing function\n * ```ts\n * animation: {\n * enter: { name: \"fadeIn\", duration: 300, timing: \"cubic-bezier(0.4, 0, 0.2, 1)\" },\n * exit: { name: \"fadeOut\", duration: 200, timing: \"ease-in-out\" },\n * }\n * ```\n */\n animation?: PageAnimation;\n}\n\nexport type ErrorHandler = (\n error: Error,\n state: ReactRouterState,\n) => ReactNode | Redirection | undefined;\n\nexport class PageDescriptor<\n TConfig extends PageConfigSchema = PageConfigSchema,\n TProps extends object = TPropsDefault,\n TPropsParent extends object = TPropsParentDefault,\n> extends Descriptor<PageDescriptorOptions<TConfig, TProps, TPropsParent>> {\n protected onInit() {\n if (this.options.static) {\n this.options.cache ??= {\n store: {\n provider: \"memory\",\n ttl: [1, \"week\"],\n },\n };\n }\n }\n\n public get name(): string {\n return this.options.name ?? this.config.propertyKey;\n }\n\n /**\n * For testing or build purposes, this will render the page (with or without the HTML layout) and return the HTML and context.\n * Only valid for server-side rendering, it will throw an error if called on the client-side.\n */\n public async render(\n options?: PageDescriptorRenderOptions,\n ): Promise<PageDescriptorRenderResult> {\n throw new AlephaError(\n \"render() method is not implemented in this environment\",\n );\n }\n\n public async fetch(options?: PageDescriptorRenderOptions): Promise<{\n html: string;\n response: Response;\n }> {\n throw new AlephaError(\n \"fetch() method is not implemented in this environment\",\n );\n }\n\n public match(url: string): boolean {\n // TODO: Implement a way to match the URL against the pathname\n return false;\n }\n\n public pathname(config: any) {\n // TODO: Implement a way to generate the pathname based on the config\n return this.options.path || \"\";\n }\n}\n\n$page[KIND] = PageDescriptor;\n\n// ---------------------------------------------------------------------------------------------------------------------\n\nexport interface PageConfigSchema {\n query?: TSchema;\n params?: TSchema;\n}\n\nexport type TPropsDefault = any;\n\nexport type TPropsParentDefault = {};\n\nexport interface PageDescriptorRenderOptions {\n params?: Record<string, string>;\n query?: Record<string, string>;\n\n /**\n * If true, the HTML layout will be included in the response.\n * If false, only the page content will be returned.\n *\n * @default true\n */\n html?: boolean;\n hydration?: boolean;\n}\n\nexport interface PageDescriptorRenderResult {\n html: string;\n state: ReactRouterState;\n redirect?: string;\n}\n\nexport interface PageRequestConfig<\n TConfig extends PageConfigSchema = PageConfigSchema,\n> {\n params: TConfig[\"params\"] extends TSchema\n ? Static<TConfig[\"params\"]>\n : Record<string, string>;\n\n query: TConfig[\"query\"] extends TSchema\n ? Static<TConfig[\"query\"]>\n : Record<string, string>;\n}\n\nexport type PageResolve<\n TConfig extends PageConfigSchema = PageConfigSchema,\n TPropsParent extends object = TPropsParentDefault,\n> = PageRequestConfig<TConfig> &\n TPropsParent &\n Omit<ReactRouterState, \"layers\" | \"onError\">;\n\nexport type PageAnimation =\n | PageAnimationObject\n | ((state: ReactRouterState) => PageAnimationObject | undefined);\n\ntype PageAnimationObject =\n | CssAnimationName\n | {\n enter?: CssAnimation | CssAnimationName;\n exit?: CssAnimation | CssAnimationName;\n };\n\ntype CssAnimationName = string;\n\ntype CssAnimation = {\n name: string;\n duration?: number;\n timing?: string;\n};\n","import {\n type PropsWithChildren,\n type ReactNode,\n useEffect,\n useState,\n} from \"react\";\n\nexport interface ClientOnlyProps {\n fallback?: ReactNode;\n disabled?: 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 const [mounted, setMounted] = useState(false);\n\n useEffect(() => setMounted(true), []);\n\n if (props.disabled) {\n return props.children;\n }\n\n return 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 error: Error;\n alepha: Alepha;\n}\n\n// TODO: design this better\n\nconst ErrorViewer = ({ error, alepha }: ErrorViewerProps) => {\n const [expanded, setExpanded] = useState(false);\n const isProduction = alepha.isProduction();\n // const status = isHttpError(error) ? error.status : 500;\n\n if (isProduction) {\n return <ErrorViewerProduction />;\n }\n\n const stackLines = error.stack?.split(\"\\n\") ?? [];\n const previewLines = stackLines.slice(0, 5);\n const hiddenLineCount = stackLines.length - previewLines.length;\n\n const copyToClipboard = (text: string) => {\n navigator.clipboard.writeText(text).catch((err) => {\n console.error(\"Clipboard error:\", err);\n });\n };\n\n const styles = {\n container: {\n padding: \"24px\",\n backgroundColor: \"#FEF2F2\",\n color: \"#7F1D1D\",\n border: \"1px solid #FECACA\",\n borderRadius: \"16px\",\n boxShadow: \"0 8px 24px rgba(0,0,0,0.05)\",\n fontFamily: \"monospace\",\n maxWidth: \"768px\",\n margin: \"40px auto\",\n },\n heading: {\n fontSize: \"20px\",\n fontWeight: \"bold\",\n marginBottom: \"10px\",\n },\n name: {\n fontSize: \"16px\",\n fontWeight: 600,\n },\n message: {\n fontSize: \"14px\",\n marginBottom: \"16px\",\n },\n sectionHeader: {\n display: \"flex\",\n justifyContent: \"space-between\",\n alignItems: \"center\",\n fontSize: \"12px\",\n marginBottom: \"4px\",\n color: \"#991B1B\",\n },\n copyButton: {\n fontSize: \"12px\",\n color: \"#DC2626\",\n background: \"none\",\n border: \"none\",\n cursor: \"pointer\",\n textDecoration: \"underline\",\n },\n stackContainer: {\n backgroundColor: \"#FEE2E2\",\n padding: \"12px\",\n borderRadius: \"8px\",\n fontSize: \"13px\",\n lineHeight: \"1.4\",\n overflowX: \"auto\" as const,\n whiteSpace: \"pre-wrap\" as const,\n },\n expandLine: {\n color: \"#F87171\",\n cursor: \"pointer\",\n marginTop: \"8px\",\n },\n };\n\n return (\n <div style={styles.container}>\n <div>\n <div style={styles.heading}>🔥 Error</div>\n <div style={styles.name}>{error.name}</div>\n <div style={styles.message}>{error.message}</div>\n </div>\n\n {stackLines.length > 0 && (\n <div>\n <div style={styles.sectionHeader}>\n <span>Stack trace</span>\n <button\n onClick={() => copyToClipboard(error.stack!)}\n style={styles.copyButton}\n >\n Copy all\n </button>\n </div>\n <pre style={styles.stackContainer}>\n {(expanded ? stackLines : previewLines).map((line, i) => (\n <div key={i}>{line}</div>\n ))}\n {!expanded && hiddenLineCount > 0 && (\n <div style={styles.expandLine} onClick={() => setExpanded(true)}>\n + {hiddenLineCount} more lines...\n </div>\n )}\n </pre>\n </div>\n )}\n </div>\n );\n};\n\nexport default ErrorViewer;\n\nconst ErrorViewerProduction = () => {\n const styles = {\n container: {\n padding: \"24px\",\n backgroundColor: \"#FEF2F2\",\n color: \"#7F1D1D\",\n border: \"1px solid #FECACA\",\n borderRadius: \"16px\",\n boxShadow: \"0 8px 24px rgba(0,0,0,0.05)\",\n fontFamily: \"monospace\",\n maxWidth: \"768px\",\n margin: \"40px auto\",\n textAlign: \"center\" as const,\n },\n heading: {\n fontSize: \"20px\",\n fontWeight: \"bold\",\n marginBottom: \"8px\",\n },\n name: {\n fontSize: \"16px\",\n fontWeight: 600,\n marginBottom: \"4px\",\n },\n message: {\n fontSize: \"14px\",\n opacity: 0.85,\n },\n };\n\n return (\n <div style={styles.container}>\n <div style={styles.heading}>🚨 An error occurred</div>\n <div style={styles.message}>\n Something went wrong. Please try again later.\n </div>\n </div>\n );\n};\n","import { createContext } from \"react\";\n\nexport interface RouterLayerContextValue {\n index: number;\n path: string;\n}\n\nexport const RouterLayerContext = createContext<\n RouterLayerContextValue | 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 public readonly redirect: string;\n\n constructor(redirect: string) {\n super(\"Redirection\");\n this.redirect = redirect;\n }\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 const alepha = useContext(AlephaContext);\n if (!alepha) {\n throw new AlephaError(\n \"Hook 'useAlepha()' must be used within an AlephaContext.Provider\",\n );\n }\n\n return 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 | ((ev: Hooks[T]) => void)\n | {\n priority?: \"first\" | \"last\";\n callback: (ev: Hooks[T]) => void;\n };\n\n/**\n * Subscribe to various router events.\n */\nexport const useRouterEvents = (\n opts: {\n onBegin?: Hook<\"react:transition:begin\">;\n onError?: Hook<\"react:transition:error\">;\n onEnd?: Hook<\"react:transition:end\">;\n onSuccess?: Hook<\"react:transition:success\">;\n } = {},\n deps: any[] = [],\n) => {\n const alepha = useAlepha();\n\n useEffect(() => {\n if (!alepha.isBrowser()) {\n return;\n }\n\n const cb = <T extends keyof Hooks>(callback: Hook<T>) => {\n if (typeof callback === \"function\") {\n return { callback };\n }\n return callback;\n };\n\n const subs: Function[] = [];\n const onBegin = opts.onBegin;\n const onEnd = opts.onEnd;\n const onError = opts.onError;\n const onSuccess = opts.onSuccess;\n\n if (onBegin) {\n subs.push(alepha.events.on(\"react:transition:begin\", cb(onBegin)));\n }\n\n if (onEnd) {\n subs.push(alepha.events.on(\"react:transition:end\", cb(onEnd)));\n }\n\n if (onError) {\n subs.push(alepha.events.on(\"react:transition:error\", cb(onError)));\n }\n\n if (onSuccess) {\n subs.push(alepha.events.on(\"react:transition:success\", cb(onSuccess)));\n }\n\n return () => {\n for (const sub of subs) {\n sub();\n }\n };\n }, 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 key: Key,\n defaultValue?: State[Key],\n): [State[Key], (value: State[Key]) => void] => {\n const alepha = useAlepha();\n\n useMemo(() => {\n if (defaultValue != null && alepha.state.get(key) == null) {\n alepha.state.set(key, defaultValue);\n }\n }, [defaultValue]);\n\n const [state, setState] = useState(alepha.state.get(key));\n\n useEffect(() => {\n if (!alepha.isBrowser()) {\n return;\n }\n\n return alepha.events.on(\"state:mutate\", (ev) => {\n if (ev.key === key) {\n setState(ev.value);\n }\n });\n }, []);\n\n return [\n state,\n (value: State[Key]) => {\n alepha.state.set(key, value);\n },\n ] 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 const [state] = useStore(\"react.router.state\");\n if (!state) {\n throw new AlephaError(\"Missing react router state\");\n }\n return state;\n};\n","import React, {\n type ErrorInfo,\n type PropsWithChildren,\n type ReactNode,\n} from \"react\";\n\n/**\n * Props for the ErrorBoundary component.\n */\nexport interface ErrorBoundaryProps {\n /**\n * Fallback React node to render when an error is caught.\n * If not provided, a default error message will be shown.\n */\n fallback: (error: Error) => ReactNode;\n\n /**\n * Optional callback that receives the error and error info.\n * Use this to log errors to a monitoring service.\n */\n onError?: (error: Error, info: ErrorInfo) => void;\n}\n\n/**\n * State of the ErrorBoundary component.\n */\ninterface ErrorBoundaryState {\n error?: 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 PropsWithChildren<ErrorBoundaryProps>,\n ErrorBoundaryState\n> {\n constructor(props: ErrorBoundaryProps) {\n super(props);\n this.state = {};\n }\n\n /**\n * Update state so the next render shows the fallback UI.\n */\n static getDerivedStateFromError(error: Error): ErrorBoundaryState {\n return {\n error,\n };\n }\n\n /**\n * Lifecycle method called when an error is caught.\n * You can log the error or perform side effects here.\n */\n componentDidCatch(error: Error, info: ErrorInfo): void {\n if (this.props.onError) {\n this.props.onError(error, info);\n }\n }\n\n render(): ReactNode {\n if (this.state.error) {\n return this.props.fallback(this.state.error);\n }\n\n return this.props.children;\n }\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 children?: ReactNode;\n errorBoundary?: 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 const index = use(RouterLayerContext)?.index ?? 0;\n const state = useRouterState();\n\n const [view, setView] = useState<ReactNode | undefined>(\n state.layers[index]?.element,\n );\n\n const [animation, setAnimation] = useState(\"\");\n const animationExitDuration = useRef<number>(0);\n const animationExitNow = useRef<number>(0);\n\n useRouterEvents(\n {\n onBegin: async ({ previous, state }) => {\n // --------- Animations Begin ---------\n const layer = previous.layers[index];\n if (`${state.url.pathname}/`.startsWith(`${layer?.path}/`)) {\n return;\n }\n\n const animationExit = parseAnimation(\n layer.route?.animation,\n state,\n \"exit\",\n );\n\n if (animationExit) {\n const duration = animationExit.duration || 200;\n animationExitNow.current = Date.now();\n animationExitDuration.current = duration;\n setAnimation(animationExit.animation);\n } else {\n animationExitNow.current = 0;\n animationExitDuration.current = 0;\n setAnimation(\"\");\n }\n // --------- Animations End ---------\n },\n onEnd: async ({ state }) => {\n const layer = state.layers[index];\n\n // --------- Animations Begin ---------\n if (animationExitNow.current) {\n const duration = animationExitDuration.current;\n const diff = Date.now() - animationExitNow.current;\n if (diff < duration) {\n await new Promise((resolve) =>\n setTimeout(resolve, duration - diff),\n );\n }\n }\n // --------- Animations End ---------\n\n if (!layer?.cache) {\n setView(layer?.element);\n\n // --------- Animations Begin ---------\n const animationEnter = parseAnimation(\n layer?.route?.animation,\n state,\n \"enter\",\n );\n\n if (animationEnter) {\n setAnimation(animationEnter.animation);\n } else {\n setAnimation(\"\");\n }\n // --------- Animations End ---------\n }\n },\n },\n [],\n );\n\n let element = view ?? props.children ?? null;\n\n // --------- Animations Begin ---------\n if (animation) {\n element = (\n <div\n style={{\n display: \"flex\",\n flex: 1,\n height: \"100%\",\n width: \"100%\",\n position: \"relative\",\n overflow: \"hidden\",\n }}\n >\n <div\n style={{ height: \"100%\", width: \"100%\", display: \"flex\", animation }}\n >\n {element}\n </div>\n </div>\n );\n }\n // --------- Animations End ---------\n\n if (props.errorBoundary === false) {\n return <>{element}</>;\n }\n\n if (props.errorBoundary) {\n return (\n <ErrorBoundary fallback={props.errorBoundary}>{element}</ErrorBoundary>\n );\n }\n\n return (\n <ErrorBoundary\n fallback={(error) => {\n const result = state.onError(error, state); // TODO: onError is not refreshed\n if (result instanceof Redirection) {\n return \"Redirection inside ErrorBoundary is not allowed.\";\n }\n return result as ReactNode;\n }}\n >\n {element}\n </ErrorBoundary>\n );\n};\n\nexport default memo(NestedView);\n\nfunction parseAnimation(\n animationLike: PageAnimation | undefined,\n state: ReactRouterState,\n type: \"enter\" | \"exit\" = \"enter\",\n):\n | {\n duration: number;\n animation: string;\n }\n | undefined {\n if (!animationLike) {\n return undefined;\n }\n\n const DEFAULT_DURATION = 300;\n\n const animation =\n typeof animationLike === \"function\" ? animationLike(state) : animationLike;\n\n if (typeof animation === \"string\") {\n if (type === \"exit\") {\n return;\n }\n return {\n duration: DEFAULT_DURATION,\n animation: `${DEFAULT_DURATION}ms ${animation}`,\n };\n }\n\n if (typeof animation === \"object\") {\n const anim = animation[type];\n const duration =\n typeof anim === \"object\"\n ? (anim.duration ?? DEFAULT_DURATION)\n : DEFAULT_DURATION;\n const name = typeof anim === \"object\" ? anim.name : anim;\n\n if (type === \"exit\") {\n const timing = typeof anim === \"object\" ? (anim.timing ?? \"\") : \"\";\n return {\n duration,\n animation: `${duration}ms ${timing} ${name}`,\n };\n }\n\n const timing = typeof anim === \"object\" ? (anim.timing ?? \"\") : \"\";\n\n return {\n duration,\n animation: `${duration}ms ${timing} ${name}`,\n };\n }\n\n return undefined;\n}\n","import type { CSSProperties } from \"react\";\n\nexport default function NotFoundPage(props: { style?: CSSProperties }) {\n return (\n <div\n style={{\n height: \"100vh\",\n display: \"flex\",\n flexDirection: \"column\",\n justifyContent: \"center\",\n alignItems: \"center\",\n textAlign: \"center\",\n fontFamily: \"sans-serif\",\n padding: \"1rem\",\n ...props.style,\n }}\n >\n <h1 style={{ fontSize: \"1rem\", marginBottom: \"0.5rem\" }}>\n 404 - This page does not exist\n </h1>\n </div>\n );\n}\n","import {\n $env,\n $hook,\n $inject,\n Alepha,\n AlephaError,\n type Static,\n type TSchema,\n t,\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 $page,\n type ErrorHandler,\n type PageDescriptor,\n type PageDescriptorOptions,\n} from \"../descriptors/$page.ts\";\nimport { Redirection } from \"../errors/Redirection.ts\";\n\nconst envSchema = t.object({\n REACT_STRICT_MODE: t.boolean({ default: true }),\n});\n\ndeclare module \"@alepha/core\" {\n export interface Env extends Partial<Static<typeof envSchema>> {}\n}\n\nexport class ReactPageProvider {\n protected readonly log = $logger();\n protected readonly env = $env(envSchema);\n protected readonly alepha = $inject(Alepha);\n protected readonly pages: PageRoute[] = [];\n\n public getPages(): PageRoute[] {\n return this.pages;\n }\n\n public page(name: string): PageRoute {\n for (const page of this.pages) {\n if (page.name === name) {\n return page;\n }\n }\n\n throw new Error(`Page ${name} not found`);\n }\n\n public pathname(\n name: string,\n options: {\n params?: Record<string, string>;\n query?: Record<string, string>;\n } = {},\n ) {\n const page = this.page(name);\n if (!page) {\n throw new Error(`Page ${name} not found`);\n }\n\n let url = page.path ?? \"\";\n let parent = page.parent;\n while (parent) {\n url = `${parent.path ?? \"\"}/${url}`;\n parent = parent.parent;\n }\n\n url = this.compile(url, options.params ?? {});\n\n if (options.query) {\n const query = new URLSearchParams(options.query);\n if (query.toString()) {\n url += `?${query.toString()}`;\n }\n }\n\n return url.replace(/\\/\\/+/g, \"/\") || \"/\";\n }\n\n public url(\n name: string,\n options: { params?: Record<string, string>; host?: string } = {},\n ): URL {\n return new URL(\n this.pathname(name, options),\n // use provided base or default to http://localhost\n options.host ?? `http://localhost`,\n );\n }\n\n public root(state: ReactRouterState): ReactNode {\n const root = createElement(\n AlephaContext.Provider,\n { value: this.alepha },\n createElement(NestedView, {}, state.layers[0]?.element),\n );\n\n if (this.env.REACT_STRICT_MODE) {\n return createElement(StrictMode, {}, root);\n }\n\n return root;\n }\n\n protected convertStringObjectToObject = (\n schema?: TSchema,\n value?: any,\n ): any => {\n if (t.schema.isObject(schema) && typeof value === \"object\") {\n for (const key in schema.properties) {\n if (\n t.schema.isObject(schema.properties[key]) &&\n typeof value[key] === \"string\"\n ) {\n try {\n value[key] = this.alepha.parse(\n schema.properties[key],\n decodeURIComponent(value[key]),\n );\n } catch (e) {\n // ignore\n }\n }\n }\n }\n return value;\n };\n\n /**\n * Create a new RouterState based on a given route and request.\n * This method resolves the layers for the route, applying any query and params schemas defined in the route.\n * It also handles errors and redirects.\n */\n public async createLayers(\n route: PageRoute,\n state: ReactRouterState,\n previous: PreviousLayerData[] = [],\n ): Promise<CreateLayersResult> {\n let context: Record<string, any> = {}; // all props\n const stack: Array<RouterStackItem> = [{ route }]; // stack of routes\n\n let parent = route.parent;\n while (parent) {\n stack.unshift({ route: parent });\n parent = parent.parent;\n }\n\n let forceRefresh = false;\n\n for (let i = 0; i < stack.length; i++) {\n const it = stack[i];\n const route = it.route;\n const config: Record<string, any> = {};\n\n try {\n this.convertStringObjectToObject(route.schema?.query, state.query);\n config.query = route.schema?.query\n ? this.alepha.parse(route.schema.query, state.query)\n : {};\n } catch (e) {\n it.error = e as Error;\n break;\n }\n\n try {\n config.params = route.schema?.params\n ? this.alepha.parse(route.schema.params, state.params)\n : {};\n } catch (e) {\n it.error = e as Error;\n break;\n }\n\n // save config\n it.config = {\n ...config,\n };\n\n // check if previous layer is the same, reuse if possible\n if (previous?.[i] && !forceRefresh && previous[i].name === route.name) {\n const url = (str?: string) => (str ? str.replace(/\\/\\/+/g, \"/\") : \"/\");\n\n const prev = JSON.stringify({\n part: url(previous[i].part),\n params: previous[i].config?.params ?? {},\n });\n\n const curr = JSON.stringify({\n part: url(route.path),\n params: config.params ?? {},\n });\n\n if (prev === curr) {\n // part is the same, reuse previous layer\n it.props = previous[i].props;\n it.error = previous[i].error;\n it.cache = true;\n context = {\n ...context,\n ...it.props,\n };\n continue;\n }\n\n // part is different, force refresh of next layers\n forceRefresh = true;\n }\n\n // no resolve, render a basic view by default\n if (!route.resolve) {\n continue;\n }\n\n try {\n const args = Object.create(state);\n Object.assign(args, config, context);\n const props = (await route.resolve?.(args)) ?? {};\n\n // save props\n it.props = {\n ...props,\n };\n\n // add props to context\n context = {\n ...context,\n ...props,\n };\n } catch (e) {\n // check if we need to redirect\n if (e instanceof Redirection) {\n return {\n redirect: e.redirect,\n };\n }\n\n this.log.error(\"Page resolver has failed\", e);\n\n it.error = e as Error;\n break;\n }\n }\n\n let acc = \"\";\n for (let i = 0; i < stack.length; i++) {\n const it = stack[i];\n const props = it.props ?? {};\n\n const params = { ...it.config?.params };\n for (const key of Object.keys(params)) {\n params[key] = String(params[key]);\n }\n\n acc += \"/\";\n acc += it.route.path ? this.compile(it.route.path, params) : \"\";\n const path = acc.replace(/\\/+/, \"/\");\n const localErrorHandler = this.getErrorHandler(it.route);\n if (localErrorHandler) {\n const onErrorParent = state.onError;\n state.onError = (error, context) => {\n const result = localErrorHandler(error, context);\n // if nothing happen, call the parent\n if (result === undefined) {\n return onErrorParent(error, context);\n }\n return result;\n };\n }\n\n // normal use case\n if (!it.error) {\n try {\n const element = await this.createElement(it.route, {\n ...props,\n ...context,\n });\n\n state.layers.push({\n name: it.route.name,\n props,\n part: it.route.path,\n config: it.config,\n element: this.renderView(i + 1, path, element, it.route),\n index: i + 1,\n path,\n route: it.route,\n cache: it.cache,\n });\n } catch (e) {\n it.error = e as Error;\n }\n }\n\n // handler has thrown an error, render an error view\n if (it.error) {\n try {\n let element: ReactNode | Redirection | undefined =\n await state.onError(it.error, state);\n\n if (element === undefined) {\n throw it.error;\n }\n\n if (element instanceof Redirection) {\n return {\n redirect: element.redirect,\n };\n }\n\n if (element === null) {\n element = this.renderError(it.error);\n }\n\n state.layers.push({\n props,\n error: it.error,\n name: it.route.name,\n part: it.route.path,\n config: it.config,\n element: this.renderView(i + 1, path, element, it.route),\n index: i + 1,\n path,\n route: it.route,\n });\n break;\n } catch (e) {\n if (e instanceof Redirection) {\n return {\n redirect: e.redirect,\n };\n }\n throw e;\n }\n }\n }\n\n return { state };\n }\n\n protected createRedirectionLayer(redirect: string): CreateLayersResult {\n return {\n redirect,\n };\n }\n\n protected getErrorHandler(route: PageRoute): ErrorHandler | undefined {\n if (route.errorHandler) return route.errorHandler;\n let parent = route.parent;\n while (parent) {\n if (parent.errorHandler) return parent.errorHandler;\n parent = parent.parent;\n }\n }\n\n protected async createElement(\n page: PageRoute,\n props: Record<string, any>,\n ): Promise<ReactNode> {\n if (page.lazy && page.component) {\n this.log.warn(\n `Page ${page.name} has both lazy and component options, lazy will be used`,\n );\n }\n\n if (page.lazy) {\n const component = await page.lazy(); // load component\n return createElement(component.default, props);\n }\n\n if (page.component) {\n return createElement(page.component, props);\n }\n\n return undefined;\n }\n\n public renderError(error: Error): ReactNode {\n return createElement(ErrorViewer, { error, alepha: this.alepha });\n }\n\n public renderEmptyView(): ReactNode {\n return createElement(NestedView, {});\n }\n\n public href(\n page: { options: { name?: string } },\n params: Record<string, any> = {},\n ): string {\n const found = this.pages.find((it) => it.name === page.options.name);\n if (!found) {\n throw new Error(`Page ${page.options.name} not found`);\n }\n\n let url = found.path ?? \"\";\n let parent = found.parent;\n while (parent) {\n url = `${parent.path ?? \"\"}/${url}`;\n parent = parent.parent;\n }\n\n url = this.compile(url, params);\n\n return url.replace(/\\/\\/+/g, \"/\") || \"/\";\n }\n\n public compile(path: string, params: Record<string, string> = {}) {\n for (const [key, value] of Object.entries(params)) {\n path = path.replace(`:${key}`, value);\n }\n return path;\n }\n\n protected renderView(\n index: number,\n path: string,\n view: ReactNode | undefined,\n page: PageRoute,\n ): ReactNode {\n view ??= this.renderEmptyView();\n\n const element = page.client\n ? createElement(\n ClientOnly,\n typeof page.client === \"object\" ? page.client : {},\n view,\n )\n : view;\n\n return createElement(\n RouterLayerContext.Provider,\n {\n value: {\n index,\n path,\n },\n },\n element,\n );\n }\n\n protected readonly configure = $hook({\n on: \"configure\",\n handler: () => {\n let hasNotFoundHandler = false;\n const pages = this.alepha.descriptors($page);\n\n const hasParent = (it: PageDescriptor) => {\n if (it.options.parent) {\n return true;\n }\n\n for (const page of pages) {\n const children = page.options.children\n ? Array.isArray(page.options.children)\n ? page.options.children\n : page.options.children()\n : [];\n if (children.includes(it)) {\n return true;\n }\n }\n };\n\n for (const page of pages) {\n if (page.options.path === \"/*\") {\n hasNotFoundHandler = true;\n }\n\n // skip children, we only want root pages\n if (hasParent(page)) {\n continue;\n }\n\n this.add(this.map(pages, page));\n }\n\n if (!hasNotFoundHandler && pages.length > 0) {\n // add a default 404 page if not already defined\n this.add({\n path: \"/*\",\n name: \"notFound\",\n cache: true,\n component: NotFoundPage,\n onServerResponse: ({ reply }) => {\n reply.status = 404;\n },\n });\n }\n },\n });\n\n protected map(\n pages: Array<PageDescriptor>,\n target: PageDescriptor,\n ): PageRouteEntry {\n const children = target.options.children\n ? Array.isArray(target.options.children)\n ? target.options.children\n : target.options.children()\n : [];\n\n const getChildrenFromParent = (it: PageDescriptor): PageDescriptor[] => {\n const children = [];\n for (const page of pages) {\n if (page.options.parent === it) {\n children.push(page);\n }\n }\n return children;\n };\n\n children.push(...getChildrenFromParent(target));\n\n return {\n ...target.options,\n name: target.name,\n parent: undefined,\n children: children.map((it) => this.map(pages, it)),\n } as PageRoute;\n }\n\n public add(entry: PageRouteEntry) {\n if (this.alepha.isReady()) {\n throw new AlephaError(\"Router is already initialized\");\n }\n\n entry.name ??= this.nextId();\n const page = entry as PageRoute;\n\n page.match = this.createMatch(page);\n this.pages.push(page);\n\n if (page.children) {\n for (const child of page.children) {\n (child as PageRoute).parent = page;\n this.add(child);\n }\n }\n }\n\n protected createMatch(page: PageRoute): string {\n let url = page.path ?? \"/\";\n let target = page.parent;\n while (target) {\n url = `${target.path ?? \"\"}/${url}`;\n target = target.parent;\n }\n\n let path = url.replace(/\\/\\/+/g, \"/\");\n\n if (path.endsWith(\"/\") && path !== \"/\") {\n // remove trailing slash\n path = path.slice(0, -1);\n }\n\n return path;\n }\n\n protected _next = 0;\n\n protected nextId(): string {\n this._next += 1;\n return `P${this._next}`;\n }\n}\n\nexport const isPageRoute = (it: any): it is PageRoute => {\n return (\n it &&\n typeof it === \"object\" &&\n typeof it.path === \"string\" &&\n typeof it.page === \"object\"\n );\n};\n\nexport interface PageRouteEntry\n extends Omit<PageDescriptorOptions, \"children\" | \"parent\"> {\n children?: PageRouteEntry[];\n}\n\nexport interface PageRoute extends PageRouteEntry {\n type: \"page\";\n name: string;\n parent?: PageRoute;\n match: string;\n}\n\nexport interface Layer {\n config?: {\n query?: Record<string, any>;\n params?: Record<string, any>;\n // stack of resolved props\n context?: Record<string, any>;\n };\n\n name: string;\n props?: Record<string, any>;\n error?: Error;\n part?: string;\n element: ReactNode;\n index: number;\n path: string;\n route?: PageRoute;\n cache?: boolean;\n}\n\nexport type PreviousLayerData = Omit<Layer, \"element\" | \"index\" | \"path\">;\n\nexport interface AnchorProps {\n href: string;\n onClick: (ev?: any) => any;\n}\n\nexport interface ReactRouterState {\n /**\n * Stack of layers for the current page.\n */\n layers: Array<Layer>;\n\n /**\n * URL of the current page.\n */\n url: URL;\n\n /**\n * Error handler for the current page.\n */\n onError: ErrorHandler;\n\n /**\n * Params extracted from the URL for the current page.\n */\n params: Record<string, any>;\n\n /**\n * Query parameters extracted from the URL for the current page.\n */\n query: Record<string, string>;\n\n /**\n * Optional meta information associated with the current page.\n */\n meta: Record<string, any>;\n}\n\nexport interface RouterStackItem {\n route: PageRoute;\n config?: Record<string, any>;\n props?: Record<string, any>;\n error?: Error;\n cache?: boolean;\n}\n\nexport interface TransitionOptions {\n previous?: PreviousLayerData[];\n}\n\nexport interface CreateLayersResult {\n redirect?: string;\n state?: ReactRouterState;\n}\n","import { existsSync } from \"node:fs\";\nimport { join } from \"node:path\";\nimport {\n $env,\n $hook,\n $inject,\n Alepha,\n AlephaError,\n type Static,\n t,\n} from \"@alepha/core\";\nimport { $logger } from \"@alepha/logger\";\nimport {\n type ServerHandler,\n ServerProvider,\n ServerRouterProvider,\n ServerTimingProvider,\n} from \"@alepha/server\";\nimport { ServerLinksProvider } from \"@alepha/server-links\";\nimport { ServerStaticProvider } from \"@alepha/server-static\";\nimport { renderToString } from \"react-dom/server\";\nimport {\n $page,\n type PageDescriptorRenderOptions,\n type PageDescriptorRenderResult,\n} from \"../descriptors/$page.ts\";\nimport { Redirection } from \"../errors/Redirection.ts\";\nimport type { ReactHydrationState } from \"./ReactBrowserProvider.ts\";\nimport {\n type PageRoute,\n ReactPageProvider,\n type ReactRouterState,\n} from \"./ReactPageProvider.ts\";\n\nconst envSchema = t.object({\n REACT_SERVER_DIST: t.text({ default: \"public\" }),\n REACT_SERVER_PREFIX: t.text({ default: \"\" }),\n REACT_SSR_ENABLED: t.optional(t.boolean()),\n REACT_ROOT_ID: t.text({ default: \"root\" }),\n REACT_SERVER_TEMPLATE: t.optional(\n t.text({\n size: \"rich\",\n }),\n ),\n});\n\ndeclare module \"@alepha/core\" {\n interface Env extends Partial<Static<typeof envSchema>> {}\n interface State {\n \"react.server.ssr\"?: boolean;\n }\n}\n\nexport class ReactServerProvider {\n protected readonly log = $logger();\n protected readonly alepha = $inject(Alepha);\n protected readonly pageApi = $inject(ReactPageProvider);\n protected readonly serverProvider = $inject(ServerProvider);\n protected readonly serverStaticProvider = $inject(ServerStaticProvider);\n protected readonly serverRouterProvider = $inject(ServerRouterProvider);\n protected readonly serverTimingProvider = $inject(ServerTimingProvider);\n protected readonly env = $env(envSchema);\n protected readonly ROOT_DIV_REGEX = new RegExp(\n `<div([^>]*)\\\\s+id=[\"']${this.env.REACT_ROOT_ID}[\"']([^>]*)>(.*?)<\\\\/div>`,\n \"is\",\n );\n protected preprocessedTemplate: PreprocessedTemplate | null = null;\n\n public readonly onConfigure = $hook({\n on: \"configure\",\n handler: async () => {\n const pages = this.alepha.descriptors($page);\n\n const ssrEnabled =\n pages.length > 0 && this.env.REACT_SSR_ENABLED !== false;\n\n this.alepha.state.set(\"react.server.ssr\", ssrEnabled);\n\n for (const page of pages) {\n page.render = this.createRenderFunction(page.name);\n page.fetch = async (options) => {\n const response = await fetch(\n `${this.serverProvider.hostname}/${page.pathname(options)}`,\n );\n const html = await response.text();\n if (options?.html) return { html, response };\n // take only text inside the root div\n const match = html.match(this.ROOT_DIV_REGEX);\n if (match) {\n return { html: match[3], response };\n }\n throw new AlephaError(\"Invalid HTML response\");\n };\n }\n\n // development mode\n if (this.alepha.isViteDev()) {\n await this.configureVite(ssrEnabled);\n return;\n }\n\n // production mode\n let root = \"\";\n\n // non-serverless mode only -> serve static files\n if (!this.alepha.isServerless()) {\n root = this.getPublicDirectory();\n if (!root) {\n this.log.warn(\n \"Missing static files, static file server will be disabled\",\n );\n } else {\n this.log.debug(`Using static files from: ${root}`);\n await this.configureStaticServer(root);\n }\n }\n\n if (ssrEnabled) {\n await this.registerPages(async () => this.template);\n this.log.info(\"SSR OK\");\n return;\n }\n\n // no SSR enabled, serve index.html for all unmatched routes\n this.log.info(\"SSR is disabled, use History API fallback\");\n this.serverRouterProvider.createRoute({\n path: \"*\",\n handler: async ({ url, reply }) => {\n if (url.pathname.includes(\".\")) {\n // If the request is for a file (e.g., /style.css), do not fallback\n reply.headers[\"content-type\"] = \"text/plain\";\n reply.body = \"Not Found\";\n reply.status = 404;\n return;\n }\n\n reply.headers[\"content-type\"] = \"text/html\";\n\n // serve index.html for all unmatched routes\n return this.template;\n },\n });\n },\n });\n\n public get template() {\n return (\n this.alepha.env.REACT_SERVER_TEMPLATE ??\n \"<!DOCTYPE html><html lang='en'><head></head><body></body></html>\"\n );\n }\n\n protected async registerPages(templateLoader: TemplateLoader) {\n // Preprocess template once\n const template = await templateLoader();\n if (template) {\n this.preprocessedTemplate = this.preprocessTemplate(template);\n }\n\n for (const page of this.pageApi.getPages()) {\n if (page.children?.length) {\n continue;\n }\n\n this.log.debug(`+ ${page.match} -> ${page.name}`);\n\n this.serverRouterProvider.createRoute({\n ...page,\n schema: undefined, // schema is handled by the page descriptor provider for now (shared by browser and server)\n method: \"GET\",\n path: page.match,\n handler: this.createHandler(page, templateLoader),\n });\n }\n }\n\n protected getPublicDirectory(): string {\n const maybe = [\n join(process.cwd(), `dist/${this.env.REACT_SERVER_DIST}`),\n join(process.cwd(), this.env.REACT_SERVER_DIST),\n ];\n\n for (const it of maybe) {\n if (existsSync(it)) {\n return it;\n }\n }\n\n return \"\";\n }\n\n protected async configureStaticServer(root: string) {\n await this.serverStaticProvider.createStaticServer({\n root,\n path: this.env.REACT_SERVER_PREFIX,\n });\n }\n\n protected async configureVite(ssrEnabled: boolean) {\n if (!ssrEnabled) {\n // do nothing, vite will handle everything for us\n return;\n }\n\n this.log.info(\"SSR (vite) OK\");\n\n const url = `http://${process.env.SERVER_HOST}:${process.env.SERVER_PORT}`;\n\n await this.registerPages(() =>\n fetch(`${url}/index.html`)\n .then((it) => it.text())\n .catch(() => undefined),\n );\n }\n\n /**\n * For testing purposes, creates a render function that can be used.\n */\n protected createRenderFunction(name: string, withIndex = false) {\n return async (\n options: PageDescriptorRenderOptions = {},\n ): Promise<PageDescriptorRenderResult> => {\n const page = this.pageApi.page(name);\n const url = new URL(this.pageApi.url(name, options));\n\n const entry: Partial<ReactRouterState> = {\n url,\n params: options.params ?? {},\n query: options.query ?? {},\n onError: () => null,\n layers: [],\n meta: {},\n };\n\n const state = entry as ReactRouterState;\n\n this.log.trace(\"Rendering\", {\n url,\n });\n\n await this.alepha.events.emit(\"react:server:render:begin\", {\n state,\n });\n\n const { redirect } = await this.pageApi.createLayers(\n page,\n state as ReactRouterState,\n );\n\n if (redirect) {\n return { state, html: \"\", redirect };\n }\n\n if (!withIndex && !options.html) {\n this.alepha.state.set(\"react.router.state\", state);\n\n return {\n state,\n html: renderToString(this.pageApi.root(state)),\n };\n }\n\n const template = this.template ?? \"\";\n const html = this.renderToHtml(template, state, options.hydration);\n\n if (html instanceof Redirection) {\n return { state, html: \"\", redirect };\n }\n\n const result = {\n state,\n html,\n };\n\n await this.alepha.events.emit(\"react:server:render:end\", result);\n\n return result;\n };\n }\n\n protected createHandler(\n route: PageRoute,\n templateLoader: TemplateLoader,\n ): ServerHandler {\n return async (serverRequest) => {\n const { url, reply, query, params } = serverRequest;\n const template = await templateLoader();\n if (!template) {\n throw new Error(\"Template not found\");\n }\n\n this.log.trace(\"Rendering page\", {\n name: route.name,\n });\n\n const entry: Partial<ReactRouterState> = {\n url,\n params,\n query,\n onError: () => null,\n layers: [],\n };\n\n const state = entry as ReactRouterState;\n\n if (this.alepha.has(ServerLinksProvider)) {\n this.alepha.state.set(\n \"api\",\n await this.alepha.inject(ServerLinksProvider).getUserApiLinks({\n user: (serverRequest as any).user, // TODO: fix type\n authorization: serverRequest.headers.authorization,\n }),\n );\n }\n\n let target: PageRoute | undefined = route; // TODO: move to PageDescriptorProvider\n while (target) {\n if (route.can && !route.can()) {\n // if the page is not accessible, return 403\n reply.status = 403;\n reply.headers[\"content-type\"] = \"text/plain\";\n return \"Forbidden\";\n }\n target = target.parent;\n }\n\n // TODO: SSR strategies\n // - only when googlebot\n // - only child pages\n // if (page.client) {\n // \t// if the page is a client-only page, return 404\n // \treply.status = 200;\n // \treply.headers[\"content-type\"] = \"text/html\";\n // \treply.body = template;\n // \treturn;\n // }\n\n await this.alepha.events.emit(\"react:server:render:begin\", {\n request: serverRequest,\n state,\n });\n\n this.serverTimingProvider.beginTiming(\"createLayers\");\n\n const { redirect } = await this.pageApi.createLayers(route, state);\n\n this.serverTimingProvider.endTiming(\"createLayers\");\n\n if (redirect) {\n return reply.redirect(redirect);\n }\n\n reply.headers[\"content-type\"] = \"text/html\";\n\n // by default, disable caching for SSR responses\n // some plugins may override this\n reply.headers[\"cache-control\"] =\n \"no-store, no-cache, must-revalidate, proxy-revalidate\";\n reply.headers.pragma = \"no-cache\";\n reply.headers.expires = \"0\";\n\n const html = this.renderToHtml(template, state);\n if (html instanceof Redirection) {\n reply.redirect(\n typeof html.redirect === \"string\"\n ? html.redirect\n : this.pageApi.href(html.redirect),\n );\n return;\n }\n\n const event = {\n request: serverRequest,\n state,\n html,\n };\n\n await this.alepha.events.emit(\"react:server:render:end\", event);\n\n route.onServerResponse?.(serverRequest);\n\n this.log.trace(\"Page rendered\", {\n name: route.name,\n });\n\n return event.html;\n };\n }\n\n public renderToHtml(\n template: string,\n state: ReactRouterState,\n hydration = true,\n ): string | Redirection {\n const element = this.pageApi.root(state);\n\n // attach react router state to the http request context\n this.alepha.state.set(\"react.router.state\", state);\n\n this.serverTimingProvider.beginTiming(\"renderToString\");\n let app = \"\";\n try {\n app = renderToString(element);\n } catch (error) {\n this.log.error(\n \"renderToString has failed, fallback to error handler\",\n error,\n );\n const element = state.onError(error as Error, state);\n if (element instanceof Redirection) {\n // if the error is a redirection, return the redirection URL\n return element;\n }\n\n app = renderToString(element);\n this.log.debug(\"Error handled successfully with fallback\");\n }\n this.serverTimingProvider.endTiming(\"renderToString\");\n\n const response = {\n html: template,\n };\n\n if (hydration) {\n const { request, context, ...store } =\n this.alepha.context.als?.getStore() ?? {}; /// TODO: als must be protected, find a way to iterate on alepha.state\n\n const hydrationData: ReactHydrationState = {\n ...store,\n // map react.router.state to the hydration state\n \"react.router.state\": undefined,\n layers: state.layers.map((it) => ({\n ...it,\n error: it.error\n ? {\n ...it.error,\n name: it.error.name,\n message: it.error.message,\n stack: !this.alepha.isProduction() ? it.error.stack : undefined,\n }\n : undefined,\n index: undefined,\n path: undefined,\n element: undefined,\n route: undefined,\n })),\n };\n\n // create hydration data\n const script = `<script>window.__ssr=${JSON.stringify(hydrationData)}</script>`;\n\n // inject app into template\n this.fillTemplate(response, app, script);\n }\n\n return response.html;\n }\n\n protected preprocessTemplate(template: string): PreprocessedTemplate {\n // Find the body close tag for script injection\n const bodyCloseMatch = template.match(/<\\/body>/i);\n const bodyCloseIndex = bodyCloseMatch?.index ?? template.length;\n\n const beforeScript = template.substring(0, bodyCloseIndex);\n const afterScript = template.substring(bodyCloseIndex);\n\n // Check if there's an existing root div\n const rootDivMatch = beforeScript.match(this.ROOT_DIV_REGEX);\n\n if (rootDivMatch) {\n // Split around the existing root div content\n const beforeDiv = beforeScript.substring(0, rootDivMatch.index!);\n const afterDivStart = rootDivMatch.index! + rootDivMatch[0].length;\n const afterDiv = beforeScript.substring(afterDivStart);\n\n const beforeApp = `${beforeDiv}<div${rootDivMatch[1]} id=\"${this.env.REACT_ROOT_ID}\"${rootDivMatch[2]}>`;\n const afterApp = `</div>${afterDiv}`;\n\n return { beforeApp, afterApp, beforeScript: \"\", afterScript };\n }\n\n // No existing root div, find body tag to inject new div\n const bodyMatch = beforeScript.match(/<body([^>]*)>/i);\n if (bodyMatch) {\n const beforeBody = beforeScript.substring(\n 0,\n bodyMatch.index! + bodyMatch[0].length,\n );\n const afterBody = beforeScript.substring(\n bodyMatch.index! + bodyMatch[0].length,\n );\n\n const beforeApp = `${beforeBody}<div id=\"${this.env.REACT_ROOT_ID}\">`;\n const afterApp = `</div>${afterBody}`;\n\n return { beforeApp, afterApp, beforeScript: \"\", afterScript };\n }\n\n // Fallback: no body tag found, just wrap everything\n return {\n beforeApp: `<div id=\"${this.env.REACT_ROOT_ID}\">`,\n afterApp: `</div>`,\n beforeScript,\n afterScript,\n };\n }\n\n protected fillTemplate(\n response: { html: string },\n app: string,\n script: string,\n ) {\n if (!this.preprocessedTemplate) {\n // Fallback to old logic if preprocessing failed\n this.preprocessedTemplate = this.preprocessTemplate(response.html);\n }\n\n // Pure concatenation - no regex replacements needed\n response.html =\n this.preprocessedTemplate.beforeApp +\n app +\n this.preprocessedTemplate.afterApp +\n script +\n this.preprocessedTemplate.afterScript;\n }\n}\n\ntype TemplateLoader = () => Promise<string | undefined>;\n\ninterface PreprocessedTemplate {\n beforeApp: string;\n afterApp: string;\n beforeScript: string;\n afterScript: 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 isPageRoute,\n type PageRoute,\n type PageRouteEntry,\n type PreviousLayerData,\n ReactPageProvider,\n type ReactRouterState,\n} from \"./ReactPageProvider.ts\";\n\nexport interface BrowserRoute extends Route {\n page: PageRoute;\n}\n\nexport class ReactBrowserRouterProvider extends RouterProvider<BrowserRoute> {\n protected readonly log = $logger();\n protected readonly alepha = $inject(Alepha);\n protected readonly pageApi = $inject(ReactPageProvider);\n\n public add(entry: PageRouteEntry) {\n this.pageApi.add(entry);\n }\n\n protected readonly configure = $hook({\n on: \"configure\",\n handler: async () => {\n for (const page of this.pageApi.getPages()) {\n // mount only if a view is provided\n if (page.component || page.lazy) {\n this.push({\n path: page.match,\n page,\n });\n }\n }\n },\n });\n\n public async transition(\n url: URL,\n previous: PreviousLayerData[] = [],\n meta = {},\n ): Promise<string | void> {\n const { pathname, search } = url;\n\n const entry: Partial<ReactRouterState> = {\n url,\n query: {},\n params: {},\n layers: [],\n onError: () => null,\n meta,\n };\n\n const state = entry as ReactRouterState;\n\n await this.alepha.events.emit(\"react:transition:begin\", {\n previous: this.alepha.state.get(\"react.router.state\")!,\n state,\n });\n\n try {\n const { route, params } = this.match(pathname);\n\n const query: Record<string, string> = {};\n if (search) {\n for (const [key, value] of new URLSearchParams(search).entries()) {\n query[key] = String(value);\n }\n }\n\n state.query = query;\n state.params = params ?? {};\n\n if (isPageRoute(route)) {\n const { redirect } = await this.pageApi.createLayers(\n route.page,\n state,\n previous,\n );\n if (redirect) {\n return redirect;\n }\n }\n\n if (state.layers.length === 0) {\n state.layers.push({\n name: \"not-found\",\n element: createElement(NotFoundPage),\n index: 0,\n path: \"/\",\n });\n }\n\n await this.alepha.events.emit(\"react:transition:success\", { state });\n } catch (e) {\n this.log.error(\"Transition has failed\", e);\n state.layers = [\n {\n name: \"error\",\n element: this.pageApi.renderError(e as Error),\n index: 0,\n path: \"/\",\n },\n ];\n\n await this.alepha.events.emit(\"react:transition:error\", {\n error: e as Error,\n state,\n });\n }\n\n // [feature]: local hook for leaving a page\n if (previous) {\n for (let i = 0; i < previous.length; i++) {\n const layer = previous[i];\n if (state.layers[i]?.name !== layer.name) {\n this.pageApi.page(layer.name)?.onLeave?.();\n }\n }\n }\n\n this.alepha.state.set(\"react.router.state\", state);\n\n await this.alepha.events.emit(\"react:transition:end\", {\n state,\n });\n }\n\n public root(state: ReactRouterState): ReactNode {\n return this.pageApi.root(state);\n }\n}\n","import {\n $env,\n $hook,\n $inject,\n Alepha,\n type State,\n type Static,\n t,\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 PreviousLayerData,\n ReactRouterState,\n TransitionOptions,\n} from \"./ReactPageProvider.ts\";\n\nconst envSchema = t.object({\n REACT_ROOT_ID: t.text({ default: \"root\" }),\n});\n\ndeclare module \"@alepha/core\" {\n interface Env extends Partial<Static<typeof envSchema>> {}\n}\n\nexport interface ReactBrowserRendererOptions {\n scrollRestoration?: \"top\" | \"manual\";\n}\n\nexport class ReactBrowserProvider {\n protected readonly env = $env(envSchema);\n protected readonly log = $logger();\n protected readonly client = $inject(LinkProvider);\n protected readonly alepha = $inject(Alepha);\n protected readonly router = $inject(ReactBrowserRouterProvider);\n protected readonly dateTimeProvider = $inject(DateTimeProvider);\n\n public options: ReactBrowserRendererOptions = {\n scrollRestoration: \"top\",\n };\n\n protected getRootElement() {\n const root = this.document.getElementById(this.env.REACT_ROOT_ID);\n if (root) {\n return root;\n }\n\n const div = this.document.createElement(\"div\");\n div.id = this.env.REACT_ROOT_ID;\n\n this.document.body.prepend(div);\n\n return div;\n }\n\n public transitioning?: {\n to: string;\n from?: string;\n };\n\n public get state(): ReactRouterState {\n return this.alepha.state.get(\"react.router.state\")!;\n }\n\n /**\n * Accessor for Document DOM API.\n */\n public get document() {\n return window.document;\n }\n\n /**\n * Accessor for History DOM API.\n */\n public get history() {\n return window.history;\n }\n\n /**\n * Accessor for Location DOM API.\n */\n public get location() {\n return window.location;\n }\n\n public get base() {\n const base = import.meta.env?.BASE_URL;\n if (!base || base === \"/\") {\n return \"\";\n }\n\n return base;\n }\n\n public get url(): string {\n const url = this.location.pathname + this.location.search;\n if (this.base) {\n return url.replace(this.base, \"\");\n }\n return url;\n }\n\n public pushState(path: string, replace?: boolean) {\n const url = this.base + path;\n\n if (replace) {\n this.history.replaceState({}, \"\", url);\n } else {\n this.history.pushState({}, \"\", url);\n }\n }\n\n public async invalidate(props?: Record<string, any>) {\n const previous: PreviousLayerData[] = [];\n\n this.log.trace(\"Invalidating layers\");\n\n if (props) {\n const [key] = Object.keys(props);\n const value = props[key];\n\n for (const layer of this.state.layers) {\n if (layer.props?.[key]) {\n previous.push({\n ...layer,\n props: {\n ...layer.props,\n [key]: value,\n },\n });\n break;\n }\n previous.push(layer);\n }\n }\n\n await this.render({ previous });\n }\n\n public async go(url: string, options: RouterGoOptions = {}): Promise<void> {\n this.log.trace(`Going to ${url}`, {\n url,\n options,\n });\n\n await this.render({\n url,\n previous: options.force ? [] : this.state.layers,\n meta: options.meta,\n });\n\n // when redirecting in browser\n if (this.state.url.pathname + this.state.url.search !== url) {\n this.pushState(this.state.url.pathname + this.state.url.search);\n return;\n }\n\n this.pushState(url, options.replace);\n }\n\n protected async render(options: RouterRenderOptions = {}): Promise<void> {\n const previous = options.previous ?? this.state.layers;\n const url = options.url ?? this.url;\n const start = this.dateTimeProvider.now();\n\n this.transitioning = {\n to: url,\n from: this.state?.url.pathname,\n };\n\n this.log.debug(\"Transitioning...\", {\n to: url,\n });\n\n const redirect = await this.router.transition(\n new URL(`http://localhost${url}`),\n previous,\n options.meta,\n );\n\n if (redirect) {\n this.log.info(\"Redirecting to\", {\n redirect,\n });\n\n // if redirect is an absolute URL, use window.location.href (full page reload)\n if (redirect.startsWith(\"http\")) {\n window.location.href = redirect;\n } else {\n // if redirect is a relative URL, use render() (single page app)\n return await this.render({ url: redirect });\n }\n }\n\n const ms = this.dateTimeProvider.now().diff(start);\n this.log.info(`Transition OK [${ms}ms]`, this.transitioning);\n\n this.transitioning = undefined;\n }\n\n /**\n * Get embedded layers from the server.\n */\n protected getHydrationState(): ReactHydrationState | undefined {\n try {\n if (\"__ssr\" in window && typeof window.__ssr === \"object\") {\n return window.__ssr as ReactHydrationState;\n }\n } catch (error) {\n console.error(error);\n }\n }\n\n // -------------------------------------------------------------------------------------------------------------------\n\n protected readonly onTransitionEnd = $hook({\n on: \"react:transition:end\",\n handler: () => {\n if (\n this.options.scrollRestoration === \"top\" &&\n typeof window !== \"undefined\" &&\n !this.alepha.isTest()\n ) {\n this.log.trace(\"Restoring scroll position to top\");\n window.scrollTo(0, 0);\n }\n },\n });\n\n public readonly ready = $hook({\n on: \"ready\",\n handler: async () => {\n const hydration = this.getHydrationState();\n const previous = hydration?.layers ?? [];\n\n if (hydration) {\n // low budget, but works for now\n for (const [key, value] of Object.entries(hydration)) {\n if (key !== \"layers\") {\n this.alepha.state.set(key as keyof State, value);\n }\n }\n }\n\n await this.render({ previous });\n\n const element = this.router.root(this.state);\n\n await this.alepha.events.emit(\"react:browser:render\", {\n element,\n root: this.getRootElement(),\n hydration,\n state: this.state,\n });\n\n window.addEventListener(\"popstate\", () => {\n // when you update silently queryParams or hash, skip rendering\n // if you want to force a rendering, use #go()\n if (this.base + this.state.url.pathname === this.location.pathname) {\n return;\n }\n\n this.log.debug(\"Popstate event triggered - rendering new state\", {\n url: this.location.pathname + this.location.search,\n });\n\n this.render();\n });\n },\n });\n}\n\n// ---------------------------------------------------------------------------------------------------------------------\n\nexport interface RouterGoOptions {\n replace?: boolean;\n match?: TransitionOptions;\n params?: Record<string, string>;\n query?: Record<string, string>;\n meta?: Record<string, any>;\n\n /**\n * Recreate the whole page, ignoring the current state.\n */\n force?: boolean;\n}\n\nexport type ReactHydrationState = {\n layers?: Array<PreviousLayerData>;\n} & {\n [key: string]: any;\n};\n\nexport interface RouterRenderOptions {\n url?: string;\n previous?: PreviousLayerData[];\n meta?: Record<string, any>;\n}\n","import { $inject, Alepha } from \"@alepha/core\";\nimport type { PageDescriptor } from \"../descriptors/$page.ts\";\nimport {\n ReactBrowserProvider,\n type RouterGoOptions,\n} from \"../providers/ReactBrowserProvider.ts\";\nimport {\n type AnchorProps,\n ReactPageProvider,\n type ReactRouterState,\n} from \"../providers/ReactPageProvider.ts\";\n\nexport class ReactRouter<T extends object> {\n protected readonly alepha = $inject(Alepha);\n protected readonly pageApi = $inject(ReactPageProvider);\n\n public get state(): ReactRouterState {\n return this.alepha.state.get(\"react.router.state\")!;\n }\n\n public get pages() {\n return this.pageApi.getPages();\n }\n\n public get browser(): ReactBrowserProvider | undefined {\n if (this.alepha.isBrowser()) {\n return this.alepha.inject(ReactBrowserProvider);\n }\n // server-side\n return undefined;\n }\n\n public path(\n name: keyof VirtualRouter<T>,\n config: {\n params?: Record<string, any>;\n query?: Record<string, any>;\n } = {},\n ): string {\n return this.pageApi.pathname(name as string, {\n params: {\n ...this.state.params,\n ...config.params,\n },\n query: config.query,\n });\n }\n\n /**\n * Reload the current page.\n * This is equivalent to calling `go()` with the current pathname and search.\n */\n public async reload() {\n if (!this.browser) {\n return;\n }\n\n await this.go(this.location.pathname + this.location.search, {\n replace: true,\n force: true,\n });\n }\n\n public getURL(): URL {\n if (!this.browser) {\n return this.state.url;\n }\n\n return new URL(this.location.href);\n }\n\n public get location(): Location {\n if (!this.browser) {\n throw new Error(\"Browser is required\");\n }\n\n return this.browser.location;\n }\n\n public get current(): ReactRouterState {\n return this.state;\n }\n\n public get pathname(): string {\n return this.state.url.pathname;\n }\n\n public get query(): Record<string, string> {\n const query: Record<string, string> = {};\n\n for (const [key, value] of new URLSearchParams(\n this.state.url.search,\n ).entries()) {\n query[key] = String(value);\n }\n\n return query;\n }\n\n public async back() {\n this.browser?.history.back();\n }\n\n public async forward() {\n this.browser?.history.forward();\n }\n\n public async invalidate(props?: Record<string, any>) {\n await this.browser?.invalidate(props);\n }\n\n public async go(path: string, options?: RouterGoOptions): Promise<void>;\n public async go(\n path: keyof VirtualRouter<T>,\n options?: RouterGoOptions,\n ): Promise<void>;\n public async go(\n path: string | keyof VirtualRouter<T>,\n options?: RouterGoOptions,\n ): Promise<void> {\n for (const page of this.pages) {\n if (page.name === path) {\n await this.browser?.go(\n this.path(path as keyof VirtualRouter<T>, options),\n options,\n );\n return;\n }\n }\n\n await this.browser?.go(path as string, options);\n }\n\n public anchor(path: string, options?: RouterGoOptions): AnchorProps;\n public anchor(\n path: keyof VirtualRouter<T>,\n options?: RouterGoOptions,\n ): AnchorProps;\n public anchor(\n path: string | keyof VirtualRouter<T>,\n options: RouterGoOptions = {},\n ): AnchorProps {\n let href = path as string;\n\n for (const page of this.pages) {\n if (page.name === path) {\n href = this.path(path as keyof VirtualRouter<T>, options);\n break;\n }\n }\n\n return {\n href: this.base(href),\n onClick: (ev: any) => {\n ev.stopPropagation();\n ev.preventDefault();\n\n this.go(href, options).catch(console.error);\n },\n };\n }\n\n public base(path: string): string {\n const base = import.meta.env?.BASE_URL;\n if (!base || base === \"/\") {\n return path;\n }\n\n return base + path;\n }\n\n /**\n * Set query params.\n *\n * @param record\n * @param options\n */\n public setQueryParams(\n record:\n | Record<string, any>\n | ((queryParams: Record<string, any>) => Record<string, any>),\n options: {\n /**\n * If true, this will add a new entry to the history stack.\n */\n push?: boolean;\n } = {},\n ) {\n const func = typeof record === \"function\" ? record : () => record;\n const search = new URLSearchParams(func(this.query)).toString();\n const state = search ? `${this.pathname}?${search}` : this.pathname;\n\n if (options.push) {\n window.history.pushState({}, \"\", state);\n } else {\n window.history.replaceState({}, \"\", state);\n }\n }\n}\n\nexport type VirtualRouter<T> = {\n [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 const alepha = useAlepha();\n return 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 return useInject(ReactRouter<T>);\n};\n","import type { AnchorHTMLAttributes } from \"react\";\nimport { useRouter } from \"../hooks/useRouter.ts\";\n\nexport interface LinkProps extends AnchorHTMLAttributes<HTMLAnchorElement> {\n href: string;\n}\n\nconst Link = (props: LinkProps) => {\n const router = useRouter();\n\n return (\n <a {...props} {...router.anchor(props.href)}>\n {props.children}\n </a>\n );\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 href: string;\n startWith?: boolean;\n}\n\nexport const useActive = (args: string | UseActiveOptions): UseActiveHook => {\n const router = useRouter();\n const [isPending, setPending] = useState(false);\n const state = useRouterState();\n const current = state.url.pathname;\n\n const options: UseActiveOptions =\n typeof args === \"string\" ? { href: args } : { ...args, href: args.href };\n const href = options.href;\n\n let isActive =\n current === href || current === `${href}/` || `${current}/` === href;\n\n if (options.startWith && !isActive) {\n isActive = current.startsWith(href);\n }\n\n return {\n isPending,\n isActive,\n anchorProps: {\n href: router.base(href),\n onClick: async (ev?: any) => {\n ev?.stopPropagation();\n ev?.preventDefault();\n if (isActive) return;\n if (isPending) return;\n\n setPending(true);\n try {\n await router.go(href);\n } finally {\n setPending(false);\n }\n },\n },\n };\n};\n\nexport interface UseActiveHook {\n isActive: boolean;\n anchorProps: AnchorProps;\n isPending: boolean;\n}\n","import {\n type ClientScope,\n type HttpVirtualClient,\n LinkProvider,\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 scope?: ClientScope,\n): HttpVirtualClient<T> => {\n return 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 schema: T,\n options: UseQueryParamsHookOptions = {},\n): [Partial<Static<T>>, (data: Static<T>) => void] => {\n const alepha = useAlepha();\n\n const key = options.key ?? \"q\";\n const router = useRouter();\n const querystring = router.query[key];\n\n const [queryParams = {}, setQueryParams] = useState<Static<T> | undefined>(\n decode(alepha, schema, router.query[key]),\n );\n\n useEffect(() => {\n setQueryParams(decode(alepha, schema, querystring));\n }, [querystring]);\n\n return [\n queryParams,\n (queryParams: Static<T>) => {\n setQueryParams(queryParams);\n router.setQueryParams((data) => {\n return { ...data, [key]: encode(alepha, schema, queryParams) };\n });\n },\n ];\n};\n\n// ---------------------------------------------------------------------------------------------------------------------\n\nexport interface UseQueryParamsHookOptions {\n format?: \"base64\" | \"querystring\";\n key?: string;\n push?: boolean;\n}\n\nconst encode = (alepha: Alepha, schema: TObject, data: any) => {\n return btoa(JSON.stringify(alepha.parse(schema, data)));\n};\n\nconst decode = <T extends TObject>(\n alepha: Alepha,\n schema: T,\n data: any,\n): Static<T> | undefined => {\n try {\n return alepha.parse(schema, JSON.parse(atob(decodeURIComponent(data))));\n } catch {\n return;\n }\n};\n","import type { Alepha } from \"@alepha/core\";\nimport {\n type FetchOptions,\n HttpClient,\n type 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 action: VirtualAction<TConfig>,\n): UseSchemaReturn<TConfig> => {\n const name = action.name;\n const alepha = useAlepha();\n const httpClient = useInject(HttpClient);\n const [schema, setSchema] = useState<UseSchemaReturn<TConfig>>(\n ssrSchemaLoading(alepha, name) as UseSchemaReturn<TConfig>,\n );\n\n useEffect(() => {\n if (!schema.loading) {\n return;\n }\n\n const opts: FetchOptions = {\n cache: true,\n };\n\n httpClient\n .fetch(`${LinkProvider.path.apiLinks}/${name}/schema`, {}, opts)\n .then((it) => setSchema(it.data as UseSchemaReturn<TConfig>));\n }, [name]);\n\n return schema;\n};\n\nexport type UseSchemaReturn<TConfig extends RequestConfigSchema> = TConfig & {\n loading: 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 // server-side rendering (SSR) context\n if (!alepha.isBrowser()) {\n // get user links\n const linkProvider = alepha.inject(LinkProvider);\n\n // check if user can access the link\n const can = linkProvider\n .getServerLinks()\n .find((link) => link.name === name);\n\n // yes!\n if (can) {\n // user-links have no schema, so we need to get it from the provider\n const schema = linkProvider.links.find((it) => it.name === name)?.schema;\n\n // oh, we have a schema!\n if (schema) {\n // attach to user link, it will be used in the client during hydration\n can.schema = schema;\n return schema;\n }\n }\n\n return { loading: true };\n }\n\n // browser side rendering (CSR) context\n // check if we have the schema already loaded\n const schema = alepha\n .inject(LinkProvider)\n .links.find((it) => it.name === name)?.schema;\n\n // yes!\n if (schema) {\n return schema;\n }\n\n // no, we need to load it\n return { 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 ReactPageProvider,\n type 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 interface State {\n \"react.router.state\"?: ReactRouterState;\n }\n\n interface Hooks {\n \"react:server:render:begin\": {\n request?: ServerRequest;\n state: ReactRouterState;\n };\n \"react:server:render:end\": {\n request?: ServerRequest;\n state: ReactRouterState;\n html: string;\n };\n // -----------------------------------------------------------------------------------------------------------------\n \"react:browser:render\": {\n root: HTMLElement;\n element: ReactNode;\n state: ReactRouterState;\n hydration?: ReactHydrationState;\n };\n \"react:transition:begin\": {\n previous: ReactRouterState;\n state: ReactRouterState;\n animation?: PageAnimation;\n };\n \"react:transition:success\": {\n state: ReactRouterState;\n };\n \"react:transition:error\": {\n state: ReactRouterState;\n error: Error;\n };\n \"react:transition:end\": {\n state: ReactRouterState;\n };\n }\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 name: \"alepha.react\",\n descriptors: [$page],\n services: [ReactServerProvider, ReactPageProvider, ReactRouter],\n register: (alepha) =>\n alepha\n .with(AlephaServer)\n .with(AlephaServerCache)\n .with(AlephaServerLinks)\n .with(ReactServerProvider)\n .with(ReactPageProvider)\n .with(ReactRouter),\n});\n"],"mappings":"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"}
|