@sveltejs/kit 3.0.0-next.18 → 3.0.0-next.19

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 (83) hide show
  1. package/package.json +12 -5
  2. package/src/cli.js +1 -1
  3. package/src/constants.js +3 -0
  4. package/src/core/config/index.js +1 -1
  5. package/src/core/env.js +1 -1
  6. package/src/core/postbuild/analyse.js +1 -1
  7. package/src/core/postbuild/prerender.js +1 -1
  8. package/src/core/sync/create_manifest_data/index.js +9 -0
  9. package/src/core/sync/sync.js +22 -9
  10. package/src/core/sync/ts.js +1 -1
  11. package/src/core/sync/write_app_types.js +1 -1
  12. package/src/core/sync/write_client_manifest.js +1 -1
  13. package/src/core/sync/write_server.js +1 -3
  14. package/src/core/sync/write_tsconfig/index.js +1 -1
  15. package/src/core/sync/write_types/index.js +6 -3
  16. package/src/exports/index.js +9 -9
  17. package/src/exports/internal/server/event.js +1 -1
  18. package/src/exports/internal/server/telemetry.js +1 -1
  19. package/src/exports/internal/shared.js +9 -0
  20. package/src/exports/{params.js → params/index.js} +6 -4
  21. package/src/exports/params/public.d.ts +63 -0
  22. package/src/exports/public.d.ts +77 -447
  23. package/src/exports/vite/build/build_server.js +2 -2
  24. package/src/exports/vite/dev/index.js +2 -3
  25. package/src/exports/vite/index.js +14 -3
  26. package/src/pathname.js +55 -0
  27. package/src/runtime/app/{forms.js → forms/index.js} +9 -8
  28. package/src/runtime/app/forms/public.d.ts +2 -0
  29. package/src/runtime/app/forms/types.d.ts +56 -0
  30. package/src/runtime/app/{navigation.js → navigation/index.js} +2 -2
  31. package/src/runtime/app/navigation/public.d.ts +237 -0
  32. package/src/runtime/app/paths/client.js +14 -8
  33. package/src/runtime/app/paths/index.js +1 -1
  34. package/src/runtime/app/paths/internal/client.js +4 -0
  35. package/src/runtime/app/paths/internal/server.js +4 -0
  36. package/src/runtime/app/paths/internal.d.ts +3 -0
  37. package/src/runtime/app/paths/public.d.ts +1 -1
  38. package/src/runtime/app/paths/server.js +6 -4
  39. package/src/runtime/app/server/index.js +1 -1
  40. package/src/runtime/app/server/remote/form.js +3 -4
  41. package/src/runtime/app/server/remote/prerender.js +3 -3
  42. package/src/runtime/app/server/remote/shared.js +3 -10
  43. package/src/runtime/app/state/index.js +4 -2
  44. package/src/runtime/app/state/public.d.ts +72 -0
  45. package/src/runtime/app/stores.js +2 -2
  46. package/src/runtime/client/client.js +65 -54
  47. package/src/runtime/client/entry.js +2 -2
  48. package/src/runtime/client/remote-functions/command.svelte.js +36 -34
  49. package/src/runtime/client/remote-functions/form.svelte.js +76 -78
  50. package/src/runtime/client/remote-functions/prerender.svelte.js +3 -3
  51. package/src/runtime/client/remote-functions/query/index.js +1 -1
  52. package/src/runtime/client/remote-functions/query/instance.svelte.js +4 -3
  53. package/src/runtime/client/remote-functions/query-batch.svelte.js +3 -3
  54. package/src/runtime/client/remote-functions/query-live/instance.svelte.js +5 -5
  55. package/src/runtime/client/remote-functions/query-live/iterator.js +5 -7
  56. package/src/runtime/client/remote-functions/shared.svelte.js +9 -14
  57. package/src/runtime/client/state.svelte.js +5 -3
  58. package/src/runtime/client/types.d.ts +2 -1
  59. package/src/runtime/pathname.js +6 -61
  60. package/src/runtime/props.svelte.js +1 -1
  61. package/src/runtime/server/constants.js +0 -3
  62. package/src/runtime/server/errors.js +53 -28
  63. package/src/runtime/server/fetch.js +1 -1
  64. package/src/runtime/server/index.js +9 -14
  65. package/src/runtime/server/page/actions.js +2 -1
  66. package/src/runtime/server/page/index.js +7 -3
  67. package/src/runtime/server/page/load_data.js +1 -1
  68. package/src/runtime/server/page/render.js +17 -11
  69. package/src/runtime/server/page/server_routing.js +3 -2
  70. package/src/runtime/server/remote-functions.js +3 -2
  71. package/src/runtime/server/respond.js +4 -8
  72. package/src/runtime/server/state.js +3 -6
  73. package/src/types/ambient.d.ts +1 -1
  74. package/src/types/internal.d.ts +8 -10
  75. package/src/types/private.d.ts +12 -3
  76. package/src/utils/error.js +30 -14
  77. package/src/utils/page_nodes.js +3 -2
  78. package/src/utils/params.js +3 -2
  79. package/src/utils/routing.js +5 -4
  80. package/src/version.js +1 -1
  81. package/types/index.d.ts +992 -932
  82. package/types/index.d.ts.map +43 -31
  83. /package/src/{runtime/telemetry/noop.js → telemetry.js} +0 -0
@@ -1,9 +1,9 @@
1
1
  /** @import { StandardSchemaV1 } from '@standard-schema/spec' */
2
2
  /** @import { RemoteFormInput, RemoteForm, RemoteQueryUpdate } from '@sveltejs/kit' */
3
3
  /** @import { InternalRemoteFormIssue } from 'types' */
4
- import { app_dir, base } from '$app/paths/internal/client';
4
+ import { app_dir, base } from '#app/paths';
5
5
  import { DEV } from 'esm-env';
6
- import { HttpError } from '@sveltejs/kit/internal';
6
+
7
7
  import {
8
8
  query_responses,
9
9
  _goto,
@@ -222,82 +222,84 @@ export function form(id) {
222
222
  /** @type {Error | undefined} */
223
223
  let updates_error;
224
224
 
225
- /** @type {Promise<boolean> & { updates: (...args: RemoteQueryUpdate[]) => Promise<boolean> }} */
226
- const promise = (async () => {
227
- try {
228
- await Promise.resolve();
225
+ const promise =
226
+ /** @type {Promise<boolean> & { updates: (...args: RemoteQueryUpdate[]) => Promise<boolean> }} */ (
227
+ (async () => {
228
+ try {
229
+ await Promise.resolve();
229
230
 
230
- if (updates_error) {
231
- throw updates_error;
232
- }
233
-
234
- if (should_preflight) {
235
- const valid = await preflight(form_data);
236
- if (!valid) return false;
237
- }
238
-
239
- const { blob } = serialize_binary_form(convert(form_data), {
240
- remote_refreshes: Array.from(refreshes ?? [])
241
- });
242
-
243
- const response = await remote_request(
244
- `${base}/${app_dir}/remote/${action_id_without_key}`,
245
- {
246
- method: 'POST',
247
- headers: {
248
- 'Content-Type': BINARY_FORM_CONTENT_TYPE,
249
- // Forms cannot be called during rendering, so it's save to use location here
250
- 'x-sveltekit-pathname': location.pathname,
251
- 'x-sveltekit-search': location.search
252
- },
253
- body: blob
254
- }
255
- );
231
+ if (updates_error) {
232
+ throw updates_error;
233
+ }
256
234
 
257
- ({ issues: raw_issues = [], result } = response._ ?? {});
235
+ if (should_preflight) {
236
+ const valid = await preflight(form_data);
237
+ if (!valid) return false;
238
+ }
258
239
 
259
- // if the developer took control of updates via `.updates(...)` (even with
260
- // no arguments), or the server performed explicit refreshes, don't invalidateAll
261
- const should_refresh = refreshes === null && !response.r;
240
+ const { blob } = serialize_binary_form(convert(form_data), {
241
+ remote_refreshes: Array.from(refreshes ?? [])
242
+ });
243
+
244
+ const response = await remote_request(
245
+ `${base}/${app_dir}/remote/${action_id_without_key}`,
246
+ {
247
+ method: 'POST',
248
+ headers: {
249
+ 'Content-Type': BINARY_FORM_CONTENT_TYPE,
250
+ // Forms cannot be called during rendering, so it's save to use location here
251
+ 'x-sveltekit-pathname': location.pathname,
252
+ 'x-sveltekit-search': location.search
253
+ },
254
+ body: blob
255
+ }
256
+ );
262
257
 
263
- if (response.redirect) {
264
- // Use internal version to allow redirects to external URLs
265
- void _goto(response.redirect, {
266
- refreshAll: should_refresh
267
- });
268
- return true;
269
- }
258
+ ({ issues: raw_issues = [], result } = response._ ?? {});
270
259
 
271
- const succeeded = raw_issues.length === 0;
260
+ // if the developer took control of updates via `.updates(...)` (even with
261
+ // no arguments), or the server performed explicit refreshes, don't invalidateAll
262
+ const should_refresh = refreshes === null && !response.r;
272
263
 
273
- if (succeeded) {
274
- if (should_refresh) {
275
- void refreshAll();
276
- }
277
- } else {
278
- if (DEV) {
279
- warn_on_missing_issue_reads();
280
- }
281
- }
264
+ if (response.redirect) {
265
+ // Use internal version to allow redirects to external URLs
266
+ void _goto(response.redirect, {
267
+ refreshAll: should_refresh
268
+ });
269
+ return true;
270
+ }
282
271
 
283
- return succeeded;
284
- } catch (e) {
285
- result = undefined;
286
- raw_issues = [];
287
- throw e;
288
- } finally {
289
- overrides?.forEach((fn) => fn());
272
+ const succeeded = raw_issues.length === 0;
290
273
 
291
- void tick().then(() => {
292
- if (entry) {
293
- entry.count--;
294
- if (entry.count === 0) {
295
- instances.delete(key);
274
+ if (succeeded) {
275
+ if (should_refresh) {
276
+ void refreshAll();
277
+ }
278
+ } else {
279
+ if (DEV) {
280
+ warn_on_missing_issue_reads();
281
+ }
296
282
  }
283
+
284
+ return succeeded;
285
+ } catch (e) {
286
+ result = undefined;
287
+ raw_issues = [];
288
+ throw e;
289
+ } finally {
290
+ overrides?.forEach((fn) => fn());
291
+
292
+ void tick().then(() => {
293
+ if (entry) {
294
+ entry.count--;
295
+ if (entry.count === 0) {
296
+ instances.delete(key);
297
+ }
298
+ }
299
+ });
297
300
  }
298
- });
299
- }
300
- })();
301
+ })()
302
+ );
301
303
 
302
304
  let updates_called = false;
303
305
  promise.updates = (...args) => {
@@ -376,8 +378,7 @@ export function form(id) {
376
378
  return true;
377
379
  }
378
380
 
379
- /** @type {RemoteForm<T, U>} */
380
- const instance = {};
381
+ const instance = /** @type {RemoteForm<T, U>} */ ({});
381
382
 
382
383
  instance.method = 'POST';
383
384
  Object.defineProperty(instance, 'action', {
@@ -477,14 +478,11 @@ export function form(id) {
477
478
 
478
479
  await enhance_callback(create_enhance_callback_instance(form, form_data));
479
480
  } catch (e) {
480
- const error =
481
- e instanceof HttpError
482
- ? e.body
483
- : await handle_error(e, {
484
- params: {},
485
- route: { id: null },
486
- url: new URL(location.href)
487
- });
481
+ const error = await handle_error(e, {
482
+ params: {},
483
+ route: { id: null },
484
+ url: new URL(location.href)
485
+ });
488
486
  void set_nearest_error_page(error);
489
487
  } finally {
490
488
  pending_count--;
@@ -1,12 +1,12 @@
1
1
  /** @import { RemotePrerenderFunction } from '@sveltejs/kit' */
2
- import { app_dir, base } from '$app/paths/internal/client';
2
+ import { app_dir, base } from '#app/paths';
3
3
  import { version } from '$app/env';
4
4
  import * as devalue from 'devalue';
5
5
  import { app, _goto, handle_error, prerender_responses } from '../client.js';
6
6
  import { get_remote_request_headers, remote_request, unwrap_node } from './shared.svelte.js';
7
7
  import { create_remote_key, stringify_remote_arg } from '../../shared.js';
8
8
  import { noop } from '../../../utils/functions.js';
9
- import { HttpError } from '@sveltejs/kit/internal';
9
+ import { HandledHttpError } from '@sveltejs/kit/internal';
10
10
 
11
11
  // Initialize Cache API for prerender functions
12
12
  const CACHE_NAME = __SVELTEKIT_DEV__ ? `sveltekit:${Date.now()}` : `sveltekit:${version}`;
@@ -172,7 +172,7 @@ class Prerender {
172
172
  });
173
173
  this.#loading = false;
174
174
  this.#error = error;
175
- throw new HttpError(error); // so that transformError doesn't transform it again
175
+ throw new HandledHttpError(error);
176
176
  }
177
177
  );
178
178
 
@@ -1,5 +1,5 @@
1
1
  /** @import { RemoteQueryFunction } from '@sveltejs/kit' */
2
- import { app_dir, base } from '$app/paths/internal/client';
2
+ import { app_dir, base } from '#app/paths';
3
3
  import { _goto, query_map } from '../../client.js';
4
4
  import { QUERY_FUNCTION_ID, remote_request } from '../shared.svelte.js';
5
5
  import { DEV } from 'esm-env';
@@ -1,5 +1,6 @@
1
+ /** @import { HttpError } from '@sveltejs/kit' */
1
2
  import { query_responses, handle_error } from '../../client.js';
2
- import { HttpError } from '@sveltejs/kit/internal';
3
+ import { HandledHttpError } from '@sveltejs/kit/internal';
3
4
  import { QUERY_OVERRIDE_KEY } from '../shared.svelte.js';
4
5
  import { noop } from '../../../../utils/functions.js';
5
6
  import { tick, untrack } from 'svelte';
@@ -70,7 +71,7 @@ export class Query {
70
71
  delete query_responses[key];
71
72
 
72
73
  if (node.e) {
73
- this.fail(new HttpError(node.e));
74
+ this.fail(new HandledHttpError(node.e));
74
75
  } else {
75
76
  this.set(/** @type {T} */ (node.v));
76
77
  }
@@ -152,7 +153,7 @@ export class Query {
152
153
  this.#loading = false;
153
154
  });
154
155
 
155
- reject(new HttpError(error)); // so that transformError doesn't transform it again
156
+ reject(new HandledHttpError(error));
156
157
  });
157
158
 
158
159
  return promise;
@@ -1,9 +1,9 @@
1
1
  /** @import { RemoteQueryFunction } from '@sveltejs/kit' */
2
- import { app_dir, base } from '$app/paths/internal/client';
2
+ import { app_dir, base } from '#app/paths';
3
3
  import { _goto } from '../client.js';
4
4
  import { QUERY_FUNCTION_ID, remote_request } from './shared.svelte.js';
5
5
  import { QueryProxy } from './query/proxy.js';
6
- import { HttpError } from '@sveltejs/kit/internal';
6
+ import { HandledHttpError } from '@sveltejs/kit/internal';
7
7
 
8
8
  /**
9
9
  * @param {string} id
@@ -71,7 +71,7 @@ export function query_batch(id) {
71
71
 
72
72
  for (const { resolve, reject } of resolvers) {
73
73
  if (result.type === 'error') {
74
- reject(new HttpError(result.error));
74
+ reject(new HandledHttpError(result.error));
75
75
  } else {
76
76
  resolve(result.data);
77
77
  }
@@ -1,5 +1,5 @@
1
1
  import { query_responses, handle_error } from '../../client.js';
2
- import { HttpError, Redirect } from '@sveltejs/kit/internal';
2
+ import { HttpError, Redirect, HandledHttpError } from '@sveltejs/kit/internal';
3
3
  import { noop, once } from '../../../../utils/functions.js';
4
4
  import { SharedIterator } from '../../../../utils/shared-iterator.js';
5
5
  import { tick } from 'svelte';
@@ -91,7 +91,7 @@ export class LiveQuery {
91
91
  // the query failed during SSR — seed the failed state (mirroring `fail()`,
92
92
  // minus its terminal `#done`), so the main loop still connects as usual
93
93
  // and the query can recover
94
- const error = new HttpError(node.e);
94
+ const error = new HandledHttpError(node.e);
95
95
  this.#loading = false;
96
96
  this.#error = error.body;
97
97
 
@@ -181,8 +181,8 @@ export class LiveQuery {
181
181
  }
182
182
 
183
183
  if (error instanceof HttpError) {
184
- // Server intentionally sent an error. Surface it and stop.
185
- this.fail(error);
184
+ // Server or client intentionally produced an error. Surface it and stop.
185
+ await this.#fail(error);
186
186
  break;
187
187
  }
188
188
 
@@ -417,7 +417,7 @@ export class LiveQuery {
417
417
  route: { id: null },
418
418
  url: new URL(location.href)
419
419
  });
420
- this.fail(new HttpError(error));
420
+ this.fail(new HandledHttpError(error));
421
421
  }
422
422
 
423
423
  get [Symbol.toStringTag]() {
@@ -1,10 +1,10 @@
1
1
  /** @import { RemoteFunctionResponse } from 'types' */
2
- import { app_dir, base } from '$app/paths/internal/client';
2
+ import { app_dir, base } from '#app/paths';
3
3
  import { app } from '../../client.js';
4
4
  import { notify_version } from '../../state.svelte.js';
5
5
  import { handle_side_channel_response } from '../shared.svelte.js';
6
6
  import * as devalue from 'devalue';
7
- import { HttpError } from '@sveltejs/kit/internal';
7
+ import { HttpError, HandledHttpError } from '@sveltejs/kit/internal';
8
8
  import { noop } from '../../../../utils/functions.js';
9
9
  import { read_sse } from '../../sse.js';
10
10
 
@@ -35,11 +35,9 @@ export async function* create_live_iterator(
35
35
  /** @type {RemoteFunctionResponse | undefined} */
36
36
  const result = await response.json().catch(() => undefined);
37
37
 
38
- throw new HttpError(
39
- result?.type === 'error'
40
- ? result.error
41
- : { status: response.status, message: response.statusText }
42
- );
38
+ throw result?.type === 'error'
39
+ ? new HandledHttpError(result.error)
40
+ : new HttpError({ status: response.status, message: response.statusText });
43
41
  }
44
42
 
45
43
  if (response.headers.get('content-type')?.includes('application/json')) {
@@ -3,7 +3,7 @@
3
3
  /** @import { CacheEntry } from './cache.svelte.js' */
4
4
  import * as devalue from 'devalue';
5
5
  import { app, _goto, live_query_map, query_map, query_responses } from '../client.js';
6
- import { HttpError, Redirect } from '@sveltejs/kit/internal';
6
+ import { HttpError, Redirect, HandledHttpError } from '@sveltejs/kit/internal';
7
7
  import { untrack } from 'svelte';
8
8
  import { create_remote_key, split_remote_key } from '../../shared.js';
9
9
  import { navigating, page, notify_version } from '../state.svelte.js';
@@ -86,7 +86,7 @@ export function pin_while_resolving(cache_map, cache, id, payload, then) {
86
86
  */
87
87
  export function unwrap_node(node) {
88
88
  if (node.e) {
89
- throw new HttpError(node.e);
89
+ throw new HandledHttpError(node.e);
90
90
  }
91
91
 
92
92
  return node.v;
@@ -118,22 +118,17 @@ export async function remote_request(url, init) {
118
118
  notify_version(response.headers.get('x-sveltekit-version'));
119
119
 
120
120
  if (!response.ok) {
121
- const result = await response.json().catch(() => ({
122
- type: 'error',
123
- status,
124
- error: {
125
- status,
126
- message: response.statusText
127
- }
128
- }));
121
+ const result = await response.json().catch(() => undefined);
129
122
 
130
- throw new HttpError({ status, ...result.error });
123
+ throw result?.type === 'error'
124
+ ? new HandledHttpError({ status, ...result.error })
125
+ : new HttpError({ status, message: response.statusText });
131
126
  }
132
127
 
133
128
  const result = /** @type {RemoteFunctionResponse} */ (await response.json());
134
129
 
135
130
  if (result.type === 'error') {
136
- throw new HttpError(result.error);
131
+ throw new HandledHttpError(result.error);
137
132
  }
138
133
 
139
134
  const data = /** @type {RemoteFunctionData} */ (
@@ -148,7 +143,7 @@ export async function remote_request(url, init) {
148
143
  function refresh(key, entry, result) {
149
144
  if (entry?.resource) {
150
145
  if (result.e) {
151
- entry.resource.fail(new HttpError(result.e));
146
+ entry.resource.fail(new HandledHttpError(result.e));
152
147
  } else {
153
148
  entry.resource.set(result.v);
154
149
  }
@@ -202,7 +197,7 @@ export async function handle_side_channel_response(response) {
202
197
  }
203
198
 
204
199
  if (response.type === 'error') {
205
- throw new HttpError(response.error);
200
+ throw new HandledHttpError(response.error);
206
201
  }
207
202
 
208
203
  return response;
@@ -1,8 +1,10 @@
1
+ /** @import { Navigation } from '$app/navigation' */
2
+ /** @import { Page } from '$app/state' */
1
3
  import { version } from '$app/env';
2
- import { assets } from '$app/paths/internal/client';
4
+ import { assets } from '#app/paths';
3
5
  import { BROWSER, DEV } from 'esm-env';
4
6
 
5
- /** @type {import('@sveltejs/kit').Page} */
7
+ /** @type {Page} */
6
8
  export const page = new (class Page {
7
9
  data = $state.raw({});
8
10
  form = $state.raw(null);
@@ -16,7 +18,7 @@ export const page = new (class Page {
16
18
  })();
17
19
 
18
20
  export const navigating = new (class Navigating {
19
- /** @type {import('@sveltejs/kit').Navigation | null} */
21
+ /** @type {Navigation | null} */
20
22
  current = $state.raw(null);
21
23
  })();
22
24
 
@@ -8,7 +8,8 @@ import {
8
8
  TrailingSlash,
9
9
  Uses
10
10
  } from 'types';
11
- import { Page, ParamMatcher } from '@sveltejs/kit';
11
+ import { ParamMatcher } from '@sveltejs/kit/params';
12
+ import { Page } from '$app/state';
12
13
  import { RenderNode } from '../props.svelte.js';
13
14
 
14
15
  export interface SvelteKitApp {
@@ -1,69 +1,17 @@
1
- const DATA_SUFFIX = '/__data.json';
2
- const HTML_DATA_SUFFIX = '.html__data.json';
1
+ import { app_dir, base } from '#app/paths';
2
+ import { add_resolution_suffix } from '../pathname.js';
3
3
 
4
- /** @param {string} pathname */
5
- export function has_data_suffix(pathname) {
6
- return pathname.endsWith(DATA_SUFFIX) || pathname.endsWith(HTML_DATA_SUFFIX);
7
- }
8
-
9
- /** @param {string} pathname */
10
- export function add_data_suffix(pathname) {
11
- if (pathname.endsWith('.html')) return pathname.replace(/\.html$/, HTML_DATA_SUFFIX);
12
- return pathname.replace(/\/$/, '') + DATA_SUFFIX;
13
- }
14
-
15
- /** @param {string} pathname */
16
- export function strip_data_suffix(pathname) {
17
- if (pathname.endsWith(HTML_DATA_SUFFIX)) {
18
- return pathname.slice(0, -HTML_DATA_SUFFIX.length) + '.html';
19
- }
20
-
21
- return pathname.slice(0, -DATA_SUFFIX.length);
22
- }
23
-
24
- const ROUTE_SUFFIX = '/__route.js';
25
- const HTML_ROUTE_SUFFIX = '.html__route.js';
26
-
27
- /**
28
- * @param {string} pathname
29
- * @returns {boolean}
30
- */
31
- export function has_resolution_suffix(pathname) {
32
- return pathname.endsWith(ROUTE_SUFFIX) || pathname.endsWith(HTML_ROUTE_SUFFIX);
33
- }
34
-
35
- /**
36
- * Convert a regular URL to a route to send to SvelteKit's server-side route resolution endpoint
37
- * @param {string} pathname
38
- * @returns {string}
39
- */
40
- export function add_resolution_suffix(pathname) {
41
- if (pathname.endsWith('.html')) return pathname.replace(/\.html$/, HTML_ROUTE_SUFFIX);
42
- return pathname.replace(/\/$/, '') + ROUTE_SUFFIX;
43
- }
44
-
45
- /**
46
- * @param {string} pathname
47
- * @returns {string}
48
- */
49
- export function strip_resolution_suffix(pathname) {
50
- if (pathname.endsWith(HTML_ROUTE_SUFFIX)) {
51
- return pathname.slice(0, -HTML_ROUTE_SUFFIX.length) + '.html';
52
- }
53
-
54
- return pathname.slice(0, -ROUTE_SUFFIX.length);
55
- }
4
+ export * from '../pathname.js';
56
5
 
57
6
  const ROUTES_PREFIX = '/routes';
58
7
 
59
8
  /**
60
9
  * The pathname of the route-ID-keyed resolution module for a given route ID,
61
10
  * e.g. `/_app/routes/blog/[slug]/__route.js` (before prefixing with `base`).
62
- * @param {string} app_dir
63
11
  * @param {string} route_id
64
12
  * @returns {string}
65
13
  */
66
- export function route_id_resolution_pathname(app_dir, route_id) {
14
+ export function route_id_resolution_pathname(route_id) {
67
15
  return add_resolution_suffix(`/${app_dir}${ROUTES_PREFIX}${route_id === '/' ? '' : route_id}`);
68
16
  }
69
17
 
@@ -71,11 +19,9 @@ export function route_id_resolution_pathname(app_dir, route_id) {
71
19
  * Whether a pathname (with the `/__route.js` suffix already stripped, and `base` NOT yet stripped)
72
20
  * is a route-ID resolution request rather than a pathname resolution request.
73
21
  * @param {string} pathname
74
- * @param {string} base
75
- * @param {string} app_dir
76
22
  * @returns {boolean}
77
23
  */
78
- export function is_route_id_resolution_path(pathname, base, app_dir) {
24
+ export function is_route_id_resolution_path(pathname) {
79
25
  const prefix = `${base}/${app_dir}${ROUTES_PREFIX}`;
80
26
  return pathname === prefix || pathname.startsWith(prefix + '/');
81
27
  }
@@ -84,9 +30,8 @@ export function is_route_id_resolution_path(pathname, base, app_dir) {
84
30
  * Extract the route ID from a decoded, base-stripped, suffix-stripped pathname,
85
31
  * e.g. `/_app/routes/blog/[slug]` -> `/blog/[slug]`, `/_app/routes` -> `/`.
86
32
  * @param {string} pathname
87
- * @param {string} app_dir
88
33
  * @returns {string}
89
34
  */
90
- export function extract_route_id(pathname, app_dir) {
35
+ export function extract_route_id(pathname) {
91
36
  return pathname.slice(`/${app_dir}${ROUTES_PREFIX}`.length) || '/';
92
37
  }
@@ -1,5 +1,5 @@
1
1
  /** @import { Component } from 'svelte'; */
2
- /** @import { Page } from '@sveltejs/kit'; */
2
+ /** @import { Page } from '$app/state'; */
3
3
 
4
4
  import { noop } from '../utils/functions.js';
5
5
 
@@ -1,4 +1 @@
1
1
  export const NULL_BODY_STATUS = [101, 103, 204, 205, 304];
2
-
3
- // eslint-disable-next-line n/prefer-global/process
4
- export const IN_WEBCONTAINER = !!globalThis.process?.versions?.webcontainer;
@@ -1,7 +1,12 @@
1
1
  import { json, text } from '@sveltejs/kit';
2
- import { HttpError, SvelteKitError } from '@sveltejs/kit/internal';
2
+ import {
3
+ HandledHttpError,
4
+ HttpError,
5
+ SvelteKitError,
6
+ ValidationError
7
+ } from '@sveltejs/kit/internal';
3
8
  import { with_request_store } from '@sveltejs/kit/internal/server';
4
- import { coalesce_to_error, get_message, get_status } from '../../utils/error.js';
9
+ import { add_deprecated_handle_error_properties, coalesce_to_error } from '../../utils/error.js';
5
10
  import { negotiate } from '../../utils/http.js';
6
11
  import { fix_stack_trace } from './internal.js';
7
12
  import { escape_html } from '../../utils/escape.js';
@@ -13,7 +18,6 @@ import { escape_html } from '../../utils/escape.js';
13
18
  * @param {unknown} error
14
19
  */
15
20
  export async function handle_fatal_error(event, state, options, error) {
16
- error = error instanceof HttpError ? error : coalesce_to_error(error);
17
21
  const body = await handle_error_and_jsonify(event, state, options, error);
18
22
  const status = body.status;
19
23
 
@@ -40,29 +44,56 @@ export async function handle_fatal_error(event, state, options, error) {
40
44
  * @returns {App.Error | Promise<App.Error>}
41
45
  */
42
46
  export function handle_error_and_jsonify(event, state, options, error) {
43
- if (error instanceof HttpError) {
44
- // @ts-expect-error custom user errors may not have a message field if App.Error is overwritten
45
- return { message: 'Unknown Error', ...error.body };
47
+ if (error instanceof HandledHttpError) {
48
+ return error.body;
46
49
  }
47
50
 
48
- let e = error;
49
- while (e instanceof Error) {
50
- fix_stack_trace(e);
51
- e = e.cause;
51
+ /** @type {import('@sveltejs/kit').CaughtError} */
52
+ let caught;
53
+
54
+ if (error instanceof HttpError) {
55
+ caught = { kind: 'app', error: error.body };
56
+ } else if (error instanceof SvelteKitError) {
57
+ caught = { kind: 'framework', error: { status: error.status, message: error.text } };
58
+ } else if (error instanceof ValidationError) {
59
+ caught = {
60
+ kind: 'validation',
61
+ error: { status: 400, message: 'Bad Request' },
62
+ issues: error.issues
63
+ };
64
+ } else {
65
+ caught = { kind: 'unknown', error };
66
+
67
+ let e = error;
68
+ while (e instanceof Error) {
69
+ fix_stack_trace(e);
70
+ e = e.cause;
71
+ }
52
72
  }
53
73
 
54
- const status = get_status(error);
55
- const message = get_message(error);
74
+ const fallback =
75
+ caught.kind === 'unknown' ? { status: 500, message: 'Internal Error' } : caught.error;
76
+
77
+ /**
78
+ * The hook returns only the properties it wants to override; anything it omits
79
+ * (including by returning nothing at all) is inherited from the caught error.
80
+ * @param {Awaited<ReturnType<import('@sveltejs/kit').HandleServerError>>} body
81
+ * @returns {App.Error}
82
+ */
83
+ function merge(body) {
84
+ return { ...fallback, ...body };
85
+ }
56
86
 
57
87
  // TODO 4.0 await this, rather than handling the non-Promise case
58
88
  let result;
59
89
  try {
60
- result = with_request_store({ event, state }, () =>
61
- options.hooks.handleError({ error, event, status, message })
62
- ) ?? { status, message };
90
+ const input = { ...caught, event };
91
+ if (__SVELTEKIT_DEV__) add_deprecated_handle_error_properties(input, fallback);
92
+
93
+ result = with_request_store({ event, state }, () => options.hooks.handleError(input));
63
94
  } catch (hook_error) {
64
95
  log_handle_error_hook_failure(error, hook_error);
65
- return { status, message: 'Internal Error' };
96
+ return { status: fallback.status, message: 'Internal Error' };
66
97
  }
67
98
 
68
99
  if (result instanceof Promise) {
@@ -76,24 +107,18 @@ export function handle_error_and_jsonify(event, state, options, error) {
76
107
  result.catch((hook_error) => log_handle_error_hook_failure(error, hook_error));
77
108
 
78
109
  return {
79
- status,
110
+ status: fallback.status,
80
111
  message: 'Internal Error'
81
112
  };
82
113
  }
83
114
 
84
- return result.then(
85
- (body) => {
86
- body ??= { status, message };
87
- return { ...body, status: get_status(body, error) };
88
- },
89
- (hook_error) => {
90
- log_handle_error_hook_failure(error, hook_error);
91
- return { status, message: 'Internal Error' };
92
- }
93
- );
115
+ return result.then(merge, (hook_error) => {
116
+ log_handle_error_hook_failure(error, hook_error);
117
+ return { status: fallback.status, message: 'Internal Error' };
118
+ });
94
119
  }
95
120
 
96
- return { ...result, status: get_status(result, error) };
121
+ return merge(result);
97
122
  }
98
123
 
99
124
  /**