@sveltejs/kit 2.52.0 → 2.52.2

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": "2.52.0",
3
+ "version": "2.52.2",
4
4
  "description": "SvelteKit is the fastest way to build Svelte apps",
5
5
  "keywords": [
6
6
  "framework",
@@ -23,12 +23,11 @@
23
23
  "@types/cookie": "^0.6.0",
24
24
  "acorn": "^8.14.1",
25
25
  "cookie": "^0.6.0",
26
- "devalue": "^5.6.2",
26
+ "devalue": "^5.6.3",
27
27
  "esm-env": "^1.2.2",
28
28
  "kleur": "^4.1.5",
29
29
  "magic-string": "^0.30.5",
30
30
  "mrmime": "^2.0.0",
31
- "sade": "^1.8.1",
32
31
  "set-cookie-parser": "^3.0.0",
33
32
  "sirv": "^3.0.0"
34
33
  },
@@ -41,7 +40,7 @@
41
40
  "@types/set-cookie-parser": "^2.4.7",
42
41
  "dts-buddy": "^0.6.2",
43
42
  "rollup": "^4.14.2",
44
- "svelte": "^5.48.4",
43
+ "svelte": "^5.51.5",
45
44
  "svelte-preprocess": "^6.0.0",
46
45
  "typescript": "^5.3.3",
47
46
  "vite": "^6.3.5",
package/src/cli.js CHANGED
@@ -1,7 +1,7 @@
1
1
  import fs from 'node:fs';
2
2
  import process from 'node:process';
3
+ import { parseArgs } from 'node:util';
3
4
  import colors from 'kleur';
4
- import sade from 'sade';
5
5
  import { load_config } from './core/config/index.js';
6
6
  import { coalesce_to_error } from './utils/error.js';
7
7
 
@@ -20,28 +20,76 @@ function handle_error(e) {
20
20
  }
21
21
 
22
22
  const pkg = JSON.parse(fs.readFileSync(new URL('../package.json', import.meta.url), 'utf-8'));
23
- const prog = sade('svelte-kit').version(pkg.version);
24
-
25
- prog
26
- .command('sync')
27
- .describe('Synchronise generated type definitions')
28
- .option('--mode', 'Specify a mode for loading environment variables', 'development')
29
- .action(async ({ mode }) => {
30
- const config_files = ['js', 'ts']
31
- .map((ext) => `svelte.config.${ext}`)
32
- .filter((f) => fs.existsSync(f));
33
- if (config_files.length === 0) {
34
- console.warn(`Missing Svelte config file in ${process.cwd()} — skipping`);
35
- return;
36
- }
37
-
38
- try {
39
- const config = await load_config();
40
- const sync = await import('./core/sync/sync.js');
41
- sync.all_types(config, mode);
42
- } catch (error) {
43
- handle_error(error);
44
- }
23
+
24
+ const help = `
25
+ Usage: svelte-kit <command> [options]
26
+
27
+ Commands:
28
+ sync Synchronise generated type definitions
29
+
30
+ Options:
31
+ --version, -v Show version number
32
+ --help, -h Show this help message
33
+
34
+ Sync Options:
35
+ --mode <mode> Specify a mode for loading environment variables (default: development)
36
+ `;
37
+
38
+ let parsed;
39
+ try {
40
+ parsed = parseArgs({
41
+ options: {
42
+ version: { type: 'boolean', short: 'v' },
43
+ help: { type: 'boolean', short: 'h' },
44
+ mode: { type: 'string', default: 'development' }
45
+ },
46
+ allowPositionals: true,
47
+ strict: true
45
48
  });
49
+ } catch (err) {
50
+ const error = /** @type {Error} */ (err);
51
+ console.error(colors.bold().red(`> ${error.message}`));
52
+ console.log(help);
53
+ process.exit(1);
54
+ }
55
+
56
+ const { values, positionals } = parsed;
57
+
58
+ if (values.version) {
59
+ console.log(pkg.version);
60
+ process.exit(0);
61
+ }
46
62
 
47
- prog.parse(process.argv, { unknown: (arg) => `Unknown option: ${arg}` });
63
+ if (values.help) {
64
+ console.log(help);
65
+ process.exit(0);
66
+ }
67
+
68
+ const command = positionals[0];
69
+
70
+ if (!command) {
71
+ console.log(help);
72
+ process.exit(0);
73
+ }
74
+
75
+ if (command === 'sync') {
76
+ const config_files = ['js', 'ts']
77
+ .map((ext) => `svelte.config.${ext}`)
78
+ .filter((f) => fs.existsSync(f));
79
+ if (config_files.length === 0) {
80
+ console.warn(`Missing Svelte config file in ${process.cwd()} — skipping`);
81
+ process.exit(0);
82
+ }
83
+
84
+ try {
85
+ const config = await load_config();
86
+ const sync = await import('./core/sync/sync.js');
87
+ sync.all_types(config, values.mode);
88
+ } catch (error) {
89
+ handle_error(error);
90
+ }
91
+ } else {
92
+ console.error(colors.bold().red(`> Unknown command: ${command}`));
93
+ console.log(help);
94
+ process.exit(1);
95
+ }
@@ -19,7 +19,7 @@ import { find_server_assets } from '../generate_manifest/find_server_assets.js';
19
19
  import { reserved } from '../env.js';
20
20
 
21
21
  const pipe = promisify(pipeline);
22
- const extensions = ['.html', '.js', '.mjs', '.json', '.css', '.svg', '.xml', '.wasm'];
22
+ const extensions = ['.html', '.js', '.mjs', '.json', '.css', '.svg', '.xml', '.wasm', '.txt'];
23
23
 
24
24
  /**
25
25
  * Creates the Builder which is passed to adapters for building the application.
@@ -1,6 +1,6 @@
1
1
  import fs from 'node:fs';
2
2
  import { mkdirp } from '../../../utils/filesystem.js';
3
- import { filter_fonts, find_deps, resolve_symlinks } from './utils.js';
3
+ import { create_function_as_string, filter_fonts, find_deps, resolve_symlinks } from './utils.js';
4
4
  import { s } from '../../../utils/misc.js';
5
5
  import { normalizePath } from 'vite';
6
6
  import { basename } from 'node:path';
@@ -78,8 +78,9 @@ export function build_server_nodes(
78
78
 
79
79
  // only convert to a function if we have adjusted any URLs
80
80
  if (css !== transformed_css) {
81
- return `function css(assets, base) { return \`${s(transformed_css).slice(1, -1)}\`; }`;
81
+ return create_function_as_string('css', ['assets', 'base'], transformed_css);
82
82
  }
83
+
83
84
  return s(css);
84
85
  };
85
86
  }
@@ -1,6 +1,7 @@
1
1
  import fs from 'node:fs';
2
2
  import path from 'node:path';
3
3
  import { normalizePath } from 'vite';
4
+ import { s } from '../../../utils/misc.js';
4
5
 
5
6
  /**
6
7
  * Adds transitive JS and CSS dependencies to the js and css inputs.
@@ -129,3 +130,18 @@ export function filter_fonts(assets) {
129
130
  export function assets_base(config) {
130
131
  return (config.paths.assets || config.paths.base || '.') + '/';
131
132
  }
133
+
134
+ /**
135
+ * Writes a function with arguments used by a template literal.
136
+ * This helps us store strings in a module and inject values at runtime.
137
+ * @param {string} name The name of the function
138
+ * @param {string[]} placeholder_names The names of the placeholders in the string
139
+ * @param {string} str A string with placeholders such as "Hello ${arg0}".
140
+ * It must have backticks and dollar signs escaped.
141
+ * @returns {string} The function written as a string
142
+ */
143
+ export function create_function_as_string(name, placeholder_names, str) {
144
+ str = s(str).slice(1, -1);
145
+ const args = placeholder_names ? placeholder_names.join(', ') : '';
146
+ return `function ${name}(${args}) { return \`${str}\`; }`;
147
+ }
@@ -110,6 +110,10 @@ export function form(id) {
110
110
 
111
111
  submitted = true;
112
112
 
113
+ // Increment pending count immediately so that `pending` reflects
114
+ // the in-progress state during async preflight validation
115
+ pending_count++;
116
+
113
117
  const validated = await preflight_schema?.['~standard'].validate(data);
114
118
 
115
119
  if (validated?.issues) {
@@ -118,9 +122,15 @@ export function form(id) {
118
122
  raw_issues,
119
123
  validated.issues.map((issue) => normalize_issue(issue, false))
120
124
  );
125
+ pending_count--;
121
126
  return;
122
127
  }
123
128
 
129
+ // Preflight passed - clear stale client-side preflight issues
130
+ if (preflight_schema) {
131
+ raw_issues = raw_issues.filter((issue) => issue.server);
132
+ }
133
+
124
134
  // TODO 3.0 remove this warning
125
135
  if (DEV) {
126
136
  const error = () => {
@@ -174,9 +184,6 @@ export function form(id) {
174
184
  entry.count++;
175
185
  }
176
186
 
177
- // Increment pending count when submission starts
178
- pending_count++;
179
-
180
187
  /** @type {Array<Query<any> | RemoteQueryOverride>} */
181
188
  let updates = [];
182
189
 
@@ -254,14 +254,30 @@ export async function deserialize_binary_form(request) {
254
254
  const file_offsets_buffer = await get_buffer(HEADER_BYTES + data_length, file_offsets_length);
255
255
  if (!file_offsets_buffer) throw deserialize_error('file offset table too short');
256
256
 
257
- file_offsets = /** @type {Array<number>} */ (
258
- JSON.parse(text_decoder.decode(file_offsets_buffer))
259
- );
257
+ const parsed_offsets = JSON.parse(text_decoder.decode(file_offsets_buffer));
258
+
259
+ if (
260
+ !Array.isArray(parsed_offsets) ||
261
+ parsed_offsets.some((n) => typeof n !== 'number' || !Number.isInteger(n) || n < 0)
262
+ ) {
263
+ throw deserialize_error('invalid file offset table');
264
+ }
265
+
266
+ file_offsets = /** @type {Array<number>} */ (parsed_offsets);
260
267
  files_start_offset = HEADER_BYTES + data_length + file_offsets_length;
261
268
  }
262
269
 
263
270
  const [data, meta] = devalue.parse(text_decoder.decode(data_buffer), {
264
271
  File: ([name, type, size, last_modified, index]) => {
272
+ if (
273
+ typeof name !== 'string' ||
274
+ typeof type !== 'string' ||
275
+ typeof size !== 'number' ||
276
+ typeof last_modified !== 'number' ||
277
+ typeof index !== 'number'
278
+ ) {
279
+ throw deserialize_error('invalid file metadata');
280
+ }
265
281
  if (files_start_offset + file_offsets[index] + size > content_length) {
266
282
  throw deserialize_error('file data overflow');
267
283
  }
package/src/utils/css.js CHANGED
@@ -1,5 +1,6 @@
1
1
  import MagicString from 'magic-string';
2
2
  import * as svelte from 'svelte/compiler';
3
+ import { escape_for_interpolation } from './escape.js';
3
4
 
4
5
  /** @typedef {ReturnType<typeof import('svelte/compiler').parseCss>['children']} StyleSheetChildren */
5
6
 
@@ -59,6 +60,8 @@ export function fix_css_urls({
59
60
  return css;
60
61
  }
61
62
 
63
+ css = escape_for_interpolation(css);
64
+
62
65
  // safe guard in case of trailing slashes (but this should never happen)
63
66
  if (paths_assets.endsWith('/')) {
64
67
  paths_assets = paths_assets.slice(0, -1);
@@ -60,3 +60,12 @@ export function escape_html(str, is_attr) {
60
60
 
61
61
  return escaped_str;
62
62
  }
63
+
64
+ /**
65
+ * Escapes backticks and dollar signs so that they can be safely used in template literals.
66
+ * @param {string} str
67
+ * @returns {string} escaped string
68
+ */
69
+ export function escape_for_interpolation(str) {
70
+ return str.replaceAll('`', '\\`').replaceAll('$', '\\$');
71
+ }
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 = '2.52.0';
4
+ export const VERSION = '2.52.2';