@sveltejs/kit 1.0.0-next.373 → 1.0.0-next.376

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.
@@ -17,10 +17,14 @@ function coalesce_to_error(err) {
17
17
  }
18
18
 
19
19
  /**
20
- * @param {import('types').LoadOutput} loaded
20
+ * @param {import('types').LoadOutput | void} loaded
21
21
  * @returns {import('types').NormalizedLoadOutput}
22
22
  */
23
23
  function normalize(loaded) {
24
+ if (!loaded) {
25
+ return {};
26
+ }
27
+
24
28
  // TODO remove for 1.0
25
29
  // @ts-expect-error
26
30
  if (loaded.fallthrough) {
@@ -40,7 +44,10 @@ function normalize(loaded) {
40
44
  const status = loaded.status;
41
45
 
42
46
  if (!loaded.error && has_error_status) {
43
- return { status: status || 500, error: new Error() };
47
+ return {
48
+ status: status || 500,
49
+ error: new Error(`${status}`)
50
+ };
44
51
  }
45
52
 
46
53
  const error = typeof loaded.error === 'string' ? new Error(loaded.error) : loaded.error;
@@ -1030,24 +1037,17 @@ function create_client({ target, session, base, trailing_slash }) {
1030
1037
  });
1031
1038
  }
1032
1039
 
1033
- let loaded;
1034
-
1035
1040
  if (import.meta.env.DEV) {
1036
1041
  try {
1037
1042
  lock_fetch();
1038
- loaded = await module.load.call(null, load_input);
1043
+ node.loaded = normalize(await module.load.call(null, load_input));
1039
1044
  } finally {
1040
1045
  unlock_fetch();
1041
1046
  }
1042
1047
  } else {
1043
- loaded = await module.load.call(null, load_input);
1044
- }
1045
-
1046
- if (!loaded) {
1047
- throw new Error('load function must return a value');
1048
+ node.loaded = normalize(await module.load.call(null, load_input));
1048
1049
  }
1049
1050
 
1050
- node.loaded = normalize(loaded);
1051
1051
  if (node.loaded.stuff) node.stuff = node.loaded.stuff;
1052
1052
  if (node.loaded.dependencies) {
1053
1053
  node.loaded.dependencies.forEach(add_dependency);
@@ -1088,7 +1088,7 @@ function create_client({ target, session, base, trailing_slash }) {
1088
1088
  let stuff = root_stuff;
1089
1089
  let stuff_changed = false;
1090
1090
 
1091
- /** @type {number | undefined} */
1091
+ /** @type {number} */
1092
1092
  let status = 200;
1093
1093
 
1094
1094
  /** @type {Error | null} */
@@ -1174,7 +1174,7 @@ function create_client({ target, session, base, trailing_slash }) {
1174
1174
 
1175
1175
  if (node.loaded) {
1176
1176
  if (node.loaded.error) {
1177
- status = node.loaded.status;
1177
+ status = node.loaded.status ?? 500;
1178
1178
  error = node.loaded.error;
1179
1179
  }
1180
1180
 
@@ -1703,7 +1703,7 @@ function create_client({ target, session, base, trailing_slash }) {
1703
1703
  if (node.loaded.error) {
1704
1704
  if (error) throw node.loaded.error;
1705
1705
  error_args = {
1706
- status: node.loaded.status,
1706
+ status: node.loaded.status ?? 500,
1707
1707
  error: node.loaded.error,
1708
1708
  url,
1709
1709
  routeId
@@ -192,6 +192,11 @@ function clone_error(error, get_stack) {
192
192
  return object;
193
193
  }
194
194
 
195
+ /** @type {import('types').SSRErrorPage} */
196
+ const GENERIC_ERROR = {
197
+ id: '__error'
198
+ };
199
+
195
200
  /** @param {string} body */
196
201
  function error(body) {
197
202
  return new Response(body, {
@@ -1369,6 +1374,14 @@ async function render_response({
1369
1374
  }
1370
1375
 
1371
1376
  if (resolve_opts.ssr) {
1377
+ const leaf = /** @type {import('./types.js').Loaded} */ (branch.at(-1));
1378
+
1379
+ if (leaf.loaded.status) {
1380
+ // explicit status returned from `load` or a page endpoint trumps
1381
+ // initial status
1382
+ status = leaf.loaded.status;
1383
+ }
1384
+
1372
1385
  for (const { node, props, loaded, fetched, uses_credentials } of branch) {
1373
1386
  if (node.imports) {
1374
1387
  node.imports.forEach((url) => modulepreloads.add(url));
@@ -2096,10 +2109,14 @@ var parseString_1 = setCookie.exports.parseString = parseString;
2096
2109
  var splitCookiesString_1 = setCookie.exports.splitCookiesString = splitCookiesString;
2097
2110
 
2098
2111
  /**
2099
- * @param {import('types').LoadOutput} loaded
2112
+ * @param {import('types').LoadOutput | void} loaded
2100
2113
  * @returns {import('types').NormalizedLoadOutput}
2101
2114
  */
2102
2115
  function normalize(loaded) {
2116
+ if (!loaded) {
2117
+ return {};
2118
+ }
2119
+
2103
2120
  // TODO remove for 1.0
2104
2121
  // @ts-expect-error
2105
2122
  if (loaded.fallthrough) {
@@ -2119,7 +2136,10 @@ function normalize(loaded) {
2119
2136
  const status = loaded.status;
2120
2137
 
2121
2138
  if (!loaded.error && has_error_status) {
2122
- return { status: status || 500, error: new Error() };
2139
+ return {
2140
+ status: status || 500,
2141
+ error: new Error(`${status}`)
2142
+ };
2123
2143
  }
2124
2144
 
2125
2145
  const error = typeof loaded.error === 'string' ? new Error(loaded.error) : loaded.error;
@@ -2205,7 +2225,7 @@ function path_matches(path, constraint) {
2205
2225
  * event: import('types').RequestEvent;
2206
2226
  * options: import('types').SSROptions;
2207
2227
  * state: import('types').SSRState;
2208
- * route: import('types').SSRPage | null;
2228
+ * route: import('types').SSRPage | import('types').SSRErrorPage;
2209
2229
  * node: import('types').SSRNode;
2210
2230
  * $session: any;
2211
2231
  * stuff: Record<string, any>;
@@ -2241,7 +2261,7 @@ async function load_node({
2241
2261
  /** @type {import('set-cookie-parser').Cookie[]} */
2242
2262
  const new_cookies = [];
2243
2263
 
2244
- /** @type {import('types').LoadOutput} */
2264
+ /** @type {import('types').NormalizedLoadOutput} */
2245
2265
  let loaded;
2246
2266
 
2247
2267
  const should_prerender = node.module.prerender ?? options.prerender.default;
@@ -2264,12 +2284,10 @@ async function load_node({
2264
2284
 
2265
2285
  if (shadow.error) {
2266
2286
  loaded = {
2267
- status: shadow.status,
2268
2287
  error: shadow.error
2269
2288
  };
2270
2289
  } else if (shadow.redirect) {
2271
2290
  loaded = {
2272
- status: shadow.status,
2273
2291
  redirect: shadow.redirect
2274
2292
  };
2275
2293
  } else if (module.load) {
@@ -2537,7 +2555,7 @@ async function load_node({
2537
2555
  return proxy;
2538
2556
  },
2539
2557
  stuff: { ...stuff },
2540
- status: is_error ? status ?? null : null,
2558
+ status: (is_error ? status : shadow.status) ?? null,
2541
2559
  error: is_error ? error ?? null : null
2542
2560
  };
2543
2561
 
@@ -2550,12 +2568,7 @@ async function load_node({
2550
2568
  });
2551
2569
  }
2552
2570
 
2553
- loaded = await module.load.call(null, load_input);
2554
-
2555
- if (!loaded) {
2556
- // TODO do we still want to enforce this now that there's no fallthrough?
2557
- throw new Error(`load function must return a value${options.dev ? ` (${node.file})` : ''}`);
2558
- }
2571
+ loaded = normalize(await module.load.call(null, load_input));
2559
2572
  } else if (shadow.body) {
2560
2573
  loaded = {
2561
2574
  props: shadow.body
@@ -2564,6 +2577,8 @@ async function load_node({
2564
2577
  loaded = {};
2565
2578
  }
2566
2579
 
2580
+ loaded.status = loaded.status ?? shadow.status;
2581
+
2567
2582
  // generate __data.json files when prerendering
2568
2583
  if (shadow.body && state.prerendering) {
2569
2584
  const pathname = `${event.url.pathname.replace(/\/$/, '')}/__data.json`;
@@ -2579,7 +2594,7 @@ async function load_node({
2579
2594
  return {
2580
2595
  node,
2581
2596
  props: shadow.body,
2582
- loaded: normalize(loaded),
2597
+ loaded,
2583
2598
  stuff: loaded.stuff || stuff,
2584
2599
  fetched,
2585
2600
  set_cookie_headers: new_cookies.map((new_cookie) => {
@@ -2622,7 +2637,7 @@ async function load_shadow_data(route, event, options, prerender) {
2622
2637
 
2623
2638
  /** @type {import('types').ShadowData} */
2624
2639
  const data = {
2625
- status: 200,
2640
+ status: undefined,
2626
2641
  cookies: [],
2627
2642
  body: {}
2628
2643
  };
@@ -2662,13 +2677,13 @@ async function load_shadow_data(route, event, options, prerender) {
2662
2677
  if (get) {
2663
2678
  const { status, headers, body } = validate_shadow_output(await get(event));
2664
2679
  add_cookies(/** @type {string[]} */ (data.cookies), headers);
2665
- data.status = status;
2666
2680
 
2667
2681
  if (body instanceof Error) {
2668
2682
  if (status < 400) {
2669
2683
  data.status = 500;
2670
2684
  data.error = new Error('A non-error status code was returned with an error body');
2671
2685
  } else {
2686
+ data.status = status;
2672
2687
  data.error = body;
2673
2688
  }
2674
2689
 
@@ -2676,11 +2691,13 @@ async function load_shadow_data(route, event, options, prerender) {
2676
2691
  }
2677
2692
 
2678
2693
  if (status >= 400) {
2694
+ data.status = status;
2679
2695
  data.error = new Error('Failed to load data');
2680
2696
  return data;
2681
2697
  }
2682
2698
 
2683
2699
  if (status >= 300) {
2700
+ data.status = status;
2684
2701
  data.redirect = /** @type {string} */ (
2685
2702
  headers instanceof Headers ? headers.get('location') : headers.location
2686
2703
  );
@@ -2790,7 +2807,7 @@ async function respond_with_error({
2790
2807
  event,
2791
2808
  options,
2792
2809
  state,
2793
- route: null,
2810
+ route: GENERIC_ERROR,
2794
2811
  node: default_layout,
2795
2812
  $session,
2796
2813
  stuff: {},
@@ -2799,12 +2816,16 @@ async function respond_with_error({
2799
2816
  })
2800
2817
  );
2801
2818
 
2819
+ if (layout_loaded.loaded.error) {
2820
+ throw layout_loaded.loaded.error;
2821
+ }
2822
+
2802
2823
  const error_loaded = /** @type {Loaded} */ (
2803
2824
  await load_node({
2804
2825
  event,
2805
2826
  options,
2806
2827
  state,
2807
- route: null,
2828
+ route: GENERIC_ERROR,
2808
2829
  node: default_error,
2809
2830
  $session,
2810
2831
  stuff: layout_loaded ? layout_loaded.stuff : {},
@@ -2969,7 +2990,8 @@ async function respond$1(opts) {
2969
2990
  }
2970
2991
 
2971
2992
  if (loaded.loaded.error) {
2972
- ({ status, error } = loaded.loaded);
2993
+ error = loaded.loaded.error;
2994
+ status = loaded.loaded.status ?? 500;
2973
2995
  }
2974
2996
  } catch (err) {
2975
2997
  const e = coalesce_to_error(err);
@@ -3448,6 +3470,12 @@ async function respond(request, options, state) {
3448
3470
  }
3449
3471
  }
3450
3472
 
3473
+ if (state.initiator === GENERIC_ERROR) {
3474
+ return new Response('Internal Server Error', {
3475
+ status: 500
3476
+ });
3477
+ }
3478
+
3451
3479
  // if this request came direct from the user, rather than
3452
3480
  // via a `fetch` in a `load`, render a 404 page
3453
3481
  if (!state.initiator) {
@@ -3502,6 +3530,7 @@ async function respond(request, options, state) {
3502
3530
  });
3503
3531
  }
3504
3532
 
3533
+ // TODO is this necessary? should we just return a plain 500 at this point?
3505
3534
  try {
3506
3535
  const $session = await options.hooks.getSession(event);
3507
3536
  return await respond_with_error({
package/dist/cli.js CHANGED
@@ -18,7 +18,7 @@ function handle_error(e) {
18
18
  process.exit(1);
19
19
  }
20
20
 
21
- const prog = sade('svelte-kit').version('1.0.0-next.373');
21
+ const prog = sade('svelte-kit').version('1.0.0-next.376');
22
22
 
23
23
  prog
24
24
  .command('package')
package/dist/vite.js CHANGED
@@ -2874,6 +2874,8 @@ function kit() {
2874
2874
  */
2875
2875
  let paths;
2876
2876
 
2877
+ let completed_build = false;
2878
+
2877
2879
  function vite_client_config() {
2878
2880
  /** @type {Record<string, string>} */
2879
2881
  const input = {
@@ -3012,6 +3014,9 @@ function kit() {
3012
3014
  * Clears the output directories.
3013
3015
  */
3014
3016
  buildStart() {
3017
+ // Reset for new build. Goes here because `build --watch` calls buildStart but not config
3018
+ completed_build = false;
3019
+
3015
3020
  if (is_build) {
3016
3021
  rimraf(paths.build_dir);
3017
3022
  mkdirp(paths.build_dir);
@@ -3110,15 +3115,20 @@ function kit() {
3110
3115
  console.log(
3111
3116
  `\nRun ${$.bold().cyan('npm run preview')} to preview your production build locally.`
3112
3117
  );
3118
+
3119
+ completed_build = true;
3113
3120
  },
3114
3121
 
3115
3122
  /**
3116
3123
  * Runs the adapter.
3117
3124
  */
3118
3125
  async closeBundle() {
3119
- if (!is_build) {
3120
- return; // vite calls closeBundle when dev-server restarts, ignore that
3126
+ if (!completed_build) {
3127
+ // vite calls closeBundle when dev-server restarts, ignore that,
3128
+ // and only adapt when build successfully completes.
3129
+ return;
3121
3130
  }
3131
+
3122
3132
  if (svelte_config.kit.adapter) {
3123
3133
  const { adapt } = await import('./chunks/index2.js');
3124
3134
  await adapt(svelte_config, build_data, prerendered, { log });
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@sveltejs/kit",
3
- "version": "1.0.0-next.373",
3
+ "version": "1.0.0-next.376",
4
4
  "repository": {
5
5
  "type": "git",
6
6
  "url": "https://github.com/sveltejs/kit",
@@ -80,7 +80,7 @@ declare module '$app/env' {
80
80
  export const dev: boolean;
81
81
 
82
82
  /**
83
- * The Vite.js mode the app is running in. Configure in `config.kit.vite.mode`.
83
+ * The Vite.js mode the app is running in. Configure in [`vite.config.js`](https://vitejs.dev/config/shared-options.html#mode).
84
84
  * Vite.js loads the dotenv file associated with the provided mode, `.env.[mode]` or `.env.[mode].local`.
85
85
  * By default, `vite dev` runs with `mode=development` and `vite build` runs with `mode=production`.
86
86
  */
package/types/index.d.ts CHANGED
@@ -151,7 +151,6 @@ export interface KitConfig {
151
151
  name?: string;
152
152
  pollInterval?: number;
153
153
  };
154
- vite?: import('vite').UserConfig | (() => MaybePromise<import('vite').UserConfig>);
155
154
  }
156
155
 
157
156
  export interface ExternalFetch {
@@ -183,7 +182,7 @@ export interface Load<
183
182
  InputProps extends Record<string, any> = Record<string, any>,
184
183
  OutputProps extends Record<string, any> = InputProps
185
184
  > {
186
- (event: LoadEvent<Params, InputProps>): MaybePromise<LoadOutput<OutputProps>>;
185
+ (event: LoadEvent<Params, InputProps>): MaybePromise<LoadOutput<OutputProps> | void>;
187
186
  }
188
187
 
189
188
  export interface LoadEvent<
@@ -113,7 +113,7 @@ export interface MethodOverride {
113
113
  }
114
114
 
115
115
  export type NormalizedLoadOutput = {
116
- status: number;
116
+ status?: number;
117
117
  error?: Error;
118
118
  redirect?: string;
119
119
  props?: Record<string, any> | Promise<Record<string, any>>;
@@ -153,12 +153,9 @@ export interface PrerenderOptions {
153
153
 
154
154
  export type RecursiveRequired<T> = {
155
155
  // Recursive implementation of TypeScript's Required utility type.
156
- // Will recursively continue until it reaches primitive or union
157
- // with a Function in it, except those commented below
156
+ // Will recursively continue until it reaches a primitive or Function
158
157
  [K in keyof T]-?: Extract<T[K], Function> extends never // If it does not have a Function type
159
158
  ? RecursiveRequired<T[K]> // recursively continue through.
160
- : K extends 'vite' // If it reaches the 'vite' key
161
- ? Extract<T[K], Function> // only take the Function type.
162
159
  : T[K]; // Use the exact type for everything else
163
160
  };
164
161
 
@@ -293,6 +290,10 @@ export interface SSRPage {
293
290
  b: Array<number | undefined>;
294
291
  }
295
292
 
293
+ export interface SSRErrorPage {
294
+ id: '__error';
295
+ }
296
+
296
297
  export interface SSRPagePart {
297
298
  id: string;
298
299
  load: SSRComponentLoader;
@@ -303,7 +304,7 @@ export type SSRRoute = SSREndpoint | SSRPage;
303
304
  export interface SSRState {
304
305
  fallback?: string;
305
306
  getClientAddress: () => string;
306
- initiator?: SSRPage | null;
307
+ initiator?: SSRPage | SSRErrorPage;
307
308
  platform?: any;
308
309
  prerendering?: PrerenderOptions;
309
310
  }