@sveltejs/kit 1.17.0 → 1.18.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.
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@sveltejs/kit",
3
- "version": "1.17.0",
3
+ "version": "1.18.0",
4
4
  "description": "The fastest way to build Svelte apps",
5
5
  "repository": {
6
6
  "type": "git",
@@ -111,6 +111,11 @@ const options = object(
111
111
  checkOrigin: boolean(true)
112
112
  }),
113
113
 
114
+ dangerZone: object({
115
+ // TODO 2.0: Remove this
116
+ trackServerFetches: boolean(false)
117
+ }),
118
+
114
119
  embedded: boolean(false),
115
120
 
116
121
  env: object({
@@ -34,6 +34,7 @@ export const options = {
34
34
  app_template_contains_nonce: ${template.includes('%sveltekit.nonce%')},
35
35
  csp: ${s(config.kit.csp)},
36
36
  csrf_check_origin: ${s(config.kit.csrf.checkOrigin)},
37
+ track_server_fetches: ${s(config.kit.dangerZone.trackServerFetches)},
37
38
  embedded: ${config.kit.embedded},
38
39
  env_public_prefix: '${config.kit.env.publicPrefix}',
39
40
  hooks: null, // added lazily, via \`get_hooks\`
@@ -186,7 +186,9 @@ export async function dev(vite, vite_config, svelte_config) {
186
186
  ) {
187
187
  try {
188
188
  query.set('inline', '');
189
- const mod = await vite.ssrLoadModule(`${url.pathname}${url.search}${url.hash}`);
189
+ const mod = await vite.ssrLoadModule(
190
+ `${decodeURI(url.pathname)}${url.search}${url.hash}`
191
+ );
190
192
  styles[dep.url] = mod.default;
191
193
  } catch {
192
194
  // this can happen with dynamically imported modules, I think
@@ -28,13 +28,20 @@ function warn_on_access(old_name, new_name, call_location) {
28
28
  );
29
29
  }
30
30
 
31
+ /**
32
+ * Shallow clone an element, so that we can access e.g. `form.action` without worrying
33
+ * that someone has added an `<input name="action">` (https://github.com/sveltejs/kit/issues/7593)
34
+ * @template {HTMLElement} T
35
+ * @param {T} element
36
+ * @returns {T}
37
+ */
38
+ function clone(element) {
39
+ return /** @type {T} */ (HTMLElement.prototype.cloneNode.call(element));
40
+ }
41
+
31
42
  /** @type {import('$app/forms').enhance} */
32
43
  export function enhance(form_element, submit = () => {}) {
33
- if (
34
- DEV &&
35
- /** @type {HTMLFormElement} */ (HTMLFormElement.prototype.cloneNode.call(form_element))
36
- .method !== 'post'
37
- ) {
44
+ if (DEV && clone(form_element).method !== 'post') {
38
45
  throw new Error('use:enhance can only be used on <form> fields with method="POST"');
39
46
  }
40
47
 
@@ -71,15 +78,25 @@ export function enhance(form_element, submit = () => {}) {
71
78
 
72
79
  const action = new URL(
73
80
  // We can't do submitter.formAction directly because that property is always set
74
- // We do cloneNode for avoid DOM clobbering - https://github.com/sveltejs/kit/issues/7593
75
81
  event.submitter?.hasAttribute('formaction')
76
82
  ? /** @type {HTMLButtonElement | HTMLInputElement} */ (event.submitter).formAction
77
- : /** @type {HTMLFormElement} */ (HTMLFormElement.prototype.cloneNode.call(form_element))
78
- .action
83
+ : clone(form_element).action
79
84
  );
80
85
 
81
86
  const form_data = new FormData(form_element);
82
87
 
88
+ if (DEV && clone(form_element).enctype !== 'multipart/form-data') {
89
+ for (const value of form_data.values()) {
90
+ if (value instanceof File) {
91
+ // TODO 2.0: Upgrade to `throw Error`
92
+ console.warn(
93
+ '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.'
94
+ );
95
+ break;
96
+ }
97
+ }
98
+ }
99
+
83
100
  const submitter_name = event.submitter?.getAttribute('name');
84
101
  if (submitter_name) {
85
102
  form_data.append(submitter_name, event.submitter?.getAttribute('value') ?? '');
@@ -76,7 +76,8 @@ export async function render_data(
76
76
  }
77
77
  }
78
78
  return data;
79
- }
79
+ },
80
+ track_server_fetches: options.track_server_fetches
80
81
  });
81
82
  } catch (e) {
82
83
  aborted = true;
@@ -150,7 +150,8 @@ export async function render_page(event, page, options, manifest, state, resolve
150
150
  if (parent) Object.assign(data, await parent.data);
151
151
  }
152
152
  return data;
153
- }
153
+ },
154
+ track_server_fetches: options.track_server_fetches
154
155
  });
155
156
  } catch (e) {
156
157
  load_error = /** @type {Error} */ (e);
@@ -10,10 +10,18 @@ import { validate_depends } from '../../shared.js';
10
10
  * state: import('types').SSRState;
11
11
  * node: import('types').SSRNode | undefined;
12
12
  * parent: () => Promise<Record<string, any>>;
13
+ * track_server_fetches: boolean;
13
14
  * }} opts
14
15
  * @returns {Promise<import('types').ServerDataNode | null>}
15
16
  */
16
- export async function load_server_data({ event, state, node, parent }) {
17
+ export async function load_server_data({
18
+ event,
19
+ state,
20
+ node,
21
+ parent,
22
+ // TODO 2.0: Remove this
23
+ track_server_fetches
24
+ }) {
17
25
  if (!node?.server) return null;
18
26
 
19
27
  let done = false;
@@ -51,7 +59,10 @@ export async function load_server_data({ event, state, node, parent }) {
51
59
  );
52
60
  }
53
61
 
54
- uses.dependencies.add(url.href);
62
+ // TODO 2.0: Remove this
63
+ if (track_server_fetches) {
64
+ uses.dependencies.add(url.href);
65
+ }
55
66
 
56
67
  return event.fetch(info, init);
57
68
  },
@@ -44,7 +44,8 @@ export async function respond_with_error({
44
44
  event,
45
45
  state,
46
46
  node: default_layout,
47
- parent: async () => ({})
47
+ parent: async () => ({}),
48
+ track_server_fetches: options.track_server_fetches
48
49
  });
49
50
 
50
51
  const server_data = await server_data_promise;
package/types/index.d.ts CHANGED
@@ -343,6 +343,16 @@ export interface KitConfig {
343
343
  */
344
344
  checkOrigin?: boolean;
345
345
  };
346
+ /**
347
+ * Here be dragons. Enable at your peril.
348
+ */
349
+ dangerZone?: {
350
+ /**
351
+ * Automatically add server-side `fetch`ed URLs to the `dependencies` map of `load` functions. This will expose secrets
352
+ * to the client if your URL contains them.
353
+ */
354
+ trackServerFetches?: boolean;
355
+ };
346
356
  /**
347
357
  * Whether or not the app is embedded inside a larger app. If `true`, SvelteKit will add its event listeners related to navigation etc on the parent of `%sveltekit.body%` instead of `window`, and will pass `params` from the server rather than inferring them from `location.pathname`.
348
358
  * @default false
@@ -333,6 +333,7 @@ export interface SSROptions {
333
333
  app_template_contains_nonce: boolean;
334
334
  csp: ValidatedConfig['kit']['csp'];
335
335
  csrf_check_origin: boolean;
336
+ track_server_fetches: boolean;
336
337
  embedded: boolean;
337
338
  env_public_prefix: string;
338
339
  hooks: ServerHooks;