@alepha/react 0.7.6 → 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 { HttpClient } from "@alepha/server";
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,
@@ -453,10 +449,6 @@ var PageDescriptorProvider = class {
453
449
  const props = it.props ?? {};
454
450
  const params = { ...it.config?.params };
455
451
  for (const key of Object.keys(params)) params[key] = String(params[key]);
456
- if (it.route.head && !it.error) this.fillHead(it.route, request, {
457
- ...props,
458
- ...context
459
- });
460
452
  acc += "/";
461
453
  acc += it.route.path ? this.compile(it.route.path, params) : "";
462
454
  const path = acc.replace(/\/+/, "/");
@@ -473,7 +465,8 @@ var PageDescriptorProvider = class {
473
465
  config: it.config,
474
466
  element: this.renderView(i + 1, path, element$1, it.route),
475
467
  index: i + 1,
476
- path
468
+ path,
469
+ route
477
470
  });
478
471
  break;
479
472
  }
@@ -488,7 +481,8 @@ var PageDescriptorProvider = class {
488
481
  config: it.config,
489
482
  element: this.renderView(i + 1, path, element, it.route),
490
483
  index: i + 1,
491
- path
484
+ path,
485
+ route
492
486
  });
493
487
  }
494
488
  return {
@@ -513,26 +507,6 @@ var PageDescriptorProvider = class {
513
507
  if (page.component) return createElement(page.component, props);
514
508
  return void 0;
515
509
  }
516
- fillHead(page, ctx, props) {
517
- if (!page.head) return;
518
- ctx.head ??= {};
519
- const head = typeof page.head === "function" ? page.head(props, ctx.head) : page.head;
520
- if (head.title) {
521
- ctx.head ??= {};
522
- if (ctx.head.titleSeparator) ctx.head.title = `${head.title}${ctx.head.titleSeparator}${ctx.head.title}`;
523
- else ctx.head.title = head.title;
524
- ctx.head.titleSeparator = head.titleSeparator;
525
- }
526
- if (head.htmlAttributes) ctx.head.htmlAttributes = {
527
- ...ctx.head.htmlAttributes,
528
- ...head.htmlAttributes
529
- };
530
- if (head.bodyAttributes) ctx.head.bodyAttributes = {
531
- ...ctx.head.bodyAttributes,
532
- ...head.bodyAttributes
533
- };
534
- if (head.meta) ctx.head.meta = [...ctx.head.meta ?? [], ...head.meta ?? []];
535
- }
536
510
  renderError(error) {
537
511
  return createElement(ErrorViewer_default, { error });
538
512
  }
@@ -564,13 +538,19 @@ var PageDescriptorProvider = class {
564
538
  } }, element);
565
539
  }
566
540
  configure = $hook({
567
- name: "configure",
541
+ on: "configure",
568
542
  handler: () => {
569
543
  let hasNotFoundHandler = false;
570
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
+ };
571
551
  for (const { value, key } of pages) value[OPTIONS].name ??= key;
572
552
  for (const { value } of pages) {
573
- if (value[OPTIONS].parent) continue;
553
+ if (hasParent(value)) continue;
574
554
  if (value[OPTIONS].path === "/*") hasNotFoundHandler = true;
575
555
  this.add(this.map(pages, value));
576
556
  }
@@ -586,7 +566,7 @@ var PageDescriptorProvider = class {
586
566
  }
587
567
  });
588
568
  map(pages, target) {
589
- const children = target[OPTIONS].children ?? [];
569
+ const children = target[OPTIONS].children ? Array.isArray(target[OPTIONS].children) ? target[OPTIONS].children : target[OPTIONS].children() : [];
590
570
  return {
591
571
  ...target[OPTIONS],
592
572
  parent: void 0,
@@ -635,7 +615,7 @@ var BrowserRouterProvider = class extends RouterProvider {
635
615
  this.pageDescriptorProvider.add(entry);
636
616
  }
637
617
  configure = $hook({
638
- name: "configure",
618
+ on: "configure",
639
619
  handler: async () => {
640
620
  for (const page of this.pageDescriptorProvider.getPages()) if (page.component || page.lazy) this.push({
641
621
  path: page.match,
@@ -654,7 +634,6 @@ var BrowserRouterProvider = class extends RouterProvider {
654
634
  url,
655
635
  query: {},
656
636
  params: {},
657
- head: {},
658
637
  onError: () => null,
659
638
  ...options.context ?? {}
660
639
  };
@@ -685,7 +664,10 @@ var BrowserRouterProvider = class extends RouterProvider {
685
664
  index: 0,
686
665
  path: "/"
687
666
  });
688
- await this.alepha.emit("react:transition:success", { state });
667
+ await this.alepha.emit("react:transition:success", {
668
+ state,
669
+ context
670
+ });
689
671
  } catch (e) {
690
672
  this.log.error(e);
691
673
  state.layers = [{
@@ -719,36 +701,13 @@ var BrowserRouterProvider = class extends RouterProvider {
719
701
  }
720
702
  };
721
703
 
722
- //#endregion
723
- //#region src/providers/BrowserHeadProvider.ts
724
- var BrowserHeadProvider = class {
725
- renderHead(document, head) {
726
- if (head.title) document.title = head.title;
727
- if (head.bodyAttributes) for (const [key, value] of Object.entries(head.bodyAttributes)) if (value) document.body.setAttribute(key, value);
728
- else document.body.removeAttribute(key);
729
- if (head.htmlAttributes) for (const [key, value] of Object.entries(head.htmlAttributes)) if (value) document.documentElement.setAttribute(key, value);
730
- else document.documentElement.removeAttribute(key);
731
- if (head.meta) for (const [key, value] of Object.entries(head.meta)) {
732
- const meta = document.querySelector(`meta[name="${key}"]`);
733
- if (meta) meta.setAttribute("content", value.content);
734
- else {
735
- const newMeta = document.createElement("meta");
736
- newMeta.setAttribute("name", key);
737
- newMeta.setAttribute("content", value.content);
738
- document.head.appendChild(newMeta);
739
- }
740
- }
741
- }
742
- };
743
-
744
704
  //#endregion
745
705
  //#region src/providers/ReactBrowserProvider.ts
746
706
  var ReactBrowserProvider = class {
747
707
  log = $logger();
748
- client = $inject(HttpClient);
708
+ client = $inject(LinkProvider);
749
709
  alepha = $inject(Alepha);
750
710
  router = $inject(BrowserRouterProvider);
751
- headProvider = $inject(BrowserHeadProvider);
752
711
  root;
753
712
  transitioning;
754
713
  state = {
@@ -821,13 +780,12 @@ var ReactBrowserProvider = class {
821
780
  }
822
781
  }
823
782
  ready = $hook({
824
- name: "ready",
783
+ on: "ready",
825
784
  handler: async () => {
826
785
  const hydration = this.getHydrationState();
827
786
  const previous = hydration?.layers ?? [];
828
787
  if (hydration?.links) for (const link of hydration.links.links) this.client.pushLink(link);
829
788
  const { context } = await this.render({ previous });
830
- if (context.head) this.headProvider.renderHead(this.document, context.head);
831
789
  await this.alepha.emit("react:browser:render", {
832
790
  state: this.state,
833
791
  context,
@@ -838,12 +796,6 @@ var ReactBrowserProvider = class {
838
796
  });
839
797
  }
840
798
  });
841
- onTransitionEnd = $hook({
842
- name: "react:transition:end",
843
- handler: async ({ context }) => {
844
- this.headProvider.renderHead(this.document, context.head);
845
- }
846
- });
847
799
  };
848
800
 
849
801
  //#endregion
@@ -864,7 +816,7 @@ var ReactBrowserRenderer = class {
864
816
  return div;
865
817
  }
866
818
  ready = $hook({
867
- name: "react:browser:render",
819
+ on: "react:browser:render",
868
820
  handler: async ({ state, context, hydration }) => {
869
821
  const element = this.browserRouterProvider.root(state, context);
870
822
  if (hydration?.layers) {
@@ -1035,7 +987,7 @@ const useInject = (clazz) => {
1035
987
  //#endregion
1036
988
  //#region src/hooks/useClient.ts
1037
989
  const useClient = (_scope) => {
1038
- return useInject(HttpClient).of();
990
+ return useInject(LinkProvider).client();
1039
991
  };
1040
992
 
1041
993
  //#endregion
@@ -1086,7 +1038,7 @@ const useRouterState = () => {
1086
1038
  //#region src/index.browser.ts
1087
1039
  var AlephaReact = class {
1088
1040
  name = "alepha.react";
1089
- $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);
1090
1042
  };
1091
1043
  __bind($page, AlephaReact);
1092
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>","ctx: PageRequest","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","context: PageRequest","query: Record<string, string>","context: PageReactContext","document: Document","head: Head","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/BrowserHeadProvider.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\thead?: Head | ((props: TProps, previous?: Head) => Head);\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\twithLayout?: boolean;\n}\n\nexport interface PageDescriptorRenderResult {\n\thtml: string;\n\tcontext: PageReactContext;\n}\n\nexport interface Head {\n\ttitle?: string;\n\tdescription?: string;\n\ttitleSeparator?: string;\n\thtmlAttributes?: Record<string, string>;\n\tbodyAttributes?: Record<string, string>;\n\tmeta?: Array<{ name: string; content: string }>;\n\n\t// TODO\n\tkeywords?: string[];\n\tauthor?: string;\n\trobots?: string;\n\tthemeColor?: string;\n\tviewport?:\n\t\t| string\n\t\t| {\n\t\t\t\twidth?: string;\n\t\t\t\theight?: string;\n\t\t\t\tinitialScale?: string;\n\t\t\t\tmaximumScale?: string;\n\t\t\t\tuserScalable?: \"no\" | \"yes\" | \"0\" | \"1\";\n\t\t\t\tinteractiveWidget?:\n\t\t\t\t\t| \"resizes-visual\"\n\t\t\t\t\t| \"resizes-content\"\n\t\t\t\t\t| \"overlays-content\";\n\t\t };\n\n\tog?: {\n\t\ttitle?: string;\n\t\tdescription?: string;\n\t\timage?: string;\n\t\turl?: string;\n\t\ttype?: string;\n\t};\n\n\ttwitter?: {\n\t\tcard?: string;\n\t\ttitle?: string;\n\t\tdescription?: string;\n\t\timage?: string;\n\t\tsite?: string;\n\t};\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 {\n\t$page,\n\ttype Head,\n\ttype PageDescriptorOptions,\n} 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\tif (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});\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});\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\tprotected fillHead(\n\t\tpage: PageRoute,\n\t\tctx: PageRequest,\n\t\tprops: Record<string, any>,\n\t): void {\n\t\tif (!page.head) {\n\t\t\treturn;\n\t\t}\n\n\t\tctx.head ??= {};\n\n\t\tconst head =\n\t\t\ttypeof page.head === \"function\" ? page.head(props, ctx.head) : page.head;\n\n\t\tif (head.title) {\n\t\t\tctx.head ??= {};\n\n\t\t\tif (ctx.head.titleSeparator) {\n\t\t\t\tctx.head.title = `${head.title}${ctx.head.titleSeparator}${ctx.head.title}`;\n\t\t\t} else {\n\t\t\t\tctx.head.title = head.title;\n\t\t\t}\n\n\t\t\tctx.head.titleSeparator = head.titleSeparator;\n\t\t}\n\n\t\tif (head.htmlAttributes) {\n\t\t\tctx.head.htmlAttributes = {\n\t\t\t\t...ctx.head.htmlAttributes,\n\t\t\t\t...head.htmlAttributes,\n\t\t\t};\n\t\t}\n\n\t\tif (head.bodyAttributes) {\n\t\t\tctx.head.bodyAttributes = {\n\t\t\t\t...ctx.head.bodyAttributes,\n\t\t\t\t...head.bodyAttributes,\n\t\t\t};\n\t\t}\n\n\t\tif (head.meta) {\n\t\t\tctx.head.meta = [...(ctx.head.meta ?? []), ...(head.meta ?? [])];\n\t\t}\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}\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\thead: Head;\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: PageRequest = {\n\t\t\turl,\n\t\t\tquery: {},\n\t\t\tparams: {},\n\t\t\thead: {},\n\t\t\tonError: () => null,\n\t\t\t...(options.context ?? {}),\n\t\t};\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 });\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 type { Head } from \"./ServerHeadProvider.ts\";\n\nexport class BrowserHeadProvider {\n\trenderHead(document: Document, head: Head): void {\n\t\tif (head.title) {\n\t\t\tdocument.title = head.title;\n\t\t}\n\n\t\tif (head.bodyAttributes) {\n\t\t\tfor (const [key, value] of Object.entries(head.bodyAttributes)) {\n\t\t\t\tif (value) {\n\t\t\t\t\tdocument.body.setAttribute(key, value);\n\t\t\t\t} else {\n\t\t\t\t\tdocument.body.removeAttribute(key);\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\n\t\tif (head.htmlAttributes) {\n\t\t\tfor (const [key, value] of Object.entries(head.htmlAttributes)) {\n\t\t\t\tif (value) {\n\t\t\t\t\tdocument.documentElement.setAttribute(key, value);\n\t\t\t\t} else {\n\t\t\t\t\tdocument.documentElement.removeAttribute(key);\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\n\t\tif (head.meta) {\n\t\t\tfor (const [key, value] of Object.entries(head.meta)) {\n\t\t\t\tconst meta = document.querySelector(`meta[name=\"${key}\"]`);\n\t\t\t\tif (meta) {\n\t\t\t\t\tmeta.setAttribute(\"content\", value.content);\n\t\t\t\t} else {\n\t\t\t\t\tconst newMeta = document.createElement(\"meta\");\n\t\t\t\t\tnewMeta.setAttribute(\"name\", key);\n\t\t\t\t\tnewMeta.setAttribute(\"content\", value.content);\n\t\t\t\t\tdocument.head.appendChild(newMeta);\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t}\n}\n","import { $hook, $inject, $logger, Alepha } from \"@alepha/core\";\nimport { type ApiLinksResponse, HttpClient } from \"@alepha/server\";\nimport type { Root } from \"react-dom/client\";\nimport { BrowserHeadProvider } from \"./BrowserHeadProvider.ts\";\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(HttpClient);\n\tprotected readonly alepha = $inject(Alepha);\n\tprotected readonly router = $inject(BrowserRouterProvider);\n\tprotected readonly headProvider = $inject(BrowserHeadProvider);\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\t\t\tif (context.head) {\n\t\t\t\tthis.headProvider.renderHead(this.document, context.head);\n\t\t\t}\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\tpublic readonly onTransitionEnd = $hook({\n\t\tname: \"react:transition:end\",\n\t\thandler: async ({ context }) => {\n\t\t\tthis.headProvider.renderHead(this.document, context.head);\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\tHttpClient,\n\ttype HttpVirtualClient,\n} from \"@alepha/server\";\nimport { useInject } from \"./useInject.ts\";\n\nexport const useClient = <T extends object>(\n\t_scope?: ClientScope,\n): HttpVirtualClient<T> => {\n\treturn useInject(HttpClient).of<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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"}