@sveltejs/kit 1.27.6 → 1.28.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.27.6",
3
+ "version": "1.28.0",
4
4
  "description": "The fastest way to build Svelte apps",
5
5
  "repository": {
6
6
  "type": "git",
@@ -33,8 +33,8 @@
33
33
  "@types/set-cookie-parser": "^2.4.2",
34
34
  "dts-buddy": "^0.2.4",
35
35
  "rollup": "^3.29.4",
36
- "svelte": "^4.2.2",
37
- "svelte-preprocess": "^5.0.4",
36
+ "svelte": "^4.2.7",
37
+ "svelte-preprocess": "^5.1.1",
38
38
  "typescript": "^4.9.4",
39
39
  "vite": "^4.4.9",
40
40
  "vitest": "^0.34.5"
@@ -39,6 +39,7 @@ export function write_root(manifest_data, output) {
39
39
  `${output}/root.svelte`,
40
40
  dedent`
41
41
  <!-- This file is generated by @sveltejs/kit — do not edit it! -->
42
+ ${isSvelte5Plus() ? '<svelte:options runes={true} />' : ''}
42
43
  <script>
43
44
  import { setContext, ${isSvelte5Plus() ? '' : 'afterUpdate, '}onMount, tick } from 'svelte';
44
45
  import { browser } from '$app/environment';
@@ -102,7 +102,7 @@ export async function preview(vite, vite_config, svelte_config) {
102
102
  return;
103
103
  }
104
104
 
105
- const { pathname } = new URL(/** @type {string} */ (req.url), 'http://dummy');
105
+ const { pathname, search } = new URL(/** @type {string} */ (req.url), 'http://dummy');
106
106
 
107
107
  let filename = normalizePath(
108
108
  join(svelte_config.kit.outDir, 'output/prerendered/pages' + pathname)
@@ -113,6 +113,7 @@ export async function preview(vite, vite_config, svelte_config) {
113
113
  const has_trailing_slash = pathname.endsWith('/');
114
114
  const html_filename = `${filename}${has_trailing_slash ? 'index.html' : '.html'}`;
115
115
 
116
+ /** @type {string | undefined} */
116
117
  let redirect;
117
118
 
118
119
  if (is_file(html_filename)) {
@@ -127,6 +128,7 @@ export async function preview(vite, vite_config, svelte_config) {
127
128
  }
128
129
 
129
130
  if (redirect) {
131
+ if (search) redirect += search;
130
132
  res.writeHead(307, {
131
133
  location: redirect
132
134
  });
@@ -559,7 +559,7 @@ export function create_client(app, target) {
559
559
  } else {
560
560
  data = (await node.universal.load.call(null, load_input)) ?? null;
561
561
  }
562
- data = data ? await unwrap_promises(data) : null;
562
+ data = data ? await unwrap_promises(data, route.id) : null;
563
563
  }
564
564
 
565
565
  return {
@@ -1,5 +1,6 @@
1
1
  import { parse, serialize } from 'cookie';
2
- import { normalize_path } from '../../utils/url.js';
2
+ import { normalize_path, resolve } from '../../utils/url.js';
3
+ import { warn_with_callsite } from './utils.js';
3
4
 
4
5
  /**
5
6
  * Tracks all cookies set during dev mode so we can emit warnings
@@ -14,6 +15,27 @@ const cookie_paths = {};
14
15
  */
15
16
  const MAX_COOKIE_SIZE = 4129;
16
17
 
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
+ );
36
+ }
37
+ }
38
+
17
39
  /**
18
40
  * @param {Request} request
19
41
  * @param {URL} url
@@ -107,6 +129,7 @@ export function get_cookies(request, url, trailing_slash) {
107
129
  * @param {import('cookie').CookieSerializeOptions} opts
108
130
  */
109
131
  set(name, value, opts = {}) {
132
+ deprecate_missing_path(opts, 'set');
110
133
  set_internal(name, value, { ...defaults, ...opts });
111
134
  },
112
135
 
@@ -115,7 +138,10 @@ export function get_cookies(request, url, trailing_slash) {
115
138
  * @param {import('cookie').CookieSerializeOptions} opts
116
139
  */
117
140
  delete(name, opts = {}) {
141
+ deprecate_missing_path(opts, 'delete');
142
+
118
143
  cookies.set(name, '', {
144
+ path: default_path, // TODO 2.0 remove this
119
145
  ...opts,
120
146
  maxAge: 0
121
147
  });
@@ -126,7 +152,9 @@ export function get_cookies(request, url, trailing_slash) {
126
152
  * @param {string} value
127
153
  * @param {import('cookie').CookieSerializeOptions} opts
128
154
  */
129
- serialize(name, value, opts) {
155
+ serialize(name, value, opts = {}) {
156
+ deprecate_missing_path(opts, 'serialize');
157
+
130
158
  return serialize(name, value, {
131
159
  ...defaults,
132
160
  ...opts
@@ -174,7 +202,15 @@ export function get_cookies(request, url, trailing_slash) {
174
202
  * @param {import('cookie').CookieSerializeOptions} opts
175
203
  */
176
204
  function set_internal(name, value, opts) {
177
- const path = opts.path ?? default_path;
205
+ let path = opts.path;
206
+
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
+ }
213
+ }
178
214
 
179
215
  new_cookies[name] = {
180
216
  name,
@@ -194,8 +230,10 @@ export function get_cookies(request, url, trailing_slash) {
194
230
  cookie_paths[name] ??= new Set();
195
231
 
196
232
  if (!value) {
233
+ // @ts-expect-error temporary
197
234
  cookie_paths[name].delete(path);
198
235
  } else {
236
+ // @ts-expect-error temporary
199
237
  cookie_paths[name].add(path);
200
238
  }
201
239
  }
@@ -14,7 +14,10 @@ import * as paths from '__sveltekit/paths';
14
14
  * @returns {typeof fetch}
15
15
  */
16
16
  export function create_fetch({ event, options, manifest, state, get_cookie_header, set_internal }) {
17
- return async (info, init) => {
17
+ /**
18
+ * @type {typeof fetch}
19
+ */
20
+ const server_fetch = async (info, init) => {
18
21
  const original_request = normalize_fetch_input(info, init, event.url);
19
22
 
20
23
  // some runtimes (e.g. Cloudflare) error if you access `request.mode`,
@@ -23,7 +26,7 @@ export function create_fetch({ event, options, manifest, state, get_cookie_heade
23
26
  let credentials =
24
27
  (info instanceof Request ? info.credentials : init?.credentials) ?? 'same-origin';
25
28
 
26
- return await options.hooks.handleFetch({
29
+ return options.hooks.handleFetch({
27
30
  event,
28
31
  request: original_request,
29
32
  fetch: async (info, init) => {
@@ -144,6 +147,15 @@ export function create_fetch({ event, options, manifest, state, get_cookie_heade
144
147
  }
145
148
  });
146
149
  };
150
+
151
+ // Don't make this function `async`! Otherwise, the user has to `catch` promises they use for streaming responses or else
152
+ // it will be an unhandled rejection. Instead, we add a `.catch(() => {})` ourselves below to this from happening.
153
+ return (input, init) => {
154
+ // See docs in fetch.js for why we need to do this
155
+ const response = server_fetch(input, init);
156
+ response.catch(() => {});
157
+ return response;
158
+ };
147
159
  }
148
160
 
149
161
  /**
@@ -125,9 +125,9 @@ export async function load_server_data({
125
125
  url
126
126
  });
127
127
 
128
- const data = result ? await unwrap_promises(result) : null;
128
+ const data = result ? await unwrap_promises(result, node.server_id) : null;
129
129
  if (__SVELTEKIT_DEV__) {
130
- validate_load_response(data, /** @type {string} */ (event.route.id));
130
+ validate_load_response(data, node.server_id);
131
131
  }
132
132
 
133
133
  done = true;
@@ -181,9 +181,9 @@ export async function load_data({
181
181
  parent
182
182
  });
183
183
 
184
- const data = result ? await unwrap_promises(result) : null;
184
+ const data = result ? await unwrap_promises(result, node.universal_id) : null;
185
185
  if (__SVELTEKIT_DEV__) {
186
- validate_load_response(data, /** @type {string} */ (event.route.id));
186
+ validate_load_response(data, node.universal_id);
187
187
  }
188
188
 
189
189
  return data;
@@ -195,13 +195,14 @@ export async function load_data({
195
195
  * @param {import('./types.js').Fetched[]} fetched
196
196
  * @param {boolean} csr
197
197
  * @param {Pick<Required<import('@sveltejs/kit').ResolveOptions>, 'filterSerializedResponseHeaders'>} resolve_opts
198
+ * @returns {typeof fetch}
198
199
  */
199
200
  export function create_universal_fetch(event, state, fetched, csr, resolve_opts) {
200
201
  /**
201
202
  * @param {URL | RequestInfo} input
202
203
  * @param {RequestInit} [init]
203
204
  */
204
- return async (input, init) => {
205
+ const universal_fetch = async (input, init) => {
205
206
  const cloned_body = input instanceof Request && input.body ? input.clone().body : null;
206
207
 
207
208
  const cloned_headers =
@@ -329,6 +330,15 @@ export function create_universal_fetch(event, state, fetched, csr, resolve_opts)
329
330
 
330
331
  return proxy;
331
332
  };
333
+
334
+ // Don't make this function `async`! Otherwise, the user has to `catch` promises they use for streaming responses or else
335
+ // it will be an unhandled rejection. Instead, we add a `.catch(() => {})` ourselves below to this from happening.
336
+ return (input, init) => {
337
+ // See docs in fetch.js for why we need to do this
338
+ const response = universal_fetch(input, init);
339
+ response.catch(() => {});
340
+ return response;
341
+ };
332
342
  }
333
343
 
334
344
  /**
@@ -350,12 +360,12 @@ async function stream_to_string(stream) {
350
360
 
351
361
  /**
352
362
  * @param {any} data
353
- * @param {string} [routeId]
363
+ * @param {string} [id]
354
364
  */
355
- function validate_load_response(data, routeId) {
365
+ function validate_load_response(data, id) {
356
366
  if (data != null && Object.getPrototypeOf(data) !== Object.prototype) {
357
367
  throw new Error(
358
- `a load function related to route '${routeId}' returned ${
368
+ `a load function in ${id} returned ${
359
369
  typeof data !== 'object'
360
370
  ? `a ${typeof data}`
361
371
  : data instanceof Response
@@ -159,3 +159,17 @@ export function stringify_uses(node) {
159
159
 
160
160
  return `"uses":{${uses.join(',')}}`;
161
161
  }
162
+
163
+ /**
164
+ * @param {string} message
165
+ * @param {number} offset
166
+ */
167
+ export function warn_with_callsite(message, offset = 0) {
168
+ if (DEV) {
169
+ const stack = fix_stack_trace(new Error()).split('\n');
170
+ const line = stack.at(3 + offset);
171
+ message += `\n${line}`;
172
+ }
173
+
174
+ console.warn(message);
175
+ }
@@ -1,10 +1,54 @@
1
+ import { DEV } from 'esm-env';
2
+
3
+ /** @type {Set<string> | null} */
4
+ let warned = null;
5
+
6
+ // TODO v2: remove all references to unwrap_promises
7
+
1
8
  /**
2
9
  * Given an object, return a new object where all top level values are awaited
3
10
  *
4
11
  * @param {Record<string, any>} object
12
+ * @param {string | null} [id]
5
13
  * @returns {Promise<Record<string, any>>}
6
14
  */
7
- export async function unwrap_promises(object) {
15
+ export async function unwrap_promises(object, id) {
16
+ if (DEV) {
17
+ /** @type {string[]} */
18
+ const promises = [];
19
+
20
+ for (const key in object) {
21
+ if (typeof object[key]?.then === 'function') {
22
+ promises.push(key);
23
+ }
24
+ }
25
+
26
+ if (promises.length > 0) {
27
+ if (!warned) warned = new Set();
28
+
29
+ const last = promises.pop();
30
+
31
+ const properties =
32
+ promises.length > 0
33
+ ? `${promises.map((p) => `"${p}"`).join(', ')} and "${last}" properties`
34
+ : `"${last}" property`;
35
+
36
+ const location = id ? `the \`load\` function in ${id}` : 'a `load` function';
37
+
38
+ const description = promises.length > 0 ? 'are promises' : 'is a promise';
39
+
40
+ const message = `The top-level ${properties} returned from ${location} ${description}.`;
41
+
42
+ if (!warned.has(message)) {
43
+ console.warn(
44
+ `\n${message}\n\nIn SvelteKit 2.0, these will longer be awaited automatically. To get rid of this warning, await all promises included as top-level properties in \`load\` return values.\n`
45
+ );
46
+
47
+ warned.add(message);
48
+ }
49
+ }
50
+ }
51
+
8
52
  for (const key in object) {
9
53
  if (typeof object[key]?.then === 'function') {
10
54
  return Object.fromEntries(
package/src/version.js CHANGED
@@ -1,4 +1,4 @@
1
1
  // generated during release, do not modify
2
2
 
3
3
  /** @type {string} */
4
- export const VERSION = '1.27.6';
4
+ export const VERSION = '1.28.0';