@sveltejs/kit 1.0.0-next.203 → 1.0.0-next.208

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/dist/ssr.js CHANGED
@@ -1,5 +1,6 @@
1
1
  import { g as get_single_valued_header, r as resolve, i as is_root_relative } from './chunks/url.js';
2
2
  import { c as coalesce_to_error } from './chunks/error.js';
3
+ import { s } from './chunks/misc.js';
3
4
 
4
5
  /** @param {Record<string, any>} obj */
5
6
  function lowercase_keys(obj) {
@@ -13,6 +14,28 @@ function lowercase_keys(obj) {
13
14
  return clone;
14
15
  }
15
16
 
17
+ /** @param {Record<string, string>} params */
18
+ function decode_params(params) {
19
+ for (const key in params) {
20
+ // input has already been decoded by decodeURI
21
+ // now handle the rest that decodeURIComponent would do
22
+ params[key] = params[key]
23
+ .replace(/%23/g, '#')
24
+ .replace(/%3[Bb]/g, ';')
25
+ .replace(/%2[Cc]/g, ',')
26
+ .replace(/%2[Ff]/g, '/')
27
+ .replace(/%3[Ff]/g, '?')
28
+ .replace(/%3[Aa]/g, ':')
29
+ .replace(/%40/g, '@')
30
+ .replace(/%26/g, '&')
31
+ .replace(/%3[Dd]/g, '=')
32
+ .replace(/%2[Bb]/g, '+')
33
+ .replace(/%24/g, '$');
34
+ }
35
+
36
+ return params;
37
+ }
38
+
16
39
  /** @param {string} body */
17
40
  function error(body) {
18
41
  return {
@@ -60,10 +83,13 @@ async function render_endpoint(request, route, match) {
60
83
  return;
61
84
  }
62
85
 
63
- const params = route.params(match);
86
+ // we're mutating `request` so that we don't have to do { ...request, params }
87
+ // on the next line, since that breaks the getters that replace path, query and
88
+ // origin. We could revert that once we remove the getters
89
+ request.params = route.params ? decode_params(route.params(match)) : {};
64
90
 
65
- const response = await handler({ ...request, params });
66
- const preface = `Invalid response from route ${request.path}`;
91
+ const response = await handler(request);
92
+ const preface = `Invalid response from route ${request.url.pathname}`;
67
93
 
68
94
  if (!response) {
69
95
  return;
@@ -478,8 +504,6 @@ function escape(str, dict, unicode_encoder) {
478
504
  return result;
479
505
  }
480
506
 
481
- const s$1 = JSON.stringify;
482
-
483
507
  // TODO rename this function/module
484
508
 
485
509
  /**
@@ -490,7 +514,8 @@ const s$1 = JSON.stringify;
490
514
  * page_config: { hydrate: boolean, router: boolean, ssr: boolean };
491
515
  * status: number;
492
516
  * error?: Error,
493
- * page?: import('types/page').Page
517
+ * url: URL;
518
+ * params: Record<string, string>
494
519
  * }} opts
495
520
  */
496
521
  async function render_response({
@@ -500,10 +525,11 @@ async function render_response({
500
525
  page_config,
501
526
  status,
502
527
  error,
503
- page
528
+ url,
529
+ params
504
530
  }) {
505
- const css = new Set(options.entry.css);
506
- const js = new Set(options.entry.js);
531
+ const css = new Set(options.manifest._.entry.css);
532
+ const js = new Set(options.manifest._.entry.js);
507
533
  const styles = new Set();
508
534
 
509
535
  /** @type {Array<{ url: string, body: string, json: string }>} */
@@ -541,10 +567,29 @@ async function render_response({
541
567
  navigating: writable(null),
542
568
  session
543
569
  },
544
- page,
570
+ page: { url, params },
545
571
  components: branch.map(({ node }) => node.module.default)
546
572
  };
547
573
 
574
+ if (options.dev) {
575
+ // TODO remove this for 1.0
576
+ /**
577
+ * @param {string} property
578
+ * @param {string} replacement
579
+ */
580
+ const print_error = (property, replacement) => {
581
+ Object.defineProperty(props.page, property, {
582
+ get: () => {
583
+ throw new Error(`$page.${property} has been replaced by $page.url.${replacement}`);
584
+ }
585
+ });
586
+ };
587
+
588
+ print_error('origin', 'origin');
589
+ print_error('path', 'pathname');
590
+ print_error('query', 'searchParams');
591
+ }
592
+
548
593
  // props_n (instead of props[n]) makes it easy to avoid
549
594
  // unnecessary updates for layout components
550
595
  for (let i = 0; i < branch.length; i += 1) {
@@ -575,8 +620,11 @@ async function render_response({
575
620
  ? `<style amp-custom>${Array.from(styles).concat(rendered.css.code).join('\n')}</style>`
576
621
  : ''
577
622
  : [
578
- ...Array.from(js).map((dep) => `<link rel="modulepreload" href="${dep}">`),
579
- ...Array.from(css).map((dep) => `<link rel="stylesheet" href="${dep}">`)
623
+ // From https://web.dev/priority-hints/:
624
+ // Generally, preloads will load in the order the parser gets to them for anything above "Medium" priority
625
+ // Thus, we should list CSS first
626
+ ...Array.from(css).map((dep) => `<link rel="stylesheet" href="${options.prefix}${dep}">`),
627
+ ...Array.from(js).map((dep) => `<link rel="modulepreload" href="${options.prefix}${dep}">`)
580
628
  ].join('\n\t\t');
581
629
 
582
630
  /** @type {string} */
@@ -593,35 +641,26 @@ async function render_response({
593
641
  } else if (include_js) {
594
642
  // prettier-ignore
595
643
  init = `<script type="module">
596
- import { start } from ${s$1(options.entry.file)};
644
+ import { start } from ${s(options.prefix + options.manifest._.entry.file)};
597
645
  start({
598
- target: ${options.target ? `document.querySelector(${s$1(options.target)})` : 'document.body'},
599
- paths: ${s$1(options.paths)},
646
+ target: ${options.target ? `document.querySelector(${s(options.target)})` : 'document.body'},
647
+ paths: ${s(options.paths)},
600
648
  session: ${try_serialize($session, (error) => {
601
649
  throw new Error(`Failed to serialize session data: ${error.message}`);
602
650
  })},
603
- host: ${page && page.host ? s$1(page.host) : 'location.host'},
604
651
  route: ${!!page_config.router},
605
652
  spa: ${!page_config.ssr},
606
- trailing_slash: ${s$1(options.trailing_slash)},
653
+ trailing_slash: ${s(options.trailing_slash)},
607
654
  hydrate: ${page_config.ssr && page_config.hydrate ? `{
608
655
  status: ${status},
609
656
  error: ${serialize_error(error)},
610
657
  nodes: [
611
658
  ${(branch || [])
612
- .map(({ node }) => `import(${s$1(node.entry)})`)
659
+ .map(({ node }) => `import(${s(options.prefix + node.entry)})`)
613
660
  .join(',\n\t\t\t\t\t\t')}
614
661
  ],
615
- page: {
616
- host: ${page && page.host ? s$1(page.host) : 'location.host'}, // TODO this is redundant
617
- path: ${page && page.path ? try_serialize(page.path, error => {
618
- throw new Error(`Failed to serialize page.path: ${error.message}`);
619
- }) : null},
620
- query: new URLSearchParams(${page && page.query ? s$1(page.query.toString()) : ''}),
621
- params: ${page && page.params ? try_serialize(page.params, error => {
622
- throw new Error(`Failed to serialize page.params: ${error.message}`);
623
- }) : null}
624
- }
662
+ url: new URL(${s(url.href)}),
663
+ params: ${devalue(params)}
625
664
  }` : 'null'}
626
665
  });
627
666
  </script>`;
@@ -776,15 +815,14 @@ function normalize(loaded) {
776
815
  return /** @type {import('types/internal').NormalizedLoadOutput} */ (loaded);
777
816
  }
778
817
 
779
- const s = JSON.stringify;
780
-
781
818
  /**
782
819
  * @param {{
783
820
  * request: import('types/hooks').ServerRequest;
784
821
  * options: import('types/internal').SSRRenderOptions;
785
822
  * state: import('types/internal').SSRRenderState;
786
823
  * route: import('types/internal').SSRPage | null;
787
- * page: import('types/page').Page;
824
+ * url: URL;
825
+ * params: Record<string, string>;
788
826
  * node: import('types/internal').SSRNode;
789
827
  * $session: any;
790
828
  * stuff: Record<string, any>;
@@ -801,7 +839,8 @@ async function load_node({
801
839
  options,
802
840
  state,
803
841
  route,
804
- page,
842
+ url,
843
+ params,
805
844
  node,
806
845
  $session,
807
846
  stuff,
@@ -831,9 +870,9 @@ async function load_node({
831
870
 
832
871
  let loaded;
833
872
 
834
- const page_proxy = new Proxy(page, {
873
+ const url_proxy = new Proxy(url, {
835
874
  get: (target, prop, receiver) => {
836
- if (prop === 'query' && prerender_enabled) {
875
+ if (prerender_enabled && (prop === 'search' || prop === 'searchParams')) {
837
876
  throw new Error('Cannot access query on a page with prerendering enabled');
838
877
  }
839
878
  return Reflect.get(target, prop, receiver);
@@ -843,7 +882,8 @@ async function load_node({
843
882
  if (module.load) {
844
883
  /** @type {import('types/page').LoadInput | import('types/page').ErrorLoadInput} */
845
884
  const load_input = {
846
- page: page_proxy,
885
+ url: url_proxy,
886
+ params,
847
887
  get session() {
848
888
  uses_credentials = true;
849
889
  return $session;
@@ -854,12 +894,12 @@ async function load_node({
854
894
  */
855
895
  fetch: async (resource, opts = {}) => {
856
896
  /** @type {string} */
857
- let url;
897
+ let requested;
858
898
 
859
899
  if (typeof resource === 'string') {
860
- url = resource;
900
+ requested = resource;
861
901
  } else {
862
- url = resource.url;
902
+ requested = resource.url;
863
903
 
864
904
  opts = {
865
905
  method: resource.method,
@@ -875,7 +915,9 @@ async function load_node({
875
915
  };
876
916
  }
877
917
 
878
- const resolved = resolve(request.path, url.split('?')[0]);
918
+ opts.headers = new Headers(opts.headers);
919
+
920
+ const resolved = resolve(request.url.pathname, requested.split('?')[0]);
879
921
 
880
922
  let response;
881
923
 
@@ -886,35 +928,37 @@ async function load_node({
886
928
  resolved.startsWith(prefix) ? resolved.slice(prefix.length) : resolved
887
929
  ).slice(1);
888
930
  const filename_html = `${filename}/index.html`; // path may also match path/index.html
889
- const asset = options.manifest.assets.find(
890
- (d) => d.file === filename || d.file === filename_html
891
- );
892
931
 
893
- if (asset) {
894
- response = options.read
895
- ? new Response(options.read(asset.file), {
896
- headers: asset.type ? { 'content-type': asset.type } : {}
897
- })
898
- : await fetch(
899
- // TODO we need to know what protocol to use
900
- `http://${page.host}/${asset.file}`,
901
- /** @type {RequestInit} */ (opts)
902
- );
932
+ const is_asset = options.manifest.assets.has(filename);
933
+ const is_asset_html = options.manifest.assets.has(filename_html);
934
+
935
+ if (is_asset || is_asset_html) {
936
+ const file = is_asset ? filename : filename_html;
937
+
938
+ if (options.read) {
939
+ const type = is_asset
940
+ ? options.manifest._.mime[filename.slice(filename.lastIndexOf('.'))]
941
+ : 'text/html';
942
+
943
+ response = new Response(options.read(file), {
944
+ headers: type ? { 'content-type': type } : {}
945
+ });
946
+ } else {
947
+ response = await fetch(`${url.origin}/${file}`, /** @type {RequestInit} */ (opts));
948
+ }
903
949
  } else if (is_root_relative(resolved)) {
904
950
  const relative = resolved;
905
951
 
906
- const headers = /** @type {import('types/helper').RequestHeaders} */ ({
907
- ...opts.headers
908
- });
909
-
910
952
  // TODO: fix type https://github.com/node-fetch/node-fetch/issues/1113
911
953
  if (opts.credentials !== 'omit') {
912
954
  uses_credentials = true;
913
955
 
914
- headers.cookie = request.headers.cookie;
956
+ if (request.headers.cookie) {
957
+ opts.headers.set('cookie', request.headers.cookie);
958
+ }
915
959
 
916
- if (!headers.authorization) {
917
- headers.authorization = request.headers.authorization;
960
+ if (request.headers.authorization && !opts.headers.has('authorization')) {
961
+ opts.headers.set('authorization', request.headers.authorization);
918
962
  }
919
963
  }
920
964
 
@@ -926,20 +970,16 @@ async function load_node({
926
970
  throw new Error('Request body must be a string');
927
971
  }
928
972
 
929
- const search = url.includes('?') ? url.slice(url.indexOf('?') + 1) : '';
930
-
931
973
  const rendered = await respond(
932
974
  {
933
- host: request.host,
975
+ url: new URL(requested, request.url),
934
976
  method: opts.method || 'GET',
935
- headers,
936
- path: relative,
937
- rawBody: opts.body == null ? null : new TextEncoder().encode(opts.body),
938
- query: new URLSearchParams(search)
977
+ headers: Object.fromEntries(opts.headers),
978
+ rawBody: opts.body == null ? null : new TextEncoder().encode(opts.body)
939
979
  },
940
980
  options,
941
981
  {
942
- fetched: url,
982
+ fetched: requested,
943
983
  initiator: route
944
984
  }
945
985
  );
@@ -956,40 +996,40 @@ async function load_node({
956
996
  status: rendered.status,
957
997
  headers: /** @type {Record<string, string>} */ (rendered.headers)
958
998
  });
999
+ } else {
1000
+ // we can't load the endpoint from our own manifest,
1001
+ // so we need to make an actual HTTP request
1002
+ return fetch(new URL(requested, request.url).href, {
1003
+ method: opts.method || 'GET',
1004
+ headers: opts.headers
1005
+ });
959
1006
  }
960
1007
  } else {
961
1008
  // external
962
1009
  if (resolved.startsWith('//')) {
963
- throw new Error(`Cannot request protocol-relative URL (${url}) in server-side fetch`);
1010
+ throw new Error(
1011
+ `Cannot request protocol-relative URL (${requested}) in server-side fetch`
1012
+ );
964
1013
  }
965
1014
 
966
1015
  // external fetch
967
- if (typeof request.host !== 'undefined') {
968
- const { hostname: fetch_hostname } = new URL(url);
969
- const [server_hostname] = request.host.split(':');
970
-
971
- // allow cookie passthrough for "same-origin"
972
- // if SvelteKit is serving my.domain.com:
973
- // - domain.com WILL NOT receive cookies
974
- // - my.domain.com WILL receive cookies
975
- // - api.domain.dom WILL NOT receive cookies
976
- // - sub.my.domain.com WILL receive cookies
977
- // ports do not affect the resolution
978
- // leading dot prevents mydomain.com matching domain.com
979
- if (
980
- `.${fetch_hostname}`.endsWith(`.${server_hostname}`) &&
981
- opts.credentials !== 'omit'
982
- ) {
983
- uses_credentials = true;
984
-
985
- opts.headers = {
986
- ...opts.headers,
987
- cookie: request.headers.cookie
988
- };
989
- }
1016
+ // allow cookie passthrough for "same-origin"
1017
+ // if SvelteKit is serving my.domain.com:
1018
+ // - domain.com WILL NOT receive cookies
1019
+ // - my.domain.com WILL receive cookies
1020
+ // - api.domain.dom WILL NOT receive cookies
1021
+ // - sub.my.domain.com WILL receive cookies
1022
+ // ports do not affect the resolution
1023
+ // leading dot prevents mydomain.com matching domain.com
1024
+ if (
1025
+ `.${new URL(requested).hostname}`.endsWith(`.${request.url.hostname}`) &&
1026
+ opts.credentials !== 'omit'
1027
+ ) {
1028
+ uses_credentials = true;
1029
+ opts.headers.set('cookie', request.headers.cookie);
990
1030
  }
991
1031
 
992
- const external_request = new Request(url, /** @type {RequestInit} */ (opts));
1032
+ const external_request = new Request(requested, /** @type {RequestInit} */ (opts));
993
1033
  response = await options.hooks.externalFetch.call(null, external_request);
994
1034
  }
995
1035
 
@@ -1012,7 +1052,7 @@ async function load_node({
1012
1052
  if (!opts.body || typeof opts.body === 'string') {
1013
1053
  // prettier-ignore
1014
1054
  fetched.push({
1015
- url,
1055
+ url: requested,
1016
1056
  body: /** @type {string} */ (opts.body),
1017
1057
  json: `{"status":${response.status},"statusText":${s(response.statusText)},"headers":${s(headers)},"body":"${escape_json_string_in_html(body)}"}`
1018
1058
  });
@@ -1050,6 +1090,15 @@ async function load_node({
1050
1090
  stuff: { ...stuff }
1051
1091
  };
1052
1092
 
1093
+ if (options.dev) {
1094
+ // TODO remove this for 1.0
1095
+ Object.defineProperty(load_input, 'page', {
1096
+ get: () => {
1097
+ throw new Error('`page` in `load` functions has been replaced by `url` and `params`');
1098
+ }
1099
+ });
1100
+ }
1101
+
1053
1102
  if (is_error) {
1054
1103
  /** @type {import('types/page').ErrorLoadInput} */ (load_input).status = status;
1055
1104
  /** @type {import('types/page').ErrorLoadInput} */ (load_input).error = error;
@@ -1096,15 +1145,11 @@ async function load_node({
1096
1145
  * }} opts
1097
1146
  */
1098
1147
  async function respond_with_error({ request, options, state, $session, status, error }) {
1099
- const default_layout = await options.load_component(options.manifest.layout);
1100
- const default_error = await options.load_component(options.manifest.error);
1101
-
1102
- const page = {
1103
- host: request.host,
1104
- path: request.path,
1105
- query: request.query,
1106
- params: {}
1107
- };
1148
+ const default_layout = await options.manifest._.nodes[0](); // 0 is always the root layout
1149
+ const default_error = await options.manifest._.nodes[1](); // 1 is always the root error
1150
+
1151
+ /** @type {Record<string, string>} */
1152
+ const params = {}; // error page has no params
1108
1153
 
1109
1154
  // error pages don't fall through, so we know it's not undefined
1110
1155
  const loaded = /** @type {Loaded} */ (
@@ -1113,7 +1158,8 @@ async function respond_with_error({ request, options, state, $session, status, e
1113
1158
  options,
1114
1159
  state,
1115
1160
  route: null,
1116
- page,
1161
+ url: request.url, // TODO this is redundant, no?
1162
+ params,
1117
1163
  node: default_layout,
1118
1164
  $session,
1119
1165
  stuff: {},
@@ -1131,7 +1177,8 @@ async function respond_with_error({ request, options, state, $session, status, e
1131
1177
  options,
1132
1178
  state,
1133
1179
  route: null,
1134
- page,
1180
+ url: request.url,
1181
+ params,
1135
1182
  node: default_error,
1136
1183
  $session,
1137
1184
  stuff: loaded ? loaded.stuff : {},
@@ -1156,7 +1203,8 @@ async function respond_with_error({ request, options, state, $session, status, e
1156
1203
  status,
1157
1204
  error,
1158
1205
  branch,
1159
- page
1206
+ url: request.url,
1207
+ params
1160
1208
  });
1161
1209
  } catch (err) {
1162
1210
  const error = coalesce_to_error(err);
@@ -1197,7 +1245,7 @@ function is_prerender_enabled(options, node, state) {
1197
1245
  * state: SSRRenderState;
1198
1246
  * $session: any;
1199
1247
  * route: import('types/internal').SSRPage;
1200
- * page: import('types/page').Page;
1248
+ * params: Record<string, string>;
1201
1249
  * }} opts
1202
1250
  * @returns {Promise<ServerResponse | undefined>}
1203
1251
  */
@@ -1208,7 +1256,9 @@ async function respond$1(opts) {
1208
1256
  let nodes;
1209
1257
 
1210
1258
  try {
1211
- nodes = await Promise.all(route.a.map((id) => (id ? options.load_component(id) : undefined)));
1259
+ nodes = await Promise.all(
1260
+ route.a.map((n) => options.manifest._.nodes[n] && options.manifest._.nodes[n]())
1261
+ );
1212
1262
  } catch (err) {
1213
1263
  const error = coalesce_to_error(err);
1214
1264
 
@@ -1263,6 +1313,7 @@ async function respond$1(opts) {
1263
1313
  try {
1264
1314
  loaded = await load_node({
1265
1315
  ...opts,
1316
+ url: request.url,
1266
1317
  node,
1267
1318
  stuff,
1268
1319
  prerender_enabled: is_prerender_enabled(options, node, state),
@@ -1305,7 +1356,7 @@ async function respond$1(opts) {
1305
1356
  if (error) {
1306
1357
  while (i--) {
1307
1358
  if (route.b[i]) {
1308
- const error_node = await options.load_component(route.b[i]);
1359
+ const error_node = await options.manifest._.nodes[route.b[i]]();
1309
1360
 
1310
1361
  /** @type {Loaded} */
1311
1362
  let node_loaded;
@@ -1319,6 +1370,7 @@ async function respond$1(opts) {
1319
1370
  const error_loaded = /** @type {import('./types').Loaded} */ (
1320
1371
  await load_node({
1321
1372
  ...opts,
1373
+ url: request.url,
1322
1374
  node: error_node,
1323
1375
  stuff: node_loaded.stuff,
1324
1376
  prerender_enabled: is_prerender_enabled(options, error_node, state),
@@ -1376,6 +1428,7 @@ async function respond$1(opts) {
1376
1428
  return with_cookies(
1377
1429
  await render_response({
1378
1430
  ...opts,
1431
+ url: request.url,
1379
1432
  page_config,
1380
1433
  status,
1381
1434
  error,
@@ -1436,18 +1489,11 @@ async function render_page(request, route, match, options, state) {
1436
1489
  return {
1437
1490
  status: 404,
1438
1491
  headers: {},
1439
- body: `Not found: ${request.path}`
1492
+ body: `Not found: ${request.url.pathname}`
1440
1493
  };
1441
1494
  }
1442
1495
 
1443
- const params = route.params(match);
1444
-
1445
- const page = {
1446
- host: request.host,
1447
- path: request.path,
1448
- query: request.query,
1449
- params
1450
- };
1496
+ const params = route.params ? decode_params(route.params(match)) : {};
1451
1497
 
1452
1498
  const $session = await options.hooks.getSession(request);
1453
1499
 
@@ -1457,7 +1503,7 @@ async function render_page(request, route, match, options, state) {
1457
1503
  state,
1458
1504
  $session,
1459
1505
  route,
1460
- page
1506
+ params
1461
1507
  });
1462
1508
 
1463
1509
  if (response) {
@@ -1662,22 +1708,25 @@ function get_multipart(text, boundary) {
1662
1708
 
1663
1709
  /** @type {import('@sveltejs/kit/ssr').Respond} */
1664
1710
  async function respond(incoming, options, state = {}) {
1665
- if (incoming.path !== '/' && options.trailing_slash !== 'ignore') {
1666
- const has_trailing_slash = incoming.path.endsWith('/');
1711
+ if (incoming.url.pathname !== '/' && options.trailing_slash !== 'ignore') {
1712
+ const has_trailing_slash = incoming.url.pathname.endsWith('/');
1667
1713
 
1668
1714
  if (
1669
1715
  (has_trailing_slash && options.trailing_slash === 'never') ||
1670
1716
  (!has_trailing_slash &&
1671
1717
  options.trailing_slash === 'always' &&
1672
- !(incoming.path.split('/').pop() || '').includes('.'))
1718
+ !(incoming.url.pathname.split('/').pop() || '').includes('.'))
1673
1719
  ) {
1674
- const path = has_trailing_slash ? incoming.path.slice(0, -1) : incoming.path + '/';
1675
- const q = incoming.query.toString();
1720
+ incoming.url.pathname = has_trailing_slash
1721
+ ? incoming.url.pathname.slice(0, -1)
1722
+ : incoming.url.pathname + '/';
1723
+
1724
+ if (incoming.url.search === '?') incoming.url.search = '';
1676
1725
 
1677
1726
  return {
1678
1727
  status: 301,
1679
1728
  headers: {
1680
- location: options.paths.base + path + (q ? `?${q}` : '')
1729
+ location: incoming.url.pathname + incoming.url.search
1681
1730
  }
1682
1731
  };
1683
1732
  }
@@ -1692,12 +1741,33 @@ async function respond(incoming, options, state = {}) {
1692
1741
  locals: {}
1693
1742
  };
1694
1743
 
1744
+ if (options.dev) {
1745
+ // TODO remove this for 1.0
1746
+ /**
1747
+ * @param {string} property
1748
+ * @param {string} replacement
1749
+ */
1750
+ const print_error = (property, replacement) => {
1751
+ Object.defineProperty(request, property, {
1752
+ get: () => {
1753
+ throw new Error(`request.${property} has been replaced by request.url.${replacement}`);
1754
+ }
1755
+ });
1756
+ };
1757
+
1758
+ print_error('origin', 'origin');
1759
+ print_error('path', 'pathname');
1760
+ print_error('query', 'searchParams');
1761
+ }
1762
+
1695
1763
  try {
1696
1764
  return await options.hooks.handle({
1697
1765
  request,
1698
1766
  resolve: async (request) => {
1699
1767
  if (state.prerender && state.prerender.fallback) {
1700
1768
  return await render_response({
1769
+ url: request.url,
1770
+ params: request.params,
1701
1771
  options,
1702
1772
  $session: await options.hooks.getSession(request),
1703
1773
  page_config: { ssr: false, router: true, hydrate: true },
@@ -1706,8 +1776,9 @@ async function respond(incoming, options, state = {}) {
1706
1776
  });
1707
1777
  }
1708
1778
 
1709
- const decoded = decodeURI(request.path);
1710
- for (const route of options.manifest.routes) {
1779
+ const decoded = decodeURI(request.url.pathname).replace(options.paths.base, '');
1780
+
1781
+ for (const route of options.manifest._.routes) {
1711
1782
  const match = route.pattern.exec(decoded);
1712
1783
  if (!match) continue;
1713
1784
 
@@ -1744,15 +1815,19 @@ async function respond(incoming, options, state = {}) {
1744
1815
  }
1745
1816
  }
1746
1817
 
1747
- const $session = await options.hooks.getSession(request);
1748
- return await respond_with_error({
1749
- request,
1750
- options,
1751
- state,
1752
- $session,
1753
- status: 404,
1754
- error: new Error(`Not found: ${request.path}`)
1755
- });
1818
+ // if this request came direct from the user, rather than
1819
+ // via a `fetch` in a `load`, render a 404 page
1820
+ if (!state.initiator) {
1821
+ const $session = await options.hooks.getSession(request);
1822
+ return await respond_with_error({
1823
+ request,
1824
+ options,
1825
+ state,
1826
+ $session,
1827
+ status: 404,
1828
+ error: new Error(`Not found: ${request.url.pathname}`)
1829
+ });
1830
+ }
1756
1831
  }
1757
1832
  });
1758
1833
  } catch (/** @type {unknown} */ err) {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@sveltejs/kit",
3
- "version": "1.0.0-next.203",
3
+ "version": "1.0.0-next.208",
4
4
  "repository": {
5
5
  "type": "git",
6
6
  "url": "https://github.com/sveltejs/kit",
@@ -87,6 +87,5 @@
87
87
  "test:unit": "uvu src \"(spec\\.js|test[\\\\/]index\\.js)\" -i packaging",
88
88
  "test:packaging": "uvu src/packaging \"(spec\\.js|test[\\\\/]index\\.js)\"",
89
89
  "test:integration": "uvu test test.js"
90
- },
91
- "readme": "# The fastest way to build Svelte apps\n\nThis is the [SvelteKit](https://kit.svelte.dev) framework and CLI.\n\nThe quickest way to get started is via the [create-svelte](https://github.com/sveltejs/kit/tree/master/packages/create-svelte) package:\n\n```bash\nnpm init svelte@next my-app\ncd my-app\nnpm install\nnpm run dev\n```\n\nSee the [documentation](https://kit.svelte.dev/docs) to learn more.\n\n## Changelog\n\n[The Changelog for this package is available on GitHub](https://github.com/sveltejs/kit/blob/master/packages/kit/CHANGELOG.md).\n"
90
+ }
92
91
  }