@sveltejs/kit 2.18.0 → 2.19.0

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.
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@sveltejs/kit",
3
- "version": "2.18.0",
3
+ "version": "2.19.0",
4
4
  "description": "SvelteKit is the fastest way to build Svelte apps",
5
5
  "keywords": [
6
6
  "framework",
@@ -1,22 +1,15 @@
1
1
  import { join } from 'node:path';
2
2
  import { pathToFileURL } from 'node:url';
3
- import { get_option } from '../../utils/options.js';
4
- import {
5
- validate_layout_exports,
6
- validate_layout_server_exports,
7
- validate_page_exports,
8
- validate_page_server_exports,
9
- validate_server_exports
10
- } from '../../utils/exports.js';
3
+ import { validate_server_exports } from '../../utils/exports.js';
11
4
  import { load_config } from '../config/index.js';
12
5
  import { forked } from '../../utils/fork.js';
13
6
  import { installPolyfills } from '../../exports/node/polyfills.js';
14
7
  import { ENDPOINT_METHODS } from '../../constants.js';
15
8
  import { filter_private_env, filter_public_env } from '../../utils/env.js';
16
9
  import { has_server_load, resolve_route } from '../../utils/routing.js';
17
- import { get_page_config } from '../../utils/route_config.js';
18
10
  import { check_feature } from '../../utils/features.js';
19
11
  import { createReadableStream } from '@sveltejs/kit/node';
12
+ import { PageNodes } from '../../utils/page_nodes.js';
20
13
 
21
14
  export default forked(import.meta.url, analyse);
22
15
 
@@ -190,25 +183,18 @@ function analyse_endpoint(route, mod) {
190
183
  * @param {import('types').SSRNode} leaf
191
184
  */
192
185
  function analyse_page(layouts, leaf) {
193
- for (const layout of layouts) {
194
- if (layout) {
195
- validate_layout_server_exports(layout.server, layout.server_id);
196
- validate_layout_exports(layout.universal, layout.universal_id);
197
- }
198
- }
199
-
200
186
  /** @type {Array<'GET' | 'POST'>} */
201
187
  const methods = ['GET'];
202
188
  if (leaf.server?.actions) methods.push('POST');
203
189
 
204
- validate_page_server_exports(leaf.server, leaf.server_id);
205
- validate_page_exports(leaf.universal, leaf.universal_id);
190
+ const nodes = new PageNodes([...layouts, leaf]);
191
+ nodes.validate();
206
192
 
207
193
  return {
208
- config: get_page_config([...layouts, leaf]),
194
+ config: nodes.get_config(),
209
195
  entries: leaf.universal?.entries ?? leaf.server?.entries,
210
196
  methods,
211
- prerender: get_option([...layouts, leaf], 'prerender') ?? false
197
+ prerender: nodes.prerender()
212
198
  };
213
199
  }
214
200
 
@@ -229,6 +229,7 @@ export function isActionFailure(e) {
229
229
  * ```
230
230
  * @param {URL | string} url
231
231
  * @returns {{ url: URL, wasNormalized: boolean, denormalize: (url?: string | URL) => URL }}
232
+ * @since 2.18.0
232
233
  */
233
234
  export function normalizeUrl(url) {
234
235
  url = new URL(url, 'http://internal');
@@ -814,7 +814,7 @@ export type ClientInit = () => MaybePromise<void>;
814
814
  * The [`reroute`](https://svelte.dev/docs/kit/hooks#Universal-hooks-reroute) hook allows you to modify the URL before it is used to determine which route to render.
815
815
  * @since 2.3.0
816
816
  */
817
- export type Reroute = (event: { url: URL }) => MaybePromise<void | string>;
817
+ export type Reroute = (event: { url: URL; fetch: typeof fetch }) => MaybePromise<void | string>;
818
818
 
819
819
  /**
820
820
  * The [`transport`](https://svelte.dev/docs/kit/hooks#Universal-hooks-transport) hook allows you to transport custom types across the server/client boundary.
@@ -188,6 +188,17 @@ const components = [];
188
188
  /** @type {{id: string, token: {}, promise: Promise<import('./types.js').NavigationResult>} | null} */
189
189
  let load_cache = null;
190
190
 
191
+ /**
192
+ * @type {Map<string, Promise<URL>>}
193
+ * Cache for client-side rerouting, since it could contain async calls which we want to
194
+ * avoid running multiple times which would slow down navigations (e.g. else preloading
195
+ * wouldn't help because on navigation it would be called again). Since `reroute` should be
196
+ * a pure function (i.e. always return the same) value it's safe to cache across navigations.
197
+ * The server reroute calls don't need to be cached because they are called using `import(...)`
198
+ * which is cached per the JS spec.
199
+ */
200
+ const reroute_cache = new Map();
201
+
191
202
  /**
192
203
  * Note on before_navigate_callbacks, on_navigate_callbacks and after_navigate_callbacks:
193
204
  * do not re-assign as some closures keep references to these Sets
@@ -679,12 +690,7 @@ async function load_node({ loader, parent, url, params, route, server_data_node
679
690
  app.hash
680
691
  ),
681
692
  async fetch(resource, init) {
682
- /** @type {URL | string} */
683
- let requested;
684
-
685
693
  if (resource instanceof Request) {
686
- requested = resource.url;
687
-
688
694
  // we're not allowed to modify the received `Request` object, so in order
689
695
  // to fixup relative urls we create a new equivalent `init` object instead
690
696
  init = {
@@ -709,25 +715,15 @@ async function load_node({ loader, parent, url, params, route, server_data_node
709
715
  signal: resource.signal,
710
716
  ...init
711
717
  };
712
- } else {
713
- requested = resource;
714
718
  }
715
719
 
716
- // we must fixup relative urls so they are resolved from the target page
717
- const resolved = new URL(requested, url);
720
+ const { resolved, promise } = resolve_fetch_url(resource, init, url);
721
+
718
722
  if (is_tracking) {
719
723
  depends(resolved.href);
720
724
  }
721
725
 
722
- // match ssr serialized data url, which is important to find cached responses
723
- if (resolved.origin === url.origin) {
724
- requested = resolved.href.slice(url.origin.length);
725
- }
726
-
727
- // prerendered pages may be served from any origin, so `initial_fetch` urls shouldn't be resolved
728
- return started
729
- ? subsequent_fetch(requested, resolved.href, init)
730
- : initial_fetch(requested, init);
726
+ return promise;
731
727
  },
732
728
  setHeaders: () => {}, // noop
733
729
  depends,
@@ -782,6 +778,30 @@ async function load_node({ loader, parent, url, params, route, server_data_node
782
778
  };
783
779
  }
784
780
 
781
+ /**
782
+ * @param {Request | string | URL} input
783
+ * @param {RequestInit | undefined} init
784
+ * @param {URL} url
785
+ */
786
+ function resolve_fetch_url(input, init, url) {
787
+ let requested = input instanceof Request ? input.url : input;
788
+
789
+ // we must fixup relative urls so they are resolved from the target page
790
+ const resolved = new URL(requested, url);
791
+
792
+ // match ssr serialized data url, which is important to find cached responses
793
+ if (resolved.origin === url.origin) {
794
+ requested = resolved.href.slice(url.origin.length);
795
+ }
796
+
797
+ // prerendered pages may be served from any origin, so `initial_fetch` urls shouldn't be resolved
798
+ const promise = started
799
+ ? subsequent_fetch(requested, resolved.href, init)
800
+ : initial_fetch(requested, init);
801
+
802
+ return { resolved, promise };
803
+ }
804
+
785
805
  /**
786
806
  * @param {boolean} parent_changed
787
807
  * @param {boolean} route_changed
@@ -1201,23 +1221,44 @@ async function load_root_error_page({ status, error, url, route }) {
1201
1221
  * @returns {Promise<URL | undefined>}
1202
1222
  */
1203
1223
  async function get_rerouted_url(url) {
1224
+ const href = url.href;
1225
+
1226
+ if (reroute_cache.has(href)) {
1227
+ return reroute_cache.get(href);
1228
+ }
1229
+
1204
1230
  let rerouted;
1231
+
1205
1232
  try {
1206
- // reroute could alter the given URL, so we pass a copy
1207
- rerouted = (await app.hooks.reroute({ url: new URL(url) })) ?? url;
1233
+ const promise = (async () => {
1234
+ // reroute could alter the given URL, so we pass a copy
1235
+ let rerouted =
1236
+ (await app.hooks.reroute({
1237
+ url: new URL(url),
1238
+ fetch: async (input, init) => {
1239
+ return resolve_fetch_url(input, init, url).promise;
1240
+ }
1241
+ })) ?? url;
1208
1242
 
1209
- if (typeof rerouted === 'string') {
1210
- const tmp = new URL(url); // do not mutate the incoming URL
1243
+ if (typeof rerouted === 'string') {
1244
+ const tmp = new URL(url); // do not mutate the incoming URL
1211
1245
 
1212
- if (app.hash) {
1213
- tmp.hash = rerouted;
1214
- } else {
1215
- tmp.pathname = rerouted;
1246
+ if (app.hash) {
1247
+ tmp.hash = rerouted;
1248
+ } else {
1249
+ tmp.pathname = rerouted;
1250
+ }
1251
+
1252
+ rerouted = tmp;
1216
1253
  }
1217
1254
 
1218
- rerouted = tmp;
1219
- }
1255
+ return rerouted;
1256
+ })();
1257
+
1258
+ reroute_cache.set(href, promise);
1259
+ rerouted = await promise;
1220
1260
  } catch (e) {
1261
+ reroute_cache.delete(href);
1221
1262
  if (DEV) {
1222
1263
  // in development, print the error...
1223
1264
  console.error(e);
@@ -29,13 +29,13 @@ function validate_options(options) {
29
29
  /**
30
30
  * @param {Request} request
31
31
  * @param {URL} url
32
- * @param {import('types').TrailingSlash} trailing_slash
33
32
  */
34
- export function get_cookies(request, url, trailing_slash) {
33
+ export function get_cookies(request, url) {
35
34
  const header = request.headers.get('cookie') ?? '';
36
35
  const initial_cookies = parse(header, { decode: (value) => value });
37
36
 
38
- const normalized_url = normalize_path(url.pathname, trailing_slash);
37
+ /** @type {string | undefined} */
38
+ let normalized_url;
39
39
 
40
40
  /** @type {Record<string, import('./page/types.js').Cookie>} */
41
41
  const new_cookies = {};
@@ -149,6 +149,9 @@ export function get_cookies(request, url, trailing_slash) {
149
149
  let path = options.path;
150
150
 
151
151
  if (!options.domain || options.domain === url.hostname) {
152
+ if (!normalized_url) {
153
+ throw new Error('Cannot serialize cookies until after the route is determined');
154
+ }
152
155
  path = resolve(normalized_url, path);
153
156
  }
154
157
 
@@ -190,12 +193,20 @@ export function get_cookies(request, url, trailing_slash) {
190
193
  .join('; ');
191
194
  }
192
195
 
196
+ /** @type {Array<() => void>} */
197
+ const internal_queue = [];
198
+
193
199
  /**
194
200
  * @param {string} name
195
201
  * @param {string} value
196
202
  * @param {import('./page/types.js').Cookie['options']} options
197
203
  */
198
204
  function set_internal(name, value, options) {
205
+ if (!normalized_url) {
206
+ internal_queue.push(() => set_internal(name, value, options));
207
+ return;
208
+ }
209
+
199
210
  let path = options.path;
200
211
 
201
212
  if (!options.domain || options.domain === url.hostname) {
@@ -220,7 +231,15 @@ export function get_cookies(request, url, trailing_slash) {
220
231
  }
221
232
  }
222
233
 
223
- return { cookies, new_cookies, get_cookie_header, set_internal };
234
+ /**
235
+ * @param {import('types').TrailingSlash} trailing_slash
236
+ */
237
+ function set_trailing_slash(trailing_slash) {
238
+ normalized_url = normalize_path(url.pathname, trailing_slash);
239
+ internal_queue.forEach((fn) => fn());
240
+ }
241
+
242
+ return { cookies, new_cookies, get_cookie_header, set_internal, set_trailing_slash };
224
243
  }
225
244
 
226
245
  /**
@@ -214,7 +214,7 @@ function check_named_default_separate(actions) {
214
214
 
215
215
  /**
216
216
  * @param {import('@sveltejs/kit').RequestEvent} event
217
- * @param {NonNullable<import('types').SSRNode['server']['actions']>} actions
217
+ * @param {NonNullable<import('types').ServerNode['actions']>} actions
218
218
  * @throws {Redirect | HttpError | SvelteKitError | Error}
219
219
  */
220
220
  async function call_action(event, actions) {
@@ -13,9 +13,7 @@ import {
13
13
  import { load_data, load_server_data } from './load_data.js';
14
14
  import { render_response } from './render.js';
15
15
  import { respond_with_error } from './respond_with_error.js';
16
- import { get_option } from '../../../utils/options.js';
17
16
  import { get_data_json } from '../data/index.js';
18
- import { load_page_nodes } from './load_page_nodes.js';
19
17
  import { DEV } from 'esm-env';
20
18
 
21
19
  /**
@@ -29,10 +27,11 @@ const MAX_DEPTH = 10;
29
27
  * @param {import('types').SSROptions} options
30
28
  * @param {import('@sveltejs/kit').SSRManifest} manifest
31
29
  * @param {import('types').SSRState} state
30
+ * @param {import('../../../utils/page_nodes.js').PageNodes} nodes
32
31
  * @param {import('types').RequiredResolveOptions} resolve_opts
33
32
  * @returns {Promise<Response>}
34
33
  */
35
- export async function render_page(event, page, options, manifest, state, resolve_opts) {
34
+ export async function render_page(event, page, options, manifest, state, nodes, resolve_opts) {
36
35
  if (state.depth > MAX_DEPTH) {
37
36
  // infinite request cycle detected
38
37
  return text(`Not found: ${event.url.pathname}`, {
@@ -46,9 +45,7 @@ export async function render_page(event, page, options, manifest, state, resolve
46
45
  }
47
46
 
48
47
  try {
49
- const nodes = await load_page_nodes(page, manifest);
50
-
51
- const leaf_node = /** @type {import('types').SSRNode} */ (nodes.at(-1));
48
+ const leaf_node = /** @type {import('types').SSRNode} */ (nodes.page());
52
49
 
53
50
  let status = 200;
54
51
 
@@ -70,16 +67,10 @@ export async function render_page(event, page, options, manifest, state, resolve
70
67
  }
71
68
  }
72
69
 
73
- const should_prerender_data = nodes.some(
74
- // prerender in case of trailingSlash because the client retrieves that value from the server
75
- (node) => node?.server?.load || node?.server?.trailingSlash !== undefined
76
- );
77
- const data_pathname = add_data_suffix(event.url.pathname);
78
-
79
70
  // it's crucial that we do this before returning the non-SSR response, otherwise
80
71
  // SvelteKit will erroneously believe that the path has been prerendered,
81
72
  // causing functions to be omitted from the manifest generated later
82
- const should_prerender = get_option(nodes, 'prerender') ?? false;
73
+ const should_prerender = nodes.prerender();
83
74
  if (should_prerender) {
84
75
  const mod = leaf_node.server;
85
76
  if (mod?.actions) {
@@ -96,13 +87,16 @@ export async function render_page(event, page, options, manifest, state, resolve
96
87
  // inherit the prerender option of the page
97
88
  state.prerender_default = should_prerender;
98
89
 
90
+ const should_prerender_data = nodes.should_prerender_data();
91
+ const data_pathname = add_data_suffix(event.url.pathname);
92
+
99
93
  /** @type {import('./types.js').Fetched[]} */
100
94
  const fetched = [];
101
95
 
102
96
  // renders an empty 'shell' page if SSR is turned off and if there is
103
97
  // no server data to prerender. As a result, the load functions and rendering
104
98
  // only occur client-side.
105
- if (get_option(nodes, 'ssr') === false && !(state.prerendering && should_prerender_data)) {
99
+ if (nodes.ssr() === false && !(state.prerendering && should_prerender_data)) {
106
100
  // if the user makes a request through a non-enhanced form, the returned value is lost
107
101
  // because there is no SSR or client-side handling of the response
108
102
  if (DEV && action_result && !event.request.headers.has('x-sveltekit-action')) {
@@ -123,7 +117,7 @@ export async function render_page(event, page, options, manifest, state, resolve
123
117
  fetched,
124
118
  page_config: {
125
119
  ssr: false,
126
- csr: get_option(nodes, 'csr') ?? true
120
+ csr: nodes.csr()
127
121
  },
128
122
  status,
129
123
  error: null,
@@ -142,7 +136,7 @@ export async function render_page(event, page, options, manifest, state, resolve
142
136
  let load_error = null;
143
137
 
144
138
  /** @type {Array<Promise<import('types').ServerDataNode | null>>} */
145
- const server_promises = nodes.map((node, i) => {
139
+ const server_promises = nodes.data.map((node, i) => {
146
140
  if (load_error) {
147
141
  // if an error happens immediately, don't bother with the rest of the nodes
148
142
  throw load_error;
@@ -177,10 +171,10 @@ export async function render_page(event, page, options, manifest, state, resolve
177
171
  });
178
172
  });
179
173
 
180
- const csr = get_option(nodes, 'csr') ?? true;
174
+ const csr = nodes.csr();
181
175
 
182
176
  /** @type {Array<Promise<Record<string, any> | null>>} */
183
- const load_promises = nodes.map((node, i) => {
177
+ const load_promises = nodes.data.map((node, i) => {
184
178
  if (load_error) throw load_error;
185
179
  return Promise.resolve().then(async () => {
186
180
  try {
@@ -211,8 +205,8 @@ export async function render_page(event, page, options, manifest, state, resolve
211
205
  for (const p of server_promises) p.catch(() => {});
212
206
  for (const p of load_promises) p.catch(() => {});
213
207
 
214
- for (let i = 0; i < nodes.length; i += 1) {
215
- const node = nodes[i];
208
+ for (let i = 0; i < nodes.data.length; i += 1) {
209
+ const node = nodes.data[i];
216
210
 
217
211
  if (node) {
218
212
  try {
@@ -300,7 +294,7 @@ export async function render_page(event, page, options, manifest, state, resolve
300
294
  });
301
295
  }
302
296
 
303
- const ssr = get_option(nodes, 'ssr') ?? true;
297
+ const ssr = nodes.ssr();
304
298
 
305
299
  return await render_response({
306
300
  event,
@@ -309,7 +303,7 @@ export async function render_page(event, page, options, manifest, state, resolve
309
303
  state,
310
304
  resolve_opts,
311
305
  page_config: {
312
- csr: get_option(nodes, 'csr') ?? true,
306
+ csr: nodes.csr(),
313
307
  ssr
314
308
  },
315
309
  status,
@@ -116,11 +116,6 @@ export async function render_response({
116
116
  }
117
117
 
118
118
  if (page_config.ssr) {
119
- if (__SVELTEKIT_DEV__ && !branch.at(-1)?.node.component) {
120
- // Can only be the leaf, layouts have a fallback component generated
121
- throw new Error(`Missing +page.svelte component for route ${event.route.id}`);
122
- }
123
-
124
119
  /** @type {Record<string, any>} */
125
120
  const props = {
126
121
  stores: {
@@ -128,7 +123,15 @@ export async function render_response({
128
123
  navigating: writable(null),
129
124
  updated
130
125
  },
131
- constructors: await Promise.all(branch.map(({ node }) => node.component())),
126
+ constructors: await Promise.all(
127
+ branch.map(({ node }) => {
128
+ if (!node.component) {
129
+ // Can only be the leaf, layouts have a fallback component generated
130
+ throw new Error(`Missing +page.svelte component for route ${event.route.id}`);
131
+ }
132
+ return node.component();
133
+ })
134
+ ),
132
135
  form: form_value
133
136
  };
134
137
 
@@ -1,9 +1,9 @@
1
1
  import { render_response } from './render.js';
2
2
  import { load_data, load_server_data } from './load_data.js';
3
3
  import { handle_error_and_jsonify, static_error_page, redirect_response } from '../utils.js';
4
- import { get_option } from '../../../utils/options.js';
5
4
  import { Redirect } from '../../control.js';
6
5
  import { get_status } from '../../../utils/error.js';
6
+ import { PageNodes } from '../../../utils/page_nodes.js';
7
7
 
8
8
  /**
9
9
  * @typedef {import('./types.js').Loaded} Loaded
@@ -40,8 +40,9 @@ export async function respond_with_error({
40
40
  try {
41
41
  const branch = [];
42
42
  const default_layout = await manifest._.nodes[0](); // 0 is always the root layout
43
- const ssr = get_option([default_layout], 'ssr') ?? true;
44
- const csr = get_option([default_layout], 'csr') ?? true;
43
+ const nodes = new PageNodes([default_layout]);
44
+ const ssr = nodes.ssr();
45
+ const csr = nodes.csr();
45
46
 
46
47
  if (ssr) {
47
48
  state.error = true;
@@ -11,21 +11,13 @@ import { exec } from '../../utils/routing.js';
11
11
  import { redirect_json_response, render_data } from './data/index.js';
12
12
  import { add_cookies_to_headers, get_cookies } from './cookie.js';
13
13
  import { create_fetch } from './fetch.js';
14
+ import { PageNodes } from '../../utils/page_nodes.js';
14
15
  import { HttpError, Redirect, SvelteKitError } from '../control.js';
15
- import {
16
- validate_layout_exports,
17
- validate_layout_server_exports,
18
- validate_page_exports,
19
- validate_page_server_exports,
20
- validate_server_exports
21
- } from '../../utils/exports.js';
22
- import { get_option } from '../../utils/options.js';
16
+ import { validate_server_exports } from '../../utils/exports.js';
23
17
  import { json, text } from '../../exports/index.js';
24
18
  import { action_json_redirect, is_action_json_request } from './page/actions.js';
25
19
  import { INVALIDATED_PARAM, TRAILING_SLASH_PARAM } from '../shared.js';
26
20
  import { get_public_env } from './env_module.js';
27
- import { load_page_nodes } from './page/load_page_nodes.js';
28
- import { get_page_config } from '../../utils/route_config.js';
29
21
  import { resolve_route } from './page/server_routing.js';
30
22
  import { validateHeaders } from './validate-headers.js';
31
23
  import {
@@ -111,11 +103,82 @@ export async function respond(request, options, manifest, state) {
111
103
  url.searchParams.delete(INVALIDATED_PARAM);
112
104
  }
113
105
 
106
+ /** @type {Record<string, string>} */
107
+ const headers = {};
108
+
109
+ const { cookies, new_cookies, get_cookie_header, set_internal, set_trailing_slash } = get_cookies(
110
+ request,
111
+ url
112
+ );
113
+
114
+ /** @type {import('@sveltejs/kit').RequestEvent} */
115
+ const event = {
116
+ cookies,
117
+ // @ts-expect-error `fetch` needs to be created after the `event` itself
118
+ fetch: null,
119
+ getClientAddress:
120
+ state.getClientAddress ||
121
+ (() => {
122
+ throw new Error(
123
+ `${__SVELTEKIT_ADAPTER_NAME__} does not specify getClientAddress. Please raise an issue`
124
+ );
125
+ }),
126
+ locals: {},
127
+ params: {},
128
+ platform: state.platform,
129
+ request,
130
+ route: { id: null },
131
+ setHeaders: (new_headers) => {
132
+ if (__SVELTEKIT_DEV__) {
133
+ validateHeaders(new_headers);
134
+ }
135
+
136
+ for (const key in new_headers) {
137
+ const lower = key.toLowerCase();
138
+ const value = new_headers[key];
139
+
140
+ if (lower === 'set-cookie') {
141
+ throw new Error(
142
+ 'Use `event.cookies.set(name, value, options)` instead of `event.setHeaders` to set cookies'
143
+ );
144
+ } else if (lower in headers) {
145
+ throw new Error(`"${key}" header is already set`);
146
+ } else {
147
+ headers[lower] = value;
148
+
149
+ if (state.prerendering && lower === 'cache-control') {
150
+ state.prerendering.cache = /** @type {string} */ (value);
151
+ }
152
+ }
153
+ }
154
+ },
155
+ url,
156
+ isDataRequest: is_data_request,
157
+ isSubRequest: state.depth > 0
158
+ };
159
+
160
+ event.fetch = create_fetch({
161
+ event,
162
+ options,
163
+ manifest,
164
+ state,
165
+ get_cookie_header,
166
+ set_internal
167
+ });
168
+
169
+ if (state.emulator?.platform) {
170
+ event.platform = await state.emulator.platform({
171
+ config: {},
172
+ prerender: !!state.prerendering?.fallback
173
+ });
174
+ }
175
+
114
176
  let resolved_path;
115
177
 
116
178
  try {
117
179
  // reroute could alter the given URL, so we pass a copy
118
- resolved_path = (await options.hooks.reroute({ url: new URL(url) })) ?? url.pathname;
180
+ resolved_path =
181
+ (await options.hooks.reroute({ url: new URL(url), fetch: event.fetch })) ?? url.pathname;
119
182
  } catch {
120
183
  return text('Internal Server Error', {
121
184
  status: 500
@@ -131,9 +194,6 @@ export async function respond(request, options, manifest, state) {
131
194
  /** @type {import('types').SSRRoute | null} */
132
195
  let route = null;
133
196
 
134
- /** @type {Record<string, string>} */
135
- let params = {};
136
-
137
197
  if (base && !state.prerendering?.fallback) {
138
198
  if (!resolved_path.startsWith(base)) {
139
199
  return text('Not found', { status: 404 });
@@ -167,68 +227,13 @@ export async function respond(request, options, manifest, state) {
167
227
  const matched = exec(match, candidate.params, matchers);
168
228
  if (matched) {
169
229
  route = candidate;
170
- params = decode_params(matched);
230
+ event.route = { id: route.id };
231
+ event.params = decode_params(matched);
171
232
  break;
172
233
  }
173
234
  }
174
235
  }
175
236
 
176
- /** @type {import('types').TrailingSlash | void} */
177
- let trailing_slash = undefined;
178
-
179
- /** @type {Record<string, string>} */
180
- const headers = {};
181
-
182
- /** @type {Record<string, import('./page/types.js').Cookie>} */
183
- let cookies_to_add = {};
184
-
185
- /** @type {import('@sveltejs/kit').RequestEvent} */
186
- const event = {
187
- // @ts-expect-error `cookies` and `fetch` need to be created after the `event` itself
188
- cookies: null,
189
- // @ts-expect-error
190
- fetch: null,
191
- getClientAddress:
192
- state.getClientAddress ||
193
- (() => {
194
- throw new Error(
195
- `${__SVELTEKIT_ADAPTER_NAME__} does not specify getClientAddress. Please raise an issue`
196
- );
197
- }),
198
- locals: {},
199
- params,
200
- platform: state.platform,
201
- request,
202
- route: { id: route?.id ?? null },
203
- setHeaders: (new_headers) => {
204
- if (__SVELTEKIT_DEV__) {
205
- validateHeaders(new_headers);
206
- }
207
-
208
- for (const key in new_headers) {
209
- const lower = key.toLowerCase();
210
- const value = new_headers[key];
211
-
212
- if (lower === 'set-cookie') {
213
- throw new Error(
214
- 'Use `event.cookies.set(name, value, options)` instead of `event.setHeaders` to set cookies'
215
- );
216
- } else if (lower in headers) {
217
- throw new Error(`"${key}" header is already set`);
218
- } else {
219
- headers[lower] = value;
220
-
221
- if (state.prerendering && lower === 'cache-control') {
222
- state.prerendering.cache = /** @type {string} */ (value);
223
- }
224
- }
225
- }
226
- },
227
- url,
228
- isDataRequest: is_data_request,
229
- isSubRequest: state.depth > 0
230
- };
231
-
232
237
  /** @type {import('types').RequiredResolveOptions} */
233
238
  let resolve_opts = {
234
239
  transformPageChunk: default_transform,
@@ -236,51 +241,36 @@ export async function respond(request, options, manifest, state) {
236
241
  preload: default_preload
237
242
  };
238
243
 
244
+ /** @type {import('types').TrailingSlash} */
245
+ let trailing_slash = 'never';
246
+
239
247
  try {
248
+ /** @type {PageNodes|undefined} */
249
+ const page_nodes = route?.page
250
+ ? new PageNodes(await load_page_nodes(route.page, manifest))
251
+ : undefined;
252
+
240
253
  // determine whether we need to redirect to add/remove a trailing slash
241
254
  if (route) {
242
255
  // if `paths.base === '/a/b/c`, then the root route is `/a/b/c/`,
243
256
  // regardless of the `trailingSlash` route option
244
257
  if (url.pathname === base || url.pathname === base + '/') {
245
258
  trailing_slash = 'always';
246
- } else if (route.page) {
247
- const nodes = await load_page_nodes(route.page, manifest);
248
-
259
+ } else if (page_nodes) {
249
260
  if (DEV) {
250
- const layouts = nodes.slice(0, -1);
251
- const page = nodes.at(-1);
252
-
253
- for (const layout of layouts) {
254
- if (layout) {
255
- validate_layout_server_exports(
256
- layout.server,
257
- /** @type {string} */ (layout.server_id)
258
- );
259
- validate_layout_exports(
260
- layout.universal,
261
- /** @type {string} */ (layout.universal_id)
262
- );
263
- }
264
- }
265
-
266
- if (page) {
267
- validate_page_server_exports(page.server, /** @type {string} */ (page.server_id));
268
- validate_page_exports(page.universal, /** @type {string} */ (page.universal_id));
269
- }
261
+ page_nodes.validate();
270
262
  }
271
-
272
- trailing_slash = get_option(nodes, 'trailingSlash');
263
+ trailing_slash = page_nodes.trailing_slash();
273
264
  } else if (route.endpoint) {
274
265
  const node = await route.endpoint();
275
- trailing_slash = node.trailingSlash;
276
-
266
+ trailing_slash = node.trailingSlash ?? 'never';
277
267
  if (DEV) {
278
268
  validate_server_exports(node, /** @type {string} */ (route.endpoint_id));
279
269
  }
280
270
  }
281
271
 
282
272
  if (!is_data_request) {
283
- const normalized = normalize_path(url.pathname, trailing_slash ?? 'never');
273
+ const normalized = normalize_path(url.pathname, trailing_slash);
284
274
 
285
275
  if (normalized !== url.pathname && !state.prerendering?.fallback) {
286
276
  return new Response(undefined, {
@@ -306,10 +296,9 @@ export async function respond(request, options, manifest, state) {
306
296
  const node = await route.endpoint();
307
297
  config = node.config ?? config;
308
298
  prerender = node.prerender ?? prerender;
309
- } else if (route.page) {
310
- const nodes = await load_page_nodes(route.page, manifest);
311
- config = get_page_config(nodes) ?? config;
312
- prerender = get_option(nodes, 'prerender') ?? false;
299
+ } else if (page_nodes) {
300
+ config = page_nodes.get_config() ?? config;
301
+ prerender = page_nodes.prerender();
313
302
  }
314
303
 
315
304
  if (state.before_handle) {
@@ -320,36 +309,16 @@ export async function respond(request, options, manifest, state) {
320
309
  event.platform = await state.emulator.platform({ config, prerender });
321
310
  }
322
311
  }
323
- } else if (state.emulator?.platform) {
324
- event.platform = await state.emulator.platform({
325
- config: {},
326
- prerender: !!state.prerendering?.fallback
327
- });
328
312
  }
329
313
 
330
- const { cookies, new_cookies, get_cookie_header, set_internal } = get_cookies(
331
- request,
332
- url,
333
- trailing_slash ?? 'never'
334
- );
335
-
336
- cookies_to_add = new_cookies;
337
- event.cookies = cookies;
338
- event.fetch = create_fetch({
339
- event,
340
- options,
341
- manifest,
342
- state,
343
- get_cookie_header,
344
- set_internal
345
- });
314
+ set_trailing_slash(trailing_slash);
346
315
 
347
316
  if (state.prerendering && !state.prerendering.fallback) disable_search(url);
348
317
 
349
318
  const response = await options.hooks.handle({
350
319
  event,
351
320
  resolve: (event, opts) =>
352
- resolve(event, opts).then((response) => {
321
+ resolve(event, page_nodes, opts).then((response) => {
353
322
  // add headers/cookies here, rather than inside `resolve`, so that we
354
323
  // can do it once for all responses instead of once per `return`
355
324
  for (const key in headers) {
@@ -357,7 +326,7 @@ export async function respond(request, options, manifest, state) {
357
326
  response.headers.set(key, /** @type {string} */ (value));
358
327
  }
359
328
 
360
- add_cookies_to_headers(response.headers, Object.values(cookies_to_add));
329
+ add_cookies_to_headers(response.headers, Object.values(new_cookies));
361
330
 
362
331
  if (state.prerendering && event.route.id !== null) {
363
332
  response.headers.set('x-sveltekit-routeid', encodeURI(event.route.id));
@@ -418,7 +387,7 @@ export async function respond(request, options, manifest, state) {
418
387
  : route?.page && is_action_json_request(event)
419
388
  ? action_json_redirect(e)
420
389
  : redirect_response(e.status, e.location);
421
- add_cookies_to_headers(response.headers, Object.values(cookies_to_add));
390
+ add_cookies_to_headers(response.headers, Object.values(new_cookies));
422
391
  return response;
423
392
  }
424
393
  return await handle_fatal_error(event, options, e);
@@ -426,9 +395,10 @@ export async function respond(request, options, manifest, state) {
426
395
 
427
396
  /**
428
397
  * @param {import('@sveltejs/kit').RequestEvent} event
398
+ * @param {PageNodes | undefined} page_nodes
429
399
  * @param {import('@sveltejs/kit').ResolveOptions} [opts]
430
400
  */
431
- async function resolve(event, opts) {
401
+ async function resolve(event, page_nodes, opts) {
432
402
  try {
433
403
  if (opts) {
434
404
  resolve_opts = {
@@ -467,13 +437,23 @@ export async function respond(request, options, manifest, state) {
467
437
  manifest,
468
438
  state,
469
439
  invalidated_data_nodes,
470
- trailing_slash ?? 'never'
440
+ trailing_slash
471
441
  );
472
442
  } else if (route.endpoint && (!route.page || is_endpoint_request(event))) {
473
443
  response = await render_endpoint(event, await route.endpoint(), state);
474
444
  } else if (route.page) {
475
- if (page_methods.has(method)) {
476
- response = await render_page(event, route.page, options, manifest, state, resolve_opts);
445
+ if (!page_nodes) {
446
+ throw new Error('page_nodes not found. This should never happen');
447
+ } else if (page_methods.has(method)) {
448
+ response = await render_page(
449
+ event,
450
+ route.page,
451
+ options,
452
+ manifest,
453
+ state,
454
+ page_nodes,
455
+ resolve_opts
456
+ );
477
457
  } else {
478
458
  const allowed_methods = new Set(allowed_page_methods);
479
459
  const node = await manifest._.nodes[route.page.leaf]();
@@ -499,9 +479,8 @@ export async function respond(request, options, manifest, state) {
499
479
  }
500
480
  }
501
481
  } else {
502
- // a route will always have a page or an endpoint, but TypeScript
503
- // doesn't know that
504
- throw new Error('This should never happen');
482
+ // a route will always have a page or an endpoint, but TypeScript doesn't know that
483
+ throw new Error('Route is neither page nor endpoint. This should never happen');
505
484
  }
506
485
 
507
486
  // If the route contains a page and an endpoint, we need to add a
@@ -578,3 +557,15 @@ export async function respond(request, options, manifest, state) {
578
557
  }
579
558
  }
580
559
  }
560
+
561
+ /**
562
+ * @param {import('types').PageNodeIndexes} page
563
+ * @param {import('@sveltejs/kit').SSRManifest} manifest
564
+ */
565
+ export function load_page_nodes(page, manifest) {
566
+ return Promise.all([
567
+ // we use == here rather than === because [undefined] serializes as "[null]"
568
+ ...page.layouts.map((n) => (n == undefined ? n : manifest._.nodes[n]())),
569
+ manifest._.nodes[page.leaf]()
570
+ ]);
571
+ }
@@ -364,8 +364,28 @@ export interface SSRComponent {
364
364
 
365
365
  export type SSRComponentLoader = () => Promise<SSRComponent>;
366
366
 
367
+ export interface UniversalNode {
368
+ load?: Load;
369
+ prerender?: PrerenderOption;
370
+ ssr?: boolean;
371
+ csr?: boolean;
372
+ trailingSlash?: TrailingSlash;
373
+ config?: any;
374
+ entries?: PrerenderEntryGenerator;
375
+ }
376
+
377
+ export interface ServerNode {
378
+ load?: ServerLoad;
379
+ prerender?: PrerenderOption;
380
+ ssr?: boolean;
381
+ csr?: boolean;
382
+ trailingSlash?: TrailingSlash;
383
+ actions?: Actions;
384
+ config?: any;
385
+ entries?: PrerenderEntryGenerator;
386
+ }
387
+
367
388
  export interface SSRNode {
368
- component: SSRComponentLoader;
369
389
  /** index into the `nodes` array in the generated `client/app.js`. */
370
390
  index: number;
371
391
  /** external JS files that are loaded on the client. `imports[0]` is the entry point (e.g. `client/nodes/0.js`) */
@@ -374,32 +394,18 @@ export interface SSRNode {
374
394
  stylesheets: string[];
375
395
  /** external font files that are loaded on the client */
376
396
  fonts: string[];
377
- /** inlined styles. */
378
- inline_styles?(): MaybePromise<Record<string, string>>;
379
-
380
- universal: {
381
- load?: Load;
382
- prerender?: PrerenderOption;
383
- ssr?: boolean;
384
- csr?: boolean;
385
- trailingSlash?: TrailingSlash;
386
- config?: any;
387
- entries?: PrerenderEntryGenerator;
388
- };
389
-
390
- server: {
391
- load?: ServerLoad;
392
- prerender?: PrerenderOption;
393
- ssr?: boolean;
394
- csr?: boolean;
395
- trailingSlash?: TrailingSlash;
396
- actions?: Actions;
397
- config?: any;
398
- entries?: PrerenderEntryGenerator;
399
- };
400
397
 
401
398
  universal_id?: string;
402
399
  server_id?: string;
400
+
401
+ /** inlined styles. */
402
+ inline_styles?(): MaybePromise<Record<string, string>>;
403
+ /** Svelte component */
404
+ component?: SSRComponentLoader;
405
+ /** +page.js or +layout.js */
406
+ universal?: UniversalNode;
407
+ /** +page.server.js, +layout.server.js, or +server.js */
408
+ server?: ServerNode;
403
409
  }
404
410
 
405
411
  export type SSRNodeLoader = () => Promise<SSRNode>;
@@ -482,6 +488,10 @@ export interface SSRState {
482
488
  */
483
489
  prerender_default?: PrerenderOption;
484
490
  read?: (file: string) => Buffer;
491
+ /**
492
+ * Used to setup `__SVELTEKIT_TRACK__` which checks if a used feature is supported.
493
+ * E.g. if `read` from `$app/server` is used, it checks whether the route's config is compatible.
494
+ */
485
495
  before_handle?: (event: RequestEvent, config: any, prerender: PrerenderOption) => void;
486
496
  emulator?: Emulator;
487
497
  }
@@ -0,0 +1,95 @@
1
+ import {
2
+ validate_layout_exports,
3
+ validate_layout_server_exports,
4
+ validate_page_exports,
5
+ validate_page_server_exports
6
+ } from './exports.js';
7
+
8
+ export class PageNodes {
9
+ data;
10
+
11
+ /**
12
+ * @param {Array<import('types').SSRNode | undefined>} nodes
13
+ */
14
+ constructor(nodes) {
15
+ this.data = nodes;
16
+ }
17
+
18
+ layouts() {
19
+ return this.data.slice(0, -1);
20
+ }
21
+
22
+ page() {
23
+ return this.data.at(-1);
24
+ }
25
+
26
+ validate() {
27
+ for (const layout of this.layouts()) {
28
+ if (layout) {
29
+ validate_layout_server_exports(layout.server, /** @type {string} */ (layout.server_id));
30
+ validate_layout_exports(layout.universal, /** @type {string} */ (layout.universal_id));
31
+ }
32
+ }
33
+
34
+ const page = this.page();
35
+ if (page) {
36
+ validate_page_server_exports(page.server, /** @type {string} */ (page.server_id));
37
+ validate_page_exports(page.universal, /** @type {string} */ (page.universal_id));
38
+ }
39
+ }
40
+
41
+ /**
42
+ * @template {'prerender' | 'ssr' | 'csr' | 'trailingSlash' | 'entries'} Option
43
+ * @template {(import('types').UniversalNode | import('types').ServerNode)[Option]} Value
44
+ * @param {Option} option
45
+ * @returns {Value | undefined}
46
+ */
47
+ #get_option(option) {
48
+ return this.data.reduce((value, node) => {
49
+ return /** @type {Value} TypeScript's too dumb to understand this */ (
50
+ node?.universal?.[option] ?? node?.server?.[option] ?? value
51
+ );
52
+ }, /** @type {Value | undefined} */ (undefined));
53
+ }
54
+
55
+ csr() {
56
+ return this.#get_option('csr') ?? true;
57
+ }
58
+
59
+ ssr() {
60
+ return this.#get_option('ssr') ?? true;
61
+ }
62
+
63
+ prerender() {
64
+ return this.#get_option('prerender') ?? false;
65
+ }
66
+
67
+ trailing_slash() {
68
+ return this.#get_option('trailingSlash') ?? 'never';
69
+ }
70
+
71
+ get_config() {
72
+ /** @type {any} */
73
+ let current = {};
74
+
75
+ for (const node of this.data) {
76
+ if (!node?.universal?.config && !node?.server?.config) continue;
77
+
78
+ current = {
79
+ ...current,
80
+ ...node?.universal?.config,
81
+ ...node?.server?.config
82
+ };
83
+ }
84
+
85
+ // TODO 3.0 always return `current`? then we can get rid of `?? {}` in other places
86
+ return Object.keys(current).length ? current : undefined;
87
+ }
88
+
89
+ should_prerender_data() {
90
+ return this.data.some(
91
+ // prerender in case of trailingSlash because the client retrieves that value from the server
92
+ (node) => node?.server?.load || node?.server?.trailingSlash !== undefined
93
+ );
94
+ }
95
+ }
package/src/version.js CHANGED
@@ -1,4 +1,4 @@
1
1
  // generated during release, do not modify
2
2
 
3
3
  /** @type {string} */
4
- export const VERSION = '2.18.0';
4
+ export const VERSION = '2.19.0';
package/types/index.d.ts CHANGED
@@ -796,7 +796,7 @@ declare module '@sveltejs/kit' {
796
796
  * The [`reroute`](https://svelte.dev/docs/kit/hooks#Universal-hooks-reroute) hook allows you to modify the URL before it is used to determine which route to render.
797
797
  * @since 2.3.0
798
798
  */
799
- export type Reroute = (event: { url: URL }) => MaybePromise<void | string>;
799
+ export type Reroute = (event: { url: URL; fetch: typeof fetch }) => MaybePromise<void | string>;
800
800
 
801
801
  /**
802
802
  * The [`transport`](https://svelte.dev/docs/kit/hooks#Universal-hooks-transport) hook allows you to transport custom types across the server/client boundary.
@@ -1842,8 +1842,28 @@ declare module '@sveltejs/kit' {
1842
1842
 
1843
1843
  type SSRComponentLoader = () => Promise<SSRComponent>;
1844
1844
 
1845
+ interface UniversalNode {
1846
+ load?: Load;
1847
+ prerender?: PrerenderOption;
1848
+ ssr?: boolean;
1849
+ csr?: boolean;
1850
+ trailingSlash?: TrailingSlash;
1851
+ config?: any;
1852
+ entries?: PrerenderEntryGenerator;
1853
+ }
1854
+
1855
+ interface ServerNode {
1856
+ load?: ServerLoad;
1857
+ prerender?: PrerenderOption;
1858
+ ssr?: boolean;
1859
+ csr?: boolean;
1860
+ trailingSlash?: TrailingSlash;
1861
+ actions?: Actions;
1862
+ config?: any;
1863
+ entries?: PrerenderEntryGenerator;
1864
+ }
1865
+
1845
1866
  interface SSRNode {
1846
- component: SSRComponentLoader;
1847
1867
  /** index into the `nodes` array in the generated `client/app.js`. */
1848
1868
  index: number;
1849
1869
  /** external JS files that are loaded on the client. `imports[0]` is the entry point (e.g. `client/nodes/0.js`) */
@@ -1852,32 +1872,18 @@ declare module '@sveltejs/kit' {
1852
1872
  stylesheets: string[];
1853
1873
  /** external font files that are loaded on the client */
1854
1874
  fonts: string[];
1855
- /** inlined styles. */
1856
- inline_styles?(): MaybePromise<Record<string, string>>;
1857
-
1858
- universal: {
1859
- load?: Load;
1860
- prerender?: PrerenderOption;
1861
- ssr?: boolean;
1862
- csr?: boolean;
1863
- trailingSlash?: TrailingSlash;
1864
- config?: any;
1865
- entries?: PrerenderEntryGenerator;
1866
- };
1867
-
1868
- server: {
1869
- load?: ServerLoad;
1870
- prerender?: PrerenderOption;
1871
- ssr?: boolean;
1872
- csr?: boolean;
1873
- trailingSlash?: TrailingSlash;
1874
- actions?: Actions;
1875
- config?: any;
1876
- entries?: PrerenderEntryGenerator;
1877
- };
1878
1875
 
1879
1876
  universal_id?: string;
1880
1877
  server_id?: string;
1878
+
1879
+ /** inlined styles. */
1880
+ inline_styles?(): MaybePromise<Record<string, string>>;
1881
+ /** Svelte component */
1882
+ component?: SSRComponentLoader;
1883
+ /** +page.js or +layout.js */
1884
+ universal?: UniversalNode;
1885
+ /** +page.server.js, +layout.server.js, or +server.js */
1886
+ server?: ServerNode;
1881
1887
  }
1882
1888
 
1883
1889
  type SSRNodeLoader = () => Promise<SSRNode>;
@@ -2016,7 +2022,8 @@ declare module '@sveltejs/kit' {
2016
2022
  * console.log(url.pathname); // /blog/post
2017
2023
  * console.log(denormalize('/blog/post/a')); // /blog/post/a/__data.json
2018
2024
  * ```
2019
- * */
2025
+ * @since 2.18.0
2026
+ */
2020
2027
  export function normalizeUrl(url: URL | string): {
2021
2028
  url: URL;
2022
2029
  wasNormalized: boolean;
@@ -73,6 +73,8 @@
73
73
  "RouteData",
74
74
  "SSRComponent",
75
75
  "SSRComponentLoader",
76
+ "UniversalNode",
77
+ "ServerNode",
76
78
  "SSRNode",
77
79
  "SSRNodeLoader",
78
80
  "PageNodeIndexes",
@@ -161,6 +163,6 @@
161
163
  null,
162
164
  null
163
165
  ],
164
- "mappings": "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",
166
+ "mappings": "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",
165
167
  "ignoreList": []
166
168
  }
@@ -1,11 +0,0 @@
1
- /**
2
- * @param {import('types').PageNodeIndexes} page
3
- * @param {import('@sveltejs/kit').SSRManifest} manifest
4
- */
5
- export function load_page_nodes(page, manifest) {
6
- return Promise.all([
7
- // we use == here rather than === because [undefined] serializes as "[null]"
8
- ...page.layouts.map((n) => (n == undefined ? n : manifest._.nodes[n]())),
9
- manifest._.nodes[page.leaf]()
10
- ]);
11
- }
@@ -1,16 +0,0 @@
1
- /**
2
- * @template {'prerender' | 'ssr' | 'csr' | 'trailingSlash' | 'entries'} Option
3
- * @template {(import('types').SSRNode['universal'] | import('types').SSRNode['server'])[Option]} Value
4
- *
5
- * @param {Array<import('types').SSRNode | undefined>} nodes
6
- * @param {Option} option
7
- *
8
- * @returns {Value | undefined}
9
- */
10
- export function get_option(nodes, option) {
11
- return nodes.reduce((value, node) => {
12
- return /** @type {Value} TypeScript's too dumb to understand this */ (
13
- node?.universal?.[option] ?? node?.server?.[option] ?? value
14
- );
15
- }, /** @type {Value | undefined} */ (undefined));
16
- }
@@ -1,21 +0,0 @@
1
- /**
2
- * Do a shallow merge (first level) of the config object
3
- * @param {Array<import('types').SSRNode | undefined>} nodes
4
- */
5
- export function get_page_config(nodes) {
6
- /** @type {any} */
7
- let current = {};
8
-
9
- for (const node of nodes) {
10
- if (!node?.universal?.config && !node?.server?.config) continue;
11
-
12
- current = {
13
- ...current,
14
- ...node?.universal?.config,
15
- ...node?.server?.config
16
- };
17
- }
18
-
19
- // TODO 3.0 always return `current`? then we can get rid of `?? {}` in other places
20
- return Object.keys(current).length ? current : undefined;
21
- }