@sveltejs/kit 1.0.0-next.374 → 1.0.0-next.377

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.
@@ -44,7 +44,10 @@ function normalize(loaded) {
44
44
  const status = loaded.status;
45
45
 
46
46
  if (!loaded.error && has_error_status) {
47
- return { status: status || 500, error: new Error() };
47
+ return {
48
+ status: status || 500,
49
+ error: new Error(`${status}`)
50
+ };
48
51
  }
49
52
 
50
53
  const error = typeof loaded.error === 'string' ? new Error(loaded.error) : loaded.error;
@@ -145,12 +145,6 @@ function is_pojo(body) {
145
145
  return true;
146
146
  }
147
147
 
148
- /** @param {import('types').RequestEvent} event */
149
- function normalize_request_method(event) {
150
- const method = event.request.method.toLowerCase();
151
- return method === 'delete' ? 'del' : method; // 'delete' is a reserved word
152
- }
153
-
154
148
  /**
155
149
  * Serialize an error into a JSON string, by copying its `name`, `message`
156
150
  * and (in dev) `stack`, plus any custom properties, plus recursively
@@ -192,6 +186,24 @@ function clone_error(error, get_stack) {
192
186
  return object;
193
187
  }
194
188
 
189
+ // TODO: Remove for 1.0
190
+ /** @param {Record<string, any>} mod */
191
+ function check_method_names(mod) {
192
+ ['get', 'post', 'put', 'patch', 'del'].forEach((m) => {
193
+ if (m in mod) {
194
+ const replacement = m === 'del' ? 'DELETE' : m.toUpperCase();
195
+ throw Error(
196
+ `Endpoint method "${m}" has changed to "${replacement}". See https://github.com/sveltejs/kit/discussions/5359 for more information.`
197
+ );
198
+ }
199
+ });
200
+ }
201
+
202
+ /** @type {import('types').SSRErrorPage} */
203
+ const GENERIC_ERROR = {
204
+ id: '__error'
205
+ };
206
+
195
207
  /** @param {string} body */
196
208
  function error(body) {
197
209
  return new Response(body, {
@@ -233,24 +245,25 @@ function is_text(content_type) {
233
245
  * @returns {Promise<Response>}
234
246
  */
235
247
  async function render_endpoint(event, mod, options) {
236
- const method = normalize_request_method(event);
248
+ const { method } = event.request;
249
+
250
+ check_method_names(mod);
237
251
 
238
252
  /** @type {import('types').RequestHandler} */
239
253
  let handler = mod[method];
240
254
 
241
- if (!handler && method === 'head') {
242
- handler = mod.get;
255
+ if (!handler && method === 'HEAD') {
256
+ handler = mod.GET;
243
257
  }
244
258
 
245
259
  if (!handler) {
246
260
  const allowed = [];
247
261
 
248
- for (const method in ['get', 'post', 'put', 'patch']) {
249
- if (mod[method]) allowed.push(method.toUpperCase());
262
+ for (const method in ['GET', 'POST', 'PUT', 'PATCH', 'DELETE']) {
263
+ if (mod[method]) allowed.push(method);
250
264
  }
251
265
 
252
- if (mod.del) allowed.push('DELETE');
253
- if (mod.get || mod.head) allowed.push('HEAD');
266
+ if (mod.GET || mod.HEAD) allowed.push('HEAD');
254
267
 
255
268
  return event.request.headers.get('x-sveltekit-load')
256
269
  ? // TODO would be nice to avoid these requests altogether,
@@ -258,7 +271,7 @@ async function render_endpoint(event, mod, options) {
258
271
  new Response(undefined, {
259
272
  status: 204
260
273
  })
261
- : new Response(`${event.request.method} method not allowed`, {
274
+ : new Response(`${method} method not allowed`, {
262
275
  status: 405,
263
276
  headers: {
264
277
  // https://developer.mozilla.org/en-US/docs/Web/HTTP/Status/405
@@ -322,7 +335,7 @@ async function render_endpoint(event, mod, options) {
322
335
  }
323
336
 
324
337
  return new Response(
325
- method !== 'head' && !bodyless_status_codes.has(status) ? normalized_body : undefined,
338
+ method !== 'HEAD' && !bodyless_status_codes.has(status) ? normalized_body : undefined,
326
339
  {
327
340
  status,
328
341
  headers
@@ -2131,7 +2144,10 @@ function normalize(loaded) {
2131
2144
  const status = loaded.status;
2132
2145
 
2133
2146
  if (!loaded.error && has_error_status) {
2134
- return { status: status || 500, error: new Error() };
2147
+ return {
2148
+ status: status || 500,
2149
+ error: new Error(`${status}`)
2150
+ };
2135
2151
  }
2136
2152
 
2137
2153
  const error = typeof loaded.error === 'string' ? new Error(loaded.error) : loaded.error;
@@ -2217,7 +2233,7 @@ function path_matches(path, constraint) {
2217
2233
  * event: import('types').RequestEvent;
2218
2234
  * options: import('types').SSROptions;
2219
2235
  * state: import('types').SSRState;
2220
- * route: import('types').SSRPage | null;
2236
+ * route: import('types').SSRPage | import('types').SSRErrorPage;
2221
2237
  * node: import('types').SSRNode;
2222
2238
  * $session: any;
2223
2239
  * stuff: Record<string, any>;
@@ -2612,13 +2628,15 @@ async function load_shadow_data(route, event, options, prerender) {
2612
2628
  try {
2613
2629
  const mod = await route.shadow();
2614
2630
 
2615
- if (prerender && (mod.post || mod.put || mod.del || mod.patch)) {
2631
+ check_method_names(mod);
2632
+
2633
+ if (prerender && (mod.POST || mod.PUT || mod.DELETE || mod.PATCH)) {
2616
2634
  throw new Error('Cannot prerender pages that have endpoints with mutative methods');
2617
2635
  }
2618
2636
 
2619
- const method = normalize_request_method(event);
2620
- const is_get = method === 'head' || method === 'get';
2621
- const handler = method === 'head' ? mod.head || mod.get : mod[method];
2637
+ const { method } = event.request;
2638
+ const is_get = method === 'HEAD' || method === 'GET';
2639
+ const handler = method === 'HEAD' ? mod.HEAD || mod.GET : mod[method];
2622
2640
 
2623
2641
  if (!handler && !is_get) {
2624
2642
  return {
@@ -2665,7 +2683,7 @@ async function load_shadow_data(route, event, options, prerender) {
2665
2683
  data.body = body;
2666
2684
  }
2667
2685
 
2668
- const get = (method === 'head' && mod.head) || mod.get;
2686
+ const get = (method === 'HEAD' && mod.HEAD) || mod.GET;
2669
2687
  if (get) {
2670
2688
  const { status, headers, body } = validate_shadow_output(await get(event));
2671
2689
  add_cookies(/** @type {string[]} */ (data.cookies), headers);
@@ -2799,7 +2817,7 @@ async function respond_with_error({
2799
2817
  event,
2800
2818
  options,
2801
2819
  state,
2802
- route: null,
2820
+ route: GENERIC_ERROR,
2803
2821
  node: default_layout,
2804
2822
  $session,
2805
2823
  stuff: {},
@@ -2808,12 +2826,16 @@ async function respond_with_error({
2808
2826
  })
2809
2827
  );
2810
2828
 
2829
+ if (layout_loaded.loaded.error) {
2830
+ throw layout_loaded.loaded.error;
2831
+ }
2832
+
2811
2833
  const error_loaded = /** @type {Loaded} */ (
2812
2834
  await load_node({
2813
2835
  event,
2814
2836
  options,
2815
2837
  state,
2816
- route: null,
2838
+ route: GENERIC_ERROR,
2817
2839
  node: default_error,
2818
2840
  $session,
2819
2841
  stuff: layout_loaded ? layout_loaded.stuff : {},
@@ -3458,6 +3480,12 @@ async function respond(request, options, state) {
3458
3480
  }
3459
3481
  }
3460
3482
 
3483
+ if (state.initiator === GENERIC_ERROR) {
3484
+ return new Response('Internal Server Error', {
3485
+ status: 500
3486
+ });
3487
+ }
3488
+
3461
3489
  // if this request came direct from the user, rather than
3462
3490
  // via a `fetch` in a `load`, render a 404 page
3463
3491
  if (!state.initiator) {
@@ -3512,6 +3540,7 @@ async function respond(request, options, state) {
3512
3540
  });
3513
3541
  }
3514
3542
 
3543
+ // TODO is this necessary? should we just return a plain 500 at this point?
3515
3544
  try {
3516
3545
  const $session = await options.hooks.getSession(event);
3517
3546
  return await respond_with_error({
@@ -83,7 +83,7 @@ function create_builder({ config, build_data, prerendered, log }) {
83
83
  content: segment
84
84
  })),
85
85
  pattern: route.pattern,
86
- methods: route.type === 'page' ? ['get'] : build_data.server.methods[route.file]
86
+ methods: route.type === 'page' ? ['GET'] : build_data.server.methods[route.file]
87
87
  }));
88
88
 
89
89
  const seen = new Set();
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.374');
21
+ const prog = sade('svelte-kit').version('1.0.0-next.377');
22
22
 
23
23
  prog
24
24
  .command('package')
package/dist/vite.js CHANGED
@@ -315,6 +315,17 @@ function remove_svelte_kit(config) {
315
315
  .filter((plugin) => plugin.name !== 'vite-plugin-svelte-kit');
316
316
  }
317
317
 
318
+ const method_names = new Set(['GET', 'HEAD', 'PUT', 'POST', 'DELETE', 'PATCH']);
319
+
320
+ // If we'd written this in TypeScript, it could be easy...
321
+ /**
322
+ * @param {string} str
323
+ * @returns {str is import('types').HttpMethod}
324
+ */
325
+ function is_http_method(str) {
326
+ return method_names.has(str);
327
+ }
328
+
318
329
  /**
319
330
  * @param {{
320
331
  * hooks: string;
@@ -563,16 +574,6 @@ async function build_server(options, client) {
563
574
  };
564
575
  }
565
576
 
566
- /** @type {Record<string, string>} */
567
- const method_names = {
568
- get: 'get',
569
- head: 'head',
570
- post: 'post',
571
- put: 'put',
572
- del: 'delete',
573
- patch: 'patch'
574
- };
575
-
576
577
  /**
577
578
  * @param {string} cwd
578
579
  * @param {import('rollup').OutputChunk[]} output
@@ -593,9 +594,7 @@ function get_methods(cwd, output, manifest_data) {
593
594
  const file = route.type === 'endpoint' ? route.file : route.shadow;
594
595
 
595
596
  if (file && lookup[file]) {
596
- methods[file] = lookup[file]
597
- .map((x) => /** @type {import('types').HttpMethod} */ (method_names[x]))
598
- .filter(Boolean);
597
+ methods[file] = lookup[file].filter(is_http_method);
599
598
  }
600
599
  });
601
600
 
@@ -2874,6 +2873,8 @@ function kit() {
2874
2873
  */
2875
2874
  let paths;
2876
2875
 
2876
+ let completed_build = false;
2877
+
2877
2878
  function vite_client_config() {
2878
2879
  /** @type {Record<string, string>} */
2879
2880
  const input = {
@@ -3012,6 +3013,9 @@ function kit() {
3012
3013
  * Clears the output directories.
3013
3014
  */
3014
3015
  buildStart() {
3016
+ // Reset for new build. Goes here because `build --watch` calls buildStart but not config
3017
+ completed_build = false;
3018
+
3015
3019
  if (is_build) {
3016
3020
  rimraf(paths.build_dir);
3017
3021
  mkdirp(paths.build_dir);
@@ -3110,15 +3114,20 @@ function kit() {
3110
3114
  console.log(
3111
3115
  `\nRun ${$.bold().cyan('npm run preview')} to preview your production build locally.`
3112
3116
  );
3117
+
3118
+ completed_build = true;
3113
3119
  },
3114
3120
 
3115
3121
  /**
3116
3122
  * Runs the adapter.
3117
3123
  */
3118
3124
  async closeBundle() {
3119
- if (!is_build) {
3120
- return; // vite calls closeBundle when dev-server restarts, ignore that
3125
+ if (!completed_build) {
3126
+ // vite calls closeBundle when dev-server restarts, ignore that,
3127
+ // and only adapt when build successfully completes.
3128
+ return;
3121
3129
  }
3130
+
3122
3131
  if (svelte_config.kit.adapter) {
3123
3132
  const { adapt } = await import('./chunks/index2.js');
3124
3133
  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.374",
3
+ "version": "1.0.0-next.377",
4
4
  "repository": {
5
5
  "type": "git",
6
6
  "url": "https://github.com/sveltejs/kit",
package/types/index.d.ts CHANGED
@@ -244,7 +244,7 @@ export interface RequestEvent<Params extends Record<string, string> = Record<str
244
244
  }
245
245
 
246
246
  /**
247
- * A `(event: RequestEvent) => RequestHandlerOutput` function exported from an endpoint that corresponds to an HTTP verb (`get`, `put`, `patch`, etc) and handles requests with that method. Note that since 'delete' is a reserved word in JavaScript, delete handles are called `del` instead.
247
+ * A `(event: RequestEvent) => RequestHandlerOutput` function exported from an endpoint that corresponds to an HTTP verb (`GET`, `PUT`, `PATCH`, etc) and handles requests with that method.
248
248
  *
249
249
  * It receives `Params` as the first generic argument, which you can skip by using [generated types](/docs/types#generated-types) instead.
250
250
  *
@@ -290,6 +290,10 @@ export interface SSRPage {
290
290
  b: Array<number | undefined>;
291
291
  }
292
292
 
293
+ export interface SSRErrorPage {
294
+ id: '__error';
295
+ }
296
+
293
297
  export interface SSRPagePart {
294
298
  id: string;
295
299
  load: SSRComponentLoader;
@@ -300,7 +304,7 @@ export type SSRRoute = SSREndpoint | SSRPage;
300
304
  export interface SSRState {
301
305
  fallback?: string;
302
306
  getClientAddress: () => string;
303
- initiator?: SSRPage | null;
307
+ initiator?: SSRPage | SSRErrorPage;
304
308
  platform?: any;
305
309
  prerendering?: PrerenderOptions;
306
310
  }
@@ -142,7 +142,7 @@ export interface CspDirectives {
142
142
  >;
143
143
  }
144
144
 
145
- export type HttpMethod = 'get' | 'head' | 'post' | 'put' | 'delete' | 'patch';
145
+ export type HttpMethod = 'GET' | 'HEAD' | 'POST' | 'PUT' | 'DELETE' | 'PATCH';
146
146
 
147
147
  export interface JSONObject {
148
148
  [key: string]: JSONValue;