@sveltejs/kit 3.0.0-next.2 → 3.0.0-next.21

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 (195) hide show
  1. package/package.json +62 -36
  2. package/src/cli.js +15 -12
  3. package/src/constants.js +6 -1
  4. package/src/core/adapt/builder.js +66 -72
  5. package/src/core/adapt/index.js +17 -6
  6. package/src/core/config/index.js +134 -80
  7. package/src/core/config/options.js +295 -273
  8. package/src/core/config/types.d.ts +1 -1
  9. package/src/core/env.js +146 -16
  10. package/src/core/generate_manifest/index.js +18 -15
  11. package/src/core/postbuild/analyse.js +8 -20
  12. package/src/core/postbuild/crawl.js +22 -6
  13. package/src/core/postbuild/entities.js +8 -2
  14. package/src/core/postbuild/fallback.js +4 -2
  15. package/src/core/postbuild/prerender.js +222 -70
  16. package/src/core/postbuild/queue.js +2 -1
  17. package/src/core/sync/create_manifest_data/conflict.js +1 -1
  18. package/src/core/sync/create_manifest_data/index.js +82 -62
  19. package/src/core/sync/sync.js +40 -31
  20. package/src/core/sync/ts.js +1 -1
  21. package/src/core/sync/utils.js +22 -2
  22. package/src/core/sync/{write_non_ambient.js → write_app_types.js} +107 -58
  23. package/src/core/sync/write_client_manifest.js +14 -29
  24. package/src/core/sync/write_env.js +7 -5
  25. package/src/core/sync/write_server.js +37 -45
  26. package/src/core/sync/write_tsconfig/index.js +274 -0
  27. package/src/core/sync/write_tsconfig/test-app/package.json +7 -0
  28. package/src/core/sync/write_tsconfig/utils.js +77 -0
  29. package/src/core/sync/write_tsconfig/validate.js +128 -0
  30. package/src/core/sync/write_types/index.js +127 -123
  31. package/src/core/utils.js +30 -5
  32. package/src/exports/env/index.js +77 -0
  33. package/src/exports/env/public.d.ts +55 -0
  34. package/src/exports/hooks/index.js +3 -9
  35. package/src/exports/hooks/public.d.ts +195 -0
  36. package/src/exports/hooks/sequence.js +9 -6
  37. package/src/exports/index.js +52 -29
  38. package/src/exports/internal/client.js +5 -0
  39. package/src/exports/internal/env.js +8 -5
  40. package/src/exports/internal/index.js +1 -90
  41. package/src/exports/internal/{event.js → server/event.js} +2 -3
  42. package/src/exports/internal/server/index.js +37 -0
  43. package/src/exports/internal/server/telemetry.js +95 -0
  44. package/src/exports/internal/shared.js +90 -0
  45. package/src/exports/node/index.js +64 -22
  46. package/src/exports/params/index.js +70 -0
  47. package/src/exports/params/public.d.ts +63 -0
  48. package/src/exports/public.d.ts +50 -1733
  49. package/src/exports/remote/index.js +11 -0
  50. package/src/exports/remote/public.d.ts +519 -0
  51. package/src/exports/url.js +86 -0
  52. package/src/exports/vite/build/build_server.js +54 -65
  53. package/src/exports/vite/build/remote.js +24 -19
  54. package/src/exports/vite/build/utils.js +0 -8
  55. package/src/exports/vite/dev/index.js +218 -146
  56. package/src/exports/vite/index.js +1590 -858
  57. package/src/exports/vite/module_ids.js +2 -2
  58. package/src/exports/vite/preview/index.js +40 -32
  59. package/src/exports/vite/public.d.ts +588 -0
  60. package/src/exports/vite/utils.js +84 -46
  61. package/src/pathname.js +55 -0
  62. package/src/runner.js +15 -0
  63. package/src/runtime/app/env/internal.js +4 -4
  64. package/src/runtime/app/env/types.d.ts +1 -1
  65. package/src/runtime/app/environment/index.js +3 -3
  66. package/src/runtime/app/{forms.js → forms/index.js} +73 -42
  67. package/src/runtime/app/forms/public.d.ts +2 -0
  68. package/src/runtime/app/forms/types.d.ts +56 -0
  69. package/src/runtime/app/internal/transport.js +53 -0
  70. package/src/runtime/app/manifest/index.js +1 -0
  71. package/src/runtime/app/{navigation.js → navigation/index.js} +2 -1
  72. package/src/runtime/app/navigation/public.d.ts +237 -0
  73. package/src/runtime/app/paths/client.js +37 -37
  74. package/src/runtime/app/paths/index.js +1 -1
  75. package/src/runtime/app/paths/internal/client.js +34 -2
  76. package/src/runtime/app/paths/internal/server.js +6 -23
  77. package/src/runtime/app/paths/internal.d.ts +3 -0
  78. package/src/runtime/app/paths/public.d.ts +1 -29
  79. package/src/runtime/app/paths/server.js +36 -17
  80. package/src/runtime/app/paths/types.d.ts +11 -19
  81. package/src/runtime/app/server/index.js +2 -2
  82. package/src/runtime/app/server/public.d.ts +201 -0
  83. package/src/runtime/app/server/remote/command.js +13 -11
  84. package/src/runtime/app/server/remote/form.js +61 -39
  85. package/src/runtime/app/server/remote/prerender.js +45 -45
  86. package/src/runtime/app/server/remote/query.js +106 -108
  87. package/src/runtime/app/server/remote/requested.js +27 -19
  88. package/src/runtime/app/server/remote/shared.js +76 -76
  89. package/src/runtime/app/service-worker/index.js +24 -0
  90. package/src/runtime/app/state/client.js +4 -2
  91. package/src/runtime/app/state/index.js +7 -5
  92. package/src/runtime/app/state/public.d.ts +72 -0
  93. package/src/runtime/app/state/server.js +3 -0
  94. package/src/runtime/app/stores.js +15 -78
  95. package/src/runtime/client/bundle.js +1 -1
  96. package/src/runtime/client/client-entry.js +3 -0
  97. package/src/runtime/client/client.js +1336 -648
  98. package/src/runtime/client/constants.js +3 -6
  99. package/src/runtime/client/entry.js +24 -3
  100. package/src/runtime/client/fetcher.js +25 -25
  101. package/src/runtime/client/ndjson.js +1 -1
  102. package/src/runtime/client/parse.js +1 -1
  103. package/src/runtime/client/payload.js +17 -0
  104. package/src/runtime/client/remote-functions/cache.svelte.js +3 -1
  105. package/src/runtime/client/remote-functions/command.svelte.js +37 -61
  106. package/src/runtime/client/remote-functions/form.svelte.js +267 -178
  107. package/src/runtime/client/remote-functions/prerender.svelte.js +32 -11
  108. package/src/runtime/client/remote-functions/query/index.js +10 -17
  109. package/src/runtime/client/remote-functions/query/instance.svelte.js +64 -18
  110. package/src/runtime/client/remote-functions/query/proxy.js +5 -5
  111. package/src/runtime/client/remote-functions/query-batch.svelte.js +61 -70
  112. package/src/runtime/client/remote-functions/query-live/index.js +1 -1
  113. package/src/runtime/client/remote-functions/query-live/instance.svelte.js +63 -21
  114. package/src/runtime/client/remote-functions/query-live/iterator.js +15 -12
  115. package/src/runtime/client/remote-functions/query-live/proxy.js +2 -12
  116. package/src/runtime/client/remote-functions/shared.svelte.js +90 -65
  117. package/src/runtime/client/snapshots.js +147 -0
  118. package/src/runtime/client/state.svelte.js +94 -55
  119. package/src/runtime/client/stream.js +3 -2
  120. package/src/runtime/client/types.d.ts +13 -9
  121. package/src/runtime/client/utils.js +22 -110
  122. package/src/runtime/components/root.svelte +56 -0
  123. package/src/runtime/env/dynamic/private.js +7 -0
  124. package/src/runtime/env/dynamic/public.js +7 -0
  125. package/src/runtime/env/static/private.js +6 -0
  126. package/src/runtime/env/static/public.js +6 -0
  127. package/src/runtime/form-utils.js +172 -61
  128. package/src/runtime/pathname.js +20 -32
  129. package/src/runtime/props.svelte.js +72 -0
  130. package/src/runtime/server/constants.js +0 -3
  131. package/src/runtime/server/cookie.js +72 -55
  132. package/src/runtime/server/csrf.js +65 -0
  133. package/src/runtime/server/data/index.js +49 -53
  134. package/src/runtime/server/dev.js +22 -0
  135. package/src/runtime/server/endpoint.js +6 -7
  136. package/src/runtime/server/env_module.js +0 -5
  137. package/src/runtime/server/errors.js +160 -0
  138. package/src/runtime/server/fetch.js +32 -39
  139. package/src/runtime/server/index.js +90 -64
  140. package/src/runtime/server/internal.js +71 -0
  141. package/src/runtime/server/page/actions.js +85 -64
  142. package/src/runtime/server/page/crypto.js +2 -2
  143. package/src/runtime/server/page/csp.js +88 -104
  144. package/src/runtime/server/page/data_serializer.js +24 -25
  145. package/src/runtime/server/page/index.js +36 -53
  146. package/src/runtime/server/page/load_data.js +50 -57
  147. package/src/runtime/server/page/render.js +173 -239
  148. package/src/runtime/server/page/respond_with_error.js +17 -31
  149. package/src/runtime/server/page/serialize_data.js +2 -13
  150. package/src/runtime/server/page/server_routing.js +85 -26
  151. package/src/runtime/server/remote-functions.js +640 -0
  152. package/src/runtime/server/respond.js +190 -131
  153. package/src/runtime/server/sourcemaps.js +183 -0
  154. package/src/runtime/server/state.js +53 -0
  155. package/src/runtime/server/utils.js +13 -155
  156. package/src/runtime/shared.js +20 -40
  157. package/src/runtime/utils.js +3 -0
  158. package/src/types/ambient-private.d.ts +11 -1
  159. package/src/types/ambient.d.ts +87 -36
  160. package/src/types/global-private.d.ts +25 -25
  161. package/src/types/internal.d.ts +163 -157
  162. package/src/types/private.d.ts +41 -1
  163. package/src/utils/error.js +28 -4
  164. package/src/utils/escape.js +9 -25
  165. package/src/utils/features.js +1 -1
  166. package/src/utils/filesystem.js +1 -23
  167. package/src/utils/fork.js +7 -2
  168. package/src/utils/hash.js +21 -0
  169. package/src/utils/http.js +8 -7
  170. package/src/utils/import.js +9 -2
  171. package/src/utils/imports.js +83 -0
  172. package/src/utils/mime.js +9 -0
  173. package/src/utils/page_nodes.js +6 -7
  174. package/src/utils/params.js +67 -0
  175. package/src/utils/regex.js +9 -0
  176. package/src/utils/routing.js +145 -73
  177. package/src/utils/shared-iterator.js +5 -0
  178. package/src/utils/streaming.js +14 -4
  179. package/src/utils/url.js +33 -2
  180. package/src/version.js +1 -1
  181. package/types/index.d.ts +2616 -2433
  182. package/types/index.d.ts.map +120 -106
  183. package/src/core/sync/write_ambient.js +0 -18
  184. package/src/core/sync/write_root.js +0 -148
  185. package/src/core/sync/write_tsconfig.js +0 -250
  186. package/src/exports/internal/server.js +0 -22
  187. package/src/exports/node/polyfills.js +0 -30
  188. package/src/runtime/server/app.js +0 -9
  189. package/src/runtime/server/remote.js +0 -457
  190. package/src/runtime/shared-server.js +0 -7
  191. package/src/runtime/telemetry/otel.js +0 -21
  192. package/src/runtime/telemetry/record_span.js +0 -65
  193. package/src/types/synthetic/$lib.md +0 -5
  194. /package/src/exports/internal/{remote-functions.js → server/remote-functions.js} +0 -0
  195. /package/src/{runtime/telemetry/noop.js → telemetry.js} +0 -0
@@ -1,21 +1,27 @@
1
- /** @import { RequestState, SSRNode } from 'types' */
1
+ /** @import { SSRNode } from 'types' */
2
2
  import { DEV } from 'esm-env';
3
3
  import { json, text } from '@sveltejs/kit';
4
4
  import { Redirect, SvelteKitError } from '@sveltejs/kit/internal';
5
- import { merge_tracing, with_request_store } from '@sveltejs/kit/internal/server';
6
- import { base, app_dir } from '$app/paths/internal/server';
5
+ import {
6
+ merge_tracing,
7
+ otel,
8
+ record_span,
9
+ with_request_store
10
+ } from '@sveltejs/kit/internal/server';
11
+ import { base, app_dir } from '#app/paths';
7
12
  import { is_endpoint_request, render_endpoint } from './endpoint.js';
8
13
  import { render_page } from './page/index.js';
9
14
  import { render_response } from './page/render.js';
10
15
  import { respond_with_error } from './page/respond_with_error.js';
11
- import { is_form_content_type } from '../../utils/http.js';
16
+ import { get_self_origin, is_csrf_forbidden, is_remote_forbidden } from './csrf.js';
17
+ import { has_prerendered_path, method_not_allowed, redirect_response } from './utils.js';
18
+ import { handle_fatal_error } from './errors.js';
12
19
  import {
13
- handle_fatal_error,
14
- has_prerendered_path,
15
- method_not_allowed,
16
- redirect_response
17
- } from './utils.js';
18
- import { decode_pathname, disable_search, normalize_path } from '../../utils/url.js';
20
+ decode_pathname,
21
+ disable_search,
22
+ normalize_path,
23
+ relative_pathname
24
+ } from '../../utils/url.js';
19
25
  import { find_route } from '../../utils/routing.js';
20
26
  import { redirect_json_response, render_data } from './data/index.js';
21
27
  import { add_cookies_to_headers, get_cookies } from './cookie.js';
@@ -25,20 +31,20 @@ import { validate_server_exports } from '../../utils/exports.js';
25
31
  import { action_json_redirect, is_action_json_request } from './page/actions.js';
26
32
  import { INVALIDATED_PARAM, TRAILING_SLASH_PARAM } from '../shared.js';
27
33
  import { get_public_env } from './env_module.js';
28
- import { resolve_route } from './page/server_routing.js';
34
+ import { resolve_route, resolve_route_by_id } from './page/server_routing.js';
29
35
  import { validateHeaders } from './validate-headers.js';
30
36
  import {
31
37
  add_data_suffix,
32
38
  add_resolution_suffix,
39
+ extract_route_id,
33
40
  has_data_suffix,
34
41
  has_resolution_suffix,
42
+ is_route_id_resolution_path,
35
43
  strip_data_suffix,
36
44
  strip_resolution_suffix
37
45
  } from '../pathname.js';
38
46
  import { server_data_serializer } from './page/data_serializer.js';
39
- import { get_remote_id, handle_remote_call } from './remote.js';
40
- import { record_span } from '../telemetry/record_span.js';
41
- import { otel } from '../telemetry/otel.js';
47
+ import { get_remote_id, handle_remote_call } from './remote-functions.js';
42
48
 
43
49
  /** @type {import('types').RequiredResolveOptions['transformPageChunk']} */
44
50
  const default_transform = ({ html }) => html;
@@ -49,6 +55,28 @@ const default_filter = () => false;
49
55
  /** @type {import('types').RequiredResolveOptions['preload']} */
50
56
  const default_preload = ({ type }) => type === 'js' || type === 'css';
51
57
 
58
+ // `Sec-Fetch-Dest` values for subresource requests that can never render an HTML error page
59
+ // https://developer.mozilla.org/en-US/docs/Web/HTTP/Reference/Headers/Sec-Fetch-Dest
60
+ const non_html_fetch_destinations = new Set([
61
+ 'audio',
62
+ 'audioworklet',
63
+ 'font',
64
+ 'image',
65
+ 'json',
66
+ 'manifest',
67
+ 'paintworklet',
68
+ 'report',
69
+ 'script',
70
+ 'serviceworker',
71
+ 'sharedworker',
72
+ 'style',
73
+ 'track',
74
+ 'video',
75
+ 'webidentity',
76
+ 'worker',
77
+ 'xslt'
78
+ ]);
79
+
52
80
  const page_methods = new Set(['GET', 'HEAD', 'POST']);
53
81
 
54
82
  const allowed_page_methods = new Set(['GET', 'HEAD', 'OPTIONS']);
@@ -59,7 +87,7 @@ export const respond = propagate_context(internal_respond);
59
87
  * @param {Request} request
60
88
  * @param {import('types').SSROptions} options
61
89
  * @param {import('@sveltejs/kit').SSRManifest} manifest
62
- * @param {import('types').SSRState} state
90
+ * @param {import('types').RequestState} state
63
91
  * @returns {Promise<Response>}
64
92
  */
65
93
  export async function internal_respond(request, options, manifest, state) {
@@ -70,23 +98,28 @@ export async function internal_respond(request, options, manifest, state) {
70
98
  const is_data_request = has_data_suffix(url.pathname);
71
99
  const remote_id = get_remote_id(url);
72
100
 
73
- if (!DEV) {
101
+ if (!__SVELTEKIT_DEV__) {
74
102
  const request_origin = request.headers.get('origin');
103
+ const self_origin = get_self_origin(options.paths_origin, url.origin);
75
104
 
76
105
  if (remote_id) {
77
- if (request.method !== 'GET' && request_origin !== url.origin) {
106
+ if (
107
+ is_remote_forbidden({
108
+ request,
109
+ request_origin,
110
+ self_origin
111
+ })
112
+ ) {
78
113
  const message = 'Cross-site remote requests are forbidden';
79
114
  return json({ message }, { status: 403 });
80
115
  }
81
116
  } else if (options.csrf_check_origin) {
82
- const forbidden =
83
- is_form_content_type(request) &&
84
- (request.method === 'POST' ||
85
- request.method === 'PUT' ||
86
- request.method === 'PATCH' ||
87
- request.method === 'DELETE') &&
88
- request_origin !== url.origin &&
89
- (!request_origin || !options.csrf_trusted_origins.includes(request_origin));
117
+ const forbidden = is_csrf_forbidden({
118
+ request,
119
+ request_origin,
120
+ self_origin,
121
+ trusted_origins: options.csrf_trusted_origins
122
+ });
90
123
 
91
124
  if (forbidden) {
92
125
  const message = `Cross-site ${request.method} form submissions are forbidden`;
@@ -108,12 +141,18 @@ export async function internal_respond(request, options, manifest, state) {
108
141
  /** @type {boolean[] | undefined} */
109
142
  let invalidated_data_nodes;
110
143
 
144
+ let skip_route_resolution = false;
145
+
146
+ /** Whether this is a `/${app_dir}/routes/<route_id>/__route.js` request, used by `preloadCode` */
147
+ let is_route_id_resolution_request = false;
148
+
111
149
  if (is_route_resolution_request) {
112
150
  /**
113
151
  * If the request is for a route resolution, first modify the URL, then continue as normal
114
152
  * for path resolution, then return the route object as a JS file.
115
153
  */
116
154
  url.pathname = strip_resolution_suffix(url.pathname);
155
+ is_route_id_resolution_request = is_route_id_resolution_path(url.pathname);
117
156
  } else if (is_data_request) {
118
157
  url.pathname =
119
158
  strip_data_suffix(url.pathname) +
@@ -125,8 +164,15 @@ export async function internal_respond(request, options, manifest, state) {
125
164
  .map((node) => node === '1');
126
165
  url.searchParams.delete(INVALIDATED_PARAM);
127
166
  } else if (remote_id) {
128
- url.pathname = request.headers.get('x-sveltekit-pathname') ?? base;
129
- url.search = request.headers.get('x-sveltekit-search') ?? '';
167
+ // query clients don't send these headers, leaving `event.url` as the endpoint URL
168
+ const pathname = request.headers.get('x-sveltekit-pathname');
169
+
170
+ if (pathname === null) {
171
+ skip_route_resolution = true;
172
+ } else {
173
+ url.pathname = pathname;
174
+ url.search = request.headers.get('x-sveltekit-search') ?? '';
175
+ }
130
176
  }
131
177
 
132
178
  /** @type {Record<string, string>} */
@@ -137,29 +183,7 @@ export async function internal_respond(request, options, manifest, state) {
137
183
  url
138
184
  );
139
185
 
140
- /** @type {RequestState} */
141
- const event_state = {
142
- prerendering: state.prerendering,
143
- transport: options.hooks.transport,
144
- handleValidationError: options.hooks.handleValidationError,
145
- tracing: {
146
- record_span
147
- },
148
- remote: {
149
- data: null,
150
- forms: null,
151
- refreshes: null,
152
- requested: null,
153
- reconnects: null,
154
- batches: null,
155
- live_iterators: null
156
- },
157
- is_in_remote_function: false,
158
- is_in_render: false,
159
- is_in_universal_load: false
160
- };
161
-
162
- /** @type {import('@sveltejs/kit').RequestEvent} */
186
+ /** @type {import('$app/server').RequestEvent} */
163
187
  const event = {
164
188
  cookies,
165
189
  // @ts-expect-error `fetch` needs to be created after the `event` itself
@@ -173,7 +197,12 @@ export async function internal_respond(request, options, manifest, state) {
173
197
  }),
174
198
  locals: {},
175
199
  params: {},
176
- platform: state.platform,
200
+ platform: state.emulator?.platform
201
+ ? await state.emulator.platform({
202
+ config: {},
203
+ prerender: !!state.prerendering?.fallback
204
+ })
205
+ : state.platform,
177
206
  request,
178
207
  route: { id: null },
179
208
  setHeaders: (new_headers) => {
@@ -211,6 +240,7 @@ export async function internal_respond(request, options, manifest, state) {
211
240
  isRemoteRequest: !!remote_id
212
241
  };
213
242
 
243
+ // @ts-expect-error this has to be assigned lazily
214
244
  event.fetch = create_fetch({
215
245
  event,
216
246
  options,
@@ -220,17 +250,11 @@ export async function internal_respond(request, options, manifest, state) {
220
250
  set_internal
221
251
  });
222
252
 
223
- if (state.emulator?.platform) {
224
- event.platform = await state.emulator.platform({
225
- config: {},
226
- prerender: !!state.prerendering?.fallback
227
- });
228
- }
229
-
230
253
  /** @type {string | null} */
231
254
  let resolved_path = url.pathname;
232
255
 
233
- if (!remote_id) {
256
+ // `reroute` hooks receive pathnames, so they must not run for route-ID resolution requests
257
+ if (!remote_id && !is_route_id_resolution_request) {
234
258
  const prerendering_reroute_state = state.prerendering?.inside_reroute;
235
259
  try {
236
260
  // For the duration or a reroute, disable the prerendering state as reroute could call API endpoints
@@ -299,7 +323,7 @@ export async function internal_respond(request, options, manifest, state) {
299
323
  statusText: response.statusText
300
324
  });
301
325
  } catch (error) {
302
- return await handle_fatal_error(event, event_state, options, error);
326
+ return await handle_fatal_error(event, state, options, error);
303
327
  }
304
328
  }
305
329
 
@@ -314,10 +338,14 @@ export async function internal_respond(request, options, manifest, state) {
314
338
  }
315
339
 
316
340
  if (is_route_resolution_request) {
341
+ if (is_route_id_resolution_request) {
342
+ return resolve_route_by_id(extract_route_id(resolved_path), new URL(request.url), manifest);
343
+ }
344
+
317
345
  return resolve_route(resolved_path, new URL(request.url), manifest);
318
346
  }
319
347
 
320
- if (resolved_path === `/${app_dir}/env.js` || resolved_path === `/${app_dir}/env.script.js`) {
348
+ if (resolved_path === `/${app_dir}/env.js`) {
321
349
  return get_public_env(request);
322
350
  }
323
351
 
@@ -328,15 +356,20 @@ export async function internal_respond(request, options, manifest, state) {
328
356
  return text('Not found', { status: 404, headers });
329
357
  }
330
358
 
331
- if (!state.prerendering?.fallback) {
332
- // TODO this could theoretically break — should probably be inside a try-catch
333
- const matchers = await manifest._.matchers();
334
- const result = find_route(resolved_path, manifest._.routes, matchers);
335
-
336
- if (result) {
337
- route = result.route;
338
- event.route = { id: route.id };
339
- event.params = result.params;
359
+ if (!state.prerendering?.fallback && !skip_route_resolution) {
360
+ try {
361
+ const matchers = await manifest._.matchers();
362
+ const result = find_route(resolved_path, manifest._.routes, matchers);
363
+
364
+ if (result) {
365
+ route = result.route;
366
+ // @ts-expect-error this has to be assigned lazily
367
+ event.route = { id: route.id };
368
+ // @ts-expect-error this has to be assigned lazily
369
+ event.params = result.params;
370
+ }
371
+ } catch (e) {
372
+ return await handle_fatal_error(event, state, options, e);
340
373
  }
341
374
  }
342
375
 
@@ -372,10 +405,9 @@ export async function internal_respond(request, options, manifest, state) {
372
405
  status: 308,
373
406
  headers: {
374
407
  'x-sveltekit-normalize': '1',
408
+ // relative so (possibly invisible) path prefixes are preserved
375
409
  location:
376
- // ensure paths starting with '//' are not treated as protocol-relative
377
- (normalized.startsWith('//') ? url.origin + normalized : normalized) +
378
- (url.search === '?' ? '' : url.search)
410
+ relative_pathname(url.pathname, normalized) + (url.search === '?' ? '' : url.search)
379
411
  }
380
412
  });
381
413
  }
@@ -393,10 +425,11 @@ export async function internal_respond(request, options, manifest, state) {
393
425
  prerender = node.prerender ?? prerender;
394
426
  } else if (page_nodes) {
395
427
  config = page_nodes.get_config() ?? config;
396
- prerender = page_nodes.prerender();
428
+ prerender = state.prerender_default = page_nodes.prerender();
397
429
  }
398
430
 
399
431
  if (state.emulator?.platform) {
432
+ // @ts-expect-error this has to be assigned lazily
400
433
  event.platform = await state.emulator.platform({ config, prerender });
401
434
  }
402
435
 
@@ -419,10 +452,10 @@ export async function internal_respond(request, options, manifest, state) {
419
452
  add_cookies_to_headers(response.headers, new_cookies.values());
420
453
  return response;
421
454
  } catch (err) {
422
- return await handle_fatal_error(event, event_state, options, err);
455
+ return await handle_fatal_error(event, state, options, err);
423
456
  }
424
457
  }
425
- return await handle_fatal_error(event, event_state, options, e);
458
+ return await handle_fatal_error(event, state, options, e);
426
459
  }
427
460
 
428
461
  async function handle() {
@@ -451,7 +484,7 @@ export async function internal_respond(request, options, manifest, state) {
451
484
  }
452
485
  };
453
486
 
454
- return await with_request_store({ event: traced_event, state: event_state }, () =>
487
+ return await with_request_store({ event: traced_event, state }, () =>
455
488
  options.hooks.handle({
456
489
  event: traced_event,
457
490
  resolve: (event, opts) => {
@@ -541,9 +574,9 @@ export async function internal_respond(request, options, manifest, state) {
541
574
  }
542
575
 
543
576
  /**
544
- * @param {import('@sveltejs/kit').RequestEvent} event
577
+ * @param {import('$app/server').RequestEvent} event
545
578
  * @param {PageNodes | undefined} page_nodes
546
- * @param {import('@sveltejs/kit').ResolveOptions} [opts]
579
+ * @param {import('@sveltejs/kit/hooks').ResolveOptions} [opts]
547
580
  */
548
581
  async function resolve(event, page_nodes, opts) {
549
582
  try {
@@ -558,11 +591,9 @@ export async function internal_respond(request, options, manifest, state) {
558
591
  if (resolved_path === null) {
559
592
  return await respond_with_error({
560
593
  event,
561
- event_state,
594
+ state,
562
595
  options,
563
596
  manifest,
564
- state,
565
- status: 400,
566
597
  error: new SvelteKitError(
567
598
  400,
568
599
  'Malformed URI',
@@ -575,10 +606,9 @@ export async function internal_respond(request, options, manifest, state) {
575
606
  if (options.hash_routing || state.prerendering?.fallback) {
576
607
  return await render_response({
577
608
  event,
578
- event_state,
609
+ state,
579
610
  options,
580
611
  manifest,
581
- state,
582
612
  page_config: { ssr: false, csr: true },
583
613
  status: 200,
584
614
  error: null,
@@ -592,12 +622,12 @@ export async function internal_respond(request, options, manifest, state) {
592
622
  ],
593
623
  fetched: [],
594
624
  resolve_opts,
595
- data_serializer: server_data_serializer(event, event_state, options)
625
+ data_serializer: server_data_serializer(event, state, options)
596
626
  });
597
627
  }
598
628
 
599
629
  if (remote_id) {
600
- return await handle_remote_call(event, event_state, options, manifest, remote_id);
630
+ return await handle_remote_call(event, state, options, manifest, remote_id);
601
631
  }
602
632
 
603
633
  if (route) {
@@ -609,62 +639,85 @@ export async function internal_respond(request, options, manifest, state) {
609
639
  if (is_data_request) {
610
640
  response = await render_data(
611
641
  event,
612
- event_state,
642
+ state,
613
643
  route,
614
644
  options,
615
645
  manifest,
616
- state,
617
646
  invalidated_data_nodes,
618
647
  trailing_slash
619
648
  );
620
- } else if (route.endpoint && (!route.page || is_endpoint_request(event))) {
621
- response = await render_endpoint(event, event_state, await route.endpoint(), state);
622
- } else if (route.page) {
623
- if (!page_nodes) {
624
- throw new Error('page_nodes not found. This should never happen');
625
- } else if (page_methods.has(method)) {
626
- response = await render_page(
627
- event,
628
- event_state,
629
- route.page,
630
- options,
631
- manifest,
632
- state,
633
- page_nodes,
634
- resolve_opts
635
- );
636
- } else {
637
- const allowed_methods = new Set(allowed_page_methods);
638
- const node = await manifest._.nodes[route.page.leaf]();
639
- if (node?.server?.actions) {
640
- allowed_methods.add('POST');
649
+ } else {
650
+ let endpoint;
651
+ if (
652
+ route.endpoint &&
653
+ (!route.page || (!state.prerendering && is_endpoint_request(event)))
654
+ ) {
655
+ endpoint = await route.endpoint();
656
+
657
+ // Prefer rendering the page if the endpoint can't handle this GET, HEAD, or POST request
658
+ if (route.page && (method === 'GET' || method === 'HEAD' || method === 'POST')) {
659
+ const endpoint_can_handle =
660
+ method === 'POST'
661
+ ? !!(endpoint.POST || endpoint.fallback)
662
+ : !!(endpoint.GET || endpoint.fallback || (method === 'HEAD' && endpoint.HEAD));
663
+ if (!endpoint_can_handle) {
664
+ endpoint = undefined;
665
+ }
641
666
  }
667
+ }
642
668
 
643
- if (method === 'OPTIONS') {
644
- // This will deny CORS preflight requests implicitly because we don't
645
- // add the required CORS headers to the response.
646
- response = new Response(null, {
647
- status: 204,
648
- headers: {
649
- allow: Array.from(allowed_methods.values()).join(', ')
650
- }
651
- });
669
+ if (endpoint) {
670
+ response = await render_endpoint(event, state, endpoint);
671
+ } else if (route.page) {
672
+ if (!page_nodes) {
673
+ throw new Error('page_nodes not found. This should never happen');
674
+ } else if (page_methods.has(method)) {
675
+ response = await render_page(
676
+ event,
677
+ state,
678
+ route.page,
679
+ options,
680
+ manifest,
681
+ page_nodes,
682
+ resolve_opts
683
+ );
652
684
  } else {
653
- const mod = [...allowed_methods].reduce((acc, curr) => {
654
- acc[curr] = true;
655
- return acc;
656
- }, /** @type {Record<string, any>} */ ({}));
657
- response = method_not_allowed(mod, method);
685
+ const allowed_methods = new Set(allowed_page_methods);
686
+ const node = await manifest._.nodes[route.page.leaf]();
687
+ if (node?.server?.actions) {
688
+ allowed_methods.add('POST');
689
+ }
690
+
691
+ if (method === 'OPTIONS') {
692
+ // This will deny CORS preflight requests implicitly because we don't
693
+ // add the required CORS headers to the response.
694
+ response = new Response(null, {
695
+ status: 204,
696
+ headers: {
697
+ allow: Array.from(allowed_methods.values()).join(', ')
698
+ }
699
+ });
700
+ } else {
701
+ const mod = [...allowed_methods].reduce((acc, curr) => {
702
+ acc[curr] = true;
703
+ return acc;
704
+ }, /** @type {Record<string, any>} */ ({}));
705
+ response = method_not_allowed(mod, method);
706
+ }
658
707
  }
708
+ } else {
709
+ // a route will always have a page or an endpoint, but TypeScript doesn't know that
710
+ throw new Error('Route is neither page nor endpoint. This should never happen');
659
711
  }
660
- } else {
661
- // a route will always have a page or an endpoint, but TypeScript doesn't know that
662
- throw new Error('Route is neither page nor endpoint. This should never happen');
663
712
  }
664
713
 
665
714
  // If the route contains a page and an endpoint, we need to add a
666
715
  // `Vary: Accept` header to the response because of browser caching
667
- if (request.method === 'GET' && route.page && route.endpoint) {
716
+ if (
717
+ (request.method === 'GET' || request.method === 'HEAD') &&
718
+ route.page &&
719
+ route.endpoint
720
+ ) {
668
721
  const vary = response.headers
669
722
  .get('vary')
670
723
  ?.split(',')
@@ -701,13 +754,18 @@ export async function internal_respond(request, options, manifest, state) {
701
754
  // if this request came direct from the user, rather than
702
755
  // via our own `fetch`, render a 404 page
703
756
  if (state.depth === 0) {
757
+ if (non_html_fetch_destinations.has(event.request.headers.get('sec-fetch-dest') ?? '')) {
758
+ return text('Not Found', {
759
+ status: 404,
760
+ headers: { vary: 'Sec-Fetch-Dest' }
761
+ });
762
+ }
763
+
704
764
  return await respond_with_error({
705
765
  event,
706
- event_state,
766
+ state,
707
767
  options,
708
768
  manifest,
709
- state,
710
- status: 404,
711
769
  error: new SvelteKitError(404, 'Not Found', `Not found: ${event.url.pathname}`),
712
770
  resolve_opts
713
771
  });
@@ -728,12 +786,13 @@ export async function internal_respond(request, options, manifest, state) {
728
786
  // and I don't even know how to describe it. need to investigate at some point
729
787
 
730
788
  // HttpError from endpoint can end up here - TODO should it be handled there instead?
731
- return await handle_fatal_error(event, event_state, options, e);
789
+ return await handle_fatal_error(event, state, options, e);
732
790
  } finally {
733
791
  event.cookies.set = () => {
734
792
  throw new Error('Cannot use `cookies.set(...)` after the response has been generated');
735
793
  };
736
794
 
795
+ // @ts-expect-error this has to be assigned lazily
737
796
  event.setHeaders = () => {
738
797
  throw new Error('Cannot use `setHeaders(...)` after the response has been generated');
739
798
  };