@alepha/react 0.7.0 → 0.7.2

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.
Files changed (37) hide show
  1. package/README.md +1 -1
  2. package/dist/index.browser.cjs +59 -22
  3. package/dist/index.browser.js +42 -6
  4. package/dist/index.cjs +152 -85
  5. package/dist/index.d.ts +317 -206
  6. package/dist/index.js +130 -64
  7. package/dist/{useActive-DjpZBEuB.cjs → useRouterState-C2uo0jXu.cjs} +319 -140
  8. package/dist/{useActive-BX41CqY8.js → useRouterState-D5__ZcUV.js} +321 -143
  9. package/package.json +11 -10
  10. package/src/components/ClientOnly.tsx +35 -0
  11. package/src/components/ErrorBoundary.tsx +1 -1
  12. package/src/components/ErrorViewer.tsx +161 -0
  13. package/src/components/Link.tsx +9 -3
  14. package/src/components/NestedView.tsx +18 -3
  15. package/src/components/NotFound.tsx +30 -0
  16. package/src/descriptors/$page.ts +141 -30
  17. package/src/errors/RedirectionError.ts +4 -1
  18. package/src/hooks/RouterHookApi.ts +42 -24
  19. package/src/hooks/useAlepha.ts +12 -0
  20. package/src/hooks/useClient.ts +8 -6
  21. package/src/hooks/useInject.ts +2 -2
  22. package/src/hooks/useQueryParams.ts +1 -1
  23. package/src/hooks/useRouter.ts +6 -0
  24. package/src/index.browser.ts +4 -2
  25. package/src/index.shared.ts +11 -5
  26. package/src/index.ts +3 -4
  27. package/src/providers/BrowserRouterProvider.ts +4 -3
  28. package/src/providers/PageDescriptorProvider.ts +91 -20
  29. package/src/providers/ReactBrowserProvider.ts +6 -59
  30. package/src/providers/ReactBrowserRenderer.ts +72 -0
  31. package/src/providers/ReactServerProvider.ts +200 -81
  32. package/dist/index.browser.cjs.map +0 -1
  33. package/dist/index.browser.js.map +0 -1
  34. package/dist/index.cjs.map +0 -1
  35. package/dist/index.js.map +0 -1
  36. package/dist/useActive-BX41CqY8.js.map +0 -1
  37. package/dist/useActive-DjpZBEuB.cjs.map +0 -1
package/dist/index.d.ts CHANGED
@@ -1,9 +1,8 @@
1
1
  import * as _alepha_core from '@alepha/core';
2
- import { Alepha, Static as Static$1, TSchema as TSchema$1, KIND, OPTIONS, Async, Class, TObject as TObject$1 } from '@alepha/core';
3
- import * as _alepha_server from '@alepha/server';
4
- import { HttpClientLink, HttpClient, ApiLinksResponse, ServerRouterProvider, ServerHandler, ServerRequest } from '@alepha/server';
2
+ import { TSchema as TSchema$1, KIND, OPTIONS, Static as Static$1, Async, Alepha, Service, TObject as TObject$1 } from '@alepha/core';
3
+ import { ServerRoute, ServerRequest, ApiLinksResponse, HttpClient, ClientScope, HttpVirtualClient, ServerRouterProvider, ServerTimingProvider, ServerHandler } from '@alepha/server';
5
4
  import * as React from 'react';
6
- import React__default, { ReactNode, FC, AnchorHTMLAttributes, PropsWithChildren, ErrorInfo } from 'react';
5
+ import React__default, { PropsWithChildren, ReactNode, FC, ErrorInfo, AnchorHTMLAttributes } from 'react';
7
6
  import { Root } from 'react-dom/client';
8
7
  import { RouterProvider, Route } from '@alepha/router';
9
8
  import * as react_jsx_runtime from 'react/jsx-runtime';
@@ -126,215 +125,138 @@ interface TSchema extends TKind, SchemaOptions {
126
125
  static: unknown;
127
126
  }
128
127
 
129
- interface Head$1 {
130
- title?: string;
131
- htmlAttributes?: Record<string, string>;
132
- bodyAttributes?: Record<string, string>;
133
- meta?: Array<{
134
- name: string;
135
- content: string;
136
- }>;
137
- }
138
- declare class ServerHeadProvider {
139
- renderHead(template: string, head: Head$1): string;
140
- mergeAttributes(existing: string, attrs: Record<string, string>): string;
141
- parseAttributes(attrStr: string): Record<string, string>;
142
- escapeHtml(str: string): string;
143
- }
144
-
145
- declare class BrowserHeadProvider {
146
- renderHead(document: Document, head: Head$1): void;
147
- }
148
-
149
- interface BrowserRoute extends Route {
150
- page: PageRoute;
151
- }
152
- declare class BrowserRouterProvider extends RouterProvider<BrowserRoute> {
153
- protected readonly log: _alepha_core.Logger;
154
- protected readonly alepha: Alepha;
155
- protected readonly pageDescriptorProvider: PageDescriptorProvider;
156
- add(entry: PageRouteEntry): void;
157
- protected readonly configure: _alepha_core.HookDescriptor<"configure">;
158
- transition(url: URL, options?: TransitionOptions): Promise<RouterRenderResult>;
159
- root(state: RouterState, context: PageReactContext): ReactNode;
128
+ interface ClientOnlyProps {
129
+ fallback?: ReactNode;
130
+ disabled?: boolean;
160
131
  }
132
+ /**
133
+ * A small utility component that renders its children only on the client side.
134
+ *
135
+ * Optionally, you can provide a fallback React node that will be rendered.
136
+ *
137
+ * You should use this component when
138
+ * - you have code that relies on browser-specific APIs
139
+ * - you want to avoid server-side rendering for a specific part of your application
140
+ * - you want to prevent pre-rendering of a component
141
+ */
142
+ declare const ClientOnly: (props: PropsWithChildren<ClientOnlyProps>) => ReactNode;
161
143
 
162
- declare const envSchema$1: _alepha_core.TObject<{
163
- REACT_ROOT_ID: TString;
164
- }>;
165
- declare module "@alepha/core" {
166
- interface Env extends Partial<Static$1<typeof envSchema$1>> {
167
- }
144
+ declare const KEY = "PAGE";
145
+ interface PageConfigSchema {
146
+ query?: TSchema$1;
147
+ params?: TSchema$1;
168
148
  }
169
- declare class ReactBrowserProvider {
170
- protected readonly log: _alepha_core.Logger;
171
- protected readonly client: HttpClient;
172
- protected readonly alepha: Alepha;
173
- protected readonly router: BrowserRouterProvider;
174
- protected readonly headProvider: BrowserHeadProvider;
175
- protected readonly env: {
176
- REACT_ROOT_ID: string;
177
- };
178
- protected root: Root;
179
- transitioning?: {
180
- to: string;
181
- };
182
- state: RouterState;
183
- get document(): Document;
184
- get history(): History;
185
- get url(): string;
186
- invalidate(props?: Record<string, any>): Promise<void>;
149
+ type TPropsDefault = any;
150
+ type TPropsParentDefault = {};
151
+ interface PageDescriptorOptions<TConfig extends PageConfigSchema = PageConfigSchema, TProps extends object = TPropsDefault, TPropsParent extends object = TPropsParentDefault> extends Pick<ServerRoute, "cache"> {
187
152
  /**
153
+ * Name your page.
188
154
  *
189
- * @param url
190
- * @param options
155
+ * @default Descriptor key
191
156
  */
192
- go(url: string, options?: RouterGoOptions): Promise<void>;
193
- protected render(options?: {
194
- url?: string;
195
- previous?: PreviousLayerData[];
196
- }): Promise<RouterRenderResult>;
157
+ name?: string;
197
158
  /**
198
- * Get embedded layers from the server.
199
- *
200
- * @protected
159
+ * Optional description of the page.
201
160
  */
202
- protected getHydrationState(): ReactHydrationState | undefined;
161
+ description?: string;
203
162
  /**
163
+ * Add a pathname to the page.
204
164
  *
205
- * @protected
206
- */
207
- protected getRootElement(): HTMLElement;
208
- /**
165
+ * Pathname can contain parameters, like `/post/:slug`.
209
166
  *
210
- * @protected
167
+ * @default ""
211
168
  */
212
- readonly ready: _alepha_core.HookDescriptor<"ready">;
213
- readonly onTransitionEnd: _alepha_core.HookDescriptor<"react:transition:end">;
214
- }
215
- interface RouterGoOptions {
216
- replace?: boolean;
217
- match?: TransitionOptions;
218
- params?: Record<string, string>;
219
- }
220
- interface ReactHydrationState {
221
- layers?: PreviousLayerData[];
222
- links?: HttpClientLink[];
223
- }
224
-
225
- declare class RouterHookApi {
226
- private readonly state;
227
- private readonly layer;
228
- private readonly browser?;
229
- constructor(state: RouterState, layer: {
230
- path: string;
231
- }, browser?: ReactBrowserProvider | undefined);
169
+ path?: string;
232
170
  /**
233
- *
171
+ * Add an input schema to define:
172
+ * - `params`: parameters from the pathname.
173
+ * - `query`: query parameters from the URL.
234
174
  */
235
- get current(): RouterState;
175
+ schema?: TConfig;
236
176
  /**
177
+ * Load data before rendering the page.
237
178
  *
238
- */
239
- get pathname(): string;
240
- /**
179
+ * This function receives
180
+ * - the request context and
181
+ * - the parent props (if page has a parent)
241
182
  *
242
- */
243
- get query(): Record<string, string>;
244
- /**
183
+ * In SSR, the returned data will be serialized and sent to the client, then reused during the client-side hydration.
245
184
  *
246
- */
247
- back(): Promise<void>;
248
- /**
185
+ * Resolve can be stopped by throwing an error, which will be handled by the `errorHandler` function.
186
+ * It's common to throw a `NotFoundError` to display a 404 page.
249
187
  *
188
+ * RedirectError can be thrown to redirect the user to another page.
250
189
  */
251
- forward(): Promise<void>;
190
+ resolve?: (context: PageResolve<TConfig, TPropsParent>) => Async<TProps>;
252
191
  /**
192
+ * The component to render when the page is loaded.
253
193
  *
254
- * @param props
194
+ * If `lazy` is defined, this will be ignored.
195
+ * Prefer using `lazy` to improve the initial loading time.
255
196
  */
256
- invalidate(props?: Record<string, any>): Promise<void>;
257
- /**
258
- * Create a valid href for the given pathname.
259
- *
260
- * @param pathname
261
- * @param layer
262
- */
263
- createHref(pathname: HrefLike, layer?: {
264
- path: string;
265
- }): string;
266
- go(path: string, options?: RouterGoOptions): Promise<void>;
267
- go<T extends object>(path: keyof VirtualRouter<T>, options?: RouterGoOptions): Promise<void>;
268
- anchor(path: string): AnchorProps;
197
+ component?: FC<TProps & TPropsParent>;
269
198
  /**
270
- * Set query params.
199
+ * Lazy load the component when the page is loaded.
271
200
  *
272
- * @param record
273
- * @param options
201
+ * It's recommended to use this for components to improve the initial loading time
202
+ * and enable code-splitting.
274
203
  */
275
- setQueryParams(record: Record<string, any> | ((queryParams: Record<string, any>) => Record<string, any>), options?: {
276
- /**
277
- * If true, this will add a new entry to the history stack.
278
- */
279
- push?: boolean;
280
- }): void;
281
- }
282
- type HrefLike = string | {
283
- options: {
284
- path?: string;
285
- name?: string;
286
- };
287
- };
288
- type VirtualRouter<T> = {
289
- [K in keyof T as T[K] extends PageDescriptor ? K : never]: T[K];
290
- };
291
-
292
- declare const KEY = "PAGE";
293
- interface PageConfigSchema {
294
- query?: TSchema$1;
295
- params?: TSchema$1;
296
- }
297
- type TPropsDefault = any;
298
- type TPropsParentDefault = object;
299
- interface PageDescriptorOptions<TConfig extends PageConfigSchema = PageConfigSchema, TProps extends object = TPropsDefault, TPropsParent extends object = TPropsParentDefault> {
300
- name?: string;
301
- path?: string;
302
- schema?: TConfig;
303
- resolve?: (config: PageResolve<TConfig, TPropsParent>) => Async<TProps>;
304
- component?: FC<TProps & TPropsParent>;
305
204
  lazy?: () => Promise<{
306
205
  default: FC<TProps & TPropsParent>;
307
206
  }>;
207
+ /**
208
+ * Set some children pages and make the page a parent page.
209
+ *
210
+ * /!\ Parent page can't be rendered directly. /!\
211
+ *
212
+ * If you still want to render at this pathname, add a child page with an empty path.
213
+ */
308
214
  children?: Array<{
309
215
  [OPTIONS]: PageDescriptorOptions;
310
216
  }>;
311
217
  parent?: {
312
- [OPTIONS]: PageDescriptorOptions<any, TPropsParent>;
218
+ [OPTIONS]: PageDescriptorOptions<PageConfigSchema, TPropsParent>;
313
219
  };
314
220
  can?: () => boolean;
315
- head?: Head | ((props: TProps, previous?: Head) => Head);
221
+ head?: Head$1 | ((props: TProps, previous?: Head$1) => Head$1);
316
222
  errorHandler?: (error: Error) => ReactNode;
223
+ prerender?: boolean | {
224
+ entries?: Array<Partial<PageRequestConfig<TConfig>>>;
225
+ };
226
+ /**
227
+ * If true, the page will be rendered on the client-side.
228
+ */
229
+ client?: boolean | ClientOnlyProps;
230
+ afterHandler?: (request: ServerRequest) => any;
317
231
  }
318
232
  interface PageDescriptor<TConfig extends PageConfigSchema = PageConfigSchema, TProps extends object = TPropsDefault, TPropsParent extends object = TPropsParentDefault> {
319
233
  [KIND]: typeof KEY;
320
234
  [OPTIONS]: PageDescriptorOptions<TConfig, TProps, TPropsParent>;
321
- render: (options?: {
322
- params?: Record<string, string>;
323
- query?: Record<string, string>;
324
- }) => Promise<string>;
325
- go: () => void;
326
- createAnchorProps: (routerHook: RouterHookApi) => {
327
- href: string;
328
- onClick: () => void;
329
- };
330
- can: () => boolean;
235
+ /**
236
+ * For testing or build purposes, this will render the page (with or without the HTML layout) and return the HTML and context.
237
+ * Only valid for server-side rendering, it will throw an error if called on the client-side.
238
+ */
239
+ render: (options?: PageDescriptorRenderOptions) => Promise<PageDescriptorRenderResult>;
331
240
  }
241
+ /**
242
+ * Main descriptor for defining a React route in the application.
243
+ */
332
244
  declare const $page: {
333
- <TConfig extends PageConfigSchema = PageConfigSchema, TProps extends object = any, TPropsParent extends object = object>(options: PageDescriptorOptions<TConfig, TProps, TPropsParent>): PageDescriptor<TConfig, TProps, TPropsParent>;
245
+ <TConfig extends PageConfigSchema = PageConfigSchema, TProps extends object = any, TPropsParent extends object = TPropsParentDefault>(options: PageDescriptorOptions<TConfig, TProps, TPropsParent>): PageDescriptor<TConfig, TProps, TPropsParent>;
334
246
  [KIND]: string;
335
247
  };
336
- interface Head {
248
+ interface PageDescriptorRenderOptions {
249
+ params?: Record<string, string>;
250
+ query?: Record<string, string>;
251
+ withLayout?: boolean;
252
+ }
253
+ interface PageDescriptorRenderResult {
254
+ html: string;
255
+ context: PageReactContext;
256
+ }
257
+ interface Head$1 {
337
258
  title?: string;
259
+ description?: string;
338
260
  titleSeparator?: string;
339
261
  htmlAttributes?: Record<string, string>;
340
262
  bodyAttributes?: Record<string, string>;
@@ -342,6 +264,32 @@ interface Head {
342
264
  name: string;
343
265
  content: string;
344
266
  }>;
267
+ keywords?: string[];
268
+ author?: string;
269
+ robots?: string;
270
+ themeColor?: string;
271
+ viewport?: string | {
272
+ width?: string;
273
+ height?: string;
274
+ initialScale?: string;
275
+ maximumScale?: string;
276
+ userScalable?: "no" | "yes" | "0" | "1";
277
+ interactiveWidget?: "resizes-visual" | "resizes-content" | "overlays-content";
278
+ };
279
+ og?: {
280
+ title?: string;
281
+ description?: string;
282
+ image?: string;
283
+ url?: string;
284
+ type?: string;
285
+ };
286
+ twitter?: {
287
+ card?: string;
288
+ title?: string;
289
+ description?: string;
290
+ image?: string;
291
+ site?: string;
292
+ };
345
293
  }
346
294
  interface PageRequestConfig<TConfig extends PageConfigSchema = PageConfigSchema> {
347
295
  params: TConfig["params"] extends TSchema$1 ? Static$1<TConfig["params"]> : Record<string, string>;
@@ -349,18 +297,32 @@ interface PageRequestConfig<TConfig extends PageConfigSchema = PageConfigSchema>
349
297
  }
350
298
  type PageResolve<TConfig extends PageConfigSchema = PageConfigSchema, TPropsParent extends object = TPropsParentDefault> = PageRequestConfig<TConfig> & TPropsParent & PageReactContext;
351
299
 
300
+ declare const envSchema$1: _alepha_core.TObject<{
301
+ REACT_STRICT_MODE: TBoolean;
302
+ }>;
303
+ declare module "@alepha/core" {
304
+ interface Env extends Partial<Static$1<typeof envSchema$1>> {
305
+ }
306
+ }
352
307
  declare class PageDescriptorProvider {
353
308
  protected readonly log: _alepha_core.Logger;
309
+ protected readonly env: {
310
+ REACT_STRICT_MODE: boolean;
311
+ };
354
312
  protected readonly alepha: Alepha;
355
313
  protected readonly pages: PageRoute[];
356
314
  getPages(): PageRoute[];
357
315
  page(name: string): PageRoute;
316
+ url(name: string, options?: {
317
+ params?: Record<string, string>;
318
+ base?: string;
319
+ }): URL;
358
320
  root(state: RouterState, context: PageReactContext): ReactNode;
359
321
  createLayers(route: PageRoute, request: PageRequest): Promise<CreateLayersResult>;
360
322
  protected getErrorHandler(route: PageRoute): ((error: Error) => ReactNode) | undefined;
361
323
  protected createElement(page: PageRoute, props: Record<string, any>): Promise<ReactNode>;
362
324
  protected fillHead(page: PageRoute, ctx: PageRequest, props: Record<string, any>): void;
363
- renderError(e: Error): ReactNode;
325
+ renderError(error: Error): ReactNode;
364
326
  renderEmptyView(): ReactNode;
365
327
  href(page: {
366
328
  options: {
@@ -368,7 +330,7 @@ declare class PageDescriptorProvider {
368
330
  };
369
331
  }, params?: Record<string, any>): string;
370
332
  compile(path: string, params?: Record<string, string>): string;
371
- protected renderView(index: number, path: string, view?: ReactNode): ReactNode;
333
+ protected renderView(index: number, path: string, view: ReactNode | undefined, page: PageRoute): ReactNode;
372
334
  protected readonly configure: _alepha_core.HookDescriptor<"configure">;
373
335
  protected map(pages: Array<{
374
336
  value: {
@@ -406,7 +368,7 @@ interface Layer {
406
368
  index: number;
407
369
  path: string;
408
370
  }
409
- type PreviousLayerData = Omit<Layer, "element">;
371
+ type PreviousLayerData = Omit<Layer, "element" | "index" | "path">;
410
372
  interface AnchorProps {
411
373
  href: string;
412
374
  onClick: (ev: any) => any;
@@ -446,27 +408,167 @@ interface CreateLayersResult extends RouterState {
446
408
  */
447
409
  interface PageReactContext {
448
410
  url: URL;
449
- head: Head;
411
+ head: Head$1;
450
412
  onError: (error: Error) => ReactNode;
451
413
  links?: ApiLinksResponse;
452
414
  }
453
415
 
416
+ interface Head {
417
+ title?: string;
418
+ htmlAttributes?: Record<string, string>;
419
+ bodyAttributes?: Record<string, string>;
420
+ meta?: Array<{
421
+ name: string;
422
+ content: string;
423
+ }>;
424
+ }
425
+ declare class ServerHeadProvider {
426
+ renderHead(template: string, head: Head): string;
427
+ mergeAttributes(existing: string, attrs: Record<string, string>): string;
428
+ parseAttributes(attrStr: string): Record<string, string>;
429
+ escapeHtml(str: string): string;
430
+ }
431
+
432
+ declare class BrowserHeadProvider {
433
+ renderHead(document: Document, head: Head): void;
434
+ }
435
+
436
+ interface BrowserRoute extends Route {
437
+ page: PageRoute;
438
+ }
439
+ declare class BrowserRouterProvider extends RouterProvider<BrowserRoute> {
440
+ protected readonly log: _alepha_core.Logger;
441
+ protected readonly alepha: Alepha;
442
+ protected readonly pageDescriptorProvider: PageDescriptorProvider;
443
+ add(entry: PageRouteEntry): void;
444
+ protected readonly configure: _alepha_core.HookDescriptor<"configure">;
445
+ transition(url: URL, options?: TransitionOptions): Promise<RouterRenderResult>;
446
+ root(state: RouterState, context: PageReactContext): ReactNode;
447
+ }
448
+
449
+ declare class ReactBrowserProvider {
450
+ protected readonly log: _alepha_core.Logger;
451
+ protected readonly client: HttpClient;
452
+ protected readonly alepha: Alepha;
453
+ protected readonly router: BrowserRouterProvider;
454
+ protected readonly headProvider: BrowserHeadProvider;
455
+ protected root: Root;
456
+ transitioning?: {
457
+ to: string;
458
+ };
459
+ state: RouterState;
460
+ get document(): Document;
461
+ get history(): History;
462
+ get url(): string;
463
+ invalidate(props?: Record<string, any>): Promise<void>;
464
+ go(url: string, options?: RouterGoOptions): Promise<void>;
465
+ protected render(options?: {
466
+ url?: string;
467
+ previous?: PreviousLayerData[];
468
+ }): Promise<RouterRenderResult>;
469
+ /**
470
+ * Get embedded layers from the server.
471
+ */
472
+ protected getHydrationState(): ReactHydrationState | undefined;
473
+ readonly ready: _alepha_core.HookDescriptor<"ready">;
474
+ readonly onTransitionEnd: _alepha_core.HookDescriptor<"react:transition:end">;
475
+ }
476
+ interface RouterGoOptions {
477
+ replace?: boolean;
478
+ match?: TransitionOptions;
479
+ params?: Record<string, string>;
480
+ }
481
+ interface ReactHydrationState {
482
+ layers?: Array<PreviousLayerData>;
483
+ links?: ApiLinksResponse;
484
+ }
485
+
454
486
  interface NestedViewProps {
455
487
  children?: ReactNode;
456
488
  }
457
489
  /**
458
- * Nested view component
490
+ * A component that renders the current view of the nested router layer.
491
+ *
492
+ * To be simple, it renders the `element` of the current child page of a parent page.
493
+ *
494
+ * @example
495
+ * ```tsx
496
+ * import { NestedView } from "@alepha/react";
459
497
  *
460
- * @param props
461
- * @constructor
498
+ * class App {
499
+ * parent = $page({
500
+ * component: () => <NestedView />,
501
+ * });
502
+ *
503
+ * child = $page({
504
+ * parent: this.root,
505
+ * component: () => <div>Child Page</div>,
506
+ * });
507
+ * }
508
+ * ```
462
509
  */
463
510
  declare const NestedView: (props: NestedViewProps) => react_jsx_runtime.JSX.Element;
464
511
 
465
- interface LinkProps extends AnchorHTMLAttributes<HTMLAnchorElement> {
466
- to: string | PageDescriptor;
467
- children?: React__default.ReactNode;
512
+ declare class RouterHookApi {
513
+ private readonly pages;
514
+ private readonly state;
515
+ private readonly layer;
516
+ private readonly browser?;
517
+ constructor(pages: PageRoute[], state: RouterState, layer: {
518
+ path: string;
519
+ }, browser?: ReactBrowserProvider | undefined);
520
+ get current(): RouterState;
521
+ get pathname(): string;
522
+ get query(): Record<string, string>;
523
+ back(): Promise<void>;
524
+ forward(): Promise<void>;
525
+ invalidate(props?: Record<string, any>): Promise<void>;
526
+ /**
527
+ * Create a valid href for the given pathname.
528
+ *
529
+ * @param pathname
530
+ * @param layer
531
+ */
532
+ createHref(pathname: HrefLike, layer?: {
533
+ path: string;
534
+ }, options?: {
535
+ params?: Record<string, any>;
536
+ }): string;
537
+ go(path: string, options?: RouterGoOptions): Promise<void>;
538
+ go<T extends object>(path: keyof VirtualRouter<T>, options?: RouterGoOptions): Promise<void>;
539
+ anchor(path: string, options?: {
540
+ params?: Record<string, any>;
541
+ }): AnchorProps;
542
+ anchor<T extends object>(path: keyof VirtualRouter<T>, options?: {
543
+ params?: Record<string, any>;
544
+ }): AnchorProps;
545
+ /**
546
+ * Set query params.
547
+ *
548
+ * @param record
549
+ * @param options
550
+ */
551
+ setQueryParams(record: Record<string, any> | ((queryParams: Record<string, any>) => Record<string, any>), options?: {
552
+ /**
553
+ * If true, this will add a new entry to the history stack.
554
+ */
555
+ push?: boolean;
556
+ }): void;
557
+ }
558
+ type HrefLike = string | {
559
+ options: {
560
+ path?: string;
561
+ name?: string;
562
+ };
563
+ };
564
+ type VirtualRouter<T> = {
565
+ [K in keyof T as T[K] extends PageDescriptor ? K : never]: T[K];
566
+ };
567
+
568
+ declare class RedirectionError extends Error {
569
+ readonly page: HrefLike;
570
+ constructor(page: HrefLike);
468
571
  }
469
- declare const Link: (props: LinkProps) => react_jsx_runtime.JSX.Element | null;
470
572
 
471
573
  /**
472
574
  * Props for the ErrorBoundary component.
@@ -507,6 +609,12 @@ declare class ErrorBoundary extends React__default.Component<PropsWithChildren<E
507
609
  render(): ReactNode;
508
610
  }
509
611
 
612
+ interface LinkProps extends AnchorHTMLAttributes<HTMLAnchorElement> {
613
+ to: string | PageDescriptor;
614
+ children?: React__default.ReactNode;
615
+ }
616
+ declare const Link: (props: LinkProps) => react_jsx_runtime.JSX.Element | null;
617
+
510
618
  interface RouterContextValue {
511
619
  alepha: Alepha;
512
620
  state: RouterState;
@@ -520,10 +628,19 @@ interface RouterLayerContextValue {
520
628
  }
521
629
  declare const RouterLayerContext: React.Context<RouterLayerContextValue | undefined>;
522
630
 
523
- declare const useInject: <T extends object>(clazz: Class<T>) => T;
631
+ declare const useActive: (path: HrefLike) => UseActiveHook;
632
+ interface UseActiveHook {
633
+ isActive: boolean;
634
+ anchorProps: AnchorProps;
635
+ isPending: boolean;
636
+ name?: string;
637
+ }
638
+
639
+ declare const useAlepha: () => Alepha;
640
+
641
+ declare const useClient: <T extends object>(_scope?: ClientScope) => HttpVirtualClient<T>;
524
642
 
525
- declare const useClient: () => HttpClient;
526
- declare const useApi: <T extends object>() => _alepha_server.HttpVirtualClient<T>;
643
+ declare const useInject: <T extends object>(clazz: Service<T>) => T;
527
644
 
528
645
  interface UseQueryParamsHookOptions {
529
646
  format?: "base64" | "querystring";
@@ -549,23 +666,10 @@ declare const useRouterEvents: (opts?: {
549
666
 
550
667
  declare const useRouterState: () => RouterState;
551
668
 
552
- declare const useActive: (path: HrefLike) => UseActiveHook;
553
- interface UseActiveHook {
554
- isActive: boolean;
555
- anchorProps: AnchorProps;
556
- isPending: boolean;
557
- name?: string;
558
- }
559
-
560
- declare class RedirectionError extends Error {
561
- readonly page: HrefLike;
562
- constructor(page: HrefLike);
563
- }
564
-
565
669
  declare const envSchema: TObject<{
566
670
  REACT_SERVER_DIST: TString;
567
671
  REACT_SERVER_PREFIX: TString;
568
- REACT_SSR_ENABLED: TBoolean;
672
+ REACT_SSR_ENABLED: TOptional<TBoolean>;
569
673
  REACT_ROOT_ID: TString;
570
674
  }>;
571
675
  declare module "@alepha/core" {
@@ -583,30 +687,37 @@ declare class ReactServerProvider {
583
687
  protected readonly serverStaticProvider: ServerStaticProvider;
584
688
  protected readonly serverRouterProvider: ServerRouterProvider;
585
689
  protected readonly headProvider: ServerHeadProvider;
690
+ protected readonly serverTimingProvider: ServerTimingProvider;
586
691
  protected readonly env: {
587
- REACT_ROOT_ID: string;
692
+ REACT_SSR_ENABLED?: boolean | undefined;
588
693
  REACT_SERVER_DIST: string;
589
694
  REACT_SERVER_PREFIX: string;
590
- REACT_SSR_ENABLED: boolean;
695
+ REACT_ROOT_ID: string;
591
696
  };
592
697
  protected readonly ROOT_DIV_REGEX: RegExp;
593
- protected readonly configure: _alepha_core.HookDescriptor<"configure">;
594
- protected registerPages(templateLoader: () => Promise<string | undefined>): Promise<void>;
698
+ readonly onConfigure: _alepha_core.HookDescriptor<"configure">;
699
+ get template(): string | undefined;
700
+ protected registerPages(templateLoader: TemplateLoader): Promise<void>;
595
701
  protected getPublicDirectory(): string;
596
702
  protected configureStaticServer(root: string): Promise<void>;
597
- protected configureVite(): Promise<void>;
703
+ protected configureVite(ssrEnabled: boolean): Promise<void>;
598
704
  /**
599
705
  * For testing purposes, creates a render function that can be used.
600
706
  */
601
- protected createRenderFunction(name: string): (options?: {
707
+ protected createRenderFunction(name: string, withIndex?: boolean): (options?: {
602
708
  params?: Record<string, string>;
603
709
  query?: Record<string, string>;
604
- }) => Promise<string>;
605
- protected createHandler(page: PageRoute, templateLoader: () => Promise<string | undefined>): ServerHandler;
606
- fillTemplate(response: {
710
+ }) => Promise<{
711
+ context: PageRequest;
712
+ html: string;
713
+ }>;
714
+ protected createHandler(page: PageRoute, templateLoader: TemplateLoader): ServerHandler;
715
+ renderToHtml(template: string, state: RouterState, context: PageReactContext): string;
716
+ protected fillTemplate(response: {
607
717
  html: string;
608
718
  }, app: string, script: string): void;
609
719
  }
720
+ type TemplateLoader = () => Promise<string | undefined>;
610
721
 
611
722
  declare module "@alepha/core" {
612
723
  interface Hooks {
@@ -642,4 +753,4 @@ declare class ReactModule {
642
753
  constructor();
643
754
  }
644
755
 
645
- export { $page, type AnchorProps, type CreateLayersResult, ErrorBoundary, type Head, type HrefLike, type Layer, Link, NestedView, type PageConfigSchema, type PageDescriptor, type PageDescriptorOptions, PageDescriptorProvider, type PageReactContext, type PageRequest, type PageRequestConfig, type PageResolve, type PageRoute, type PageRouteEntry, type PreviousLayerData, ReactBrowserProvider, type ReactHydrationState, ReactModule, ReactServerProvider, RedirectionError, RouterContext, type RouterContextValue, type RouterGoOptions, RouterHookApi, RouterLayerContext, type RouterLayerContextValue, type RouterRenderResult, type RouterStackItem, type RouterState, type TPropsDefault, type TPropsParentDefault, type TransitionOptions, type UseActiveHook, type UseQueryParamsHookOptions, type VirtualRouter, envSchema, isPageRoute, useActive, useApi, useClient, useInject, useQueryParams, useRouter, useRouterEvents, useRouterState };
756
+ export { $page, type AnchorProps, ClientOnly, type CreateLayersResult, ErrorBoundary, type Head$1 as Head, type HrefLike, type Layer, Link, NestedView, type PageConfigSchema, type PageDescriptor, type PageDescriptorOptions, PageDescriptorProvider, type PageDescriptorRenderOptions, type PageDescriptorRenderResult, type PageReactContext, type PageRequest, type PageRequestConfig, type PageResolve, type PageRoute, type PageRouteEntry, type PreviousLayerData, ReactBrowserProvider, type ReactHydrationState, ReactModule, ReactServerProvider, RedirectionError, RouterContext, type RouterContextValue, type RouterGoOptions, RouterHookApi, RouterLayerContext, type RouterLayerContextValue, type RouterRenderResult, type RouterStackItem, type RouterState, type TPropsDefault, type TPropsParentDefault, type TransitionOptions, type UseActiveHook, type UseQueryParamsHookOptions, type VirtualRouter, envSchema, isPageRoute, useActive, useAlepha, useClient, useInject, useQueryParams, useRouter, useRouterEvents, useRouterState };