@sveltejs/kit 1.0.0-next.47 → 1.0.0-next.472

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 (117) hide show
  1. package/README.md +12 -9
  2. package/package.json +93 -64
  3. package/scripts/special-types/$env+dynamic+private.md +8 -0
  4. package/scripts/special-types/$env+dynamic+public.md +8 -0
  5. package/scripts/special-types/$env+static+private.md +19 -0
  6. package/scripts/special-types/$env+static+public.md +7 -0
  7. package/scripts/special-types/$lib.md +1 -0
  8. package/src/cli.js +112 -0
  9. package/src/constants.js +7 -0
  10. package/src/core/adapt/builder.js +207 -0
  11. package/src/core/adapt/index.js +31 -0
  12. package/src/core/config/default-error.html +56 -0
  13. package/src/core/config/index.js +105 -0
  14. package/src/core/config/options.js +492 -0
  15. package/src/core/config/types.d.ts +1 -0
  16. package/src/core/env.js +121 -0
  17. package/src/core/generate_manifest/index.js +92 -0
  18. package/src/core/prerender/crawl.js +194 -0
  19. package/src/core/prerender/prerender.js +431 -0
  20. package/src/core/prerender/queue.js +80 -0
  21. package/src/core/sync/create_manifest_data/index.js +472 -0
  22. package/src/core/sync/create_manifest_data/types.d.ts +37 -0
  23. package/src/core/sync/sync.js +59 -0
  24. package/src/core/sync/utils.js +33 -0
  25. package/src/core/sync/write_ambient.js +53 -0
  26. package/src/core/sync/write_client_manifest.js +94 -0
  27. package/src/core/sync/write_matchers.js +25 -0
  28. package/src/core/sync/write_root.js +91 -0
  29. package/src/core/sync/write_tsconfig.js +195 -0
  30. package/src/core/sync/write_types/index.js +673 -0
  31. package/src/core/utils.js +70 -0
  32. package/src/exports/hooks/index.js +1 -0
  33. package/src/exports/hooks/sequence.js +44 -0
  34. package/src/exports/index.js +54 -0
  35. package/src/exports/node/index.js +145 -0
  36. package/src/exports/node/polyfills.js +41 -0
  37. package/src/exports/vite/build/build_server.js +357 -0
  38. package/src/exports/vite/build/build_service_worker.js +90 -0
  39. package/src/exports/vite/build/utils.js +162 -0
  40. package/src/exports/vite/dev/index.js +554 -0
  41. package/src/exports/vite/index.js +591 -0
  42. package/src/exports/vite/preview/index.js +186 -0
  43. package/src/exports/vite/types.d.ts +3 -0
  44. package/src/exports/vite/utils.js +361 -0
  45. package/src/runtime/app/env.js +1 -0
  46. package/src/runtime/app/environment.js +11 -0
  47. package/src/runtime/app/forms.js +65 -0
  48. package/src/runtime/app/navigation.js +23 -0
  49. package/src/runtime/app/paths.js +1 -0
  50. package/src/runtime/app/stores.js +102 -0
  51. package/src/runtime/client/ambient.d.ts +24 -0
  52. package/src/runtime/client/client.js +1558 -0
  53. package/src/runtime/client/fetcher.js +107 -0
  54. package/src/runtime/client/parse.js +60 -0
  55. package/src/runtime/client/singletons.js +21 -0
  56. package/src/runtime/client/start.js +37 -0
  57. package/src/runtime/client/types.d.ts +87 -0
  58. package/src/runtime/client/utils.js +159 -0
  59. package/src/runtime/components/error.svelte +16 -0
  60. package/{assets → src/runtime}/components/layout.svelte +0 -0
  61. package/src/runtime/control.js +100 -0
  62. package/src/runtime/env/dynamic/private.js +1 -0
  63. package/src/runtime/env/dynamic/public.js +1 -0
  64. package/src/runtime/env-private.js +6 -0
  65. package/src/runtime/env-public.js +6 -0
  66. package/src/runtime/env.js +6 -0
  67. package/src/runtime/hash.js +16 -0
  68. package/src/runtime/paths.js +11 -0
  69. package/src/runtime/server/cookie.js +76 -0
  70. package/src/runtime/server/data/index.js +146 -0
  71. package/src/runtime/server/endpoint.js +66 -0
  72. package/src/runtime/server/index.js +339 -0
  73. package/src/runtime/server/page/actions.js +225 -0
  74. package/src/runtime/server/page/crypto.js +239 -0
  75. package/src/runtime/server/page/csp.js +249 -0
  76. package/src/runtime/server/page/fetch.js +286 -0
  77. package/src/runtime/server/page/index.js +308 -0
  78. package/src/runtime/server/page/load_data.js +124 -0
  79. package/src/runtime/server/page/render.js +359 -0
  80. package/src/runtime/server/page/respond_with_error.js +92 -0
  81. package/src/runtime/server/page/serialize_data.js +87 -0
  82. package/src/runtime/server/page/types.d.ts +41 -0
  83. package/src/runtime/server/utils.js +220 -0
  84. package/src/utils/array.js +9 -0
  85. package/src/utils/error.js +22 -0
  86. package/src/utils/escape.js +46 -0
  87. package/src/utils/filesystem.js +108 -0
  88. package/src/utils/functions.js +16 -0
  89. package/src/utils/http.js +55 -0
  90. package/src/utils/misc.js +1 -0
  91. package/src/utils/routing.js +117 -0
  92. package/src/utils/url.js +142 -0
  93. package/svelte-kit.js +1 -1
  94. package/types/ambient.d.ts +404 -0
  95. package/types/index.d.ts +396 -0
  96. package/types/internal.d.ts +377 -0
  97. package/types/private.d.ts +210 -0
  98. package/CHANGELOG.md +0 -463
  99. package/assets/components/error.svelte +0 -13
  100. package/assets/runtime/app/env.js +0 -5
  101. package/assets/runtime/app/navigation.js +0 -44
  102. package/assets/runtime/app/paths.js +0 -1
  103. package/assets/runtime/app/stores.js +0 -93
  104. package/assets/runtime/chunks/utils.js +0 -22
  105. package/assets/runtime/internal/singletons.js +0 -23
  106. package/assets/runtime/internal/start.js +0 -773
  107. package/assets/runtime/paths.js +0 -12
  108. package/dist/chunks/index.js +0 -3517
  109. package/dist/chunks/index2.js +0 -587
  110. package/dist/chunks/index3.js +0 -246
  111. package/dist/chunks/index4.js +0 -530
  112. package/dist/chunks/index5.js +0 -763
  113. package/dist/chunks/index6.js +0 -322
  114. package/dist/chunks/standard.js +0 -99
  115. package/dist/chunks/utils.js +0 -83
  116. package/dist/cli.js +0 -553
  117. package/dist/ssr.js +0 -2581
@@ -0,0 +1,286 @@
1
+ import * as cookie from 'cookie';
2
+ import * as set_cookie_parser from 'set-cookie-parser';
3
+ import { respond } from '../index.js';
4
+ import { domain_matches, path_matches } from '../cookie.js';
5
+
6
+ /**
7
+ * @param {{
8
+ * event: import('types').RequestEvent;
9
+ * options: import('types').SSROptions;
10
+ * state: import('types').SSRState;
11
+ * route: import('types').SSRRoute | import('types').SSRErrorPage;
12
+ * prerender_default?: import('types').PrerenderOption;
13
+ * resolve_opts: import('types').RequiredResolveOptions;
14
+ * }} opts
15
+ */
16
+ export function create_fetch({ event, options, state, route, prerender_default, resolve_opts }) {
17
+ /** @type {import('./types').Fetched[]} */
18
+ const fetched = [];
19
+
20
+ const initial_cookies = cookie.parse(event.request.headers.get('cookie') || '');
21
+
22
+ /** @type {import('set-cookie-parser').Cookie[]} */
23
+ const set_cookies = [];
24
+
25
+ /**
26
+ * @param {URL} url
27
+ * @param {string | null} header
28
+ */
29
+ function get_cookie_header(url, header) {
30
+ /** @type {Record<string, string>} */
31
+ const new_cookies = {};
32
+
33
+ for (const cookie of set_cookies) {
34
+ if (!domain_matches(url.hostname, cookie.domain)) continue;
35
+ if (!path_matches(url.pathname, cookie.path)) continue;
36
+
37
+ new_cookies[cookie.name] = cookie.value;
38
+ }
39
+
40
+ // cookies from explicit `cookie` header take precedence over cookies previously set
41
+ // during this load with `set-cookie`, which take precedence over the cookies
42
+ // sent by the user agent
43
+ const combined_cookies = {
44
+ ...initial_cookies,
45
+ ...new_cookies,
46
+ ...cookie.parse(header ?? '')
47
+ };
48
+
49
+ return Object.entries(combined_cookies)
50
+ .map(([name, value]) => `${name}=${value}`)
51
+ .join('; ');
52
+ }
53
+
54
+ /** @type {typeof fetch} */
55
+ const fetcher = async (info, init) => {
56
+ const request = normalize_fetch_input(info, init, event.url);
57
+
58
+ const request_body = init?.body;
59
+
60
+ /** @type {import('types').PrerenderDependency} */
61
+ let dependency;
62
+
63
+ const response = await options.hooks.handleFetch({
64
+ event,
65
+ request,
66
+ fetch: async (info, init) => {
67
+ const request = normalize_fetch_input(info, init, event.url);
68
+
69
+ const url = new URL(request.url);
70
+
71
+ if (url.origin !== event.url.origin) {
72
+ // allow cookie passthrough for "same-origin"
73
+ // if SvelteKit is serving my.domain.com:
74
+ // - domain.com WILL NOT receive cookies
75
+ // - my.domain.com WILL receive cookies
76
+ // - api.domain.dom WILL NOT receive cookies
77
+ // - sub.my.domain.com WILL receive cookies
78
+ // ports do not affect the resolution
79
+ // leading dot prevents mydomain.com matching domain.com
80
+ if (
81
+ `.${url.hostname}`.endsWith(`.${event.url.hostname}`) &&
82
+ request.credentials !== 'omit'
83
+ ) {
84
+ const cookie = get_cookie_header(url, request.headers.get('cookie'));
85
+ if (cookie) request.headers.set('cookie', cookie);
86
+ }
87
+
88
+ let response = await fetch(request);
89
+
90
+ if (request.mode === 'no-cors') {
91
+ response = new Response('', {
92
+ status: response.status,
93
+ statusText: response.statusText,
94
+ headers: response.headers
95
+ });
96
+ } else {
97
+ if (url.origin !== event.url.origin) {
98
+ const acao = response.headers.get('access-control-allow-origin');
99
+ if (!acao || (acao !== event.url.origin && acao !== '*')) {
100
+ throw new Error(
101
+ `CORS error: ${
102
+ acao ? 'Incorrect' : 'No'
103
+ } 'Access-Control-Allow-Origin' header is present on the requested resource`
104
+ );
105
+ }
106
+ }
107
+ }
108
+
109
+ return response;
110
+ }
111
+
112
+ /** @type {Response} */
113
+ let response;
114
+
115
+ // handle fetch requests for static assets. e.g. prebaked data, etc.
116
+ // we need to support everything the browser's fetch supports
117
+ const prefix = options.paths.assets || options.paths.base;
118
+ const decoded = decodeURIComponent(url.pathname);
119
+ const filename = (
120
+ decoded.startsWith(prefix) ? decoded.slice(prefix.length) : decoded
121
+ ).slice(1);
122
+ const filename_html = `${filename}/index.html`; // path may also match path/index.html
123
+
124
+ const is_asset = options.manifest.assets.has(filename);
125
+ const is_asset_html = options.manifest.assets.has(filename_html);
126
+
127
+ if (is_asset || is_asset_html) {
128
+ const file = is_asset ? filename : filename_html;
129
+
130
+ if (options.read) {
131
+ const type = is_asset
132
+ ? options.manifest.mimeTypes[filename.slice(filename.lastIndexOf('.'))]
133
+ : 'text/html';
134
+
135
+ return new Response(options.read(file), {
136
+ headers: type ? { 'content-type': type } : {}
137
+ });
138
+ }
139
+
140
+ return await fetch(request);
141
+ }
142
+
143
+ if (request.credentials !== 'omit') {
144
+ const cookie = get_cookie_header(url, request.headers.get('cookie'));
145
+ if (cookie) {
146
+ request.headers.set('cookie', cookie);
147
+ }
148
+
149
+ const authorization = event.request.headers.get('authorization');
150
+ if (authorization && !request.headers.has('authorization')) {
151
+ request.headers.set('authorization', authorization);
152
+ }
153
+ }
154
+
155
+ if (request_body && typeof request_body !== 'string') {
156
+ // TODO is this still necessary? we just bail out below
157
+ // per https://developer.mozilla.org/en-US/docs/Web/API/Request/Request, this can be a
158
+ // Blob, BufferSource, FormData, URLSearchParams, USVString, or ReadableStream object.
159
+ // non-string bodies are irksome to deal with, but luckily aren't particularly useful
160
+ // in this context anyway, so we take the easy route and ban them
161
+ throw new Error('Request body must be a string');
162
+ }
163
+
164
+ response = await respond(request, options, {
165
+ prerender_default,
166
+ ...state,
167
+ initiator: route
168
+ });
169
+
170
+ if (state.prerendering) {
171
+ dependency = { response, body: null };
172
+ state.prerendering.dependencies.set(url.pathname, dependency);
173
+ }
174
+
175
+ return response;
176
+ }
177
+ });
178
+
179
+ const set_cookie = response.headers.get('set-cookie');
180
+ if (set_cookie) {
181
+ set_cookies.push(
182
+ ...set_cookie_parser
183
+ .splitCookiesString(set_cookie)
184
+ .map((str) => set_cookie_parser.parseString(str))
185
+ );
186
+ }
187
+
188
+ const proxy = new Proxy(response, {
189
+ get(response, key, _receiver) {
190
+ async function text() {
191
+ const body = await response.text();
192
+
193
+ if (!body || typeof body === 'string') {
194
+ const status_number = Number(response.status);
195
+ if (isNaN(status_number)) {
196
+ throw new Error(
197
+ `response.status is not a number. value: "${
198
+ response.status
199
+ }" type: ${typeof response.status}`
200
+ );
201
+ }
202
+
203
+ fetched.push({
204
+ url: request.url.startsWith(event.url.origin)
205
+ ? request.url.slice(event.url.origin.length)
206
+ : request.url,
207
+ method: request.method,
208
+ request_body: /** @type {string | undefined} */ (request_body),
209
+ response_body: body,
210
+ response: response
211
+ });
212
+
213
+ // ensure that excluded headers can't be read
214
+ const get = response.headers.get;
215
+ response.headers.get = (key) => {
216
+ const lower = key.toLowerCase();
217
+ const value = get.call(response.headers, lower);
218
+ if (value && !lower.startsWith('x-sveltekit-')) {
219
+ const included = resolve_opts.filterSerializedResponseHeaders(lower, value);
220
+ if (!included) {
221
+ throw new Error(
222
+ `Failed to get response header "${lower}" — it must be included by the \`filterSerializedResponseHeaders\` option: https://kit.svelte.dev/docs/hooks#handle`
223
+ );
224
+ }
225
+ }
226
+
227
+ return value;
228
+ };
229
+ }
230
+
231
+ if (dependency) {
232
+ dependency.body = body;
233
+ }
234
+
235
+ return body;
236
+ }
237
+
238
+ if (key === 'arrayBuffer') {
239
+ return async () => {
240
+ const buffer = await response.arrayBuffer();
241
+
242
+ if (dependency) {
243
+ dependency.body = new Uint8Array(buffer);
244
+ }
245
+
246
+ // TODO should buffer be inlined into the page (albeit base64'd)?
247
+ // any conditions in which it shouldn't be?
248
+
249
+ return buffer;
250
+ };
251
+ }
252
+
253
+ if (key === 'text') {
254
+ return text;
255
+ }
256
+
257
+ if (key === 'json') {
258
+ return async () => {
259
+ return JSON.parse(await text());
260
+ };
261
+ }
262
+
263
+ // TODO arrayBuffer?
264
+
265
+ return Reflect.get(response, key, response);
266
+ }
267
+ });
268
+
269
+ return proxy;
270
+ };
271
+
272
+ return { fetcher, fetched, cookies: set_cookies };
273
+ }
274
+
275
+ /**
276
+ * @param {RequestInfo | URL} info
277
+ * @param {RequestInit | undefined} init
278
+ * @param {URL} url
279
+ */
280
+ function normalize_fetch_input(info, init, url) {
281
+ if (info instanceof Request) {
282
+ return info;
283
+ }
284
+
285
+ return new Request(typeof info === 'string' ? new URL(info, url) : info, init);
286
+ }
@@ -0,0 +1,308 @@
1
+ import { devalue } from 'devalue';
2
+ import { DATA_SUFFIX } from '../../../constants.js';
3
+ import { compact } from '../../../utils/array.js';
4
+ import { normalize_error } from '../../../utils/error.js';
5
+ import { HttpError, Redirect } from '../../control.js';
6
+ import { get_option, redirect_response, static_error_page } from '../utils.js';
7
+ import {
8
+ handle_action_json_request,
9
+ handle_action_request,
10
+ is_action_json_request,
11
+ is_action_request
12
+ } from './actions.js';
13
+ import { create_fetch } from './fetch.js';
14
+ import { load_data, load_server_data } from './load_data.js';
15
+ import { render_response } from './render.js';
16
+ import { respond_with_error } from './respond_with_error.js';
17
+
18
+ /**
19
+ * @param {import('types').RequestEvent} event
20
+ * @param {import('types').SSRRoute} route
21
+ * @param {import('types').PageNodeIndexes} page
22
+ * @param {import('types').SSROptions} options
23
+ * @param {import('types').SSRState} state
24
+ * @param {import('types').RequiredResolveOptions} resolve_opts
25
+ * @returns {Promise<Response>}
26
+ */
27
+ export async function render_page(event, route, page, options, state, resolve_opts) {
28
+ if (state.initiator === route) {
29
+ // infinite request cycle detected
30
+ return new Response(`Not found: ${event.url.pathname}`, {
31
+ status: 404
32
+ });
33
+ }
34
+
35
+ if (is_action_json_request(event)) {
36
+ const node = await options.manifest._.nodes[page.leaf]();
37
+ if (node.server) {
38
+ return handle_action_json_request(event, options, node.server);
39
+ }
40
+ }
41
+
42
+ try {
43
+ const nodes = await Promise.all([
44
+ // we use == here rather than === because [undefined] serializes as "[null]"
45
+ ...page.layouts.map((n) => (n == undefined ? n : options.manifest._.nodes[n]())),
46
+ options.manifest._.nodes[page.leaf]()
47
+ ]);
48
+
49
+ const leaf_node = /** @type {import('types').SSRNode} */ (nodes.at(-1));
50
+
51
+ let status = 200;
52
+
53
+ /** @type {import('types').ActionResult | undefined} */
54
+ let action_result = undefined;
55
+
56
+ if (is_action_request(event, leaf_node)) {
57
+ // for action requests, first call handler in +page.server.js
58
+ // (this also determines status code)
59
+ action_result = await handle_action_request(event, leaf_node.server);
60
+ if (action_result?.type === 'redirect') {
61
+ return redirect_response(303, action_result.location);
62
+ }
63
+ if (action_result?.type === 'error') {
64
+ const error = action_result.error;
65
+ status = error instanceof HttpError ? error.status : 500;
66
+ }
67
+ if (action_result?.type === 'invalid') {
68
+ status = action_result.status;
69
+ }
70
+ }
71
+
72
+ const should_prerender_data = nodes.some((node) => node?.server);
73
+ const data_pathname = event.url.pathname.replace(/\/$/, '') + DATA_SUFFIX;
74
+
75
+ // it's crucial that we do this before returning the non-SSR response, otherwise
76
+ // SvelteKit will erroneously believe that the path has been prerendered,
77
+ // causing functions to be omitted from the manifesst generated later
78
+ const should_prerender = get_option(nodes, 'prerender') ?? false;
79
+ if (should_prerender) {
80
+ const mod = leaf_node.server;
81
+ if (mod && mod.actions) {
82
+ throw new Error('Cannot prerender pages with actions');
83
+ }
84
+ } else if (state.prerendering) {
85
+ // if the page isn't marked as prerenderable, then bail out at this point
86
+ return new Response(undefined, {
87
+ status: 204
88
+ });
89
+ }
90
+
91
+ const { fetcher, fetched, cookies } = create_fetch({
92
+ event,
93
+ options,
94
+ state,
95
+ route,
96
+ prerender_default: should_prerender,
97
+ resolve_opts
98
+ });
99
+
100
+ if (get_option(nodes, 'ssr') === false) {
101
+ return await render_response({
102
+ branch: [],
103
+ fetched,
104
+ cookies,
105
+ page_config: {
106
+ ssr: false,
107
+ csr: get_option(nodes, 'csr') ?? true
108
+ },
109
+ status,
110
+ error: null,
111
+ event,
112
+ options,
113
+ state,
114
+ resolve_opts
115
+ });
116
+ }
117
+
118
+ /** @type {Array<import('./types.js').Loaded | null>} */
119
+ let branch = [];
120
+
121
+ /** @type {Error | null} */
122
+ let load_error = null;
123
+
124
+ /** @type {Array<Promise<import('types').ServerDataNode | null>>} */
125
+ const server_promises = nodes.map((node, i) => {
126
+ if (load_error) {
127
+ // if an error happens immediately, don't bother with the rest of the nodes
128
+ throw load_error;
129
+ }
130
+
131
+ return Promise.resolve().then(async () => {
132
+ try {
133
+ if (node === leaf_node && action_result?.type === 'error') {
134
+ // we wait until here to throw the error so that we can use
135
+ // any nested +error.svelte components that were defined
136
+ throw action_result.error;
137
+ }
138
+
139
+ return await load_server_data({
140
+ event,
141
+ state,
142
+ node,
143
+ parent: async () => {
144
+ /** @type {Record<string, any>} */
145
+ const data = {};
146
+ for (let j = 0; j < i; j += 1) {
147
+ const parent = await server_promises[j];
148
+ if (parent) Object.assign(data, await parent.data);
149
+ }
150
+ return data;
151
+ }
152
+ });
153
+ } catch (e) {
154
+ load_error = /** @type {Error} */ (e);
155
+ throw load_error;
156
+ }
157
+ });
158
+ });
159
+
160
+ /** @type {Array<Promise<Record<string, any> | null>>} */
161
+ const load_promises = nodes.map((node, i) => {
162
+ if (load_error) throw load_error;
163
+ return Promise.resolve().then(async () => {
164
+ try {
165
+ return await load_data({
166
+ event,
167
+ fetcher,
168
+ node,
169
+ parent: async () => {
170
+ const data = {};
171
+ for (let j = 0; j < i; j += 1) {
172
+ Object.assign(data, await load_promises[j]);
173
+ }
174
+ return data;
175
+ },
176
+ server_data_promise: server_promises[i],
177
+ state
178
+ });
179
+ } catch (e) {
180
+ load_error = /** @type {Error} */ (e);
181
+ throw load_error;
182
+ }
183
+ });
184
+ });
185
+
186
+ // if we don't do this, rejections will be unhandled
187
+ for (const p of server_promises) p.catch(() => {});
188
+ for (const p of load_promises) p.catch(() => {});
189
+
190
+ for (let i = 0; i < nodes.length; i += 1) {
191
+ const node = nodes[i];
192
+
193
+ if (node) {
194
+ try {
195
+ const server_data = await server_promises[i];
196
+ const data = await load_promises[i];
197
+
198
+ branch.push({ node, server_data, data });
199
+ } catch (e) {
200
+ const error = normalize_error(e);
201
+
202
+ if (error instanceof Redirect) {
203
+ if (state.prerendering && should_prerender_data) {
204
+ const body = `window.__sveltekit_data = ${JSON.stringify({
205
+ type: 'redirect',
206
+ location: error.location
207
+ })}`;
208
+
209
+ state.prerendering.dependencies.set(data_pathname, {
210
+ response: new Response(body),
211
+ body
212
+ });
213
+ }
214
+
215
+ return redirect_response(error.status, error.location);
216
+ }
217
+
218
+ if (!(error instanceof HttpError)) {
219
+ options.handle_error(/** @type {Error} */ (error), event);
220
+ }
221
+
222
+ const status = error instanceof HttpError ? error.status : 500;
223
+
224
+ while (i--) {
225
+ if (page.errors[i]) {
226
+ const index = /** @type {number} */ (page.errors[i]);
227
+ const node = await options.manifest._.nodes[index]();
228
+
229
+ let j = i;
230
+ while (!branch[j]) j -= 1;
231
+
232
+ return await render_response({
233
+ event,
234
+ options,
235
+ state,
236
+ resolve_opts,
237
+ page_config: { ssr: true, csr: true },
238
+ status,
239
+ error,
240
+ branch: compact(branch.slice(0, j + 1)).concat({
241
+ node,
242
+ data: null,
243
+ server_data: null
244
+ }),
245
+ fetched,
246
+ cookies
247
+ });
248
+ }
249
+ }
250
+
251
+ // if we're still here, it means the error happened in the root layout,
252
+ // which means we have to fall back to error.html
253
+ return static_error_page(
254
+ options,
255
+ status,
256
+ /** @type {HttpError | Error} */ (error).message
257
+ );
258
+ }
259
+ } else {
260
+ // push an empty slot so we can rewind past gaps to the
261
+ // layout that corresponds with an +error.svelte page
262
+ branch.push(null);
263
+ }
264
+ }
265
+
266
+ if (state.prerendering && should_prerender_data) {
267
+ const body = `window.__sveltekit_data = ${devalue({
268
+ type: 'data',
269
+ nodes: branch.map((branch_node) => branch_node?.server_data)
270
+ })}`;
271
+
272
+ state.prerendering.dependencies.set(data_pathname, {
273
+ response: new Response(body),
274
+ body
275
+ });
276
+ }
277
+
278
+ return await render_response({
279
+ event,
280
+ options,
281
+ state,
282
+ resolve_opts,
283
+ page_config: {
284
+ csr: get_option(nodes, 'csr') ?? true,
285
+ ssr: true
286
+ },
287
+ status,
288
+ error: null,
289
+ branch: compact(branch),
290
+ action_result,
291
+ fetched,
292
+ cookies
293
+ });
294
+ } catch (error) {
295
+ // if we end up here, it means the data loaded successfull
296
+ // but the page failed to render, or that a prerendering error occurred
297
+ options.handle_error(/** @type {Error} */ (error), event);
298
+
299
+ return await respond_with_error({
300
+ event,
301
+ options,
302
+ state,
303
+ status: 500,
304
+ error: /** @type {Error} */ (error),
305
+ resolve_opts
306
+ });
307
+ }
308
+ }
@@ -0,0 +1,124 @@
1
+ import { disable_search, make_trackable } from '../../../utils/url.js';
2
+
3
+ /**
4
+ * Calls the user's `load` function.
5
+ * @param {{
6
+ * event: import('types').RequestEvent;
7
+ * state: import('types').SSRState;
8
+ * node: import('types').SSRNode | undefined;
9
+ * parent: () => Promise<Record<string, any>>;
10
+ * }} opts
11
+ * @returns {Promise<import('types').ServerDataNode | null>}
12
+ */
13
+ export async function load_server_data({ event, state, node, parent }) {
14
+ if (!node?.server) return null;
15
+
16
+ const uses = {
17
+ dependencies: new Set(),
18
+ params: new Set(),
19
+ parent: false,
20
+ url: false
21
+ };
22
+
23
+ const url = make_trackable(event.url, () => {
24
+ uses.url = true;
25
+ });
26
+
27
+ if (state.prerendering) {
28
+ disable_search(url);
29
+ }
30
+
31
+ const result = await node.server.load?.call(null, {
32
+ ...event,
33
+ /** @param {string[]} deps */
34
+ depends: (...deps) => {
35
+ for (const dep of deps) {
36
+ const { href } = new URL(dep, event.url);
37
+ uses.dependencies.add(href);
38
+ }
39
+ },
40
+ params: new Proxy(event.params, {
41
+ get: (target, key) => {
42
+ uses.params.add(key);
43
+ return target[/** @type {string} */ (key)];
44
+ }
45
+ }),
46
+ parent: async () => {
47
+ uses.parent = true;
48
+ return parent();
49
+ },
50
+ url
51
+ });
52
+
53
+ const data = result ? await unwrap_promises(result) : null;
54
+
55
+ return {
56
+ type: 'data',
57
+ data,
58
+ uses: {
59
+ dependencies: uses.dependencies.size > 0 ? Array.from(uses.dependencies) : undefined,
60
+ params: uses.params.size > 0 ? Array.from(uses.params) : undefined,
61
+ parent: uses.parent ? 1 : undefined,
62
+ url: uses.url ? 1 : undefined
63
+ }
64
+ };
65
+ }
66
+
67
+ /**
68
+ * Calls the user's `load` function.
69
+ * @param {{
70
+ * event: import('types').RequestEvent;
71
+ * fetcher: typeof fetch;
72
+ * node: import('types').SSRNode | undefined;
73
+ * parent: () => Promise<Record<string, any>>;
74
+ * server_data_promise: Promise<import('types').ServerDataNode | null>;
75
+ * state: import('types').SSRState;
76
+ * }} opts
77
+ * @returns {Promise<Record<string, any> | null>}
78
+ */
79
+ export async function load_data({ event, fetcher, node, parent, server_data_promise }) {
80
+ const server_data_node = await server_data_promise;
81
+
82
+ if (!node?.shared?.load) {
83
+ return server_data_node?.data ?? null;
84
+ }
85
+
86
+ const load_event = {
87
+ url: event.url,
88
+ params: event.params,
89
+ data: server_data_node?.data ?? null,
90
+ routeId: event.routeId,
91
+ fetch: fetcher,
92
+ setHeaders: event.setHeaders,
93
+ depends: () => {},
94
+ parent
95
+ };
96
+
97
+ // TODO remove this for 1.0
98
+ Object.defineProperties(load_event, {
99
+ session: {
100
+ get() {
101
+ throw new Error(
102
+ 'session is no longer available. See https://github.com/sveltejs/kit/discussions/5883'
103
+ );
104
+ },
105
+ enumerable: false
106
+ }
107
+ });
108
+
109
+ const data = await node.shared.load.call(null, load_event);
110
+
111
+ return data ? unwrap_promises(data) : null;
112
+ }
113
+
114
+ /** @param {Record<string, any>} object */
115
+ async function unwrap_promises(object) {
116
+ /** @type {Record<string, any>} */
117
+ const unwrapped = {};
118
+
119
+ for (const key in object) {
120
+ unwrapped[key] = await object[key];
121
+ }
122
+
123
+ return unwrapped;
124
+ }