@sveltejs/kit 2.55.0 → 2.56.1

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 (42) hide show
  1. package/package.json +3 -4
  2. package/src/core/postbuild/analyse.js +3 -3
  3. package/src/core/postbuild/prerender.js +9 -6
  4. package/src/core/sync/write_tsconfig.js +3 -1
  5. package/src/exports/internal/remote-functions.js +2 -2
  6. package/src/exports/public.d.ts +39 -13
  7. package/src/exports/vite/build/build_server.js +24 -4
  8. package/src/exports/vite/build/build_service_worker.js +16 -6
  9. package/src/exports/vite/build/utils.js +18 -3
  10. package/src/exports/vite/index.js +336 -327
  11. package/src/runtime/app/paths/server.js +1 -1
  12. package/src/runtime/app/server/index.js +1 -1
  13. package/src/runtime/app/server/remote/command.js +12 -7
  14. package/src/runtime/app/server/remote/form.js +14 -14
  15. package/src/runtime/app/server/remote/index.js +1 -0
  16. package/src/runtime/app/server/remote/prerender.js +8 -7
  17. package/src/runtime/app/server/remote/query.js +141 -66
  18. package/src/runtime/app/server/remote/requested.js +172 -0
  19. package/src/runtime/app/server/remote/shared.js +32 -10
  20. package/src/runtime/client/client.js +45 -20
  21. package/src/runtime/client/remote-functions/command.svelte.js +39 -16
  22. package/src/runtime/client/remote-functions/form.svelte.js +41 -24
  23. package/src/runtime/client/remote-functions/prerender.svelte.js +105 -76
  24. package/src/runtime/client/remote-functions/query.svelte.js +408 -138
  25. package/src/runtime/client/remote-functions/shared.svelte.js +95 -94
  26. package/src/runtime/components/svelte-5/error.svelte +2 -0
  27. package/src/runtime/form-utils.js +3 -7
  28. package/src/runtime/server/endpoint.js +0 -1
  29. package/src/runtime/server/page/actions.js +2 -1
  30. package/src/runtime/server/page/load_data.js +3 -1
  31. package/src/runtime/server/page/render.js +38 -15
  32. package/src/runtime/server/remote.js +65 -50
  33. package/src/runtime/server/respond.js +17 -3
  34. package/src/runtime/server/utils.js +0 -12
  35. package/src/runtime/shared.js +233 -5
  36. package/src/types/global-private.d.ts +4 -4
  37. package/src/types/internal.d.ts +80 -44
  38. package/src/utils/css.js +0 -3
  39. package/src/utils/escape.js +15 -3
  40. package/src/version.js +1 -1
  41. package/types/index.d.ts +68 -14
  42. package/types/index.d.ts.map +6 -1
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@sveltejs/kit",
3
- "version": "2.55.0",
3
+ "version": "2.56.1",
4
4
  "description": "SvelteKit is the fastest way to build Svelte apps",
5
5
  "keywords": [
6
6
  "framework",
@@ -40,8 +40,7 @@
40
40
  "@types/set-cookie-parser": "^2.4.7",
41
41
  "dts-buddy": "^0.7.0",
42
42
  "rollup": "^4.59.0",
43
- "svelte": "^5.53.5",
44
- "svelte-preprocess": "^6.0.0",
43
+ "svelte": "^5.53.12",
45
44
  "typescript": "^5.3.3",
46
45
  "vite": "^6.3.5",
47
46
  "vitest": "^4.0.0"
@@ -50,7 +49,7 @@
50
49
  "@sveltejs/vite-plugin-svelte": "^3.0.0 || ^4.0.0-next.1 || ^5.0.0 || ^6.0.0-next.0 || ^7.0.0",
51
50
  "@opentelemetry/api": "^1.0.0",
52
51
  "svelte": "^4.0.0 || ^5.0.0-next.0",
53
- "typescript": "^5.3.3",
52
+ "typescript": "^5.3.3 || ^6.0.0",
54
53
  "vite": "^5.0.3 || ^6.0.0 || ^7.0.0-beta.0 || ^8.0.0"
55
54
  },
56
55
  "peerDependenciesMeta": {
@@ -163,12 +163,12 @@ async function analyse({
163
163
  const exports = new Map();
164
164
 
165
165
  for (const name in functions) {
166
- const info = /** @type {import('types').RemoteInfo} */ (functions[name].__);
167
- const type = info.type;
166
+ const internals = /** @type {import('types').RemoteInternals} */ (functions[name].__);
167
+ const type = internals.type;
168
168
 
169
169
  exports.set(name, {
170
170
  type,
171
- dynamic: type !== 'prerender' || info.dynamic
171
+ dynamic: type !== 'prerender' || internals.dynamic
172
172
  });
173
173
  }
174
174
 
@@ -496,7 +496,7 @@ async function prerender({ hash, out, manifest_path, metadata, verbose, env }) {
496
496
  internal.set_manifest(manifest);
497
497
  internal.set_read_implementation((file) => createReadableStream(`${out}/server/${file}`));
498
498
 
499
- /** @type {Array<import('types').RemoteInfo & { type: 'prerender'}>} */
499
+ /** @type {Array<import('types').RemotePrerenderInternals>} */
500
500
  const prerender_functions = [];
501
501
 
502
502
  for (const loader of Object.values(manifest._.remotes)) {
@@ -549,13 +549,16 @@ async function prerender({ hash, out, manifest_path, metadata, verbose, env }) {
549
549
  }
550
550
 
551
551
  const transport = (await internal.get_hooks()).transport ?? {};
552
- for (const info of prerender_functions) {
553
- if (info.has_arg) {
554
- for (const arg of (await info.inputs?.()) ?? []) {
555
- void enqueue(null, remote_prefix + info.id + '/' + stringify_remote_arg(arg, transport));
552
+ for (const internals of prerender_functions) {
553
+ if (internals.has_arg) {
554
+ for (const arg of (await internals.inputs?.()) ?? []) {
555
+ void enqueue(
556
+ null,
557
+ remote_prefix + internals.id + '/' + stringify_remote_arg(arg, transport)
558
+ );
556
559
  }
557
560
  } else {
558
- void enqueue(null, remote_prefix + info.id);
561
+ void enqueue(null, remote_prefix + internals.id);
559
562
  }
560
563
  }
561
564
 
@@ -121,7 +121,8 @@ export function get_tsconfig(kit) {
121
121
  moduleResolution: 'bundler',
122
122
  module: 'esnext',
123
123
  noEmit: true, // prevent tsconfig error "overwriting input files" - Vite handles the build and ignores this
124
- target: 'esnext'
124
+ target: 'esnext',
125
+ types: ['node']
125
126
  },
126
127
  include: [...include],
127
128
  exclude
@@ -165,6 +166,7 @@ function validate_user_config(cwd, out, config) {
165
166
  if (extends_framework_config) {
166
167
  const { paths, baseUrl } = options;
167
168
 
169
+ // TODO: baseUrl will be removed in TypeScript 7.0
168
170
  if (baseUrl || paths) {
169
171
  console.warn(
170
172
  colors
@@ -1,6 +1,6 @@
1
- /** @import { RemoteInfo } from 'types' */
1
+ /** @import { RemoteInternals } from 'types' */
2
2
 
3
- /** @type {RemoteInfo['type'][]} */
3
+ /** @type {RemoteInternals['type'][]} */
4
4
  const types = ['command', 'form', 'prerender', 'query', 'query_batch'];
5
5
 
6
6
  /**
@@ -1452,6 +1452,22 @@ export interface Page<
1452
1452
  */
1453
1453
  export type ParamMatcher = (param: string) => boolean;
1454
1454
 
1455
+ export type RequestedResult<T> = Iterable<T> &
1456
+ AsyncIterable<T> & {
1457
+ /**
1458
+ * Call `refresh` on all queries selected by this `requested` invocation.
1459
+ * This is identical to:
1460
+ * ```ts
1461
+ * import { requested } from '$app/server';
1462
+ *
1463
+ * for await (const arg of requested(query, ...) {
1464
+ * void query(arg).refresh();
1465
+ * }
1466
+ * ```
1467
+ */
1468
+ refreshAll: () => Promise<void>;
1469
+ };
1470
+
1455
1471
  export interface RequestEvent<
1456
1472
  Params extends AppLayoutParams<'/'> = AppLayoutParams<'/'>,
1457
1473
  RouteId extends AppRouteId | null = AppRouteId | null
@@ -1914,10 +1930,12 @@ export type RemoteFormFieldValue = string | string[] | number | boolean | File |
1914
1930
  type AsArgs<Type extends keyof InputTypeMap, Value> = Type extends 'checkbox'
1915
1931
  ? Value extends string[]
1916
1932
  ? [type: Type, value: Value[number] | (string & {})]
1917
- : [type: Type]
1933
+ : [type: Type] | [type: Type, value: Value | (string & {})]
1918
1934
  : Type extends 'radio' | 'submit' | 'hidden'
1919
1935
  ? [type: Type, value: Value | (string & {})]
1920
- : [type: Type];
1936
+ : Type extends 'file' | 'file multiple'
1937
+ ? [type: Type]
1938
+ : [type: Type] | [type: Type, value: Value | (string & {})];
1921
1939
 
1922
1940
  /**
1923
1941
  * Form field accessor type that provides name(), value(), and issues() methods
@@ -2058,7 +2076,7 @@ export type RemoteForm<Input extends RemoteFormInput | void, Output> = {
2058
2076
  form: HTMLFormElement;
2059
2077
  data: Input;
2060
2078
  submit: () => Promise<void> & {
2061
- updates: (...queries: Array<RemoteQuery<any> | RemoteQueryOverride>) => Promise<void>;
2079
+ updates: (...updates: RemoteQueryUpdate[]) => Promise<void>;
2062
2080
  };
2063
2081
  }) => void | Promise<void>
2064
2082
  ): {
@@ -2102,14 +2120,19 @@ export type RemoteForm<Input extends RemoteFormInput | void, Output> = {
2102
2120
  * The return value of a remote `command` function. See [Remote functions](https://svelte.dev/docs/kit/remote-functions#command) for full documentation.
2103
2121
  */
2104
2122
  export type RemoteCommand<Input, Output> = {
2105
- (arg: undefined extends Input ? Input | void : Input): Promise<Awaited<Output>> & {
2106
- updates(...queries: Array<RemoteQuery<any> | RemoteQueryOverride>): Promise<Awaited<Output>>;
2123
+ (arg: undefined extends Input ? Input | void : Input): Promise<Output> & {
2124
+ updates(...updates: RemoteQueryUpdate[]): Promise<Output>;
2107
2125
  };
2108
2126
  /** The number of pending command executions */
2109
2127
  get pending(): number;
2110
2128
  };
2111
2129
 
2112
- export type RemoteResource<T> = Promise<Awaited<T>> & {
2130
+ export type RemoteQueryUpdate =
2131
+ | RemoteQuery<any>
2132
+ | RemoteQueryFunction<any, any>
2133
+ | RemoteQueryOverride;
2134
+
2135
+ export type RemoteResource<T> = Promise<T> & {
2113
2136
  /** The error in case the query fails. Most often this is a [`HttpError`](https://svelte.dev/docs/kit/@sveltejs-kit#HttpError) but it isn't guaranteed to be. */
2114
2137
  get error(): any;
2115
2138
  /** `true` before the first result is available and during refreshes */
@@ -2122,12 +2145,18 @@ export type RemoteResource<T> = Promise<Awaited<T>> & {
2122
2145
  }
2123
2146
  | {
2124
2147
  /** The current value of the query. Undefined until `ready` is `true` */
2125
- get current(): Awaited<T>;
2148
+ get current(): T;
2126
2149
  ready: true;
2127
2150
  }
2128
2151
  );
2129
2152
 
2130
2153
  export type RemoteQuery<T> = RemoteResource<T> & {
2154
+ /**
2155
+ * Returns a plain promise with the result.
2156
+ * Unlike awaiting the resource directly, this can only be used _outside_ render
2157
+ * (i.e. in load functions, event handlers and so on)
2158
+ */
2159
+ run(): Promise<T>;
2131
2160
  /**
2132
2161
  * On the client, this function will update the value of the query without re-fetching it.
2133
2162
  *
@@ -2143,7 +2172,7 @@ export type RemoteQuery<T> = RemoteResource<T> & {
2143
2172
  */
2144
2173
  refresh(): Promise<void>;
2145
2174
  /**
2146
- * Temporarily override the value of a query. This is used with the `updates` method of a [command](https://svelte.dev/docs/kit/remote-functions#command-Updating-queries) or [enhanced form submission](https://svelte.dev/docs/kit/remote-functions#form-enhance) to provide optimistic updates.
2175
+ * Temporarily override a query's value during a [single-flight mutation](https://svelte.dev/docs/kit/remote-functions#Single-flight-mutations) to provide optimistic updates.
2147
2176
  *
2148
2177
  * ```svelte
2149
2178
  * <script>
@@ -2161,13 +2190,10 @@ export type RemoteQuery<T> = RemoteResource<T> & {
2161
2190
  * </form>
2162
2191
  * ```
2163
2192
  */
2164
- withOverride(update: (current: Awaited<T>) => Awaited<T>): RemoteQueryOverride;
2193
+ withOverride(update: (current: T) => T): RemoteQueryOverride;
2165
2194
  };
2166
2195
 
2167
- export interface RemoteQueryOverride {
2168
- _key: string;
2169
- release(): void;
2170
- }
2196
+ export type RemoteQueryOverride = () => void;
2171
2197
 
2172
2198
  /**
2173
2199
  * The return value of a remote `prerender` function. See [Remote functions](https://svelte.dev/docs/kit/remote-functions#prerender) for full documentation.
@@ -1,10 +1,17 @@
1
1
  import fs from 'node:fs';
2
2
  import { mkdirp } from '../../../utils/filesystem.js';
3
- import { create_function_as_string, filter_fonts, find_deps, resolve_symlinks } from './utils.js';
3
+ import {
4
+ create_function_as_string,
5
+ filter_fonts,
6
+ find_deps,
7
+ generate_placeholder,
8
+ resolve_symlinks
9
+ } from './utils.js';
4
10
  import { s } from '../../../utils/misc.js';
5
11
  import { normalizePath } from 'vite';
6
12
  import { basename } from 'node:path';
7
13
  import { fix_css_urls } from '../../../utils/css.js';
14
+ import { escape_for_interpolation } from '../../../utils/escape.js';
8
15
 
9
16
  /**
10
17
  * @param {string} out
@@ -67,18 +74,31 @@ export function build_server_nodes(
67
74
  const static_asset_prefix = segments.map(() => '..').join('/') + '/';
68
75
 
69
76
  prepare_css_for_inlining = (css, eager_assets) => {
77
+ const assets_placeholder = generate_placeholder(css, 'ASSETS');
78
+ const base_placeholder = generate_placeholder(css, 'BASE');
79
+
70
80
  const transformed_css = fix_css_urls({
71
81
  css,
72
82
  vite_assets: eager_assets,
73
83
  static_assets,
74
- paths_assets: '${assets}',
75
- base: '${base}',
84
+ paths_assets: assets_placeholder,
85
+ base: base_placeholder,
76
86
  static_asset_prefix
77
87
  });
78
88
 
79
89
  // only convert to a function if we have adjusted any URLs
80
90
  if (css !== transformed_css) {
81
- return create_function_as_string('css', ['assets', 'base'], transformed_css);
91
+ const escaped = escape_for_interpolation(transformed_css, [
92
+ {
93
+ placeholder: assets_placeholder,
94
+ replacement: '${assets}'
95
+ },
96
+ {
97
+ placeholder: base_placeholder,
98
+ replacement: '${base}'
99
+ }
100
+ ]);
101
+ return create_function_as_string('css', ['assets', 'base'], escaped);
82
102
  }
83
103
 
84
104
  return s(css);
@@ -8,7 +8,7 @@ import { create_static_module } from '../../../core/env.js';
8
8
  import { env_static_public, service_worker } from '../module_ids.js';
9
9
 
10
10
  // @ts-ignore `vite.rolldownVersion` only exists in `rolldown-vite`
11
- const isRolldown = !!vite.rolldownVersion;
11
+ const is_rolldown = !!vite.rolldownVersion;
12
12
 
13
13
  /**
14
14
  * @param {string} out
@@ -98,7 +98,8 @@ export async function build_service_worker(
98
98
  }
99
99
  };
100
100
 
101
- await vite.build({
101
+ /** @type {import('vite').InlineConfig} */
102
+ const config = {
102
103
  build: {
103
104
  modulePreload: false,
104
105
  rollupOptions: {
@@ -107,9 +108,9 @@ export async function build_service_worker(
107
108
  },
108
109
  output: {
109
110
  // .mjs so that esbuild doesn't incorrectly inject `export` https://github.com/vitejs/vite/issues/15379
110
- entryFileNames: `service-worker.${isRolldown ? 'js' : 'mjs'}`,
111
+ entryFileNames: `service-worker.${is_rolldown ? 'js' : 'mjs'}`,
111
112
  assetFileNames: `${kit.appDir}/immutable/assets/[name].[hash][extname]`,
112
- inlineDynamicImports: true
113
+ inlineDynamicImports: !is_rolldown
113
114
  }
114
115
  },
115
116
  outDir: `${out}/client`,
@@ -130,10 +131,19 @@ export async function build_service_worker(
130
131
  };
131
132
  }
132
133
  }
133
- });
134
+ };
135
+
136
+ // we must reference Vite 8 options conditionally. Otherwise, older Vite
137
+ // versions throw an error about unknown config options
138
+ if (is_rolldown && config?.build?.rollupOptions?.output) {
139
+ // @ts-ignore only available in Vite 8
140
+ config.build.rollupOptions.output.codeSplitting = true;
141
+ }
142
+
143
+ await vite.build(config);
134
144
 
135
145
  // rename .mjs to .js to avoid incorrect MIME types with ancient webservers
136
- if (!isRolldown) {
146
+ if (!is_rolldown) {
137
147
  fs.renameSync(`${out}/client/service-worker.mjs`, `${out}/client/service-worker.js`);
138
148
  }
139
149
  }
@@ -1,7 +1,6 @@
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';
5
4
 
6
5
  /**
7
6
  * Adds transitive JS and CSS dependencies to the js and css inputs.
@@ -137,11 +136,27 @@ export function assets_base(config) {
137
136
  * @param {string} name The name of the function
138
137
  * @param {string[]} placeholder_names The names of the placeholders in the string
139
138
  * @param {string} str A string with placeholders such as "Hello ${arg0}".
140
- * It must have backticks and dollar signs escaped.
139
+ * It must have backslashes, backticks and dollar signs already escaped.
141
140
  * @returns {string} The function written as a string
142
141
  */
143
142
  export function create_function_as_string(name, placeholder_names, str) {
144
- str = s(str).slice(1, -1);
145
143
  const args = placeholder_names ? placeholder_names.join(', ') : '';
146
144
  return `function ${name}(${args}) { return \`${str}\`; }`;
147
145
  }
146
+
147
+ /**
148
+ * Guarantees that the generated placeholder is not already present in the content.
149
+ * @param {string} content
150
+ * @param {string} key
151
+ * @returns {string}
152
+ */
153
+ export function generate_placeholder(content, key) {
154
+ let id = 1;
155
+ let placeholder = `__SVELTEKIT_${key}_${id}__`;
156
+
157
+ while (content.includes(placeholder)) {
158
+ placeholder = `__SVELTEKIT_${key}_${++id}__`;
159
+ }
160
+
161
+ return placeholder;
162
+ }