@sveltejs/kit 3.0.0-next.2 → 3.0.0-next.21

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 (195) hide show
  1. package/package.json +62 -36
  2. package/src/cli.js +15 -12
  3. package/src/constants.js +6 -1
  4. package/src/core/adapt/builder.js +66 -72
  5. package/src/core/adapt/index.js +17 -6
  6. package/src/core/config/index.js +134 -80
  7. package/src/core/config/options.js +295 -273
  8. package/src/core/config/types.d.ts +1 -1
  9. package/src/core/env.js +146 -16
  10. package/src/core/generate_manifest/index.js +18 -15
  11. package/src/core/postbuild/analyse.js +8 -20
  12. package/src/core/postbuild/crawl.js +22 -6
  13. package/src/core/postbuild/entities.js +8 -2
  14. package/src/core/postbuild/fallback.js +4 -2
  15. package/src/core/postbuild/prerender.js +222 -70
  16. package/src/core/postbuild/queue.js +2 -1
  17. package/src/core/sync/create_manifest_data/conflict.js +1 -1
  18. package/src/core/sync/create_manifest_data/index.js +82 -62
  19. package/src/core/sync/sync.js +40 -31
  20. package/src/core/sync/ts.js +1 -1
  21. package/src/core/sync/utils.js +22 -2
  22. package/src/core/sync/{write_non_ambient.js → write_app_types.js} +107 -58
  23. package/src/core/sync/write_client_manifest.js +14 -29
  24. package/src/core/sync/write_env.js +7 -5
  25. package/src/core/sync/write_server.js +37 -45
  26. package/src/core/sync/write_tsconfig/index.js +274 -0
  27. package/src/core/sync/write_tsconfig/test-app/package.json +7 -0
  28. package/src/core/sync/write_tsconfig/utils.js +77 -0
  29. package/src/core/sync/write_tsconfig/validate.js +128 -0
  30. package/src/core/sync/write_types/index.js +127 -123
  31. package/src/core/utils.js +30 -5
  32. package/src/exports/env/index.js +77 -0
  33. package/src/exports/env/public.d.ts +55 -0
  34. package/src/exports/hooks/index.js +3 -9
  35. package/src/exports/hooks/public.d.ts +195 -0
  36. package/src/exports/hooks/sequence.js +9 -6
  37. package/src/exports/index.js +52 -29
  38. package/src/exports/internal/client.js +5 -0
  39. package/src/exports/internal/env.js +8 -5
  40. package/src/exports/internal/index.js +1 -90
  41. package/src/exports/internal/{event.js → server/event.js} +2 -3
  42. package/src/exports/internal/server/index.js +37 -0
  43. package/src/exports/internal/server/telemetry.js +95 -0
  44. package/src/exports/internal/shared.js +90 -0
  45. package/src/exports/node/index.js +64 -22
  46. package/src/exports/params/index.js +70 -0
  47. package/src/exports/params/public.d.ts +63 -0
  48. package/src/exports/public.d.ts +50 -1733
  49. package/src/exports/remote/index.js +11 -0
  50. package/src/exports/remote/public.d.ts +519 -0
  51. package/src/exports/url.js +86 -0
  52. package/src/exports/vite/build/build_server.js +54 -65
  53. package/src/exports/vite/build/remote.js +24 -19
  54. package/src/exports/vite/build/utils.js +0 -8
  55. package/src/exports/vite/dev/index.js +218 -146
  56. package/src/exports/vite/index.js +1590 -858
  57. package/src/exports/vite/module_ids.js +2 -2
  58. package/src/exports/vite/preview/index.js +40 -32
  59. package/src/exports/vite/public.d.ts +588 -0
  60. package/src/exports/vite/utils.js +84 -46
  61. package/src/pathname.js +55 -0
  62. package/src/runner.js +15 -0
  63. package/src/runtime/app/env/internal.js +4 -4
  64. package/src/runtime/app/env/types.d.ts +1 -1
  65. package/src/runtime/app/environment/index.js +3 -3
  66. package/src/runtime/app/{forms.js → forms/index.js} +73 -42
  67. package/src/runtime/app/forms/public.d.ts +2 -0
  68. package/src/runtime/app/forms/types.d.ts +56 -0
  69. package/src/runtime/app/internal/transport.js +53 -0
  70. package/src/runtime/app/manifest/index.js +1 -0
  71. package/src/runtime/app/{navigation.js → navigation/index.js} +2 -1
  72. package/src/runtime/app/navigation/public.d.ts +237 -0
  73. package/src/runtime/app/paths/client.js +37 -37
  74. package/src/runtime/app/paths/index.js +1 -1
  75. package/src/runtime/app/paths/internal/client.js +34 -2
  76. package/src/runtime/app/paths/internal/server.js +6 -23
  77. package/src/runtime/app/paths/internal.d.ts +3 -0
  78. package/src/runtime/app/paths/public.d.ts +1 -29
  79. package/src/runtime/app/paths/server.js +36 -17
  80. package/src/runtime/app/paths/types.d.ts +11 -19
  81. package/src/runtime/app/server/index.js +2 -2
  82. package/src/runtime/app/server/public.d.ts +201 -0
  83. package/src/runtime/app/server/remote/command.js +13 -11
  84. package/src/runtime/app/server/remote/form.js +61 -39
  85. package/src/runtime/app/server/remote/prerender.js +45 -45
  86. package/src/runtime/app/server/remote/query.js +106 -108
  87. package/src/runtime/app/server/remote/requested.js +27 -19
  88. package/src/runtime/app/server/remote/shared.js +76 -76
  89. package/src/runtime/app/service-worker/index.js +24 -0
  90. package/src/runtime/app/state/client.js +4 -2
  91. package/src/runtime/app/state/index.js +7 -5
  92. package/src/runtime/app/state/public.d.ts +72 -0
  93. package/src/runtime/app/state/server.js +3 -0
  94. package/src/runtime/app/stores.js +15 -78
  95. package/src/runtime/client/bundle.js +1 -1
  96. package/src/runtime/client/client-entry.js +3 -0
  97. package/src/runtime/client/client.js +1336 -648
  98. package/src/runtime/client/constants.js +3 -6
  99. package/src/runtime/client/entry.js +24 -3
  100. package/src/runtime/client/fetcher.js +25 -25
  101. package/src/runtime/client/ndjson.js +1 -1
  102. package/src/runtime/client/parse.js +1 -1
  103. package/src/runtime/client/payload.js +17 -0
  104. package/src/runtime/client/remote-functions/cache.svelte.js +3 -1
  105. package/src/runtime/client/remote-functions/command.svelte.js +37 -61
  106. package/src/runtime/client/remote-functions/form.svelte.js +267 -178
  107. package/src/runtime/client/remote-functions/prerender.svelte.js +32 -11
  108. package/src/runtime/client/remote-functions/query/index.js +10 -17
  109. package/src/runtime/client/remote-functions/query/instance.svelte.js +64 -18
  110. package/src/runtime/client/remote-functions/query/proxy.js +5 -5
  111. package/src/runtime/client/remote-functions/query-batch.svelte.js +61 -70
  112. package/src/runtime/client/remote-functions/query-live/index.js +1 -1
  113. package/src/runtime/client/remote-functions/query-live/instance.svelte.js +63 -21
  114. package/src/runtime/client/remote-functions/query-live/iterator.js +15 -12
  115. package/src/runtime/client/remote-functions/query-live/proxy.js +2 -12
  116. package/src/runtime/client/remote-functions/shared.svelte.js +90 -65
  117. package/src/runtime/client/snapshots.js +147 -0
  118. package/src/runtime/client/state.svelte.js +94 -55
  119. package/src/runtime/client/stream.js +3 -2
  120. package/src/runtime/client/types.d.ts +13 -9
  121. package/src/runtime/client/utils.js +22 -110
  122. package/src/runtime/components/root.svelte +56 -0
  123. package/src/runtime/env/dynamic/private.js +7 -0
  124. package/src/runtime/env/dynamic/public.js +7 -0
  125. package/src/runtime/env/static/private.js +6 -0
  126. package/src/runtime/env/static/public.js +6 -0
  127. package/src/runtime/form-utils.js +172 -61
  128. package/src/runtime/pathname.js +20 -32
  129. package/src/runtime/props.svelte.js +72 -0
  130. package/src/runtime/server/constants.js +0 -3
  131. package/src/runtime/server/cookie.js +72 -55
  132. package/src/runtime/server/csrf.js +65 -0
  133. package/src/runtime/server/data/index.js +49 -53
  134. package/src/runtime/server/dev.js +22 -0
  135. package/src/runtime/server/endpoint.js +6 -7
  136. package/src/runtime/server/env_module.js +0 -5
  137. package/src/runtime/server/errors.js +160 -0
  138. package/src/runtime/server/fetch.js +32 -39
  139. package/src/runtime/server/index.js +90 -64
  140. package/src/runtime/server/internal.js +71 -0
  141. package/src/runtime/server/page/actions.js +85 -64
  142. package/src/runtime/server/page/crypto.js +2 -2
  143. package/src/runtime/server/page/csp.js +88 -104
  144. package/src/runtime/server/page/data_serializer.js +24 -25
  145. package/src/runtime/server/page/index.js +36 -53
  146. package/src/runtime/server/page/load_data.js +50 -57
  147. package/src/runtime/server/page/render.js +173 -239
  148. package/src/runtime/server/page/respond_with_error.js +17 -31
  149. package/src/runtime/server/page/serialize_data.js +2 -13
  150. package/src/runtime/server/page/server_routing.js +85 -26
  151. package/src/runtime/server/remote-functions.js +640 -0
  152. package/src/runtime/server/respond.js +190 -131
  153. package/src/runtime/server/sourcemaps.js +183 -0
  154. package/src/runtime/server/state.js +53 -0
  155. package/src/runtime/server/utils.js +13 -155
  156. package/src/runtime/shared.js +20 -40
  157. package/src/runtime/utils.js +3 -0
  158. package/src/types/ambient-private.d.ts +11 -1
  159. package/src/types/ambient.d.ts +87 -36
  160. package/src/types/global-private.d.ts +25 -25
  161. package/src/types/internal.d.ts +163 -157
  162. package/src/types/private.d.ts +41 -1
  163. package/src/utils/error.js +28 -4
  164. package/src/utils/escape.js +9 -25
  165. package/src/utils/features.js +1 -1
  166. package/src/utils/filesystem.js +1 -23
  167. package/src/utils/fork.js +7 -2
  168. package/src/utils/hash.js +21 -0
  169. package/src/utils/http.js +8 -7
  170. package/src/utils/import.js +9 -2
  171. package/src/utils/imports.js +83 -0
  172. package/src/utils/mime.js +9 -0
  173. package/src/utils/page_nodes.js +6 -7
  174. package/src/utils/params.js +67 -0
  175. package/src/utils/regex.js +9 -0
  176. package/src/utils/routing.js +145 -73
  177. package/src/utils/shared-iterator.js +5 -0
  178. package/src/utils/streaming.js +14 -4
  179. package/src/utils/url.js +33 -2
  180. package/src/version.js +1 -1
  181. package/types/index.d.ts +2616 -2433
  182. package/types/index.d.ts.map +120 -106
  183. package/src/core/sync/write_ambient.js +0 -18
  184. package/src/core/sync/write_root.js +0 -148
  185. package/src/core/sync/write_tsconfig.js +0 -250
  186. package/src/exports/internal/server.js +0 -22
  187. package/src/exports/node/polyfills.js +0 -30
  188. package/src/runtime/server/app.js +0 -9
  189. package/src/runtime/server/remote.js +0 -457
  190. package/src/runtime/shared-server.js +0 -7
  191. package/src/runtime/telemetry/otel.js +0 -21
  192. package/src/runtime/telemetry/record_span.js +0 -65
  193. package/src/types/synthetic/$lib.md +0 -5
  194. /package/src/exports/internal/{remote-functions.js → server/remote-functions.js} +0 -0
  195. /package/src/{runtime/telemetry/noop.js → telemetry.js} +0 -0
package/src/core/env.js CHANGED
@@ -1,8 +1,7 @@
1
1
  /** @import { StandardSchemaV1 } from '@standard-schema/spec' */
2
- /** @import { EnvVarConfig } from '@sveltejs/kit' */
3
- /** @import { ValidatedKitConfig } from 'types' */
2
+ /** @import { EnvVarConfig } from '@sveltejs/kit/env' */
3
+ /** @import { ValidatedConfig } from 'types' */
4
4
  import path from 'node:path';
5
- import * as vite from 'vite';
6
5
  import * as devalue from 'devalue';
7
6
  import { GENERATED_COMMENT } from '../constants.js';
8
7
  import { dedent } from './sync/utils.js';
@@ -10,13 +9,14 @@ import { runtime_directory } from './utils.js';
10
9
  import { resolve_entry } from '../utils/filesystem.js';
11
10
  import { handle_issues, validate } from '../exports/internal/env.js';
12
11
  import { get_config_aliases } from '../exports/vite/utils.js';
12
+ import { get_runner } from '../runner.js';
13
13
 
14
14
  /**
15
15
  * @typedef {'public' | 'private'} EnvType
16
16
  */
17
17
 
18
18
  /**
19
- * @param {import('types').ValidatedKitConfig} config
19
+ * @param {ValidatedConfig} config
20
20
  * @returns {string | null}
21
21
  */
22
22
  export function resolve_explicit_env_entry(config) {
@@ -24,13 +24,14 @@ export function resolve_explicit_env_entry(config) {
24
24
  }
25
25
 
26
26
  /**
27
- * @param {ValidatedKitConfig} kit
27
+ * @param {typeof import('vite')} vite
28
+ * @param {ValidatedConfig} kit
28
29
  * @param {string | null} file
29
30
  * @param {string} root
30
31
  * @param {string} mode
31
32
  * @returns {Promise<Record<string, EnvVarConfig<any>> | null>}
32
33
  */
33
- export async function load_explicit_env(kit, file, root, mode) {
34
+ export async function load_explicit_env(vite, kit, file, root, mode) {
34
35
  if (!file) return null;
35
36
 
36
37
  const server = await vite.createServer({
@@ -38,6 +39,7 @@ export async function load_explicit_env(kit, file, root, mode) {
38
39
  logLevel: 'silent',
39
40
  mode,
40
41
  define: {
42
+ __SVELTEKIT_PAYLOAD__: 'undefined', // coming in through static import in env/internal.js but will end up unused
41
43
  __SVELTEKIT_APP_VERSION__: JSON.stringify(kit.version.name) // needed by $app/env
42
44
  },
43
45
  resolve: {
@@ -51,8 +53,14 @@ export async function load_explicit_env(kit, file, root, mode) {
51
53
  /** @type {Record<string, EnvVarConfig<any>>} */
52
54
  let variables;
53
55
 
56
+ const runner = get_runner(vite, server);
57
+
58
+ /** @type {typeof import('../runtime/app/env/internal.js')} */ (
59
+ await runner.import(`${runtime_directory}/app/env/internal.js`)
60
+ ).set_building();
61
+
54
62
  try {
55
- ({ variables } = await server.ssrLoadModule(file));
63
+ ({ variables } = await runner.import(file));
56
64
 
57
65
  if (!variables || typeof variables !== 'object') {
58
66
  throw new Error(`${file} must export a variables object`);
@@ -87,11 +95,12 @@ export async function load_explicit_env(kit, file, root, mode) {
87
95
 
88
96
  /**
89
97
  * Creates the `__sveltekit/env` module
90
- * @param {Record<string, EnvVarConfig<any>> | null} variables
98
+ * @param {Record<string, EnvVarConfig<any> | undefined> | null} variables
91
99
  * @param {Record<string, string>} env
92
100
  * @param {string | null} entry
101
+ * @param {boolean} is_dev
93
102
  */
94
- export function create_sveltekit_env(variables, env, entry) {
103
+ export function create_sveltekit_env(variables, env, entry, is_dev) {
95
104
  const imports = entry
96
105
  ? [
97
106
  `import { variables } from ${JSON.stringify(entry)};`,
@@ -106,7 +115,7 @@ export function create_sveltekit_env(variables, env, entry) {
106
115
  const issues = {};
107
116
 
108
117
  for (const [name, config] of Object.entries(variables ?? {})) {
109
- if (config.static) {
118
+ if (config?.static) {
110
119
  if (config.public) {
111
120
  const value = validate(variables ?? {}, env[name], name, issues);
112
121
  declarations.push(`explicit_public_env.${name} = ${devalue.uneval(value)};`);
@@ -116,7 +125,7 @@ export function create_sveltekit_env(variables, env, entry) {
116
125
  `const ${name} = validate(variables, env.${name}, ${JSON.stringify(name)}, issues);`
117
126
  );
118
127
 
119
- if (config.public) {
128
+ if (config?.public) {
120
129
  setters.push(`explicit_public_env.${name} = ${name};`);
121
130
  setters.push(`rendered_env.${name} = ${name};`);
122
131
  } else {
@@ -145,6 +154,19 @@ export function create_sveltekit_env(variables, env, entry) {
145
154
  }`
146
155
  ];
147
156
 
157
+ // In dev, initialise the env immediately. Tools like `vite-node` load modules
158
+ // through the Vite config but don't run the SvelteKit dev server, which is what
159
+ // normally calls `set_env`. Without this, dynamic env vars imported from
160
+ // `$app/env/public` and `$app/env/private` would be `undefined` in such contexts.
161
+ if (is_dev) {
162
+ /** @type {Record<string, string>} */
163
+ const dev_env = {};
164
+ for (const name of Object.keys(variables ?? {})) {
165
+ if (name in env) dev_env[name] = env[name];
166
+ }
167
+ blocks.push(`set_env(${devalue.uneval(dev_env)});`);
168
+ }
169
+
148
170
  const module = blocks.join('\n\n');
149
171
 
150
172
  return module;
@@ -213,14 +235,52 @@ export function create_sveltekit_env_public(variables, env, prelude) {
213
235
  return `${prelude}\n\n${exports.join('')}`;
214
236
  }
215
237
 
238
+ /**
239
+ * Creates the `__sveltekit/env/service-worker` module used in production. When an app uses
240
+ * dynamic public env vars, they're loaded at runtime via an import of the prerendered
241
+ * `env.js`. If there are none, values are inlined.
242
+ * @param {Record<string, EnvVarConfig<any>> | null} variables
243
+ * @param {Record<string, string>} env
244
+ * @param {string} version
245
+ * @param {string} global
246
+ * @param {string} base
247
+ * @param {string} app_dir
248
+ */
249
+ export function create_sveltekit_env_service_worker(
250
+ variables,
251
+ env,
252
+ version,
253
+ global,
254
+ base,
255
+ app_dir
256
+ ) {
257
+ const has_dynamic_public_env = Object.values(variables ?? {}).some(
258
+ (config) => config.public && !config.static
259
+ );
260
+
261
+ if (!has_dynamic_public_env) {
262
+ return create_sveltekit_env_service_worker_dev(variables, env, version, global);
263
+ }
264
+
265
+ return dedent`
266
+ import { env } from '${base}/${app_dir}/env.js';
267
+
268
+ ${global} = {
269
+ base: location.pathname.split('/').slice(0, -1).join('/'),
270
+ env,
271
+ version: ${JSON.stringify(version)}
272
+ };
273
+ `;
274
+ }
275
+
216
276
  /**
217
277
  * Creates the `__sveltekit/env/service-worker` module used in development
218
- * (but not in prod, which goes through build_service_worker instead)
219
278
  * @param {Record<string, EnvVarConfig<any>> | null} variables
220
279
  * @param {Record<string, string>} env
280
+ * @param {string} version
221
281
  * @param {string} global
222
282
  */
223
- export function create_sveltekit_env_service_worker_dev(variables, env, global) {
283
+ export function create_sveltekit_env_service_worker_dev(variables, env, version, global) {
224
284
  /** @type {string[]} */
225
285
  const properties = [];
226
286
 
@@ -237,12 +297,12 @@ export function create_sveltekit_env_service_worker_dev(variables, env, global)
237
297
  handle_issues(issues);
238
298
 
239
299
  return dedent`
240
- globalThis.__SVELTEKIT_EXPERIMENTAL_EXPLICIT_ENVIRONMENT_VARIABLES__ = true;
241
-
242
300
  ${global} = {
301
+ base: location.pathname.split('/').slice(0, -1).join('/'),
243
302
  env: {
244
303
  ${properties.join(',\n\t\t') || '// empty'}
245
- }
304
+ },
305
+ version: ${JSON.stringify(version)}
246
306
  };
247
307
  `;
248
308
  }
@@ -330,3 +390,73 @@ export const reserved = new Set([
330
390
  ]);
331
391
 
332
392
  export const valid_identifier = /^[a-zA-Z_$][a-zA-Z0-9_$]*$/;
393
+
394
+ /**
395
+ * Generates `export const` declarations (and, for reserved-word names that need
396
+ * aliasing, `const` + re-export specifiers) for a set of named exports.
397
+ *
398
+ * For regular names, emits a single efficient `export const name = expr;` statement.
399
+ * For reserved-word names (e.g. `delete`, `class`), emits `const alias = expr;` plus
400
+ * a re-export specifier (`alias as name`), since reserved words can't be `const`
401
+ * binding names but CAN appear in export specifiers.
402
+ *
403
+ * You can do evil things like `export { c as class }`. In order to import/re-export
404
+ * these, you need to alias the binding, then un-alias it when re-exporting:
405
+ *
406
+ * const _0 = ...; // safe binding name
407
+ * export { _0 as class }; // valid — `class` is allowed in export specifiers
408
+ *
409
+ * Aliases are chosen to avoid collisions with any of the supplied names. The
410
+ * namespace binding (used to hold the imported module) is likewise chosen to
411
+ * avoid collisions.
412
+ *
413
+ * @param {Iterable<string>} names — the export names
414
+ * @param {(name: string, namespace: string) => string} build_expression —
415
+ * called for each name to produce the right-hand side of the declaration;
416
+ * receives the chosen namespace binding so it can reference the imported module
417
+ * @param {string} namespace_prefix — the preferred binding name for the namespace
418
+ * (suffixed with a number if it collides with any export name)
419
+ * @returns {{ namespace: string, declarations: string[], reexports: string[] }}
420
+ */
421
+ export function create_exported_declarations(names, build_expression, namespace_prefix) {
422
+ /** @type {Set<string>} */
423
+ const set = new Set(names);
424
+
425
+ let namespace = namespace_prefix;
426
+ let namespace_index = 0;
427
+ while (set.has(namespace)) {
428
+ namespace = `${namespace_prefix}${namespace_index++}`;
429
+ }
430
+
431
+ let alias_index = 0;
432
+ /** @type {Map<string, string>} */
433
+ const aliases = new Map();
434
+
435
+ for (const name of set) {
436
+ if (!reserved.has(name)) continue;
437
+
438
+ let alias = `_${alias_index++}`;
439
+ while (set.has(alias)) {
440
+ alias = `_${alias_index++}`;
441
+ }
442
+ aliases.set(name, alias);
443
+ }
444
+
445
+ /** @type {string[]} */
446
+ const declarations = [];
447
+ /** @type {string[]} */
448
+ const reexports = [];
449
+
450
+ for (const name of set) {
451
+ const alias = aliases.get(name);
452
+ const expr = build_expression(name, namespace);
453
+ if (alias) {
454
+ declarations.push(`const ${alias} = ${expr};`);
455
+ reexports.push(`${alias} as ${name}`);
456
+ } else {
457
+ declarations.push(`export const ${name} = ${expr};`);
458
+ }
459
+ }
460
+
461
+ return { namespace, declarations, reexports };
462
+ }
@@ -1,7 +1,7 @@
1
1
  /** @import { RemoteChunk } from 'types' */
2
2
  import fs from 'node:fs';
3
3
  import path from 'node:path';
4
- import * as mime from 'mrmime';
4
+ import { lookup as mime_lookup } from '../../utils/mime.js';
5
5
  import { s } from '../../utils/misc.js';
6
6
  import { get_mime_lookup } from '../utils.js';
7
7
  import { resolve_symlinks } from '../../exports/vite/build/utils.js';
@@ -69,10 +69,8 @@ export function generate_manifest({
69
69
  assets.push(build_data.service_worker);
70
70
  }
71
71
 
72
- // In case of server-side route resolution, we need to include all matchers. Prerendered routes are not part
73
- // of the server manifest, and they could reference matchers that then would not be included.
74
- const matchers = new Set(
75
- build_data.client?.nodes ? Object.keys(build_data.manifest_data.matchers) : undefined
72
+ const uses_matchers = build_data.manifest_data.routes.some((route) =>
73
+ route.params.some((param) => param.matcher)
76
74
  );
77
75
 
78
76
  /** @param {Array<number | undefined>} indexes */
@@ -93,7 +91,13 @@ export function generate_manifest({
93
91
  files[file] = fs.statSync(path.resolve(build_data.out_dir, 'server', file)).size;
94
92
 
95
93
  const ext = path.extname(file);
96
- mime_types[ext] ??= mime.lookup(ext) || '';
94
+ mime_types[ext] ??= mime_lookup(ext) || '';
95
+ }
96
+
97
+ // record extensions that only exist in prerendered output, e.g. a prerendered favicon.ico
98
+ for (const pathname of prerendered) {
99
+ const ext = path.extname(pathname);
100
+ if (ext) mime_types[ext] ??= mime_lookup(ext) || '';
97
101
  }
98
102
 
99
103
  // prettier-ignore
@@ -117,10 +121,6 @@ export function generate_manifest({
117
121
  ${routes.map(route => {
118
122
  if (!route.page && !route.endpoint) return;
119
123
 
120
- route.params.forEach(param => {
121
- if (param.matcher) matchers.add(param.matcher);
122
- });
123
-
124
124
  return dedent`
125
125
  {
126
126
  id: ${s(route.id)},
@@ -134,11 +134,14 @@ export function generate_manifest({
134
134
  ],
135
135
  prerendered_routes: new Set(${s(prerendered)}),
136
136
  matchers: async () => {
137
- ${Array.from(
138
- matchers,
139
- type => `const { match: ${type} } = await import ('${(join_relative(relative_path, `/entries/matchers/${type}.js`))}')`
140
- ).join('\n')}
141
- return { ${Array.from(matchers).join(', ')} };
137
+ ${
138
+ uses_matchers && build_data.manifest_data.params
139
+ ? dedent`
140
+ const { params } = await import('${join_relative(relative_path, '/entries/params.js')}');
141
+ return params;
142
+ `
143
+ : 'return {};'
144
+ }
142
145
  },
143
146
  server_assets: ${s(files)}
144
147
  }
@@ -1,4 +1,3 @@
1
- /** @import { Adapter } from '@sveltejs/kit' */
2
1
  /** @import { RemoteChunk } from 'types' */
3
2
  import { join } from 'node:path';
4
3
  import { pathToFileURL } from 'node:url';
@@ -10,7 +9,6 @@ import { has_server_load, resolve_route } from '../../utils/routing.js';
10
9
  import { check_feature } from '../../utils/features.js';
11
10
  import { createReadableStream } from '@sveltejs/kit/node';
12
11
  import { PageNodes } from '../../utils/page_nodes.js';
13
- import { build_server_nodes } from '../../exports/vite/build/build_server.js';
14
12
 
15
13
  export default forked(import.meta.url, analyse);
16
14
 
@@ -22,9 +20,7 @@ export default forked(import.meta.url, analyse);
22
20
  * server_manifest: import('vite').Manifest;
23
21
  * tracked_features: Record<string, string[]>;
24
22
  * env: Record<string, string>;
25
- * out: string;
26
23
  * remotes: RemoteChunk[];
27
- * root: string;
28
24
  * vite_config_file: string | undefined;
29
25
  * }} opts
30
26
  */
@@ -35,24 +31,14 @@ async function analyse({
35
31
  server_manifest,
36
32
  tracked_features,
37
33
  env,
38
- out,
39
34
  remotes,
40
- root,
41
35
  vite_config_file
42
36
  }) {
43
37
  /** @type {import('@sveltejs/kit').SSRManifest} */
44
38
  const manifest = (await import(pathToFileURL(manifest_path).href)).manifest;
45
39
 
46
40
  const vite_config = await load_vite_config(vite_config_file);
47
-
48
- const config = extract_svelte_config(vite_config).kit;
49
-
50
- // TODO i think this can just be config.adapter?
51
- /** @type {Adapter | undefined} */
52
- const adapter = vite_config.plugins.find(
53
- (plugin) => plugin.name === 'vite-plugin-sveltekit-adapter'
54
- )?.api?.adapter;
55
-
41
+ const config = extract_svelte_config(vite_config);
56
42
  const server_root = join(config.outDir, 'output');
57
43
 
58
44
  /** @type {import('types').ServerInternalModule} */
@@ -62,13 +48,15 @@ async function analyse({
62
48
  // essential we do this before analysing the code
63
49
  internal.set_building();
64
50
 
65
- // set env, `read`, and `manifest`, in case they're used in initialisation
66
- internal.set_env(env);
51
+ // set `read` and `manifest`, in case they're used in initialisation
67
52
  internal.set_manifest(manifest);
68
53
  internal.set_read_implementation((file) => createReadableStream(`${server_root}/server/${file}`));
69
54
 
70
- // first, build server nodes without the client manifest so we can analyse it
71
- build_server_nodes(out, config, manifest_data, server_manifest, null, null, null, root);
55
+ // `set_env` lives in a separate module that imports the user's `src/env` config. We import it
56
+ // *after* `set_building()` so that `building`-dependent expressions resolve correctly
57
+ /** @type {typeof import('__sveltekit/env')} */
58
+ const { set_env } = await import(pathToFileURL(`${server_root}/server/env.js`).href);
59
+ set_env(env);
72
60
 
73
61
  /** @type {import('types').ServerMetadata} */
74
62
  const metadata = {
@@ -134,7 +122,7 @@ async function analyse({
134
122
  server_manifest,
135
123
  tracked_features
136
124
  )) {
137
- check_feature(route.id, route_config, feature, adapter);
125
+ check_feature(route.id, route_config, feature, config.adapter);
138
126
  }
139
127
  }
140
128
 
@@ -38,6 +38,18 @@ export function crawl(html, base) {
38
38
  /** @type {string[]} */
39
39
  const hrefs = [];
40
40
 
41
+ /** @type {string[]} */
42
+ const invalid = [];
43
+
44
+ /** @param {string} url */
45
+ const push_href = (url) => {
46
+ try {
47
+ hrefs.push(resolve(base, url));
48
+ } catch {
49
+ invalid.push(url);
50
+ }
51
+ };
52
+
41
53
  let i = 0;
42
54
  main: while (i < html.length) {
43
55
  const char = html[i];
@@ -186,9 +198,13 @@ export function crawl(html, base) {
186
198
 
187
199
  if (href) {
188
200
  if (tag === 'BASE') {
189
- base = resolve(base, href);
201
+ try {
202
+ base = resolve(base, href);
203
+ } catch {
204
+ invalid.push(href);
205
+ }
190
206
  } else if (!rel || !/\bexternal\b/i.test(rel)) {
191
- hrefs.push(resolve(base, href));
207
+ push_href(href);
192
208
  }
193
209
  }
194
210
 
@@ -201,7 +217,7 @@ export function crawl(html, base) {
201
217
  }
202
218
 
203
219
  if (src) {
204
- hrefs.push(resolve(base, src));
220
+ push_href(src);
205
221
  }
206
222
 
207
223
  if (srcset) {
@@ -222,7 +238,7 @@ export function crawl(html, base) {
222
238
  candidates.push(value);
223
239
  for (const candidate of candidates) {
224
240
  const src = candidate.split(WHITESPACE)[0];
225
- if (src) hrefs.push(resolve(base, src));
241
+ if (src) push_href(src);
226
242
  }
227
243
  }
228
244
 
@@ -230,7 +246,7 @@ export function crawl(html, base) {
230
246
  const attr = name ?? property;
231
247
 
232
248
  if (attr && CRAWLABLE_META_NAME_ATTRS.has(attr)) {
233
- hrefs.push(resolve(base, content));
249
+ push_href(content);
234
250
  }
235
251
  }
236
252
  }
@@ -239,5 +255,5 @@ export function crawl(html, base) {
239
255
  i += 1;
240
256
  }
241
257
 
242
- return { ids, hrefs };
258
+ return { ids, hrefs, invalid };
243
259
  }
@@ -2236,7 +2236,7 @@ const entities = {
2236
2236
  'zwnj;': '‌'
2237
2237
  };
2238
2238
 
2239
- const numeric = /&#(x)?([0-9a-f]+);/i;
2239
+ const numeric = /&#(x)?([0-9a-f]+);/gi;
2240
2240
  const named = new RegExp(
2241
2241
  `&(${Object.keys(entities)
2242
2242
  .sort((a, b) => b.length - a.length)
@@ -2247,6 +2247,12 @@ const named = new RegExp(
2247
2247
  /** @param {string} str */
2248
2248
  export function decode(str) {
2249
2249
  return str
2250
- .replace(numeric, (_match, hex, code) => String.fromCharCode(hex ? parseInt(code, 16) : +code))
2250
+ .replace(numeric, (_match, hex, code) => {
2251
+ const codepoint = hex ? parseInt(code, 16) : +code;
2252
+ // mirror the HTML parser, which replaces invalid numeric references with U+FFFD
2253
+ return Number.isInteger(codepoint) && codepoint <= 0x10ffff
2254
+ ? String.fromCodePoint(codepoint)
2255
+ : '\ufffd';
2256
+ })
2251
2257
  .replace(named, (_match, entity) => entities[entity]);
2252
2258
  }
@@ -2,6 +2,7 @@ import { readFileSync } from 'node:fs';
2
2
  import { join } from 'node:path';
3
3
  import { pathToFileURL } from 'node:url';
4
4
  import { forked } from '../../utils/fork.js';
5
+ import { stackless } from '../../utils/error.js';
5
6
 
6
7
  export default forked(import.meta.url, generate_fallback);
7
8
 
@@ -38,7 +39,8 @@ async function generate_fallback({ manifest_path, env, out_dir, origin, assets }
38
39
  prerendering: {
39
40
  fallback: true,
40
41
  dependencies: new Map(),
41
- remote_responses: new Map()
42
+ remote_responses: new Map(),
43
+ resolved_route_ids: new Set()
42
44
  },
43
45
  read: (file) => readFileSync(join(assets, file))
44
46
  });
@@ -47,5 +49,5 @@ async function generate_fallback({ manifest_path, env, out_dir, origin, assets }
47
49
  return await response.text();
48
50
  }
49
51
 
50
- throw new Error(`Could not create a fallback page — failed with status ${response.status}`);
52
+ throw stackless('Could not create a fallback page');
51
53
  }