@sveltejs/kit 3.0.0-next.1 → 3.0.0-next.11

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 (144) hide show
  1. package/package.json +33 -21
  2. package/src/constants.js +2 -0
  3. package/src/core/adapt/builder.js +32 -49
  4. package/src/core/adapt/index.js +1 -4
  5. package/src/core/config/index.js +137 -71
  6. package/src/core/config/options.js +236 -244
  7. package/src/core/config/types.d.ts +1 -1
  8. package/src/core/env.js +121 -5
  9. package/src/core/generate_manifest/index.js +12 -15
  10. package/src/core/postbuild/analyse.js +7 -19
  11. package/src/core/postbuild/crawl.js +22 -6
  12. package/src/core/postbuild/fallback.js +2 -1
  13. package/src/core/postbuild/prerender.js +114 -48
  14. package/src/core/postbuild/queue.js +2 -1
  15. package/src/core/sync/create_manifest_data/index.js +53 -50
  16. package/src/core/sync/sync.js +0 -2
  17. package/src/core/sync/write_client_manifest.js +8 -15
  18. package/src/core/sync/write_env.js +2 -1
  19. package/src/core/sync/write_non_ambient.js +12 -9
  20. package/src/core/sync/write_server.js +14 -15
  21. package/src/core/sync/write_tsconfig.js +16 -8
  22. package/src/core/sync/write_tsconfig_test/package.json +7 -0
  23. package/src/core/sync/write_types/index.js +28 -24
  24. package/src/core/utils.js +30 -5
  25. package/src/exports/env/index.js +77 -0
  26. package/src/exports/hooks/index.js +3 -9
  27. package/src/exports/hooks/sequence.js +3 -2
  28. package/src/exports/index.js +35 -13
  29. package/src/exports/internal/client.js +5 -0
  30. package/src/exports/internal/env.js +8 -5
  31. package/src/exports/internal/index.js +1 -90
  32. package/src/exports/internal/{event.js → server/event.js} +1 -2
  33. package/src/exports/internal/server/index.js +33 -0
  34. package/src/exports/internal/shared.js +89 -0
  35. package/src/exports/node/index.js +62 -15
  36. package/src/exports/params.js +68 -0
  37. package/src/exports/public.d.ts +363 -189
  38. package/src/exports/url.js +86 -0
  39. package/src/exports/vite/build/build_server.js +53 -59
  40. package/src/exports/vite/build/remote.js +18 -11
  41. package/src/exports/vite/build/utils.js +0 -8
  42. package/src/exports/vite/dev/index.js +92 -50
  43. package/src/exports/vite/index.js +903 -681
  44. package/src/exports/vite/module_ids.js +0 -2
  45. package/src/exports/vite/preview/index.js +32 -24
  46. package/src/exports/vite/static_analysis/index.js +2 -4
  47. package/src/exports/vite/static_analysis/types.d.ts +14 -0
  48. package/src/exports/vite/utils.js +40 -35
  49. package/src/runtime/app/env/internal.js +4 -4
  50. package/src/runtime/app/env/types.d.ts +1 -1
  51. package/src/runtime/app/environment/index.js +3 -3
  52. package/src/runtime/app/forms.js +24 -7
  53. package/src/runtime/app/paths/client.js +4 -10
  54. package/src/runtime/app/paths/internal/client.js +4 -2
  55. package/src/runtime/app/paths/internal/server.js +2 -23
  56. package/src/runtime/app/paths/public.d.ts +0 -28
  57. package/src/runtime/app/paths/server.js +10 -6
  58. package/src/runtime/app/server/index.js +1 -1
  59. package/src/runtime/app/server/remote/command.js +0 -3
  60. package/src/runtime/app/server/remote/form.js +27 -15
  61. package/src/runtime/app/server/remote/prerender.js +29 -36
  62. package/src/runtime/app/server/remote/query.js +101 -99
  63. package/src/runtime/app/server/remote/requested.js +22 -14
  64. package/src/runtime/app/server/remote/shared.js +30 -26
  65. package/src/runtime/app/state/client.js +1 -2
  66. package/src/runtime/app/stores.js +13 -76
  67. package/src/runtime/client/bundle.js +1 -1
  68. package/src/runtime/client/client-entry.js +3 -0
  69. package/src/runtime/client/client.js +411 -318
  70. package/src/runtime/client/entry.js +24 -3
  71. package/src/runtime/client/fetcher.js +3 -2
  72. package/src/runtime/client/ndjson.js +6 -33
  73. package/src/runtime/client/payload.js +17 -0
  74. package/src/runtime/client/remote-functions/cache.svelte.js +3 -1
  75. package/src/runtime/client/remote-functions/command.svelte.js +7 -32
  76. package/src/runtime/client/remote-functions/form.svelte.js +183 -112
  77. package/src/runtime/client/remote-functions/prerender.svelte.js +29 -8
  78. package/src/runtime/client/remote-functions/query/index.js +7 -14
  79. package/src/runtime/client/remote-functions/query/instance.svelte.js +63 -18
  80. package/src/runtime/client/remote-functions/query/proxy.js +3 -3
  81. package/src/runtime/client/remote-functions/query-batch.svelte.js +60 -68
  82. package/src/runtime/client/remote-functions/query-live/instance.svelte.js +60 -18
  83. package/src/runtime/client/remote-functions/query-live/iterator.js +36 -55
  84. package/src/runtime/client/remote-functions/shared.svelte.js +88 -62
  85. package/src/runtime/client/sse.js +32 -0
  86. package/src/runtime/client/state.svelte.js +65 -49
  87. package/src/runtime/client/stream.js +39 -0
  88. package/src/runtime/client/types.d.ts +11 -7
  89. package/src/runtime/client/utils.js +0 -96
  90. package/src/runtime/components/root.svelte +66 -0
  91. package/src/runtime/env/dynamic/private.js +7 -0
  92. package/src/runtime/env/dynamic/public.js +7 -0
  93. package/src/runtime/env/static/private.js +6 -0
  94. package/src/runtime/env/static/public.js +6 -0
  95. package/src/runtime/form-utils.js +100 -22
  96. package/src/runtime/server/cookie.js +69 -52
  97. package/src/runtime/server/csrf.js +65 -0
  98. package/src/runtime/server/data/index.js +15 -19
  99. package/src/runtime/server/env_module.js +0 -5
  100. package/src/runtime/server/errors.js +135 -0
  101. package/src/runtime/server/fetch.js +1 -1
  102. package/src/runtime/server/index.js +22 -12
  103. package/src/runtime/server/internal.js +25 -0
  104. package/src/runtime/server/page/actions.js +43 -27
  105. package/src/runtime/server/page/data_serializer.js +10 -10
  106. package/src/runtime/server/page/index.js +12 -17
  107. package/src/runtime/server/page/load_data.js +2 -2
  108. package/src/runtime/server/page/render.js +114 -193
  109. package/src/runtime/server/page/respond_with_error.js +11 -11
  110. package/src/runtime/server/page/server_routing.js +27 -18
  111. package/src/runtime/server/remote-functions.js +596 -0
  112. package/src/runtime/server/respond.js +100 -68
  113. package/src/runtime/server/sourcemaps.js +183 -0
  114. package/src/runtime/server/utils.js +2 -134
  115. package/src/runtime/shared.js +83 -13
  116. package/src/runtime/telemetry/otel.js +1 -1
  117. package/src/runtime/types.d.ts +8 -0
  118. package/src/types/ambient-private.d.ts +2 -0
  119. package/src/types/ambient.d.ts +10 -5
  120. package/src/types/global-private.d.ts +13 -25
  121. package/src/types/internal.d.ts +95 -80
  122. package/src/types/private.d.ts +41 -1
  123. package/src/utils/error.js +24 -4
  124. package/src/utils/escape.js +9 -25
  125. package/src/utils/features.js +1 -1
  126. package/src/utils/fork.js +7 -2
  127. package/src/utils/import.js +6 -1
  128. package/src/utils/imports.js +83 -0
  129. package/src/utils/mime.js +9 -0
  130. package/src/utils/page_nodes.js +3 -5
  131. package/src/utils/params.js +66 -0
  132. package/src/utils/routing.js +90 -44
  133. package/src/utils/shared-iterator.js +5 -0
  134. package/src/utils/streaming.js +14 -4
  135. package/src/utils/url.js +20 -2
  136. package/src/version.js +1 -1
  137. package/types/index.d.ts +537 -557
  138. package/types/index.d.ts.map +24 -39
  139. package/src/core/sync/write_root.js +0 -148
  140. package/src/exports/internal/server.js +0 -22
  141. package/src/runtime/server/remote.js +0 -457
  142. package/src/runtime/shared-server.js +0 -7
  143. package/src/types/synthetic/$lib.md +0 -5
  144. /package/src/exports/internal/{remote-functions.js → server/remote-functions.js} +0 -0
@@ -1,5 +1,5 @@
1
+ /** @import { RenderNode } from '../../types.js' */
1
2
  import * as devalue from 'devalue';
2
- import { readable, writable } from 'svelte/store';
3
3
  import { DEV } from 'esm-env';
4
4
  import { isRedirect, text } from '@sveltejs/kit';
5
5
  import * as paths from '$app/paths/internal/server';
@@ -11,26 +11,18 @@ import { uneval_action_response } from './actions.js';
11
11
  import { SVELTE_KIT_ASSETS } from '../../../constants.js';
12
12
  import { SCHEME } from '../../../utils/url.js';
13
13
  import { create_server_routing_response, generate_route_object } from './server_routing.js';
14
- import { add_resolution_suffix } from '../../pathname.js';
14
+ import { add_data_suffix, add_resolution_suffix } from '../../pathname.js';
15
15
  import { try_get_request_store, with_request_store } from '@sveltejs/kit/internal/server';
16
16
  import { text_encoder } from '../../utils.js';
17
- import {
18
- count_non_ssi_comments,
19
- create_replacer,
20
- get_global_name,
21
- handle_error_and_jsonify
22
- } from '../utils.js';
23
- import { create_remote_key } from '../../shared.js';
24
- import { get_status } from '../../../utils/error.js';
17
+ import { count_non_ssi_comments, create_replacer, get_global_name } from '../utils.js';
18
+ import { handle_error_and_jsonify } from '../errors.js';
25
19
  import * as env from '__sveltekit/env';
20
+ import { collect_remote_data } from '../remote-functions.js';
21
+ import Root from '../../components/root.svelte';
22
+ import { render } from 'svelte/server';
26
23
 
27
24
  // TODO rename this function/module
28
25
 
29
- const updated = {
30
- ...readable(false),
31
- check: () => false
32
- };
33
-
34
26
  /**
35
27
  * Creates the HTML response.
36
28
  * @param {{
@@ -47,7 +39,7 @@ const updated = {
47
39
  * resolve_opts: import('types').RequiredResolveOptions;
48
40
  * action_result?: import('@sveltejs/kit').ActionResult;
49
41
  * data_serializer: import('./types.js').ServerDataSerializer;
50
- * error_components?: Array<import('types').SSRComponent | undefined>
42
+ * error_components?: Array<import('svelte').Component | undefined>
51
43
  * }} opts
52
44
  */
53
45
  export async function render_response({
@@ -68,7 +60,7 @@ export async function render_response({
68
60
  }) {
69
61
  if (state.prerendering) {
70
62
  if (options.csp.mode === 'nonce') {
71
- throw new Error('Cannot use prerendering if config.kit.csp.mode === "nonce"');
63
+ throw new Error('Cannot use prerendering if config.csp.mode === "nonce"');
72
64
  }
73
65
 
74
66
  if (options.app_template_contains_nonce) {
@@ -78,9 +70,9 @@ export async function render_response({
78
70
 
79
71
  const { client } = manifest._;
80
72
 
81
- const modulepreloads = new Set(client.imports);
82
- const stylesheets = new Set(client.stylesheets);
83
- const fonts = new Set(client.fonts);
73
+ const modulepreloads = new Set(client?.imports);
74
+ const stylesheets = new Set(client?.stylesheets);
75
+ const fonts = new Set(client?.fonts);
84
76
 
85
77
  /**
86
78
  * The value of the Link header that is added to the response when not prerendering
@@ -92,7 +84,8 @@ export async function render_response({
92
84
  // TODO if we add a client entry point one day, we will need to include inline_styles with the entry, otherwise stylesheets will be linked even if they are below inlineStyleThreshold
93
85
  const inline_styles = new Map();
94
86
 
95
- /** @type {ReturnType<typeof options.root.render>} */
87
+ // TODO `svelte/server` should expose `RenderOutput`
88
+ /** @type {{ head: string, body: string, hashes: { script: string[] } }} */
96
89
  let rendered;
97
90
 
98
91
  const form_value =
@@ -119,7 +112,12 @@ export async function render_response({
119
112
  // if appropriate, use relative paths for greater portability
120
113
  if (paths.relative) {
121
114
  if (!state.prerendering?.fallback) {
122
- const segments = event.url.pathname.slice(paths.base.length).split('/').slice(2);
115
+ // the relative path depth must reflect the URL the browser is actually at, which
116
+ // for a data request includes the `__data.json` suffix that was stripped during routing
117
+ const pathname = event.isDataRequest
118
+ ? add_data_suffix(event.url.pathname)
119
+ : event.url.pathname;
120
+ const segments = pathname.slice(paths.base.length).split('/').slice(2);
123
121
 
124
122
  base = segments.map(() => '..').join('/') || '.';
125
123
 
@@ -138,49 +136,47 @@ export async function render_response({
138
136
  if (page_config.ssr) {
139
137
  /** @type {Record<string, any>} */
140
138
  const props = {
141
- stores: {
142
- page: writable(null),
143
- navigating: writable(null),
144
- updated
145
- },
146
- constructors: await Promise.all(
147
- branch.map(({ node }) => {
148
- if (!node.component) {
149
- // Can only be the leaf, layouts have a fallback component generated
150
- throw new Error(`Missing +page.svelte component for route ${event.route.id}`);
151
- }
152
- return node.component();
153
- })
154
- ),
155
- form: form_value
156
- };
157
-
158
- if (error_components) {
159
- if (error) {
160
- props.error = error;
139
+ components: [],
140
+ resetters: [],
141
+ form: form_value,
142
+ tree: /** @type {RenderNode} */ ({}),
143
+ error,
144
+ page: {
145
+ error,
146
+ params: /** @type {Record<string, any>} */ (event.params),
147
+ route: event.route,
148
+ status,
149
+ url: event.url,
150
+ data: {},
151
+ form: form_value,
152
+ state: {}
161
153
  }
162
- props.errors = error_components;
163
- }
154
+ };
164
155
 
165
- let data = {};
156
+ let current_node = props.tree;
157
+ let data = props.page.data;
166
158
 
167
- // props_n (instead of props[n]) makes it easy to avoid
168
- // unnecessary updates for layout components
169
159
  for (let i = 0; i < branch.length; i += 1) {
170
- data = { ...data, ...branch[i].data };
171
- props[`data_${i}`] = data;
160
+ const node = branch[i];
161
+
162
+ data = { ...data, ...node.data };
163
+
164
+ // TODO this is undefined sometimes... where does the default error component come from?
165
+ const error = error_components?.slice(0, i + 1).findLast((x) => x);
166
+
167
+ current_node.error = error;
168
+ current_node.component = await node.node.component?.();
169
+ current_node.data = data;
170
+
171
+ if (i < branch.length - 1) {
172
+ current_node.child = /** @type {import('../../types.js').RenderNode} */ ({});
173
+ current_node = current_node.child;
174
+ }
172
175
  }
173
176
 
174
- props.page = {
175
- error,
176
- params: /** @type {Record<string, any>} */ (event.params),
177
- route: event.route,
178
- status,
179
- url: event.url,
180
- data,
181
- form: form_value,
182
- state: {}
183
- };
177
+ props.page.data = data;
178
+
179
+ const render_state = { ...event_state, is_in_render: true };
184
180
 
185
181
  const render_opts = {
186
182
  context: new Map([
@@ -193,15 +189,28 @@ export async function render_response({
193
189
  ]),
194
190
  csp: csp.script_needs_nonce ? { nonce: csp.nonce } : { hash: csp.script_needs_hash },
195
191
  transformError: error_components
196
- ? /** @param {unknown} e */ async (e) => {
192
+ ? /** @param {unknown} e */ (e) => {
197
193
  if (isRedirect(e)) {
198
194
  throw e;
199
195
  }
200
196
 
201
- const transformed = await handle_error_and_jsonify(event, event_state, options, e);
202
- props.page.error = props.error = error = transformed;
203
- props.page.status = status = get_status(e);
204
- return transformed;
197
+ const handled = handle_error_and_jsonify(event, render_state, options, e);
198
+
199
+ // TODO 4.0 make this an async function and await `handled`
200
+ if (handled instanceof Promise) {
201
+ return handled.then((e) => {
202
+ error = e;
203
+ props.page.error = error;
204
+ props.page.status = status = error.status;
205
+ return error;
206
+ });
207
+ }
208
+
209
+ error = handled;
210
+ props.page.error = error;
211
+ props.page.status = status = error.status;
212
+
213
+ return error;
205
214
  }
206
215
  : undefined
207
216
  };
@@ -227,53 +236,27 @@ export async function render_response({
227
236
  };
228
237
  }
229
238
 
230
- const state = { ...event_state, is_in_render: true };
231
-
232
- rendered = await with_request_store({ event, state }, async () => {
233
- // use relative paths during rendering, so that the resulting HTML is as
234
- // portable as possible, but reset afterwards
235
- if (paths.relative) paths.override({ base, assets });
236
-
237
- const maybe_promise = options.root.render(props, render_opts);
239
+ rendered = await with_request_store({ event, state: render_state }, async () => {
238
240
  // We have to invoke .then eagerly here in order to kick off rendering: it's only starting on access,
239
241
  // and `await maybe_promise` would eagerly access the .then property but call its function only after a tick, which is too late
240
242
  // for the paths.reset() below and for any eager getRequestEvent() calls during rendering without AsyncLocalStorage available.
241
- const rendered =
242
- options.async && 'then' in maybe_promise
243
- ? /** @type {ReturnType<typeof options.root.render> & Promise<any>} */ (
244
- maybe_promise
245
- ).then((r) => r)
246
- : maybe_promise;
247
-
248
- // TODO 3.0 remove options.async
249
- if (options.async) {
250
- // we reset this synchronously, rather than after async rendering is complete,
251
- // to avoid cross-talk between requests. This is a breaking change for
252
- // anyone who opts into async SSR, since `base` and `assets` will no
253
- // longer be relative to the current pathname.
254
- // TODO 3.0 remove `base` and `assets` in favour of `resolve(...)` and `asset(...)`
255
- paths.reset();
256
- }
243
+ const rendered = render(Root, { ...render_opts, props });
257
244
 
258
- const { head, html, css, hashes } = /** @type {ReturnType<typeof options.root.render>} */ (
259
- options.async ? await rendered : rendered
260
- );
245
+ const { head, body, hashes } = await rendered;
261
246
 
262
247
  if (hashes) {
263
248
  csp.add_script_hashes(hashes.script);
264
249
  }
265
250
 
266
- return { head, html, css, hashes };
251
+ return { head, body, hashes };
267
252
  });
268
253
  } finally {
269
254
  if (DEV) {
270
255
  globalThis.fetch = fetch;
271
256
  }
272
-
273
- paths.reset(); // just in case `options.root.render(...)` failed
274
257
  }
275
258
  } else {
276
- rendered = { head: '', html: '', css: { code: '', map: null }, hashes: { script: [] } };
259
+ rendered = { head: '', body: '', hashes: { script: [] } };
277
260
  }
278
261
 
279
262
  for (const { node } of branch) {
@@ -281,7 +264,7 @@ export async function render_response({
281
264
  for (const url of node.stylesheets) stylesheets.add(url);
282
265
  for (const url of node.fonts) fonts.add(url);
283
266
 
284
- if (node.inline_styles && !client.inline) {
267
+ if (node.inline_styles && !client?.inline) {
285
268
  Object.entries(await node.inline_styles()).forEach(([filename, css]) => {
286
269
  if (typeof css === 'string') {
287
270
  inline_styles.set(filename, css);
@@ -294,7 +277,7 @@ export async function render_response({
294
277
  }
295
278
 
296
279
  const head = new Head(rendered.head);
297
- let body = rendered.html;
280
+ let body = rendered.body;
298
281
 
299
282
  /** @param {string} path */
300
283
  const prefixed = (path) => {
@@ -307,7 +290,7 @@ export async function render_response({
307
290
  return `${assets}/${path}`;
308
291
  };
309
292
 
310
- const style = client.inline
293
+ const style = client?.inline
311
294
  ? client.inline?.style
312
295
  : Array.from(inline_styles.values()).join('\n');
313
296
 
@@ -371,10 +354,16 @@ export async function render_response({
371
354
  .join('\n\t\t\t')}`;
372
355
  }
373
356
 
374
- if (page_config.csr) {
375
- const route = manifest._.client.routes?.find((r) => r.id === event.route.id) ?? null;
357
+ if (page_config.csr && client) {
358
+ const route = client.routes?.find((r) => r.id === event.route.id) ?? null;
359
+
360
+ // when serving a prerendered page in an app that uses runtime public env vars, we must
361
+ // import the env.js module so that it evaluates before any user code can evaluate.
362
+ // TODO revert to using top-level await once https://bugs.webkit.org/show_bug.cgi?id=242740 is fixed
363
+ // https://github.com/sveltejs/kit/pull/11601
364
+ const load_env_eagerly = client.uses_env_dynamic_public && !!state.prerendering;
376
365
 
377
- if (client.uses_env_dynamic_public && state.prerendering) {
366
+ if (load_env_eagerly) {
378
367
  modulepreloads.add(`${paths.app_dir}/env.js`);
379
368
  }
380
369
 
@@ -386,7 +375,7 @@ export async function render_response({
386
375
  /** @type {(path: string) => void} */
387
376
  let add_preload;
388
377
 
389
- // see the kit.output.preloadStrategy option for details on why we have multiple options here
378
+ // see the output.preloadStrategy option for details on why we have multiple options here
390
379
  if (options.link_header_preload && !state.prerendering) {
391
380
  add_preload = (path) =>
392
381
  link_headers.add(`<${encodeURI(path)}>; rel="modulepreload"; nopush`);
@@ -400,24 +389,18 @@ export async function render_response({
400
389
  }
401
390
 
402
391
  // prerender a `/path/to/page/__route.js` module
403
- if (manifest._.client.routes && state.prerendering && !state.prerendering.fallback) {
392
+ if (client.routes && state.prerendering && !state.prerendering.fallback) {
404
393
  const pathname = add_resolution_suffix(event.url.pathname);
405
394
 
406
395
  state.prerendering.dependencies.set(
407
396
  pathname,
408
- create_server_routing_response(route, event.params, new URL(pathname, event.url), manifest)
397
+ create_server_routing_response(route, event.params, new URL(pathname, event.url), client)
409
398
  );
410
399
  }
411
400
 
412
401
  const blocks = [];
413
402
 
414
- // when serving a prerendered page in an app that uses $app/env/public, we must
415
- // import the env.js module so that it evaluates before any user code can evaluate.
416
- // TODO revert to using top-level await once https://bugs.webkit.org/show_bug.cgi?id=242740 is fixed
417
- // https://github.com/sveltejs/kit/pull/11601
418
- const load_env_eagerly = client.uses_env_dynamic_public && state.prerendering; // TODO implement uses_env_dynamic_public
419
-
420
- const properties = [`base: ${base_expression}`];
403
+ const properties = [`base: ${base_expression}`, `version: ${s(__SVELTEKIT_APP_VERSION__)}`];
421
404
 
422
405
  if (paths.assets) {
423
406
  properties.push(`assets: ${s(paths.assets)}`);
@@ -438,9 +421,11 @@ export async function render_response({
438
421
 
439
422
  if (Object.keys(options.hooks.transport).length > 0) {
440
423
  if (client.inline) {
441
- app_declaration = `const app = __sveltekit_${options.version_hash}.app.app;`;
424
+ app_declaration = `const app = ${global}.app.app;`;
442
425
  } else if (client.app) {
443
- app_declaration = `const app = await import(${s(prefixed(client.app))});`;
426
+ app_declaration = `const kit = await import(${s(prefixed(client.start))});
427
+ kit.init(${global});
428
+ const app = await import(${s(prefixed(client.app))});`;
444
429
  } else {
445
430
  app_declaration = `const { app } = await import(${s(prefixed(client.start))});`;
446
431
  }
@@ -501,13 +486,13 @@ export async function render_response({
501
486
  `error: ${serialized.error}`
502
487
  ];
503
488
 
504
- if (status !== 200) {
489
+ if (status !== 200 && !error) {
505
490
  hydrate.push(`status: ${status}`);
506
491
  }
507
492
 
508
- if (manifest._.client.routes) {
493
+ if (client.routes) {
509
494
  if (route) {
510
- const stringified = generate_route_object(route, event.url, manifest).replaceAll(
495
+ const stringified = generate_route_object(route, event.url, client).replaceAll(
511
496
  '\n',
512
497
  '\n\t\t\t\t\t\t\t'
513
498
  ); // make output after it's put together with the rest more readable
@@ -521,87 +506,26 @@ export async function render_response({
521
506
  args.push(`{\n${indent}\t${hydrate.join(`,\n${indent}\t`)}\n${indent}}`);
522
507
  }
523
508
 
524
- const { remote } = event_state;
525
-
526
- let serialized_query_data = '';
527
- let serialized_prerender_data = '';
528
-
529
- if (remote.data) {
530
- /** @type {Record<string, any>} */
531
- const query = {};
532
-
533
- /** @type {Record<string, any>} */
534
- const prerender = {};
535
-
536
- for (const [internals, cache] of remote.data) {
537
- // remote functions without an `id` aren't exported, and thus
538
- // cannot be called from the client
539
- if (!internals.id) continue;
540
-
541
- for (const key in cache) {
542
- const entry = cache[key];
543
-
544
- if (!entry.serialize) continue;
545
-
546
- const remote_key = create_remote_key(internals.id, key);
547
-
548
- const store = internals.type === 'prerender' ? prerender : query;
549
-
550
- if (
551
- event_state.remote.refreshes?.has(remote_key) ||
552
- event_state.remote.reconnects?.has(remote_key)
553
- ) {
554
- // This entry was refreshed/set by a command or form action.
555
- // Always await it so the mutation result is serialized.
556
- store[remote_key] = await entry.data;
557
- } else {
558
- // Don't block the response on pending remote data - if a query
559
- // hasn't settled yet, it wasn't awaited in the template (or is behind a pending boundary).
560
- const result = await Promise.race([
561
- Promise.resolve(entry.data).then(
562
- (v) => /** @type {const} */ ({ settled: true, value: v }),
563
- (e) => /** @type {const} */ ({ settled: true, error: e })
564
- ),
565
- new Promise((resolve) => {
566
- queueMicrotask(() => resolve(/** @type {const} */ ({ settled: false })));
567
- })
568
- ]);
569
-
570
- if (result.settled) {
571
- if ('error' in result) throw result.error;
572
- store[remote_key] = result.value;
573
- }
574
- }
575
- }
576
- }
577
-
578
- const replacer = create_replacer(options.hooks.transport);
509
+ const remote_data = await collect_remote_data({}, event, event_state, options);
579
510
 
580
- if (Object.keys(query).length > 0) {
581
- serialized_query_data = `${global}.query = ${devalue.uneval(query, replacer)};\n\n\t\t\t\t\t\t`;
582
- }
583
-
584
- if (Object.keys(prerender).length > 0) {
585
- serialized_prerender_data = `${global}.prerender = ${devalue.uneval(prerender, replacer)};\n\n\t\t\t\t\t\t`;
586
- }
587
- }
588
-
589
- const serialized_remote_data = `${serialized_query_data}${serialized_prerender_data}`;
511
+ const serialized_data =
512
+ Object.keys(remote_data).length > 0
513
+ ? `${global}.data = ${devalue.uneval(remote_data, create_replacer(options.hooks.transport))};\n\n\t\t\t\t\t\t`
514
+ : '';
590
515
 
591
516
  // `client.app` is a proxy for `bundleStrategy === 'split'`
592
517
  const boot = client.inline
593
518
  ? `${client.inline.script}
594
519
 
595
- ${serialized_remote_data}${global}.app.start(${args.join(', ')});`
520
+ ${serialized_data}${global}.app.start(${args.join(', ')});`
596
521
  : client.app
597
- ? `Promise.all([
598
- import(${s(prefixed(client.start))}),
599
- import(${s(prefixed(client.app))})
600
- ]).then(([kit, app]) => {
601
- ${serialized_remote_data}kit.start(app, ${args.join(', ')});
522
+ ? `import(${s(prefixed(client.start))}).then(async (kit) => {
523
+ kit.init(${global});
524
+ const app = await import(${s(prefixed(client.app))});
525
+ ${serialized_data}kit.start(app, ${args.join(', ')});
602
526
  });`
603
527
  : `import(${s(prefixed(client.start))}).then((app) => {
604
- ${serialized_remote_data}app.start(${args.join(', ')})
528
+ ${serialized_data}app.start(${args.join(', ')})
605
529
  });`;
606
530
 
607
531
  if (load_env_eagerly) {
@@ -615,12 +539,9 @@ export async function render_response({
615
539
  }
616
540
 
617
541
  if (options.service_worker) {
618
- let opts = __SVELTEKIT_DEV__ ? ", { type: 'module' }" : '';
542
+ let opts = ", { type: 'module' }";
619
543
  if (options.service_worker_options != null) {
620
- const service_worker_options = { ...options.service_worker_options };
621
- if (__SVELTEKIT_DEV__) {
622
- service_worker_options.type = 'module';
623
- }
544
+ const service_worker_options = { ...options.service_worker_options, type: 'module' };
624
545
  opts = `, ${s(service_worker_options)}`;
625
546
  }
626
547
 
@@ -1,8 +1,8 @@
1
1
  import { Redirect } from '@sveltejs/kit/internal';
2
2
  import { render_response } from './render.js';
3
3
  import { load_data, load_server_data } from './load_data.js';
4
- import { handle_error_and_jsonify, static_error_page, redirect_response } from '../utils.js';
5
- import { get_status } from '../../../utils/error.js';
4
+ import { redirect_response } from '../utils.js';
5
+ import { handle_error_and_jsonify, static_error_page } from '../errors.js';
6
6
  import { PageNodes } from '../../../utils/page_nodes.js';
7
7
  import { server_data_serializer } from './data_serializer.js';
8
8
 
@@ -34,12 +34,12 @@ export async function respond_with_error({
34
34
  }) {
35
35
  // reroute to the fallback page to prevent an infinite chain of requests.
36
36
  if (event.request.headers.get('x-sveltekit-error')) {
37
- return static_error_page(options, status, /** @type {Error} */ (error).message);
37
+ const transformed = await handle_error_and_jsonify(event, event_state, options, error);
38
+ return static_error_page(options, status, transformed.message);
38
39
  }
39
40
 
40
41
  /** @type {import('./types.js').Fetched[]} */
41
42
  const fetched = [];
42
-
43
43
  try {
44
44
  const branch = [];
45
45
  const default_layout = await manifest._.nodes[0](); // 0 is always the root layout
@@ -47,6 +47,8 @@ export async function respond_with_error({
47
47
  const ssr = nodes.ssr();
48
48
  const csr = nodes.csr();
49
49
  const data_serializer = server_data_serializer(event, event_state, options);
50
+ // Do this here first in case the awaits below before rendering themselves error
51
+ const transformed = await handle_error_and_jsonify(event, event_state, options, error);
50
52
 
51
53
  if (ssr) {
52
54
  state.error = true;
@@ -98,8 +100,8 @@ export async function respond_with_error({
98
100
  ssr,
99
101
  csr
100
102
  },
101
- status,
102
- error: await handle_error_and_jsonify(event, event_state, options, error),
103
+ status: transformed.status,
104
+ error: transformed,
103
105
  branch,
104
106
  error_components: [],
105
107
  fetched,
@@ -115,10 +117,8 @@ export async function respond_with_error({
115
117
  return redirect_response(e.status, e.location);
116
118
  }
117
119
 
118
- return static_error_page(
119
- options,
120
- get_status(e),
121
- (await handle_error_and_jsonify(event, event_state, options, e)).message
122
- );
120
+ const transformed = await handle_error_and_jsonify(event, event_state, options, e);
121
+
122
+ return static_error_page(options, transformed.status, transformed.message);
123
123
  }
124
124
  }
@@ -1,3 +1,4 @@
1
+ /** @import { SSRManifest } from '@sveltejs/kit' */
1
2
  import { base, assets, relative } from '$app/paths/internal/server';
2
3
  import { text } from '@sveltejs/kit';
3
4
  import { s } from '../../../utils/misc.js';
@@ -7,15 +8,15 @@ import { get_relative_path } from '../../utils.js';
7
8
  /**
8
9
  * @param {import('types').SSRClientRoute} route
9
10
  * @param {URL} url
10
- * @param {import('@sveltejs/kit').SSRManifest} manifest
11
+ * @param {NonNullable<SSRManifest['_']['client']>} client
11
12
  * @returns {string}
12
13
  */
13
- export function generate_route_object(route, url, manifest) {
14
+ export function generate_route_object(route, url, client) {
14
15
  const { errors, layouts, leaf } = route;
15
16
 
16
17
  const nodes = [...errors, ...layouts.map((l) => l?.[1]), leaf[1]]
17
18
  .filter((n) => typeof n === 'number')
18
- .map((n) => `'${n}': () => ${create_client_import(manifest._.client.nodes?.[n], url)}`)
19
+ .map((n) => `'${n}': () => ${create_client_import(client.nodes?.[n], url)}`)
19
20
  .join(',\n\t\t');
20
21
 
21
22
  // stringified version of
@@ -60,36 +61,44 @@ function create_client_import(import_path, url) {
60
61
  /**
61
62
  * @param {string} resolved_path
62
63
  * @param {URL} url
63
- * @param {import('@sveltejs/kit').SSRManifest} manifest
64
+ * @param {SSRManifest} manifest
64
65
  * @returns {Promise<Response>}
65
66
  */
66
67
  export async function resolve_route(resolved_path, url, manifest) {
67
- if (!manifest._.client.routes) {
68
+ if (!manifest._.client?.routes) {
68
69
  return text('Server-side route resolution disabled', { status: 400 });
69
70
  }
70
71
 
71
- const matchers = await manifest._.matchers();
72
- const result = find_route(resolved_path, manifest._.client.routes, matchers);
73
-
74
- return create_server_routing_response(result?.route ?? null, result?.params ?? {}, url, manifest)
75
- .response;
72
+ try {
73
+ const matchers = await manifest._.matchers();
74
+ const result = find_route(resolved_path, manifest._.client.routes, matchers);
75
+
76
+ return create_server_routing_response(
77
+ result?.route ?? null,
78
+ result?.params ?? {},
79
+ url,
80
+ manifest._.client
81
+ ).response;
82
+ } catch {
83
+ return text('Error resolving route', { status: 500 });
84
+ }
76
85
  }
77
86
 
78
87
  /**
79
88
  * @param {import('types').SSRClientRoute | null} route
80
89
  * @param {Partial<Record<string, string>>} params
81
90
  * @param {URL} url
82
- * @param {import('@sveltejs/kit').SSRManifest} manifest
91
+ * @param {NonNullable<SSRManifest['_']['client']>} client
83
92
  * @returns {{response: Response, body: string}}
84
93
  */
85
- export function create_server_routing_response(route, params, url, manifest) {
94
+ export function create_server_routing_response(route, params, url, client) {
86
95
  const headers = new Headers({
87
96
  'content-type': 'application/javascript; charset=utf-8'
88
97
  });
89
98
 
90
99
  if (route) {
91
- const csr_route = generate_route_object(route, url, manifest);
92
- const body = `${create_css_import(route, url, manifest)}\nexport const route = ${csr_route}; export const params = ${JSON.stringify(params)};`;
100
+ const csr_route = generate_route_object(route, url, client);
101
+ const body = `${create_css_import(route, url, client)}\nexport const route = ${csr_route}; export const params = ${JSON.stringify(params)};`;
93
102
 
94
103
  return { response: text(body, { headers }), body };
95
104
  } else {
@@ -105,17 +114,17 @@ export function create_server_routing_response(route, params, url, manifest) {
105
114
  *
106
115
  * @param {import('types').SSRClientRoute} route
107
116
  * @param {URL} url
108
- * @param {import('@sveltejs/kit').SSRManifest} manifest
117
+ * @param {NonNullable<SSRManifest['_']['client']>} client
109
118
  * @returns {string}
110
119
  */
111
- function create_css_import(route, url, manifest) {
120
+ function create_css_import(route, url, client) {
112
121
  const { errors, layouts, leaf } = route;
113
122
 
114
123
  let css = '';
115
124
 
116
125
  for (const node of [...errors, ...layouts.map((l) => l?.[1]), leaf[1]]) {
117
126
  if (typeof node !== 'number') continue;
118
- const node_css = manifest._.client.css?.[node];
127
+ const node_css = client.css?.[node];
119
128
  for (const css_path of node_css ?? []) {
120
129
  css += `'${assets || base}/${css_path}',`;
121
130
  }
@@ -123,5 +132,5 @@ function create_css_import(route, url, manifest) {
123
132
 
124
133
  if (!css) return '';
125
134
 
126
- return `${create_client_import(/** @type {string} */ (manifest._.client.start), url)}.then(x => x.load_css([${css}]));`;
135
+ return `${create_client_import(client.start, url)}.then(x => x.load_css([${css}]));`;
127
136
  }