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

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} +1030 -1746
  14. package/lib/chunks/worker-thread.mjs +317 -0
  15. package/lib/index.d.ts +80 -39
  16. package/lib/index.qwik.mjs +141 -80
  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 +24 -1104
  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 +404 -115
  31. package/package.json +4 -3
  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, f as fetchRouteLoaderData, g as getClientNavPath, s as shouldPreload, i as isSamePath, t as toPath, a as isSameOrigin, Q as QACTION_KEY, e as ensureRouteLoaderSignals, b as setLoaderSignalValue, c as createDocumentHead, C as ContentContext, d as ContentInternalContext, D as DocumentHeadContext, H as HttpStatusContext, h as RouteLocationContext, j as RouteNavigateContext, k as RouteStateContext, m as RouteLoaderCtxContext, n as RouteActionContext, o as RoutePreventNavigateContext, u as updateRouteLoaderPaths, r as resolveHead, p as Q_ROUTE, q as toUrl, v as getRequestEvent, w as QFN_KEY, x as QDATA_KEY } from './chunks/head.qwik.mjs';
7
+ export { y as routeLoader$, z 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';
@@ -30,7 +29,7 @@ const ErrorBoundary = /* @__PURE__ */ componentQrl(/* @__PURE__ */ inlinedQrl((p
30
29
  }, "ErrorBoundary_component_pOa6vjtC7ik"));
31
30
 
32
31
  async function prefetchRoute(url, prefetchData, probability = 0.8, manifestHash, prefetchBundle = true) {
33
- if (!isBrowser) {
32
+ if (!isBrowser || isDev) {
34
33
  return;
35
34
  }
36
35
  try {
@@ -70,14 +69,12 @@ async function prefetchRoute(url, prefetchData, probability = 0.8, manifestHash,
70
69
  }
71
70
  }
72
71
 
73
- const __vite_import_meta_env__ = {};
74
72
  const Link = /* @__PURE__ */ componentQrl(/* @__PURE__ */ inlinedQrl((props) => {
75
73
  const nav = useNavigate();
76
74
  const loc = useLocation();
77
75
  const head = useDocumentHead();
78
76
  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;
77
+ const { onClick$, prefetch: prefetchProp, reload, replaceState, scroll, prefetchBundles: prefetchBundlesProp = "visible", prefetchData: prefetchDataProp = prefetchProp === "js" ? "off" : "intent", ...linkProps } = props;
81
78
  const clientNavPath = untrack(getClientNavPath, {
82
79
  ...linkProps,
83
80
  reload
@@ -85,7 +82,10 @@ const Link = /* @__PURE__ */ componentQrl(/* @__PURE__ */ inlinedQrl((props) =>
85
82
  linkProps.href = clientNavPath || originalHref;
86
83
  const isDepratedPrefetchDisabled = prefetchProp === false;
87
84
  const shouldPrefetch = untrack(shouldPreload, clientNavPath, loc);
88
- const shouldPrefetchBundle = !!clientNavPath && prefetchBundleProp !== "off" && shouldPrefetch && !isDepratedPrefetchDisabled;
85
+ const shouldVisiblePrefetchBundles = !!clientNavPath && shouldPrefetch && !isDepratedPrefetchDisabled && (prefetchBundlesProp === "visible" || // deprecated prop below, remove in favor of prefetchBundles
86
+ prefetchProp === "js" || prefetchProp === true);
87
+ const shouldVisiblePrefetchData = !!clientNavPath && shouldPrefetch && !isDepratedPrefetchDisabled && (prefetchDataProp === "visible" || // deprecated prop below, remove in favor of prefetchData
88
+ prefetchProp === true);
89
89
  const shouldPrefetchData = !!clientNavPath && prefetchDataProp !== "off" && shouldPrefetch && !isDepratedPrefetchDisabled;
90
90
  const handleDataPrefetch = shouldPrefetchData ? /* @__PURE__ */ inlinedQrl((_, elm) => {
91
91
  const head2 = _captures[0];
@@ -142,46 +142,11 @@ const Link = /* @__PURE__ */ componentQrl(/* @__PURE__ */ inlinedQrl((props) =>
142
142
  const url = new URL(elm.href);
143
143
  prefetchRoute(url, false, 1);
144
144
  }, "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
145
  return /* @__PURE__ */ _jsxSplit("a", {
181
- ref: anchorRef,
182
146
  "q:link": !!clientNavPath,
183
147
  ..._getVarProps(linkProps),
184
148
  ..._getConstProps(linkProps),
149
+ "data-q-prefetch": shouldVisiblePrefetchBundles && shouldVisiblePrefetchData ? "bd" : shouldVisiblePrefetchBundles ? "b" : shouldVisiblePrefetchData ? "d" : null,
185
150
  "q-e:click": [
186
151
  preventDefault,
187
152
  handlePreload,
@@ -204,10 +169,7 @@ const Link = /* @__PURE__ */ componentQrl(/* @__PURE__ */ inlinedQrl((props) =>
204
169
  linkProps.onKeyDown$,
205
170
  prefetchDataProp === "commit" ? onEnterKeyDown : null
206
171
  ]
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");
172
+ }, null, /* @__PURE__ */ _jsxSorted(Slot, null, null, null, 3, "jO_0"), 0, "jO_1");
211
173
  }, "Link_component_VPmar9tb3t4"));
212
174
 
213
175
  const newScrollState = () => {
@@ -234,8 +196,78 @@ const clientNavigate = (win, navType, fromURL, toURL, replaceState = false) => {
234
196
  }
235
197
  }
236
198
  };
199
+ const preloadRouteBundles = (path, probability = 0.8) => {
200
+ if (isBrowser) {
201
+ path = ensureSlash(path);
202
+ path = path.length > 1 && path.startsWith("/") ? path.slice(1) : path;
203
+ p(path, probability);
204
+ }
205
+ };
237
206
 
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}}}";
207
+ let prefetchedLinks = /* @__PURE__ */ new WeakSet();
208
+ let cleanupPrefetchObserver;
209
+ const resetLinkPrefetchState = () => {
210
+ prefetchedLinks = /* @__PURE__ */ new WeakSet();
211
+ };
212
+ const createLinkPrefetchObserver = (manifestHash) => {
213
+ const anchors = document.querySelectorAll("a[q\\:link][data-q-prefetch]");
214
+ const prefetchAnchor = (anchor, observer2) => {
215
+ if (prefetchedLinks.has(anchor)) {
216
+ return;
217
+ }
218
+ prefetchedLinks.add(anchor);
219
+ observer2?.unobserve(anchor);
220
+ if (navigator.connection?.saveData || !anchor.href) {
221
+ return;
222
+ }
223
+ let url;
224
+ try {
225
+ url = new URL(anchor.href);
226
+ } catch {
227
+ return;
228
+ }
229
+ const currentUrl = new URL(location.href);
230
+ if (!isSameOrigin(url, currentUrl) || !shouldPreload(toPath(url), {
231
+ url: currentUrl
232
+ })) {
233
+ return;
234
+ }
235
+ const mode = anchor.getAttribute("data-q-prefetch") || "";
236
+ if (mode.includes("b")) {
237
+ preloadRouteBundles(url.pathname);
238
+ }
239
+ if (mode.includes("d")) {
240
+ prefetchRoute(url, true, 0.8, manifestHash, false);
241
+ }
242
+ };
243
+ if (typeof IntersectionObserver === "undefined") {
244
+ anchors.forEach((anchor) => prefetchAnchor(anchor));
245
+ return () => {
246
+ };
247
+ }
248
+ const observer = new IntersectionObserver((entries) => {
249
+ for (const entry of entries) {
250
+ if (entry.isIntersecting) {
251
+ prefetchAnchor(entry.target, observer);
252
+ }
253
+ }
254
+ });
255
+ anchors.forEach((anchor) => observer.observe(anchor));
256
+ return () => {
257
+ observer.disconnect();
258
+ };
259
+ };
260
+ const refreshLinkPrefetchObserver = (manifestHash) => {
261
+ resetLinkPrefetchState();
262
+ cleanupPrefetchObserver?.();
263
+ cleanupPrefetchObserver = createLinkPrefetchObserver(manifestHash);
264
+ };
265
+ const linkPrefetchInit = (manifestHash) => eventQrl(/* @__PURE__ */ inlinedQrl(() => {
266
+ const manifestHash2 = _captures[0];
267
+ refreshLinkPrefetchObserver(manifestHash2);
268
+ }, "linkPrefetchInit_event_hoZr9O26Irg", [
269
+ manifestHash
270
+ ]));
239
271
 
240
272
  function callRestoreScrollOnDocument() {
241
273
  if (document.__q_scroll_restore__) {
@@ -469,7 +501,7 @@ async function submitAction(action, routePath) {
469
501
  }
470
502
  if ((response.headers.get("content-type") || "").includes("json")) {
471
503
  const text = await response.text();
472
- const data = _deserialize(text);
504
+ const data = await _deserialize(text);
473
505
  return {
474
506
  status: response.status,
475
507
  result: data?.result,
@@ -480,8 +512,22 @@ async function submitAction(action, routePath) {
480
512
  return void 0;
481
513
  }
482
514
 
515
+ 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}}}";
516
+
517
+ const shouldStartViewTransition = (viewTransition) => viewTransition === true && "startViewTransition" in document;
518
+ const VIEW_TRANSITION_STYLE_ID = "qwik-view-transition";
519
+ const ensureViewTransitionStyles = () => {
520
+ if (document.getElementById(VIEW_TRANSITION_STYLE_ID)) {
521
+ return;
522
+ }
523
+ const style = document.createElement("style");
524
+ style.id = VIEW_TRANSITION_STYLE_ID;
525
+ style.textContent = transitionCss;
526
+ document.head.appendChild(style);
527
+ };
483
528
  const startViewTransition = (params) => {
484
529
  if ("startViewTransition" in document) {
530
+ ensureViewTransitionStyles();
485
531
  let transition;
486
532
  try {
487
533
  transition = document.startViewTransition(params);
@@ -538,14 +584,12 @@ const useQwikMockRouter = (props) => {
538
584
  deep: false
539
585
  });
540
586
  for (const [loaderId, data] of Object.entries(loadersData ?? {})) {
541
- loadersState[loaderId] ||= createAsyncQrl(/* @__PURE__ */ inlinedQrl(async () => {
587
+ loadersState[loaderId] ||= createComputedQrl(/* @__PURE__ */ inlinedQrl(() => {
542
588
  const data2 = _captures[0];
543
589
  return data2;
544
- }, "useQwikMockRouter_createAsync_clbxpuXqpEU", [
590
+ }, "useQwikMockRouter_createComputed_JL6bChMwwyc", [
545
591
  data
546
- ]), {
547
- initial: data
548
- });
592
+ ]));
549
593
  }
550
594
  const goto = props.goto ?? /* @__PURE__ */ inlinedQrl(async () => {
551
595
  console.warn("QwikRouterMockProvider: goto not provided");
@@ -703,7 +747,6 @@ const useQwikRouter = (props) => {
703
747
  if (!isServer) {
704
748
  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
749
  }
706
- useStylesQrl(/* @__PURE__ */ inlinedQrl(transitionCss, "qwik_view_transition_css_inline_vNfd9raIMI0"));
707
750
  const env = useQwikRouterEnv();
708
751
  if (!env?.params) {
709
752
  throw new Error(`Missing Qwik Router Env Data for help visit https://github.com/QwikDev/qwik/issues/6237`);
@@ -726,6 +769,7 @@ const useQwikRouter = (props) => {
726
769
  });
727
770
  const navResolver = {};
728
771
  const routeLoaderCtx = useStore(env.routeLoaderCtx);
772
+ routeLoaderCtx.manifestHash = manifestHash;
729
773
  const loaderState = {};
730
774
  const contentModulesForInit = env.loadedRoute.$mods$;
731
775
  const loaders = ensureRouteLoaderSignals(contentModulesForInit, loaderState, routeLoaderCtx);
@@ -810,15 +854,14 @@ const useQwikRouter = (props) => {
810
854
  if (navResolver2.p && !forceReload && typeof dest !== "number" && isSamePath(dest, lastDest) && dest.href === lastDest.href) {
811
855
  return navResolver2.p;
812
856
  }
813
- internalState.navCount++;
857
+ const navCount = ++internalState.navCount;
814
858
  internalState.currentTransition?.skipTransition();
815
859
  if (preventNav.$cbs$ && (forceReload || typeof dest === "number" || !isSamePath(dest, lastDest) || !isSameOrigin(dest, lastDest))) {
816
- const ourNavId = internalState.navCount;
817
860
  const prevents = await Promise.all([
818
861
  ...preventNav.$cbs$.values()
819
862
  ].map((cb) => cb(dest)));
820
- if (ourNavId !== internalState.navCount || prevents.some(Boolean)) {
821
- if (ourNavId === internalState.navCount && type === "popstate") {
863
+ if (navCount !== internalState.navCount || prevents.some(Boolean)) {
864
+ if (navCount === internalState.navCount && type === "popstate") {
822
865
  history.pushState(null, "", lastDest);
823
866
  }
824
867
  return;
@@ -864,6 +907,15 @@ const useQwikRouter = (props) => {
864
907
  clientNavigate(window, type, new URL(location.href), dest, replaceState);
865
908
  historyUpdated = true;
866
909
  }
910
+ routeLocation2.isNavigating = true;
911
+ const container = isBrowser ? _getContextContainer() : void 0;
912
+ if (container) {
913
+ await _waitUntilRendered(container);
914
+ if (navCount !== internalState.navCount) {
915
+ return;
916
+ }
917
+ }
918
+ actionState2.value = void 0;
867
919
  routeInternal2.value = {
868
920
  type,
869
921
  dest,
@@ -875,8 +927,6 @@ const useQwikRouter = (props) => {
875
927
  if (isBrowser) {
876
928
  prefetchRoute(dest, true, 0.8, manifestHash2);
877
929
  }
878
- actionState2.value = void 0;
879
- routeLocation2.isNavigating = true;
880
930
  navResolver2.p = new Promise((resolve) => {
881
931
  navResolver2.r = () => {
882
932
  navResolver2.r = void 0;
@@ -951,11 +1001,6 @@ const useQwikRouter = (props) => {
951
1001
  };
952
1002
  return;
953
1003
  }
954
- actionData = {
955
- status: result.status,
956
- action: action.id,
957
- actionResult: result.result
958
- };
959
1004
  if (action.resolve) {
960
1005
  action.resolve({
961
1006
  status: result.status,
@@ -963,6 +1008,17 @@ const useQwikRouter = (props) => {
963
1008
  });
964
1009
  action.resolve = void 0;
965
1010
  }
1011
+ if (result.redirect) {
1012
+ goto2(result.redirect, {
1013
+ replaceState: true
1014
+ });
1015
+ return;
1016
+ }
1017
+ actionData = {
1018
+ status: result.status,
1019
+ action: action.id,
1020
+ actionResult: result.result
1021
+ };
966
1022
  actionLoaderHashes = result.loaderHashes;
967
1023
  shouldInvalidateActionLoaders = true;
968
1024
  }
@@ -988,7 +1044,7 @@ const useQwikRouter = (props) => {
988
1044
  if (routeLoaders.length > 0) {
989
1045
  for (let i = 0; i < routeLoaders.length; i++) {
990
1046
  const loader = routeLoaders[i];
991
- loaderState2[loader.__id].untrackedLoading;
1047
+ loaderState2[loader.__id].untrackedPending;
992
1048
  }
993
1049
  }
994
1050
  if (internalState.navCount !== navCountBefore) {
@@ -1064,6 +1120,7 @@ const useQwikRouter = (props) => {
1064
1120
  navContext2.value = noSerialize({
1065
1121
  routeName: $routeName$,
1066
1122
  navType,
1123
+ prevUrl,
1067
1124
  replaceState,
1068
1125
  shouldForcePrevUrl,
1069
1126
  shouldForceUrl,
@@ -1115,7 +1172,7 @@ const useQwikRouter = (props) => {
1115
1172
  deferUpdates: isServer
1116
1173
  });
1117
1174
  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];
1175
+ 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
1176
  const nav = track(navContext2);
1120
1177
  if (isServer || !nav) {
1121
1178
  return;
@@ -1125,9 +1182,8 @@ const useQwikRouter = (props) => {
1125
1182
  }
1126
1183
  const container = _getContextContainer();
1127
1184
  const navigation = routeInternal2.untrackedValue;
1128
- const { navType, replaceState, routeName } = nav;
1185
+ const { navType, prevUrl, replaceState, routeName } = nav;
1129
1186
  const trackUrl = routeLocation2.url;
1130
- const prevUrl = routeLocation2.prevUrl ?? trackUrl;
1131
1187
  const scroller = getScroller();
1132
1188
  let scrollState;
1133
1189
  if (navType === "popstate") {
@@ -1169,7 +1225,7 @@ const useQwikRouter = (props) => {
1169
1225
  return navigatePromise = _waitUntilRendered(container);
1170
1226
  };
1171
1227
  const _waitNextPage = () => {
1172
- if (props2?.viewTransition === false || !("startViewTransition" in document)) {
1228
+ if (!shouldStartViewTransition(props2?.viewTransition)) {
1173
1229
  return navigate().then(() => void 0);
1174
1230
  }
1175
1231
  const { ready, transition } = startViewTransition({
@@ -1202,6 +1258,7 @@ const useQwikRouter = (props) => {
1202
1258
  saveScrollHistory(scrollState2);
1203
1259
  window._qRouterScrollEnabled = true;
1204
1260
  callRestoreScrollOnDocument();
1261
+ refreshLinkPrefetchObserver(manifestHash2);
1205
1262
  if (nav.shouldForcePrevUrl) {
1206
1263
  forceStoreEffects(routeLocation2, "prevUrl");
1207
1264
  }
@@ -1217,6 +1274,7 @@ const useQwikRouter = (props) => {
1217
1274
  }, "useQwikRouter_useTask_2_yw17chooOac", [
1218
1275
  contentInternal,
1219
1276
  goto,
1277
+ manifestHash,
1220
1278
  navContext,
1221
1279
  navResolver,
1222
1280
  props,
@@ -1246,6 +1304,7 @@ const RouterOutlet = /* @__PURE__ */ componentQrl(/* @__PURE__ */ inlinedQrl(()
1246
1304
  throw new Error("PrefetchServiceWorker component must be rendered on the server.");
1247
1305
  }
1248
1306
  const internalContext = useContext(ContentInternalContext);
1307
+ const head = useDocumentHead();
1249
1308
  const nav = useNavigate();
1250
1309
  const contents = internalContext.value;
1251
1310
  if (contents && contents.length > 0) {
@@ -1259,6 +1318,10 @@ const RouterOutlet = /* @__PURE__ */ componentQrl(/* @__PURE__ */ inlinedQrl(()
1259
1318
  return /* @__PURE__ */ _jsxSorted(Fragment, null, null, [
1260
1319
  cmp,
1261
1320
  !__EXPERIMENTAL__.noSPA && /* @__PURE__ */ _jsxSorted("script", {
1321
+ "q-d:qcinit": [
1322
+ spaInit,
1323
+ linkPrefetchInit(head.manifestHash)
1324
+ ],
1262
1325
  "q-d:qinit": _qrlSync(() => {
1263
1326
  ((w, h) => {
1264
1327
  if (!w._qcs) {
@@ -1274,9 +1337,7 @@ const RouterOutlet = /* @__PURE__ */ componentQrl(/* @__PURE__ */ inlinedQrl(()
1274
1337
  }, '()=>{((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
1338
  "q-d:qrouterpopstate": /* @__PURE__ */ inlinedQrl((event, _1, nav2) => handleRouterPopstate(nav2, event), "RouterOutlet_component_Fragment_script_q_d_qrouterpopstate_aRL6GvFyews"),
1276
1339
  "q:p": nav
1277
- }, {
1278
- "q-d:qcinit": spaInit
1279
- }, null, 6, "Fn_1")
1340
+ }, null, null, 6, "Fn_1")
1280
1341
  ], 1, "Fn_2");
1281
1342
  }
1282
1343
  return SkipRender;
@@ -1570,7 +1631,7 @@ const deserializeStream = async function* (stream, abortSignal) {
1570
1631
  const lines = buffer.split(/\n/);
1571
1632
  buffer = lines.pop();
1572
1633
  for (const line of lines) {
1573
- const deserializedData = _deserialize(line);
1634
+ const deserializedData = await _deserialize(line);
1574
1635
  yield deserializedData;
1575
1636
  }
1576
1637
  }
@@ -1658,7 +1719,7 @@ const serverQrl = (qrl, options) => {
1658
1719
  })();
1659
1720
  } else if (contentType === "application/qwik-json") {
1660
1721
  const str = await res.text();
1661
- const obj = _deserialize(str);
1722
+ const obj = await _deserialize(str);
1662
1723
  if (res.status >= 400) {
1663
1724
  throw obj;
1664
1725
  }
@@ -1888,4 +1949,4 @@ const DocumentHeadTags = /* @__PURE__ */ componentQrl(/* @__PURE__ */ inlinedQrl
1888
1949
  ], 1, "r5_3");
1889
1950
  }, "DocumentHeadTags_component_9CrWYOoCpgY"));
1890
1951
 
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 };
1952
+ 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 */
@@ -5,7 +5,9 @@ import { createReadStream } from 'node:fs';
5
5
  import { join, basename, extname } from 'node:path';
6
6
  import { fileURLToPath } from 'node:url';
7
7
  import { n as normalizeRequestUrl, M as MIME_TYPES } from '../../chunks/url.mjs';
8
+ import { d as devPreloadedRouteLoaders } from '../../chunks/dev-preloaded-route-loader.mjs';
8
9
  import { Http2ServerRequest } from 'node:http2';
10
+ import { D as DEFAULT_REQUEST_BODY_LIMIT, v as validateRequestBodyLimit, R as RequestBodyLimitError } from '../../chunks/request-body-limit.mjs';
9
11
 
10
12
  function fallbackOrigin(req) {
11
13
  const { PROTOCOL_HEADER, HOST_HEADER } = process.env;
@@ -184,7 +186,8 @@ function createNodeResponseSink(res) {
184
186
  close
185
187
  };
186
188
  }
187
- async function fromNodeHttp(url, req, res, mode, getClientConn) {
189
+ async function fromNodeHttp(url, req, res, mode, getClientConn, requestBodyLimit = DEFAULT_REQUEST_BODY_LIMIT) {
190
+ validateRequestBodyLimit(requestBodyLimit);
188
191
  const requestHeaders = new Headers();
189
192
  const nodeRequestHeaders = req.headers;
190
193
  try {
@@ -204,7 +207,14 @@ async function fromNodeHttp(url, req, res, mode, getClientConn) {
204
207
  console.error(err);
205
208
  }
206
209
  const getRequestBody = async function* () {
210
+ let received = 0;
207
211
  for await (const chunk of req) {
212
+ const byteLength = typeof chunk === "string" ? Buffer.byteLength(chunk) : chunk.byteLength;
213
+ if (byteLength > requestBodyLimit - received) {
214
+ req.resume();
215
+ throw new RequestBodyLimitError(requestBodyLimit);
216
+ }
217
+ received += byteLength;
208
218
  yield chunk;
209
219
  }
210
220
  };
@@ -280,13 +290,28 @@ function createQwikRouter(opts) {
280
290
  setServerPlatform(opts.manifest);
281
291
  }
282
292
  const staticFolder = opts.static?.root ?? join(fileURLToPath(import.meta.url), "..", "..", "dist");
283
- const router = async (req, res, next) => {
293
+ const router = async (req, res, next, limits = {}) => {
284
294
  try {
285
295
  const origin = computeOrigin(req, opts);
286
- const serverRequestEv = await fromNodeHttp(getUrl(req, origin), req, res, "server", opts.getClientConn);
296
+ let requestBodyLimit = opts.requestBodyLimit;
297
+ if (limits?.bodyLimit !== void 0) {
298
+ if (requestBodyLimit === void 0) {
299
+ requestBodyLimit = limits.bodyLimit;
300
+ } else {
301
+ requestBodyLimit = Math.min(requestBodyLimit, limits.bodyLimit);
302
+ }
303
+ }
304
+ const serverRequestEv = await fromNodeHttp(getUrl(req, origin), req, res, "server", opts.getClientConn, requestBodyLimit);
287
305
  if (isDev && opts.platform) {
288
306
  Object.assign(serverRequestEv.platform, opts.platform);
289
307
  }
308
+ if (isDev) {
309
+ const loader = devPreloadedRouteLoaders.get(req);
310
+ if (loader) {
311
+ devPreloadedRouteLoaders.set(serverRequestEv.request, loader);
312
+ devPreloadedRouteLoaders.delete(req);
313
+ }
314
+ }
290
315
  const handled = await requestHandler(serverRequestEv, opts);
291
316
  if (handled) {
292
317
  const err = await handled.completion;