@sveltejs/kit 1.30.2 → 2.0.0

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 (57) hide show
  1. package/package.json +24 -24
  2. package/src/core/adapt/builder.js +8 -1
  3. package/src/core/config/index.js +9 -1
  4. package/src/core/config/options.js +1 -12
  5. package/src/core/postbuild/analyse.js +98 -80
  6. package/src/core/postbuild/prerender.js +11 -9
  7. package/src/core/sync/sync.js +2 -0
  8. package/src/core/sync/write_non_ambient.js +42 -0
  9. package/src/core/sync/write_server.js +3 -3
  10. package/src/core/sync/write_tsconfig.js +27 -78
  11. package/src/core/sync/write_types/index.js +1 -1
  12. package/src/exports/hooks/sequence.js +1 -1
  13. package/src/exports/index.js +88 -71
  14. package/src/exports/node/index.js +21 -24
  15. package/src/exports/node/polyfills.js +5 -34
  16. package/src/exports/public.d.ts +82 -61
  17. package/src/exports/vite/dev/index.js +11 -19
  18. package/src/exports/vite/graph_analysis/index.js +2 -4
  19. package/src/exports/vite/index.js +73 -14
  20. package/src/exports/vite/module_ids.js +7 -0
  21. package/src/exports/vite/preview/index.js +56 -130
  22. package/src/runtime/app/forms.js +2 -35
  23. package/src/runtime/app/navigation.js +33 -18
  24. package/src/runtime/app/paths.js +2 -29
  25. package/src/runtime/client/client.js +449 -199
  26. package/src/runtime/client/constants.js +5 -1
  27. package/src/runtime/client/session-storage.js +7 -5
  28. package/src/runtime/client/singletons.js +7 -1
  29. package/src/runtime/client/types.d.ts +6 -2
  30. package/src/runtime/client/utils.js +12 -10
  31. package/src/runtime/control.js +16 -8
  32. package/src/runtime/server/cookie.js +38 -61
  33. package/src/runtime/server/data/index.js +6 -4
  34. package/src/runtime/server/env_module.js +29 -0
  35. package/src/runtime/server/fetch.js +7 -6
  36. package/src/runtime/server/index.js +23 -20
  37. package/src/runtime/server/page/actions.js +24 -15
  38. package/src/runtime/server/page/index.js +6 -8
  39. package/src/runtime/server/page/load_data.js +58 -40
  40. package/src/runtime/server/page/render.js +12 -7
  41. package/src/runtime/server/page/respond_with_error.js +4 -4
  42. package/src/runtime/server/page/types.d.ts +1 -1
  43. package/src/runtime/server/respond.js +14 -12
  44. package/src/runtime/server/utils.js +11 -8
  45. package/src/runtime/shared-server.js +19 -2
  46. package/src/types/ambient.d.ts +7 -1
  47. package/src/types/internal.d.ts +4 -1
  48. package/src/types/synthetic/$env+dynamic+private.md +2 -0
  49. package/src/types/synthetic/$env+dynamic+public.md +2 -0
  50. package/src/utils/error.js +17 -1
  51. package/src/utils/routing.js +47 -1
  52. package/src/utils/url.js +45 -27
  53. package/src/version.js +1 -1
  54. package/types/index.d.ts +171 -118
  55. package/types/index.d.ts.map +9 -5
  56. package/src/utils/platform.js +0 -1
  57. package/src/utils/promises.js +0 -61
@@ -1,6 +1,10 @@
1
1
  export const SNAPSHOT_KEY = 'sveltekit:snapshot';
2
2
  export const SCROLL_KEY = 'sveltekit:scroll';
3
- export const INDEX_KEY = 'sveltekit:index';
3
+ export const STATES_KEY = 'sveltekit:states';
4
+ export const PAGE_URL_KEY = 'sveltekit:pageurl';
5
+
6
+ export const HISTORY_INDEX = 'sveltekit:history';
7
+ export const NAVIGATION_INDEX = 'sveltekit:navigation';
4
8
 
5
9
  export const PRELOAD_PRIORITIES = /** @type {const} */ ({
6
10
  tap: 1,
@@ -1,10 +1,11 @@
1
1
  /**
2
2
  * Read a value from `sessionStorage`
3
3
  * @param {string} key
4
+ * @param {(value: string) => any} parse
4
5
  */
5
- export function get(key) {
6
+ export function get(key, parse = JSON.parse) {
6
7
  try {
7
- return JSON.parse(sessionStorage[key]);
8
+ return parse(sessionStorage[key]);
8
9
  } catch {
9
10
  // do nothing
10
11
  }
@@ -14,11 +15,12 @@ export function get(key) {
14
15
  * Write a value to `sessionStorage`
15
16
  * @param {string} key
16
17
  * @param {any} value
18
+ * @param {(value: any) => string} stringify
17
19
  */
18
- export function set(key, value) {
19
- const json = JSON.stringify(value);
20
+ export function set(key, value, stringify = JSON.stringify) {
21
+ const data = stringify(value);
20
22
  try {
21
- sessionStorage[key] = json;
23
+ sessionStorage[key] = data;
22
24
  } catch {
23
25
  // do nothing
24
26
  }
@@ -21,7 +21,13 @@ export function init(opts) {
21
21
  */
22
22
  export function client_method(key) {
23
23
  if (!BROWSER) {
24
- if (key === 'before_navigate' || key === 'after_navigate' || key === 'on_navigate') {
24
+ if (
25
+ key === 'before_navigate' ||
26
+ key === 'after_navigate' ||
27
+ key === 'on_navigate' ||
28
+ key === 'push_state' ||
29
+ key === 'replace_state'
30
+ ) {
25
31
  // @ts-expect-error doesn't recognize that both keys here return void so expects a async function
26
32
  return () => {};
27
33
  } else {
@@ -7,7 +7,9 @@ import {
7
7
  invalidate,
8
8
  invalidateAll,
9
9
  preloadCode,
10
- preloadData
10
+ preloadData,
11
+ pushState,
12
+ replaceState
11
13
  } from '../app/navigation.js';
12
14
  import { SvelteComponent } from 'svelte';
13
15
  import { ClientHooks, CSRPageNode, CSRPageNodeLoader, CSRRoute, TrailingSlash, Uses } from 'types';
@@ -51,6 +53,8 @@ export interface Client {
51
53
  invalidate_all: typeof invalidateAll;
52
54
  preload_code: typeof preloadCode;
53
55
  preload_data: typeof preloadData;
56
+ push_state: typeof pushState;
57
+ replace_state: typeof replaceState;
54
58
  apply_action: typeof applyAction;
55
59
 
56
60
  // private API
@@ -92,7 +96,7 @@ export type NavigationFinished = {
92
96
  props: {
93
97
  constructors: Array<typeof SvelteComponent>;
94
98
  components?: Array<SvelteComponent>;
95
- page?: Page;
99
+ page: Page;
96
100
  form?: Record<string, any> | null;
97
101
  [key: `data_${number}`]: Record<string, any>;
98
102
  };
@@ -8,16 +8,18 @@ import { PRELOAD_PRIORITIES } from './constants.js';
8
8
 
9
9
  export const origin = BROWSER ? location.origin : '';
10
10
 
11
- /** @param {HTMLDocument} doc */
12
- export function get_base_uri(doc) {
13
- let baseURI = doc.baseURI;
11
+ /** @param {string | URL} url */
12
+ export function resolve_url(url) {
13
+ if (url instanceof URL) return url;
14
+
15
+ let baseURI = document.baseURI;
14
16
 
15
17
  if (!baseURI) {
16
- const baseTags = doc.getElementsByTagName('base');
17
- baseURI = baseTags.length ? baseTags[0].href : doc.URL;
18
+ const baseTags = document.getElementsByTagName('base');
19
+ baseURI = baseTags.length ? baseTags[0].href : document.URL;
18
20
  }
19
21
 
20
- return baseURI;
22
+ return new URL(url, baseURI);
21
23
  }
22
24
 
23
25
  export function scroll_state() {
@@ -147,7 +149,7 @@ export function get_link_info(a, base) {
147
149
  */
148
150
  export function get_router_options(element) {
149
151
  /** @type {ValidLinkOptions<'keepfocus'> | null} */
150
- let keep_focus = null;
152
+ let keepfocus = null;
151
153
 
152
154
  /** @type {ValidLinkOptions<'noscroll'> | null} */
153
155
  let noscroll = null;
@@ -170,7 +172,7 @@ export function get_router_options(element) {
170
172
  while (el && el !== document.documentElement) {
171
173
  if (preload_code === null) preload_code = link_option(el, 'preload-code');
172
174
  if (preload_data === null) preload_data = link_option(el, 'preload-data');
173
- if (keep_focus === null) keep_focus = link_option(el, 'keepfocus');
175
+ if (keepfocus === null) keepfocus = link_option(el, 'keepfocus');
174
176
  if (noscroll === null) noscroll = link_option(el, 'noscroll');
175
177
  if (reload === null) reload = link_option(el, 'reload');
176
178
  if (replace_state === null) replace_state = link_option(el, 'replacestate');
@@ -188,14 +190,14 @@ export function get_router_options(element) {
188
190
  case 'false':
189
191
  return false;
190
192
  default:
191
- return null;
193
+ return undefined;
192
194
  }
193
195
  }
194
196
 
195
197
  return {
196
198
  preload_code: levels[preload_code ?? 'off'],
197
199
  preload_data: levels[preload_data ?? 'off'],
198
- keep_focus: get_option_state(keep_focus),
200
+ keepfocus: get_option_state(keepfocus),
199
201
  noscroll: get_option_state(noscroll),
200
202
  reload: get_option_state(reload),
201
203
  replace_state: get_option_state(replace_state)
@@ -30,15 +30,20 @@ export class Redirect {
30
30
  }
31
31
  }
32
32
 
33
- export class NotFound extends Error {
33
+ /**
34
+ * An error that was thrown from within the SvelteKit runtime that is not fatal and doesn't result in a 500, such as a 404.
35
+ * `SvelteKitError` goes through `handleError`.
36
+ */
37
+ export class SvelteKitError extends Error {
34
38
  /**
35
- * @param {string} pathname
39
+ * @param {number} status
40
+ * @param {string} text
41
+ * @param {string} message
36
42
  */
37
- constructor(pathname) {
38
- super();
39
-
40
- this.status = 404;
41
- this.message = `Not found: ${pathname}`;
43
+ constructor(status, text, message) {
44
+ super(message);
45
+ this.status = status;
46
+ this.text = text;
42
47
  }
43
48
  }
44
49
 
@@ -48,7 +53,7 @@ export class NotFound extends Error {
48
53
  export class ActionFailure {
49
54
  /**
50
55
  * @param {number} status
51
- * @param {T} [data]
56
+ * @param {T} data
52
57
  */
53
58
  constructor(status, data) {
54
59
  this.status = status;
@@ -66,6 +71,7 @@ export class ActionFailure {
66
71
  * ActionFailure: typeof ActionFailure;
67
72
  * HttpError: typeof HttpError;
68
73
  * Redirect: typeof Redirect;
74
+ * SvelteKitError: typeof SvelteKitError;
69
75
  * }} implementations
70
76
  */
71
77
  export function replace_implementations(implementations) {
@@ -75,4 +81,6 @@ export function replace_implementations(implementations) {
75
81
  HttpError = implementations.HttpError; // eslint-disable-line no-class-assign
76
82
  // @ts-expect-error
77
83
  Redirect = implementations.Redirect; // eslint-disable-line no-class-assign
84
+ // @ts-expect-error
85
+ SvelteKitError = implementations.SvelteKitError; // eslint-disable-line no-class-assign
78
86
  }
@@ -1,6 +1,5 @@
1
1
  import { parse, serialize } from 'cookie';
2
- import { normalize_path, resolve } from '../../utils/url.js';
3
- import { warn_with_callsite } from './utils.js';
2
+ import { add_data_suffix, normalize_path, resolve } from '../../utils/url.js';
4
3
 
5
4
  /**
6
5
  * Tracks all cookies set during dev mode so we can emit warnings
@@ -15,24 +14,11 @@ const cookie_paths = {};
15
14
  */
16
15
  const MAX_COOKIE_SIZE = 4129;
17
16
 
18
- /**
19
- *
20
- * @param {import('cookie').CookieSerializeOptions} opts
21
- * @param {'set' | 'delete' | 'serialize'} method
22
- */
23
- function deprecate_missing_path(opts, method) {
24
- if (opts.path === undefined) {
25
- warn_with_callsite(
26
- `Calling \`cookies.${method}(...)\` without specifying a \`path\` is deprecated, and will be disallowed in SvelteKit 2.0. Relative paths can be used`,
27
- 1
28
- );
29
- }
30
-
31
- if (opts.path === '') {
32
- warn_with_callsite(
33
- `Calling \`cookies.${method}(...)\` with \`path: ''\` will behave differently in SvelteKit 2.0. Instead of using the browser default behaviour, it will set the cookie path to the current pathname`,
34
- 1
35
- );
17
+ // TODO 3.0 remove this check
18
+ /** @param {import('./page/types.js').Cookie['options']} options */
19
+ function validate_options(options) {
20
+ if (options?.path === undefined) {
21
+ throw new Error('You must specify a `path` when setting, deleting or serializing cookies');
36
22
  }
37
23
  }
38
24
 
@@ -46,8 +32,6 @@ export function get_cookies(request, url, trailing_slash) {
46
32
  const initial_cookies = parse(header, { decode: (value) => value });
47
33
 
48
34
  const normalized_url = normalize_path(url.pathname, trailing_slash);
49
- // Emulate browser-behavior: if the cookie is set at '/foo/bar', its path is '/foo'
50
- const default_path = normalized_url.split('/').slice(0, -1).join('/') || '/';
51
35
 
52
36
  /** @type {Record<string, import('./page/types.js').Cookie>} */
53
37
  const new_cookies = {};
@@ -126,39 +110,37 @@ export function get_cookies(request, url, trailing_slash) {
126
110
  /**
127
111
  * @param {string} name
128
112
  * @param {string} value
129
- * @param {import('cookie').CookieSerializeOptions} opts
113
+ * @param {import('./page/types.js').Cookie['options']} options
130
114
  */
131
- set(name, value, opts = {}) {
132
- deprecate_missing_path(opts, 'set');
133
- set_internal(name, value, { ...defaults, ...opts });
115
+ set(name, value, options) {
116
+ validate_options(options);
117
+ set_internal(name, value, { ...defaults, ...options });
134
118
  },
135
119
 
136
120
  /**
137
121
  * @param {string} name
138
- * @param {import('cookie').CookieSerializeOptions} opts
122
+ * @param {import('./page/types.js').Cookie['options']} options
139
123
  */
140
- delete(name, opts = {}) {
141
- deprecate_missing_path(opts, 'delete');
142
-
143
- cookies.set(name, '', {
144
- path: default_path, // TODO 2.0 remove this
145
- ...opts,
146
- maxAge: 0
147
- });
124
+ delete(name, options) {
125
+ validate_options(options);
126
+ cookies.set(name, '', { ...options, maxAge: 0 });
148
127
  },
149
128
 
150
129
  /**
151
130
  * @param {string} name
152
131
  * @param {string} value
153
- * @param {import('cookie').CookieSerializeOptions} opts
132
+ * @param {import('./page/types.js').Cookie['options']} options
154
133
  */
155
- serialize(name, value, opts = {}) {
156
- deprecate_missing_path(opts, 'serialize');
134
+ serialize(name, value, options) {
135
+ validate_options(options);
136
+
137
+ let path = options.path;
138
+
139
+ if (!options.domain || options.domain === url.hostname) {
140
+ path = resolve(normalized_url, path);
141
+ }
157
142
 
158
- return serialize(name, value, {
159
- ...defaults,
160
- ...opts
161
- });
143
+ return serialize(name, value, { ...defaults, ...options, path });
162
144
  }
163
145
  };
164
146
 
@@ -199,27 +181,16 @@ export function get_cookies(request, url, trailing_slash) {
199
181
  /**
200
182
  * @param {string} name
201
183
  * @param {string} value
202
- * @param {import('cookie').CookieSerializeOptions} opts
184
+ * @param {import('./page/types.js').Cookie['options']} options
203
185
  */
204
- function set_internal(name, value, opts) {
205
- let path = opts.path;
186
+ function set_internal(name, value, options) {
187
+ let path = options.path;
206
188
 
207
- if (!opts.domain || opts.domain === url.hostname) {
208
- if (path) {
209
- if (path[0] === '.') path = resolve(url.pathname, path);
210
- } else {
211
- path = default_path;
212
- }
189
+ if (!options.domain || options.domain === url.hostname) {
190
+ path = resolve(normalized_url, path);
213
191
  }
214
192
 
215
- new_cookies[name] = {
216
- name,
217
- value,
218
- options: {
219
- ...opts,
220
- path
221
- }
222
- };
193
+ new_cookies[name] = { name, value, options: { ...options, path } };
223
194
 
224
195
  if (__SVELTEKIT_DEV__) {
225
196
  const serialized = serialize(name, value, new_cookies[name].options);
@@ -230,10 +201,8 @@ export function get_cookies(request, url, trailing_slash) {
230
201
  cookie_paths[name] ??= new Set();
231
202
 
232
203
  if (!value) {
233
- // @ts-expect-error temporary
234
204
  cookie_paths[name].delete(path);
235
205
  } else {
236
- // @ts-expect-error temporary
237
206
  cookie_paths[name].add(path);
238
207
  }
239
208
  }
@@ -276,6 +245,14 @@ export function add_cookies_to_headers(headers, cookies) {
276
245
  for (const new_cookie of cookies) {
277
246
  const { name, value, options } = new_cookie;
278
247
  headers.append('set-cookie', serialize(name, value, options));
248
+
249
+ // special case — for routes ending with .html, the route data lives in a sibling
250
+ // `.html__data.json` file rather than a child `/__data.json` file, which means
251
+ // we need to duplicate the cookie
252
+ if (options.path.endsWith('.html')) {
253
+ const path = add_data_suffix(options.path);
254
+ headers.append('set-cookie', serialize(name, value, { ...options, path }));
255
+ }
279
256
  }
280
257
  }
281
258
 
@@ -1,4 +1,4 @@
1
- import { HttpError, Redirect } from '../../control.js';
1
+ import { HttpError, SvelteKitError, Redirect } from '../../control.js';
2
2
  import { normalize_error } from '../../../utils/error.js';
3
3
  import { once } from '../../../utils/functions.js';
4
4
  import { load_server_data } from '../page/load_data.js';
@@ -76,8 +76,7 @@ export async function render_data(
76
76
  }
77
77
  }
78
78
  return data;
79
- },
80
- track_server_fetches: options.track_server_fetches
79
+ }
81
80
  });
82
81
  } catch (e) {
83
82
  aborted = true;
@@ -110,7 +109,10 @@ export async function render_data(
110
109
  return /** @type {import('types').ServerErrorNode} */ ({
111
110
  type: 'error',
112
111
  error: await handle_error_and_jsonify(event, options, error),
113
- status: error instanceof HttpError ? error.status : undefined
112
+ status:
113
+ error instanceof HttpError || error instanceof SvelteKitError
114
+ ? error.status
115
+ : undefined
114
116
  });
115
117
  })
116
118
  )
@@ -0,0 +1,29 @@
1
+ import { public_env } from '../shared-server.js';
2
+
3
+ /** @type {string} */
4
+ let body;
5
+
6
+ /** @type {string} */
7
+ let etag;
8
+
9
+ /** @type {Headers} */
10
+ let headers;
11
+
12
+ /**
13
+ * @param {Request} request
14
+ * @returns {Response}
15
+ */
16
+ export function get_public_env(request) {
17
+ body ??= `export const env=${JSON.stringify(public_env)}`;
18
+ etag ??= `W/${Date.now()}`;
19
+ headers ??= new Headers({
20
+ 'content-type': 'application/javascript; charset=utf-8',
21
+ etag
22
+ });
23
+
24
+ if (request.headers.get('if-none-match') === etag) {
25
+ return new Response(undefined, { status: 304, headers });
26
+ }
27
+
28
+ return new Response(body, { headers });
29
+ }
@@ -9,7 +9,7 @@ import * as paths from '__sveltekit/paths';
9
9
  * manifest: import('@sveltejs/kit').SSRManifest;
10
10
  * state: import('types').SSRState;
11
11
  * get_cookie_header: (url: URL, header: string | null) => string;
12
- * set_internal: (name: string, value: string, opts: import('cookie').CookieSerializeOptions) => void;
12
+ * set_internal: (name: string, value: string, opts: import('./page/types.js').Cookie['options']) => void;
13
13
  * }} opts
14
14
  * @returns {typeof fetch}
15
15
  */
@@ -134,12 +134,13 @@ export function create_fetch({ event, options, manifest, state, get_cookie_heade
134
134
  for (const str of set_cookie_parser.splitCookiesString(set_cookie)) {
135
135
  const { name, value, ...options } = set_cookie_parser.parseString(str);
136
136
 
137
+ const path = options.path ?? (url.pathname.split('/').slice(0, -1).join('/') || '/');
138
+
137
139
  // options.sameSite is string, something more specific is required - type cast is safe
138
- set_internal(
139
- name,
140
- value,
141
- /** @type {import('cookie').CookieSerializeOptions} */ (options)
142
- );
140
+ set_internal(name, value, {
141
+ path,
142
+ .../** @type {import('cookie').CookieSerializeOptions} */ (options)
143
+ });
143
144
  }
144
145
  }
145
146
 
@@ -1,8 +1,18 @@
1
1
  import { respond } from './respond.js';
2
- import { set_private_env, set_public_env } from '../shared-server.js';
2
+ import { set_private_env, set_public_env, set_safe_public_env } from '../shared-server.js';
3
3
  import { options, get_hooks } from '__SERVER__/internal.js';
4
4
  import { DEV } from 'esm-env';
5
5
  import { filter_private_env, filter_public_env } from '../../utils/env.js';
6
+ import { building } from '../app/environment.js';
7
+
8
+ /** @type {ProxyHandler<{ type: 'public' | 'private' }>} */
9
+ const prerender_env_handler = {
10
+ get({ type }, prop) {
11
+ throw new Error(
12
+ `Cannot read values from $env/dynamic/${type} while prerendering (attempted to read env.${prop.toString()}). Use $env/static/${type} instead`
13
+ );
14
+ }
15
+ };
6
16
 
7
17
  export class Server {
8
18
  /** @type {import('types').SSROptions} */
@@ -27,19 +37,19 @@ export class Server {
27
37
  // Take care: Some adapters may have to call `Server.init` per-request to set env vars,
28
38
  // so anything that shouldn't be rerun should be wrapped in an `if` block to make sure it hasn't
29
39
  // been done already.
40
+
30
41
  // set env, in case it's used in initialisation
31
- set_private_env(
32
- filter_private_env(env, {
33
- public_prefix: this.#options.env_public_prefix,
34
- private_prefix: this.#options.env_private_prefix
35
- })
36
- );
37
- set_public_env(
38
- filter_public_env(env, {
39
- public_prefix: this.#options.env_public_prefix,
40
- private_prefix: this.#options.env_private_prefix
41
- })
42
- );
42
+ const prefixes = {
43
+ public_prefix: this.#options.env_public_prefix,
44
+ private_prefix: this.#options.env_private_prefix
45
+ };
46
+
47
+ const private_env = filter_private_env(env, prefixes);
48
+ const public_env = filter_public_env(env, prefixes);
49
+
50
+ set_private_env(building ? new Proxy({ type: 'private' }, prerender_env_handler) : private_env);
51
+ set_public_env(building ? new Proxy({ type: 'public' }, prerender_env_handler) : public_env);
52
+ set_safe_public_env(public_env);
43
53
 
44
54
  if (!this.#options.hooks) {
45
55
  try {
@@ -71,13 +81,6 @@ export class Server {
71
81
  * @param {import('types').RequestOptions} options
72
82
  */
73
83
  async respond(request, options) {
74
- // TODO this should probably have been removed for 1.0 — i think we can get rid of it?
75
- if (!(request instanceof Request)) {
76
- throw new Error(
77
- 'The first argument to server.respond must be a Request object. See https://github.com/sveltejs/kit/pull/3384 for details'
78
- );
79
- }
80
-
81
84
  return respond(request, this.#options, this.#manifest, {
82
85
  ...options,
83
86
  error: false,
@@ -1,8 +1,8 @@
1
1
  import * as devalue from 'devalue';
2
- import { error, json } from '../../../exports/index.js';
3
- import { normalize_error } from '../../../utils/error.js';
2
+ import { json } from '../../../exports/index.js';
3
+ import { get_status, normalize_error } from '../../../utils/error.js';
4
4
  import { is_form_content_type, negotiate } from '../../../utils/http.js';
5
- import { HttpError, Redirect, ActionFailure } from '../../control.js';
5
+ import { HttpError, Redirect, ActionFailure, SvelteKitError } from '../../control.js';
6
6
  import { handle_error_and_jsonify } from '../utils.js';
7
7
 
8
8
  /** @param {import('@sveltejs/kit').RequestEvent} event */
@@ -24,8 +24,11 @@ export async function handle_action_json_request(event, options, server) {
24
24
  const actions = server?.actions;
25
25
 
26
26
  if (!actions) {
27
- // TODO should this be a different error altogether?
28
- const no_actions_error = error(405, 'POST method not allowed. No actions exist for this page');
27
+ const no_actions_error = new SvelteKitError(
28
+ 405,
29
+ 'Method Not Allowed',
30
+ 'POST method not allowed. No actions exist for this page'
31
+ );
29
32
  return action_json(
30
33
  {
31
34
  type: 'error',
@@ -81,7 +84,7 @@ export async function handle_action_json_request(event, options, server) {
81
84
  error: await handle_error_and_jsonify(event, options, check_incorrect_fail_use(err))
82
85
  },
83
86
  {
84
- status: err instanceof HttpError ? err.status : 500
87
+ status: get_status(err)
85
88
  }
86
89
  );
87
90
  }
@@ -139,7 +142,11 @@ export async function handle_action_request(event, server) {
139
142
  });
140
143
  return {
141
144
  type: 'error',
142
- error: error(405, 'POST method not allowed. No actions exist for this page')
145
+ error: new SvelteKitError(
146
+ 405,
147
+ 'Method Not Allowed',
148
+ 'POST method not allowed. No actions exist for this page'
149
+ )
143
150
  };
144
151
  }
145
152
 
@@ -198,7 +205,7 @@ function check_named_default_separate(actions) {
198
205
  /**
199
206
  * @param {import('@sveltejs/kit').RequestEvent} event
200
207
  * @param {NonNullable<import('types').SSRNode['server']['actions']>} actions
201
- * @throws {Redirect | ActionFailure | HttpError | Error}
208
+ * @throws {Redirect | HttpError | SvelteKitError | Error}
202
209
  */
203
210
  async function call_action(event, actions) {
204
211
  const url = new URL(event.request.url);
@@ -216,12 +223,16 @@ async function call_action(event, actions) {
216
223
 
217
224
  const action = actions[name];
218
225
  if (!action) {
219
- throw new Error(`No action with name '${name}' found`);
226
+ throw new SvelteKitError(404, 'Not Found', `No action with name '${name}' found`);
220
227
  }
221
228
 
222
229
  if (!is_form_content_type(event.request)) {
223
- throw new Error(
224
- `Actions expect form-encoded data (received ${event.request.headers.get('content-type')})`
230
+ throw new SvelteKitError(
231
+ 415,
232
+ 'Unsupported Media Type',
233
+ `Form actions expect form-encoded data — received ${event.request.headers.get(
234
+ 'content-type'
235
+ )}`
225
236
  );
226
237
  }
227
238
 
@@ -231,13 +242,11 @@ async function call_action(event, actions) {
231
242
  /** @param {any} data */
232
243
  function validate_action_return(data) {
233
244
  if (data instanceof Redirect) {
234
- throw new Error('Cannot `return redirect(...)` — use `throw redirect(...)` instead');
245
+ throw new Error('Cannot `return redirect(...)` — use `redirect(...)` instead');
235
246
  }
236
247
 
237
248
  if (data instanceof HttpError) {
238
- throw new Error(
239
- 'Cannot `return error(...)` — use `throw error(...)` or `return fail(...)` instead'
240
- );
249
+ throw new Error('Cannot `return error(...)` — use `error(...)` or `return fail(...)` instead');
241
250
  }
242
251
  }
243
252
 
@@ -1,8 +1,8 @@
1
1
  import { text } from '../../../exports/index.js';
2
2
  import { compact } from '../../../utils/array.js';
3
- import { normalize_error } from '../../../utils/error.js';
3
+ import { get_status, normalize_error } from '../../../utils/error.js';
4
4
  import { add_data_suffix } from '../../../utils/url.js';
5
- import { HttpError, Redirect } from '../../control.js';
5
+ import { Redirect } from '../../control.js';
6
6
  import { redirect_response, static_error_page, handle_error_and_jsonify } from '../utils.js';
7
7
  import {
8
8
  handle_action_json_request,
@@ -65,8 +65,7 @@ export async function render_page(event, page, options, manifest, state, resolve
65
65
  return redirect_response(action_result.status, action_result.location);
66
66
  }
67
67
  if (action_result?.type === 'error') {
68
- const error = action_result.error;
69
- status = error instanceof HttpError ? error.status : 500;
68
+ status = get_status(action_result.error);
70
69
  }
71
70
  if (action_result?.type === 'failure') {
72
71
  status = action_result.status;
@@ -78,7 +77,7 @@ export async function render_page(event, page, options, manifest, state, resolve
78
77
 
79
78
  // it's crucial that we do this before returning the non-SSR response, otherwise
80
79
  // SvelteKit will erroneously believe that the path has been prerendered,
81
- // causing functions to be omitted from the manifesst generated later
80
+ // causing functions to be omitted from the manifest generated later
82
81
  const should_prerender = get_option(nodes, 'prerender') ?? false;
83
82
  if (should_prerender) {
84
83
  const mod = leaf_node.server;
@@ -150,8 +149,7 @@ export async function render_page(event, page, options, manifest, state, resolve
150
149
  if (parent) Object.assign(data, await parent.data);
151
150
  }
152
151
  return data;
153
- },
154
- track_server_fetches: options.track_server_fetches
152
+ }
155
153
  });
156
154
  } catch (e) {
157
155
  load_error = /** @type {Error} */ (e);
@@ -222,7 +220,7 @@ export async function render_page(event, page, options, manifest, state, resolve
222
220
  return redirect_response(err.status, err.location);
223
221
  }
224
222
 
225
- const status = err instanceof HttpError ? err.status : 500;
223
+ const status = get_status(err);
226
224
  const error = await handle_error_and_jsonify(event, options, err);
227
225
 
228
226
  while (i--) {