UNPKG

alepha

Version:

Easy-to-use modern TypeScript framework for building many kind of applications.

1,223 lines 83.3 kB
import { Alepha, AlephaError, Async, KIND, Middleware, Primitive, SchemaValidator, Static, TObject, TSchema } from "alepha"; import { DateTimeProvider } from "alepha/datetime"; import { BrowserHeadProvider, Head, ServerHeadProvider, SimpleHead } from "alepha/react/head"; import { ServerHandler, ServerRequest, ServerRouterProvider } from "alepha/server"; import { LinkProvider } from "alepha/server/links"; import { AnchorHTMLAttributes, CSSProperties, FC, ReactNode } from "react"; import { ServerStaticProvider } from "alepha/server/static"; import { FileSystemProvider } from "alepha/system"; import { Route, RouterProvider } from "alepha/router"; //#region ../../src/react/router/constants/PAGE_PRELOAD_KEY.d.ts /** * Symbol key for SSR module preloading path. * Using Symbol.for() allows the Vite plugin to inject this at build time. * @internal */ declare const PAGE_PRELOAD_KEY: unique symbol; //#endregion //#region ../../src/react/router/errors/Redirection.d.ts /** * Used for Redirection during the page loading. * * Depends on the context, it can be thrown or just returned. * * @example * ```ts * import { Redirection } from "alepha/react"; * * const MyPage = $page({ * loader: async () => { * if (needRedirect) { * throw new Redirection("/new-path"); * } * }, * }); * ``` */ declare class Redirection extends AlephaError { readonly redirect: string; constructor(redirect: string); } //#endregion //#region ../../src/react/router/providers/RootComponentsProvider.d.ts /** * Extension point letting any module contribute root-level React nodes that * render on every page (siblings of the page view, inside AlephaContext). * * A module pushes into `rootComponents` from its `register` hook; the array * is rendered by `ReactPageProvider.root()`. SSR-safe (same element feeds * server render + client hydrate). */ declare class RootComponentsProvider { rootComponents: ReactNode[]; } //#endregion //#region ../../src/react/router/providers/RouterLocaleProvider.d.ts /** * Generic locale path-prefix mechanism for the router. * * This provider knows nothing about i18n — it only deals with URL path * segments. It is configured by the i18n module (`I18nProvider`) when * `routing: "prefix"` is enabled, which keeps the dependency one-directional * (`i18n → router`) and avoids a module cycle. * * The default locale is served WITHOUT a prefix (`/about` = default, * `/fr/about` = French). The active locale is derived from the current * request/navigation and stored under `alepha.react.router.locale`, so every * URL the router builds (`pathname()`) automatically carries the right prefix. */ declare class RouterLocaleProvider { protected readonly alepha: Alepha; /** * Whether locale path-prefixing is active. Off by default — opt-in via the * i18n module. */ enabled: boolean; /** * The default locale, served without a path prefix (e.g. `"en"` → `/about`). */ defaultLocale: string; /** * All known locales, including the default one. */ locales: string[]; /** * Configure the provider. Called by the i18n module before the SSR routes * are registered. */ configure(options: { enabled?: boolean; defaultLocale?: string; locales?: string[]; }): void; /** * Locales that carry a URL prefix — every known locale except the default. */ get prefixedLocales(): string[]; /** * Splits a leading locale segment off a pathname. * * - `/fr/about` → `{ locale: "fr", pathname: "/about" }` when `fr` is a * prefixed locale. * - `/about` → `{ locale: defaultLocale, pathname: "/about" }`. * * When prefixing is disabled the pathname is returned untouched. */ detect(pathname: string): { locale: string; pathname: string; }; /** * Prepends the locale prefix to a pathname when needed. The default locale * (and any unknown/disabled case) returns the pathname unchanged. */ withPrefix(pathname: string, locale?: string): string; /** * The active locale, derived from the current request/navigation. Falls back * to the default locale when nothing has been detected. */ get current(): string; set current(locale: string); /** * Normalizes a stripped pathname so it always starts with a single slash and * carries no trailing slash (except the root `/`). */ protected normalize(pathname: string): string; } //#endregion //#region ../../src/react/router/providers/ReactPageProvider.d.ts declare const reactPageOptions: import("alepha").Atom<import("zod").ZodObject<{ strictMode: import("zod").ZodDefault<import("zod").ZodBoolean>; staticFilePattern: import("zod").ZodString; }, import("zod/v4/core").$strip>, "alepha.react.page.options">; /** * Handle page routes for React applications. (Browser and Server) */ declare class ReactPageProvider { protected readonly dateTimeProvider: DateTimeProvider; protected readonly log: import("alepha/logger").Logger; protected readonly options: Readonly<{ strictMode: boolean; staticFilePattern: string; }>; protected readonly alepha: Alepha; protected readonly rootComponentsProvider: RootComponentsProvider; protected readonly localeProvider: RouterLocaleProvider; protected readonly pages: PageRoute[]; protected nextIdCursor: number; protected readonly configure: import("alepha").HookPrimitive<"configure">; getPages(): PageRoute[]; getConcretePages(): ConcretePageRoute[]; page(name: string): PageRoute; /** * Find a route by name anywhere in the tree (including nested children). * Returns undefined if no page with that name exists. */ protected findRoute(name: string, routes?: PageRouteEntry[]): PageRoute | undefined; pathname(name: string, options?: { params?: Record<string, string>; query?: Record<string, string>; }): string; url(name: string, options?: { params?: Record<string, string>; host?: string; }): URL; root(state: ReactRouterState): ReactNode; protected convertStringObjectToObject: (schema?: TSchema, value?: any) => any; /** * Create a new RouterState based on a given route and request. * This method resolves the layers for the route, applying any query and params schemas defined in the route. * It also handles errors and redirects. */ createLayers(route: PageRoute, state: ReactRouterState, previous?: PreviousLayerData[]): Promise<CreateLayersResult>; protected getErrorHandler(route: PageRoute): ErrorHandler | undefined; protected createElement(page: PageRoute, props: Record<string, any>, targetUrl?: URL): Promise<ReactNode>; /** * Detect chunk load errors caused by stale dynamic imports after a deployment. * When new assets are deployed with different hashes, old chunk URLs return 404. */ protected isChunkLoadError(error: unknown): boolean; /** * Navigate to the target URL to fetch updated assets after a chunk load failure. * Uses sessionStorage to prevent infinite reload loops. * Returns true if navigation was initiated. */ protected reloadAfterChunkError(url?: URL): boolean; renderError(error: Error): ReactNode; renderEmptyView(): ReactNode; href(page: { options: { name?: string; }; }, params?: Record<string, any>): string; compile(path: string, params?: Record<string, string>): string; protected renderView(index: number, path: string, view: ReactNode | undefined, page: PageRoute): ReactNode; /** * Resolve the effective `ssr` value for a route by walking up the parent * chain. Returns the nearest explicit `ssr` value, defaulting to `true`. * * The decision is made at the leaf: a parent's `ssr` only acts as a default * for descendants that did not set their own value. */ isSSR(route: PageRoute): boolean; protected map(pages: Array<PagePrimitive>, target: PagePrimitive): PageRouteEntry; add(entry: PageRouteEntry): void; protected createMatch(page: PageRoute): string; protected nextId(): string; } declare const isPageRoute: (it: any) => it is PageRoute; interface PageRouteEntry extends Omit<PagePrimitiveOptions, "children" | "parent"> { children?: PageRouteEntry[]; } interface ConcretePageRoute extends PageRoute { /** * When exported, static routes can be split into multiple pages with different params. * We replace 'name' by the new name for each static entry, and old 'name' becomes 'staticName'. */ staticName?: string; params?: Record<string, string>; } interface PageRoute extends PageRouteEntry { type: "page"; name: string; parent?: PageRoute; match: string; /** * Optional meta information associated with the page route, can be used for any purpose (e.g. menu label, icon, etc.). */ label?: string; } interface Layer { config?: { query?: Record<string, any>; params?: Record<string, any>; context?: Record<string, any>; }; name: string; props?: Record<string, any>; error?: Error; part?: string; element: ReactNode; index: number; path: string; route?: PageRoute; cache?: boolean; } type PreviousLayerData = Omit<Layer, "element" | "index" | "path">; interface AnchorProps { href: string; onClick: (ev?: any) => any; } interface ReactRouterState { /** * Stack of layers for the current page. */ layers: Array<Layer>; /** * URL of the current page. */ url: URL; /** * Error handler for the current page. */ onError: ErrorHandler; /** * Params extracted from the URL for the current page. */ params: Record<string, any>; /** * Query parameters extracted from the URL for the current page. */ query: Record<string, string>; /** * Optional meta information associated with the current page. */ meta: Record<string, any>; /** * Head configuration for the current page (title, meta tags, etc.). * Populated by HeadProvider during SSR. */ head: Head; /** * Optional name of the current page route */ name?: string; } interface RouterStackItem { route: PageRoute; config?: Record<string, any>; props?: Record<string, any>; error?: Error; cache?: boolean; } interface CreateLayersResult { redirect?: string; state?: ReactRouterState; } //#endregion //#region ../../src/react/router/services/ReactPageService.d.ts /** * $page methods interface. */ declare abstract class ReactPageService { fetch(pathname: string, options?: PagePrimitiveRenderOptions): Promise<{ html: string; response: Response; }>; render(name: string, options?: PagePrimitiveRenderOptions): Promise<PagePrimitiveRenderResult>; } //#endregion //#region ../../src/react/router/primitives/$page.d.ts /** * Main primitive for defining a React route in the application. * * The $page primitive is the core building block for creating type-safe, SSR-enabled React routes. * It provides a declarative way to define pages with powerful features: * * **Routing & Navigation** * - URL pattern matching with parameters (e.g., `/users/:id`) * - Nested routing with parent-child relationships * - Type-safe URL parameter and query string validation * * **Data Loading** * - Server-side data fetching with the `loader` function * - Automatic serialization and hydration for SSR * - Access to request context, URL params, and parent data * * **Component Loading** * - Direct component rendering or lazy loading for code splitting * - Client-only rendering when browser APIs are needed * - Automatic fallback handling during hydration * * **Performance Optimization** * - Static generation for pre-rendered pages at build time * - Server-side caching with configurable TTL and providers * - Code splitting through lazy component loading * * **Error Handling** * - Custom error handlers with support for redirects * - Hierarchical error handling (child → parent) * - HTTP status code handling (404, 401, etc.) * * @example Simple page with data fetching * ```typescript * const userProfile = $page({ * path: "/users/:id", * schema: { * params: z.object({ id: z.integer() }), * query: z.object({ tab: z.text().optional() }) * }, * loader: async ({ params }) => { * const user = await userApi.getUser(params.id); * return { user }; * }, * lazy: () => import("./UserProfile.tsx") * }); * ``` * * @example Nested routing with error handling * ```typescript * const projectSection = $page({ * path: "/projects/:id", * children: () => [projectBoard, projectSettings], * loader: async ({ params }) => { * const project = await projectApi.get(params.id); * return { project }; * }, * errorHandler: (error) => { * if (HttpError.is(error, 404)) { * return <ProjectNotFound />; * } * } * }); * ``` * * @example Static generation with caching * ```typescript * const blogPost = $page({ * path: "/blog/:slug", * static: { * entries: posts.map(p => ({ params: { slug: p.slug } })) * }, * loader: async ({ params }) => { * const post = await loadPost(params.slug); * return { post }; * } * }); * ``` */ declare const $page: { <TConfig extends PageConfigSchema = PageConfigSchema, TProps extends object = any, TPropsParent extends object = TPropsParentDefault>(options: PagePrimitiveOptions<TConfig, TProps, TPropsParent>): PagePrimitive<TConfig, TProps, TPropsParent>; [KIND]: typeof PagePrimitive; }; interface PagePrimitiveOptions<TConfig extends PageConfigSchema = PageConfigSchema, TProps extends object = TPropsDefault, TPropsParent extends object = TPropsParentDefault> { /** * Identifier name for the page. Must be unique. * * @default Primitive key */ name?: string; /** * Add a pathname to the page. * * Pathname can contain parameters, like `/post/:slug`. * * @default "" */ path?: string; /** * Add an input schema to define: * - `params`: parameters from the pathname. * - `query`: query parameters from the URL. */ schema?: TConfig; /** * Middleware to apply to the loader function. * Works the same as `use` on `$action` and `$job`. * * @example * ```ts * dashboard = $page({ * use: [$cache({ ttl: [5, "minutes"] })], * loader: async ({ params }) => this.dashboardService.getData(), * lazy: () => import("./Dashboard.tsx"), * }); * ``` */ use?: Middleware[]; /** * Load data before rendering the page. * * This function receives * - the request context (params, query, etc.) * - the parent props (if page has a parent) * * > In SSR, the returned data will be serialized and sent to the client, then reused during the client-side hydration. * * Loader can be stopped by throwing an error, which will be handled by the `errorHandler` function. * It's common to throw a `NotFoundError` to display a 404 page. * * RedirectError can be thrown to redirect the user to another page. */ loader?: (context: PageLoader<TConfig, TPropsParent>) => Async<TProps>; /** * Default props to pass to the component when rendering the page. * * Resolved props from the `resolve` function will override these default props. */ props?: () => Partial<TProps>; /** * The component to render when the page is loaded. * * If `lazy` is defined, this will be ignored. * Prefer using `lazy` to improve the initial loading time. */ component?: FC<TProps & TPropsParent>; /** * Lazy load the component when the page is loaded. * * It's recommended to use this for components to improve the initial loading time * and enable code-splitting. */ lazy?: () => Promise<{ default: FC<TProps & TPropsParent>; }>; /** * Attach child pages to create nested routes, adopting them as children of * this page. * * Use this when you want a parent to own children it cannot modify — most * notably pages that come from an injected router in another package, whose * `$page` definitions are frozen and cannot declare `parent` themselves. * * ```ts * layout = $page({ * path: "/app", * children: () => [ * this.productRouter.catalogPage, // from $inject(ProductRouter) * this.productRouter.checkoutPage, * ], * }); * ``` * * Use a thunk (`() => [...]`) when the children are defined later in the * same class. * * **Declare each edge from one side only.** If a child already sets * `parent: thisPage`, do NOT also add it to `children` — the link is * already established, and declaring it on both sides creates a TypeScript * circular dependency between the two class fields (each references the * other before it is initialised). */ children?: Array<PagePrimitive> | (() => Array<PagePrimitive>); /** * Define a parent page for nested routing. * * Use this when you own the child page and can edit its definition — it is * the simplest way to nest routes and reads top-down. For pages you do NOT * own (e.g. pages exposed by an injected router from another package), let * the parent adopt them via its `children` option instead. * * **Declare each edge from one side only.** If you set `parent` here, do * NOT also add this page to the parent's `children` array — the link is * already established, and declaring it on both sides creates a TypeScript * circular dependency between the two class fields. */ parent?: PagePrimitive<PageConfigSchema, TPropsParent, any>; /** * UI-affordance predicate for this page's navigation entry — **NOT security**. * For real access control, gate the route with `use: [$secure({ permissions })]` * (server-enforced); `can` is only consulted by navigation surfaces (sidebar, * breadcrumbs, command palette), never by the router. * * Receives a `{ has }` context (a permission probe equivalent to * `useAuth().has`) so it can express arbitrary access logic — including * OR-of-permissions, which `nav.permission` (AND) cannot. * * - `true` (or omitted) → nav entry visible and enabled. * - `"disabled"` → visible but disabled (greyed — e.g. insufficient role / paywalled). * - `false` → hidden. * * For the common "needs these permissions" case, prefer the declarative * {@link PageNav.permission} instead. */ can?: (ctx: PageCanContext) => boolean | "disabled"; /** * Navigation metadata — declares this page's presence in navigation * surfaces: the sidebar, the breadcrumb trail, and a command palette * (Spotlight). A page WITHOUT `nav` is route-only (reachable by URL but not * listed). * * `$page` is pure React, so `label` / `icon` / `description` / `badge` accept * `ReactNode` (pass `<Users />` directly). * * Visibility is UI-only (NOT security — gate the route with `use: [$secure(...)]`): * an entry is hidden when `nav.hidden`, when `nav.permission` is set and not * fully granted, or when `can()` returns `false`; it renders disabled when * `can()` returns `"disabled"`. */ nav?: PageNav; /** * Catch any error from the `loader` function or during `rendering`. * * Expected to return one of the following: * - a ReactNode to render an error page * - a Redirection to redirect the user * - undefined to let the error propagate * * If not defined, the error will be thrown and handled by the server or client error handler. * If a leaf $page does not define an error handler, the error can be caught by parent pages. * * @example Catch a 404 from API and render a custom not found component: * ```ts * loader: async ({ params, query }) => { * api.fetch("/api/resource", { params, query }); * }, * errorHandler: (error, context) => { * if (HttpError.is(error, 404)) { * return <ResourceNotFound />; * } * } * ``` * * @example Catch an 401 error and redirect the user to the login page: * ```ts * loader: async ({ params, query }) => { * // but the user is not authenticated * api.fetch("/api/resource", { params, query }); * }, * errorHandler: (error, context) => { * if (HttpError.is(error, 401)) { * // throwing a Redirection is also valid! * return new Redirection("/login"); * } * } * ``` */ errorHandler?: ErrorHandler; /** * If true, the page will be considered as a static page, immutable and cacheable. * Replace boolean by an object to define static entries. (e.g. list of params/query) * * Browser-side: it only works with the build pipeline, which can pre-render the page at build time. * * Server-side: It will act as timeless cached page. You can use `cache` to configure the cache behavior. */ static?: boolean | { entries?: Array<Partial<PageRequestConfig<TConfig>>>; }; /** * Enable or disable server-side rendering for this page. * * - `true` (default): the page component is rendered on the server and * hydrated on the client. * - `false`: the loader still runs on the server (so data is preloaded and * serialized for hydration), but the component is rendered only on the * client. The server emits no HTML for this page. * * **Decided at the leaf, inherited as default by descendants.** * * The effective value is determined by the matched leaf page: walk up the * parent chain and use the nearest explicit `ssr` value. Setting * `ssr: false` on a parent therefore acts as the default for its children; * a child can override with `ssr: true`. * * Skipping rendering while keeping the loader is the recommended strategy * for CPU-constrained server environments (e.g. Cloudflare Workers) and * heavy admin/dashboard views where SSR provides little SEO value. * * @example * ```ts * root = $page({ ssr: false }); // default for children * home = $page({ parent: root, ssr: true }); // overrides → SSR * about = $page({ parent: root }); // inherits → no SSR * ``` * * @default true */ ssr?: boolean; /** * Called before the server response is sent to the client. (server only) */ onServerResponse?: (request: ServerRequest) => unknown; /** * Called when user enters the page. (browser only) * * Useful for browser-only side effects like analytics, scroll management, * or focus handling that don't need to return data to the component. * * @example * ```ts * onEnter: () => { * analytics.trackPageView("/dashboard"); * window.scrollTo(0, 0); * } * ``` */ onEnter?: () => void; /** * Called when user leaves the page. (browser only) */ onLeave?: () => void; /** * @experimental * * Add a css animation when the page is loaded or unloaded. * It uses CSS animations, so you need to define the keyframes in your CSS. * * @example Simple animation name * ```ts * animation: "fadeIn" * ``` * * CSS example: * ```css * @keyframes fadeIn { * from { opacity: 0; } * to { opacity: 1; } * } * ``` * * @example Detailed animation * ```ts * animation: { * enter: { name: "fadeIn", duration: 300 }, * exit: { name: "fadeOut", duration: 200, timing: "ease-in-out" }, * } * ``` * * @example Only exit animation * ```ts * animation: { * exit: "fadeOut" * } * ``` * * @example With custom timing function * ```ts * animation: { * enter: { name: "fadeIn", duration: 300, timing: "cubic-bezier(0.4, 0, 0.2, 1)" }, * exit: { name: "fadeOut", duration: 200, timing: "ease-in-out" }, * } * ``` */ animation?: PageAnimation; /** * Head configuration for the page (title, meta tags, etc.). * * Can be a static object or a function that receives resolved props. * * @example Static head * ```ts * head: { * title: "My Page", * description: "Page description", * } * ``` * * @example Dynamic head based on props * ```ts * head: (props) => ({ * title: props.user.name, * description: `Profile of ${props.user.name}`, * }) * ``` */ head?: Head | ((props: TProps, previous?: Head) => Head); /** * Redirect to another path when this page is matched. * * This is a shorthand for throwing a `Redirection` in the loader. * The redirect is performed before any loader or component rendering. * * @example * ```ts * home = $page({ * path: "/", * redirect: "/dashboard", * }); * ``` */ redirect?: string; /** * Label for the page, used for navigation menus or breadcrumbs. * * This is optional and can be used by the application to display a user-friendly name for the page. * It has no functional impact on routing or rendering. */ label?: string; /** * Source path for SSR module preloading. * * This is automatically injected by the viteAlephaPreload plugin. * It maps to the source file path used in Vite's SSR manifest. * * @internal */ [PAGE_PRELOAD_KEY]?: string; } declare class PagePrimitive<TConfig extends PageConfigSchema = PageConfigSchema, TProps extends object = TPropsDefault, TPropsParent extends object = TPropsParentDefault> extends Primitive<PagePrimitiveOptions<TConfig, TProps, TPropsParent>> { protected readonly reactPageService: ReactPageService; protected onInit(): void; get name(): string; /** * For testing or build purposes. * * This will render the page (HTML layout included or not) and return the HTML + context. * Only valid for server-side rendering, it will throw an error if called on the client-side. */ render(options?: PagePrimitiveRenderOptions): Promise<PagePrimitiveRenderResult>; fetch(options?: PagePrimitiveRenderOptions): Promise<{ html: string; response: Response; }>; } /** * Context passed to {@link PagePrimitiveOptions.can} — a permission probe * (equivalent to `useAuth().has`) supplied by the navigation builder. */ interface PageCanContext { has: (permission: string) => boolean; } /** * Navigation metadata for a page — see {@link PagePrimitiveOptions.nav}. * Consumed by the sidebar, breadcrumbs and the command palette, all derived * from the route tree (no separate nav list). */ interface PageNav { /** * Label for nav surfaces. Falls back to the page's `label`, then `head.title`. */ label?: ReactNode; /** * Leading icon — a React element, e.g. `icon: <Users />`. */ icon?: ReactNode; /** * Section the entry belongs to: sidebar group heading + command-palette section. */ group?: string; /** * Sort order within the group (ascending). */ order?: number; /** * Permission(s) required to SEE the entry — a single string or an array * (ALL required, matching `$secure({ permissions })`). UI gate only; the * real route gate is `use: [$secure(...)]`. For OR / custom logic use `can`. */ permission?: string | string[]; /** * Extra search terms for the command palette (synonyms / aliases beyond the label). */ keywords?: string[]; /** * Short description — command-palette subtitle / sidebar tooltip. */ description?: ReactNode; /** * Trailing badge (unread count, "New", …) for the sidebar entry. */ badge?: ReactNode; /** * Keep the route but exclude it from nav surfaces (e.g. a `/users/:id` detail page). */ hidden?: boolean; } type ErrorHandler = (error: Error, state: ReactRouterState) => ReactNode | Redirection | undefined; interface PageConfigSchema { query?: TSchema; params?: TSchema; } type TPropsDefault = any; type TPropsParentDefault = {}; interface PagePrimitiveRenderOptions { params?: Record<string, string>; query?: Record<string, string>; /** * If true, the HTML layout will be included in the response. * If false, only the page content will be returned. * * @default true */ html?: boolean; hydration?: boolean; } interface PagePrimitiveRenderResult { html: string; state: ReactRouterState; redirect?: string; } interface PageRequestConfig<TConfig extends PageConfigSchema = PageConfigSchema> { params: TConfig["params"] extends TSchema ? Static<TConfig["params"]> : Record<string, string>; query: TConfig["query"] extends TSchema ? Static<TConfig["query"]> : Record<string, string>; } type PageLoader<TConfig extends PageConfigSchema = PageConfigSchema, TPropsParent extends object = TPropsParentDefault> = PageRequestConfig<TConfig> & TPropsParent & Omit<ReactRouterState, "layers" | "onError">; type PageAnimation = PageAnimationObject | ((state: ReactRouterState) => PageAnimationObject | undefined); type PageAnimationObject = CssAnimationName | { enter?: CssAnimation | CssAnimationName; exit?: CssAnimation | CssAnimationName; }; type CssAnimationName = string; type CssAnimation = { name: string; duration?: number; timing?: string; }; //#endregion //#region ../../src/react/router/services/ReactRouter.d.ts interface RouterPushOptions { replace?: boolean; params?: Record<string, string>; query?: Record<string, string>; meta?: Record<string, any>; /** * Recreate the whole page, ignoring the current state. */ force?: boolean; } /** * Friendly browser router API. * * Can be safely used server-side, but most methods will be no-op. */ declare class ReactRouter<T extends object> { protected readonly alepha: Alepha; protected readonly pageApi: ReactPageProvider; get state(): ReactRouterState; get pages(): import("alepha/react/router").PageRoute[]; get concretePages(): import("alepha/react/router").ConcretePageRoute[]; get browser(): ReactBrowserProvider | undefined; isActive(href: string, options?: { startWith?: boolean; }): boolean; node(name: keyof VirtualRouter<T> | string, config?: { params?: Record<string, any>; query?: Record<string, any>; }): any; path(name: keyof VirtualRouter<T> | string, config?: { params?: Record<string, any>; query?: Record<string, any>; }): string; /** * Reload the current page. * This is equivalent to calling `go()` with the current pathname and search. */ reload(): Promise<void>; getURL(): URL; get location(): Location; get current(): ReactRouterState; get pathname(): string; get query(): Record<string, string>; back(): Promise<void>; forward(): Promise<void>; invalidate(props?: Record<string, any>): Promise<void>; push(path: string, options?: RouterPushOptions): Promise<void>; push(path: keyof VirtualRouter<T>, options?: RouterPushOptions): Promise<void>; anchor(path: string, options?: RouterPushOptions): AnchorProps; anchor(path: keyof VirtualRouter<T>, options?: RouterPushOptions): AnchorProps; /** * Prepend the base URL to the given path. */ base(path: string): string; /** * Set query params. * * @param record * @param options */ setQueryParams(record: Record<string, any> | ((queryParams: Record<string, any>) => Record<string, any>), options?: { /** * If true, this will add a new entry to the history stack. */ push?: boolean; }): void; } type VirtualRouter<T> = { [K in keyof T as T[K] extends PagePrimitive ? K : never]: T[K]; }; //#endregion //#region ../../src/react/router/providers/ReactBrowserRouterProvider.d.ts interface BrowserRoute extends Route { page: PageRoute; } /** * Implementation of AlephaRouter for React in browser environment. */ declare class ReactBrowserRouterProvider extends RouterProvider<BrowserRoute> { protected readonly log: import("alepha/logger").Logger; protected readonly alepha: Alepha; protected readonly pageApi: ReactPageProvider; protected readonly browserHeadProvider: BrowserHeadProvider; protected readonly localeProvider: RouterLocaleProvider; add(entry: PageRouteEntry): void; protected readonly configure: import("alepha").HookPrimitive<"configure">; transition(url: URL, previous?: PreviousLayerData[], meta?: {}, isStale?: () => boolean): Promise<string | undefined>; root(state: ReactRouterState): ReactNode; } //#endregion //#region ../../src/react/router/providers/ReactBrowserProvider.d.ts /** * React browser renderer configuration atom */ declare const reactBrowserOptions: import("alepha").Atom<import("zod").ZodObject<{ scrollRestoration: import("zod").ZodEnum<{ manual: "manual"; top: "top"; }>; interceptAnchorClicks: import("zod").ZodDefault<import("zod").ZodBoolean>; }, import("zod/v4/core").$strip>, "alepha.react.browser.options">; type ReactBrowserRendererOptions = Static<typeof reactBrowserOptions.schema>; declare module "alepha" { interface State { [reactBrowserOptions.key]: ReactBrowserRendererOptions; } } declare class ReactBrowserProvider { protected readonly log: import("alepha/logger").Logger; protected readonly client: LinkProvider; protected readonly alepha: Alepha; protected readonly router: ReactBrowserRouterProvider; protected readonly dateTimeProvider: DateTimeProvider; protected readonly browserHeadProvider: BrowserHeadProvider; protected readonly validator: SchemaValidator; protected readonly options: Readonly<{ scrollRestoration: "manual" | "top"; interceptAnchorClicks: boolean; }>; get rootId(): string; protected getRootElement(): HTMLElement; transitioning?: { to: string; from?: string; }; /** * Monotonic counter used to detect stale (superseded) transitions. * * Each call to `render()` captures `++this.transitionId` and any * subsequent `render()` invalidates older in-flight transitions. * This prevents a slow page from racing past a newer navigation * (e.g. user clicks /pageA which has a 2s loader, then clicks /pageB * — pageB must remain the committed page). */ protected transitionId: number; get state(): ReactRouterState; /** * Accessor for Document DOM API. */ get document(): Document; /** * Accessor for History DOM API. */ get history(): History; /** * Accessor for Location DOM API. */ get location(): Location; get base(): string; get url(): string; pushState(path: string, replace?: boolean): void; invalidate(props?: Record<string, any>): Promise<void>; push(url: string, options?: RouterPushOptions): Promise<void>; protected render(options?: RouterRenderOptions): Promise<void>; /** * Get embedded layers from the server. */ protected getHydrationState(): ReactHydrationState | undefined; /** * Apply the SSR hydration payload (the `#__ssr` script tag) to the atom * store. * * Every key except `alepha.react.router.layers` is treated as an atom * value. A registered atom's value is explicitly schema-validated: an * invalid value is dropped (warn + keep the atom's default) instead of * being trusted, so a tampered payload can't smuggle bad data into a * validated atom. Atoms not registered yet fall through to * `Alepha.set()`, which lets `StateManager.register()` decode them * against the schema the moment they first get used. * * `alepha.react.router.layers` is deliberately skipped by this loop: it * carries render instructions (`part`, `name`, `config`, `props`, * `error`), not atom values. Those are NOT hardened here and are trusted * as-is from the SSR payload — a tampered payload can still influence * rendering through this key. Validating router layers is separate, * future work; this method only guarantees atom values. */ protected applyHydration(hydration: ReactHydrationState): void; protected readonly onTransitionEnd: import("alepha").HookPrimitive<"react:transition:end">; readonly ready: import("alepha").HookPrimitive<"ready">; /** * Attach a delegated click listener that routes plain `<a href="/...">` * clicks through the SPA router. Returns a detach function (used in tests). * * Bails out on modifier keys, non-primary mouse buttons, `target`, `download`, * `data-no-router`, hash-only/external/non-http hrefs, and already-prevented * events. Honors the runtime `interceptAnchorClicks` flag. */ protected attachAnchorInterceptor(): () => void; protected stripBase(path: string): string; } type ReactHydrationState = { "alepha.react.router.layers"?: Array<PreviousLayerData>; } & { [key: string]: any; }; interface RouterRenderOptions { url?: string; previous?: PreviousLayerData[]; meta?: Record<string, any>; /** * Transition id used to detect supersession by a newer navigation. * When omitted, render() allocates a fresh id internally. */ transitionId?: number; } //#endregion //#region ../../src/react/router/components/ErrorViewer.d.ts interface ErrorViewerProps { error: Error; alepha: Alepha; onRetry?: () => void; } declare const ErrorViewer: (props: ErrorViewerProps) => import("react").JSX.Element; //#endregion //#region ../../src/react/router/components/Link.d.ts interface LinkProps extends AnchorHTMLAttributes<HTMLAnchorElement> { href: string; } /** * Link component for client-side navigation. * * It's a simple wrapper around an anchor (`<a>`) element using the `useRouter` hook. */ declare const Link: (props: LinkProps) => import("react").DetailedReactHTMLElement<{ children?: import("react").ReactNode | undefined; dangerouslySetInnerHTML?: { __html: string | TrustedHTML; } | undefined; onCopy?: import("react").ClipboardEventHandler<HTMLAnchorElement> | undefined; onCopyCapture?: import("react").ClipboardEventHandler<HTMLAnchorElement> | undefined; onCut?: import("react").ClipboardEventHandler<HTMLAnchorElement> | undefined; onCutCapture?: import("react").ClipboardEventHandler<HTMLAnchorElement> | undefined; onPaste?: import("react").ClipboardEventHandler<HTMLAnchorElement> | undefined; onPasteCapture?: import("react").ClipboardEventHandler<HTMLAnchorElement> | undefined; onCompositionEnd?: import("react").CompositionEventHandler<HTMLAnchorElement> | undefined; onCompositionEndCapture?: import("react").CompositionEventHandler<HTMLAnchorElement> | undefined; onCompositionStart?: import("react").CompositionEventHandler<HTMLAnchorElement> | undefined; onCompositionStartCapture?: import("react").CompositionEventHandler<HTMLAnchorElement> | undefined; onCompositionUpdate?: import("react").CompositionEventHandler<HTMLAnchorElement> | undefined; onCompositionUpdateCapture?: import("react").CompositionEventHandler<HTMLAnchorElement> | undefined; onFocus?: import("react").FocusEventHandler<HTMLAnchorElement> | undefined; onFocusCapture?: import("react").FocusEventHandler<HTMLAnchorElement> | undefined; onBlur?: import("react").FocusEventHandler<HTMLAnchorElement> | undefined; onBlurCapture?: import("react").FocusEventHandler<HTMLAnchorElement> | undefined; onChange?: import("react").ChangeEventHandler<HTMLAnchorElement, Element> | undefined; onChangeCapture?: import("react").ChangeEventHandler<HTMLAnchorElement, Element> | undefined; onBeforeInput?: import("react").InputEventHandler<HTMLAnchorElement> | undefined; onBeforeInputCapture?: import("react").InputEventHandler<HTMLAnchorElement> | undefined; onInput?: import("react").InputEventHandler<HTMLAnchorElement> | undefined; onInputCapture?: import("react").InputEventHandler<HTMLAnchorElement> | undefined; onReset?: import("react").ReactEventHandler<HTMLAnchorElement> | undefined; onResetCapture?: import("react").ReactEventHandler<HTMLAnchorElement> | undefined; onSubmit?: import("react").SubmitEventHandler<HTMLAnchorElement> | undefined; onSubmitCapture?: import("react").SubmitEventHandler<HTMLAnchorElement> | undefined; onInvalid?: import("react").ReactEventHandler<HTMLAnchorElement> | undefined; onInvalidCapture?: import("react").ReactEventHandler<HTMLAnchorElement> | undefined; onLoad?: import("react").ReactEventHandler<HTMLAnchorElement> | undefined; onLoadCapture?: import("react").ReactEventHandler<HTMLAnchorElement> | undefined; onError?: import("react").ReactEventHandler<HTMLAnchorElement> | undefined; onErrorCapture?: import("react").ReactEventHandler<HTMLAnchorElement> | undefined; onKeyDown?: import("react").KeyboardEventHandler<HTMLAnchorElement> | undefined; onKeyDownCapture?: import("react").KeyboardEventHandler<HTMLAnchorElement> | undefined; onKeyPress?: import("react").KeyboardEventHandler<HTMLAnchorElement> | undefined; onKeyPressCapture?: import("react").KeyboardEventHandler<HTMLAnchorElement> | undefined; onKeyUp?: import("react").KeyboardEventHandler<HTMLAnchorElement> | undefined; onKeyUpCapture?: import("react").KeyboardEventHandler<HTMLAnchorElement> | undefined; onAbort?: import("react").ReactEventHandler<HTMLAnchorElement> | undefined; onAbortCapture?: import("react").ReactEventHandler<HTMLAnchorElement> | undefined; onCanPlay?: import("react").ReactEventHandler<HTMLAnchorElement> | undefined; onCanPlayCapture?: import("react").ReactEventHandler<HTMLAnchorElement> | undefined; onCanPlayThrough?: import("react").ReactEventHandler<HTMLAnchorElement> | undefined; onCanPlayThroughCapture?: import("react").ReactEventHandler<HTMLAnchorElement> | undefined; onDurationChange?: import("react").ReactEventHandler<HTMLAnchorElement> | undefined; onDurationChangeCapture?: import("react").ReactEventHandler<HTMLAnchorElement> | undefined; onEmptied?: import("react").ReactEventHandler<HTMLAnchorElement> | undefined; onEmptiedCapture?: import("react").ReactEventHandler<HTMLAnchorElement> | undefined; onEncrypted?: import("react").ReactEventHandler<HTMLAnchorElement> | undefined; onEncryptedCapture?: import("react").ReactEventHandler<HTMLAnchorElement> | undefined; onEnded?: import("react").ReactEventHandler<HTMLAnchorElement> | undefined; onEndedCapture?: import("react").ReactEventHandler<HTMLAnchorElement> | undefined; onLoadedData?: import("react").ReactEventHandler<HTMLAnchorElement> | undefined; onLoadedDataCapture?: import("react").ReactEventHandler<HTMLAnchorElement> | undefined; onLoadedMetadata?: import("react").ReactEventHandler<HTMLAnchorElement> | undefined; onLoadedMetadataCapture?: import("react").ReactEventHandler<HTMLAnchorElement> | undefined; onLoadStart?: import("react").ReactEventHandler<HTMLAnchorElement> | undefined; onLoadStartCapture?: import("react").ReactEventHandler<HTMLAnchorElement> | undefined; onPause?: import("react").ReactEventHandler<HTMLAnchorElement> | undefined; onPauseCapture?: import("react").ReactEventHandler<HTMLAnchorElement> | undefined; onPlay?: import("react").ReactEventHandler<HTMLAnchorElement> | undefined; onPlayCapture?: import("react").ReactEventHandler<HTMLAnchorElement> | undefined; onPlaying?: import("react").ReactEventHandler<HTMLAnchorElement> | undefined; onPlayingCapture?: import("react").ReactEventHandler<HTMLAnchorElement> | undefined; onProgress?: import("react").ReactEventHandler<HTMLAnchorElement> | undefined; onProgressCapture?: import("react").ReactEventHandler<HTMLAnchorElement> | undefined; onRateChange?: import("react").ReactEventHandler<HTMLAnchorElement> | undefined; onRateChangeCapture?: import("react").ReactEventHandler<HTMLAnchorElement> | undefined; onSeeked?: import("react").ReactEventHandler<HTMLAnchorElement> | undefined; onSeekedCapture?: import("react").ReactEventHandler<HTMLAnchorElement> | undefined; onSeeking?: import("react").ReactEventHandler<HTMLAnchorElement> | undefined; onSeekingCapture?: import("react").ReactEventHandler<HTMLAnchorElement> | undefined; onStalled?: import("react").ReactEventHandler<HTMLAnchorElement> | undefined; onStalledCapture?: import("react").ReactEventHandler<HTMLAnchorElement> | undefined; onSuspend?: import("react").ReactEventHandler<HTMLAnchorElement> | undefined; onSuspendCapture?: import("react").ReactEventHandler<HTMLAnchorElement> | undefined; onTimeUpdate?: import("react").ReactEventHandler<HTMLAnchorElement> | undefined; onTimeUpdateCapture?: import("react").ReactEventHandler<HTMLAnchorElement> | undefined; onVolumeChange?: import("react").ReactEventHandler<HTMLAnchorElement> | undefined; onVolumeChangeCapture?: import("react").ReactEventHandler<HTMLAnchorElement> | undefined; onWaiting?: import("react").ReactEventHandler<HTMLAnchorElement> | undefined; onWaitingCapture?: import("react").ReactEventHandler<HTMLAnchorElement> | undefined; onAuxClick?: import("react").MouseEventHandler<HTMLAnchorElement> | undefined; onAuxClickCapture?: import("react").MouseEventHandler<HTMLAnchorElement> | undefined; onClickCapture?: import("react").MouseEventHandler<HTMLAnchorElement> | undefined; onContextMenu?: import("react").MouseEventHandler<HTMLAnchorElement> | undefined; onContextMenuCapture?: import("react").MouseEventHandler<HTMLAnchorElement> | undefined; onDoubleClick?: import("react").MouseEventHandler<HTMLAnchorElement> | undefined; onDoubleClickCapture?: import("react").MouseEventHandler<HTMLAnchorElement> | undefined; onDrag?: import("react").DragEventHandler<HTMLAnchorElement> | undefined; onDragCapture?: import("react").DragEventHandler<HTMLAnchorElement> | undefined; onDragEnd?: import("react").DragEventHandler<HTMLAnchorElement> | undefined; onDragEndCapture?: import("react").DragEventHandler<HTMLAnchorElement> | undefined; onDragEnter?: import("react").DragEventHandler<HTMLAnchorElement> | undefined; onDragEnterCapture?: import("react").DragEventHandler<HTMLAnchorElement> | undefined; onDragExit?: import("react").DragEventHandler<HTMLAnchorElement> | undefined; onDragExitCapture?: import("react").DragEventHandler<HTMLAnchorElement> | undefined; onDragLeave?: import("react").DragEventHandler<HTMLAnchorElement> | undefined; onDragLeaveCapture?: import("react").DragEventHandler<HTMLAnchorElement> | undefined; onDragOver?: import("react").DragEventHandler<HTMLAnchorElement> | undefined; onDragOverCapture?: import("react").DragEventHandler<HTMLAnchorElement> | undefined; onDragStart?: import("react").DragEventHandler<HTMLAnchorElement> | undefined; onDragStartCapture?: import("react").DragEventHandler<HTMLAnchorElement> | undefined; onDrop?: import("react").DragEventHandler<HTMLAnchorElement> | undefined; onDropCapture?: import("react").DragEventHandler<HTMLAnchorElement> | undefined; onMouseDown?: import("react").MouseEventHandler<HTMLAnchorElement> | undefined; onMouseDownCapture?: import("react").MouseEventHandler<HTMLAnchorElement> | undefined; onMouseEnter?: import("react").MouseEventHandler<HTMLAnchorElement> | undefined; onMouseLeave?: import("react").MouseEventHandler<HTMLAnchorElement> | undefined; onMouseMove?: import("react").MouseEventHandler<HTMLAnchorElement> | undefined; onMouseMoveCapture?: import("react").MouseEventHandler<HTMLAnchorElement> | undefined; onMouseOut?: import("react").MouseEventHandler<HTMLAnchorElement> | undefined; onMouseOutCapture?: import("react").MouseEventHandler<HTMLAnchorElement> | undefined; onMouseOver?: import("react").MouseEventHandler<HTMLAnchorElement> | undefined; onMouseOverCapture?: import("react").MouseEventHandler<HTMLAnchorElement> | undefined; onMouseUp?: import("react").MouseEventHandler<HTMLAnchorElement> | undefined; onMouseUpCapture?: import("react").MouseEventHandler<HTMLAnchorElement> | undefined; onSelect?: import("react").ReactEventHandler<HTMLAnchorElement> | undefined; onSelectCapture?: import("react").ReactEventHandler<HTMLAnchorElement> | undefined; onTouchCancel?: import("react").TouchEventHandler<HTMLAnchorElement> | undefined; onTouchCancelCapture?: import("react").TouchEventHandler<HTMLAnchorElement> | undefined; onTouchEnd?: import("react").TouchEventHandler<HTMLAnchorElement> | undefined; onTouchEndCapture?: import("react").TouchEventHandler<HTMLAnchorElement> | undefined; onTouchMove?: import("react").TouchEventHandler<HTMLAnchorElement> | undefined; onTouchMoveCapture?: import("react").TouchEventHandler<HTMLAnchorElement> | undefined; onTouchStart?: import("react").TouchEventHandler<HTMLAnchorElement> | undefined; onTouchStartCapture?: import("react").TouchEventHandler<HTMLAnchorElement> | undefined; onPointerDown?: import("react").PointerEventHandler<HTMLAnchorElement> | undefined; onPointerDownCapture?: import("react").PointerEventHandler<HTMLAnchorElement> | undefined; onPointerMove?: import("react").PointerEventHandler<HTMLAnchorElement> | undefined; onPointerMoveCapture?: import("react").PointerEventHandler<HTMLAnchorElement> | undefined; onPointerUp?: import("react").PointerEventHandler<HTMLAnchorElement> | undefined; onPointerUpCapture?: import("react").PointerEventHandler<HTMLAnchorElement> | undefined; onPointerCancel?: import("react").PointerEventHandler<HTMLAnchorElement> | undefined; onPointerCancelCapture?: import("react").PointerEventHandler<HTMLAnchorElement> | undefined; onPointerEnter?: import("react").PointerEventHandler<HTMLAnchorElement> | undefined; onPointerLeave?: import("react").PointerEventHandler<HTMLAnchorElement> | undefined; onPointerOver?: import("react").PointerEventHandler<HTMLAnchorElement> | undefined; onPointerOverCapture?: import("react").PointerEventHandler<HTMLAnchorElement> | undefined; onPointerOut?: import("react").PointerEventHandler<HTMLAnchorElement> | undefined; onPointerOutCapture?: import("react").PointerEventHandler<HTMLAnchorElement> | undefined; onGotPointerCapture?: import("react").PointerEventHandler<HTMLAnchorElement> | undefined; onGotPointerCaptureCapture?: import("react").PointerEventHandler<HTMLAnchorElement> | undefined; onLostPointerCapture?: import("react").PointerEventHandler<HTMLAnchorElement> | undefined; onLostPointerCaptureCapture?: import("react").PointerEventHandler<HTMLAnchorElement> | undefined; onScroll?: import("react").UIEventHandler<HTMLAnchorElement> | undefined; onScrollCapture?: import("react").UIEventHandler<HTMLAnchorElement> | undefined; onScrollEnd?: import("react").UIEventHandler