@nuxt/docs-nightly 4.6.0-29803612.ea5d49fb → 4.6.0-29809894.6056487a

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.
@@ -551,6 +551,80 @@ export default defineNuxtConfig({
551
551
  })
552
552
  ```
553
553
 
554
+ ### Typed `$fetch` Rebuilt on Generated Route Types
555
+
556
+ 🚦 **Impact Level**: Medium
557
+
558
+ #### What Changed
559
+
560
+ With `compatibilityVersion: 5`, `$fetch` and `useFetch` are typed from the routes Nuxt's server
561
+ builder reports, rather than from nitro's `InternalApi` interface. As well as response types, a
562
+ `body`, `query` or `headers` the matching handler validates are now enforced on the call, a method
563
+ the route does not handle is rejected, and a response is typed as it arrives over the wire, so a
564
+ `Date` a handler returns is a `string` at the call site.
565
+
566
+ Two things follow from this:
567
+
568
+ - Routes you augmented by hand on nitro's `InternalApi` are no longer picked up. Augment
569
+ `ServerRoutes` from `@nuxt/schema` instead.
570
+ - The `params` option is no longer accepted by `$fetch` or `useFetch`. It was an alias for `query`.
571
+
572
+ #### Reasons for Change
573
+
574
+ Nitro v3 drops typed fetch, and the old implementation did not scale past about 300 routes. The new
575
+ generated route types cost the same to check whatever the route count, and carry enough information
576
+ to type the request as well as the response. `params` is dropped so the name is free for named route
577
+ parameters later.
578
+
579
+ #### Migration Steps
580
+
581
+ Move any `params` option to `query`:
582
+
583
+ ```diff
584
+ const { data } = await useFetch('/api/search', {
585
+ - params: { q: 'nuxt' },
586
+ + query: { q: 'nuxt' },
587
+ })
588
+ ```
589
+
590
+ Move any manual route augmentation from `InternalApi` to `ServerRoutes`:
591
+
592
+ ```diff [shared/server-routes.d.ts]
593
+ - declare module 'nitropack' {
594
+ - interface InternalApi {
595
+ - '/api/hello': { get: { message: string } }
596
+ - }
597
+ - }
598
+ + import type { Endpoint } from 'nuxt/app'
599
+ +
600
+ + declare module '@nuxt/schema' {
601
+ + interface ServerRoutes {
602
+ + '/api/hello': {
603
+ + [Endpoint]: {
604
+ + GET: { response: { message: string } }
605
+ + }
606
+ + }
607
+ + }
608
+ + }
609
+ ```
610
+
611
+ ::note
612
+ While Nuxt 4 runs on nitro v2, nitro declares a global `$fetch` of its own, typed from
613
+ `InternalApi`. Import `$fetch` from `#build/fetch` where you want the generated route types to apply
614
+ to a direct call; `useFetch`, `useLazyFetch` and `useRequestFetch()` are unaffected.
615
+ ::
616
+
617
+ ::tip
618
+ Either typing can be selected on its own with
619
+ [`experimental.routeTypedFetch`](/docs/4.x/guide/going-further/experimental-features#routetypedfetch),
620
+ so you can adopt this before moving to Nuxt 5, or move to Nuxt 5 with `routeTypedFetch: false` and
621
+ adopt it separately. The option is temporary: from Nuxt 5 the generated route set is the only
622
+ source.
623
+ ::
624
+
625
+ Set [`experimental.strictRouteTypes`](/docs/4.x/guide/going-further/experimental-features#strictroutetypes)
626
+ to reject a path no route answers.
627
+
554
628
  ### TypeScript `baseUrl` Is Ignored
555
629
 
556
630
  🚦 **Impact Level**: Minimal
@@ -1050,6 +1050,101 @@ export default defineNuxtConfig({
1050
1050
  })
1051
1051
  ```
1052
1052
 
1053
+ ## routeTypedFetch
1054
+
1055
+ Type `$fetch` and `useFetch` from the routes your server builder reports, rather than from the
1056
+ responses nitro contributes to `ServerRoutes` through its `InternalApi` interface.
1057
+
1058
+ ```ts twoslash [nuxt.config.ts]
1059
+ export default defineNuxtConfig({
1060
+ experimental: {
1061
+ routeTypedFetch: true,
1062
+ },
1063
+ })
1064
+ ```
1065
+
1066
+ The generated route set carries the `body`, `query` and `headers` a handler validates as well as its
1067
+ response, typed as it arrives over the wire, so a resolving call is typed more tightly than before:
1068
+
1069
+ - a `Date` a handler returns is a `string` at the call site
1070
+ - a `body` the handler validates cannot be omitted or given the wrong shape
1071
+ - a method the route does not answer is rejected
1072
+ - `params` is no longer accepted, since it was only ever an alias for `query`
1073
+ - a route you registered by augmenting `ServerRoutes` by hand needs rewriting, as the two
1074
+ descriptions of a route differ (see [the upgrade guide](/docs/4.x/getting-started/upgrade#typed-fetch-rebuilt-on-generated-route-types))
1075
+
1076
+ Because of those, it is opt-in, and `future.compatibilityVersion: 5` enables it. Setting it
1077
+ explicitly selects either typing whatever the compatibility version, so you can adopt it before
1078
+ moving to Nuxt 5, or move to Nuxt 5 with `routeTypedFetch: false` and adopt it separately.
1079
+
1080
+ ::note
1081
+ This option exists only while both typings are supported. From Nuxt 5 the generated route set is the
1082
+ only source and the option is gone.
1083
+ ::
1084
+
1085
+ ::note
1086
+ While Nuxt 4 runs on nitro v2, nitro declares a global `$fetch` of its own, typed from
1087
+ `InternalApi`. Import `$fetch` from `#build/fetch` where you want the generated route types to apply
1088
+ to a direct call; `useFetch`, `useLazyFetch` and `useRequestFetch()` are unaffected.
1089
+ ::
1090
+
1091
+ ## strictRouteTypes
1092
+
1093
+ Reject a request to a path no server route answers. Requires
1094
+ [`routeTypedFetch`](#routetypedfetch), which types `$fetch` and `useFetch` from the routes your
1095
+ server will serve.
1096
+
1097
+ ```ts twoslash [nuxt.config.ts]
1098
+ export default defineNuxtConfig({
1099
+ experimental: {
1100
+ routeTypedFetch: true,
1101
+ strictRouteTypes: true,
1102
+ },
1103
+ })
1104
+ ```
1105
+
1106
+ With `routeTypedFetch` enabled a response is typed by the handler that answers it whatever this
1107
+ option is set to. What the option decides is whether a path Nuxt does not recognise is an error or
1108
+ is simply typed as `unknown`.
1109
+
1110
+ - `false` (default) - a path Nuxt does not recognise is accepted and resolves to `unknown`, and no
1111
+ method is rejected. Nuxt cannot see every way a request may be answered: nitro middleware, a
1112
+ [`routeRules`](/docs/4.x/guide/concepts/rendering#hybrid-rendering) proxy or a catch-all handler
1113
+ can answer a path no route describes.
1114
+ - `true` - only the routes your server builder reports are accepted, for the methods they answer.
1115
+ - `'isomorphic'` - as `true`, and your pages are included as `GET` routes returning `string`, so
1116
+ `$fetch('/about')` is typed by the route the Vue router serves rather than rejected.
1117
+
1118
+ With the option on, a typo and a method the route does not answer are both errors:
1119
+
1120
+ ```ts
1121
+ // server/api/todos.post.ts answers POST only
1122
+ await $fetch('/api/todos', { method: 'POST' })
1123
+ await $fetch('/api/todo', { method: 'POST' })
1124
+ // ^ no POST route matches '/api/todo'
1125
+ await $fetch('/api/todos')
1126
+ // ^ no GET route matches '/api/todos'
1127
+ ```
1128
+
1129
+ Two things stay accepted, because they are not Nuxt's to describe: an absolute URL
1130
+ (`$fetch('https://example.com')`), and a path built at runtime, which resolves to `unknown` as it
1131
+ does with the option off. A `baseURL` is resolved into the path before it is matched, so a request
1132
+ made through one is checked against the route it actually asks for. Naming the response type also
1133
+ opts a call out, since doing so turns off inference for the request:
1134
+
1135
+ ```ts
1136
+ const data = await $fetch<{ id: string }>(`/api/${resource}`)
1137
+ ```
1138
+
1139
+ ::note
1140
+ Files in your `public/` directory are not routes your server builder reports, so requesting one
1141
+ with `strictRouteTypes` enabled is an error. Fetch those with an explicit response type, or leave
1142
+ the option off.
1143
+ ::
1144
+
1145
+ Set this only where your routing is enumerable. An app with a catch-all page under `'isomorphic'`
1146
+ matches every path, which is correct but means the option constrains nothing.
1147
+
1053
1148
  ## pendingWhenIdle
1054
1149
 
1055
1150
  `pendingWhenIdle` controls the `pending` ref returned by `useAsyncData` and `useFetch`.
@@ -57,6 +57,7 @@ Check the [schema source code](https://github.com/nuxt/nuxt/blob/main/packages/s
57
57
  | `pages:extend` | `pages` | Called after page routes are scanned from the file system. |
58
58
  | `pages:resolved` | `pages` | Called after page routes have been augmented with scanned metadata. |
59
59
  | `pages:routerOptions` | `{ files: Array<{ path: string, optional?: boolean }> }` | Called when resolving `router.options` files. Later items in the array override earlier ones. |
60
+ | `server:routes` | `routes`, `context` | Called when Nuxt needs the full set of route handlers the server will serve, so that it can type `$fetch` and `useFetch` against them. |
60
61
  | `server:devHandler` | `handler` | Called when the dev middleware is being registered on the Nitro dev server. |
61
62
  | `imports:sources` | `presets` | Called at setup allowing modules to extend sources. |
62
63
  | `imports:extend` | `imports` | Called at setup allowing modules to extend imports. |
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@nuxt/docs-nightly",
3
- "version": "4.6.0-29803612.ea5d49fb",
3
+ "version": "4.6.0-29809894.6056487a",
4
4
  "repository": {
5
5
  "type": "git",
6
6
  "url": "git+https://github.com/nuxt/nuxt.git",