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

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 (35) hide show
  1. package/lib/adapters/cloudflare-pages/vite/index.mjs +2 -2
  2. package/lib/adapters/shared/vite/index.d.ts +3 -4
  3. package/lib/adapters/shared/vite/index.mjs +158 -143
  4. package/lib/chunks/dev-preloaded-route-loader.mjs +3 -0
  5. package/lib/chunks/fs.mjs +6 -2
  6. package/lib/chunks/head.qwik.mjs +814 -93
  7. package/lib/chunks/request-body-limit.mjs +37 -0
  8. package/lib/chunks/request-path.mjs +2 -2
  9. package/lib/chunks/routes.mjs +47 -0
  10. package/lib/chunks/server-error.mjs +19 -0
  11. package/lib/chunks/system.mjs +2 -1
  12. package/lib/chunks/use-functions.qwik.mjs +1 -1
  13. package/lib/chunks/{worker-thread.qwik.mjs → user-response.mjs} +1053 -1749
  14. package/lib/chunks/worker-thread.mjs +317 -0
  15. package/lib/index.d.ts +89 -55
  16. package/lib/index.qwik.mjs +178 -100
  17. package/lib/middleware/azure-swa/index.mjs +13 -9
  18. package/lib/middleware/cloudflare-pages/index.mjs +2 -2
  19. package/lib/middleware/deno/index.d.ts +2 -0
  20. package/lib/middleware/deno/index.mjs +2 -1
  21. package/lib/middleware/netlify-edge/index.mjs +2 -2
  22. package/lib/middleware/node/index.d.ts +9 -1
  23. package/lib/middleware/node/index.mjs +28 -3
  24. package/lib/middleware/request-handler/index.d.ts +9 -10
  25. package/lib/middleware/request-handler/index.mjs +26 -1105
  26. package/lib/middleware/vercel-edge/index.mjs +2 -2
  27. package/lib/ssg/index.d.ts +2 -10
  28. package/lib/ssg/index.mjs +10 -50
  29. package/lib/vite/index.d.ts +8 -0
  30. package/lib/vite/index.mjs +406 -117
  31. package/package.json +5 -4
  32. package/lib/chunks/action-handler.mjs +0 -782
  33. package/lib/chunks/deepFreeze.qwik.mjs +0 -608
  34. package/lib/chunks/error-handler.mjs +0 -57
  35. package/lib/chunks/not-found-wrapper.qwik.mjs +0 -25
@@ -1,14 +1,13 @@
1
- import { componentQrl, inlinedQrl, useErrorBoundary, useOnWindow, _captures, _jsxSorted, Slot, isBrowser, useSignal, untrack, _qrlSync, useVisibleTaskQrl, _jsxSplit, _getConstProps, _getVarProps, isDev, eventQrl, isServer, useStylesQrl, useServerData, useStore, useContextProvider, useTaskQrl, noSerialize, getLocale, useContext, SkipRender, implicit$FirstArg, withLocale, _wrapProp, _restProps, _fnSignal, createElement } from '@qwik.dev/core';
1
+ import { componentQrl, inlinedQrl, useErrorBoundary, useOnWindow, _captures, _jsxSorted, Slot, isBrowser, isDev, untrack, _qrlSync, _jsxSplit, _getConstProps, _getVarProps, eventQrl, isServer, useServerData, useStore, useSignal, useContextProvider, useTaskQrl, noSerialize, getLocale, createComputedQrl, useContext, SkipRender, implicit$FirstArg, withLocale, _wrapProp, _restProps, _fnSignal, createElement } from '@qwik.dev/core';
2
2
  import { Fragment } from '@qwik.dev/core/jsx-runtime';
3
3
  import * as qwikRouterConfig from '@qwik-router-config';
4
4
  import { p } from '@qwik.dev/core/preloader';
5
5
  import { e as ensureSlash } from './chunks/pathname.mjs';
6
- import { f as fetchRouteLoaderData, Q as QACTION_KEY, e as ensureRouteLoaderSignals, s as setLoaderSignalValue, C as ContentContext, a as ContentInternalContext, D as DocumentHeadContext, H as HttpStatusContext, R as RouteLocationContext, b as RouteNavigateContext, c as RouteStateContext, d as RouteLoaderCtxContext, g as RouteActionContext, h as RoutePreventNavigateContext, u as updateRouteLoaderPaths, i as Q_ROUTE, j as getRequestEvent, k as QFN_KEY, l as QDATA_KEY } from './chunks/deepFreeze.qwik.mjs';
7
- export { r as routeLoader$, m as routeLoaderQrl } from './chunks/deepFreeze.qwik.mjs';
8
- import { l as loadRoute, g as getClientNavPath, s as shouldPreload, i as isSamePath, t as toPath, c as createDocumentHead, r as resolveHead, a as toUrl, b as isSameOrigin } from './chunks/head.qwik.mjs';
6
+ import { l as loadRoute, g as getModuleRouteLoaders, f as fetchRouteLoaderData, a as getClientNavPath, s as shouldPreload, i as isSamePath, t as toPath, b as isSameOrigin, Q as QACTION_KEY, e as ensureRouteLoaderSignals, c as setLoaderSignalValue, d as createDocumentHead, C as ContentContext, h as ContentInternalContext, D as DocumentHeadContext, H as HttpStatusContext, j as RouteLocationContext, k as RouteNavigateContext, m as RouteStateContext, n as RouteLoaderCtxContext, o as RouteActionContext, p as RoutePreventNavigateContext, u as updateRouteLoaderPaths, q as invalidateNavRouteLoaders, r as isImmutableLoader, v as clearNavFetchCache, w as resolveHead, x as Q_ROUTE, y as toUrl, z as getRequestEvent, A as QFN_KEY, B as QDATA_KEY } from './chunks/head.qwik.mjs';
7
+ export { E as routeLoader$, G as routeLoaderQrl } from './chunks/head.qwik.mjs';
9
8
  import { u as useNavigate, a as useLocation, b as useDocumentHead, c as useQwikRouterEnv, d as useAction } from './chunks/use-functions.qwik.mjs';
10
9
  export { e as useContent, f as useHttpStatus, g as usePreventNavigate$, h as usePreventNavigateQrl } from './chunks/use-functions.qwik.mjs';
11
- import { _deserialize, _hasStoreEffects, _getContextContainer, forceStoreEffects, createAsyncQrl, _waitUntilRendered, _getContextHostElement, _serialize } from '@qwik.dev/core/internal';
10
+ import { _deserialize, _hasStoreEffects, _getContextContainer, forceStoreEffects, _waitUntilRendered, _getContextHostElement, _serialize } from '@qwik.dev/core/internal';
12
11
  import * as v from 'valibot';
13
12
  import * as z from 'zod';
14
13
  export { z } from 'zod';
@@ -29,8 +28,32 @@ const ErrorBoundary = /* @__PURE__ */ componentQrl(/* @__PURE__ */ inlinedQrl((p
29
28
  return /* @__PURE__ */ _jsxSorted(Slot, null, null, null, 3, "bA_1");
30
29
  }, "ErrorBoundary_component_pOa6vjtC7ik"));
31
30
 
31
+ const prefetchLoaderData = (loadedRoute, url, manifestHash) => {
32
+ if (!loadedRoute.$loaders$?.length || !loadedRoute.$loaderPaths$) {
33
+ return;
34
+ }
35
+ const immutableIds = new Set(getModuleRouteLoaders(loadedRoute.$mods$).filter((loader) => loader.__cacheControl === "immutable").map((loader) => loader.__id));
36
+ const basePath = qwikRouterConfig.basePathname ?? "/";
37
+ for (const hash of loadedRoute.$loaders$) {
38
+ if (immutableIds.has(hash)) {
39
+ continue;
40
+ }
41
+ let loaderPath = loadedRoute.$loaderPaths$[hash];
42
+ if (!loaderPath) {
43
+ continue;
44
+ }
45
+ if (basePath !== "/" && !loaderPath.startsWith(basePath)) {
46
+ loaderPath = basePath + loaderPath.slice(1);
47
+ }
48
+ fetchRouteLoaderData(hash, loaderPath, manifestHash, {
49
+ pageUrl: url,
50
+ basePath
51
+ }).catch(() => {
52
+ });
53
+ }
54
+ };
32
55
  async function prefetchRoute(url, prefetchData, probability = 0.8, manifestHash, prefetchBundle = true) {
33
- if (!isBrowser) {
56
+ if (!isBrowser || isDev) {
34
57
  return;
35
58
  }
36
59
  try {
@@ -49,35 +72,17 @@ async function prefetchRoute(url, prefetchData, probability = 0.8, manifestHash,
49
72
  if (!prefetchData || !manifestHash) {
50
73
  return;
51
74
  }
52
- if (loadedRoute.$loaders$?.length && loadedRoute.$loaderPaths$) {
53
- const basePath = qwikRouterConfig.basePathname ?? "/";
54
- for (const hash of loadedRoute.$loaders$) {
55
- let loaderPath = loadedRoute.$loaderPaths$?.[hash];
56
- if (!loaderPath) {
57
- continue;
58
- }
59
- if (basePath !== "/" && !loaderPath.startsWith(basePath)) {
60
- loaderPath = basePath + loaderPath.slice(1);
61
- }
62
- fetchRouteLoaderData(hash, loaderPath, manifestHash, {
63
- pageUrl: url,
64
- basePath
65
- }).catch(() => {
66
- });
67
- }
68
- }
75
+ prefetchLoaderData(loadedRoute, url, manifestHash);
69
76
  } catch {
70
77
  }
71
78
  }
72
79
 
73
- const __vite_import_meta_env__ = {};
74
80
  const Link = /* @__PURE__ */ componentQrl(/* @__PURE__ */ inlinedQrl((props) => {
75
81
  const nav = useNavigate();
76
82
  const loc = useLocation();
77
83
  const head = useDocumentHead();
78
84
  const originalHref = props.href;
79
- const anchorRef = useSignal();
80
- const { onClick$, prefetch: prefetchProp, reload, replaceState, scroll, prefetchBundle: prefetchBundleProp = "visible", prefetchData: prefetchDataProp = prefetchProp === "js" ? "off" : "intent", ...linkProps } = props;
85
+ const { onClick$, prefetch: prefetchProp, reload, replaceState, scroll, prefetchBundles: prefetchBundlesProp = "visible", prefetchData: prefetchDataProp = prefetchProp === "js" ? "off" : "intent", ...linkProps } = props;
81
86
  const clientNavPath = untrack(getClientNavPath, {
82
87
  ...linkProps,
83
88
  reload
@@ -85,7 +90,10 @@ const Link = /* @__PURE__ */ componentQrl(/* @__PURE__ */ inlinedQrl((props) =>
85
90
  linkProps.href = clientNavPath || originalHref;
86
91
  const isDepratedPrefetchDisabled = prefetchProp === false;
87
92
  const shouldPrefetch = untrack(shouldPreload, clientNavPath, loc);
88
- const shouldPrefetchBundle = !!clientNavPath && prefetchBundleProp !== "off" && shouldPrefetch && !isDepratedPrefetchDisabled;
93
+ const shouldVisiblePrefetchBundles = !!clientNavPath && shouldPrefetch && !isDepratedPrefetchDisabled && (prefetchBundlesProp === "visible" || // deprecated prop below, remove in favor of prefetchBundles
94
+ prefetchProp === "js" || prefetchProp === true);
95
+ const shouldVisiblePrefetchData = !!clientNavPath && shouldPrefetch && !isDepratedPrefetchDisabled && (prefetchDataProp === "visible" || // deprecated prop below, remove in favor of prefetchData
96
+ prefetchProp === true);
89
97
  const shouldPrefetchData = !!clientNavPath && prefetchDataProp !== "off" && shouldPrefetch && !isDepratedPrefetchDisabled;
90
98
  const handleDataPrefetch = shouldPrefetchData ? /* @__PURE__ */ inlinedQrl((_, elm) => {
91
99
  const head2 = _captures[0];
@@ -142,46 +150,11 @@ const Link = /* @__PURE__ */ componentQrl(/* @__PURE__ */ inlinedQrl((props) =>
142
150
  const url = new URL(elm.href);
143
151
  prefetchRoute(url, false, 1);
144
152
  }, "Link_component_handlePreload_AAemwtuBjsE");
145
- useVisibleTaskQrl(/* @__PURE__ */ inlinedQrl(({ track }) => {
146
- const anchorRef2 = _captures[0], handleDataPrefetch2 = _captures[1], head2 = _captures[2], linkProps2 = _captures[3], loc2 = _captures[4], prefetchBundleProp2 = _captures[5], prefetchDataProp2 = _captures[6], prefetchProp2 = _captures[7], shouldPrefetchBundle2 = _captures[8];
147
- track(() => loc2.url.pathname);
148
- const handler = linkProps2.onQVisible$;
149
- if (handler) {
150
- const event = new CustomEvent("qvisible");
151
- if (Array.isArray(handler)) {
152
- handler.flat(10).forEach((handler2) => handler2?.(event, anchorRef2.value));
153
- } else {
154
- handler?.(event, anchorRef2.value);
155
- }
156
- }
157
- const isProdOrTest = !isDev || __vite_import_meta_env__?.TEST;
158
- if (isProdOrTest && anchorRef2.value?.href && !navigator.connection?.saveData) {
159
- if (handleDataPrefetch2 && (prefetchDataProp2 === "visible" || // deprecated prop below, remove in favor of prefetchData
160
- prefetchProp2 === true)) {
161
- const url = new URL(anchorRef2.value.href);
162
- prefetchRoute(url, true, 0.8, head2.manifestHash, shouldPrefetchBundle2);
163
- } else if (shouldPrefetchBundle2 && (prefetchBundleProp2 === "visible" || // deprecated prop below, remove in favor of prefetchBundle
164
- prefetchProp2 === "js" || prefetchProp2 === true)) {
165
- const url = new URL(anchorRef2.value.href);
166
- prefetchRoute(url, false, 0.8);
167
- }
168
- }
169
- }, "Link_component_useVisibleTask_xKeuRmnoNSA", [
170
- anchorRef,
171
- handleDataPrefetch,
172
- head,
173
- linkProps,
174
- loc,
175
- prefetchBundleProp,
176
- prefetchDataProp,
177
- prefetchProp,
178
- shouldPrefetchBundle
179
- ]));
180
153
  return /* @__PURE__ */ _jsxSplit("a", {
181
- ref: anchorRef,
182
154
  "q:link": !!clientNavPath,
183
155
  ..._getVarProps(linkProps),
184
156
  ..._getConstProps(linkProps),
157
+ "data-q-prefetch": shouldVisiblePrefetchBundles && shouldVisiblePrefetchData ? "bd" : shouldVisiblePrefetchBundles ? "b" : shouldVisiblePrefetchData ? "d" : null,
185
158
  "q-e:click": [
186
159
  preventDefault,
187
160
  handlePreload,
@@ -204,10 +177,7 @@ const Link = /* @__PURE__ */ componentQrl(/* @__PURE__ */ inlinedQrl((props) =>
204
177
  linkProps.onKeyDown$,
205
178
  prefetchDataProp === "commit" ? onEnterKeyDown : null
206
179
  ]
207
- }, {
208
- // We need to prevent the onQVisible$ from being called twice since it is handled in the visible task
209
- "q-e:qvisible": []
210
- }, /* @__PURE__ */ _jsxSorted(Slot, null, null, null, 3, "jO_0"), 0, "jO_1");
180
+ }, null, /* @__PURE__ */ _jsxSorted(Slot, null, null, null, 3, "jO_0"), 0, "jO_1");
211
181
  }, "Link_component_VPmar9tb3t4"));
212
182
 
213
183
  const newScrollState = () => {
@@ -234,8 +204,76 @@ const clientNavigate = (win, navType, fromURL, toURL, replaceState = false) => {
234
204
  }
235
205
  }
236
206
  };
207
+ const preloadRouteBundles = (path, probability = 0.8) => {
208
+ if (isBrowser) {
209
+ path = ensureSlash(path);
210
+ path = path.length > 1 && path.startsWith("/") ? path.slice(1) : path;
211
+ p(path, probability);
212
+ }
213
+ };
237
214
 
238
- const transitionCss = "@layer qwik{@supports selector(html:active-view-transition-type(type)){html:active-view-transition-type(qwik-navigation){:root{view-transition-name:none}}}@supports not selector(html:active-view-transition-type(type)){:root{view-transition-name:none}}}";
215
+ let prefetchedLinks = /* @__PURE__ */ new WeakSet();
216
+ let cleanupPrefetchObserver;
217
+ const resetLinkPrefetchState = () => {
218
+ prefetchedLinks = /* @__PURE__ */ new WeakSet();
219
+ };
220
+ const createLinkPrefetchObserver = (manifestHash) => {
221
+ const anchors = document.querySelectorAll("a[q\\:link][data-q-prefetch]");
222
+ const prefetchAnchor = (anchor, observer2) => {
223
+ if (prefetchedLinks.has(anchor)) {
224
+ return;
225
+ }
226
+ prefetchedLinks.add(anchor);
227
+ observer2?.unobserve(anchor);
228
+ if (navigator.connection?.saveData || !anchor.href) {
229
+ return;
230
+ }
231
+ let url;
232
+ try {
233
+ url = new URL(anchor.href);
234
+ } catch {
235
+ return;
236
+ }
237
+ const currentUrl = new URL(location.href);
238
+ if (!isSameOrigin(url, currentUrl) || !shouldPreload(toPath(url), {
239
+ url: currentUrl
240
+ })) {
241
+ return;
242
+ }
243
+ const mode = anchor.getAttribute("data-q-prefetch") || "";
244
+ if (mode.includes("b")) {
245
+ preloadRouteBundles(url.pathname);
246
+ }
247
+ if (mode.includes("d")) {
248
+ prefetchRoute(url, true, 0.8, manifestHash, false);
249
+ }
250
+ };
251
+ if (typeof IntersectionObserver === "undefined") {
252
+ anchors.forEach((anchor) => prefetchAnchor(anchor));
253
+ return () => {
254
+ };
255
+ }
256
+ const observer = new IntersectionObserver((entries) => {
257
+ for (const entry of entries) {
258
+ if (entry.isIntersecting) {
259
+ prefetchAnchor(entry.target, observer);
260
+ }
261
+ }
262
+ });
263
+ anchors.forEach((anchor) => observer.observe(anchor));
264
+ return () => {
265
+ observer.disconnect();
266
+ };
267
+ };
268
+ const refreshLinkPrefetchObserver = (manifestHash) => {
269
+ resetLinkPrefetchState();
270
+ cleanupPrefetchObserver?.();
271
+ cleanupPrefetchObserver = createLinkPrefetchObserver(manifestHash);
272
+ };
273
+ const linkPrefetchInit = eventQrl(/* @__PURE__ */ inlinedQrl((_, element) => {
274
+ const manifestHash = element.closest("[q\\:manifest-hash]")?.getAttribute("q:manifest-hash") || void 0;
275
+ refreshLinkPrefetchObserver(manifestHash);
276
+ }, "linkPrefetchInit_event_hoZr9O26Irg"));
239
277
 
240
278
  function callRestoreScrollOnDocument() {
241
279
  if (document.__q_scroll_restore__) {
@@ -433,9 +471,12 @@ const spaInit = eventQrl(/* @__PURE__ */ inlinedQrl((_, el) => {
433
471
  }
434
472
  }, "spa_init_event_igI1pUsax0E"));
435
473
 
436
- async function submitAction(action, routePath) {
437
- const pathBase = ensureSlash(routePath);
438
- const url = `${pathBase}?${QACTION_KEY}=${encodeURIComponent(action.id)}`;
474
+ async function submitAction(action, routeUrl) {
475
+ const pathBase = ensureSlash(routeUrl.pathname);
476
+ const searchParams = new URLSearchParams(routeUrl.search);
477
+ searchParams.set(QACTION_KEY, action.id);
478
+ const search = searchParams.toString();
479
+ const url = `${pathBase}?${search}`;
439
480
  const actionData = action.data;
440
481
  action.data = void 0;
441
482
  let fetchOptions;
@@ -469,7 +510,7 @@ async function submitAction(action, routePath) {
469
510
  }
470
511
  if ((response.headers.get("content-type") || "").includes("json")) {
471
512
  const text = await response.text();
472
- const data = _deserialize(text);
513
+ const data = await _deserialize(text);
473
514
  return {
474
515
  status: response.status,
475
516
  result: data?.result,
@@ -480,8 +521,22 @@ async function submitAction(action, routePath) {
480
521
  return void 0;
481
522
  }
482
523
 
524
+ const transitionCss = "@layer qwik{@supports selector(html:active-view-transition-type(type)){html:active-view-transition-type(qwik-navigation){:root{view-transition-name:none}}}@supports not selector(html:active-view-transition-type(type)){:root{view-transition-name:none}}}";
525
+
526
+ const shouldStartViewTransition = (viewTransition) => viewTransition === true && "startViewTransition" in document;
527
+ const VIEW_TRANSITION_STYLE_ID = "qwik-view-transition";
528
+ const ensureViewTransitionStyles = () => {
529
+ if (document.getElementById(VIEW_TRANSITION_STYLE_ID)) {
530
+ return;
531
+ }
532
+ const style = document.createElement("style");
533
+ style.id = VIEW_TRANSITION_STYLE_ID;
534
+ style.textContent = transitionCss;
535
+ document.head.appendChild(style);
536
+ };
483
537
  const startViewTransition = (params) => {
484
538
  if ("startViewTransition" in document) {
539
+ ensureViewTransitionStyles();
485
540
  let transition;
486
541
  try {
487
542
  transition = document.startViewTransition(params);
@@ -538,14 +593,12 @@ const useQwikMockRouter = (props) => {
538
593
  deep: false
539
594
  });
540
595
  for (const [loaderId, data] of Object.entries(loadersData ?? {})) {
541
- loadersState[loaderId] ||= createAsyncQrl(/* @__PURE__ */ inlinedQrl(async () => {
596
+ loadersState[loaderId] ||= createComputedQrl(/* @__PURE__ */ inlinedQrl(() => {
542
597
  const data2 = _captures[0];
543
598
  return data2;
544
- }, "useQwikMockRouter_createAsync_clbxpuXqpEU", [
599
+ }, "useQwikMockRouter_createComputed_JL6bChMwwyc", [
545
600
  data
546
- ]), {
547
- initial: data
548
- });
601
+ ]));
549
602
  }
550
603
  const goto = props.goto ?? /* @__PURE__ */ inlinedQrl(async () => {
551
604
  console.warn("QwikRouterMockProvider: goto not provided");
@@ -703,7 +756,6 @@ const useQwikRouter = (props) => {
703
756
  if (!isServer) {
704
757
  throw new Error("useQwikRouter can only run during SSR on the server. If you are seeing this, it means you are re-rendering the root of your application. Fix that or use the <QwikRouterProvider> component around the root of your application.");
705
758
  }
706
- useStylesQrl(/* @__PURE__ */ inlinedQrl(transitionCss, "qwik_view_transition_css_inline_vNfd9raIMI0"));
707
759
  const env = useQwikRouterEnv();
708
760
  if (!env?.params) {
709
761
  throw new Error(`Missing Qwik Router Env Data for help visit https://github.com/QwikDev/qwik/issues/6237`);
@@ -726,6 +778,7 @@ const useQwikRouter = (props) => {
726
778
  });
727
779
  const navResolver = {};
728
780
  const routeLoaderCtx = useStore(env.routeLoaderCtx);
781
+ routeLoaderCtx.manifestHash = manifestHash;
729
782
  const loaderState = {};
730
783
  const contentModulesForInit = env.loadedRoute.$mods$;
731
784
  const loaders = ensureRouteLoaderSignals(contentModulesForInit, loaderState, routeLoaderCtx);
@@ -810,15 +863,14 @@ const useQwikRouter = (props) => {
810
863
  if (navResolver2.p && !forceReload && typeof dest !== "number" && isSamePath(dest, lastDest) && dest.href === lastDest.href) {
811
864
  return navResolver2.p;
812
865
  }
813
- internalState.navCount++;
866
+ const navCount = ++internalState.navCount;
814
867
  internalState.currentTransition?.skipTransition();
815
868
  if (preventNav.$cbs$ && (forceReload || typeof dest === "number" || !isSamePath(dest, lastDest) || !isSameOrigin(dest, lastDest))) {
816
- const ourNavId = internalState.navCount;
817
869
  const prevents = await Promise.all([
818
870
  ...preventNav.$cbs$.values()
819
871
  ].map((cb) => cb(dest)));
820
- if (ourNavId !== internalState.navCount || prevents.some(Boolean)) {
821
- if (ourNavId === internalState.navCount && type === "popstate") {
872
+ if (navCount !== internalState.navCount || prevents.some(Boolean)) {
873
+ if (navCount === internalState.navCount && type === "popstate") {
822
874
  history.pushState(null, "", lastDest);
823
875
  }
824
876
  return;
@@ -864,6 +916,15 @@ const useQwikRouter = (props) => {
864
916
  clientNavigate(window, type, new URL(location.href), dest, replaceState);
865
917
  historyUpdated = true;
866
918
  }
919
+ routeLocation2.isNavigating = true;
920
+ const container = isBrowser ? _getContextContainer() : void 0;
921
+ if (container) {
922
+ await _waitUntilRendered(container);
923
+ if (navCount !== internalState.navCount) {
924
+ return;
925
+ }
926
+ }
927
+ actionState2.value = void 0;
867
928
  routeInternal2.value = {
868
929
  type,
869
930
  dest,
@@ -875,8 +936,6 @@ const useQwikRouter = (props) => {
875
936
  if (isBrowser) {
876
937
  prefetchRoute(dest, true, 0.8, manifestHash2);
877
938
  }
878
- actionState2.value = void 0;
879
- routeLocation2.isNavigating = true;
880
939
  navResolver2.p = new Promise((resolve) => {
881
940
  navResolver2.r = () => {
882
941
  navResolver2.r = void 0;
@@ -943,7 +1002,7 @@ const useQwikRouter = (props) => {
943
1002
  return;
944
1003
  }
945
1004
  if (action) {
946
- const result = await submitAction(action, trackUrl.pathname);
1005
+ const result = await submitAction(action, trackUrl);
947
1006
  if (!result) {
948
1007
  routeInternal2.untrackedValue = {
949
1008
  type: navType,
@@ -951,11 +1010,6 @@ const useQwikRouter = (props) => {
951
1010
  };
952
1011
  return;
953
1012
  }
954
- actionData = {
955
- status: result.status,
956
- action: action.id,
957
- actionResult: result.result
958
- };
959
1013
  if (action.resolve) {
960
1014
  action.resolve({
961
1015
  status: result.status,
@@ -963,6 +1017,17 @@ const useQwikRouter = (props) => {
963
1017
  });
964
1018
  action.resolve = void 0;
965
1019
  }
1020
+ if (result.redirect) {
1021
+ goto2(result.redirect, {
1022
+ replaceState: true
1023
+ });
1024
+ return;
1025
+ }
1026
+ actionData = {
1027
+ status: result.status,
1028
+ action: action.id,
1029
+ actionResult: result.result
1030
+ };
966
1031
  actionLoaderHashes = result.loaderHashes;
967
1032
  shouldInvalidateActionLoaders = true;
968
1033
  }
@@ -974,6 +1039,9 @@ const useQwikRouter = (props) => {
974
1039
  }
975
1040
  updateRouteLoaderPaths(routeLoaderCtx2, loadedRoute.$loaderPaths$, trackUrl);
976
1041
  const routeLoaders = ensureRouteLoaderSignals(contentModules, loaderState2, routeLoaderCtx2);
1042
+ if (!isServer) {
1043
+ invalidateNavRouteLoaders(loaderState2);
1044
+ }
977
1045
  if (shouldInvalidateActionLoaders) {
978
1046
  if (actionLoaderHashes !== void 0) {
979
1047
  for (const hash of actionLoaderHashes) {
@@ -988,9 +1056,14 @@ const useQwikRouter = (props) => {
988
1056
  if (routeLoaders.length > 0) {
989
1057
  for (let i = 0; i < routeLoaders.length; i++) {
990
1058
  const loader = routeLoaders[i];
991
- loaderState2[loader.__id].untrackedLoading;
1059
+ if (!isImmutableLoader(loader.__id)) {
1060
+ loaderState2[loader.__id].untrackedPending;
1061
+ }
992
1062
  }
993
1063
  }
1064
+ if (!isServer) {
1065
+ clearNavFetchCache();
1066
+ }
994
1067
  if (internalState.navCount !== navCountBefore) {
995
1068
  return;
996
1069
  }
@@ -1064,6 +1137,7 @@ const useQwikRouter = (props) => {
1064
1137
  navContext2.value = noSerialize({
1065
1138
  routeName: $routeName$,
1066
1139
  navType,
1140
+ prevUrl,
1067
1141
  replaceState,
1068
1142
  shouldForcePrevUrl,
1069
1143
  shouldForceUrl,
@@ -1115,7 +1189,7 @@ const useQwikRouter = (props) => {
1115
1189
  deferUpdates: isServer
1116
1190
  });
1117
1191
  useTaskQrl(/* @__PURE__ */ inlinedQrl(({ track }) => {
1118
- const contentInternal2 = _captures[0], goto2 = _captures[1], navContext2 = _captures[2], navResolver2 = _captures[3], props2 = _captures[4], routeInternal2 = _captures[5], routeLocation2 = _captures[6];
1192
+ const contentInternal2 = _captures[0], goto2 = _captures[1], manifestHash2 = _captures[2], navContext2 = _captures[3], navResolver2 = _captures[4], props2 = _captures[5], routeInternal2 = _captures[6], routeLocation2 = _captures[7];
1119
1193
  const nav = track(navContext2);
1120
1194
  if (isServer || !nav) {
1121
1195
  return;
@@ -1125,9 +1199,8 @@ const useQwikRouter = (props) => {
1125
1199
  }
1126
1200
  const container = _getContextContainer();
1127
1201
  const navigation = routeInternal2.untrackedValue;
1128
- const { navType, replaceState, routeName } = nav;
1202
+ const { navType, prevUrl, replaceState, routeName } = nav;
1129
1203
  const trackUrl = routeLocation2.url;
1130
- const prevUrl = routeLocation2.prevUrl ?? trackUrl;
1131
1204
  const scroller = getScroller();
1132
1205
  let scrollState;
1133
1206
  if (navType === "popstate") {
@@ -1169,7 +1242,7 @@ const useQwikRouter = (props) => {
1169
1242
  return navigatePromise = _waitUntilRendered(container);
1170
1243
  };
1171
1244
  const _waitNextPage = () => {
1172
- if (props2?.viewTransition === false || !("startViewTransition" in document)) {
1245
+ if (!shouldStartViewTransition(props2?.viewTransition)) {
1173
1246
  return navigate().then(() => void 0);
1174
1247
  }
1175
1248
  const { ready, transition } = startViewTransition({
@@ -1202,6 +1275,7 @@ const useQwikRouter = (props) => {
1202
1275
  saveScrollHistory(scrollState2);
1203
1276
  window._qRouterScrollEnabled = true;
1204
1277
  callRestoreScrollOnDocument();
1278
+ refreshLinkPrefetchObserver(manifestHash2);
1205
1279
  if (nav.shouldForcePrevUrl) {
1206
1280
  forceStoreEffects(routeLocation2, "prevUrl");
1207
1281
  }
@@ -1217,6 +1291,7 @@ const useQwikRouter = (props) => {
1217
1291
  }, "useQwikRouter_useTask_2_yw17chooOac", [
1218
1292
  contentInternal,
1219
1293
  goto,
1294
+ manifestHash,
1220
1295
  navContext,
1221
1296
  navResolver,
1222
1297
  props,
@@ -1272,10 +1347,13 @@ const RouterOutlet = /* @__PURE__ */ componentQrl(/* @__PURE__ */ inlinedQrl(()
1272
1347
  }
1273
1348
  })(window, history);
1274
1349
  }, '()=>{((w,h)=>{if(!w._qcs){w._qcs=!0;const s=h.state?._qRouterScroll;if(s){h.scrollRestoration="manual";w.scrollTo(s.x,s.y);}document.dispatchEvent(new Event("qcinit"));}})(window,history);}'),
1275
- "q-d:qrouterpopstate": /* @__PURE__ */ inlinedQrl((event, _1, nav2) => handleRouterPopstate(nav2, event), "RouterOutlet_component_Fragment_script_q_d_qrouterpopstate_aRL6GvFyews"),
1350
+ "q-d:qrouterpopstate": /* @__PURE__ */ inlinedQrl((event, _1, nav2) => handleRouterPopstate(nav2, event), "RouterOutlet_component_Fragment_script_q_d_qrouterpopstate_aRL6GvFyews").m(),
1276
1351
  "q:p": nav
1277
1352
  }, {
1278
- "q-d:qcinit": spaInit
1353
+ "q-d:qcinit": [
1354
+ spaInit,
1355
+ linkPrefetchInit
1356
+ ]
1279
1357
  }, null, 6, "Fn_1")
1280
1358
  ], 1, "Fn_2");
1281
1359
  }
@@ -1570,7 +1648,7 @@ const deserializeStream = async function* (stream, abortSignal) {
1570
1648
  const lines = buffer.split(/\n/);
1571
1649
  buffer = lines.pop();
1572
1650
  for (const line of lines) {
1573
- const deserializedData = _deserialize(line);
1651
+ const deserializedData = await _deserialize(line);
1574
1652
  yield deserializedData;
1575
1653
  }
1576
1654
  }
@@ -1658,7 +1736,7 @@ const serverQrl = (qrl, options) => {
1658
1736
  })();
1659
1737
  } else if (contentType === "application/qwik-json") {
1660
1738
  const str = await res.text();
1661
- const obj = _deserialize(str);
1739
+ const obj = await _deserialize(str);
1662
1740
  if (res.status >= 400) {
1663
1741
  throw obj;
1664
1742
  }
@@ -1888,4 +1966,4 @@ const DocumentHeadTags = /* @__PURE__ */ componentQrl(/* @__PURE__ */ inlinedQrl
1888
1966
  ], 1, "r5_3");
1889
1967
  }, "DocumentHeadTags_component_9CrWYOoCpgY"));
1890
1968
 
1891
- export { DocumentHeadTags, ErrorBoundary, Form, Link, QWIK_CITY_SCROLLER, QWIK_ROUTER_SCROLLER, QwikCityMockProvider, QwikCityProvider, QwikRouterMockProvider, QwikRouterProvider, RouterOutlet, ServiceWorkerRegister, createRenderer, globalAction$, globalActionQrl, omitProps, routeAction$, routeActionQrl, server$, serverQrl, untypedAppUrl, useDocumentHead, useLocation, useNavigate, useQwikRouter, valibot$, valibotQrl, validator$, validatorQrl, zod$, zodQrl };
1969
+ export { DocumentHeadTags, ErrorBoundary, Form, Link, QWIK_CITY_SCROLLER, QWIK_ROUTER_SCROLLER, QwikCityMockProvider, QwikCityProvider, QwikRouterMockProvider, QwikRouterProvider, RouterOutlet, ServiceWorkerRegister, createRenderer, getRequestEvent, globalAction$, globalActionQrl, omitProps, routeAction$, routeActionQrl, server$, serverQrl, untypedAppUrl, useDocumentHead, useLocation, useNavigate, useQwikRouter, valibot$, valibotQrl, validator$, validatorQrl, zod$, zodQrl };
@@ -1,5 +1,5 @@
1
1
  import { setServerPlatform } from '@qwik.dev/core/server';
2
- import { requestHandler, isStaticPath, getNotFound } from '@qwik.dev/router/middleware/request-handler';
2
+ import { requestHandler, isStaticPath, getErrorHtml } from '@qwik.dev/router/middleware/request-handler';
3
3
  import { parseString } from 'set-cookie-parser';
4
4
 
5
5
  function createQwikRouter(opts) {
@@ -26,23 +26,27 @@ function createQwikRouter(opts) {
26
26
  },
27
27
  request: new Request(url, options),
28
28
  getWritableStream: (status, headers, cookies, resolve) => {
29
+ const chunks = [];
30
+ let bodyLength = 0;
29
31
  const response = {
30
32
  status,
31
- body: new Uint8Array(),
32
33
  headers: {},
33
34
  cookies: cookies.headers().map((header) => parseString(header))
34
35
  };
35
36
  headers.forEach((value, key) => response.headers[key] = value);
36
37
  return new WritableStream({
37
38
  write(chunk) {
38
- if (response.body instanceof Uint8Array) {
39
- const newBuffer = new Uint8Array(response.body.length + chunk.length);
40
- newBuffer.set(response.body);
41
- newBuffer.set(chunk, response.body.length);
42
- response.body = newBuffer;
43
- }
39
+ chunks.push(chunk.slice());
40
+ bodyLength += chunk.length;
44
41
  },
45
42
  close() {
43
+ const body = new Uint8Array(bodyLength);
44
+ let offset = 0;
45
+ for (const chunk of chunks) {
46
+ body.set(chunk, offset);
47
+ offset += chunk.length;
48
+ }
49
+ response.body = body;
46
50
  resolve(response);
47
51
  }
48
52
  });
@@ -66,7 +70,7 @@ function createQwikRouter(opts) {
66
70
  return response;
67
71
  }
68
72
  }
69
- const notFoundHtml = !req.headers.accept?.includes("text/html") || isStaticPath(req.method || "GET", url) ? "Not Found" : getNotFound(url.pathname);
73
+ const notFoundHtml = !req.headers.accept?.includes("text/html") || isStaticPath(req.method || "GET", url) ? "Not Found" : getErrorHtml(404, "Not Found");
70
74
  return {
71
75
  status: 404,
72
76
  headers: {
@@ -1,5 +1,5 @@
1
1
  import { setServerPlatform } from '@qwik.dev/core/server';
2
- import { _TextEncoderStream_polyfill, isStaticPath, mergeHeadersCookies, requestHandler, getNotFound } from '@qwik.dev/router/middleware/request-handler';
2
+ import { _TextEncoderStream_polyfill, isStaticPath, mergeHeadersCookies, requestHandler, getErrorHtml } from '@qwik.dev/router/middleware/request-handler';
3
3
  import { isDev } from '@qwik.dev/core/build';
4
4
 
5
5
  function createQwikRouter(opts) {
@@ -72,7 +72,7 @@ function createQwikRouter(opts) {
72
72
  return response;
73
73
  }
74
74
  }
75
- const notFoundHtml = !request.headers.get("accept")?.includes("text/html") || isStaticPath(request.method || "GET", url) ? "Not Found" : getNotFound(url.pathname);
75
+ const notFoundHtml = !request.headers.get("accept")?.includes("text/html") || isStaticPath(request.method || "GET", url) ? "Not Found" : getErrorHtml(404, "Not Found");
76
76
  return new Response(notFoundHtml, {
77
77
  status: 404,
78
78
  headers: {
@@ -33,6 +33,8 @@ export declare interface QwikRouterDenoMiddleware {
33
33
 
34
34
  /** @public */
35
35
  export declare interface QwikRouterDenoOptions extends ServerRenderOptions {
36
+ /** Maximum request body size in bytes. Defaults to 10 MiB. */
37
+ requestBodyLimit?: number;
36
38
  /** Options for serving static files */
37
39
  static?: {
38
40
  /** The root folder for statics files. Defaults to /dist */
@@ -1,6 +1,7 @@
1
1
  import { setServerPlatform } from '@qwik.dev/core/server';
2
2
  import { isStaticPath, mergeHeadersCookies, requestHandler } from '@qwik.dev/router/middleware/request-handler';
3
3
  import { M as MIME_TYPES, n as normalizeRequestUrl } from '../../chunks/url.mjs';
4
+ import { l as limitRequestBody } from '../../chunks/request-body-limit.mjs';
4
5
  import { join, fromFileUrl, extname } from 'https://deno.land/std/path/mod.ts';
5
6
  import { isDev } from '@qwik.dev/core/build';
6
7
 
@@ -26,7 +27,7 @@ function createQwikRouter(opts) {
26
27
  url,
27
28
  // @ts-ignore
28
29
  env: Deno.env,
29
- request,
30
+ request: limitRequestBody(request, opts.requestBodyLimit),
30
31
  getWritableStream: (status, headers, cookies, resolve) => {
31
32
  const { readable, writable } = new TransformStream();
32
33
  const response = new Response(readable, {
@@ -1,5 +1,5 @@
1
1
  import { setServerPlatform } from '@qwik.dev/core/server';
2
- import { isStaticPath, mergeHeadersCookies, requestHandler, getNotFound } from '@qwik.dev/router/middleware/request-handler';
2
+ import { isStaticPath, mergeHeadersCookies, requestHandler, getErrorHtml } from '@qwik.dev/router/middleware/request-handler';
3
3
  import { isDev } from '@qwik.dev/core/build';
4
4
 
5
5
  function createQwikRouter(opts) {
@@ -47,7 +47,7 @@ function createQwikRouter(opts) {
47
47
  return response;
48
48
  }
49
49
  }
50
- const notFoundHtml = !request.headers.get("accept")?.includes("text/html") || isStaticPath(request.method || "GET", url) ? "Not Found" : getNotFound(url.pathname);
50
+ const notFoundHtml = !request.headers.get("accept")?.includes("text/html") || isStaticPath(request.method || "GET", url) ? "Not Found" : getErrorHtml(404, "Not Found");
51
51
  return new Response(notFoundHtml, {
52
52
  status: 404,
53
53
  headers: {
@@ -33,14 +33,22 @@ export declare type QwikCityNodeRequestOptions = QwikRouterNodeRequestOptions;
33
33
 
34
34
  /** @public */
35
35
  export declare interface QwikRouterNodeMiddleware {
36
- router: (req: IncomingMessage | Http2ServerRequest, res: ServerResponse, next: NodeRequestNextFunction) => Promise<void>;
36
+ router: (req: IncomingMessage | Http2ServerRequest, res: ServerResponse, next: NodeRequestNextFunction, limits?: QwikRouterNodeRequestLimits) => Promise<void>;
37
37
  /** @deprecated `router` handles 404 responses. Will be removed in V3. */
38
38
  notFound: (req: IncomingMessage | Http2ServerRequest, res: ServerResponse, next: (e: any) => void) => Promise<void>;
39
39
  staticFile: (req: IncomingMessage | Http2ServerRequest, res: ServerResponse, next: (e?: any) => void) => Promise<void>;
40
40
  }
41
41
 
42
+ /** @public */
43
+ export declare interface QwikRouterNodeRequestLimits {
44
+ /** Maximum request body size in bytes imposed by the host. */
45
+ bodyLimit?: number;
46
+ }
47
+
42
48
  /** @public */
43
49
  export declare interface QwikRouterNodeRequestOptions extends ServerRenderOptions {
50
+ /** Maximum request body size in bytes. Defaults to 10 MiB. */
51
+ requestBodyLimit?: number;
44
52
  /** Options for serving static files */
45
53
  static?: {
46
54
  /** The root folder for statics files. Defaults to /dist */