@sveltejs/kit 1.0.0-next.446 → 1.0.0-next.449

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.
Files changed (66) hide show
  1. package/package.json +5 -7
  2. package/src/{core/constants.js → constants.js} +2 -0
  3. package/src/core/env.js +1 -1
  4. package/src/core/sync/write_ambient.js +1 -1
  5. package/src/core/sync/write_types/index.js +2 -2
  6. package/src/exports/vite/dev/index.js +1 -1
  7. package/src/exports/vite/preview/index.js +1 -1
  8. package/src/runtime/client/client.js +69 -54
  9. package/src/runtime/client/start.js +2 -0
  10. package/src/runtime/client/types.d.ts +2 -0
  11. package/src/runtime/server/data/index.js +146 -0
  12. package/src/runtime/server/index.js +20 -143
  13. package/src/runtime/server/page/index.js +17 -12
  14. package/src/runtime/server/page/load_data.js +1 -45
  15. package/src/runtime/server/page/render.js +29 -11
  16. package/src/runtime/server/page/respond_with_error.js +0 -1
  17. package/src/runtime/server/utils.js +21 -0
  18. package/types/internal.d.ts +0 -1
  19. package/src/core/sync/write_types/test/layout/+layout.js +0 -5
  20. package/src/core/sync/write_types/test/layout/+layout.server.js +0 -5
  21. package/src/core/sync/write_types/test/layout/+layout.svelte +0 -0
  22. package/src/core/sync/write_types/test/layout/+page.js +0 -5
  23. package/src/core/sync/write_types/test/layout/+page.server.js +0 -5
  24. package/src/core/sync/write_types/test/layout/+page.svelte +0 -0
  25. package/src/core/sync/write_types/test/layout/_expected/$types.d.ts +0 -67
  26. package/src/core/sync/write_types/test/layout-advanced/(main)/+layout.server.js +0 -5
  27. package/src/core/sync/write_types/test/layout-advanced/(main)/+layout.svelte +0 -0
  28. package/src/core/sync/write_types/test/layout-advanced/(main)/+page.js +0 -5
  29. package/src/core/sync/write_types/test/layout-advanced/(main)/+page@.svelte +0 -0
  30. package/src/core/sync/write_types/test/layout-advanced/(main)/sub/+page.js +0 -5
  31. package/src/core/sync/write_types/test/layout-advanced/(main)/sub/+page.svelte +0 -0
  32. package/src/core/sync/write_types/test/layout-advanced/+layout.js +0 -5
  33. package/src/core/sync/write_types/test/layout-advanced/+layout.svelte +0 -0
  34. package/src/core/sync/write_types/test/layout-advanced/_expected/$types.d.ts +0 -32
  35. package/src/core/sync/write_types/test/layout-advanced/_expected/(main)/$types.d.ts +0 -42
  36. package/src/core/sync/write_types/test/layout-advanced/_expected/(main)/sub/$types.d.ts +0 -33
  37. package/src/core/sync/write_types/test/simple-page-server-and-shared/+page.js +0 -5
  38. package/src/core/sync/write_types/test/simple-page-server-and-shared/+page.server.js +0 -5
  39. package/src/core/sync/write_types/test/simple-page-server-and-shared/+page.svelte +0 -0
  40. package/src/core/sync/write_types/test/simple-page-server-and-shared/_expected/$types.d.ts +0 -44
  41. package/src/core/sync/write_types/test/simple-page-server-only/+page.server.js +0 -5
  42. package/src/core/sync/write_types/test/simple-page-server-only/+page.svelte +0 -0
  43. package/src/core/sync/write_types/test/simple-page-server-only/_expected/$types.d.ts +0 -30
  44. package/src/core/sync/write_types/test/simple-page-shared-only/+page.js +0 -5
  45. package/src/core/sync/write_types/test/simple-page-shared-only/+page.svelte +0 -0
  46. package/src/core/sync/write_types/test/simple-page-shared-only/_expected/$types.d.ts +0 -33
  47. package/src/core/sync/write_types/test/slugs/+layout.js +0 -1
  48. package/src/core/sync/write_types/test/slugs/+layout.svelte +0 -1
  49. package/src/core/sync/write_types/test/slugs/[...rest]/+page.js +0 -3
  50. package/src/core/sync/write_types/test/slugs/[...rest]/+page.svelte +0 -0
  51. package/src/core/sync/write_types/test/slugs/[slug]/+page.js +0 -3
  52. package/src/core/sync/write_types/test/slugs/[slug]/+page.svelte +0 -0
  53. package/src/core/sync/write_types/test/slugs/_expected/$types.d.ts +0 -32
  54. package/src/core/sync/write_types/test/slugs/_expected/[...rest]/$types.d.ts +0 -29
  55. package/src/core/sync/write_types/test/slugs/_expected/[slug]/$types.d.ts +0 -29
  56. package/src/core/sync/write_types/test/slugs-layout-not-all-pages-have-load/+layout.js +0 -1
  57. package/src/core/sync/write_types/test/slugs-layout-not-all-pages-have-load/+layout.svelte +0 -1
  58. package/src/core/sync/write_types/test/slugs-layout-not-all-pages-have-load/_expected/$types.d.ts +0 -30
  59. package/src/core/sync/write_types/test/slugs-layout-not-all-pages-have-load/_expected/nested/$types.d.ts +0 -32
  60. package/src/core/sync/write_types/test/slugs-layout-not-all-pages-have-load/_expected/nested/[...rest]/$types.d.ts +0 -37
  61. package/src/core/sync/write_types/test/slugs-layout-not-all-pages-have-load/_expected/nested/[slug]/$types.d.ts +0 -17
  62. package/src/core/sync/write_types/test/slugs-layout-not-all-pages-have-load/nested/+layout.js +0 -1
  63. package/src/core/sync/write_types/test/slugs-layout-not-all-pages-have-load/nested/+layout.svelte +0 -1
  64. package/src/core/sync/write_types/test/slugs-layout-not-all-pages-have-load/nested/[...rest]/+page.js +0 -3
  65. package/src/core/sync/write_types/test/slugs-layout-not-all-pages-have-load/nested/[...rest]/+page.svelte +0 -0
  66. package/src/core/sync/write_types/test/slugs-layout-not-all-pages-have-load/nested/[slug]/+page@.svelte +0 -0
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@sveltejs/kit",
3
- "version": "1.0.0-next.446",
3
+ "version": "1.0.0-next.449",
4
4
  "repository": {
5
5
  "type": "git",
6
6
  "url": "https://github.com/sveltejs/kit",
@@ -12,7 +12,7 @@
12
12
  "dependencies": {
13
13
  "@sveltejs/vite-plugin-svelte": "^1.0.1",
14
14
  "cookie": "^0.5.0",
15
- "devalue": "^2.0.1",
15
+ "devalue": "^3.1.2",
16
16
  "kleur": "^4.1.4",
17
17
  "magic-string": "^0.26.2",
18
18
  "mime": "^3.0.0",
@@ -36,7 +36,6 @@
36
36
  "rollup": "^2.75.7",
37
37
  "svelte": "^3.48.0",
38
38
  "svelte-preprocess": "^4.10.6",
39
- "tiny-glob": "^0.2.9",
40
39
  "typescript": "^4.7.4",
41
40
  "uvu": "^0.5.3",
42
41
  "vite": "^3.0.9"
@@ -51,9 +50,8 @@
51
50
  "files": [
52
51
  "src",
53
52
  "!src/**/*.spec.js",
54
- "!src/packaging/test",
55
53
  "!src/core/**/fixtures",
56
- "!src/core/sync/create_manifest_data/test",
54
+ "!src/core/**/test",
57
55
  "types",
58
56
  "svelte-kit.js"
59
57
  ],
@@ -78,7 +76,7 @@
78
76
  },
79
77
  "types": "types/index.d.ts",
80
78
  "engines": {
81
- "node": ">=16.9"
79
+ "node": ">=16.14"
82
80
  },
83
81
  "scripts": {
84
82
  "build": "npm run types",
@@ -88,7 +86,7 @@
88
86
  "format": "npm run lint -- --write",
89
87
  "test": "npm run test:unit && npm run test:integration",
90
88
  "test:integration": "pnpm run -r --workspace-concurrency 1 --filter=\"./test/**\" test",
91
- "test:unit": "uvu src \"(spec\\.js|test[\\\\/]index\\.js)\" -i packaging",
89
+ "test:unit": "uvu src \"(spec\\.js|test[\\\\/]index\\.js)\"",
92
90
  "types": "node scripts/extract-types.js",
93
91
  "postinstall": "node svelte-kit.js sync"
94
92
  }
@@ -3,3 +3,5 @@
3
3
  export const SVELTE_KIT_ASSETS = '/_svelte_kit_assets';
4
4
 
5
5
  export const GENERATED_COMMENT = '// this file is generated — do not edit it\n';
6
+
7
+ export const DATA_SUFFIX = '/__data.js';
package/src/core/env.js CHANGED
@@ -1,4 +1,4 @@
1
- import { GENERATED_COMMENT } from './constants.js';
1
+ import { GENERATED_COMMENT } from '../constants.js';
2
2
  import { runtime_base } from './utils.js';
3
3
 
4
4
  /**
@@ -1,6 +1,6 @@
1
1
  import path from 'path';
2
2
  import { get_env } from '../../exports/vite/utils.js';
3
- import { GENERATED_COMMENT } from '../constants.js';
3
+ import { GENERATED_COMMENT } from '../../constants.js';
4
4
  import { create_types } from '../env.js';
5
5
  import { write_if_changed } from './utils.js';
6
6
 
@@ -561,11 +561,11 @@ export function tweak_types(content, names) {
561
561
  );
562
562
  } else {
563
563
  // prevent "type X is imported but not used" (isn't silenced by @ts-nocheck) when svelte-check runs
564
- code.append(`;${type};`);
564
+ code.append(`;null as any as ${type};`);
565
565
  }
566
566
  } else {
567
567
  // prevent "type X is imported but not used" (isn't silenced by @ts-nocheck) when svelte-check runs
568
- code.append(`;${type};`);
568
+ code.append(`;null as any as ${type};`);
569
569
  }
570
570
 
571
571
  modified = true;
@@ -8,7 +8,7 @@ import { installPolyfills } from '../../../exports/node/polyfills.js';
8
8
  import { coalesce_to_error } from '../../../utils/error.js';
9
9
  import { posixify } from '../../../utils/filesystem.js';
10
10
  import { load_template } from '../../../core/config/index.js';
11
- import { SVELTE_KIT_ASSETS } from '../../../core/constants.js';
11
+ import { SVELTE_KIT_ASSETS } from '../../../constants.js';
12
12
  import * as sync from '../../../core/sync/sync.js';
13
13
  import { get_mime_lookup, runtime_base, runtime_prefix } from '../../../core/utils.js';
14
14
  import { get_env, prevent_illegal_vite_imports, resolve_entry } from '../utils.js';
@@ -4,7 +4,7 @@ import sirv from 'sirv';
4
4
  import { pathToFileURL } from 'url';
5
5
  import { getRequest, setResponse } from '../../../exports/node/index.js';
6
6
  import { installPolyfills } from '../../../exports/node/polyfills.js';
7
- import { SVELTE_KIT_ASSETS } from '../../../core/constants.js';
7
+ import { SVELTE_KIT_ASSETS } from '../../../constants.js';
8
8
  import { loadEnv } from 'vite';
9
9
 
10
10
  /** @typedef {import('http').IncomingMessage} Req */
@@ -10,6 +10,7 @@ import Root from '__GENERATED__/root.svelte';
10
10
  import { nodes, server_loads, dictionary, matchers } from '__GENERATED__/client-manifest.js';
11
11
  import { HttpError, Redirect } from '../control.js';
12
12
  import { stores } from './singletons.js';
13
+ import { DATA_SUFFIX } from '../../constants.js';
13
14
 
14
15
  const SCROLL_KEY = 'sveltekit:scroll';
15
16
  const INDEX_KEY = 'sveltekit:index';
@@ -393,7 +394,7 @@ export function create_client({ target, base, trailing_slash }) {
393
394
  * status: number;
394
395
  * error: HttpError | Error | null;
395
396
  * routeId: string | null;
396
- * validation_errors?: string | undefined;
397
+ * validation_errors?: Record<string, any> | null;
397
398
  * }} opts
398
399
  */
399
400
  async function get_navigation_result_from_branch({
@@ -715,24 +716,14 @@ export function create_client({ target, base, trailing_slash }) {
715
716
 
716
717
  if (invalid_server_nodes.some(Boolean)) {
717
718
  try {
718
- const res = await native_fetch(
719
- `${url.pathname}${url.pathname.endsWith('/') ? '' : '/'}__data.json${url.search}`,
720
- {
721
- headers: {
722
- 'x-sveltekit-invalidated': invalid_server_nodes.map((x) => (x ? '1' : '')).join(',')
723
- }
724
- }
725
- );
726
-
727
- server_data = /** @type {import('types').ServerData} */ (await res.json());
728
-
729
- if (!res.ok) {
730
- throw server_data;
731
- }
732
- } catch (e) {
733
- // something went catastrophically wrong — bail and defer to the server
734
- native_navigation(url);
735
- return;
719
+ server_data = await load_data(url, invalid_server_nodes);
720
+ } catch (error) {
721
+ return load_root_error_page({
722
+ status: 500,
723
+ error: /** @type {Error} */ (error),
724
+ url,
725
+ routeId: route.id
726
+ });
736
727
  }
737
728
 
738
729
  if (server_data.type === 'redirect') {
@@ -882,19 +873,18 @@ export function create_client({ target, base, trailing_slash }) {
882
873
  if (node.server) {
883
874
  // TODO post-https://github.com/sveltejs/kit/discussions/6124 we can use
884
875
  // existing root layout data
885
- const res = await native_fetch(
886
- `${url.pathname}${url.pathname.endsWith('/') ? '' : '/'}__data.json${url.search}`,
887
- {
888
- headers: {
889
- 'x-sveltekit-invalidated': '1'
890
- }
891
- }
892
- );
876
+ try {
877
+ const server_data = await load_data(url, [true]);
893
878
 
894
- const server_data_nodes = await res.json();
895
- server_data_node = server_data_nodes?.[0] ?? null;
879
+ if (
880
+ server_data.type !== 'data' ||
881
+ (server_data.nodes[0] && server_data.nodes[0].type !== 'data')
882
+ ) {
883
+ throw 0;
884
+ }
896
885
 
897
- if (!res.ok || server_data_nodes?.type !== 'data') {
886
+ server_data_node = server_data.nodes[0] ?? null;
887
+ } catch {
898
888
  // at this point we have no choice but to fall back to the server
899
889
  native_navigation(url);
900
890
 
@@ -1298,32 +1288,24 @@ export function create_client({ target, base, trailing_slash }) {
1298
1288
  });
1299
1289
  },
1300
1290
 
1301
- _hydrate: async ({ status, error, node_ids, params, routeId }) => {
1291
+ _hydrate: async ({
1292
+ status,
1293
+ error: original_error, // TODO get rid of this
1294
+ node_ids,
1295
+ params,
1296
+ routeId,
1297
+ data: server_data_nodes,
1298
+ errors: validation_errors
1299
+ }) => {
1302
1300
  const url = new URL(location.href);
1303
1301
 
1304
1302
  /** @type {import('./types').NavigationFinished | undefined} */
1305
1303
  let result;
1306
1304
 
1307
1305
  try {
1308
- /**
1309
- * @param {string} type
1310
- * @param {any} fallback
1311
- */
1312
- const parse = (type, fallback) => {
1313
- const script = document.querySelector(`script[sveltekit\\:data-type="${type}"]`);
1314
- return script?.textContent ? JSON.parse(script.textContent) : fallback;
1315
- };
1316
- /**
1317
- * @type {Array<import('types').ServerDataNode | null>}
1318
- * On initial navigation, this will only consist of data nodes or `null`.
1319
- * A possible error is passed through the `error` property, in which case
1320
- * the last entry of `node_ids` is an error page and the last entry of
1321
- * `server_data_nodes` is `null`.
1322
- */
1323
- const server_data_nodes = parse('server_data', []);
1324
- const validation_errors = parse('validation_errors', undefined);
1325
-
1326
1306
  const branch_promises = node_ids.map(async (n, i) => {
1307
+ const server_data_node = server_data_nodes[i];
1308
+
1327
1309
  return load_node({
1328
1310
  loader: nodes[n],
1329
1311
  url,
@@ -1336,7 +1318,7 @@ export function create_client({ target, base, trailing_slash }) {
1336
1318
  }
1337
1319
  return data;
1338
1320
  },
1339
- server_data_node: create_data_node(server_data_nodes[i])
1321
+ server_data_node: create_data_node(server_data_node)
1340
1322
  });
1341
1323
  });
1342
1324
 
@@ -1345,13 +1327,15 @@ export function create_client({ target, base, trailing_slash }) {
1345
1327
  params,
1346
1328
  branch: await Promise.all(branch_promises),
1347
1329
  status,
1348
- error: /** @type {import('../server/page/types').SerializedHttpError} */ (error)
1330
+ error: /** @type {import('../server/page/types').SerializedHttpError} */ (original_error)
1349
1331
  ?.__is_http_error
1350
1332
  ? new HttpError(
1351
- /** @type {import('../server/page/types').SerializedHttpError} */ (error).status,
1352
- error.message
1333
+ /** @type {import('../server/page/types').SerializedHttpError} */ (
1334
+ original_error
1335
+ ).status,
1336
+ original_error.message
1353
1337
  )
1354
- : error,
1338
+ : original_error,
1355
1339
  validation_errors,
1356
1340
  routeId
1357
1341
  });
@@ -1377,3 +1361,34 @@ export function create_client({ target, base, trailing_slash }) {
1377
1361
  }
1378
1362
  };
1379
1363
  }
1364
+
1365
+ let data_id = 1;
1366
+
1367
+ /**
1368
+ * @param {URL} url
1369
+ * @param {boolean[]} invalid
1370
+ * @returns {Promise<import('types').ServerData>}
1371
+ */
1372
+ async function load_data(url, invalid) {
1373
+ const data_url = new URL(url);
1374
+ data_url.pathname = url.pathname.replace(/\/$/, '') + DATA_SUFFIX;
1375
+ data_url.searchParams.set('__invalid', invalid.map((x) => (x ? 'y' : 'n')).join(''));
1376
+ data_url.searchParams.set('__id', String(data_id++));
1377
+
1378
+ // The __data.js file is generated by the server and looks like
1379
+ // `window.__sveltekit_data = ${devalue(data)}`. We do this instead
1380
+ // of `export const data` because modules are cached indefinitely,
1381
+ // and that would cause memory leaks.
1382
+ //
1383
+ // The data is read and deleted in the same tick as the promise
1384
+ // resolves, so it's not vulnerable to race conditions
1385
+ await import(/* @vite-ignore */ data_url.href);
1386
+
1387
+ // @ts-expect-error
1388
+ const server_data = window.__sveltekit_data;
1389
+
1390
+ // @ts-expect-error
1391
+ delete window.__sveltekit_data;
1392
+
1393
+ return server_data;
1394
+ }
@@ -20,6 +20,8 @@ export { set_public_env } from '../env-public.js';
20
20
  * node_ids: number[];
21
21
  * params: Record<string, string>;
22
22
  * routeId: string | null;
23
+ * data: Array<import('types').ServerDataNode | null>;
24
+ * errors: Record<string, any> | null;
23
25
  * };
24
26
  * }} opts
25
27
  */
@@ -27,6 +27,8 @@ export interface Client {
27
27
  node_ids: number[];
28
28
  params: Record<string, string>;
29
29
  routeId: string | null;
30
+ data: Array<import('types').ServerDataNode | null>;
31
+ errors: Record<string, any> | null;
30
32
  }) => Promise<void>;
31
33
  _start_router: () => void;
32
34
  }
@@ -0,0 +1,146 @@
1
+ import { HttpError, Redirect } from '../../control.js';
2
+ import { normalize_error } from '../../../utils/error.js';
3
+ import { once } from '../../../utils/functions.js';
4
+ import { load_server_data } from '../page/load_data.js';
5
+ import { data_response, error_to_pojo } from '../utils.js';
6
+ import { normalize_path } from '../../../utils/url.js';
7
+ import { DATA_SUFFIX } from '../../../constants.js';
8
+
9
+ /**
10
+ * @param {import('types').RequestEvent} event
11
+ * @param {import('types').SSRRoute} route
12
+ * @param {import('types').SSROptions} options
13
+ * @param {import('types').SSRState} state
14
+ * @returns {Promise<Response>}
15
+ */
16
+ export async function render_data(event, route, options, state) {
17
+ if (!route.page) {
18
+ // requesting /__data.js should fail for a +server.js
19
+ return new Response(undefined, {
20
+ status: 404
21
+ });
22
+ }
23
+
24
+ try {
25
+ const node_ids = [...route.page.layouts, route.page.leaf];
26
+
27
+ const invalidated =
28
+ event.url.searchParams
29
+ .get('__invalid')
30
+ ?.split('')
31
+ .map((x) => x === 'y') ?? node_ids.map(() => true);
32
+
33
+ let aborted = false;
34
+
35
+ const url = new URL(event.url);
36
+ url.pathname = normalize_path(
37
+ url.pathname.slice(0, -DATA_SUFFIX.length),
38
+ options.trailing_slash
39
+ );
40
+
41
+ url.searchParams.delete('__invalid');
42
+ url.searchParams.delete('__id');
43
+
44
+ const new_event = { ...event, url };
45
+
46
+ const functions = node_ids.map((n, i) => {
47
+ return once(async () => {
48
+ try {
49
+ if (aborted) {
50
+ return /** @type {import('types').ServerDataSkippedNode} */ ({
51
+ type: 'skip'
52
+ });
53
+ }
54
+
55
+ // == because it could be undefined (in dev) or null (in build, because of JSON.stringify)
56
+ const node = n == undefined ? n : await options.manifest._.nodes[n]();
57
+ return load_server_data({
58
+ event: new_event,
59
+ state,
60
+ node,
61
+ parent: async () => {
62
+ /** @type {Record<string, any>} */
63
+ const data = {};
64
+ for (let j = 0; j < i; j += 1) {
65
+ const parent = /** @type {import('types').ServerDataNode | null} */ (
66
+ await functions[j]()
67
+ );
68
+
69
+ if (parent) {
70
+ Object.assign(data, parent.data);
71
+ }
72
+ }
73
+ return data;
74
+ }
75
+ });
76
+ } catch (e) {
77
+ aborted = true;
78
+ throw e;
79
+ }
80
+ });
81
+ });
82
+
83
+ const promises = functions.map(async (fn, i) => {
84
+ if (!invalidated[i]) {
85
+ return /** @type {import('types').ServerDataSkippedNode} */ ({
86
+ type: 'skip'
87
+ });
88
+ }
89
+
90
+ return fn();
91
+ });
92
+
93
+ let length = promises.length;
94
+ const nodes = await Promise.all(
95
+ promises.map((p, i) =>
96
+ p.catch((e) => {
97
+ const error = normalize_error(e);
98
+
99
+ if (error instanceof Redirect) {
100
+ throw error;
101
+ }
102
+
103
+ // Math.min because array isn't guaranteed to resolve in order
104
+ length = Math.min(length, i + 1);
105
+
106
+ if (error instanceof HttpError) {
107
+ return /** @type {import('types').ServerErrorNode} */ ({
108
+ type: 'error',
109
+ httperror: { ...error }
110
+ });
111
+ }
112
+
113
+ options.handle_error(error, event);
114
+
115
+ return /** @type {import('types').ServerErrorNode} */ ({
116
+ type: 'error',
117
+ error: error_to_pojo(error, options.get_stack)
118
+ });
119
+ })
120
+ )
121
+ );
122
+
123
+ /** @type {import('types').ServerData} */
124
+ const server_data = {
125
+ type: 'data',
126
+ nodes: nodes.slice(0, length)
127
+ };
128
+
129
+ return data_response(server_data);
130
+ } catch (e) {
131
+ const error = normalize_error(e);
132
+
133
+ if (error instanceof Redirect) {
134
+ /** @type {import('types').ServerData} */
135
+ const server_data = {
136
+ type: 'redirect',
137
+ location: error.location
138
+ };
139
+
140
+ return data_response(server_data);
141
+ } else {
142
+ // TODO make it clearer that this was an unexpected error
143
+ return data_response(error_to_pojo(error, options.get_stack));
144
+ }
145
+ }
146
+ }
@@ -2,20 +2,16 @@ import { render_endpoint } from './endpoint.js';
2
2
  import { render_page } from './page/index.js';
3
3
  import { render_response } from './page/render.js';
4
4
  import { respond_with_error } from './page/respond_with_error.js';
5
- import { coalesce_to_error, normalize_error } from '../../utils/error.js';
6
- import { serialize_error, GENERIC_ERROR, error_to_pojo } from './utils.js';
5
+ import { coalesce_to_error } from '../../utils/error.js';
6
+ import { serialize_error, GENERIC_ERROR } from './utils.js';
7
7
  import { decode_params, disable_search, normalize_path } from '../../utils/url.js';
8
8
  import { exec } from '../../utils/routing.js';
9
9
  import { negotiate } from '../../utils/http.js';
10
- import { HttpError, Redirect } from '../control.js';
11
- import { load_server_data } from './page/load_data.js';
12
- import { json } from '../../exports/index.js';
13
- import { once } from '../../utils/functions.js';
10
+ import { render_data } from './data/index.js';
11
+ import { DATA_SUFFIX } from '../../constants.js';
14
12
 
15
13
  /* global __SVELTEKIT_ADAPTER_NAME__ */
16
14
 
17
- const DATA_SUFFIX = '/__data.json';
18
-
19
15
  /** @param {{ html: string }} opts */
20
16
  const default_transform = ({ html }) => html;
21
17
 
@@ -69,12 +65,7 @@ export async function respond(request, options, state) {
69
65
  }
70
66
 
71
67
  const is_data_request = decoded.endsWith(DATA_SUFFIX);
72
-
73
- if (is_data_request) {
74
- const data_suffix_length = DATA_SUFFIX.length - (options.trailing_slash === 'always' ? 1 : 0);
75
- decoded = decoded.slice(0, -data_suffix_length) || '/';
76
- url = new URL(url.origin + url.pathname.slice(0, -data_suffix_length) + url.search);
77
- }
68
+ if (is_data_request) decoded = decoded.slice(0, -DATA_SUFFIX.length);
78
69
 
79
70
  if (!state.prerendering?.fallback) {
80
71
  const matchers = await options.manifest._.matchers();
@@ -92,26 +83,19 @@ export async function respond(request, options, state) {
92
83
  }
93
84
  }
94
85
 
95
- if (route) {
96
- if (route.page) {
97
- const normalized = normalize_path(url.pathname, options.trailing_slash);
98
-
99
- if (normalized !== url.pathname && !state.prerendering?.fallback) {
100
- return new Response(undefined, {
101
- status: 301,
102
- headers: {
103
- 'x-sveltekit-normalize': '1',
104
- location:
105
- // ensure paths starting with '//' are not treated as protocol-relative
106
- (normalized.startsWith('//') ? url.origin + normalized : normalized) +
107
- (url.search === '?' ? '' : url.search)
108
- }
109
- });
110
- }
111
- } else if (is_data_request) {
112
- // requesting /__data.json should fail for a standalone endpoint
86
+ if (route?.page && !is_data_request) {
87
+ const normalized = normalize_path(url.pathname, options.trailing_slash);
88
+
89
+ if (normalized !== url.pathname && !state.prerendering?.fallback) {
113
90
  return new Response(undefined, {
114
- status: 404
91
+ status: 301,
92
+ headers: {
93
+ 'x-sveltekit-normalize': '1',
94
+ location:
95
+ // ensure paths starting with '//' are not treated as protocol-relative
96
+ (normalized.startsWith('//') ? url.origin + normalized : normalized) +
97
+ (url.search === '?' ? '' : url.search)
98
+ }
115
99
  });
116
100
  }
117
101
  }
@@ -250,116 +234,9 @@ export async function respond(request, options, state) {
250
234
  if (route) {
251
235
  /** @type {Response} */
252
236
  let response;
253
- if (is_data_request && route.page) {
254
- try {
255
- const node_ids = [...route.page.layouts, route.page.leaf];
256
-
257
- const invalidated =
258
- request.headers.get('x-sveltekit-invalidated')?.split(',').map(Boolean) ??
259
- node_ids.map(() => true);
260
-
261
- let aborted = false;
262
-
263
- const functions = node_ids.map((n, i) => {
264
- return once(async () => {
265
- try {
266
- if (aborted) {
267
- return /** @type {import('types').ServerDataSkippedNode} */ ({
268
- type: 'skip'
269
- });
270
- }
271
-
272
- // == because it could be undefined (in dev) or null (in build, because of JSON.stringify)
273
- const node = n == undefined ? n : await options.manifest._.nodes[n]();
274
- return load_server_data({
275
- dev: options.dev,
276
- event,
277
- state,
278
- node,
279
- parent: async () => {
280
- /** @type {Record<string, any>} */
281
- const data = {};
282
- for (let j = 0; j < i; j += 1) {
283
- const parent = /** @type {import('types').ServerDataNode | null} */ (
284
- await functions[j]()
285
- );
286
-
287
- if (parent) {
288
- Object.assign(data, parent.data);
289
- }
290
- }
291
- return data;
292
- }
293
- });
294
- } catch (e) {
295
- aborted = true;
296
- throw e;
297
- }
298
- });
299
- });
300
237
 
301
- const promises = functions.map(async (fn, i) => {
302
- if (!invalidated[i]) {
303
- return /** @type {import('types').ServerDataSkippedNode} */ ({
304
- type: 'skip'
305
- });
306
- }
307
-
308
- return fn();
309
- });
310
-
311
- let length = promises.length;
312
- const nodes = await Promise.all(
313
- promises.map((p, i) =>
314
- p.catch((e) => {
315
- const error = normalize_error(e);
316
-
317
- if (error instanceof Redirect) {
318
- throw error;
319
- }
320
-
321
- // Math.min because array isn't guaranteed to resolve in order
322
- length = Math.min(length, i + 1);
323
-
324
- if (error instanceof HttpError) {
325
- return /** @type {import('types').ServerErrorNode} */ ({
326
- type: 'error',
327
- httperror: { ...error }
328
- });
329
- }
330
-
331
- options.handle_error(error, event);
332
-
333
- return /** @type {import('types').ServerErrorNode} */ ({
334
- type: 'error',
335
- error: error_to_pojo(error, options.get_stack)
336
- });
337
- })
338
- )
339
- );
340
-
341
- /** @type {import('types').ServerData} */
342
- const server_data = {
343
- type: 'data',
344
- nodes: nodes.slice(0, length)
345
- };
346
-
347
- response = json(server_data);
348
- } catch (e) {
349
- const error = normalize_error(e);
350
-
351
- if (error instanceof Redirect) {
352
- /** @type {import('types').ServerData} */
353
- const server_data = {
354
- type: 'redirect',
355
- location: error.location
356
- };
357
-
358
- response = json(server_data);
359
- } else {
360
- response = json(error_to_pojo(error, options.get_stack), { status: 500 });
361
- }
362
- }
238
+ if (is_data_request) {
239
+ response = await render_data(event, route, options, state);
363
240
  } else if (route.page) {
364
241
  response = await render_page(event, route, route.page, options, state, resolve_opts);
365
242
  } else if (route.endpoint) {
@@ -371,7 +248,7 @@ export async function respond(request, options, state) {
371
248
  }
372
249
 
373
250
  if (!is_data_request) {
374
- // we only want to set cookies on __data.json requests, we don't
251
+ // we only want to set cookies on __data.js requests, we don't
375
252
  // want to cache stuff erroneously etc
376
253
  for (const key in headers) {
377
254
  const value = headers[key];