@alepha/react 0.7.7 → 0.8.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -1,8 +1,9 @@
1
1
  import { $hook, $inject, $logger, Alepha, KIND, NotImplementedError, OPTIONS, __bind, __descriptor, t } from "@alepha/core";
2
+ import { AlephaServer } from "@alepha/server";
3
+ import { AlephaServerLinks, LinkProvider } from "@alepha/server-links";
2
4
  import { RouterProvider } from "@alepha/router";
3
5
  import React, { StrictMode, createContext, createElement, useContext, useEffect, useMemo, useState } from "react";
4
6
  import { jsx, jsxs } from "react/jsx-runtime";
5
- import { LinkProvider } from "@alepha/server-links";
6
7
  import { createRoot, hydrateRoot } from "react-dom/client";
7
8
 
8
9
  //#region src/descriptors/$page.ts
@@ -12,11 +13,6 @@ const KEY = "PAGE";
12
13
  */
13
14
  const $page = (options) => {
14
15
  __descriptor(KEY);
15
- if (options.children) for (const child of options.children) child[OPTIONS].parent = { [OPTIONS]: options };
16
- if (options.parent) {
17
- options.parent[OPTIONS].children ??= [];
18
- options.parent[OPTIONS].children.push({ [OPTIONS]: options });
19
- }
20
16
  return {
21
17
  [KIND]: KEY,
22
18
  [OPTIONS]: options,
@@ -542,13 +538,19 @@ var PageDescriptorProvider = class {
542
538
  } }, element);
543
539
  }
544
540
  configure = $hook({
545
- name: "configure",
541
+ on: "configure",
546
542
  handler: () => {
547
543
  let hasNotFoundHandler = false;
548
544
  const pages = this.alepha.getDescriptorValues($page);
545
+ const hasParent = (it) => {
546
+ for (const page of pages) {
547
+ const children = page.value[OPTIONS].children ? Array.isArray(page.value[OPTIONS].children) ? page.value[OPTIONS].children : page.value[OPTIONS].children() : [];
548
+ if (children.includes(it)) return true;
549
+ }
550
+ };
549
551
  for (const { value, key } of pages) value[OPTIONS].name ??= key;
550
552
  for (const { value } of pages) {
551
- if (value[OPTIONS].parent) continue;
553
+ if (hasParent(value)) continue;
552
554
  if (value[OPTIONS].path === "/*") hasNotFoundHandler = true;
553
555
  this.add(this.map(pages, value));
554
556
  }
@@ -564,7 +566,7 @@ var PageDescriptorProvider = class {
564
566
  }
565
567
  });
566
568
  map(pages, target) {
567
- const children = target[OPTIONS].children ?? [];
569
+ const children = target[OPTIONS].children ? Array.isArray(target[OPTIONS].children) ? target[OPTIONS].children : target[OPTIONS].children() : [];
568
570
  return {
569
571
  ...target[OPTIONS],
570
572
  parent: void 0,
@@ -613,7 +615,7 @@ var BrowserRouterProvider = class extends RouterProvider {
613
615
  this.pageDescriptorProvider.add(entry);
614
616
  }
615
617
  configure = $hook({
616
- name: "configure",
618
+ on: "configure",
617
619
  handler: async () => {
618
620
  for (const page of this.pageDescriptorProvider.getPages()) if (page.component || page.lazy) this.push({
619
621
  path: page.match,
@@ -778,7 +780,7 @@ var ReactBrowserProvider = class {
778
780
  }
779
781
  }
780
782
  ready = $hook({
781
- name: "ready",
783
+ on: "ready",
782
784
  handler: async () => {
783
785
  const hydration = this.getHydrationState();
784
786
  const previous = hydration?.layers ?? [];
@@ -814,7 +816,7 @@ var ReactBrowserRenderer = class {
814
816
  return div;
815
817
  }
816
818
  ready = $hook({
817
- name: "react:browser:render",
819
+ on: "react:browser:render",
818
820
  handler: async ({ state, context, hydration }) => {
819
821
  const element = this.browserRouterProvider.root(state, context);
820
822
  if (hydration?.layers) {
@@ -1036,7 +1038,7 @@ const useRouterState = () => {
1036
1038
  //#region src/index.browser.ts
1037
1039
  var AlephaReact = class {
1038
1040
  name = "alepha.react";
1039
- $services = (alepha) => alepha.with(PageDescriptorProvider).with(ReactBrowserProvider).with(BrowserRouterProvider).with(ReactBrowserRenderer);
1041
+ $services = (alepha) => alepha.with(AlephaServer).with(AlephaServerLinks).with(PageDescriptorProvider).with(ReactBrowserProvider).with(BrowserRouterProvider).with(ReactBrowserRenderer);
1040
1042
  };
1041
1043
  __bind($page, AlephaReact);
1042
1044
 
@@ -1 +1 @@
1
- {"version":3,"file":"index.browser.js","names":["options: PageDescriptorOptions<TConfig, TProps, TPropsParent>","props: PropsWithChildren<ClientOnlyProps>","text: string","opts: {\n\t\tonBegin?: (ev: { state: RouterState }) => void;\n\t\tonEnd?: (ev: { state: RouterState }) => void;\n\t\tonError?: (ev: { state: RouterState; error: Error }) => void;\n\t}","deps: any[]","subs: Function[]","props: ErrorBoundaryProps","error: Error","info: ErrorInfo","props: NestedViewProps","ErrorBoundary","page: HrefLike","envSchema","name: string","options: { params?: Record<string, string>; base?: string }","state: RouterState","context: PageReactContext","NestedView","route: PageRoute","request: PageRequest","layers: Layer[]","context: Record<string, any>","stack: Array<RouterStackItem>","route","config: Record<string, any>","str?: string","element: ReactNode","element","page: PageRoute","props: Record<string, any>","error: Error","ErrorViewer","page: { options: { name?: string } }","params: Record<string, any>","path: string","params: Record<string, string>","index: number","view: ReactNode | undefined","ClientOnly","pages: Array<{ value: { [OPTIONS]: PageDescriptorOptions } }>","target: { [OPTIONS]: PageDescriptorOptions }","entry: PageRouteEntry","it: any","entry: PageRouteEntry","url: URL","options: TransitionOptions","state: RouterState","query: Record<string, string>","context: PageReactContext","props?: Record<string, any>","previous: PreviousLayerData[]","url: string","options: RouterGoOptions","options: { url?: string; previous?: PreviousLayerData[] }","pages: PageRoute[]","state: RouterState","layer: {\n\t\t\tpath: string;\n\t\t}","browser?: ReactBrowserProvider","query: Record<string, string>","props?: Record<string, any>","pathname: HrefLike","layer: { path: string }","options: { params?: Record<string, any> }","path: string","options?: RouterGoOptions","ev: any","record:\n\t\t\t| Record<string, any>\n\t\t\t| ((queryParams: Record<string, any>) => Record<string, any>)","options: {\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}","props: LinkProps","path: HrefLike","name: string | undefined","ev: any","clazz: Service<T>","_scope?: ClientScope","schema: T","options: UseQueryParamsHookOptions","queryParams: Static<T>","queryParams","alepha: Alepha","schema: TObject","data: any","state","alepha: Alepha"],"sources":["../src/descriptors/$page.ts","../src/components/NotFound.tsx","../src/components/ClientOnly.tsx","../src/contexts/RouterContext.ts","../src/hooks/useAlepha.ts","../src/components/ErrorViewer.tsx","../src/contexts/RouterLayerContext.ts","../src/hooks/useRouterEvents.ts","../src/components/ErrorBoundary.tsx","../src/components/NestedView.tsx","../src/errors/RedirectionError.ts","../src/providers/PageDescriptorProvider.ts","../src/providers/BrowserRouterProvider.ts","../src/providers/ReactBrowserProvider.ts","../src/providers/ReactBrowserRenderer.ts","../src/hooks/RouterHookApi.ts","../src/hooks/useRouter.ts","../src/components/Link.tsx","../src/hooks/useActive.ts","../src/hooks/useInject.ts","../src/hooks/useClient.ts","../src/hooks/useQueryParams.ts","../src/hooks/useRouterState.ts","../src/index.browser.ts"],"sourcesContent":["import {\n\t__descriptor,\n\ttype Async,\n\tKIND,\n\tNotImplementedError,\n\tOPTIONS,\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 { PageReactContext } from \"../providers/PageDescriptorProvider.ts\";\n\nconst KEY = \"PAGE\";\n\nexport interface PageConfigSchema {\n\tquery?: TSchema;\n\tparams?: TSchema;\n}\n\nexport type TPropsDefault = any;\n\nexport type TPropsParentDefault = {};\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<{ [OPTIONS]: PageDescriptorOptions }>;\n\n\tparent?: { [OPTIONS]: PageDescriptorOptions<PageConfigSchema, TPropsParent> };\n\n\tcan?: () => boolean;\n\n\terrorHandler?: (error: Error) => ReactNode;\n\n\tprerender?:\n\t\t| boolean\n\t\t| {\n\t\t\t\tentries?: Array<Partial<PageRequestConfig<TConfig>>>;\n\t\t };\n\n\t/**\n\t * If true, the page will be rendered on the client-side.\n\t */\n\tclient?: boolean | ClientOnlyProps;\n\n\tafterHandler?: (request: ServerRequest) => any;\n\n\tcache?: ServerRouteCache;\n}\n\nexport interface PageDescriptor<\n\tTConfig extends PageConfigSchema = PageConfigSchema,\n\tTProps extends object = TPropsDefault,\n\tTPropsParent extends object = TPropsParentDefault,\n> {\n\t[KIND]: typeof KEY;\n\t[OPTIONS]: PageDescriptorOptions<TConfig, TProps, TPropsParent>;\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\trender: (\n\t\toptions?: PageDescriptorRenderOptions,\n\t) => Promise<PageDescriptorRenderResult>;\n}\n\n/**\n * Main descriptor for defining a React route in the application.\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\t__descriptor(KEY);\n\n\tif (options.children) {\n\t\tfor (const child of options.children) {\n\t\t\tchild[OPTIONS].parent = {\n\t\t\t\t[OPTIONS]: options as PageDescriptorOptions<any, any, any>,\n\t\t\t};\n\t\t}\n\t}\n\n\tif (options.parent) {\n\t\toptions.parent[OPTIONS].children ??= [];\n\t\toptions.parent[OPTIONS].children.push({\n\t\t\t[OPTIONS]: options as PageDescriptorOptions<any, any, any>,\n\t\t});\n\t}\n\n\treturn {\n\t\t[KIND]: KEY,\n\t\t[OPTIONS]: options,\n\t\trender: () => {\n\t\t\tthrow new NotImplementedError(KEY);\n\t\t},\n\t};\n};\n\n$page[KIND] = KEY;\n\n// ---------------------------------------------------------------------------------------------------------------------\n\nexport interface PageDescriptorRenderOptions {\n\tparams?: Record<string, string>;\n\tquery?: Record<string, string>;\n\thtml?: boolean;\n\thydration?: boolean;\n}\n\nexport interface PageDescriptorRenderResult {\n\thtml: string;\n\tcontext: PageReactContext;\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> & TPropsParent & PageReactContext;\n","export default function NotFoundPage() {\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}}\n\t\t>\n\t\t\t<h1 style={{ fontSize: \"1rem\", marginBottom: \"0.5rem\" }}>\n\t\t\t\tThis page does not exist\n\t\t\t</h1>\n\t\t</div>\n\t);\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 { createContext } from \"react\";\nimport type {\n\tPageReactContext,\n\tRouterState,\n} from \"../providers/PageDescriptorProvider.ts\";\n\nexport interface RouterContextValue {\n\talepha: Alepha;\n\tstate: RouterState;\n\tcontext: PageReactContext;\n}\n\nexport const RouterContext = createContext<RouterContextValue | undefined>(\n\tundefined,\n);\n","import type { Alepha } from \"@alepha/core\";\nimport { useContext } from \"react\";\nimport { RouterContext } from \"../contexts/RouterContext.ts\";\n\nexport const useAlepha = (): Alepha => {\n\tconst routerContext = useContext(RouterContext);\n\tif (!routerContext) {\n\t\tthrow new Error(\"useAlepha must be used within a RouterProvider\");\n\t}\n\n\treturn routerContext.alepha;\n};\n","import { useState } from \"react\";\nimport { useAlepha } from \"../hooks/useAlepha.ts\";\n\ninterface ErrorViewerProps {\n\terror: Error;\n}\n\n// TODO: design this better\n\nconst ErrorViewer = ({ error }: ErrorViewerProps) => {\n\tconst [expanded, setExpanded] = useState(false);\n\tconst isProduction = useAlepha().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: \"4px\",\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","import { useContext, useEffect } from \"react\";\nimport { RouterContext } from \"../contexts/RouterContext.ts\";\nimport type { RouterState } from \"../providers/PageDescriptorProvider.ts\";\n\nexport const useRouterEvents = (\n\topts: {\n\t\tonBegin?: (ev: { state: RouterState }) => void;\n\t\tonEnd?: (ev: { state: RouterState }) => void;\n\t\tonError?: (ev: { state: RouterState; error: Error }) => void;\n\t} = {},\n\tdeps: any[] = [],\n) => {\n\tconst ctx = useContext(RouterContext);\n\tif (!ctx) {\n\t\tthrow new Error(\"useRouter must be used within a RouterProvider\");\n\t}\n\n\tuseEffect(() => {\n\t\tif (!ctx.alepha.isBrowser()) {\n\t\t\treturn;\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\n\t\tif (onBegin) {\n\t\t\tsubs.push(\n\t\t\t\tctx.alepha.on(\"react:transition:begin\", {\n\t\t\t\t\tcallback: onBegin,\n\t\t\t\t}),\n\t\t\t);\n\t\t}\n\n\t\tif (onEnd) {\n\t\t\tsubs.push(\n\t\t\t\tctx.alepha.on(\"react:transition:end\", {\n\t\t\t\t\tcallback: onEnd,\n\t\t\t\t}),\n\t\t\t);\n\t\t}\n\n\t\tif (onError) {\n\t\t\tsubs.push(\n\t\t\t\tctx.alepha.on(\"react:transition:error\", {\n\t\t\t\t\tcallback: onError,\n\t\t\t\t}),\n\t\t\t);\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 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 type { ReactNode } from \"react\";\nimport { useContext, useState } from \"react\";\nimport { RouterContext } from \"../contexts/RouterContext.ts\";\nimport { RouterLayerContext } from \"../contexts/RouterLayerContext.ts\";\nimport { useRouterEvents } from \"../hooks/useRouterEvents.ts\";\nimport ErrorBoundary from \"./ErrorBoundary.tsx\";\n\nexport interface NestedViewProps {\n\tchildren?: 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 app = useContext(RouterContext);\n\tconst layer = useContext(RouterLayerContext);\n\tconst index = layer?.index ?? 0;\n\n\tconst [view, setView] = useState<ReactNode | undefined>(\n\t\tapp?.state.layers[index]?.element,\n\t);\n\n\tuseRouterEvents(\n\t\t{\n\t\t\tonEnd: ({ state }) => {\n\t\t\t\tsetView(state.layers[index]?.element);\n\t\t\t},\n\t\t},\n\t\t[app],\n\t);\n\n\tif (!app) {\n\t\tthrow new Error(\"NestedView must be used within a RouterContext.\");\n\t}\n\n\tconst element = view ?? props.children ?? null;\n\n\treturn (\n\t\t<ErrorBoundary fallback={app.context.onError!}>{element}</ErrorBoundary>\n\t);\n};\n\nexport default NestedView;\n","import type { HrefLike } from \"../hooks/RouterHookApi.ts\";\n\nexport class RedirectionError extends Error {\n\tpublic readonly page: HrefLike;\n\n\tconstructor(page: HrefLike) {\n\t\tsuper(\"Redirection\");\n\t\tthis.page = page;\n\t}\n}\n","import type { Static } from \"@alepha/core\";\nimport { $hook, $inject, $logger, Alepha, OPTIONS, t } from \"@alepha/core\";\nimport type { ApiLinksResponse } from \"@alepha/server\";\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 { RouterContext } from \"../contexts/RouterContext.ts\";\nimport { RouterLayerContext } from \"../contexts/RouterLayerContext.ts\";\nimport { $page, type PageDescriptorOptions } from \"../descriptors/$page.ts\";\nimport { RedirectionError } from \"../errors/RedirectionError.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 PageDescriptorProvider {\n\tprotected readonly log = $logger();\n\tprotected readonly env = $inject(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 url(\n\t\tname: string,\n\t\toptions: { params?: Record<string, string>; base?: string } = {},\n\t): URL {\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\treturn new URL(\n\t\t\turl.replace(/\\/\\/+/g, \"/\") || \"/\",\n\t\t\toptions.base ?? `http://localhost`,\n\t\t);\n\t}\n\n\tpublic root(state: RouterState, context: PageReactContext): ReactNode {\n\t\tconst root = createElement(\n\t\t\tRouterContext.Provider,\n\t\t\t{\n\t\t\t\tvalue: {\n\t\t\t\t\talepha: this.alepha,\n\t\t\t\t\tstate,\n\t\t\t\t\tcontext,\n\t\t\t\t},\n\t\t\t},\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\tpublic async createLayers(\n\t\troute: PageRoute,\n\t\trequest: PageRequest,\n\t): Promise<CreateLayersResult> {\n\t\tconst { pathname, search } = request.url;\n\t\tconst layers: Layer[] = []; // result layers\n\t\tlet context: Record<string, any> = {}; // all props\n\t\tconst stack: Array<RouterStackItem> = [{ route }]; // stack of routes\n\t\trequest.onError = (error) => this.renderError(error); // error handler\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\tconfig.query = route.schema?.query\n\t\t\t\t\t? this.alepha.parse(route.schema.query, request.query)\n\t\t\t\t\t: request.query;\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, request.params)\n\t\t\t\t\t: request.params;\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// 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\t// check if previous layer is the same, reuse if possible\n\t\t\tconst previous = request.previous;\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\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\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\ttry {\n\t\t\t\tconst props =\n\t\t\t\t\t(await route.resolve?.({\n\t\t\t\t\t\t...request, // request\n\t\t\t\t\t\t...config, // params, query\n\t\t\t\t\t\t...context, // previous props\n\t\t\t\t\t} as any)) ?? {};\n\n\t\t\t\t// save props\n\t\t\t\tit.props = {\n\t\t\t\t\t...props,\n\t\t\t\t};\n\n\t\t\t\t// add props to context\n\t\t\t\tcontext = {\n\t\t\t\t\t...context,\n\t\t\t\t\t...props,\n\t\t\t\t};\n\t\t\t} catch (e) {\n\t\t\t\t// check if we need to redirect\n\t\t\t\tif (e instanceof RedirectionError) {\n\t\t\t\t\treturn {\n\t\t\t\t\t\tlayers: [],\n\t\t\t\t\t\tredirect: typeof e.page === \"string\" ? e.page : this.href(e.page),\n\t\t\t\t\t\tpathname,\n\t\t\t\t\t\tsearch,\n\t\t\t\t\t};\n\t\t\t\t}\n\n\t\t\t\tthis.log.error(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\t// if (it.route.head && !it.error) {\n\t\t\t// \tthis.fillHead(it.route, request, {\n\t\t\t// \t\t...props,\n\t\t\t// \t\t...context,\n\t\t\t// \t});\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\trequest.onError = localErrorHandler;\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\tlet element: ReactNode = await request.onError(it.error);\n\t\t\t\tif (element === null) {\n\t\t\t\t\telement = this.renderError(it.error);\n\t\t\t\t}\n\n\t\t\t\tlayers.push({\n\t\t\t\t\tprops,\n\t\t\t\t\terror: it.error,\n\t\t\t\t\tname: it.route.name,\n\t\t\t\t\tpart: it.route.path,\n\t\t\t\t\tconfig: it.config,\n\t\t\t\t\telement: this.renderView(i + 1, path, element, it.route),\n\t\t\t\t\tindex: i + 1,\n\t\t\t\t\tpath,\n\t\t\t\t\troute,\n\t\t\t\t});\n\t\t\t\tbreak;\n\t\t\t}\n\n\t\t\t// normal use case\n\n\t\t\tconst element = await this.createElement(it.route, {\n\t\t\t\t...props,\n\t\t\t\t...context,\n\t\t\t});\n\n\t\t\tlayers.push({\n\t\t\t\tname: it.route.name,\n\t\t\t\tprops,\n\t\t\t\tpart: it.route.path,\n\t\t\t\tconfig: it.config,\n\t\t\t\telement: this.renderView(i + 1, path, element, it.route),\n\t\t\t\tindex: i + 1,\n\t\t\t\tpath,\n\t\t\t\troute,\n\t\t\t});\n\t\t}\n\n\t\treturn { layers, pathname, search };\n\t}\n\n\tprotected getErrorHandler(route: PageRoute) {\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) {\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 });\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\tname: \"configure\",\n\t\thandler: () => {\n\t\t\tlet hasNotFoundHandler = false;\n\t\t\tconst pages = this.alepha.getDescriptorValues($page);\n\t\t\tfor (const { value, key } of pages) {\n\t\t\t\tvalue[OPTIONS].name ??= key;\n\t\t\t}\n\n\t\t\tfor (const { value } of pages) {\n\t\t\t\t// skip children, we only want root pages\n\t\t\t\tif (value[OPTIONS].parent) {\n\t\t\t\t\tcontinue;\n\t\t\t\t}\n\n\t\t\t\tif (value[OPTIONS].path === \"/*\") {\n\t\t\t\t\thasNotFoundHandler = true;\n\t\t\t\t}\n\n\t\t\t\tthis.add(this.map(pages, value));\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\tafterHandler: ({ 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<{ value: { [OPTIONS]: PageDescriptorOptions } }>,\n\t\ttarget: { [OPTIONS]: PageDescriptorOptions },\n\t): PageRouteEntry {\n\t\tconst children = target[OPTIONS].children ?? [];\n\n\t\treturn {\n\t\t\t...target[OPTIONS],\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}\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 RouterState {\n\tpathname: string;\n\tsearch: string;\n\tlayers: Array<Layer>;\n}\n\nexport interface TransitionOptions {\n\tstate?: RouterState;\n\tprevious?: PreviousLayerData[];\n\tcontext?: PageReactContext;\n}\n\nexport interface RouterStackItem {\n\troute: PageRoute;\n\tconfig?: Record<string, any>;\n\tprops?: Record<string, any>;\n\terror?: Error;\n}\n\nexport interface RouterRenderResult {\n\tstate: RouterState;\n\tcontext: PageReactContext;\n\tredirect?: string;\n}\n\nexport interface PageRequest extends PageReactContext {\n\tparams: Record<string, any>;\n\tquery: Record<string, string>;\n\n\t// previous layers (browser history or browser hydration, always null on server)\n\tprevious?: PreviousLayerData[];\n}\n\nexport interface CreateLayersResult extends RouterState {\n\tredirect?: string;\n}\n\n/**\n * It's like RouterState, but publicly available in React context.\n * This is where we store all plugin data!\n */\nexport interface PageReactContext {\n\turl: URL;\n\tonError: (error: Error) => ReactNode;\n\tlinks?: ApiLinksResponse;\n}\n","import { $hook, $inject, $logger, Alepha } from \"@alepha/core\";\nimport { type Route, RouterProvider } from \"@alepha/router\";\nimport { createElement, type ReactNode } from \"react\";\nimport NotFoundPage from \"../components/NotFound.tsx\";\nimport {\n\tisPageRoute,\n\tPageDescriptorProvider,\n\ttype PageReactContext,\n\ttype PageRequest,\n\ttype PageRoute,\n\ttype PageRouteEntry,\n\ttype RouterRenderResult,\n\ttype RouterState,\n\ttype TransitionOptions,\n} from \"./PageDescriptorProvider.ts\";\n\nexport interface BrowserRoute extends Route {\n\tpage: PageRoute;\n}\n\nexport class BrowserRouterProvider extends RouterProvider<BrowserRoute> {\n\tprotected readonly log = $logger();\n\tprotected readonly alepha = $inject(Alepha);\n\tprotected readonly pageDescriptorProvider = $inject(PageDescriptorProvider);\n\n\tpublic add(entry: PageRouteEntry) {\n\t\tthis.pageDescriptorProvider.add(entry);\n\t}\n\n\tprotected readonly configure = $hook({\n\t\tname: \"configure\",\n\t\thandler: async () => {\n\t\t\tfor (const page of this.pageDescriptorProvider.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\toptions: TransitionOptions = {},\n\t): Promise<RouterRenderResult> {\n\t\tconst { pathname, search } = url;\n\t\tconst state: RouterState = {\n\t\t\tpathname,\n\t\t\tsearch,\n\t\t\tlayers: [],\n\t\t};\n\n\t\tconst context = {\n\t\t\turl,\n\t\t\tquery: {},\n\t\t\tparams: {},\n\t\t\tonError: () => null,\n\t\t\t...(options.context ?? {}),\n\t\t} as PageRequest;\n\n\t\tawait this.alepha.emit(\"react:transition:begin\", { state, context });\n\n\t\ttry {\n\t\t\tconst previous = options.previous;\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\tcontext.query = query;\n\t\t\tcontext.params = params ?? {};\n\t\t\tcontext.previous = previous;\n\n\t\t\tif (isPageRoute(route)) {\n\t\t\t\tconst result = await this.pageDescriptorProvider.createLayers(\n\t\t\t\t\troute.page,\n\t\t\t\t\tcontext,\n\t\t\t\t);\n\n\t\t\t\tif (result.redirect) {\n\t\t\t\t\treturn {\n\t\t\t\t\t\tredirect: result.redirect,\n\t\t\t\t\t\tstate,\n\t\t\t\t\t\tcontext,\n\t\t\t\t\t};\n\t\t\t\t}\n\n\t\t\t\tstate.layers = result.layers;\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.emit(\"react:transition:success\", { state, context });\n\t\t} catch (e) {\n\t\t\tthis.log.error(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.pageDescriptorProvider.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.emit(\"react:transition:error\", {\n\t\t\t\terror: e as Error,\n\t\t\t\tstate,\n\t\t\t\tcontext,\n\t\t\t});\n\t\t}\n\n\t\tif (options.state) {\n\t\t\toptions.state.layers = state.layers;\n\t\t\toptions.state.pathname = state.pathname;\n\t\t\toptions.state.search = state.search;\n\t\t}\n\n\t\tawait this.alepha.emit(\"react:transition:end\", {\n\t\t\tstate: options.state,\n\t\t\tcontext,\n\t\t});\n\n\t\treturn {\n\t\t\tcontext,\n\t\t\tstate,\n\t\t};\n\t}\n\n\tpublic root(state: RouterState, context: PageReactContext): ReactNode {\n\t\treturn this.pageDescriptorProvider.root(state, context);\n\t}\n}\n","import { $hook, $inject, $logger, Alepha } from \"@alepha/core\";\nimport type { ApiLinksResponse } from \"@alepha/server\";\nimport { LinkProvider } from \"@alepha/server-links\";\nimport type { Root } from \"react-dom/client\";\nimport { BrowserRouterProvider } from \"./BrowserRouterProvider.ts\";\nimport type {\n\tPreviousLayerData,\n\tRouterRenderResult,\n\tRouterState,\n\tTransitionOptions,\n} from \"./PageDescriptorProvider.ts\";\n\nexport class ReactBrowserProvider {\n\tprotected readonly log = $logger();\n\tprotected readonly client = $inject(LinkProvider);\n\tprotected readonly alepha = $inject(Alepha);\n\tprotected readonly router = $inject(BrowserRouterProvider);\n\tprotected root!: Root;\n\n\tpublic transitioning?: {\n\t\tto: string;\n\t};\n\n\tpublic state: RouterState = {\n\t\tlayers: [],\n\t\tpathname: \"\",\n\t\tsearch: \"\",\n\t};\n\n\tpublic get document() {\n\t\treturn window.document;\n\t}\n\n\tpublic get history() {\n\t\treturn window.history;\n\t}\n\n\tpublic get url(): string {\n\t\treturn window.location.pathname + window.location.search;\n\t}\n\n\tpublic async invalidate(props?: Record<string, any>) {\n\t\tconst previous: PreviousLayerData[] = [];\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\tconst result = await this.render({\n\t\t\turl,\n\t\t});\n\n\t\t// when redirecting in browser\n\t\tif (result.context.url.pathname !== url) {\n\t\t\t// TODO: check if losing search params is acceptable?\n\t\t\tthis.history.replaceState({}, \"\", result.context.url.pathname);\n\t\t\treturn;\n\t\t}\n\n\t\tif (options.replace) {\n\t\t\tthis.history.replaceState({}, \"\", url);\n\t\t\treturn;\n\t\t}\n\n\t\tthis.history.pushState({}, \"\", url);\n\t}\n\n\tprotected async render(\n\t\toptions: { url?: string; previous?: PreviousLayerData[] } = {},\n\t): Promise<RouterRenderResult> {\n\t\tconst previous = options.previous ?? this.state.layers;\n\t\tconst url = options.url ?? this.url;\n\n\t\tthis.transitioning = { to: url };\n\n\t\tconst result = await this.router.transition(\n\t\t\tnew URL(`http://localhost${url}`),\n\t\t\t{\n\t\t\t\tprevious,\n\t\t\t\tstate: this.state,\n\t\t\t},\n\t\t);\n\n\t\tif (result.redirect) {\n\t\t\treturn await this.render({ url: result.redirect });\n\t\t}\n\n\t\tthis.transitioning = undefined;\n\n\t\treturn result;\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\tpublic readonly ready = $hook({\n\t\tname: \"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?.links) {\n\t\t\t\tfor (const link of hydration.links.links) {\n\t\t\t\t\tthis.client.pushLink(link);\n\t\t\t\t}\n\t\t\t}\n\n\t\t\tconst { context } = await this.render({ previous });\n\n\t\t\tawait this.alepha.emit(\"react:browser:render\", {\n\t\t\t\tstate: this.state,\n\t\t\t\tcontext,\n\t\t\t\thydration,\n\t\t\t});\n\n\t\t\twindow.addEventListener(\"popstate\", () => {\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}\n\nexport interface ReactHydrationState {\n\tlayers?: Array<PreviousLayerData>;\n\tlinks?: ApiLinksResponse;\n}\n","import { $hook, $inject, $logger, type Static, t } from \"@alepha/core\";\nimport type { ApiLinksResponse } from \"@alepha/server\";\nimport type { Root } from \"react-dom/client\";\nimport { createRoot, hydrateRoot } from \"react-dom/client\";\nimport { BrowserRouterProvider } from \"./BrowserRouterProvider.ts\";\nimport type {\n\tPreviousLayerData,\n\tTransitionOptions,\n} from \"./PageDescriptorProvider.ts\";\nimport { ReactBrowserProvider } from \"./ReactBrowserProvider.ts\";\n\nconst envSchema = t.object({\n\tREACT_ROOT_ID: t.string({ default: \"root\" }),\n});\n\ndeclare module \"@alepha/core\" {\n\tinterface Env extends Partial<Static<typeof envSchema>> {}\n}\n\n// TODO: move to ReactBrowserProvider when it will be removed from server-side imports\nexport class ReactBrowserRenderer {\n\tprotected readonly browserProvider = $inject(ReactBrowserProvider);\n\tprotected readonly browserRouterProvider = $inject(BrowserRouterProvider);\n\tprotected readonly env = $inject(envSchema);\n\tprotected readonly log = $logger();\n\n\tprotected root!: Root;\n\n\tprotected getRootElement() {\n\t\tconst root = this.browserProvider.document.getElementById(\n\t\t\tthis.env.REACT_ROOT_ID,\n\t\t);\n\t\tif (root) {\n\t\t\treturn root;\n\t\t}\n\n\t\tconst div = this.browserProvider.document.createElement(\"div\");\n\t\tdiv.id = this.env.REACT_ROOT_ID;\n\n\t\tthis.browserProvider.document.body.prepend(div);\n\n\t\treturn div;\n\t}\n\n\tpublic readonly ready = $hook({\n\t\tname: \"react:browser:render\",\n\t\thandler: async ({ state, context, hydration }) => {\n\t\t\tconst element = this.browserRouterProvider.root(state, context);\n\n\t\t\tif (hydration?.layers) {\n\t\t\t\tthis.root = hydrateRoot(this.getRootElement(), element);\n\t\t\t\tthis.log.info(\"Hydrated root element\");\n\t\t\t} else {\n\t\t\t\tthis.root ??= createRoot(this.getRootElement());\n\t\t\t\tthis.root.render(element);\n\t\t\t\tthis.log.info(\"Created root element\");\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}\n\nexport interface ReactHydrationState {\n\tlayers?: Array<PreviousLayerData>;\n\tlinks?: ApiLinksResponse;\n}\n","import type { PageDescriptor } from \"../descriptors/$page.ts\";\nimport type {\n\tAnchorProps,\n\tPageRoute,\n\tRouterState,\n} from \"../providers/PageDescriptorProvider.ts\";\nimport type {\n\tReactBrowserProvider,\n\tRouterGoOptions,\n} from \"../providers/ReactBrowserProvider.ts\";\n\nexport class RouterHookApi {\n\tconstructor(\n\t\tprivate readonly pages: PageRoute[],\n\t\tprivate readonly state: RouterState,\n\t\tprivate readonly layer: {\n\t\t\tpath: string;\n\t\t},\n\t\tprivate readonly browser?: ReactBrowserProvider,\n\t) {}\n\n\tpublic get current(): RouterState {\n\t\treturn this.state;\n\t}\n\n\tpublic get pathname(): string {\n\t\treturn this.state.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.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\t/**\n\t * Create a valid href for the given pathname.\n\t *\n\t * @param pathname\n\t * @param layer\n\t */\n\tpublic createHref(\n\t\tpathname: HrefLike,\n\t\tlayer: { path: string } = this.layer,\n\t\toptions: { params?: Record<string, any> } = {},\n\t) {\n\t\tif (typeof pathname === \"object\") {\n\t\t\tpathname = pathname.options.path ?? \"\";\n\t\t}\n\n\t\tif (options.params) {\n\t\t\tfor (const [key, value] of Object.entries(options.params)) {\n\t\t\t\tpathname = pathname.replace(`:${key}`, String(value));\n\t\t\t}\n\t\t}\n\n\t\treturn pathname.startsWith(\"/\")\n\t\t\t? pathname\n\t\t\t: `${layer.path}/${pathname}`.replace(/\\/\\/+/g, \"/\");\n\t}\n\n\tpublic async go(path: string, options?: RouterGoOptions): Promise<void>;\n\tpublic async go<T extends object>(\n\t\tpath: keyof VirtualRouter<T>,\n\t\toptions?: RouterGoOptions,\n\t): Promise<void>;\n\tpublic async go(path: string, options?: RouterGoOptions): Promise<void> {\n\t\tfor (const page of this.pages) {\n\t\t\tif (page.name === path) {\n\t\t\t\tpath = page.path ?? \"\";\n\t\t\t\tbreak;\n\t\t\t}\n\t\t}\n\n\t\tawait this.browser?.go(this.createHref(path, this.layer, options), options);\n\t}\n\n\tpublic anchor(\n\t\tpath: string,\n\t\toptions?: { params?: Record<string, any> },\n\t): AnchorProps;\n\tpublic anchor<T extends object>(\n\t\tpath: keyof VirtualRouter<T>,\n\t\toptions?: { params?: Record<string, any> },\n\t): AnchorProps;\n\tpublic anchor(\n\t\tpath: string,\n\t\toptions: { params?: Record<string, any> } = {},\n\t): AnchorProps {\n\t\tfor (const page of this.pages) {\n\t\t\tif (page.name === path) {\n\t\t\t\tpath = page.path ?? \"\";\n\t\t\t\tbreak;\n\t\t\t}\n\t\t}\n\n\t\tconst href = this.createHref(path, this.layer, options);\n\t\treturn {\n\t\t\thref,\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(path, options).catch(console.error);\n\t\t\t},\n\t\t};\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 HrefLike = string | { options: { path?: string; name?: string } };\n\nexport type VirtualRouter<T> = {\n\t[K in keyof T as T[K] extends PageDescriptor ? K : never]: T[K];\n};\n","import { useContext, useMemo } from \"react\";\nimport { RouterContext } from \"../contexts/RouterContext.ts\";\nimport { RouterLayerContext } from \"../contexts/RouterLayerContext.ts\";\nimport { PageDescriptorProvider } from \"../providers/PageDescriptorProvider.ts\";\nimport { ReactBrowserProvider } from \"../providers/ReactBrowserProvider.ts\";\nimport { RouterHookApi } from \"./RouterHookApi.ts\";\n\nexport const useRouter = (): RouterHookApi => {\n\tconst ctx = useContext(RouterContext);\n\tconst layer = useContext(RouterLayerContext);\n\tif (!ctx || !layer) {\n\t\tthrow new Error(\"useRouter must be used within a RouterProvider\");\n\t}\n\n\tconst pages = useMemo(() => {\n\t\treturn ctx.alepha.get(PageDescriptorProvider).getPages();\n\t}, []);\n\n\treturn useMemo(\n\t\t() =>\n\t\t\tnew RouterHookApi(\n\t\t\t\tpages,\n\t\t\t\tctx.state,\n\t\t\t\tlayer,\n\t\t\t\tctx.alepha.isBrowser()\n\t\t\t\t\t? ctx.alepha.get(ReactBrowserProvider)\n\t\t\t\t\t: undefined,\n\t\t\t),\n\t\t[layer],\n\t);\n};\n","import { OPTIONS } from \"@alepha/core\";\nimport type { AnchorHTMLAttributes } from \"react\";\nimport React from \"react\";\nimport { RouterContext } from \"../contexts/RouterContext.ts\";\nimport type { PageDescriptor } from \"../descriptors/$page.ts\";\nimport { useRouter } from \"../hooks/useRouter.ts\";\n\nexport interface LinkProps extends AnchorHTMLAttributes<HTMLAnchorElement> {\n\tto: string | PageDescriptor;\n\tchildren?: React.ReactNode;\n}\n\nconst Link = (props: LinkProps) => {\n\tReact.useContext(RouterContext);\n\n\tconst router = useRouter();\n\n\tconst to = typeof props.to === \"string\" ? props.to : props.to[OPTIONS].path;\n\tif (!to) {\n\t\treturn null;\n\t}\n\n\tconst can = typeof props.to === \"string\" ? undefined : props.to[OPTIONS].can;\n\tif (can && !can()) {\n\t\treturn null;\n\t}\n\n\tconst name =\n\t\ttypeof props.to === \"string\" ? undefined : props.to[OPTIONS].name;\n\n\tconst anchorProps = {\n\t\t...props,\n\t\tto: undefined,\n\t};\n\n\treturn (\n\t\t<a {...router.anchor(to)} {...anchorProps}>\n\t\t\t{props.children ?? name}\n\t\t</a>\n\t);\n};\n\nexport default Link;\n","import { useContext, useMemo, useState } from \"react\";\nimport { RouterContext } from \"../contexts/RouterContext.ts\";\nimport { RouterLayerContext } from \"../contexts/RouterLayerContext.ts\";\nimport type { AnchorProps } from \"../providers/PageDescriptorProvider.ts\";\nimport type { HrefLike } from \"./RouterHookApi.ts\";\nimport { useRouter } from \"./useRouter.ts\";\nimport { useRouterEvents } from \"./useRouterEvents.ts\";\n\nexport const useActive = (path: HrefLike): UseActiveHook => {\n\tconst router = useRouter();\n\tconst ctx = useContext(RouterContext);\n\tconst layer = useContext(RouterLayerContext);\n\tif (!ctx || !layer) {\n\t\tthrow new Error(\"useRouter must be used within a RouterProvider\");\n\t}\n\n\tlet name: string | undefined;\n\tif (typeof path === \"object\" && path.options.name) {\n\t\tname = path.options.name;\n\t}\n\n\tconst [current, setCurrent] = useState(ctx.state.pathname);\n\tconst href = useMemo(() => router.createHref(path, layer), [path, layer]);\n\tconst [isPending, setPending] = useState(false);\n\tconst isActive = current === href;\n\n\tuseRouterEvents({\n\t\tonEnd: ({ state }) => setCurrent(state.pathname),\n\t});\n\n\treturn {\n\t\tname,\n\t\tisPending,\n\t\tisActive,\n\t\tanchorProps: {\n\t\t\thref,\n\t\t\tonClick: (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\trouter.go(href).then(() => {\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\tname?: string;\n}\n","import type { Service } from \"@alepha/core\";\nimport { useContext, useMemo } from \"react\";\nimport { RouterContext } from \"../contexts/RouterContext.ts\";\n\nexport const useInject = <T extends object>(clazz: Service<T>): T => {\n\tconst ctx = useContext(RouterContext);\n\tif (!ctx) {\n\t\tthrow new Error(\"useRouter must be used within a <RouterProvider>\");\n\t}\n\n\treturn useMemo(() => ctx.alepha.get(clazz), []);\n};\n","import {\n\ttype ClientScope,\n\ttype HttpVirtualClient,\n\tLinkProvider,\n} from \"@alepha/server-links\";\nimport { useInject } from \"./useInject.ts\";\n\nexport const useClient = <T extends object>(\n\t_scope?: ClientScope,\n): HttpVirtualClient<T> => {\n\treturn useInject(LinkProvider).client<T>();\n};\n","import type { Alepha, Static, TObject } from \"@alepha/core\";\nimport { useContext, useEffect, useState } from \"react\";\nimport { RouterContext } from \"../contexts/RouterContext.ts\";\nimport { useRouter } from \"./useRouter.ts\";\n\nexport interface UseQueryParamsHookOptions {\n\tformat?: \"base64\" | \"querystring\";\n\tkey?: string;\n\tpush?: boolean;\n}\n\nexport const useQueryParams = <T extends TObject>(\n\tschema: T,\n\toptions: UseQueryParamsHookOptions = {},\n): [Static<T>, (data: Static<T>) => void] => {\n\tconst ctx = useContext(RouterContext);\n\tif (!ctx) {\n\t\tthrow new Error(\"useQueryParams must be used within a RouterProvider\");\n\t}\n\n\tconst key = options.key ?? \"q\";\n\tconst router = useRouter();\n\tconst querystring = router.query[key];\n\n\tconst [queryParams, setQueryParams] = useState(\n\t\tdecode(ctx.alepha, schema, router.query[key]),\n\t);\n\n\tuseEffect(() => {\n\t\tsetQueryParams(decode(ctx.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(ctx.alepha, schema, queryParams) };\n\t\t\t});\n\t\t},\n\t];\n};\n\n// ---------------------------------------------------------------------------------------------------------------------\n\nconst encode = (alepha: Alepha, schema: TObject, data: any) => {\n\treturn btoa(JSON.stringify(alepha.parse(schema, data)));\n};\n\nconst decode = (alepha: Alepha, schema: TObject, data: any) => {\n\ttry {\n\t\treturn alepha.parse(schema, JSON.parse(atob(decodeURIComponent(data))));\n\t} catch (_error) {\n\t\treturn {};\n\t}\n};\n","import { useContext, useState } from \"react\";\nimport { RouterContext } from \"../contexts/RouterContext.ts\";\nimport { RouterLayerContext } from \"../contexts/RouterLayerContext.ts\";\nimport type { RouterState } from \"../providers/PageDescriptorProvider.ts\";\nimport { useRouterEvents } from \"./useRouterEvents.ts\";\n\nexport const useRouterState = (): RouterState => {\n\tconst ctx = useContext(RouterContext);\n\tconst layer = useContext(RouterLayerContext);\n\tif (!ctx || !layer) {\n\t\tthrow new Error(\"useRouter must be used within a RouterProvider\");\n\t}\n\n\tconst [state, setState] = useState(ctx.state);\n\n\tuseRouterEvents({\n\t\tonEnd: ({ state }) => setState({ ...state }),\n\t});\n\n\treturn state;\n};\n","import { __bind, type Alepha, type Module } from \"@alepha/core\";\nimport { $page } from \"./descriptors/$page.ts\";\nimport { BrowserRouterProvider } from \"./providers/BrowserRouterProvider.ts\";\nimport { PageDescriptorProvider } from \"./providers/PageDescriptorProvider.ts\";\nimport { ReactBrowserProvider } from \"./providers/ReactBrowserProvider.ts\";\nimport { ReactBrowserRenderer } from \"./providers/ReactBrowserRenderer.ts\";\n\n// ---------------------------------------------------------------------------------------------------------------------\n\nexport * from \"./index.shared.ts\";\nexport * from \"./providers/BrowserRouterProvider.ts\";\nexport * from \"./providers/PageDescriptorProvider.ts\";\nexport * from \"./providers/ReactBrowserProvider.ts\";\n\n// ---------------------------------------------------------------------------------------------------------------------\n\nexport class AlephaReact implements Module {\n\tpublic readonly name = \"alepha.react\";\n\tpublic readonly $services = (alepha: Alepha) =>\n\t\talepha\n\t\t\t.with(PageDescriptorProvider)\n\t\t\t.with(ReactBrowserProvider)\n\t\t\t.with(BrowserRouterProvider)\n\t\t\t.with(ReactBrowserRenderer);\n}\n\n__bind($page, AlephaReact);\n"],"mappings":"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"}
1
+ {"version":3,"file":"index.browser.js","names":["options: PageDescriptorOptions<TConfig, TProps, TPropsParent>","props: PropsWithChildren<ClientOnlyProps>","text: string","opts: {\n\t\tonBegin?: (ev: { state: RouterState }) => void;\n\t\tonEnd?: (ev: { state: RouterState }) => void;\n\t\tonError?: (ev: { state: RouterState; error: Error }) => void;\n\t}","deps: any[]","subs: Function[]","props: ErrorBoundaryProps","error: Error","info: ErrorInfo","props: NestedViewProps","ErrorBoundary","page: HrefLike","envSchema","name: string","options: { params?: Record<string, string>; base?: string }","state: RouterState","context: PageReactContext","NestedView","route: PageRoute","request: PageRequest","layers: Layer[]","context: Record<string, any>","stack: Array<RouterStackItem>","route","config: Record<string, any>","str?: string","element: ReactNode","element","page: PageRoute","props: Record<string, any>","error: Error","ErrorViewer","page: { options: { name?: string } }","params: Record<string, any>","path: string","params: Record<string, string>","index: number","view: ReactNode | undefined","ClientOnly","it: { [OPTIONS]: PageDescriptorOptions }","pages: Array<{ value: { [OPTIONS]: PageDescriptorOptions } }>","target: { [OPTIONS]: PageDescriptorOptions }","entry: PageRouteEntry","it: any","entry: PageRouteEntry","url: URL","options: TransitionOptions","state: RouterState","query: Record<string, string>","context: PageReactContext","props?: Record<string, any>","previous: PreviousLayerData[]","url: string","options: RouterGoOptions","options: { url?: string; previous?: PreviousLayerData[] }","pages: PageRoute[]","state: RouterState","layer: {\n\t\t\tpath: string;\n\t\t}","browser?: ReactBrowserProvider","query: Record<string, string>","props?: Record<string, any>","pathname: HrefLike","layer: { path: string }","options: { params?: Record<string, any> }","path: string","options?: RouterGoOptions","ev: any","record:\n\t\t\t| Record<string, any>\n\t\t\t| ((queryParams: Record<string, any>) => Record<string, any>)","options: {\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}","props: LinkProps","path: HrefLike","name: string | undefined","ev: any","clazz: Service<T>","_scope?: ClientScope","schema: T","options: UseQueryParamsHookOptions","queryParams: Static<T>","queryParams","alepha: Alepha","schema: TObject","data: any","state","alepha: Alepha"],"sources":["../src/descriptors/$page.ts","../src/components/NotFound.tsx","../src/components/ClientOnly.tsx","../src/contexts/RouterContext.ts","../src/hooks/useAlepha.ts","../src/components/ErrorViewer.tsx","../src/contexts/RouterLayerContext.ts","../src/hooks/useRouterEvents.ts","../src/components/ErrorBoundary.tsx","../src/components/NestedView.tsx","../src/errors/RedirectionError.ts","../src/providers/PageDescriptorProvider.ts","../src/providers/BrowserRouterProvider.ts","../src/providers/ReactBrowserProvider.ts","../src/providers/ReactBrowserRenderer.ts","../src/hooks/RouterHookApi.ts","../src/hooks/useRouter.ts","../src/components/Link.tsx","../src/hooks/useActive.ts","../src/hooks/useInject.ts","../src/hooks/useClient.ts","../src/hooks/useQueryParams.ts","../src/hooks/useRouterState.ts","../src/index.browser.ts"],"sourcesContent":["import {\n\t__descriptor,\n\ttype Async,\n\tKIND,\n\tNotImplementedError,\n\tOPTIONS,\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 { PageReactContext } from \"../providers/PageDescriptorProvider.ts\";\n\nconst KEY = \"PAGE\";\n\nexport interface PageConfigSchema {\n\tquery?: TSchema;\n\tparams?: TSchema;\n}\n\nexport type TPropsDefault = any;\n\nexport type TPropsParentDefault = {};\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?:\n\t\t| Array<{ [OPTIONS]: PageDescriptorOptions }>\n\t\t| (() => Array<{ [OPTIONS]: PageDescriptorOptions }>);\n\n\tparent?: { [OPTIONS]: PageDescriptorOptions<PageConfigSchema, TPropsParent> };\n\n\tcan?: () => boolean;\n\n\terrorHandler?: (error: Error) => ReactNode;\n\n\t/**\n\t * If true, the page will be rendered on the build time.\n\t * Works only with viteAlepha plugin.\n\t *\n\t * Replace boolean by an object to define static entries. (e.g. list of params/query)\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\t/**\n\t * If true, the page will be rendered on the client-side.\n\t */\n\tclient?: boolean | ClientOnlyProps;\n\n\tafterHandler?: (request: ServerRequest) => any;\n\n\tcache?: ServerRouteCache;\n}\n\nexport interface PageDescriptor<\n\tTConfig extends PageConfigSchema = PageConfigSchema,\n\tTProps extends object = TPropsDefault,\n\tTPropsParent extends object = TPropsParentDefault,\n> {\n\t[KIND]: typeof KEY;\n\t[OPTIONS]: PageDescriptorOptions<TConfig, TProps, TPropsParent>;\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\trender: (\n\t\toptions?: PageDescriptorRenderOptions,\n\t) => Promise<PageDescriptorRenderResult>;\n}\n\n/**\n * Main descriptor for defining a React route in the application.\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\t__descriptor(KEY);\n\n\t// if (options.children) {\n\t// \tfor (const child of options.children) {\n\t// \t\tchild[OPTIONS].parent = {\n\t// \t\t\t[OPTIONS]: options as PageDescriptorOptions<any, any, any>,\n\t// \t\t};\n\t// \t}\n\t// }\n\n\t// if (options.parent) {\n\t// \toptions.parent[OPTIONS].children ??= [];\n\t// \toptions.parent[OPTIONS].children.push({\n\t// \t\t[OPTIONS]: options as PageDescriptorOptions<any, any, any>,\n\t// \t});\n\t// }\n\n\treturn {\n\t\t[KIND]: KEY,\n\t\t[OPTIONS]: options,\n\t\trender: () => {\n\t\t\tthrow new NotImplementedError(KEY);\n\t\t},\n\t};\n};\n\n$page[KIND] = KEY;\n\n// ---------------------------------------------------------------------------------------------------------------------\n\nexport interface PageDescriptorRenderOptions {\n\tparams?: Record<string, string>;\n\tquery?: Record<string, string>;\n\thtml?: boolean;\n\thydration?: boolean;\n}\n\nexport interface PageDescriptorRenderResult {\n\thtml: string;\n\tcontext: PageReactContext;\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> & TPropsParent & PageReactContext;\n","export default function NotFoundPage() {\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}}\n\t\t>\n\t\t\t<h1 style={{ fontSize: \"1rem\", marginBottom: \"0.5rem\" }}>\n\t\t\t\tThis page does not exist\n\t\t\t</h1>\n\t\t</div>\n\t);\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 { createContext } from \"react\";\nimport type {\n\tPageReactContext,\n\tRouterState,\n} from \"../providers/PageDescriptorProvider.ts\";\n\nexport interface RouterContextValue {\n\talepha: Alepha;\n\tstate: RouterState;\n\tcontext: PageReactContext;\n}\n\nexport const RouterContext = createContext<RouterContextValue | undefined>(\n\tundefined,\n);\n","import type { Alepha } from \"@alepha/core\";\nimport { useContext } from \"react\";\nimport { RouterContext } from \"../contexts/RouterContext.ts\";\n\nexport const useAlepha = (): Alepha => {\n\tconst routerContext = useContext(RouterContext);\n\tif (!routerContext) {\n\t\tthrow new Error(\"useAlepha must be used within a RouterProvider\");\n\t}\n\n\treturn routerContext.alepha;\n};\n","import { useState } from \"react\";\nimport { useAlepha } from \"../hooks/useAlepha.ts\";\n\ninterface ErrorViewerProps {\n\terror: Error;\n}\n\n// TODO: design this better\n\nconst ErrorViewer = ({ error }: ErrorViewerProps) => {\n\tconst [expanded, setExpanded] = useState(false);\n\tconst isProduction = useAlepha().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: \"4px\",\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","import { useContext, useEffect } from \"react\";\nimport { RouterContext } from \"../contexts/RouterContext.ts\";\nimport type { RouterState } from \"../providers/PageDescriptorProvider.ts\";\n\nexport const useRouterEvents = (\n\topts: {\n\t\tonBegin?: (ev: { state: RouterState }) => void;\n\t\tonEnd?: (ev: { state: RouterState }) => void;\n\t\tonError?: (ev: { state: RouterState; error: Error }) => void;\n\t} = {},\n\tdeps: any[] = [],\n) => {\n\tconst ctx = useContext(RouterContext);\n\tif (!ctx) {\n\t\tthrow new Error(\"useRouter must be used within a RouterProvider\");\n\t}\n\n\tuseEffect(() => {\n\t\tif (!ctx.alepha.isBrowser()) {\n\t\t\treturn;\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\n\t\tif (onBegin) {\n\t\t\tsubs.push(\n\t\t\t\tctx.alepha.on(\"react:transition:begin\", {\n\t\t\t\t\tcallback: onBegin,\n\t\t\t\t}),\n\t\t\t);\n\t\t}\n\n\t\tif (onEnd) {\n\t\t\tsubs.push(\n\t\t\t\tctx.alepha.on(\"react:transition:end\", {\n\t\t\t\t\tcallback: onEnd,\n\t\t\t\t}),\n\t\t\t);\n\t\t}\n\n\t\tif (onError) {\n\t\t\tsubs.push(\n\t\t\t\tctx.alepha.on(\"react:transition:error\", {\n\t\t\t\t\tcallback: onError,\n\t\t\t\t}),\n\t\t\t);\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 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 type { ReactNode } from \"react\";\nimport { useContext, useState } from \"react\";\nimport { RouterContext } from \"../contexts/RouterContext.ts\";\nimport { RouterLayerContext } from \"../contexts/RouterLayerContext.ts\";\nimport { useRouterEvents } from \"../hooks/useRouterEvents.ts\";\nimport ErrorBoundary from \"./ErrorBoundary.tsx\";\n\nexport interface NestedViewProps {\n\tchildren?: 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 app = useContext(RouterContext);\n\tconst layer = useContext(RouterLayerContext);\n\tconst index = layer?.index ?? 0;\n\n\tconst [view, setView] = useState<ReactNode | undefined>(\n\t\tapp?.state.layers[index]?.element,\n\t);\n\n\tuseRouterEvents(\n\t\t{\n\t\t\tonEnd: ({ state }) => {\n\t\t\t\tsetView(state.layers[index]?.element);\n\t\t\t},\n\t\t},\n\t\t[app],\n\t);\n\n\tif (!app) {\n\t\tthrow new Error(\"NestedView must be used within a RouterContext.\");\n\t}\n\n\tconst element = view ?? props.children ?? null;\n\n\treturn (\n\t\t<ErrorBoundary fallback={app.context.onError!}>{element}</ErrorBoundary>\n\t);\n};\n\nexport default NestedView;\n","import type { HrefLike } from \"../hooks/RouterHookApi.ts\";\n\nexport class RedirectionError extends Error {\n\tpublic readonly page: HrefLike;\n\n\tconstructor(page: HrefLike) {\n\t\tsuper(\"Redirection\");\n\t\tthis.page = page;\n\t}\n}\n","import type { Static } from \"@alepha/core\";\nimport { $hook, $inject, $logger, Alepha, OPTIONS, t } from \"@alepha/core\";\nimport type { ApiLinksResponse } from \"@alepha/server\";\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 { RouterContext } from \"../contexts/RouterContext.ts\";\nimport { RouterLayerContext } from \"../contexts/RouterLayerContext.ts\";\nimport { $page, type PageDescriptorOptions } from \"../descriptors/$page.ts\";\nimport { RedirectionError } from \"../errors/RedirectionError.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 PageDescriptorProvider {\n\tprotected readonly log = $logger();\n\tprotected readonly env = $inject(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 url(\n\t\tname: string,\n\t\toptions: { params?: Record<string, string>; base?: string } = {},\n\t): URL {\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\treturn new URL(\n\t\t\turl.replace(/\\/\\/+/g, \"/\") || \"/\",\n\t\t\toptions.base ?? `http://localhost`,\n\t\t);\n\t}\n\n\tpublic root(state: RouterState, context: PageReactContext): ReactNode {\n\t\tconst root = createElement(\n\t\t\tRouterContext.Provider,\n\t\t\t{\n\t\t\t\tvalue: {\n\t\t\t\t\talepha: this.alepha,\n\t\t\t\t\tstate,\n\t\t\t\t\tcontext,\n\t\t\t\t},\n\t\t\t},\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\tpublic async createLayers(\n\t\troute: PageRoute,\n\t\trequest: PageRequest,\n\t): Promise<CreateLayersResult> {\n\t\tconst { pathname, search } = request.url;\n\t\tconst layers: Layer[] = []; // result layers\n\t\tlet context: Record<string, any> = {}; // all props\n\t\tconst stack: Array<RouterStackItem> = [{ route }]; // stack of routes\n\t\trequest.onError = (error) => this.renderError(error); // error handler\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\tconfig.query = route.schema?.query\n\t\t\t\t\t? this.alepha.parse(route.schema.query, request.query)\n\t\t\t\t\t: request.query;\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, request.params)\n\t\t\t\t\t: request.params;\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// 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\t// check if previous layer is the same, reuse if possible\n\t\t\tconst previous = request.previous;\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\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\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\ttry {\n\t\t\t\tconst props =\n\t\t\t\t\t(await route.resolve?.({\n\t\t\t\t\t\t...request, // request\n\t\t\t\t\t\t...config, // params, query\n\t\t\t\t\t\t...context, // previous props\n\t\t\t\t\t} as any)) ?? {};\n\n\t\t\t\t// save props\n\t\t\t\tit.props = {\n\t\t\t\t\t...props,\n\t\t\t\t};\n\n\t\t\t\t// add props to context\n\t\t\t\tcontext = {\n\t\t\t\t\t...context,\n\t\t\t\t\t...props,\n\t\t\t\t};\n\t\t\t} catch (e) {\n\t\t\t\t// check if we need to redirect\n\t\t\t\tif (e instanceof RedirectionError) {\n\t\t\t\t\treturn {\n\t\t\t\t\t\tlayers: [],\n\t\t\t\t\t\tredirect: typeof e.page === \"string\" ? e.page : this.href(e.page),\n\t\t\t\t\t\tpathname,\n\t\t\t\t\t\tsearch,\n\t\t\t\t\t};\n\t\t\t\t}\n\n\t\t\t\tthis.log.error(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\trequest.onError = localErrorHandler;\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\tlet element: ReactNode = await request.onError(it.error);\n\t\t\t\tif (element === null) {\n\t\t\t\t\telement = this.renderError(it.error);\n\t\t\t\t}\n\n\t\t\t\tlayers.push({\n\t\t\t\t\tprops,\n\t\t\t\t\terror: it.error,\n\t\t\t\t\tname: it.route.name,\n\t\t\t\t\tpart: it.route.path,\n\t\t\t\t\tconfig: it.config,\n\t\t\t\t\telement: this.renderView(i + 1, path, element, it.route),\n\t\t\t\t\tindex: i + 1,\n\t\t\t\t\tpath,\n\t\t\t\t\troute,\n\t\t\t\t});\n\t\t\t\tbreak;\n\t\t\t}\n\n\t\t\t// normal use case\n\n\t\t\tconst element = await this.createElement(it.route, {\n\t\t\t\t...props,\n\t\t\t\t...context,\n\t\t\t});\n\n\t\t\tlayers.push({\n\t\t\t\tname: it.route.name,\n\t\t\t\tprops,\n\t\t\t\tpart: it.route.path,\n\t\t\t\tconfig: it.config,\n\t\t\t\telement: this.renderView(i + 1, path, element, it.route),\n\t\t\t\tindex: i + 1,\n\t\t\t\tpath,\n\t\t\t\troute,\n\t\t\t});\n\t\t}\n\n\t\treturn { layers, pathname, search };\n\t}\n\n\tprotected getErrorHandler(route: PageRoute) {\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) {\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 });\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.getDescriptorValues($page);\n\n\t\t\tconst hasParent = (it: { [OPTIONS]: PageDescriptorOptions }) => {\n\t\t\t\tfor (const page of pages) {\n\t\t\t\t\tconst children = page.value[OPTIONS].children\n\t\t\t\t\t\t? Array.isArray(page.value[OPTIONS].children)\n\t\t\t\t\t\t\t? page.value[OPTIONS].children\n\t\t\t\t\t\t\t: page.value[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 { value, key } of pages) {\n\t\t\t\tvalue[OPTIONS].name ??= key;\n\t\t\t}\n\n\t\t\tfor (const { value } of pages) {\n\t\t\t\t// skip children, we only want root pages\n\t\t\t\tif (hasParent(value)) {\n\t\t\t\t\tcontinue;\n\t\t\t\t}\n\n\t\t\t\tif (value[OPTIONS].path === \"/*\") {\n\t\t\t\t\thasNotFoundHandler = true;\n\t\t\t\t}\n\n\t\t\t\tthis.add(this.map(pages, value));\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\tafterHandler: ({ 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<{ value: { [OPTIONS]: PageDescriptorOptions } }>,\n\t\ttarget: { [OPTIONS]: PageDescriptorOptions },\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\treturn {\n\t\t\t...target[OPTIONS],\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}\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 RouterState {\n\tpathname: string;\n\tsearch: string;\n\tlayers: Array<Layer>;\n}\n\nexport interface TransitionOptions {\n\tstate?: RouterState;\n\tprevious?: PreviousLayerData[];\n\tcontext?: PageReactContext;\n}\n\nexport interface RouterStackItem {\n\troute: PageRoute;\n\tconfig?: Record<string, any>;\n\tprops?: Record<string, any>;\n\terror?: Error;\n}\n\nexport interface RouterRenderResult {\n\tstate: RouterState;\n\tcontext: PageReactContext;\n\tredirect?: string;\n}\n\nexport interface PageRequest extends PageReactContext {\n\tparams: Record<string, any>;\n\tquery: Record<string, string>;\n\n\t// previous layers (browser history or browser hydration, always null on server)\n\tprevious?: PreviousLayerData[];\n}\n\nexport interface CreateLayersResult extends RouterState {\n\tredirect?: string;\n}\n\n/**\n * It's like RouterState, but publicly available in React context.\n * This is where we store all plugin data!\n */\nexport interface PageReactContext {\n\turl: URL;\n\tonError: (error: Error) => ReactNode;\n\tlinks?: ApiLinksResponse;\n}\n","import { $hook, $inject, $logger, Alepha } from \"@alepha/core\";\nimport { type Route, RouterProvider } from \"@alepha/router\";\nimport { createElement, type ReactNode } from \"react\";\nimport NotFoundPage from \"../components/NotFound.tsx\";\nimport {\n\tisPageRoute,\n\tPageDescriptorProvider,\n\ttype PageReactContext,\n\ttype PageRequest,\n\ttype PageRoute,\n\ttype PageRouteEntry,\n\ttype RouterRenderResult,\n\ttype RouterState,\n\ttype TransitionOptions,\n} from \"./PageDescriptorProvider.ts\";\n\nexport interface BrowserRoute extends Route {\n\tpage: PageRoute;\n}\n\nexport class BrowserRouterProvider extends RouterProvider<BrowserRoute> {\n\tprotected readonly log = $logger();\n\tprotected readonly alepha = $inject(Alepha);\n\tprotected readonly pageDescriptorProvider = $inject(PageDescriptorProvider);\n\n\tpublic add(entry: PageRouteEntry) {\n\t\tthis.pageDescriptorProvider.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.pageDescriptorProvider.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\toptions: TransitionOptions = {},\n\t): Promise<RouterRenderResult> {\n\t\tconst { pathname, search } = url;\n\t\tconst state: RouterState = {\n\t\t\tpathname,\n\t\t\tsearch,\n\t\t\tlayers: [],\n\t\t};\n\n\t\tconst context = {\n\t\t\turl,\n\t\t\tquery: {},\n\t\t\tparams: {},\n\t\t\tonError: () => null,\n\t\t\t...(options.context ?? {}),\n\t\t} as PageRequest;\n\n\t\tawait this.alepha.emit(\"react:transition:begin\", { state, context });\n\n\t\ttry {\n\t\t\tconst previous = options.previous;\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\tcontext.query = query;\n\t\t\tcontext.params = params ?? {};\n\t\t\tcontext.previous = previous;\n\n\t\t\tif (isPageRoute(route)) {\n\t\t\t\tconst result = await this.pageDescriptorProvider.createLayers(\n\t\t\t\t\troute.page,\n\t\t\t\t\tcontext,\n\t\t\t\t);\n\n\t\t\t\tif (result.redirect) {\n\t\t\t\t\treturn {\n\t\t\t\t\t\tredirect: result.redirect,\n\t\t\t\t\t\tstate,\n\t\t\t\t\t\tcontext,\n\t\t\t\t\t};\n\t\t\t\t}\n\n\t\t\t\tstate.layers = result.layers;\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.emit(\"react:transition:success\", { state, context });\n\t\t} catch (e) {\n\t\t\tthis.log.error(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.pageDescriptorProvider.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.emit(\"react:transition:error\", {\n\t\t\t\terror: e as Error,\n\t\t\t\tstate,\n\t\t\t\tcontext,\n\t\t\t});\n\t\t}\n\n\t\tif (options.state) {\n\t\t\toptions.state.layers = state.layers;\n\t\t\toptions.state.pathname = state.pathname;\n\t\t\toptions.state.search = state.search;\n\t\t}\n\n\t\tawait this.alepha.emit(\"react:transition:end\", {\n\t\t\tstate: options.state,\n\t\t\tcontext,\n\t\t});\n\n\t\treturn {\n\t\t\tcontext,\n\t\t\tstate,\n\t\t};\n\t}\n\n\tpublic root(state: RouterState, context: PageReactContext): ReactNode {\n\t\treturn this.pageDescriptorProvider.root(state, context);\n\t}\n}\n","import { $hook, $inject, $logger, Alepha } from \"@alepha/core\";\nimport type { ApiLinksResponse } from \"@alepha/server\";\nimport { LinkProvider } from \"@alepha/server-links\";\nimport type { Root } from \"react-dom/client\";\nimport { BrowserRouterProvider } from \"./BrowserRouterProvider.ts\";\nimport type {\n\tPreviousLayerData,\n\tRouterRenderResult,\n\tRouterState,\n\tTransitionOptions,\n} from \"./PageDescriptorProvider.ts\";\n\nexport class ReactBrowserProvider {\n\tprotected readonly log = $logger();\n\tprotected readonly client = $inject(LinkProvider);\n\tprotected readonly alepha = $inject(Alepha);\n\tprotected readonly router = $inject(BrowserRouterProvider);\n\tprotected root!: Root;\n\n\tpublic transitioning?: {\n\t\tto: string;\n\t};\n\n\tpublic state: RouterState = {\n\t\tlayers: [],\n\t\tpathname: \"\",\n\t\tsearch: \"\",\n\t};\n\n\tpublic get document() {\n\t\treturn window.document;\n\t}\n\n\tpublic get history() {\n\t\treturn window.history;\n\t}\n\n\tpublic get url(): string {\n\t\treturn window.location.pathname + window.location.search;\n\t}\n\n\tpublic async invalidate(props?: Record<string, any>) {\n\t\tconst previous: PreviousLayerData[] = [];\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\tconst result = await this.render({\n\t\t\turl,\n\t\t});\n\n\t\t// when redirecting in browser\n\t\tif (result.context.url.pathname !== url) {\n\t\t\t// TODO: check if losing search params is acceptable?\n\t\t\tthis.history.replaceState({}, \"\", result.context.url.pathname);\n\t\t\treturn;\n\t\t}\n\n\t\tif (options.replace) {\n\t\t\tthis.history.replaceState({}, \"\", url);\n\t\t\treturn;\n\t\t}\n\n\t\tthis.history.pushState({}, \"\", url);\n\t}\n\n\tprotected async render(\n\t\toptions: { url?: string; previous?: PreviousLayerData[] } = {},\n\t): Promise<RouterRenderResult> {\n\t\tconst previous = options.previous ?? this.state.layers;\n\t\tconst url = options.url ?? this.url;\n\n\t\tthis.transitioning = { to: url };\n\n\t\tconst result = await this.router.transition(\n\t\t\tnew URL(`http://localhost${url}`),\n\t\t\t{\n\t\t\t\tprevious,\n\t\t\t\tstate: this.state,\n\t\t\t},\n\t\t);\n\n\t\tif (result.redirect) {\n\t\t\treturn await this.render({ url: result.redirect });\n\t\t}\n\n\t\tthis.transitioning = undefined;\n\n\t\treturn result;\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\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?.links) {\n\t\t\t\tfor (const link of hydration.links.links) {\n\t\t\t\t\tthis.client.pushLink(link);\n\t\t\t\t}\n\t\t\t}\n\n\t\t\tconst { context } = await this.render({ previous });\n\n\t\t\tawait this.alepha.emit(\"react:browser:render\", {\n\t\t\t\tstate: this.state,\n\t\t\t\tcontext,\n\t\t\t\thydration,\n\t\t\t});\n\n\t\t\twindow.addEventListener(\"popstate\", () => {\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}\n\nexport interface ReactHydrationState {\n\tlayers?: Array<PreviousLayerData>;\n\tlinks?: ApiLinksResponse;\n}\n","import { $hook, $inject, $logger, type Static, t } from \"@alepha/core\";\nimport type { ApiLinksResponse } from \"@alepha/server\";\nimport type { Root } from \"react-dom/client\";\nimport { createRoot, hydrateRoot } from \"react-dom/client\";\nimport { BrowserRouterProvider } from \"./BrowserRouterProvider.ts\";\nimport type {\n\tPreviousLayerData,\n\tTransitionOptions,\n} from \"./PageDescriptorProvider.ts\";\nimport { ReactBrowserProvider } from \"./ReactBrowserProvider.ts\";\n\nconst envSchema = t.object({\n\tREACT_ROOT_ID: t.string({ default: \"root\" }),\n});\n\ndeclare module \"@alepha/core\" {\n\tinterface Env extends Partial<Static<typeof envSchema>> {}\n}\n\n// TODO: move to ReactBrowserProvider when it will be removed from server-side imports\nexport class ReactBrowserRenderer {\n\tprotected readonly browserProvider = $inject(ReactBrowserProvider);\n\tprotected readonly browserRouterProvider = $inject(BrowserRouterProvider);\n\tprotected readonly env = $inject(envSchema);\n\tprotected readonly log = $logger();\n\n\tprotected root!: Root;\n\n\tprotected getRootElement() {\n\t\tconst root = this.browserProvider.document.getElementById(\n\t\t\tthis.env.REACT_ROOT_ID,\n\t\t);\n\t\tif (root) {\n\t\t\treturn root;\n\t\t}\n\n\t\tconst div = this.browserProvider.document.createElement(\"div\");\n\t\tdiv.id = this.env.REACT_ROOT_ID;\n\n\t\tthis.browserProvider.document.body.prepend(div);\n\n\t\treturn div;\n\t}\n\n\tpublic readonly ready = $hook({\n\t\ton: \"react:browser:render\",\n\t\thandler: async ({ state, context, hydration }) => {\n\t\t\tconst element = this.browserRouterProvider.root(state, context);\n\n\t\t\tif (hydration?.layers) {\n\t\t\t\tthis.root = hydrateRoot(this.getRootElement(), element);\n\t\t\t\tthis.log.info(\"Hydrated root element\");\n\t\t\t} else {\n\t\t\t\tthis.root ??= createRoot(this.getRootElement());\n\t\t\t\tthis.root.render(element);\n\t\t\t\tthis.log.info(\"Created root element\");\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}\n\nexport interface ReactHydrationState {\n\tlayers?: Array<PreviousLayerData>;\n\tlinks?: ApiLinksResponse;\n}\n","import type { PageDescriptor } from \"../descriptors/$page.ts\";\nimport type {\n\tAnchorProps,\n\tPageRoute,\n\tRouterState,\n} from \"../providers/PageDescriptorProvider.ts\";\nimport type {\n\tReactBrowserProvider,\n\tRouterGoOptions,\n} from \"../providers/ReactBrowserProvider.ts\";\n\nexport class RouterHookApi {\n\tconstructor(\n\t\tprivate readonly pages: PageRoute[],\n\t\tprivate readonly state: RouterState,\n\t\tprivate readonly layer: {\n\t\t\tpath: string;\n\t\t},\n\t\tprivate readonly browser?: ReactBrowserProvider,\n\t) {}\n\n\tpublic get current(): RouterState {\n\t\treturn this.state;\n\t}\n\n\tpublic get pathname(): string {\n\t\treturn this.state.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.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\t/**\n\t * Create a valid href for the given pathname.\n\t *\n\t * @param pathname\n\t * @param layer\n\t */\n\tpublic createHref(\n\t\tpathname: HrefLike,\n\t\tlayer: { path: string } = this.layer,\n\t\toptions: { params?: Record<string, any> } = {},\n\t) {\n\t\tif (typeof pathname === \"object\") {\n\t\t\tpathname = pathname.options.path ?? \"\";\n\t\t}\n\n\t\tif (options.params) {\n\t\t\tfor (const [key, value] of Object.entries(options.params)) {\n\t\t\t\tpathname = pathname.replace(`:${key}`, String(value));\n\t\t\t}\n\t\t}\n\n\t\treturn pathname.startsWith(\"/\")\n\t\t\t? pathname\n\t\t\t: `${layer.path}/${pathname}`.replace(/\\/\\/+/g, \"/\");\n\t}\n\n\tpublic async go(path: string, options?: RouterGoOptions): Promise<void>;\n\tpublic async go<T extends object>(\n\t\tpath: keyof VirtualRouter<T>,\n\t\toptions?: RouterGoOptions,\n\t): Promise<void>;\n\tpublic async go(path: string, options?: RouterGoOptions): Promise<void> {\n\t\tfor (const page of this.pages) {\n\t\t\tif (page.name === path) {\n\t\t\t\tpath = page.path ?? \"\";\n\t\t\t\tbreak;\n\t\t\t}\n\t\t}\n\n\t\tawait this.browser?.go(this.createHref(path, this.layer, options), options);\n\t}\n\n\tpublic anchor(\n\t\tpath: string,\n\t\toptions?: { params?: Record<string, any> },\n\t): AnchorProps;\n\tpublic anchor<T extends object>(\n\t\tpath: keyof VirtualRouter<T>,\n\t\toptions?: { params?: Record<string, any> },\n\t): AnchorProps;\n\tpublic anchor(\n\t\tpath: string,\n\t\toptions: { params?: Record<string, any> } = {},\n\t): AnchorProps {\n\t\tfor (const page of this.pages) {\n\t\t\tif (page.name === path) {\n\t\t\t\tpath = page.path ?? \"\";\n\t\t\t\tbreak;\n\t\t\t}\n\t\t}\n\n\t\tconst href = this.createHref(path, this.layer, options);\n\t\treturn {\n\t\t\thref,\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(path, options).catch(console.error);\n\t\t\t},\n\t\t};\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 HrefLike = string | { options: { path?: string; name?: string } };\n\nexport type VirtualRouter<T> = {\n\t[K in keyof T as T[K] extends PageDescriptor ? K : never]: T[K];\n};\n","import { useContext, useMemo } from \"react\";\nimport { RouterContext } from \"../contexts/RouterContext.ts\";\nimport { RouterLayerContext } from \"../contexts/RouterLayerContext.ts\";\nimport { PageDescriptorProvider } from \"../providers/PageDescriptorProvider.ts\";\nimport { ReactBrowserProvider } from \"../providers/ReactBrowserProvider.ts\";\nimport { RouterHookApi } from \"./RouterHookApi.ts\";\n\nexport const useRouter = (): RouterHookApi => {\n\tconst ctx = useContext(RouterContext);\n\tconst layer = useContext(RouterLayerContext);\n\tif (!ctx || !layer) {\n\t\tthrow new Error(\"useRouter must be used within a RouterProvider\");\n\t}\n\n\tconst pages = useMemo(() => {\n\t\treturn ctx.alepha.get(PageDescriptorProvider).getPages();\n\t}, []);\n\n\treturn useMemo(\n\t\t() =>\n\t\t\tnew RouterHookApi(\n\t\t\t\tpages,\n\t\t\t\tctx.state,\n\t\t\t\tlayer,\n\t\t\t\tctx.alepha.isBrowser()\n\t\t\t\t\t? ctx.alepha.get(ReactBrowserProvider)\n\t\t\t\t\t: undefined,\n\t\t\t),\n\t\t[layer],\n\t);\n};\n","import { OPTIONS } from \"@alepha/core\";\nimport type { AnchorHTMLAttributes } from \"react\";\nimport React from \"react\";\nimport { RouterContext } from \"../contexts/RouterContext.ts\";\nimport type { PageDescriptor } from \"../descriptors/$page.ts\";\nimport { useRouter } from \"../hooks/useRouter.ts\";\n\nexport interface LinkProps extends AnchorHTMLAttributes<HTMLAnchorElement> {\n\tto: string | PageDescriptor;\n\tchildren?: React.ReactNode;\n}\n\nconst Link = (props: LinkProps) => {\n\tReact.useContext(RouterContext);\n\n\tconst router = useRouter();\n\n\tconst to = typeof props.to === \"string\" ? props.to : props.to[OPTIONS].path;\n\tif (!to) {\n\t\treturn null;\n\t}\n\n\tconst can = typeof props.to === \"string\" ? undefined : props.to[OPTIONS].can;\n\tif (can && !can()) {\n\t\treturn null;\n\t}\n\n\tconst name =\n\t\ttypeof props.to === \"string\" ? undefined : props.to[OPTIONS].name;\n\n\tconst anchorProps = {\n\t\t...props,\n\t\tto: undefined,\n\t};\n\n\treturn (\n\t\t<a {...router.anchor(to)} {...anchorProps}>\n\t\t\t{props.children ?? name}\n\t\t</a>\n\t);\n};\n\nexport default Link;\n","import { useContext, useMemo, useState } from \"react\";\nimport { RouterContext } from \"../contexts/RouterContext.ts\";\nimport { RouterLayerContext } from \"../contexts/RouterLayerContext.ts\";\nimport type { AnchorProps } from \"../providers/PageDescriptorProvider.ts\";\nimport type { HrefLike } from \"./RouterHookApi.ts\";\nimport { useRouter } from \"./useRouter.ts\";\nimport { useRouterEvents } from \"./useRouterEvents.ts\";\n\nexport const useActive = (path: HrefLike): UseActiveHook => {\n\tconst router = useRouter();\n\tconst ctx = useContext(RouterContext);\n\tconst layer = useContext(RouterLayerContext);\n\tif (!ctx || !layer) {\n\t\tthrow new Error(\"useRouter must be used within a RouterProvider\");\n\t}\n\n\tlet name: string | undefined;\n\tif (typeof path === \"object\" && path.options.name) {\n\t\tname = path.options.name;\n\t}\n\n\tconst [current, setCurrent] = useState(ctx.state.pathname);\n\tconst href = useMemo(() => router.createHref(path, layer), [path, layer]);\n\tconst [isPending, setPending] = useState(false);\n\tconst isActive = current === href;\n\n\tuseRouterEvents({\n\t\tonEnd: ({ state }) => setCurrent(state.pathname),\n\t});\n\n\treturn {\n\t\tname,\n\t\tisPending,\n\t\tisActive,\n\t\tanchorProps: {\n\t\t\thref,\n\t\t\tonClick: (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\trouter.go(href).then(() => {\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\tname?: string;\n}\n","import type { Service } from \"@alepha/core\";\nimport { useContext, useMemo } from \"react\";\nimport { RouterContext } from \"../contexts/RouterContext.ts\";\n\nexport const useInject = <T extends object>(clazz: Service<T>): T => {\n\tconst ctx = useContext(RouterContext);\n\tif (!ctx) {\n\t\tthrow new Error(\"useRouter must be used within a <RouterProvider>\");\n\t}\n\n\treturn useMemo(() => ctx.alepha.get(clazz), []);\n};\n","import {\n\ttype ClientScope,\n\ttype HttpVirtualClient,\n\tLinkProvider,\n} from \"@alepha/server-links\";\nimport { useInject } from \"./useInject.ts\";\n\nexport const useClient = <T extends object>(\n\t_scope?: ClientScope,\n): HttpVirtualClient<T> => {\n\treturn useInject(LinkProvider).client<T>();\n};\n","import type { Alepha, Static, TObject } from \"@alepha/core\";\nimport { useContext, useEffect, useState } from \"react\";\nimport { RouterContext } from \"../contexts/RouterContext.ts\";\nimport { useRouter } from \"./useRouter.ts\";\n\nexport interface UseQueryParamsHookOptions {\n\tformat?: \"base64\" | \"querystring\";\n\tkey?: string;\n\tpush?: boolean;\n}\n\nexport const useQueryParams = <T extends TObject>(\n\tschema: T,\n\toptions: UseQueryParamsHookOptions = {},\n): [Static<T>, (data: Static<T>) => void] => {\n\tconst ctx = useContext(RouterContext);\n\tif (!ctx) {\n\t\tthrow new Error(\"useQueryParams must be used within a RouterProvider\");\n\t}\n\n\tconst key = options.key ?? \"q\";\n\tconst router = useRouter();\n\tconst querystring = router.query[key];\n\n\tconst [queryParams, setQueryParams] = useState(\n\t\tdecode(ctx.alepha, schema, router.query[key]),\n\t);\n\n\tuseEffect(() => {\n\t\tsetQueryParams(decode(ctx.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(ctx.alepha, schema, queryParams) };\n\t\t\t});\n\t\t},\n\t];\n};\n\n// ---------------------------------------------------------------------------------------------------------------------\n\nconst encode = (alepha: Alepha, schema: TObject, data: any) => {\n\treturn btoa(JSON.stringify(alepha.parse(schema, data)));\n};\n\nconst decode = (alepha: Alepha, schema: TObject, data: any) => {\n\ttry {\n\t\treturn alepha.parse(schema, JSON.parse(atob(decodeURIComponent(data))));\n\t} catch (_error) {\n\t\treturn {};\n\t}\n};\n","import { useContext, useState } from \"react\";\nimport { RouterContext } from \"../contexts/RouterContext.ts\";\nimport { RouterLayerContext } from \"../contexts/RouterLayerContext.ts\";\nimport type { RouterState } from \"../providers/PageDescriptorProvider.ts\";\nimport { useRouterEvents } from \"./useRouterEvents.ts\";\n\nexport const useRouterState = (): RouterState => {\n\tconst ctx = useContext(RouterContext);\n\tconst layer = useContext(RouterLayerContext);\n\tif (!ctx || !layer) {\n\t\tthrow new Error(\"useRouter must be used within a RouterProvider\");\n\t}\n\n\tconst [state, setState] = useState(ctx.state);\n\n\tuseRouterEvents({\n\t\tonEnd: ({ state }) => setState({ ...state }),\n\t});\n\n\treturn state;\n};\n","import { __bind, type Alepha, type Module } from \"@alepha/core\";\nimport { AlephaServer } from \"@alepha/server\";\nimport { AlephaServerLinks } from \"@alepha/server-links\";\nimport { $page } from \"./descriptors/$page.ts\";\nimport { BrowserRouterProvider } from \"./providers/BrowserRouterProvider.ts\";\nimport { PageDescriptorProvider } from \"./providers/PageDescriptorProvider.ts\";\nimport { ReactBrowserProvider } from \"./providers/ReactBrowserProvider.ts\";\nimport { ReactBrowserRenderer } from \"./providers/ReactBrowserRenderer.ts\";\n\n// ---------------------------------------------------------------------------------------------------------------------\n\nexport * from \"./index.shared.ts\";\nexport * from \"./providers/BrowserRouterProvider.ts\";\nexport * from \"./providers/PageDescriptorProvider.ts\";\nexport * from \"./providers/ReactBrowserProvider.ts\";\n\n// ---------------------------------------------------------------------------------------------------------------------\n\nexport class AlephaReact implements Module {\n\tpublic readonly name = \"alepha.react\";\n\tpublic readonly $services = (alepha: Alepha) =>\n\t\talepha\n\t\t\t.with(AlephaServer)\n\t\t\t.with(AlephaServerLinks)\n\t\t\t.with(PageDescriptorProvider)\n\t\t\t.with(ReactBrowserProvider)\n\t\t\t.with(BrowserRouterProvider)\n\t\t\t.with(ReactBrowserRenderer);\n}\n\n__bind($page, AlephaReact);\n"],"mappings":"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"}
package/dist/index.cjs CHANGED
@@ -24,11 +24,11 @@ var __toESM = (mod, isNodeMode, target) => (target = mod != null ? __create(__ge
24
24
  const __alepha_core = __toESM(require("@alepha/core"));
25
25
  const __alepha_server = __toESM(require("@alepha/server"));
26
26
  const __alepha_server_cache = __toESM(require("@alepha/server-cache"));
27
+ const __alepha_server_links = __toESM(require("@alepha/server-links"));
27
28
  const react = __toESM(require("react"));
28
29
  const react_jsx_runtime = __toESM(require("react/jsx-runtime"));
29
30
  const node_fs = __toESM(require("node:fs"));
30
31
  const node_path = __toESM(require("node:path"));
31
- const __alepha_server_links = __toESM(require("@alepha/server-links"));
32
32
  const __alepha_server_static = __toESM(require("@alepha/server-static"));
33
33
  const react_dom_server = __toESM(require("react-dom/server"));
34
34
  const __alepha_router = __toESM(require("@alepha/router"));
@@ -40,11 +40,6 @@ const KEY = "PAGE";
40
40
  */
41
41
  const $page = (options) => {
42
42
  (0, __alepha_core.__descriptor)(KEY);
43
- if (options.children) for (const child of options.children) child[__alepha_core.OPTIONS].parent = { [__alepha_core.OPTIONS]: options };
44
- if (options.parent) {
45
- options.parent[__alepha_core.OPTIONS].children ??= [];
46
- options.parent[__alepha_core.OPTIONS].children.push({ [__alepha_core.OPTIONS]: options });
47
- }
48
43
  return {
49
44
  [__alepha_core.KIND]: KEY,
50
45
  [__alepha_core.OPTIONS]: options,
@@ -570,13 +565,19 @@ var PageDescriptorProvider = class {
570
565
  } }, element);
571
566
  }
572
567
  configure = (0, __alepha_core.$hook)({
573
- name: "configure",
568
+ on: "configure",
574
569
  handler: () => {
575
570
  let hasNotFoundHandler = false;
576
571
  const pages = this.alepha.getDescriptorValues($page);
572
+ const hasParent = (it) => {
573
+ for (const page of pages) {
574
+ const children = page.value[__alepha_core.OPTIONS].children ? Array.isArray(page.value[__alepha_core.OPTIONS].children) ? page.value[__alepha_core.OPTIONS].children : page.value[__alepha_core.OPTIONS].children() : [];
575
+ if (children.includes(it)) return true;
576
+ }
577
+ };
577
578
  for (const { value, key } of pages) value[__alepha_core.OPTIONS].name ??= key;
578
579
  for (const { value } of pages) {
579
- if (value[__alepha_core.OPTIONS].parent) continue;
580
+ if (hasParent(value)) continue;
580
581
  if (value[__alepha_core.OPTIONS].path === "/*") hasNotFoundHandler = true;
581
582
  this.add(this.map(pages, value));
582
583
  }
@@ -592,7 +593,7 @@ var PageDescriptorProvider = class {
592
593
  }
593
594
  });
594
595
  map(pages, target) {
595
- const children = target[__alepha_core.OPTIONS].children ?? [];
596
+ const children = target[__alepha_core.OPTIONS].children ? Array.isArray(target[__alepha_core.OPTIONS].children) ? target[__alepha_core.OPTIONS].children : target[__alepha_core.OPTIONS].children() : [];
596
597
  return {
597
598
  ...target[__alepha_core.OPTIONS],
598
599
  parent: void 0,
@@ -649,7 +650,7 @@ var ReactServerProvider = class {
649
650
  env = (0, __alepha_core.$inject)(envSchema);
650
651
  ROOT_DIV_REGEX = new RegExp(`<div([^>]*)\\s+id=["']${this.env.REACT_ROOT_ID}["']([^>]*)>(.*?)<\\/div>`, "is");
651
652
  onConfigure = (0, __alepha_core.$hook)({
652
- name: "configure",
653
+ on: "configure",
653
654
  handler: async () => {
654
655
  const pages = this.alepha.getDescriptorValues($page);
655
656
  const ssrEnabled = pages.length > 0 && this.env.REACT_SSR_ENABLED !== false;
@@ -868,7 +869,7 @@ var BrowserRouterProvider = class extends __alepha_router.RouterProvider {
868
869
  this.pageDescriptorProvider.add(entry);
869
870
  }
870
871
  configure = (0, __alepha_core.$hook)({
871
- name: "configure",
872
+ on: "configure",
872
873
  handler: async () => {
873
874
  for (const page of this.pageDescriptorProvider.getPages()) if (page.component || page.lazy) this.push({
874
875
  path: page.match,
@@ -1033,7 +1034,7 @@ var ReactBrowserProvider = class {
1033
1034
  }
1034
1035
  }
1035
1036
  ready = (0, __alepha_core.$hook)({
1036
- name: "ready",
1037
+ on: "ready",
1037
1038
  handler: async () => {
1038
1039
  const hydration = this.getHydrationState();
1039
1040
  const previous = hydration?.layers ?? [];
@@ -1267,7 +1268,7 @@ const useRouterState = () => {
1267
1268
  */
1268
1269
  var AlephaReact = class {
1269
1270
  name = "alepha.react";
1270
- $services = (alepha) => alepha.with(__alepha_server.AlephaServer).with(__alepha_server_cache.AlephaServerCache).with(ReactServerProvider).with(PageDescriptorProvider);
1271
+ $services = (alepha) => alepha.with(__alepha_server.AlephaServer).with(__alepha_server_cache.AlephaServerCache).with(__alepha_server_links.AlephaServerLinks).with(ReactServerProvider).with(PageDescriptorProvider);
1271
1272
  };
1272
1273
  (0, __alepha_core.__bind)($page, AlephaReact);
1273
1274