@qwik.dev/router 2.0.0-beta.45 → 2.0.0-beta.47

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.
@@ -1,13 +1,11 @@
1
- import { $ as basePathname, B as DocumentHeadContext, C as getRequestEvent, F as routeLoaderQrl, G as RouteNavigateContext, H as RouteActionContext, I as setLoaderSignalValue, J as QACTION_KEY, K as RoutePreventNavigateContext, N as restoreRouteLoaders, O as isImmutableLoader, P as routeLoader$, R as ContentContext, S as getModuleRouteLoaders, U as RouteLoaderCtxContext, V as HttpStatusContext, W as RouteLocationContext, X as QFN_KEY, Y as QDATA_KEY, Z as Q_ROUTE, _ as commitRouteLoaders, a as isPromise, b as getClientRouteLoaders, c as shouldPreload, d as loadRoute, h as clearNavFetchCache, i as getClientNavPath, j as prepareRouteLoaders, l as toPath, m as abortRouteLoaderNavigation, n as resolveHead, o as isSameOrigin, q as RouteStateContext, s as isSamePath, t as createDocumentHead, u as toUrl, v as ensureRouteLoaderSignals, y as fetchRouteLoaderData, z as ContentInternalContext } from "./chunks/head.qwik.mjs";
2
1
  import { t as ensureSlash } from "./chunks/pathname.mjs";
3
- import { SkipRender, Slot, _captures, _fnSignal, _getConstProps, _getVarProps, _jsxSorted, _jsxSplit, _qrlSync, _restProps, _wrapProp, componentQrl, createComputedQrl, createElement, eventQrl, getLocale, implicit$FirstArg, inlinedQrl, isBrowser, isDev, isServer, noSerialize, untrack, useContext, useContextProvider, useServerData, useSignal, useStore, useTaskQrl, useVisibleTaskQrl, withLocale } from "@qwik.dev/core";
4
- import { p } from "@qwik.dev/core/preloader";
5
- import { _deserialize, _getContextContainer, _getContextHostElement, _hasStoreEffects, _serialize, _waitUntilRendered, forceStoreEffects } from "@qwik.dev/core/internal";
2
+ import { $ as RoutePreventNavigateContext, B as _setRouterConfig, C as getRequestEvent, F as routeLoader$, G as ContentContext, H as getRouterConfig, I as routeLoaderQrl, J as HttpStatusContext, K as ContentInternalContext, L as setLoaderSignalValue, M as prepareRouteLoaders, P as restoreRouteLoaders, Q as RouteNavigateContext, S as getModuleRouteLoaders, U as getRoutes, V as getBasePathname, W as getTrailingSlash, X as RouteLoaderCtxContext, Y as RouteActionContext, Z as RouteLocationContext, _ as commitRouteLoaders, a as isPromise, b as getClientRouteLoaders, c as shouldPreload, d as loadRoute, et as RouteStateContext, h as clearNavFetchCache, i as getClientNavPath, it as Q_ROUTE, k as isImmutableLoader, l as toPath, m as abortRouteLoaderNavigation, n as resolveHead, nt as QDATA_KEY, o as isSameOrigin, q as DocumentHeadContext, rt as QFN_KEY, s as isSamePath, t as createDocumentHead, tt as QACTION_KEY, u as toUrl, v as ensureRouteLoaderSignals, y as fetchRouteLoaderData, z as _getServiceWorkerUrl } from "./chunks/head.qwik.mjs";
3
+ import { SkipRender, Slot, _capturesObj, _fnSignal, _getConstProps, _getVarProps, _jsxSorted, _jsxSplit, _qrlSync, _restProps, _wrapProp, componentQrl, createComputedQrl, createElement, eventQrl, getLocale, implicit$FirstArg, inlinedQrl, isBrowser, isDev, isServer, noSerialize, untrack, useContext, useContextProvider, useServerData, useSignal, useStore, useTaskQrl, useVisibleTaskQrl, withLocale } from "@qwik.dev/core";
4
+ import { _deserialize, _getContextContainer, _getContextHostElement, _hasStoreEffects, _regInlinedQrl, _requestPreload, _serialize, _waitUntilRendered, forceStoreEffects } from "@qwik.dev/core/internal";
6
5
  import { Fragment } from "@qwik.dev/core/jsx-runtime";
7
6
  import * as v from "valibot";
8
7
  import * as z$1 from "zod";
9
8
  import { z } from "zod";
10
- import swRegister from "@qwik-router-sw-register";
11
9
  import { renderToStream } from "@qwik.dev/core/server";
12
10
  /**
13
11
  * Prefetch a route's JS bundles and optionally its loader data.
@@ -25,14 +23,14 @@ import { renderToStream } from "@qwik.dev/core/server";
25
23
  async function prefetchRoute(url, prefetchData, probability = .8, manifestHash, prefetchBundle = true) {
26
24
  if (!isBrowser || isDev) return;
27
25
  try {
28
- const qwikRouterConfig = await import("@qwik-router-config");
29
- const loadedRoute = await loadRoute(qwikRouterConfig.routes, qwikRouterConfig.cacheModules, url.pathname);
26
+ const { routes, cacheModules } = await getRouterConfig();
27
+ const loadedRoute = await loadRoute(routes, cacheModules, url.pathname);
30
28
  if (!loadedRoute) return;
31
29
  if (prefetchBundle) {
32
30
  let routeName = loadedRoute.$routeName$;
33
31
  routeName = ensureSlash(routeName);
34
32
  if (routeName.length > 1 && routeName.startsWith("/")) routeName = routeName.slice(1);
35
- p(routeName, probability);
33
+ _requestPreload(routeName, probability);
36
34
  }
37
35
  if (!prefetchData || !manifestHash) return;
38
36
  prefetchLoaderData(loadedRoute, url, manifestHash);
@@ -47,7 +45,7 @@ async function prefetchRoute(url, prefetchData, probability = .8, manifestHash,
47
45
  var prefetchLoaderData = (loadedRoute, url, manifestHash) => {
48
46
  if (!loadedRoute.$loaders$?.length || !loadedRoute.$loaderPaths$) return;
49
47
  const immutableIds = new Set(getModuleRouteLoaders(loadedRoute.$mods$).filter((loader) => loader.__cacheControl === "immutable").map((loader) => loader.__id));
50
- const basePath = basePathname;
48
+ const basePath = getBasePathname();
51
49
  for (const hash of loadedRoute.$loaders$) {
52
50
  if (immutableIds.has(hash)) continue;
53
51
  let loaderPath = loadedRoute.$loaderPaths$[hash];
@@ -77,7 +75,7 @@ var useNavigate = () => useContext(RouteNavigateContext);
77
75
  var usePreventNavigateQrl = (fn) => {
78
76
  const registerPreventNav = useContext(RoutePreventNavigateContext);
79
77
  useVisibleTaskQrl(/*#__PURE__*/ inlinedQrl(() => {
80
- const fn = _captures[0], registerPreventNav = _captures[1];
78
+ let fn = _capturesObj._[0], registerPreventNav = _capturesObj._[1];
81
79
  return registerPreventNav(fn);
82
80
  }, "usePreventNavigateQrl_useVisibleTask_BsYUaz9XhUs", [fn, registerPreventNav]));
83
81
  };
@@ -133,8 +131,14 @@ var Link = /*#__PURE__*/ componentQrl(/*#__PURE__*/ inlinedQrl((props) => {
133
131
  const shouldPrefetch = untrack(shouldPreload, clientNavPath, loc);
134
132
  const shouldVisiblePrefetchBundles = !!clientNavPath && shouldPrefetch && !isDepratedPrefetchDisabled && (prefetchBundlesProp === "visible" || prefetchProp === "js" || prefetchProp === true);
135
133
  const shouldVisiblePrefetchData = !!clientNavPath && shouldPrefetch && !isDepratedPrefetchDisabled && (prefetchDataProp === "visible" || prefetchProp === true);
136
- const handleDataPrefetch = !!clientNavPath && prefetchDataProp !== "off" && shouldPrefetch && !isDepratedPrefetchDisabled ? /*#__PURE__*/ inlinedQrl((_, elm) => {
137
- const head = _captures[0];
134
+ const shouldPrefetchBundles = !!clientNavPath && prefetchBundlesProp !== "off" && shouldPrefetch && !isDepratedPrefetchDisabled;
135
+ const shouldPrefetchData = !!clientNavPath && prefetchDataProp !== "off" && shouldPrefetch && !isDepratedPrefetchDisabled;
136
+ const handleBundlePrefetch = shouldPrefetchBundles ? /*#__PURE__*/ inlinedQrl((_, elm) => {
137
+ if (navigator.connection?.saveData) return;
138
+ if (elm && elm.href) prefetchRoute(new URL(elm.href), false, .8);
139
+ }, "Link_component_handleBundlePrefetch_ZttUP0kLKj0") : null;
140
+ const handleDataPrefetch = shouldPrefetchData ? /*#__PURE__*/ inlinedQrl((_, elm) => {
141
+ let head = _capturesObj._[0];
138
142
  if (navigator.connection?.saveData) return;
139
143
  if (elm && elm.href) prefetchRoute(new URL(elm.href), true, .8, head.manifestHash, false);
140
144
  }, "Link_component_handleDataPrefetch_lcd4O9LHbbA", [head]) : null;
@@ -142,15 +146,22 @@ var Link = /*#__PURE__*/ componentQrl(/*#__PURE__*/ inlinedQrl((props) => {
142
146
  if (!(event.metaKey || event.ctrlKey || event.shiftKey || event.altKey)) event.preventDefault();
143
147
  }, "event=>{if(!(event.metaKey||event.ctrlKey||event.shiftKey||event.altKey)){event.preventDefault();}}") : null;
144
148
  const prefetchData = /*#__PURE__*/ inlinedQrl(async (_, elm) => {
145
- const handleDataPrefetch = _captures[0];
149
+ let handleDataPrefetch = _capturesObj._[0];
146
150
  handleDataPrefetch?.(null, elm);
147
151
  }, "Link_component_prefetchData_UwVx4NhHkSo", [handleDataPrefetch]);
148
152
  const onEnterKeyDown = /*#__PURE__*/ inlinedQrl((event, element) => {
149
- const prefetchData = _captures[0];
150
- if (event.key === "Enter") prefetchData(null, element);
151
- }, "Link_component_onEnterKeyDown_z274ws00irY", [prefetchData]);
153
+ let handleBundlePrefetch = _capturesObj._[0], prefetchBundlesProp = _capturesObj._[1], prefetchData = _capturesObj._[2], prefetchDataProp = _capturesObj._[3];
154
+ if (event.key !== "Enter") return;
155
+ if (prefetchDataProp === "commit") prefetchData(null, element);
156
+ if (prefetchBundlesProp === "commit") handleBundlePrefetch?.(null, element);
157
+ }, "Link_component_onEnterKeyDown_z274ws00irY", [
158
+ handleBundlePrefetch,
159
+ prefetchBundlesProp,
160
+ prefetchData,
161
+ prefetchDataProp
162
+ ]);
152
163
  const handleClientSideNavigation = clientNavPath ? /*#__PURE__*/ inlinedQrl((event, elm) => {
153
- const nav = _captures[0], reload = _captures[1], replaceState = _captures[2], scroll = _captures[3];
164
+ let nav = _capturesObj._[0], reload = _capturesObj._[1], replaceState = _capturesObj._[2], scroll = _capturesObj._[3];
154
165
  if (event.defaultPrevented) {
155
166
  if (elm.href) {
156
167
  elm.setAttribute("aria-pressed", "true");
@@ -182,10 +193,22 @@ var Link = /*#__PURE__*/ componentQrl(/*#__PURE__*/ inlinedQrl((props) => {
182
193
  onClick$,
183
194
  handleClientSideNavigation
184
195
  ],
185
- "q-e:pointerenter": [linkProps.onMouseOver$, prefetchDataProp === "intent" ? prefetchData : null],
186
- "q-e:focus": [linkProps.onFocus$, prefetchDataProp === "intent" ? prefetchData : null],
187
- "q-e:pointerdown": [linkProps.onPointerDown$, prefetchDataProp === "commit" ? prefetchData : null],
188
- "q-e:keydown": [linkProps.onKeyDown$, prefetchDataProp === "commit" ? onEnterKeyDown : null]
196
+ "q-e:pointerenter": [
197
+ linkProps.onPointerEnter$,
198
+ prefetchDataProp === "intent" ? prefetchData : null,
199
+ prefetchBundlesProp === "intent" ? handleBundlePrefetch : null
200
+ ],
201
+ "q-e:focus": [
202
+ linkProps.onFocus$,
203
+ prefetchDataProp === "intent" ? prefetchData : null,
204
+ prefetchBundlesProp === "intent" ? handleBundlePrefetch : null
205
+ ],
206
+ "q-e:pointerdown": [
207
+ linkProps.onPointerDown$,
208
+ prefetchDataProp === "commit" ? prefetchData : null,
209
+ prefetchBundlesProp === "commit" ? handleBundlePrefetch : null
210
+ ],
211
+ "q-e:keydown": [linkProps.onKeyDown$, prefetchDataProp === "commit" || prefetchBundlesProp === "commit" ? onEnterKeyDown : null]
189
212
  }, null, /*#__PURE__*/ _jsxSorted(Slot, null, null, null, 3, "xa_0"), 0, "xa_1");
190
213
  }, "Link_component_VPmar9tb3t4"));
191
214
  var clientNavigate = (win, navType, fromURL, toURL, replaceState = false) => {
@@ -211,7 +234,7 @@ var preloadRouteBundles = (path, probability = .8) => {
211
234
  if (isBrowser) {
212
235
  path = ensureSlash(path);
213
236
  path = path.length > 1 && path.startsWith("/") ? path.slice(1) : path;
214
- p(path, probability);
237
+ _requestPreload(path, probability);
215
238
  }
216
239
  };
217
240
  var prefetchedLinks = /* @__PURE__ */ new WeakSet();
@@ -550,7 +573,7 @@ var useQwikRouter = (props) => {
550
573
  });
551
574
  const contentInternal = useSignal();
552
575
  /**
553
- * Non-serializable navigation context passed from the nav task to the head+commit task. Only the
576
+ * Non-serializable navigation context passed from the nav task to the navigation task. Only the
554
577
  * data that can't be derived from existing stores/signals.
555
578
  */
556
579
  const navContext = useSignal();
@@ -605,7 +628,7 @@ var useQwikRouter = (props) => {
605
628
  * make sure to change the address bar before awaiting anything.
606
629
  */
607
630
  const goto = /*#__PURE__*/ inlinedQrl(async (path, opt) => {
608
- const actionState = _captures[0], manifestHash = _captures[1], navResolver = _captures[2], routeInternal = _captures[3], routeLoaderCtx = _captures[4], routeLocation = _captures[5];
631
+ let actionState = _capturesObj._[0], manifestHash = _capturesObj._[1], navResolver = _capturesObj._[2], routeInternal = _capturesObj._[3], routeLoaderCtx = _capturesObj._[4], routeLocation = _capturesObj._[5];
609
632
  const { type = "link", forceReload = path === void 0, replaceState = false, scroll = true } = typeof opt === "object" ? opt : { forceReload: opt };
610
633
  if (isBrowser && type === "link" && routeInternal.value.type === "initial") {
611
634
  const url = new URL(window.location.href);
@@ -709,9 +732,11 @@ var useQwikRouter = (props) => {
709
732
  * before we trigger the render, and we need to subscribe only head to loader signal updates
710
733
  */
711
734
  useTaskQrl(/*#__PURE__*/ inlinedQrl(async ({ track }) => {
712
- const actionDataSignal = _captures[0], actionState = _captures[1], content = _captures[2], contentInternal = _captures[3], env = _captures[4], goto = _captures[5], httpStatus = _captures[6], loaderState = _captures[7], navContext = _captures[8], navResolver = _captures[9], routeInternal = _captures[10], routeLoaderCtx = _captures[11], routeLocation = _captures[12], routeLocationTarget = _captures[13];
735
+ let actionDataSignal = _capturesObj._[0], actionState = _capturesObj._[1], content = _capturesObj._[2], contentInternal = _capturesObj._[3], env = _capturesObj._[4], goto = _capturesObj._[5], httpStatus = _capturesObj._[6], loaderState = _capturesObj._[7], navContext = _capturesObj._[8], navResolver = _capturesObj._[9], routeInternal = _capturesObj._[10], routeLoaderCtx = _capturesObj._[11], routeLocation = _capturesObj._[12], routeLocationTarget = _capturesObj._[13];
713
736
  const navigation = track(routeInternal);
714
737
  const action = track(actionState);
738
+ action?.resolveDispatch?.();
739
+ if (action) action.resolveDispatch = void 0;
715
740
  const prevUrl = routeLocation.url;
716
741
  const navType = action ? "form" : navigation.type;
717
742
  const replaceState = navigation.replaceState;
@@ -734,7 +759,7 @@ var useQwikRouter = (props) => {
734
759
  if (trackUrl.pathname.endsWith("/")) {
735
760
  if (globalThis.__NO_TRAILING_SLASH__) trackUrl.pathname = trackUrl.pathname.slice(0, -1);
736
761
  } else if (!globalThis.__NO_TRAILING_SLASH__) trackUrl.pathname = ensureSlash(trackUrl.pathname);
737
- const loadRoutePromise = import("@qwik-router-config").then((config) => {
762
+ const loadRoutePromise = getRouterConfig().then((config) => {
738
763
  if (internalState.navCount !== navCountBefore) return;
739
764
  return loadRoute(config.routes, config.cacheModules, trackUrl.pathname);
740
765
  });
@@ -879,7 +904,7 @@ var useQwikRouter = (props) => {
879
904
  * Note that on the server these tasks run sequentially.
880
905
  */
881
906
  useTaskQrl(/*#__PURE__*/ inlinedQrl(({ track }) => {
882
- const actionDataSignal = _captures[0], contentInternal = _captures[1], documentHead = _captures[2], loaderState = _captures[3], navContext = _captures[4], routeLocation = _captures[5], serverHead = _captures[6];
907
+ let actionDataSignal = _capturesObj._[0], contentInternal = _capturesObj._[1], documentHead = _capturesObj._[2], loaderState = _capturesObj._[3], navContext = _capturesObj._[4], routeLocation = _capturesObj._[5], serverHead = _capturesObj._[6];
883
908
  const contentModules = track(contentInternal);
884
909
  const nav = navContext.untrackedValue;
885
910
  if (!isServer && routeLocation.isNavigating && nav && nav.navCount !== internalState.navCount) return;
@@ -910,7 +935,7 @@ var useQwikRouter = (props) => {
910
935
  ]), { deferUpdates: isServer });
911
936
  /** Actual navigation */
912
937
  useTaskQrl(/*#__PURE__*/ inlinedQrl(({ track }) => {
913
- const contentInternal = _captures[0], goto = _captures[1], loaderState = _captures[2], manifestHash = _captures[3], navContext = _captures[4], navResolver = _captures[5], props = _captures[6], routeInternal = _captures[7], routeLoaderCtx = _captures[8], routeLocation = _captures[9];
938
+ let contentInternal = _capturesObj._[0], goto = _capturesObj._[1], loaderState = _capturesObj._[2], manifestHash = _capturesObj._[3], navContext = _capturesObj._[4], navResolver = _capturesObj._[5], props = _capturesObj._[6], routeInternal = _capturesObj._[7], routeLoaderCtx = _capturesObj._[8], routeLocation = _capturesObj._[9];
914
939
  const nav = track(navContext);
915
940
  if (isServer || !nav) return;
916
941
  if (nav.navCount !== internalState.navCount) return;
@@ -1089,7 +1114,7 @@ var useQwikMockRouter = (props) => {
1089
1114
  }, {});
1090
1115
  const loadersState = useStore({}, { deep: false });
1091
1116
  for (const [loaderId, data] of Object.entries(loadersData ?? {})) loadersState[loaderId] ||= createComputedQrl(/*#__PURE__*/ inlinedQrl(() => {
1092
- return _captures[0];
1117
+ return _capturesObj._[0];
1093
1118
  }, "useQwikMockRouter_createComputed_JL6bChMwwyc", [data]));
1094
1119
  const goto = props.goto ?? /*#__PURE__*/ inlinedQrl(async () => {
1095
1120
  console.warn("QwikRouterMockProvider: goto not provided");
@@ -1118,8 +1143,10 @@ var useQwikMockRouter = (props) => {
1118
1143
  return acc;
1119
1144
  }, {});
1120
1145
  useTaskQrl(/*#__PURE__*/ inlinedQrl(async ({ track }) => {
1121
- const actionState = _captures[0], actionsMocks = _captures[1];
1146
+ let actionState = _capturesObj._[0], actionsMocks = _capturesObj._[1];
1122
1147
  const action = track(actionState);
1148
+ action?.resolveDispatch?.();
1149
+ if (action) action.resolveDispatch = void 0;
1123
1150
  if (!action?.resolve) return;
1124
1151
  const mock = actionsMocks?.[action.id];
1125
1152
  if (mock) {
@@ -1178,9 +1205,9 @@ var RouterOutlet = /*#__PURE__*/ componentQrl(/*#__PURE__*/ inlinedQrl(() => {
1178
1205
  return SkipRender;
1179
1206
  }, "RouterOutlet_component_QwONcWD5gIg"));
1180
1207
  /**
1181
- * Hoisted function declarations (not consts) on purpose, like `routeLoaderQrl`: generated route
1182
- * modules call these factories back during their own evaluation via the `@qwik-router-config`
1183
- * cycle, where a `const` binding would throw a TDZ ReferenceError.
1208
+ * Hoisted function declarations (not consts) on purpose, like `routeLoaderQrl`: the app's route
1209
+ * modules call these factories during their own evaluation, which a bundle may run before this
1210
+ * module, where a `const` binding would throw a TDZ ReferenceError.
1184
1211
  *
1185
1212
  * @public
1186
1213
  */
@@ -1211,7 +1238,7 @@ function routeActionQrl(actionQrl, ...rest) {
1211
1238
  return initialState;
1212
1239
  });
1213
1240
  initialState.submit = /* @__PURE__ */ inlinedQrl((input = {}) => {
1214
- const currentAction = _captures[0], id = _captures[1], latestSubmission = _captures[2], loc = _captures[3], state = _captures[4];
1241
+ let currentAction = _capturesObj._[0], id = _capturesObj._[1], latestSubmission = _capturesObj._[2], loc = _capturesObj._[3], state = _capturesObj._[4];
1215
1242
  if (isServer) throw new Error(`Actions can not be invoked within the server during SSR.
1216
1243
  Action.run() can only be called on the browser, for example when a user clicks a button, or submits a form.`);
1217
1244
  let data;
@@ -1225,7 +1252,12 @@ Action.run() can only be called on the browser, for example when a user clicks a
1225
1252
  } else data = input;
1226
1253
  const submission = {};
1227
1254
  latestSubmission.current = submission;
1228
- return new Promise((resolve) => {
1255
+ const previousDispatch = currentAction.pendingDispatch ?? Promise.resolve();
1256
+ let resolveDispatch;
1257
+ currentAction.pendingDispatch = noSerialize(new Promise((resolve) => {
1258
+ resolveDispatch = resolve;
1259
+ }));
1260
+ return previousDispatch.then(() => new Promise((resolve) => {
1229
1261
  if (data instanceof FormData) state.formData = data;
1230
1262
  state.submitted = true;
1231
1263
  state.isRunning = true;
@@ -1233,9 +1265,10 @@ Action.run() can only be called on the browser, for example when a user clicks a
1233
1265
  currentAction.value = {
1234
1266
  data,
1235
1267
  id,
1236
- resolve: noSerialize(resolve)
1268
+ resolve: noSerialize(resolve),
1269
+ resolveDispatch: noSerialize(resolveDispatch)
1237
1270
  };
1238
- }).then(({ result, status }) => {
1271
+ })).then(({ result, status }) => {
1239
1272
  const isLatestSubmission = latestSubmission.current === submission;
1240
1273
  if (isLatestSubmission) {
1241
1274
  state.isRunning = false;
@@ -1404,6 +1437,7 @@ var zod$ = /*#__PURE__*/ implicit$FirstArg(zodQrl);
1404
1437
  /** @internal */
1405
1438
  function serverQrl(qrl, options) {
1406
1439
  if (isServer) {
1440
+ _regInlinedQrl(qrl);
1407
1441
  const captured = qrl.getCaptured();
1408
1442
  if (captured && captured.length > 0 && !_getContextHostElement()) throw new Error("For security reasons, we cannot serialize QRLs that capture lexical scope.");
1409
1443
  }
@@ -1412,7 +1446,7 @@ function serverQrl(qrl, options) {
1412
1446
  const origin = options?.origin || "";
1413
1447
  const fetchOptions = options?.fetchOptions || {};
1414
1448
  return /*#__PURE__*/ inlinedQrl(async function(...args) {
1415
- const fetchOptions = _captures[0], headers = _captures[1], method = _captures[2], origin = _captures[3], qrl = _captures[4];
1449
+ let fetchOptions = _capturesObj._[0], headers = _capturesObj._[1], method = _capturesObj._[2], origin = _capturesObj._[3], qrl = _capturesObj._[4];
1416
1450
  const abortSignal = args.length > 0 && args[0] instanceof AbortSignal ? args.shift() : void 0;
1417
1451
  if (isServer) return qrl.apply(getRequestEvent(this), args);
1418
1452
  else {
@@ -1521,6 +1555,10 @@ var deserializeStream = async function* (stream, abortSignal) {
1521
1555
  reader.releaseLock();
1522
1556
  }
1523
1557
  };
1558
+ var SW_REGISTER = `(()=>{if("serviceWorker"in navigator){navigator.serviceWorker.register("__url").catch(e=>console.error(e));"caches"in window&&caches.keys().then(r=>{const e=r.find(c=>c.startsWith("QwikBuild"));e&&caches.delete(e).catch(console.error)}).catch(console.error)}else console.log("Service worker not supported in this browser.")})()`;
1559
+ var SW_UNREGISTER = `"serviceWorker"in navigator&&navigator.serviceWorker.getRegistrations().then(r=>{for(const e of r){const c="__url".split("/").pop();e.active?.scriptURL.endsWith(c||"service-worker.js")&&e.unregister().catch(console.error)}}),"caches"in window&&caches.keys().then(r=>{const e=r.find(c=>c.startsWith("QwikBuild"));e&&caches.delete(e).catch(console.error)}).catch(console.error)`;
1560
+ /** @internal */
1561
+ var _getServiceWorkerScript = (serviceWorkerUrl) => (serviceWorkerUrl ? SW_REGISTER : SW_UNREGISTER).replace("__url", serviceWorkerUrl ?? "/service-worker.js");
1524
1562
  /**
1525
1563
  * Loads the service workers that are defined in the routes. Any file named `service-worker.*` (all
1526
1564
  * JS extensions are allowed) will be picked up, bundled into a separate file, and registered as a
@@ -1534,10 +1572,10 @@ var deserializeStream = async function* (stream, abortSignal) {
1534
1572
  *
1535
1573
  * @public
1536
1574
  */
1537
- var ServiceWorkerRegister = (props) => /*#__PURE__*/ _jsxSorted("script", { nonce: _wrapProp(props, "nonce") }, {
1538
- type: "module",
1539
- dangerouslySetInnerHTML: swRegister
1540
- }, null, 3, "UM_0");
1575
+ var ServiceWorkerRegister = (props) => /*#__PURE__*/ _jsxSorted("script", {
1576
+ dangerouslySetInnerHTML: _getServiceWorkerScript(_getServiceWorkerUrl()),
1577
+ nonce: _wrapProp(props, "nonce")
1578
+ }, { type: "module" }, null, 3, "UM_0");
1541
1579
  var _hf0 = (p0) => p0.spaReset ? "true" : void 0;
1542
1580
  var _hf0_str = "p0.spaReset?\"true\":undefined";
1543
1581
  /** @public */
@@ -1549,7 +1587,7 @@ var Form = ({ action, spaReset, reloadDocument, onSubmit$, ...rest }, key) => {
1549
1587
  action: _wrapProp(action, "actionPath"),
1550
1588
  "preventdefault:submit": !reloadDocument,
1551
1589
  "q-e:submit": [...onSubmit$, !reloadDocument ? /*#__PURE__*/ inlinedQrl((evt) => {
1552
- const action = _captures[0];
1590
+ let action = _capturesObj._[0];
1553
1591
  if (!action.submitted) return action.submit(evt);
1554
1592
  }, "Form_form_q_e_submit_6i0Jq5q8JFg", [action]) : void 0],
1555
1593
  ["data-spa-reset"]: spaReset ? "true" : void 0
@@ -1585,7 +1623,7 @@ var GetForm = /*#__PURE__*/ componentQrl(/*#__PURE__*/ inlinedQrl((_rawProps) =>
1585
1623
  "q-e:submit": [
1586
1624
  ...Array.isArray(_rawProps.onSubmit$) ? _rawProps.onSubmit$ : [_rawProps.onSubmit$],
1587
1625
  /*#__PURE__*/ inlinedQrl(async (_evt, form) => {
1588
- const nav = _captures[0];
1626
+ let nav = _capturesObj._[0];
1589
1627
  const formData = new FormData(form);
1590
1628
  const params = new URLSearchParams();
1591
1629
  formData.forEach((value, key) => {
@@ -1737,4 +1775,4 @@ var DocumentHeadTags = /*#__PURE__*/ componentQrl(/*#__PURE__*/ inlinedQrl((prop
1737
1775
  })
1738
1776
  ], 1, "eL_3");
1739
1777
  }, "DocumentHeadTags_component_9CrWYOoCpgY"));
1740
- export { DocumentHeadTags, Form, Link, QWIK_CITY_SCROLLER, QWIK_ROUTER_SCROLLER, QwikCityMockProvider, QwikCityProvider, QwikRouterMockProvider, QwikRouterProvider, RouterOutlet, ServiceWorkerRegister, createRenderer, getRequestEvent, globalAction$, globalActionQrl, omitProps, routeAction$, routeActionQrl, routeLoader$, routeLoaderQrl, server$, serverQrl, untypedAppUrl, useContent, useDocumentHead, useHttpStatus, useLocation, useNavigate, usePreventNavigate$, usePreventNavigateQrl, useQwikRouter, valibot$, valibotQrl, validator$, validatorQrl, z, zod$, zodQrl };
1778
+ export { DocumentHeadTags, Form, Link, QWIK_CITY_SCROLLER, QWIK_ROUTER_SCROLLER, QwikCityMockProvider, QwikCityProvider, QwikRouterMockProvider, QwikRouterProvider, RouterOutlet, ServiceWorkerRegister, _getServiceWorkerScript, _setRouterConfig, createRenderer, getBasePathname, getRequestEvent, getRouterConfig, getRoutes, getTrailingSlash, globalAction$, globalActionQrl, omitProps, routeAction$, routeActionQrl, routeLoader$, routeLoaderQrl, server$, serverQrl, untypedAppUrl, useContent, useDocumentHead, useHttpStatus, useLocation, useNavigate, usePreventNavigate$, usePreventNavigateQrl, useQwikRouter, valibot$, valibotQrl, validator$, validatorQrl, z, zod$, zodQrl };
@@ -18,8 +18,13 @@ export declare class AbortMessage {
18
18
  readonly __controlFlow: true;
19
19
  }
20
20
 
21
- /** @internal */
22
- export declare let _asyncRequestStore: AsyncLocalStorage<RequestEventInternal> | undefined;
21
+ /**
22
+ * Shared with the router copy of a Qwik library kept external on the server, so its
23
+ * `getRequestEvent()` and `server$` see the request the app is serving.
24
+ *
25
+ * @internal
26
+ */
27
+ export declare const _asyncRequestStore: AsyncLocalStorage<RequestEventInternal> | undefined;
23
28
 
24
29
  /** @public */
25
30
  export declare type CacheControl = CacheControlOptions | number | 'day' | 'week' | 'month' | 'year' | 'no-cache' | 'immutable' | 'private';
@@ -399,8 +404,16 @@ declare interface LoadedRoute {
399
404
  $loaders$?: string[];
400
405
  /** Runtime-only mapping of routeLoader$ hashes to the matched pathname used for q-loader fetches */
401
406
  $loaderPaths$?: Record<string, string>;
407
+ /** Runtime-only mapping of routeLoader$ hashes to params matched at their loader path */
408
+ $loaderParams$?: Record<string, PathParams>;
409
+ }
410
+
411
+ declare interface MenuModule {
412
+ readonly default: ContentMenu;
402
413
  }
403
414
 
415
+ declare type MenuModuleLoader = () => Promise<MenuModule>;
416
+
404
417
  /** @public */
405
418
  export declare const mergeHeadersCookies: (headers: Headers, cookies: Cookie) => Headers;
406
419
 
@@ -422,6 +435,25 @@ declare type PathParams = Record<string, string>;
422
435
 
423
436
  declare type QwikRouterCompletion = Error | undefined | object;
424
437
 
438
+ /** @public */
439
+ declare interface QwikRouterConfig {
440
+ readonly routes: RouteData;
441
+ readonly serverPlugins?: RouteModule[];
442
+ readonly basePathname?: string;
443
+ readonly trailingSlash?: boolean;
444
+ readonly cacheModules?: boolean;
445
+ /** When true, return null instead of rendering the 404 page, letting the adapter handle it */
446
+ readonly fallthrough?: boolean;
447
+ /**
448
+ * Imports the modules containing `server$` functions so their registration side effects run.
449
+ * Called by the request handler before serving; deliberately async so the config module itself
450
+ * evaluates without touching the runtime (see the import-cycle notes in `route-loaders.ts`).
451
+ */
452
+ readonly importEagerModules?: () => Promise<unknown>;
453
+ /** URL of the app's service worker, when the routes define one. */
454
+ readonly serviceWorkerUrl?: string;
455
+ }
456
+
425
457
  declare interface QwikRouterRun<T> {
426
458
  response: Promise<T | null>;
427
459
  requestEv: RequestEvent_2;
@@ -632,6 +664,7 @@ export declare interface RequestEventCommon<PLATFORM = QwikRouterPlatform> exten
632
664
  declare interface RequestEventInternal extends Readonly<RequestEvent>, Readonly<RequestEventLoader> {
633
665
  readonly [RequestEvMode]: ServerRequestMode;
634
666
  readonly [RequestEvRoute]: LoadedRoute;
667
+ readonly [RequestEvRouterConfig]: QwikRouterConfig | undefined;
635
668
  /**
636
669
  * Check if this request is already written to.
637
670
  *
@@ -658,6 +691,9 @@ declare const RequestEvMode: unique symbol;
658
691
 
659
692
  declare const RequestEvRoute: unique symbol;
660
693
 
694
+ /** The request event's key for the config of the app serving it. */
695
+ declare const RequestEvRouterConfig: unique symbol;
696
+
661
697
  /** @public */
662
698
  export declare type RequestHandler<PLATFORM = QwikRouterPlatform> = (ev: RequestEvent<PLATFORM>) => Promise<void | AbortMessage | ServerError> | void | AbortMessage | ServerError;
663
699
 
@@ -714,6 +750,60 @@ declare interface RouteConfigValue {
714
750
  readonly cacheKey?: CacheKeyFn;
715
751
  }
716
752
 
753
+ /**
754
+ * A nested route trie structure. The root represents `/` and each level represents a URL segment.
755
+ *
756
+ * Keys starting with a single `_` are metadata; all other keys are child route segments. A static
757
+ * segment that starts with `_` is stored with an extra `_` (`_drafts` → `__drafts`).
758
+ *
759
+ * - Use `_W` as the key for a single dynamic segment (param); `_P` on that node names the param.
760
+ * - Use `_A` as the key for a rest/catch-all segment; `_P` on that node names the param.
761
+ * - For infix params like `pre[slug]post`, use `_W` with `_0` (prefix) and `_9` (suffix).
762
+ * - Use `_M` for an array of group (pathless layout) nodes, sorted by group name.
763
+ *
764
+ * When matching, exact segments are tried first (case-insensitive), then `_W` (with optional
765
+ * prefix/suffix), then `_A`. When no route matches, the closest `_E` (error.tsx) or `_4` (404.tsx)
766
+ * loader in the ancestor chain is used to render the error page.
767
+ *
768
+ * @public
769
+ */
770
+ declare interface RouteData {
771
+ /** This node's layout loader (single). Runtime accumulates these during trie traversal. */
772
+ _L?: ContentModuleLoader;
773
+ /**
774
+ * This node's index/page loader. Single = normal (runtime prepends gathered _L). Array = override
775
+ * (layout stop / named layout — IS the complete chain).
776
+ */
777
+ _I?: ContentModuleLoader | ModuleLoader[];
778
+ /** Rewrite/goto target path. Matcher re-walks trie from root using this path's keys. */
779
+ _G?: string;
780
+ /** The JS bundle names for this route (SSR only) */
781
+ _B?: string[];
782
+ /**
783
+ * Not-found (404) boundary: single loader (runtime prepends layouts) or override chain
784
+ * (`404@layout`/`!`).
785
+ */
786
+ _4?: ContentModuleLoader | ModuleLoader[];
787
+ /** Error (error.tsx) boundary, same single-or-override-chain shape as `_4`. */
788
+ _E?: ContentModuleLoader | ModuleLoader[];
789
+ /** The parameter name when this node is reached via `_W` or `_A` from the parent */
790
+ _P?: string;
791
+ /** Prefix for infix params (e.g. "pre" for `pre[slug]post`) — only on `_W` nodes */
792
+ _0?: string;
793
+ /** Suffix for infix params (e.g. "post" for `pre[slug]post`) — only on `_W` nodes */
794
+ _9?: string;
795
+ /** Group (pathless layout) nodes merged into this level, sorted by group name */
796
+ _M?: RouteData[];
797
+ /** Menu loader for this subtree (from menu.md). Runtime uses nearest ancestor during traversal. */
798
+ _N?: MenuModuleLoader;
799
+ /** Inherited layout and server plugin routeLoader$ hashes. */
800
+ _R?: string[];
801
+ /** Page loader hashes; override pages include their selected layouts and plugins. */
802
+ _D?: string[];
803
+ /** Child route segments (any key not starting with a single `_`) */
804
+ [part: string]: RouteData | RouteData[] | ModuleLoader[] | ContentModuleLoader | MenuModuleLoader | string[] | string | undefined;
805
+ }
806
+
717
807
  /** @public */
718
808
  declare interface RouteLocation {
719
809
  readonly params: Readonly<Record<string, string>>;
@@ -766,6 +856,16 @@ export declare interface ServerRenderOptions extends RenderOptions {
766
856
  * Defaults to `true`.
767
857
  */
768
858
  checkOrigin?: boolean | 'lax-proto';
859
+ /**
860
+ * Use the `X-Forwarded-Host` and `X-Forwarded-Proto` request headers to compute the URL exposed
861
+ * by `useLocation()` during SSR.
862
+ *
863
+ * Only enable this when the server is behind a proxy that overwrites these headers, otherwise
864
+ * clients can spoof the URL.
865
+ *
866
+ * Defaults to `false`.
867
+ */
868
+ trustForwardedHeaders?: boolean;
769
869
  }
770
870
 
771
871
  /**
@@ -1,37 +1,22 @@
1
- import { Q as _asyncRequestStore, d as loadRoute } from "../../chunks/head.qwik.mjs";
1
+ import { H as getRouterConfig, d as loadRoute, ot as _asyncRequestStore } from "../../chunks/head.qwik.mjs";
2
2
  import { c as resolveValidInternalFullPathname, l as trimInternalPathname, s as recognizeRequest, u as trimRecognizedInternalPathname } from "../../chunks/request-path.mjs";
3
3
  import { i as RedirectMessage, r as AbortMessage, t as ServerError } from "../../chunks/server-error.mjs";
4
4
  import { t as devPreloadedRouteLoaders } from "../../chunks/dev-preloaded-route-loader.mjs";
5
5
  import { a as getStaticPathRedirect, c as clearSsrCache, d as mergeHeadersCookies, i as resolveRequestHandlers, n as getErrorHtml, o as isStaticPath, r as renderQwikMiddleware, s as clearLoaderCache, t as runQwikRouter, u as RewriteMessage } from "../../chunks/user-response.mjs";
6
6
  import { isDev } from "@qwik.dev/core";
7
- var qwikRouterConfig;
8
- async function getConfig() {
9
- if (isDev) {
10
- const config = await import("@qwik-router-config");
11
- await config.importEagerModules?.();
12
- return config;
13
- }
14
- if (!qwikRouterConfig) {
15
- const config = await import("@qwik-router-config");
16
- await config.importEagerModules?.();
17
- qwikRouterConfig = config;
18
- }
19
- return qwikRouterConfig;
20
- }
21
7
  /**
22
8
  * The request handler for QwikRouter. Called by every adapter.
23
9
  *
24
10
  * @public
25
11
  */
26
12
  async function requestHandler(serverRequestEv, opts) {
27
- const { render, checkOrigin } = opts;
28
- const config = await getConfig();
13
+ const config = await getRouterConfig();
29
14
  const pathname = getRequestHandlerPathname(serverRequestEv);
30
15
  if (pathname === "/.well-known" || pathname.startsWith("/.well-known/")) return null;
31
16
  const staticPathRedirect = getStaticPathRedirect(serverRequestEv.request.method, serverRequestEv.url);
32
17
  const rebuildRouteInfo = async (url) => {
33
18
  const cleanPathname = trimInternalPathname(url.pathname);
34
- return loadRequestHandlers(config, cleanPathname, serverRequestEv.request.method, checkOrigin ?? true, render, serverRequestEv);
19
+ return loadRequestHandlers(config, cleanPathname, serverRequestEv.request.method, opts, serverRequestEv);
35
20
  };
36
21
  if (staticPathRedirect) return runQwikRouter(serverRequestEv, {
37
22
  $routeName$: pathname,
@@ -39,10 +24,10 @@ async function requestHandler(serverRequestEv, opts) {
39
24
  $mods$: []
40
25
  }, [(event) => {
41
26
  throw event.redirect(301, staticPathRedirect);
42
- }], rebuildRouteInfo, config.basePathname);
43
- const { loadedRoute, requestHandlers } = await loadRequestHandlers(config, pathname, serverRequestEv.request.method, checkOrigin ?? true, render, serverRequestEv);
27
+ }], rebuildRouteInfo, config.basePathname, config);
28
+ const { loadedRoute, requestHandlers } = await loadRequestHandlers(config, pathname, serverRequestEv.request.method, opts, serverRequestEv);
44
29
  if (config.fallthrough && loadedRoute.$notFound$) return null;
45
- return runQwikRouter(serverRequestEv, loadedRoute, requestHandlers, rebuildRouteInfo, config.basePathname);
30
+ return runQwikRouter(serverRequestEv, loadedRoute, requestHandlers, rebuildRouteInfo, config.basePathname, config);
46
31
  }
47
32
  function getRequestHandlerPathname(serverRequestEv, isDevRequest = isDev) {
48
33
  const recognized = recognizeRequest(serverRequestEv.url.pathname);
@@ -52,7 +37,7 @@ function getRequestHandlerPathname(serverRequestEv, isDevRequest = isDev) {
52
37
  const routePath = serverRequestEv.request.headers.get("X-Qwik-fullpath") ?? (isDevRequest ? serverRequestEv.request.headers.get("X-Qwik-route-path") : null);
53
38
  return resolveValidInternalFullPathname(loaderPathname, routePath) ?? loaderPathname;
54
39
  }
55
- async function loadRequestHandlers(qwikRouterConfig, pathname, method, checkOrigin, renderFn, serverRequestEv) {
40
+ async function loadRequestHandlers(qwikRouterConfig, pathname, method, opts, serverRequestEv) {
56
41
  const { routes, serverPlugins, cacheModules } = qwikRouterConfig;
57
42
  const loadedRoute = await loadRoute(routes, cacheModules, pathname);
58
43
  const loader = isDev ? devPreloadedRouteLoaders.get(serverRequestEv.request) : void 0;
@@ -60,7 +45,7 @@ async function loadRequestHandlers(qwikRouterConfig, pathname, method, checkOrig
60
45
  if (loader && lastModule) loadedRoute.$mods$[loadedRoute.$mods$.length - 1] = Object.assign({}, lastModule, { __preloadedRouteLoader: loader });
61
46
  return {
62
47
  loadedRoute,
63
- requestHandlers: resolveRequestHandlers(serverPlugins, loadedRoute, method, checkOrigin, renderQwikMiddleware(renderFn))
48
+ requestHandlers: resolveRequestHandlers(serverPlugins, loadedRoute, method, opts.checkOrigin ?? true, renderQwikMiddleware(opts.render, opts.trustForwardedHeaders))
64
49
  };
65
50
  }
66
51
  /**
package/lib/ssg/index.mjs CHANGED
@@ -1,4 +1,5 @@
1
1
  import { n as getPathnameForDynamicRoute, t as ensureSlash } from "../chunks/pathname.mjs";
2
+ import { n as isStaticTrieKey, r as unescapeStaticTrieKey } from "../chunks/route-trie-key.mjs";
2
3
  import { r as msToString } from "../chunks/format.mjs";
3
4
  import { t as createRouteTester } from "../chunks/routes.mjs";
4
5
  import { relative } from "node:path";
@@ -171,8 +172,8 @@ async function mainThread(sys) {
171
172
  await traverseRouteTree(childNode, [...pathParts, pathPart], basePathname, currentLoaders);
172
173
  }
173
174
  for (const [key, child] of Object.entries(node)) {
174
- if (key.charCodeAt(0) === 95) continue;
175
- await traverseRouteTree(child, [...pathParts, key], basePathname, currentLoaders);
175
+ if (!isStaticTrieKey(key)) continue;
176
+ await traverseRouteTree(child, [...pathParts, unescapeStaticTrieKey(key)], basePathname, currentLoaders);
176
177
  }
177
178
  };
178
179
  const loadStaticRoutes = async () => {