@sveltejs/kit 1.30.3 → 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 +28 -15
  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 +166 -115
  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
@@ -7,8 +7,6 @@ import { loadEnv, normalizePath } from 'vite';
7
7
  import { getRequest, setResponse } from '../../../exports/node/index.js';
8
8
  import { installPolyfills } from '../../../exports/node/polyfills.js';
9
9
  import { SVELTE_KIT_ASSETS } from '../../../constants.js';
10
- import { should_polyfill } from '../../../utils/platform.js';
11
- import { not_found } from '../utils.js';
12
10
 
13
11
  /** @typedef {import('http').IncomingMessage} Req */
14
12
  /** @typedef {import('http').ServerResponse} Res */
@@ -20,12 +18,9 @@ import { not_found } from '../utils.js';
20
18
  * @param {import('types').ValidatedConfig} svelte_config
21
19
  */
22
20
  export async function preview(vite, vite_config, svelte_config) {
23
- if (should_polyfill) {
24
- installPolyfills();
25
- }
21
+ installPolyfills();
26
22
 
27
23
  const { paths } = svelte_config.kit;
28
- const base = paths.base;
29
24
  const assets = paths.assets ? SVELTE_KIT_ASSETS : paths.base;
30
25
 
31
26
  const protocol = vite_config.preview.https ? 'https' : 'http';
@@ -54,131 +49,84 @@ export async function preview(vite, vite_config, svelte_config) {
54
49
  });
55
50
 
56
51
  return () => {
57
- // generated client assets and the contents of `static`
52
+ // prerendered dependencies
58
53
  vite.middlewares.use(
59
- scoped(
60
- assets,
61
- sirv(join(svelte_config.kit.outDir, 'output/client'), {
62
- setHeaders: (res, pathname) => {
63
- // only apply to immutable directory, not e.g. version.json
64
- if (pathname.startsWith(`/${svelte_config.kit.appDir}/immutable`)) {
65
- res.setHeader('cache-control', 'public,max-age=31536000,immutable');
66
- }
67
- }
68
- })
69
- )
54
+ mutable(join(svelte_config.kit.outDir, 'output/prerendered/dependencies'))
70
55
  );
71
56
 
57
+ // prerendered pages (we can't just use sirv because we need to
58
+ // preserve the correct trailingSlash behaviour)
72
59
  vite.middlewares.use((req, res, next) => {
73
- const original_url = /** @type {string} */ (req.url);
74
- const { pathname, search } = new URL(original_url, 'http://dummy');
75
-
76
- // if `paths.base === '/a/b/c`, then the root route is `/a/b/c/`,
77
- // regardless of the `trailingSlash` route option
78
- if (base.length > 1 && pathname === base) {
79
- let location = base + '/';
80
- if (search) location += search;
81
- res.writeHead(307, {
82
- location
83
- });
60
+ let if_none_match_value = req.headers['if-none-match'];
61
+
62
+ if (if_none_match_value?.startsWith('W/"')) {
63
+ if_none_match_value = if_none_match_value.substring(2);
64
+ }
65
+
66
+ if (if_none_match_value === etag) {
67
+ res.statusCode = 304;
84
68
  res.end();
85
69
  return;
86
70
  }
87
71
 
88
- if (pathname.startsWith(base)) {
89
- next();
90
- } else {
91
- res.statusCode = 404;
92
- not_found(req, res, base);
93
- }
94
- });
72
+ const { pathname, search } = new URL(/** @type {string} */ (req.url), 'http://dummy');
95
73
 
96
- // prerendered dependencies
97
- vite.middlewares.use(
98
- scoped(base, mutable(join(svelte_config.kit.outDir, 'output/prerendered/dependencies')))
99
- );
100
-
101
- // prerendered pages (we can't just use sirv because we need to
102
- // preserve the correct trailingSlash behaviour)
103
- vite.middlewares.use(
104
- scoped(base, (req, res, next) => {
105
- let if_none_match_value = req.headers['if-none-match'];
74
+ let filename = normalizePath(
75
+ join(svelte_config.kit.outDir, 'output/prerendered/pages' + pathname)
76
+ );
77
+ let prerendered = is_file(filename);
106
78
 
107
- if (if_none_match_value?.startsWith('W/"')) {
108
- if_none_match_value = if_none_match_value.substring(2);
109
- }
79
+ if (!prerendered) {
80
+ const has_trailing_slash = pathname.endsWith('/');
81
+ const html_filename = `${filename}${has_trailing_slash ? 'index.html' : '.html'}`;
110
82
 
111
- if (if_none_match_value === etag) {
112
- res.statusCode = 304;
113
- res.end();
114
- return;
115
- }
83
+ /** @type {string | undefined} */
84
+ let redirect;
116
85
 
117
- const { pathname, search } = new URL(/** @type {string} */ (req.url), 'http://dummy');
118
-
119
- let filename = normalizePath(
120
- join(svelte_config.kit.outDir, 'output/prerendered/pages' + pathname)
121
- );
122
- let prerendered = is_file(filename);
123
-
124
- if (!prerendered) {
125
- const has_trailing_slash = pathname.endsWith('/');
126
- const html_filename = `${filename}${has_trailing_slash ? 'index.html' : '.html'}`;
127
-
128
- /** @type {string | undefined} */
129
- let redirect;
130
-
131
- if (is_file(html_filename)) {
132
- filename = html_filename;
133
- prerendered = true;
134
- } else if (has_trailing_slash) {
135
- if (is_file(filename.slice(0, -1) + '.html')) {
136
- redirect = pathname.slice(0, -1);
137
- }
138
- } else if (is_file(filename + '/index.html')) {
139
- redirect = pathname + '/';
86
+ if (is_file(html_filename)) {
87
+ filename = html_filename;
88
+ prerendered = true;
89
+ } else if (has_trailing_slash) {
90
+ if (is_file(filename.slice(0, -1) + '.html')) {
91
+ redirect = pathname.slice(0, -1);
140
92
  }
93
+ } else if (is_file(filename + '/index.html')) {
94
+ redirect = pathname + '/';
95
+ }
141
96
 
142
- if (redirect) {
143
- if (search) redirect += search;
144
- res.writeHead(307, {
145
- location: redirect
146
- });
97
+ if (redirect) {
98
+ if (search) redirect += search;
99
+ res.writeHead(307, {
100
+ location: redirect
101
+ });
147
102
 
148
- res.end();
103
+ res.end();
149
104
 
150
- return;
151
- }
105
+ return;
152
106
  }
107
+ }
153
108
 
154
- if (prerendered) {
155
- res.writeHead(200, {
156
- 'content-type': lookup(pathname) || 'text/html',
157
- etag
158
- });
109
+ if (prerendered) {
110
+ res.writeHead(200, {
111
+ 'content-type': lookup(pathname) || 'text/html',
112
+ etag
113
+ });
159
114
 
160
- fs.createReadStream(filename).pipe(res);
161
- } else {
162
- next();
163
- }
164
- })
165
- );
115
+ fs.createReadStream(filename).pipe(res);
116
+ } else {
117
+ next();
118
+ }
119
+ });
166
120
 
167
121
  // SSR
168
122
  vite.middlewares.use(async (req, res) => {
169
123
  const host = req.headers['host'];
124
+ req.url = req.originalUrl;
170
125
 
171
- let request;
172
-
173
- try {
174
- request = await getRequest({
175
- base: `${protocol}://${host}`,
176
- request: req
177
- });
178
- } catch (/** @type {any} */ err) {
179
- res.statusCode = err.status || 400;
180
- return res.end('Invalid request body');
181
- }
126
+ const request = await getRequest({
127
+ base: `${protocol}://${host}`,
128
+ request: req
129
+ });
182
130
 
183
131
  setResponse(
184
132
  res,
@@ -204,31 +152,9 @@ const mutable = (dir) =>
204
152
  ? sirv(dir, {
205
153
  etag: true,
206
154
  maxAge: 0
207
- })
155
+ })
208
156
  : (_req, _res, next) => next();
209
157
 
210
- /**
211
- * @param {string} scope
212
- * @param {Handler} handler
213
- * @returns {Handler}
214
- */
215
- function scoped(scope, handler) {
216
- if (scope === '') return handler;
217
-
218
- return (req, res, next) => {
219
- if (req.url?.startsWith(scope)) {
220
- const original_url = req.url;
221
- req.url = req.url.slice(scope.length);
222
- handler(req, res, () => {
223
- req.url = original_url;
224
- next();
225
- });
226
- } else {
227
- next();
228
- }
229
- };
230
- }
231
-
232
158
  /** @param {string} path */
233
159
  function is_file(path) {
234
160
  return fs.existsSync(path) && !fs.statSync(path).isDirectory();
@@ -49,20 +49,6 @@ export function deserialize(result) {
49
49
  return parsed;
50
50
  }
51
51
 
52
- /**
53
- * @param {string} old_name
54
- * @param {string} new_name
55
- * @param {string} call_location
56
- * @returns void
57
- */
58
- function warn_on_access(old_name, new_name, call_location) {
59
- if (!DEV) return;
60
- // TODO 2.0: Remove this code
61
- console.warn(
62
- `\`${old_name}\` has been deprecated in favor of \`${new_name}\`. \`${old_name}\` will be removed in a future version. (Called from ${call_location})`
63
- );
64
- }
65
-
66
52
  /**
67
53
  * Shallow clone an element, so that we can access e.g. `form.action` without worrying
68
54
  * that someone has added an `<input name="action">` (https://github.com/sveltejs/kit/issues/7593)
@@ -157,11 +143,9 @@ export function enhance(form_element, submit = () => {}) {
157
143
  if (DEV && clone(form_element).enctype !== 'multipart/form-data') {
158
144
  for (const value of form_data.values()) {
159
145
  if (value instanceof File) {
160
- // TODO 2.0: Upgrade to `throw Error`
161
- console.warn(
162
- 'Your form contains <input type="file"> fields, but is missing the `enctype="multipart/form-data"` attribute. This will lead to inconsistent behavior between enhanced and native forms. For more details, see https://github.com/sveltejs/kit/issues/9819. This will be upgraded to an error in v2.0.'
146
+ throw new Error(
147
+ 'Your form contains <input type="file"> fields, but is missing the necessary `enctype="multipart/form-data"` attribute. This will lead to inconsistent behavior between enhanced and native forms. For more details, see https://github.com/sveltejs/kit/issues/9819.'
163
148
  );
164
- break;
165
149
  }
166
150
  }
167
151
  }
@@ -176,21 +160,12 @@ export function enhance(form_element, submit = () => {}) {
176
160
  let cancelled = false;
177
161
  const cancel = () => (cancelled = true);
178
162
 
179
- // TODO 2.0: Remove `data` and `form`
180
163
  const callback =
181
164
  (await submit({
182
165
  action,
183
166
  cancel,
184
167
  controller,
185
- get data() {
186
- warn_on_access('data', 'formData', 'use:enhance submit function');
187
- return form_data;
188
- },
189
168
  formData: form_data,
190
- get form() {
191
- warn_on_access('form', 'formElement', 'use:enhance submit function');
192
- return form_element;
193
- },
194
169
  formElement: form_element,
195
170
  submitter: event.submitter
196
171
  })) ?? fallback_callback;
@@ -220,15 +195,7 @@ export function enhance(form_element, submit = () => {}) {
220
195
 
221
196
  callback({
222
197
  action,
223
- get data() {
224
- warn_on_access('data', 'formData', 'callback returned from use:enhance submit function');
225
- return form_data;
226
- },
227
198
  formData: form_data,
228
- get form() {
229
- warn_on_access('form', 'formElement', 'callback returned from use:enhance submit function');
230
- return form_element;
231
- },
232
199
  formElement: form_element,
233
200
  update: (opts) =>
234
201
  fallback_callback({
@@ -11,20 +11,13 @@ export const disableScrollHandling = /* @__PURE__ */ client_method('disable_scro
11
11
  * Returns a Promise that resolves when SvelteKit navigates (or fails to navigate, in which case the promise rejects) to the specified `url`.
12
12
  * For external URLs, use `window.location = url` instead of calling `goto(url)`.
13
13
  *
14
- * @type {(url: string | URL, opts?: {
15
- * replaceState?: boolean;
16
- * noScroll?: boolean;
17
- * keepFocus?: boolean;
18
- * invalidateAll?: boolean;
19
- * state?: any
20
- * }) => Promise<void>}
14
+ * @type {(url: string | URL, opts?: { replaceState?: boolean; noScroll?: boolean; keepFocus?: boolean; invalidateAll?: boolean; }) => Promise<void>}
21
15
  * @param {string | URL} url Where to navigate to. Note that if you've set [`config.kit.paths.base`](https://kit.svelte.dev/docs/configuration#paths) and the URL is root-relative, you need to prepend the base path if you want to navigate within the app.
22
16
  * @param {Object} [opts] Options related to the navigation
23
17
  * @param {boolean} [opts.replaceState] If `true`, will replace the current `history` entry rather than creating a new one with `pushState`
24
18
  * @param {boolean} [opts.noScroll] If `true`, the browser will maintain its scroll position rather than scrolling to the top of the page after navigation
25
19
  * @param {boolean} [opts.keepFocus] If `true`, the currently focused element will retain focus after navigation. Otherwise, focus will be reset to the body
26
- * @param {boolean} [invalidateAll] If `true`, all `load` functions of the page will be rerun. See https://kit.svelte.dev/docs/load#rerunning-load-functions for more info on invalidation.
27
- * @param {any} [opts.state] The state of the new/updated history entry
20
+ * @param {boolean} [opts.invalidateAll] If `true`, all `load` functions of the page will be rerun. See https://kit.svelte.dev/docs/load#rerunning-load-functions for more info on invalidation.
28
21
  * @returns {Promise<void>}
29
22
  */
30
23
  export const goto = /* @__PURE__ */ client_method('goto');
@@ -64,11 +57,11 @@ export const invalidateAll = /* @__PURE__ */ client_method('invalidate_all');
64
57
  *
65
58
  * This is the same behaviour that SvelteKit triggers when the user taps or mouses over an `<a>` element with `data-sveltekit-preload-data`.
66
59
  * If the next navigation is to `href`, the values returned from load will be used, making navigation instantaneous.
67
- * Returns a Promise that resolves when the preload is complete.
60
+ * Returns a Promise that resolves with the result of running the new route's `load` functions once the preload is complete.
68
61
  *
69
- * @type {(href: string) => Promise<void>}
62
+ * @type {(href: string) => Promise<Record<string, any>>}
70
63
  * @param {string} href Page to preload
71
- * @returns {Promise<void>}
64
+ * @returns {Promise<{ type: 'loaded'; status: number; data: Record<string, any> } | { type: 'redirect'; location: string }>}
72
65
  */
73
66
  export const preloadData = /* @__PURE__ */ client_method('preload_data');
74
67
 
@@ -81,8 +74,8 @@ export const preloadData = /* @__PURE__ */ client_method('preload_data');
81
74
  * Unlike `preloadData`, this won't call `load` functions.
82
75
  * Returns a Promise that resolves when the modules have been imported.
83
76
  *
84
- * @type {(...urls: string[]) => Promise<void>}
85
- * @param {...string[]} urls
77
+ * @type {(url: string) => Promise<void>}
78
+ * @param {string} url
86
79
  * @returns {Promise<void>}
87
80
  */
88
81
  export const preloadCode = /* @__PURE__ */ client_method('preload_code');
@@ -111,7 +104,7 @@ export const beforeNavigate = /* @__PURE__ */ client_method('before_navigate');
111
104
  * If a function (or a `Promise` that resolves to a function) is returned from the callback, it will be called once the DOM has updated.
112
105
  *
113
106
  * `onNavigate` must be called during a component initialization. It remains active as long as the component is mounted.
114
- * @type {(callback: (navigation: import('@sveltejs/kit').OnNavigate) => import('../../types/internal.js').MaybePromise<(() => void) | void>) => void}
107
+ * @type {(callback: (navigation: import('@sveltejs/kit').OnNavigate) => import('types').MaybePromise<(() => void) | void>) => void}
115
108
  * @param {(navigation: import('@sveltejs/kit').OnNavigate) => void} callback
116
109
  * @returns {void}
117
110
  */
@@ -126,3 +119,23 @@ export const onNavigate = /* @__PURE__ */ client_method('on_navigate');
126
119
  * @returns {void}
127
120
  */
128
121
  export const afterNavigate = /* @__PURE__ */ client_method('after_navigate');
122
+
123
+ /**
124
+ * Programmatically create a new history entry with the given `$page.state`. To use the current URL, you can pass `''` as the first argument. Used for [shallow routing](https://kit.svelte.dev/docs/shallow-routing).
125
+ *
126
+ * @type {(url: string | URL, state: App.PageState) => void}
127
+ * @param {string | URL} url
128
+ * @param {App.PageState} state
129
+ * @returns {void}
130
+ */
131
+ export const pushState = /* @__PURE__ */ client_method('push_state');
132
+
133
+ /**
134
+ * Programmatically replace the current history entry with the given `$page.state`. To use the current URL, you can pass `''` as the first argument. Used for [shallow routing](https://kit.svelte.dev/docs/shallow-routing).
135
+ *
136
+ * @type {(url: string | URL, state: App.PageState) => void}
137
+ * @param {string | URL} url
138
+ * @param {App.PageState} state
139
+ * @returns {void}
140
+ */
141
+ export const replaceState = /* @__PURE__ */ client_method('replace_state');
@@ -1,8 +1,6 @@
1
1
  export { base, assets } from '__sveltekit/paths';
2
2
  import { base } from '__sveltekit/paths';
3
- import { get_route_segments } from '../../utils/routing.js';
4
-
5
- const basic_param_pattern = /\[(\[)?(\.\.\.)?(\w+?)(?:=(\w+))?\]\]?/g;
3
+ import { resolve_route } from '../../utils/routing.js';
6
4
 
7
5
  /**
8
6
  * Populate a route ID with params to resolve a pathname.
@@ -21,30 +19,5 @@ const basic_param_pattern = /\[(\[)?(\.\.\.)?(\w+?)(?:=(\w+))?\]\]?/g;
21
19
  * @returns {string}
22
20
  */
23
21
  export function resolveRoute(id, params) {
24
- const segments = get_route_segments(id);
25
- return (
26
- base +
27
- '/' +
28
- segments
29
- .map((segment) =>
30
- segment.replace(basic_param_pattern, (_, optional, rest, name) => {
31
- const param_value = params[name];
32
-
33
- // This is nested so TS correctly narrows the type
34
- if (!param_value) {
35
- if (optional) return '';
36
- if (rest && param_value !== undefined) return '';
37
- throw new Error(`Missing parameter '${name}' in route ${id}`);
38
- }
39
-
40
- if (param_value.startsWith('/') || param_value.endsWith('/'))
41
- throw new Error(
42
- `Parameter '${name}' in route ${id} cannot start or end with a slash -- this would cause an invalid route like foo//bar`
43
- );
44
- return param_value;
45
- })
46
- )
47
- .filter(Boolean)
48
- .join('/')
49
- );
22
+ return base + resolve_route(id, params);
50
23
  }