@qwik.dev/router 2.0.0-beta.35 → 2.0.0-beta.37

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/lib/index.d.ts CHANGED
@@ -7,13 +7,15 @@ import { CookieOptions } from '@qwik.dev/router/middleware/request-handler';
7
7
  import { CookieValue } from '@qwik.dev/router/middleware/request-handler';
8
8
  import { DeferReturn } from '@qwik.dev/router/middleware/request-handler';
9
9
  import type { EnvGetter } from '@qwik.dev/router/middleware/request-handler';
10
+ import { InternalRequest } from '@qwik.dev/router/middleware/request-handler';
10
11
  import { JSXOutput } from '@qwik.dev/core';
12
+ import { NoSerialize } from '@qwik.dev/core';
11
13
  import { QRL } from '@qwik.dev/core';
12
14
  import { QRLEventHandlerMulti } from '@qwik.dev/core';
13
15
  import { QwikIntrinsicElements } from '@qwik.dev/core';
14
16
  import { QwikJSX } from '@qwik.dev/core';
15
17
  import { Render } from '@qwik.dev/core/server';
16
- import { RenderOptions } from '@qwik.dev/core/server';
18
+ import { RenderToStreamOptions } from '@qwik.dev/core/server';
17
19
  import { RequestEvent } from '@qwik.dev/router/middleware/request-handler';
18
20
  import { RequestEventAction } from '@qwik.dev/router/middleware/request-handler';
19
21
  import { RequestEventBase } from '@qwik.dev/router/middleware/request-handler';
@@ -162,15 +164,25 @@ export declare type ActionStore<RETURN, INPUT, OPTIONAL extends boolean = true>
162
164
  declare type AnchorAttributes = QwikIntrinsicElements['a'];
163
165
 
164
166
  /**
165
- * The cacheKey export type. When exported from a page module alongside eTag, enables in-memory SSR
166
- * caching.
167
+ * Cache key function. Used by `routeConfig.cacheKey` (SSR HTML cache) and by `routeLoader$`'s
168
+ * `cacheKey` option (per-loader JSON cache).
167
169
  *
168
- * - `true`: use the default cache key `status|eTag|pathname`
169
- * - Function: receives status, eTag, and pathname; returns a cache key string or null (no cache)
170
+ * - `true`: use the surface's default key.
171
+ *
172
+ * - SSR default: `${status}|${eTag}|${pathname}` when an eTag is set, otherwise
173
+ * `${status}|${pathname}`.
174
+ * - Loader default: `${pathname}|${filteredSearch}|${loaderId}|${eTag}` when an eTag is set,
175
+ * otherwise `${pathname}|${filteredSearch}|${loaderId}`.
176
+ * - Function: receives the request event and the normalized, unquoted eTag (or an empty string when
177
+ * none was provided). Return the cache key string, or `null` or `''` to skip caching for this
178
+ * request. Loader callbacks receive the loader-scoped request event, with `url`, `query`, and
179
+ * `request.url` filtered by the loader's `search` allowlist.
180
+ *
181
+ * Note: valid cacheKeys are non-empty strings.
170
182
  *
171
183
  * @public
172
184
  */
173
- export declare type CacheKeyFn = true | ((status: number, eTag: string, pathname: string) => string | null);
185
+ export declare type CacheKeyFn = true | ((requestEv: RequestEvent, eTag: string) => string | null);
174
186
 
175
187
  /** @public */
176
188
  export declare interface ContentHeading {
@@ -189,7 +201,18 @@ export declare interface ContentMenu {
189
201
  declare type ContentModule = PageModule | LayoutModule;
190
202
 
191
203
  /**
192
- * The eTag export type: a static string or a function receiving DocumentHeadProps.
204
+ * The eTag export type for routeConfig.
205
+ *
206
+ * - `string` — static ETag value.
207
+ * - `(props: DocumentHeadProps) => string | null` — compute the ETag from route context (params, URL,
208
+ * loaded data via `resolveValue`, etc.). Return `null` to skip eTag for this request.
209
+ *
210
+ * Qwik normalizes eTag values by stripping weak-form `W/` prefixes, quotes, and forbidden chars,
211
+ * then sends a strong `ETag` header. Values that normalize to an empty string are treated as
212
+ * absent.
213
+ *
214
+ * When set (and a value is produced), the server includes an `ETag` header and returns `304` if
215
+ * `If-None-Match` matches.
193
216
  *
194
217
  * @public
195
218
  */
@@ -357,10 +380,10 @@ declare type EndpointModuleLoader = () => ValueOrPromise<RouteModule>;
357
380
  declare interface EndpointResponse {
358
381
  status: number;
359
382
  statusMessage?: string;
360
- loaders: Record<string, unknown>;
361
- loadersSerializationStrategy: Map<string, SerializationStrategy>;
362
383
  formData?: FormData;
363
384
  action?: string;
385
+ actionResult?: unknown;
386
+ loaderHashes?: string[];
364
387
  }
365
388
 
366
389
  /** @public */
@@ -433,6 +456,8 @@ export declare type HttpErrorProps = {
433
456
  message: string;
434
457
  };
435
458
 
459
+ export { InternalRequest }
460
+
436
461
  declare type IsAny<Type> = 0 extends 1 & Type ? true : false;
437
462
 
438
463
  /** @public */
@@ -511,6 +536,10 @@ declare interface LoadedRoute {
511
536
  $notFound$?: boolean;
512
537
  /** The error module loader (nearest _E ancestor), for rendering ServerErrors */
513
538
  $errorLoader$?: ContentModuleLoader;
539
+ /** Merged array of routeLoader$ hashes from all matched nodes (layouts + page) */
540
+ $loaders$?: string[];
541
+ /** Runtime-only mapping of routeLoader$ hashes to the matched pathname used for q-loader fetches */
542
+ $loaderPaths$?: Record<string, string>;
514
543
  }
515
544
 
516
545
  /** @public */
@@ -537,9 +566,79 @@ declare type LoaderConstructorQRL = {
537
566
 
538
567
  /** @public */
539
568
  declare type LoaderOptions = {
569
+ /** @deprecated Unused */
540
570
  readonly id?: string;
541
571
  readonly validation?: DataValidator[];
542
572
  readonly serializationStrategy?: SerializationStrategy;
573
+ /**
574
+ * Time in milliseconds after which the loader data is considered stale. The server derives
575
+ * `Cache-Control: max-age` seconds from this value on loader responses.
576
+ *
577
+ * On the client, the loader's AsyncSignal `expires` is set to this value. If `poll` is true, the
578
+ * signal auto-refetches when expired. If `poll` is false (default), the data is marked stale but
579
+ * not auto-refetched.
580
+ */
581
+ readonly expires?: number;
582
+ /**
583
+ * When true AND `expires` is set, the loader data is automatically refetched when it expires
584
+ * (polling behavior). When false (default), expired data is marked stale but not auto-refetched.
585
+ */
586
+ readonly poll?: boolean;
587
+ /**
588
+ * Enable ETag-based caching for this loader's JSON responses.
589
+ *
590
+ * - `string` — static ETag value; if `If-None-Match` matches, the loader is skipped entirely
591
+ * - `(ev: RequestEvent) => string | null` — compute the ETag from the request context (params, URL,
592
+ * headers, etc.); if `If-None-Match` matches, the loader is skipped entirely. Return null to
593
+ * skip eTag for this request.
594
+ *
595
+ * Qwik normalizes eTag values by stripping weak-form `W/` prefixes, quotes, and forbidden chars,
596
+ * then sends a strong `ETag` header. Values that normalize to an empty string are treated as
597
+ * absent.
598
+ *
599
+ * When set, the server includes an `ETag` header on `q-loader-*.json` responses and returns `304`
600
+ * if the client sends a matching `If-None-Match` header.
601
+ *
602
+ * For auto-computed eTags, use `cacheKey` instead — on cache write the eTag is hashed from the
603
+ * serialized response and stored alongside it, so subsequent hits get the same eTag.
604
+ */
605
+ readonly eTag?: string | ((ev: RequestEvent) => string | null);
606
+ /**
607
+ * Enable in-memory server-side caching of this loader's serialized JSON response.
608
+ *
609
+ * - `true` — use the default key `${pathname}|${filteredSearch}|${loaderId}` (suffixed with
610
+ * `|${eTag}` when an eTag is set).
611
+ * - Function `(requestEv, eTag) => string | null` — return a custom key, or `null` to skip caching
612
+ * this request.
613
+ *
614
+ * On cache miss the loader runs, the serialized response is stored alongside its eTag (computed
615
+ * from the data when no `eTag` option is set), and the response is sent. On cache hit the stored
616
+ * `{ eTag, data }` pair is served directly — `If-None-Match` is checked against the stored eTag
617
+ * and a `304` is returned when it matches.
618
+ */
619
+ readonly cacheKey?: CacheKeyFn;
620
+ /**
621
+ * Allowlist of URL search parameter names that this loader depends on.
622
+ *
623
+ * When set, the loader only re-fetches when the listed search params change — other param changes
624
+ * are ignored. Only the listed params are sent in the loader JSON request URL. During SSR and
625
+ * loader JSON requests, the loader receives a request event with `url`, `query`, and
626
+ * `request.url` filtered to the same params.
627
+ *
628
+ * When not set, the `qwikRouter()` plugin option `strictLoaders` determines the behavior. If
629
+ * `strictLoaders` is `true` (this is the default), no search params are sent and changes do not
630
+ * trigger a re-fetch. If `strictLoaders` is `false`, all search params are sent and any change
631
+ * triggers a re-fetch.
632
+ */
633
+ readonly search?: string[];
634
+ /**
635
+ * When true (default), the previous value is kept while the loader re-fetches after navigation,
636
+ * so components see stale data until the new response arrives.
637
+ *
638
+ * When false, the value is cleared on re-fetch, causing reads to suspend (show a loading
639
+ * boundary). This is useful when showing old data during navigation would be confusing.
640
+ */
641
+ readonly allowStale?: boolean;
543
642
  };
544
643
 
545
644
  /** @public */
@@ -673,6 +772,8 @@ export declare interface QwikRouterEnvData {
673
772
  params: PathParams;
674
773
  response: EndpointResponse;
675
774
  loadedRoute: LoadedRoute;
775
+ routeLoaderCtx: RouteLoaderCtx;
776
+ loaderValues: Record<string, unknown>;
676
777
  }
677
778
 
678
779
  /** @public */
@@ -754,12 +855,12 @@ export declare interface QwikRouterProps {
754
855
  export declare const QwikRouterProvider: Component<QwikRouterProps>;
755
856
 
756
857
  /** @public */
757
- export declare type RendererOptions = Omit<RenderOptions, 'serverData'> & {
858
+ export declare type RendererOptions = Omit<RenderToStreamOptions, 'serverData'> & {
758
859
  serverData: ServerData;
759
860
  };
760
861
 
761
862
  /** @public */
762
- export declare type RendererOutputOptions = Omit<RenderOptions, 'serverData'> & {
863
+ export declare type RendererOutputOptions = Omit<RenderToStreamOptions, 'serverData'> & {
763
864
  serverData: ServerData & {
764
865
  documentHead?: DocumentHeadValue;
765
866
  } & Record<string, unknown>;
@@ -783,7 +884,26 @@ export declare type ResolvedDocumentHead<FrontMatter extends Record<string, any>
783
884
  readonly manifestHash: string;
784
885
  };
785
886
 
786
- /** @public */
887
+ /**
888
+ * Define a route action that handles form submissions or programmatic invocations.
889
+ *
890
+ * Actions run on the server when submitted from the client. The result is returned as an
891
+ * `ActionStore` with `.value` for success data and `.error` for errors (including validation errors
892
+ * from `zod$`/`valibot$` where `.fieldErrors` etc. are accessible directly on `.error`).
893
+ *
894
+ * By default, after an action completes, ALL current route loaders are invalidated on the client
895
+ * and re-fetched as needed (so that the browser cache is correct). This can be controlled with:
896
+ *
897
+ * - `invalidate: [loader1, loader2]`: Only invalidate specific loaders. The client re-fetches them
898
+ * individually. Other loaders keep their current data.
899
+ * - `invalidate: []`: No loaders are invalidated. The action response only contains the action
900
+ * result. Use this when the action doesn't affect any loader data.
901
+ *
902
+ * The `strictLoaders` Vite plugin option applies `invalidate: []` globally for all actions that
903
+ * don't specify an explicit `invalidate` option.
904
+ *
905
+ * @public
906
+ */
787
907
  export declare const routeAction$: ActionConstructor;
788
908
 
789
909
  /* Excluded from this release type: routeActionQrl */
@@ -857,13 +977,59 @@ export declare interface RouteData {
857
977
  _M?: RouteData[];
858
978
  /** Menu loader for this subtree (from menu.md). Runtime uses nearest ancestor during traversal. */
859
979
  _N?: MenuModuleLoader;
980
+ /** Array of routeLoader$ hashes for this node's loaders */
981
+ _R?: string[];
860
982
  /** Child route segments (any key not starting with `_`) */
861
983
  [part: string]: RouteData | RouteData[] | ModuleLoader[] | ContentModuleLoader | MenuModuleLoader | string[] | string | undefined;
862
984
  }
863
985
 
864
- /** @public */
986
+ /**
987
+ * Define a route loader that fetches data before the route renders.
988
+ *
989
+ * Route loaders run on the server during SSR and return data as an `AsyncSignal`. On the client,
990
+ * loaders automatically re-fetch when the route changes (SPA navigation). Each loader gets its own
991
+ * JSON endpoint (`q-loader-{id}.{hash}.json`), so only the loaders present on the target route are
992
+ * fetched.
993
+ *
994
+ * **Important:** Route loader data uses Qwik's custom serialization format, not standard JSON. This
995
+ * means the data supports features like circular references, Dates, and other non-JSON types, but
996
+ * it cannot be consumed by external clients expecting plain JSON.
997
+ *
998
+ * ## Options
999
+ *
1000
+ * - `search: string[]`: Allowlist of URL search params the loader depends on. Only listed params are
1001
+ * sent in the request and changes to other params are ignored. During SSR and loader JSON
1002
+ * requests, the loader's request event is filtered to those params too. `search: []` means no
1003
+ * search params are sent and only route path changes trigger a re-fetch.
1004
+ * - `allowStale: false`: Clears the previous value when re-fetching, so components see a loading
1005
+ * state instead of stale data during navigation. Useful when old data would be confusing.
1006
+ * - `eTag`: Enable ETag-based caching. Can be `true` (auto-hash), a string, or a function.
1007
+ * - `expires` / `poll`: Control client-side caching and polling behavior.
1008
+ *
1009
+ * The `strictLoaders` Vite plugin option applies `search: []` globally for all loaders that don't
1010
+ * specify an explicit `search` option.
1011
+ *
1012
+ * @public
1013
+ */
865
1014
  export declare const routeLoader$: LoaderConstructor;
866
1015
 
1016
+ /**
1017
+ * Reactive context for route loaders. On the server this is stored in sharedMap, on the client it's
1018
+ * a store that gets updated on navigation.
1019
+ *
1020
+ * - `loaderPaths`: loader ID → fetch path (the longest route path for that loader)
1021
+ * - `pagePathname` / `pageSearch`: client-only navigation state used for loader invalidation and
1022
+ * q-loader fetches. They are intentionally omitted from SSR state and fall back to `location`
1023
+ * until the first SPA navigation.
1024
+ */
1025
+ declare type RouteLoaderCtx = {
1026
+ loaderPaths: Record<string, string | undefined>;
1027
+ pagePathname?: string;
1028
+ pageSearch?: string;
1029
+ /** SPA navigation function. Client-only and intentionally omitted from SSR state. */
1030
+ goto?: NoSerialize<RouteNavigate>;
1031
+ };
1032
+
867
1033
  /* Excluded from this release type: routeLoaderQrl */
868
1034
 
869
1035
  /** @public */
@@ -911,6 +1077,7 @@ declare interface ServerConfig {
911
1077
  export declare type ServerData = {
912
1078
  url: string;
913
1079
  requestHeaders: Record<string, string>;
1080
+ renderMode: 'static' | 'server';
914
1081
  locale: string | undefined;
915
1082
  nonce: string | undefined;
916
1083
  containerAttributes: Record<string, string> & {