@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
@@ -0,0 +1,317 @@
1
+ import { _serialize } from '@qwik.dev/core/internal';
2
+ import { parentPort } from 'node:worker_threads';
3
+ import { r as runQwikRouter, a as resolveRequestHandlers, b as renderQwikMiddleware } from './user-response.mjs';
4
+ import { b as trimInternalPathname } from './request-path.mjs';
5
+ import { A as getRouteLoaders, B as getRouteLoaderValues, l as loadRoute } from './head.qwik.mjs';
6
+
7
+ const staticWorkerThreadDeps = {
8
+ loadRoute,
9
+ renderQwikMiddleware,
10
+ resolveRequestHandlers,
11
+ trimInternalPathname,
12
+ runQwikRouter
13
+ };
14
+ const createNoopWritableStream = () => new WritableStream();
15
+ function isRedirectMessage(value) {
16
+ return typeof value === "object" && value !== null && value.constructor?.name === "RedirectMessage";
17
+ }
18
+ async function requestHandlerForSsg(serverRequestEv, opts, deps) {
19
+ const { render, checkOrigin, qwikRouterConfig } = opts;
20
+ if (!qwikRouterConfig) {
21
+ throw new Error("qwikRouterConfig is required.");
22
+ }
23
+ const pathname = deps.trimInternalPathname(serverRequestEv.url.pathname);
24
+ if (pathname === "/.well-known" || pathname.startsWith("/.well-known/")) {
25
+ return null;
26
+ }
27
+ const { routes, serverPlugins, cacheModules } = qwikRouterConfig;
28
+ const loadedRoute = await deps.loadRoute(routes, cacheModules, pathname);
29
+ const requestHandlers = deps.resolveRequestHandlers(serverPlugins, loadedRoute, serverRequestEv.request.method, checkOrigin ?? true, deps.renderQwikMiddleware(render));
30
+ if (qwikRouterConfig.fallthrough && loadedRoute.$notFound$ && !pathname.endsWith("/404.html")) {
31
+ return null;
32
+ }
33
+ const rebuildRouteInfo = async (url) => {
34
+ const cleanPathname = deps.trimInternalPathname(url.pathname);
35
+ const loadedRoute2 = await deps.loadRoute(routes, cacheModules, cleanPathname);
36
+ const requestHandlers2 = deps.resolveRequestHandlers(serverPlugins, loadedRoute2, serverRequestEv.request.method, checkOrigin ?? true, deps.renderQwikMiddleware(render));
37
+ return {
38
+ loadedRoute: loadedRoute2,
39
+ requestHandlers: requestHandlers2
40
+ };
41
+ };
42
+ return deps.runQwikRouter(serverRequestEv, loadedRoute, requestHandlers, rebuildRouteInfo, qwikRouterConfig.basePathname);
43
+ }
44
+ async function workerRender(sys, opts, staticRoute, pendingPromises, callback, deps) {
45
+ const url = new URL(staticRoute.pathname, opts.origin);
46
+ const result = {
47
+ type: "render",
48
+ pathname: staticRoute.pathname,
49
+ url: url.href,
50
+ ok: false,
51
+ error: null,
52
+ filePath: null,
53
+ contentType: null,
54
+ resourceType: null
55
+ };
56
+ try {
57
+ let routeWriter = null;
58
+ let closeResolved;
59
+ const closePromise = new Promise((closePromiseResolve) => {
60
+ closeResolved = closePromiseResolve;
61
+ });
62
+ const request = new Request(url);
63
+ const requestCtx = {
64
+ mode: "static",
65
+ locale: void 0,
66
+ url,
67
+ request,
68
+ env: {
69
+ get(key) {
70
+ return sys.getEnv(key);
71
+ }
72
+ },
73
+ platform: sys.platform,
74
+ getClientConn: () => {
75
+ return {};
76
+ },
77
+ getWritableStream: (status, headers, _, _r, requestEv) => {
78
+ const isNotFoundPage = url.pathname.endsWith("/404.html");
79
+ result.ok = status >= 200 && status < 300 || isNotFoundPage && status === 404;
80
+ if (!result.ok) {
81
+ return createNoopWritableStream();
82
+ }
83
+ result.contentType = (headers.get("Content-Type") || "").toLowerCase();
84
+ const isHtml = result.contentType.includes("text/html");
85
+ const routeFilePath = sys.getRouteFilePath(url.pathname, isHtml);
86
+ if (isHtml) {
87
+ result.resourceType = "page";
88
+ }
89
+ const hasRouteWriter = isHtml ? opts.emitHtml !== false : true;
90
+ const writeLoaderDataEnabled = isHtml && opts.emitData !== false;
91
+ const stream = new WritableStream({
92
+ async start() {
93
+ try {
94
+ if (hasRouteWriter || writeLoaderDataEnabled) {
95
+ await sys.ensureDir(routeFilePath);
96
+ }
97
+ if (hasRouteWriter) {
98
+ routeWriter = sys.createWriteStream(routeFilePath);
99
+ routeWriter.on("error", (e) => {
100
+ console.error(e);
101
+ routeWriter = null;
102
+ result.error = {
103
+ message: e.message,
104
+ stack: e.stack
105
+ };
106
+ });
107
+ }
108
+ } catch (e) {
109
+ console.error("Error during stream start", staticRoute.pathname, e);
110
+ routeWriter = null;
111
+ result.error = {
112
+ message: String(e),
113
+ stack: e.stack || ""
114
+ };
115
+ }
116
+ },
117
+ write(chunk) {
118
+ try {
119
+ if (routeWriter) {
120
+ routeWriter.write(Buffer.from(chunk.buffer));
121
+ }
122
+ } catch (e) {
123
+ console.error("Error during stream write", staticRoute.pathname, e);
124
+ routeWriter = null;
125
+ result.error = {
126
+ message: String(e),
127
+ stack: e.stack || ""
128
+ };
129
+ }
130
+ },
131
+ async close() {
132
+ const writePromises = [];
133
+ try {
134
+ if (writeLoaderDataEnabled && !isNotFoundPage) {
135
+ const routeLoaders = getRouteLoaders(requestEv);
136
+ const loaderValues = getRouteLoaderValues(requestEv);
137
+ const manifestHash = opts.manifest?.manifestHash || "dev";
138
+ for (const loader of routeLoaders) {
139
+ if (loader.__expires !== 0) {
140
+ continue;
141
+ }
142
+ const data = loaderValues[loader.__id];
143
+ if (data === void 0) {
144
+ continue;
145
+ }
146
+ const loaderFilePath = sys.getLoaderFilePath(url.pathname, loader.__id, manifestHash);
147
+ const loaderWriter = sys.createWriteStream(loaderFilePath);
148
+ loaderWriter.on("error", (e) => {
149
+ console.error(e);
150
+ result.error = {
151
+ message: e.message,
152
+ stack: e.stack
153
+ };
154
+ });
155
+ const serialized = await deps.serialize({
156
+ d: data
157
+ });
158
+ loaderWriter.write(serialized);
159
+ writePromises.push(new Promise((resolve) => {
160
+ result.filePath = routeFilePath;
161
+ loaderWriter.end(resolve);
162
+ }));
163
+ }
164
+ }
165
+ if (routeWriter) {
166
+ writePromises.push(new Promise((resolve) => {
167
+ result.filePath = routeFilePath;
168
+ routeWriter.end(resolve);
169
+ }).finally(closeResolved));
170
+ }
171
+ if (writePromises.length > 0) {
172
+ await Promise.all(writePromises);
173
+ }
174
+ } catch (e) {
175
+ console.error("Error during stream close", staticRoute.pathname, e);
176
+ routeWriter = null;
177
+ result.error = {
178
+ message: String(e),
179
+ stack: e.stack || ""
180
+ };
181
+ }
182
+ }
183
+ });
184
+ return stream;
185
+ }
186
+ };
187
+ const promise = requestHandlerForSsg(requestCtx, opts, deps).then((rsp) => {
188
+ if (rsp != null) {
189
+ return rsp.completion.then((r) => {
190
+ if (routeWriter) {
191
+ return closePromise.then(() => r);
192
+ }
193
+ return r;
194
+ });
195
+ }
196
+ }).then((e) => {
197
+ if (e !== void 0) {
198
+ if (isRedirectMessage(e)) {
199
+ return;
200
+ }
201
+ if (e instanceof Error) {
202
+ result.error = {
203
+ message: e.message,
204
+ stack: e.stack
205
+ };
206
+ } else {
207
+ result.error = {
208
+ message: String(e),
209
+ stack: void 0
210
+ };
211
+ }
212
+ console.error("Error during request handling", staticRoute.pathname, e);
213
+ }
214
+ }).catch((e) => {
215
+ console.error("Unhandled error during request handling", staticRoute.pathname, e);
216
+ result.error = {
217
+ message: String(e),
218
+ stack: e.stack || ""
219
+ };
220
+ }).finally(() => {
221
+ pendingPromises.delete(promise);
222
+ callback(result);
223
+ });
224
+ pendingPromises.add(promise);
225
+ } catch (e) {
226
+ console.error("Error during render", staticRoute.pathname, e);
227
+ if (e instanceof Error) {
228
+ result.error = {
229
+ message: e.message,
230
+ stack: e.stack
231
+ };
232
+ } else {
233
+ result.error = {
234
+ message: String(e),
235
+ stack: void 0
236
+ };
237
+ }
238
+ callback(result);
239
+ }
240
+ }
241
+ async function workerThread(sys) {
242
+ const opts = sys.getOptions();
243
+ const pendingPromises = /* @__PURE__ */ new Set();
244
+ const deps = {
245
+ ...staticWorkerThreadDeps,
246
+ serialize: _serialize
247
+ };
248
+ process.on("uncaughtException", (e) => {
249
+ console.error("Worker uncaught exception (suppressed):", e.message);
250
+ });
251
+ process.on("unhandledRejection", (e) => {
252
+ console.error("Worker unhandled rejection (suppressed):", e instanceof Error ? e.message : e);
253
+ });
254
+ const onMessage = async (msg) => {
255
+ switch (msg.type) {
256
+ case "render": {
257
+ return new Promise((resolve) => {
258
+ workerRender(sys, opts, msg, pendingPromises, resolve, deps).catch((e) => {
259
+ console.error("Error during render", msg.pathname, e);
260
+ resolve({
261
+ type: "render",
262
+ pathname: msg.pathname,
263
+ url: "",
264
+ ok: false,
265
+ error: {
266
+ message: e instanceof Error ? e.message : String(e),
267
+ stack: e instanceof Error ? e.stack : void 0
268
+ },
269
+ filePath: null,
270
+ contentType: null,
271
+ resourceType: null
272
+ });
273
+ });
274
+ });
275
+ }
276
+ case "close": {
277
+ if (pendingPromises.size) {
278
+ const promises = Array.from(pendingPromises);
279
+ pendingPromises.clear();
280
+ await Promise.all(promises);
281
+ }
282
+ return {
283
+ type: "close"
284
+ };
285
+ }
286
+ }
287
+ };
288
+ parentPort?.on("message", async (msg) => {
289
+ try {
290
+ parentPort?.postMessage(await onMessage(msg));
291
+ } catch (e) {
292
+ if (msg.type === "render") {
293
+ const error = e instanceof Error ? e : new Error(String(e));
294
+ parentPort?.postMessage({
295
+ type: "render",
296
+ pathname: msg.pathname,
297
+ url: "",
298
+ ok: false,
299
+ error: {
300
+ message: error.message,
301
+ stack: error.stack
302
+ },
303
+ filePath: null,
304
+ contentType: null,
305
+ resourceType: null
306
+ });
307
+ } else {
308
+ console.error("Worker message handler error", e);
309
+ }
310
+ }
311
+ if (msg.type === "close") {
312
+ parentPort?.close();
313
+ }
314
+ });
315
+ }
316
+
317
+ export { workerThread };
package/lib/index.d.ts CHANGED
@@ -1,7 +1,8 @@
1
1
  /// <reference path="./modules.d.ts" />
2
2
 
3
- import type { AsyncSignal } from '@qwik.dev/core';
3
+ import type { AbortMessage } from '@qwik.dev/router/middleware/request-handler';
4
4
  import { Component } from '@qwik.dev/core';
5
+ import type { ComputedSignal } from '@qwik.dev/core';
5
6
  import { Cookie } from '@qwik.dev/router/middleware/request-handler';
6
7
  import { CookieOptions } from '@qwik.dev/router/middleware/request-handler';
7
8
  import { CookieValue } from '@qwik.dev/router/middleware/request-handler';
@@ -24,6 +25,7 @@ import { RequestEventLoader } from '@qwik.dev/router/middleware/request-handler'
24
25
  import { RequestHandler } from '@qwik.dev/router/middleware/request-handler';
25
26
  import type { ResolveSyncValue } from '@qwik.dev/router/middleware/request-handler';
26
27
  import type { SerializationStrategy } from '@qwik.dev/core/internal';
28
+ import type { ServerError } from '@qwik.dev/router/middleware/request-handler';
27
29
  import type { Signal } from '@qwik.dev/core';
28
30
  import type * as v from 'valibot';
29
31
  import type { ValueOrPromise } from '@qwik.dev/core';
@@ -38,51 +40,53 @@ export declare type Action<RETURN, INPUT = Record<string, unknown>, OPTIONAL ext
38
40
  * component$(). Like all `use-` functions and methods, it can only be invoked within a
39
41
  * `component$()`.
40
42
  */
41
- (): ActionStore<RETURN, INPUT, OPTIONAL>;
43
+ (): ActionStore<ExcludeControlFlow<RETURN>, INPUT, OPTIONAL>;
42
44
  };
43
45
 
44
46
  /** @public */
45
47
  export declare type ActionConstructor = {
46
- <OBJ extends Record<string, any> | void | null, VALIDATOR extends TypedDataValidator, REST extends [DataValidator, ...DataValidator[]]>(actionQrl: (data: GetValidatorOutputType<VALIDATOR>, event: RequestEventAction) => ValueOrPromise<OBJ>, options: {
47
- readonly id?: string;
48
+ <OBJ extends Record<string, any> | void | null, VALIDATOR extends TypedDataValidator, REST extends [DataValidator, ...DataValidator[]]>(actionQrl: (data: GetValidatorOutputType<VALIDATOR>, event: RequestEventAction) => ValueOrPromise<OBJ>, options: ActionOptions & {
48
49
  readonly validation: [VALIDATOR, ...REST];
49
50
  }): Action<StrictUnion<OBJ | FailReturn<ValidatorErrorType<GetValidatorInputType<VALIDATOR>>> | FailReturn<FailOfRest<REST>>>, GetValidatorInputType<VALIDATOR>, false>;
50
- <OBJ extends Record<string, any> | void | null, VALIDATOR extends TypedDataValidator>(actionQrl: (data: GetValidatorOutputType<VALIDATOR>, event: RequestEventAction) => ValueOrPromise<OBJ>, options: {
51
- readonly id?: string;
51
+ <OBJ extends Record<string, any> | void | null, VALIDATOR extends TypedDataValidator>(actionQrl: (data: GetValidatorOutputType<VALIDATOR>, event: RequestEventAction) => ValueOrPromise<OBJ>, options: ActionOptions & {
52
52
  readonly validation: [VALIDATOR];
53
53
  }): Action<StrictUnion<OBJ | FailReturn<ValidatorErrorType<GetValidatorInputType<VALIDATOR>>>>, GetValidatorInputType<VALIDATOR>, false>;
54
- <OBJ extends Record<string, any> | void | null, REST extends [DataValidator, ...DataValidator[]]>(actionQrl: (data: JSONObject, event: RequestEventAction) => ValueOrPromise<OBJ>, options: {
55
- readonly id?: string;
54
+ <OBJ extends Record<string, any> | void | null, REST extends [DataValidator, ...DataValidator[]]>(actionQrl: (data: JSONObject, event: RequestEventAction) => ValueOrPromise<OBJ>, options: ActionOptions & {
56
55
  readonly validation: REST;
57
56
  }): Action<StrictUnion<OBJ | FailReturn<FailOfRest<REST>>>>;
58
57
  <OBJ extends Record<string, any> | void | null, VALIDATOR extends TypedDataValidator, REST extends [DataValidator, ...DataValidator[]]>(actionQrl: (data: GetValidatorOutputType<VALIDATOR>, event: RequestEventAction) => ValueOrPromise<OBJ>, options: VALIDATOR, ...rest: REST): Action<StrictUnion<OBJ | FailReturn<ValidatorErrorType<GetValidatorInputType<VALIDATOR>>> | FailReturn<FailOfRest<REST>>>, GetValidatorInputType<VALIDATOR>, false>;
59
58
  <OBJ extends Record<string, any> | void | null, VALIDATOR extends TypedDataValidator>(actionQrl: (data: GetValidatorOutputType<VALIDATOR>, event: RequestEventAction) => ValueOrPromise<OBJ>, options: VALIDATOR): Action<StrictUnion<OBJ | FailReturn<ValidatorErrorType<GetValidatorInputType<VALIDATOR>>>>, GetValidatorInputType<VALIDATOR>, false>;
60
59
  <OBJ extends Record<string, any> | void | null, REST extends [DataValidator, ...DataValidator[]]>(actionQrl: (form: JSONObject, event: RequestEventAction) => ValueOrPromise<OBJ>, ...rest: REST): Action<StrictUnion<OBJ | FailReturn<FailOfRest<REST>>>>;
61
- <OBJ>(actionQrl: (form: JSONObject, event: RequestEventAction) => ValueOrPromise<OBJ>, options?: {
62
- readonly id?: string;
63
- }): Action<StrictUnion<OBJ>>;
60
+ <OBJ>(actionQrl: (form: JSONObject, event: RequestEventAction) => ValueOrPromise<OBJ>, options?: ActionOptions): Action<StrictUnion<OBJ>>;
64
61
  };
65
62
 
66
63
  /** @public */
67
64
  declare type ActionConstructorQRL = {
68
- <OBJ extends Record<string, any> | void | null, VALIDATOR extends TypedDataValidator, REST extends [DataValidator, ...DataValidator[]]>(actionQrl: QRL<(data: GetValidatorOutputType<VALIDATOR>, event: RequestEventAction) => ValueOrPromise<OBJ>>, options: {
69
- readonly id?: string;
65
+ <OBJ extends Record<string, any> | void | null, VALIDATOR extends TypedDataValidator, REST extends [DataValidator, ...DataValidator[]]>(actionQrl: QRL<(data: GetValidatorOutputType<VALIDATOR>, event: RequestEventAction) => ValueOrPromise<OBJ>>, options: ActionOptions & {
70
66
  readonly validation: [VALIDATOR, ...REST];
71
67
  }): Action<StrictUnion<OBJ | FailReturn<ValidatorErrorType<GetValidatorInputType<VALIDATOR>>> | FailReturn<FailOfRest<REST>>>, GetValidatorInputType<VALIDATOR>, false>;
72
- <OBJ extends Record<string, any> | void | null, VALIDATOR extends TypedDataValidator>(actionQrl: QRL<(data: GetValidatorOutputType<VALIDATOR>, event: RequestEventAction) => ValueOrPromise<OBJ>>, options: {
73
- readonly id?: string;
68
+ <OBJ extends Record<string, any> | void | null, VALIDATOR extends TypedDataValidator>(actionQrl: QRL<(data: GetValidatorOutputType<VALIDATOR>, event: RequestEventAction) => ValueOrPromise<OBJ>>, options: ActionOptions & {
74
69
  readonly validation: [VALIDATOR];
75
70
  }): Action<StrictUnion<OBJ | FailReturn<ValidatorErrorType<GetValidatorInputType<VALIDATOR>>>>, GetValidatorInputType<VALIDATOR>, false>;
76
- <OBJ extends Record<string, any> | void | null, REST extends [DataValidator, ...DataValidator[]]>(actionQrl: QRL<(data: JSONObject, event: RequestEventAction) => ValueOrPromise<OBJ>>, options: {
77
- readonly id?: string;
71
+ <OBJ extends Record<string, any> | void | null, REST extends [DataValidator, ...DataValidator[]]>(actionQrl: QRL<(data: JSONObject, event: RequestEventAction) => ValueOrPromise<OBJ>>, options: ActionOptions & {
78
72
  readonly validation: REST;
79
73
  }): Action<StrictUnion<OBJ | FailReturn<FailOfRest<REST>>>>;
80
74
  <OBJ extends Record<string, any> | void | null, VALIDATOR extends TypedDataValidator, REST extends [DataValidator, ...DataValidator[]]>(actionQrl: QRL<(data: GetValidatorOutputType<VALIDATOR>, event: RequestEventAction) => ValueOrPromise<OBJ>>, options: VALIDATOR, ...rest: REST): Action<StrictUnion<OBJ | FailReturn<ValidatorErrorType<GetValidatorInputType<VALIDATOR>>> | FailReturn<FailOfRest<REST>>>, GetValidatorInputType<VALIDATOR>, false>;
81
75
  <OBJ extends Record<string, any> | void | null, VALIDATOR extends TypedDataValidator>(actionQrl: QRL<(data: GetValidatorOutputType<VALIDATOR>, event: RequestEventAction) => ValueOrPromise<OBJ>>, options: VALIDATOR): Action<StrictUnion<OBJ | FailReturn<ValidatorErrorType<GetValidatorInputType<VALIDATOR>>>>, GetValidatorInputType<VALIDATOR>, false>;
82
76
  <OBJ extends Record<string, any> | void | null, REST extends [DataValidator, ...DataValidator[]]>(actionQrl: QRL<(form: JSONObject, event: RequestEventAction) => ValueOrPromise<OBJ>>, ...rest: REST): Action<StrictUnion<OBJ | FailReturn<FailOfRest<REST>>>>;
83
- <OBJ>(actionQrl: QRL<(form: JSONObject, event: RequestEventAction) => ValueOrPromise<OBJ>>, options?: {
84
- readonly id?: string;
85
- }): Action<StrictUnion<OBJ>>;
77
+ <OBJ>(actionQrl: QRL<(form: JSONObject, event: RequestEventAction) => ValueOrPromise<OBJ>>, options?: ActionOptions): Action<StrictUnion<OBJ>>;
78
+ };
79
+
80
+ /** @public */
81
+ export declare type ActionOptions = {
82
+ readonly id?: string;
83
+ readonly validation?: DataValidator[];
84
+ /**
85
+ * Route loaders to invalidate after this action completes. The loader hooks' hashes are sent to
86
+ * the client so it knows which loaders to re-fetch. If omitted, ALL route loaders are invalidated
87
+ * (unless `strictLoaders` is enabled globally in the Vite plugin).
88
+ */
89
+ readonly invalidate?: Loader_2<any>[];
86
90
  };
87
91
 
88
92
  /** @public */
@@ -394,6 +398,14 @@ declare interface ErrorBoundaryProps {
394
398
  fallback$?: QRL<(error: any) => any>;
395
399
  }
396
400
 
401
+ /**
402
+ * Drops control-flow signals (`ev.redirect()`, `ev.error()`, etc.) from a loader/action return
403
+ * type: those are thrown, not surfaced as data. `ev.fail()` is plain data and is kept.
404
+ *
405
+ * @public
406
+ */
407
+ export declare type ExcludeControlFlow<T> = Exclude<T, AbortMessage | ServerError>;
408
+
397
409
  declare type Failed = {
398
410
  failed: true;
399
411
  };
@@ -434,6 +446,14 @@ export declare interface FormSubmitSuccessDetail<T> {
434
446
  value: T;
435
447
  }
436
448
 
449
+ /**
450
+ * Returns the current RequestEvent if possible. Only usable on the server, and only during request
451
+ * processing.
452
+ *
453
+ * @public
454
+ */
455
+ export declare const getRequestEvent: (thisArg?: unknown) => RequestEvent | undefined;
456
+
437
457
  /** @public */
438
458
  export declare type GetValidatorInputType<VALIDATOR extends TypedDataValidator> = VALIDATOR extends ValibotDataValidator<infer TYPE> ? v.InferInput<TYPE> : VALIDATOR extends ZodDataValidator<infer TYPE> ? z_2.input<TYPE> : never;
439
459
 
@@ -482,8 +502,8 @@ export declare const Link: Component<LinkProps>;
482
502
  /** @public */
483
503
  export declare interface LinkProps extends AnchorAttributes {
484
504
  /**
485
- * @deprecated Use `prefetchBundle` and `prefetchData` instead for more granular control over what
486
- * is prefetched and when. This prop will be removed in a future major version.
505
+ * @deprecated Use `prefetchBundles` and `prefetchData` instead for more granular control over
506
+ * what is prefetched and when. This prop will be removed in a future major version.
487
507
  *
488
508
  * Legacy prefetch control for this **`Link`**.
489
509
  *
@@ -501,7 +521,7 @@ export declare interface LinkProps extends AnchorAttributes {
501
521
  *
502
522
  * Prefetching will not occur if the user has the **data saver** setting enabled.
503
523
  */
504
- prefetchBundle?: PrefetchStrategy;
524
+ prefetchBundles?: PrefetchStrategy;
505
525
  /**
506
526
  * Controls when Qwik should prefetch and cache route data for this **`Link`** target, including
507
527
  * invoking any **`routeLoader$`**, **`onGet`**, etc.
@@ -534,8 +554,8 @@ declare interface LoadedRoute {
534
554
  $routeBundleNames$?: string[] | undefined;
535
555
  /** Whether this route is a not-found (404) route */
536
556
  $notFound$?: boolean;
537
- /** The error module loader (nearest _E ancestor), for rendering ServerErrors */
538
- $errorLoader$?: ContentModuleLoader;
557
+ /** The nearest _E (error.tsx) boundary's chain to render on a thrown ServerError (in its layouts). */
558
+ $errorLoader$?: ModuleLoader[];
539
559
  /** Merged array of routeLoader$ hashes from all matched nodes (layouts + page) */
540
560
  $loaders$?: string[];
541
561
  /** Runtime-only mapping of routeLoader$ hashes to the matched pathname used for q-loader fetches */
@@ -548,7 +568,7 @@ declare type Loader_2<RETURN> = {
548
568
  * Returns the `Signal` containing the data returned by the `loader$` function. Like all `use-`
549
569
  * functions and methods, it can only be invoked within a `component$()`.
550
570
  */
551
- (): LoaderSignal<RETURN>;
571
+ (): LoaderSignal<ExcludeControlFlow<RETURN>>;
552
572
  };
553
573
  export { Loader_2 as Loader }
554
574
 
@@ -566,7 +586,10 @@ declare type LoaderConstructorQRL = {
566
586
 
567
587
  /** @public */
568
588
  declare type LoaderOptions = {
569
- /** @deprecated Unused */
589
+ /**
590
+ * Explicit loader id, overriding the QRL hash. Pass a distinct value (e.g. `fn.getHash()`) when
591
+ * loaders share a wrapper QRL.
592
+ */
570
593
  readonly id?: string;
571
594
  readonly validation?: DataValidator[];
572
595
  readonly serializationStrategy?: SerializationStrategy;
@@ -574,9 +597,9 @@ declare type LoaderOptions = {
574
597
  * Time in milliseconds after which the loader data is considered stale. The server derives
575
598
  * `Cache-Control: max-age` seconds from this value on loader responses.
576
599
  *
577
- * On the client, the loader's AsyncSignal `expires` is set to this value. If `poll` is true, the
578
- * signal auto-refetches when expired. If `poll` is false (default), the data is marked stale but
579
- * not auto-refetched.
600
+ * On the client, the loader's ComputedSignal `expires` is set to this value. If `poll` is true,
601
+ * the signal auto-refetches when expired. If `poll` is false (default), the data is marked stale
602
+ * but not auto-refetched.
580
603
  */
581
604
  readonly expires?: number;
582
605
  /**
@@ -639,10 +662,22 @@ declare type LoaderOptions = {
639
662
  * boundary). This is useful when showing old data during navigation would be confusing.
640
663
  */
641
664
  readonly allowStale?: boolean;
665
+ /**
666
+ * When true (default), the loader is awaited before SSR renders, so its redirect or error can
667
+ * short-circuit the response and its value is ready for synchronous reads (e.g. in the head).
668
+ *
669
+ * When false, the loader runs in the background without blocking SSR: rendering starts
670
+ * immediately and reading its `.value` suspends until it resolves. A background loader cannot
671
+ * redirect or error the initial SSR response; treat it as a separate request.
672
+ *
673
+ * Setting `false` is experimental and requires adding `experimental: ["blockSSR"]` to your
674
+ * qwikVite plugin options.
675
+ */
676
+ readonly blockSSR?: boolean;
642
677
  };
643
678
 
644
679
  /** @public */
645
- export declare type LoaderSignal<TYPE> = (TYPE extends () => ValueOrPromise<infer VALIDATOR> ? Signal<ValueOrPromise<VALIDATOR>> : Signal<TYPE>) & Pick<AsyncSignal, 'promise' | 'loading' | 'error'>;
680
+ export declare type LoaderSignal<TYPE> = (TYPE extends () => ValueOrPromise<infer VALIDATOR> ? Signal<ValueOrPromise<VALIDATOR>> : Signal<TYPE>) & Pick<ComputedSignal<any>, 'promise' | 'pending' | 'error' | 'loading'>;
646
681
 
647
682
  declare interface MenuModule {
648
683
  readonly default: ContentMenu;
@@ -840,9 +875,9 @@ export declare const QwikRouterMockProvider: Component<QwikRouterMockProps>;
840
875
  /** @public */
841
876
  export declare interface QwikRouterProps {
842
877
  /**
843
- * Enable the ViewTransition API
878
+ * Enable the ViewTransition API on SPA navigation. Opt-in: set to `true` to enable.
844
879
  *
845
- * Default: `true`
880
+ * Default: `false`
846
881
  *
847
882
  * @see https://github.com/WICG/view-transitions/blob/main/explainer.md
848
883
  * @see https://developer.mozilla.org/en-US/docs/Web/API/View_Transitions_API
@@ -906,7 +941,8 @@ export declare type ResolvedDocumentHead<FrontMatter extends Record<string, any>
906
941
  */
907
942
  export declare const routeAction$: ActionConstructor;
908
943
 
909
- /* Excluded from this release type: routeActionQrl */
944
+ /** @public */
945
+ export declare const routeActionQrl: ActionConstructorQRL;
910
946
 
911
947
  declare type RouteActionResolver = {
912
948
  status: number;
@@ -963,10 +999,13 @@ export declare interface RouteData {
963
999
  _G?: string;
964
1000
  /** The JS bundle names for this route (SSR only) */
965
1001
  _B?: string[];
966
- /** The not-found (404) module loader for this subtree */
967
- _4?: ContentModuleLoader;
968
- /** The error page module loader for this subtree (error.tsx, takes precedence over _4) */
969
- _E?: ContentModuleLoader;
1002
+ /**
1003
+ * Not-found (404) boundary: single loader (runtime prepends layouts) or override chain
1004
+ * (`404@layout`/`!`).
1005
+ */
1006
+ _4?: ContentModuleLoader | ModuleLoader[];
1007
+ /** Error (error.tsx) boundary, same single-or-override-chain shape as `_4`. */
1008
+ _E?: ContentModuleLoader | ModuleLoader[];
970
1009
  /** The parameter name when this node is reached via `_W` or `_A` from the parent */
971
1010
  _P?: string;
972
1011
  /** Prefix for infix params (e.g. "pre" for `pre[slug]post`) — only on `_W` nodes */
@@ -986,7 +1025,7 @@ export declare interface RouteData {
986
1025
  /**
987
1026
  * Define a route loader that fetches data before the route renders.
988
1027
  *
989
- * Route loaders run on the server during SSR and return data as an `AsyncSignal`. On the client,
1028
+ * Route loaders run on the server during SSR and return data as a `ComputedSignal`. On the client,
990
1029
  * loaders automatically re-fetch when the route changes (SPA navigation). Each loader gets its own
991
1030
  * JSON endpoint (`q-loader-{id}.{hash}.json`), so only the loaders present on the target route are
992
1031
  * fetched.
@@ -1028,6 +1067,8 @@ declare type RouteLoaderCtx = {
1028
1067
  pageSearch?: string;
1029
1068
  /** SPA navigation function. Client-only and intentionally omitted from SSR state. */
1030
1069
  goto?: NoSerialize<RouteNavigate>;
1070
+ /** Client manifest hash for q-loader fetch URLs. */
1071
+ manifestHash?: string;
1031
1072
  };
1032
1073
 
1033
1074
  /* Excluded from this release type: routeLoaderQrl */