@sveltejs/kit 1.0.0-next.268 → 1.0.0-next.271

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.
@@ -1282,7 +1282,7 @@ class Renderer {
1282
1282
  `${url.pathname}${url.pathname.endsWith('/') ? '' : '/'}__data.json`,
1283
1283
  {
1284
1284
  headers: {
1285
- 'x-sveltekit-noredirect': 'true'
1285
+ 'x-sveltekit-load': 'true'
1286
1286
  }
1287
1287
  }
1288
1288
  );
@@ -88,6 +88,14 @@ function is_pojo(body) {
88
88
 
89
89
  return true;
90
90
  }
91
+ /**
92
+ * @param {import('types/hooks').RequestEvent} event
93
+ * @returns string
94
+ */
95
+ function normalize_request_method(event) {
96
+ const method = event.request.method.toLowerCase();
97
+ return method === 'delete' ? 'del' : method; // 'delete' is a reserved word
98
+ }
91
99
 
92
100
  /** @param {string} body */
93
101
  function error(body) {
@@ -127,9 +135,14 @@ function is_text(content_type) {
127
135
  * @returns {Promise<Response | undefined>}
128
136
  */
129
137
  async function render_endpoint(event, mod) {
138
+ const method = normalize_request_method(event);
139
+
130
140
  /** @type {import('types/endpoint').RequestHandler} */
131
- const handler = mod[event.request.method.toLowerCase().replace('delete', 'del')]; // 'delete' is a reserved word
141
+ let handler = mod[method];
132
142
 
143
+ if (!handler && method === 'head') {
144
+ handler = mod.get;
145
+ }
133
146
  if (!handler) {
134
147
  return;
135
148
  }
@@ -179,7 +192,7 @@ async function render_endpoint(event, mod) {
179
192
  }
180
193
  }
181
194
 
182
- return new Response(normalized_body, {
195
+ return new Response(method !== 'head' ? normalized_body : undefined, {
183
196
  status,
184
197
  headers
185
198
  });
@@ -1044,7 +1057,7 @@ const updated = {
1044
1057
  * error?: Error;
1045
1058
  * url: URL;
1046
1059
  * params: Record<string, string>;
1047
- * ssr: boolean;
1060
+ * resolve_opts: import('types/hooks').RequiredResolveOptions;
1048
1061
  * stuff: Record<string, any>;
1049
1062
  * }} opts
1050
1063
  */
@@ -1058,7 +1071,7 @@ async function render_response({
1058
1071
  error,
1059
1072
  url,
1060
1073
  params,
1061
- ssr,
1074
+ resolve_opts,
1062
1075
  stuff
1063
1076
  }) {
1064
1077
  if (state.prerender) {
@@ -1090,7 +1103,7 @@ async function render_response({
1090
1103
  error.stack = options.get_stack(error);
1091
1104
  }
1092
1105
 
1093
- if (ssr) {
1106
+ if (resolve_opts.ssr) {
1094
1107
  branch.forEach(({ node, props, loaded, fetched, uses_credentials }) => {
1095
1108
  if (node.css) node.css.forEach((url) => stylesheets.add(url));
1096
1109
  if (node.js) node.js.forEach((url) => modulepreloads.add(url));
@@ -1186,9 +1199,9 @@ async function render_response({
1186
1199
  throw new Error(`Failed to serialize session data: ${error.message}`);
1187
1200
  })},
1188
1201
  route: ${!!page_config.router},
1189
- spa: ${!ssr},
1202
+ spa: ${!resolve_opts.ssr},
1190
1203
  trailing_slash: ${s(options.trailing_slash)},
1191
- hydrate: ${ssr && page_config.hydrate ? `{
1204
+ hydrate: ${resolve_opts.ssr && page_config.hydrate ? `{
1192
1205
  status: ${status},
1193
1206
  error: ${serialize_error(error)},
1194
1207
  nodes: [
@@ -1314,7 +1327,9 @@ async function render_response({
1314
1327
  const assets =
1315
1328
  options.paths.assets || (segments.length > 0 ? segments.map(() => '..').join('/') : '.');
1316
1329
 
1317
- const html = options.template({ head, body, assets, nonce: /** @type {string} */ (csp.nonce) });
1330
+ const html = resolve_opts.transformPage({
1331
+ html: options.template({ head, body, assets, nonce: /** @type {string} */ (csp.nonce) })
1332
+ });
1318
1333
 
1319
1334
  const headers = new Headers({
1320
1335
  'content-type': 'text/html',
@@ -1550,6 +1565,7 @@ async function load_node({
1550
1565
  ? await load_shadow_data(
1551
1566
  /** @type {import('types/internal').SSRPage} */ (route),
1552
1567
  event,
1568
+ options,
1553
1569
  !!state.prerender
1554
1570
  )
1555
1571
  : {};
@@ -1854,10 +1870,11 @@ async function load_node({
1854
1870
  *
1855
1871
  * @param {import('types/internal').SSRPage} route
1856
1872
  * @param {import('types/hooks').RequestEvent} event
1873
+ * @param {import('types/internal').SSROptions} options
1857
1874
  * @param {boolean} prerender
1858
1875
  * @returns {Promise<import('types/endpoint').ShadowData>}
1859
1876
  */
1860
- async function load_shadow_data(route, event, prerender) {
1877
+ async function load_shadow_data(route, event, options, prerender) {
1861
1878
  if (!route.shadow) return {};
1862
1879
 
1863
1880
  try {
@@ -1867,10 +1884,11 @@ async function load_shadow_data(route, event, prerender) {
1867
1884
  throw new Error('Cannot prerender pages that have shadow endpoints with mutative methods');
1868
1885
  }
1869
1886
 
1870
- const method = event.request.method.toLowerCase().replace('delete', 'del');
1871
- const handler = mod[method];
1887
+ const method = normalize_request_method(event);
1888
+ const is_get = method === 'head' || method === 'get';
1889
+ const handler = method === 'head' ? mod.head || mod.get : mod[method];
1872
1890
 
1873
- if (!handler) {
1891
+ if (!handler && !is_get) {
1874
1892
  return {
1875
1893
  status: 405,
1876
1894
  error: new Error(`${method} method not allowed`)
@@ -1884,7 +1902,7 @@ async function load_shadow_data(route, event, prerender) {
1884
1902
  body: {}
1885
1903
  };
1886
1904
 
1887
- if (method !== 'get') {
1905
+ if (!is_get) {
1888
1906
  const result = await handler(event);
1889
1907
 
1890
1908
  if (result.fallthrough) return result;
@@ -1908,8 +1926,9 @@ async function load_shadow_data(route, event, prerender) {
1908
1926
  data.body = body;
1909
1927
  }
1910
1928
 
1911
- if (mod.get) {
1912
- const result = await mod.get.call(null, event);
1929
+ const get = (method === 'head' && mod.head) || mod.get;
1930
+ if (get) {
1931
+ const result = await get(event);
1913
1932
 
1914
1933
  if (result.fallthrough) return result;
1915
1934
 
@@ -1934,9 +1953,12 @@ async function load_shadow_data(route, event, prerender) {
1934
1953
 
1935
1954
  return data;
1936
1955
  } catch (e) {
1956
+ const error = coalesce_to_error(e);
1957
+ options.handle_error(error, event);
1958
+
1937
1959
  return {
1938
1960
  status: 500,
1939
- error: coalesce_to_error(e)
1961
+ error
1940
1962
  };
1941
1963
  }
1942
1964
  }
@@ -1994,10 +2016,18 @@ function validate_shadow_output(result) {
1994
2016
  * $session: any;
1995
2017
  * status: number;
1996
2018
  * error: Error;
1997
- * ssr: boolean;
2019
+ * resolve_opts: import('types/hooks').RequiredResolveOptions;
1998
2020
  * }} opts
1999
2021
  */
2000
- async function respond_with_error({ event, options, state, $session, status, error, ssr }) {
2022
+ async function respond_with_error({
2023
+ event,
2024
+ options,
2025
+ state,
2026
+ $session,
2027
+ status,
2028
+ error,
2029
+ resolve_opts
2030
+ }) {
2001
2031
  try {
2002
2032
  const default_layout = await options.manifest._.nodes[0](); // 0 is always the root layout
2003
2033
  const default_error = await options.manifest._.nodes[1](); // 1 is always the root error
@@ -2053,7 +2083,7 @@ async function respond_with_error({ event, options, state, $session, status, err
2053
2083
  branch: [layout_loaded, error_loaded],
2054
2084
  url: event.url,
2055
2085
  params,
2056
- ssr
2086
+ resolve_opts
2057
2087
  });
2058
2088
  } catch (err) {
2059
2089
  const error = coalesce_to_error(err);
@@ -2079,19 +2109,19 @@ async function respond_with_error({ event, options, state, $session, status, err
2079
2109
  * options: SSROptions;
2080
2110
  * state: SSRState;
2081
2111
  * $session: any;
2112
+ * resolve_opts: import('types/hooks').RequiredResolveOptions;
2082
2113
  * route: import('types/internal').SSRPage;
2083
2114
  * params: Record<string, string>;
2084
- * ssr: boolean;
2085
2115
  * }} opts
2086
2116
  * @returns {Promise<Response | undefined>}
2087
2117
  */
2088
2118
  async function respond$1(opts) {
2089
- const { event, options, state, $session, route, ssr } = opts;
2119
+ const { event, options, state, $session, route, resolve_opts } = opts;
2090
2120
 
2091
2121
  /** @type {Array<SSRNode | undefined>} */
2092
2122
  let nodes;
2093
2123
 
2094
- if (!ssr) {
2124
+ if (!resolve_opts.ssr) {
2095
2125
  return await render_response({
2096
2126
  ...opts,
2097
2127
  branch: [],
@@ -2121,7 +2151,7 @@ async function respond$1(opts) {
2121
2151
  $session,
2122
2152
  status: 500,
2123
2153
  error,
2124
- ssr
2154
+ resolve_opts
2125
2155
  });
2126
2156
  }
2127
2157
 
@@ -2152,7 +2182,7 @@ async function respond$1(opts) {
2152
2182
 
2153
2183
  let stuff = {};
2154
2184
 
2155
- ssr: if (ssr) {
2185
+ ssr: if (resolve_opts.ssr) {
2156
2186
  for (let i = 0; i < nodes.length; i += 1) {
2157
2187
  const node = nodes[i];
2158
2188
 
@@ -2257,7 +2287,7 @@ async function respond$1(opts) {
2257
2287
  $session,
2258
2288
  status,
2259
2289
  error,
2260
- ssr
2290
+ resolve_opts
2261
2291
  }),
2262
2292
  set_cookie_headers
2263
2293
  );
@@ -2338,10 +2368,10 @@ function with_cookies(response, set_cookie_headers) {
2338
2368
  * @param {import('types/internal').SSRPage} route
2339
2369
  * @param {import('types/internal').SSROptions} options
2340
2370
  * @param {import('types/internal').SSRState} state
2341
- * @param {boolean} ssr
2371
+ * @param {import('types/hooks').RequiredResolveOptions} resolve_opts
2342
2372
  * @returns {Promise<Response | undefined>}
2343
2373
  */
2344
- async function render_page(event, route, options, state, ssr) {
2374
+ async function render_page(event, route, options, state, resolve_opts) {
2345
2375
  if (state.initiator === route) {
2346
2376
  // infinite request cycle detected
2347
2377
  return new Response(`Not found: ${event.url.pathname}`, {
@@ -2367,9 +2397,9 @@ async function render_page(event, route, options, state, ssr) {
2367
2397
  options,
2368
2398
  state,
2369
2399
  $session,
2400
+ resolve_opts,
2370
2401
  route,
2371
- params: event.params, // TODO this is redundant
2372
- ssr
2402
+ params: event.params // TODO this is redundant
2373
2403
  });
2374
2404
 
2375
2405
  if (response) {
@@ -2441,6 +2471,9 @@ function negotiate(accept, types) {
2441
2471
 
2442
2472
  const DATA_SUFFIX = '/__data.json';
2443
2473
 
2474
+ /** @param {{ html: string }} opts */
2475
+ const default_transform = ({ html }) => html;
2476
+
2444
2477
  /** @type {import('types/internal').Respond} */
2445
2478
  async function respond(request, options, state = {}) {
2446
2479
  const url = new URL(request.url);
@@ -2524,13 +2557,22 @@ async function respond(request, options, state = {}) {
2524
2557
  rawBody: body_getter
2525
2558
  });
2526
2559
 
2527
- let ssr = true;
2560
+ /** @type {import('types/hooks').RequiredResolveOptions} */
2561
+ let resolve_opts = {
2562
+ ssr: true,
2563
+ transformPage: default_transform
2564
+ };
2528
2565
 
2529
2566
  try {
2530
2567
  const response = await options.hooks.handle({
2531
2568
  event,
2532
2569
  resolve: async (event, opts) => {
2533
- if (opts && 'ssr' in opts) ssr = /** @type {boolean} */ (opts.ssr);
2570
+ if (opts) {
2571
+ resolve_opts = {
2572
+ ssr: opts.ssr !== false,
2573
+ transformPage: opts.transformPage || default_transform
2574
+ };
2575
+ }
2534
2576
 
2535
2577
  if (state.prerender && state.prerender.fallback) {
2536
2578
  return await render_response({
@@ -2543,7 +2585,10 @@ async function respond(request, options, state = {}) {
2543
2585
  stuff: {},
2544
2586
  status: 200,
2545
2587
  branch: [],
2546
- ssr: false
2588
+ resolve_opts: {
2589
+ ...resolve_opts,
2590
+ ssr: false
2591
+ }
2547
2592
  });
2548
2593
  }
2549
2594
 
@@ -2571,22 +2616,30 @@ async function respond(request, options, state = {}) {
2571
2616
  if (is_data_request && route.type === 'page' && route.shadow) {
2572
2617
  response = await render_endpoint(event, await route.shadow());
2573
2618
 
2574
- // since redirects are opaque to the browser, we need to repackage
2575
- // 3xx responses as 200s with a custom header
2576
- if (
2577
- response &&
2578
- response.status >= 300 &&
2579
- response.status < 400 &&
2580
- request.headers.get('x-sveltekit-noredirect') === 'true'
2581
- ) {
2582
- const location = response.headers.get('location');
2583
-
2584
- if (location) {
2585
- const headers = new Headers(response.headers);
2586
- headers.set('x-sveltekit-location', location);
2587
- response = new Response(undefined, {
2588
- status: 204,
2589
- headers
2619
+ // loading data for a client-side transition is a special case
2620
+ if (request.headers.get('x-sveltekit-load') === 'true') {
2621
+ if (response) {
2622
+ // since redirects are opaque to the browser, we need to repackage
2623
+ // 3xx responses as 200s with a custom header
2624
+ if (response.status >= 300 && response.status < 400) {
2625
+ const location = response.headers.get('location');
2626
+
2627
+ if (location) {
2628
+ const headers = new Headers(response.headers);
2629
+ headers.set('x-sveltekit-location', location);
2630
+ response = new Response(undefined, {
2631
+ status: 204,
2632
+ headers
2633
+ });
2634
+ }
2635
+ }
2636
+ } else {
2637
+ // TODO ideally, the client wouldn't request this data
2638
+ // in the first place (at least in production)
2639
+ response = new Response('{}', {
2640
+ headers: {
2641
+ 'content-type': 'application/json'
2642
+ }
2590
2643
  });
2591
2644
  }
2592
2645
  }
@@ -2594,7 +2647,7 @@ async function respond(request, options, state = {}) {
2594
2647
  response =
2595
2648
  route.type === 'endpoint'
2596
2649
  ? await render_endpoint(event, await route.load())
2597
- : await render_page(event, route, options, state, ssr);
2650
+ : await render_page(event, route, options, state, resolve_opts);
2598
2651
  }
2599
2652
 
2600
2653
  if (response) {
@@ -2646,7 +2699,7 @@ async function respond(request, options, state = {}) {
2646
2699
  $session,
2647
2700
  status: 404,
2648
2701
  error: new Error(`Not found: ${event.url.pathname}`),
2649
- ssr
2702
+ resolve_opts
2650
2703
  });
2651
2704
  }
2652
2705
 
@@ -2682,7 +2735,7 @@ async function respond(request, options, state = {}) {
2682
2735
  $session,
2683
2736
  status: 500,
2684
2737
  error,
2685
- ssr
2738
+ resolve_opts
2686
2739
  });
2687
2740
  } catch (/** @type {unknown} */ e) {
2688
2741
  const error = coalesce_to_error(e);
package/dist/cli.js CHANGED
@@ -998,7 +998,7 @@ async function launch(port, https) {
998
998
  exec(`${cmd} ${https ? 'https' : 'http'}://localhost:${port}`);
999
999
  }
1000
1000
 
1001
- const prog = sade('svelte-kit').version('1.0.0-next.268');
1001
+ const prog = sade('svelte-kit').version('1.0.0-next.271');
1002
1002
 
1003
1003
  prog
1004
1004
  .command('dev')
@@ -1156,7 +1156,7 @@ async function check_port(port) {
1156
1156
  function welcome({ port, host, https, open, loose, allow, cwd }) {
1157
1157
  if (open) launch(port, https);
1158
1158
 
1159
- console.log($.bold().cyan(`\n SvelteKit v${'1.0.0-next.268'}\n`));
1159
+ console.log($.bold().cyan(`\n SvelteKit v${'1.0.0-next.271'}\n`));
1160
1160
 
1161
1161
  const protocol = https ? 'https:' : 'http:';
1162
1162
  const exposed = typeof host !== 'undefined' && host !== 'localhost' && host !== '127.0.0.1';
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@sveltejs/kit",
3
- "version": "1.0.0-next.268",
3
+ "version": "1.0.0-next.271",
4
4
  "repository": {
5
5
  "type": "git",
6
6
  "url": "https://github.com/sveltejs/kit",
package/types/hooks.d.ts CHANGED
@@ -14,14 +14,17 @@ export interface GetSession {
14
14
  (event: RequestEvent): MaybePromise<App.Session>;
15
15
  }
16
16
 
17
- export interface ResolveOpts {
18
- ssr?: boolean;
17
+ export interface RequiredResolveOptions {
18
+ ssr: boolean;
19
+ transformPage: ({ html }: { html: string }) => string;
19
20
  }
20
21
 
22
+ export type ResolveOptions = Partial<RequiredResolveOptions>;
23
+
21
24
  export interface Handle {
22
25
  (input: {
23
26
  event: RequestEvent;
24
- resolve(event: RequestEvent, opts?: ResolveOpts): MaybePromise<Response>;
27
+ resolve(event: RequestEvent, opts?: ResolveOptions): MaybePromise<Response>;
25
28
  }): MaybePromise<Response>;
26
29
  }
27
30
 
package/types/index.d.ts CHANGED
@@ -14,4 +14,11 @@ export {
14
14
  } from './config';
15
15
  export { EndpointOutput, RequestHandler } from './endpoint';
16
16
  export { ErrorLoad, ErrorLoadInput, Load, LoadInput, LoadOutput } from './page';
17
- export { ExternalFetch, GetSession, Handle, HandleError, RequestEvent, ResolveOpts } from './hooks';
17
+ export {
18
+ ExternalFetch,
19
+ GetSession,
20
+ Handle,
21
+ HandleError,
22
+ RequestEvent,
23
+ ResolveOptions
24
+ } from './hooks';