@sveltejs/kit 3.0.0-next.6 → 3.0.0-next.8

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 (80) hide show
  1. package/package.json +8 -3
  2. package/src/core/adapt/builder.js +11 -39
  3. package/src/core/config/index.js +76 -71
  4. package/src/core/config/options.js +280 -285
  5. package/src/core/config/types.d.ts +1 -1
  6. package/src/core/env.js +86 -1
  7. package/src/core/generate_manifest/index.js +12 -15
  8. package/src/core/sync/create_manifest_data/index.js +7 -45
  9. package/src/core/sync/sync.js +0 -2
  10. package/src/core/sync/write_client_manifest.js +7 -21
  11. package/src/core/sync/write_non_ambient.js +12 -9
  12. package/src/core/sync/write_server.js +0 -4
  13. package/src/core/sync/write_types/index.js +28 -24
  14. package/src/core/utils.js +2 -2
  15. package/src/exports/index.js +3 -3
  16. package/src/exports/internal/client.js +5 -0
  17. package/src/exports/internal/index.js +1 -91
  18. package/src/exports/internal/{event.js → server/event.js} +1 -2
  19. package/src/exports/internal/server/index.js +33 -0
  20. package/src/exports/internal/shared.js +89 -0
  21. package/src/exports/node/index.js +5 -9
  22. package/src/exports/params.js +63 -0
  23. package/src/exports/public.d.ts +103 -46
  24. package/src/exports/url.js +84 -0
  25. package/src/exports/vite/dev/index.js +31 -20
  26. package/src/exports/vite/index.js +280 -199
  27. package/src/exports/vite/preview/index.js +14 -15
  28. package/src/exports/vite/utils.js +8 -10
  29. package/src/runtime/app/env/internal.js +4 -4
  30. package/src/runtime/app/forms.js +2 -2
  31. package/src/runtime/app/paths/client.js +3 -7
  32. package/src/runtime/app/paths/internal/client.js +4 -2
  33. package/src/runtime/app/paths/internal/server.js +2 -23
  34. package/src/runtime/app/paths/server.js +3 -3
  35. package/src/runtime/app/server/remote/query.js +6 -12
  36. package/src/runtime/app/state/client.js +1 -2
  37. package/src/runtime/app/stores.js +13 -76
  38. package/src/runtime/client/bundle.js +1 -1
  39. package/src/runtime/client/client-entry.js +3 -0
  40. package/src/runtime/client/client.js +230 -238
  41. package/src/runtime/client/entry.js +24 -3
  42. package/src/runtime/client/payload.js +17 -0
  43. package/src/runtime/client/remote-functions/cache.svelte.js +3 -1
  44. package/src/runtime/client/remote-functions/form.svelte.js +11 -30
  45. package/src/runtime/client/remote-functions/prerender.svelte.js +10 -3
  46. package/src/runtime/client/remote-functions/query/instance.svelte.js +18 -9
  47. package/src/runtime/client/remote-functions/query-live/instance.svelte.js +16 -6
  48. package/src/runtime/client/remote-functions/shared.svelte.js +1 -2
  49. package/src/runtime/client/state.svelte.js +66 -49
  50. package/src/runtime/client/types.d.ts +3 -7
  51. package/src/runtime/client/utils.js +0 -96
  52. package/src/runtime/components/root.svelte +66 -0
  53. package/src/runtime/form-utils.js +16 -6
  54. package/src/runtime/server/cookie.js +17 -7
  55. package/src/runtime/server/index.js +1 -1
  56. package/src/runtime/server/page/index.js +7 -14
  57. package/src/runtime/server/page/load_data.js +1 -1
  58. package/src/runtime/server/page/render.js +72 -88
  59. package/src/runtime/server/page/server_routing.js +13 -9
  60. package/src/runtime/server/remote.js +23 -13
  61. package/src/runtime/server/respond.js +11 -8
  62. package/src/runtime/server/utils.js +28 -5
  63. package/src/runtime/telemetry/otel.js +1 -1
  64. package/src/runtime/types.d.ts +8 -0
  65. package/src/types/ambient.d.ts +5 -1
  66. package/src/types/global-private.d.ts +11 -18
  67. package/src/types/internal.d.ts +25 -30
  68. package/src/utils/error.js +1 -1
  69. package/src/utils/import.js +6 -1
  70. package/src/utils/mime.js +9 -0
  71. package/src/utils/params.js +66 -0
  72. package/src/utils/routing.js +90 -44
  73. package/src/utils/streaming.js +14 -4
  74. package/src/utils/url.js +0 -79
  75. package/src/version.js +1 -1
  76. package/types/index.d.ts +127 -125
  77. package/types/index.d.ts.map +12 -8
  78. package/src/core/sync/write_root.js +0 -148
  79. package/src/exports/internal/server.js +0 -22
  80. /package/src/exports/internal/{remote-functions.js → server/remote-functions.js} +0 -0
package/src/core/env.js CHANGED
@@ -38,6 +38,7 @@ export async function load_explicit_env(kit, file, root, mode) {
38
38
  logLevel: 'silent',
39
39
  mode,
40
40
  define: {
41
+ __SVELTEKIT_PAYLOAD__: 'undefined', // coming in through static import in env/internal.js but will end up unused
41
42
  __SVELTEKIT_APP_VERSION__: JSON.stringify(kit.version.name) // needed by $app/env
42
43
  },
43
44
  resolve: {
@@ -94,8 +95,9 @@ export async function load_explicit_env(kit, file, root, mode) {
94
95
  * @param {Record<string, EnvVarConfig<any> | undefined> | null} variables
95
96
  * @param {Record<string, string>} env
96
97
  * @param {string | null} entry
98
+ * @param {boolean} is_dev
97
99
  */
98
- export function create_sveltekit_env(variables, env, entry) {
100
+ export function create_sveltekit_env(variables, env, entry, is_dev) {
99
101
  const imports = entry
100
102
  ? [
101
103
  `import { variables } from ${JSON.stringify(entry)};`,
@@ -149,6 +151,19 @@ export function create_sveltekit_env(variables, env, entry) {
149
151
  }`
150
152
  ];
151
153
 
154
+ // In dev, initialise the env immediately. Tools like `vite-node` load modules
155
+ // through the Vite config but don't run the SvelteKit dev server, which is what
156
+ // normally calls `set_env`. Without this, dynamic env vars imported from
157
+ // `$app/env/public` and `$app/env/private` would be `undefined` in such contexts.
158
+ if (is_dev) {
159
+ /** @type {Record<string, string>} */
160
+ const dev_env = {};
161
+ for (const name of Object.keys(variables ?? {})) {
162
+ if (name in env) dev_env[name] = env[name];
163
+ }
164
+ blocks.push(`set_env(${devalue.uneval(dev_env)});`);
165
+ }
166
+
152
167
  const module = blocks.join('\n\n');
153
168
 
154
169
  return module;
@@ -361,3 +376,73 @@ export const reserved = new Set([
361
376
  ]);
362
377
 
363
378
  export const valid_identifier = /^[a-zA-Z_$][a-zA-Z0-9_$]*$/;
379
+
380
+ /**
381
+ * Generates `export const` declarations (and, for reserved-word names that need
382
+ * aliasing, `const` + re-export specifiers) for a set of named exports.
383
+ *
384
+ * For regular names, emits a single efficient `export const name = expr;` statement.
385
+ * For reserved-word names (e.g. `delete`, `class`), emits `const alias = expr;` plus
386
+ * a re-export specifier (`alias as name`), since reserved words can't be `const`
387
+ * binding names but CAN appear in export specifiers.
388
+ *
389
+ * You can do evil things like `export { c as class }`. In order to import/re-export
390
+ * these, you need to alias the binding, then un-alias it when re-exporting:
391
+ *
392
+ * const _0 = ...; // safe binding name
393
+ * export { _0 as class }; // valid — `class` is allowed in export specifiers
394
+ *
395
+ * Aliases are chosen to avoid collisions with any of the supplied names. The
396
+ * namespace binding (used to hold the imported module) is likewise chosen to
397
+ * avoid collisions.
398
+ *
399
+ * @param {Iterable<string>} names — the export names
400
+ * @param {(name: string, namespace: string) => string} build_expression —
401
+ * called for each name to produce the right-hand side of the declaration;
402
+ * receives the chosen namespace binding so it can reference the imported module
403
+ * @param {string} namespace_prefix — the preferred binding name for the namespace
404
+ * (suffixed with a number if it collides with any export name)
405
+ * @returns {{ namespace: string, declarations: string[], reexports: string[] }}
406
+ */
407
+ export function create_exported_declarations(names, build_expression, namespace_prefix) {
408
+ /** @type {Set<string>} */
409
+ const set = new Set(names);
410
+
411
+ let namespace = namespace_prefix;
412
+ let namespace_index = 0;
413
+ while (set.has(namespace)) {
414
+ namespace = `${namespace_prefix}${namespace_index++}`;
415
+ }
416
+
417
+ let alias_index = 0;
418
+ /** @type {Map<string, string>} */
419
+ const aliases = new Map();
420
+
421
+ for (const name of set) {
422
+ if (!reserved.has(name)) continue;
423
+
424
+ let alias = `_${alias_index++}`;
425
+ while (set.has(alias)) {
426
+ alias = `_${alias_index++}`;
427
+ }
428
+ aliases.set(name, alias);
429
+ }
430
+
431
+ /** @type {string[]} */
432
+ const declarations = [];
433
+ /** @type {string[]} */
434
+ const reexports = [];
435
+
436
+ for (const name of set) {
437
+ const alias = aliases.get(name);
438
+ const expr = build_expression(name, namespace);
439
+ if (alias) {
440
+ declarations.push(`const ${alias} = ${expr};`);
441
+ reexports.push(`${alias} as ${name}`);
442
+ } else {
443
+ declarations.push(`export const ${name} = ${expr};`);
444
+ }
445
+ }
446
+
447
+ return { namespace, declarations, reexports };
448
+ }
@@ -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,7 @@ 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) || '';
97
95
  }
98
96
 
99
97
  // prettier-ignore
@@ -117,10 +115,6 @@ export function generate_manifest({
117
115
  ${routes.map(route => {
118
116
  if (!route.page && !route.endpoint) return;
119
117
 
120
- route.params.forEach(param => {
121
- if (param.matcher) matchers.add(param.matcher);
122
- });
123
-
124
118
  return dedent`
125
119
  {
126
120
  id: ${s(route.id)},
@@ -134,11 +128,14 @@ export function generate_manifest({
134
128
  ],
135
129
  prerendered_routes: new Set(${s(prerendered)}),
136
130
  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(', ')} };
131
+ ${
132
+ uses_matchers && build_data.manifest_data.params
133
+ ? dedent`
134
+ const { params } = await import('${join_relative(relative_path, '/entries/params.js')}');
135
+ return params;
136
+ `
137
+ : 'return {};'
138
+ }
142
139
  },
143
140
  server_assets: ${s(files)}
144
141
  }
@@ -1,4 +1,4 @@
1
- import { lookup } from 'mrmime';
1
+ import { lookup } from '../../../utils/mime.js';
2
2
  import fs from 'node:fs';
3
3
  import path from 'node:path';
4
4
  import { styleText } from 'node:util';
@@ -29,22 +29,13 @@ export default function create_manifest_data({
29
29
  }) {
30
30
  const assets = create_assets(config);
31
31
  const hooks = create_hooks(config, cwd);
32
- const matchers = create_matchers(config, cwd);
32
+ const params = resolve_params(config, cwd);
33
33
  const { nodes, routes } = create_routes_and_nodes(cwd, config, fallback);
34
34
 
35
- // validate matcher names used in parameterised routes
36
- for (const route of routes) {
37
- for (const param of route.params) {
38
- if (param.matcher && !matchers[param.matcher]) {
39
- throw new Error(`No matcher found for parameter '${param.matcher}' in route ${route.id}`);
40
- }
41
- }
42
- }
43
-
44
35
  return {
45
36
  assets,
46
37
  hooks,
47
- matchers,
38
+ params,
48
39
  nodes,
49
40
  routes
50
41
  };
@@ -82,38 +73,9 @@ function create_hooks(config, cwd) {
82
73
  * @param {import('types').ValidatedConfig} config
83
74
  * @param {string} cwd
84
75
  */
85
- function create_matchers(config, cwd) {
86
- const params_base = path.relative(cwd, config.kit.files.params);
87
-
88
- /** @type {Record<string, string>} */
89
- const matchers = {};
90
- if (fs.existsSync(config.kit.files.params)) {
91
- for (const file of fs.readdirSync(config.kit.files.params)) {
92
- const ext = path.extname(file);
93
- if (!config.kit.moduleExtensions.includes(ext)) continue;
94
- const type = file.slice(0, -ext.length);
95
-
96
- if (/^\w+$/.test(type)) {
97
- const matcher_file = path.join(params_base, file);
98
-
99
- // Disallow same matcher with different extensions
100
- if (matchers[type]) {
101
- throw new Error(`Duplicate matchers: ${matcher_file} and ${matchers[type]}`);
102
- } else {
103
- matchers[type] = matcher_file;
104
- }
105
- } else {
106
- // Allow for matcher test collocation
107
- if (type.endsWith('.test') || type.endsWith('.spec')) continue;
108
-
109
- throw new Error(
110
- `Matcher names can only have underscores and alphanumeric characters — "${file}" is invalid`
111
- );
112
- }
113
- }
114
- }
115
-
116
- return matchers;
76
+ function resolve_params(config, cwd) {
77
+ const params_file = resolve_entry(config.kit.files.params);
78
+ return params_file ? posixify(path.relative(cwd, params_file)) : null;
117
79
  }
118
80
 
119
81
  /**
@@ -180,7 +142,7 @@ function create_routes_and_nodes(cwd, config, fallback) {
180
142
  throw new Error(`Route ${id} should be renamed to ${id.replace(/#/g, '[x+23]')}`);
181
143
  }
182
144
 
183
- if (/\[\.\.\.\w+\]\/\[\[/.test(id)) {
145
+ if (/\[\.\.\.[\w-]+\]\/\[\[/.test(id)) {
184
146
  throw new Error(
185
147
  `Invalid route ${id} — an [[optional]] route segment cannot follow a [...rest] route segment`
186
148
  );
@@ -2,7 +2,6 @@ import path from 'node:path';
2
2
  import process from 'node:process';
3
3
  import create_manifest_data from './create_manifest_data/index.js';
4
4
  import { write_client_manifest } from './write_client_manifest.js';
5
- import { write_root } from './write_root.js';
6
5
  import { write_tsconfig } from './write_tsconfig.js';
7
6
  import { write_types, write_all_types } from './write_types/index.js';
8
7
  import { write_ambient } from './write_ambient.js';
@@ -37,7 +36,6 @@ export function create(config, root) {
37
36
 
38
37
  write_client_manifest(config.kit, manifest_data, `${output}/client`);
39
38
  write_server(config, output, root);
40
- write_root(manifest_data, config, output);
41
39
  write_all_types(config, manifest_data, root);
42
40
  write_non_ambient(config.kit, manifest_data);
43
41
 
@@ -139,11 +139,6 @@ export function write_client_manifest(kit, manifest_data, output, metadata) {
139
139
  write_if_changed(
140
140
  `${output}/app.js`,
141
141
  dedent`
142
- // in dev, this makes Vite inject its client as this module's first dependency,
143
- // so that global constant replacements are installed before any other module
144
- // (including user hooks) evaluates. In build it's inert.
145
- import.meta.hot;
146
-
147
142
  ${
148
143
  client_hooks_file
149
144
  ? `import * as client_hooks from '${relative_path(output, client_hooks_file)}';`
@@ -181,28 +176,19 @@ export function write_client_manifest(kit, manifest_data, output, metadata) {
181
176
 
182
177
  export const decode = (type, value) => decoders[type](value);
183
178
 
184
- export { default as root } from '../root.js';
185
-
186
179
  export const get_error_template = () => import('../shared/error-template.js').then(m => m.default);
187
180
  `
188
181
  );
189
182
 
190
183
  if (client_routing) {
191
- // write matchers to a separate module so that we don't
192
- // need to worry about name conflicts
193
- const imports = [];
194
- const matchers = [];
195
-
196
- for (const key in manifest_data.matchers) {
197
- const src = manifest_data.matchers[key];
198
-
199
- imports.push(`import { match as ${key} } from ${s(relative_path(output, src))};`);
200
- matchers.push(key);
201
- }
184
+ const uses_matchers = manifest_data.routes.some((route) =>
185
+ route.params.some((param) => param.matcher)
186
+ );
202
187
 
203
- const module = imports.length
204
- ? `${imports.join('\n')}\n\nexport const matchers = { ${matchers.join(', ')} };`
205
- : 'export const matchers = {};';
188
+ const module =
189
+ !manifest_data.params || !uses_matchers
190
+ ? 'export const matchers = {};'
191
+ : `import { params as matchers } from ${s(relative_path(output, manifest_data.params))};\n\nexport { matchers };`;
206
192
 
207
193
  write_if_changed(`${output}/matchers.js`, module);
208
194
  }
@@ -1,5 +1,6 @@
1
1
  import path from 'node:path';
2
2
  import { GENERATED_COMMENT } from '../../constants.js';
3
+ import { resolve_entry } from '../../utils/filesystem.js';
3
4
  import { posixify } from '../../utils/os.js';
4
5
  import { write_if_changed } from './utils.js';
5
6
  import { s } from '../../utils/misc.js';
@@ -85,10 +86,6 @@ export {};
85
86
  * @param {import('types').ValidatedKitConfig} config
86
87
  */
87
88
  function generate_app_types(manifest_data, config) {
88
- /** @param {string} matcher */
89
- const path_to_matcher = (matcher) =>
90
- posixify(path.relative(config.outDir, path.join(config.files.params, matcher + '.js')));
91
-
92
89
  /** @type {Map<string, string>} */
93
90
  const matcher_types = new Map();
94
91
 
@@ -98,7 +95,15 @@ function generate_app_types(manifest_data, config) {
98
95
 
99
96
  let type = matcher_types.get(matcher);
100
97
  if (!type) {
101
- type = `MatcherParam<typeof import('${path_to_matcher(matcher)}').match>`;
98
+ const path_to_params = () => {
99
+ const params_file =
100
+ resolve_entry(config.files.params) ??
101
+ config.files.params.replace(/\.(js|ts)$/, '') + '.js';
102
+
103
+ return posixify(path.relative(config.outDir, params_file));
104
+ };
105
+
106
+ type = `import('@sveltejs/kit').MatcherParam<(typeof import('${path_to_params()}').params)[${JSON.stringify(matcher)}]>`;
102
107
  matcher_types.set(matcher, type);
103
108
  }
104
109
 
@@ -204,7 +209,7 @@ function generate_app_types(manifest_data, config) {
204
209
  if (route.params.length > 0) {
205
210
  const params = route.params.map((p) => {
206
211
  const type = get_matcher_type(p.matcher);
207
- return `${p.name}${p.optional ? '?:' : ':'} ${type}${p.optional ? ' | undefined' : ''}`;
212
+ return `${/^\w+$/.test(p.name) ? p.name : `'${p.name}'`}${p.optional ? '?:' : ':'} ${type}${p.optional ? ' | undefined' : ''}`;
208
213
  });
209
214
  const route_type = `${s(route.id)}: { ${params.join('; ')} }`;
210
215
 
@@ -225,7 +230,7 @@ function generate_app_types(manifest_data, config) {
225
230
  const params = Array.from(layout_params)
226
231
  .map(([name, { optional, matchers }]) => {
227
232
  const type = get_matchers_type(matchers);
228
- return `${name}${optional ? '?:' : ':'} ${type}${optional ? ' | undefined' : ''}`;
233
+ return `${/^\w+$/.test(name) ? name : `'${name}'`}${optional ? '?:' : ':'} ${type}${optional ? ' | undefined' : ''}`;
229
234
  })
230
235
  .join('; ');
231
236
 
@@ -239,8 +244,6 @@ function generate_app_types(manifest_data, config) {
239
244
 
240
245
  return [
241
246
  'declare module "$app/types" {',
242
- '\ttype MatcherParam<M> = M extends (param : string) => param is (infer U extends string) ? U : string;',
243
- '',
244
247
  '\texport interface AppTypes {',
245
248
  `\t\tRouteId(): ${manifest_data.routes.map((r) => s(r.id)).join(' | ')};`,
246
249
  `\t\tRouteParams(): {\n\t\t\t${dynamic_routes.join(';\n\t\t\t')}\n\t\t};`,
@@ -24,7 +24,6 @@ const server_template = ({
24
24
  has_service_worker,
25
25
  template
26
26
  }) => `
27
- import root from '../root.js';
28
27
  import { set_building, set_prerendering } from '$app/env/internal';
29
28
  import { set_assets } from '$app/paths/internal/server';
30
29
  import { set_manifest, set_read_implementation } from '__sveltekit/server';
@@ -32,7 +31,6 @@ import error from '../shared/error-template.js';
32
31
 
33
32
  export const options = {
34
33
  app_template_contains_nonce: ${template.includes('%sveltekit.nonce%')},
35
- async: ${s(!!config.compilerOptions?.experimental?.async)},
36
34
  csp: ${s(config.kit.csp)},
37
35
  csrf_check_origin: ${s(!config.kit.csrf.trustedOrigins.includes('*'))},
38
36
  csrf_trusted_origins: ${s(config.kit.csrf.trustedOrigins)},
@@ -41,10 +39,8 @@ export const options = {
41
39
  hooks: null, // added lazily, via \`get_hooks\`
42
40
  link_header_preload: ${s(config.kit.output.linkHeaderPreload)},
43
41
  paths_origin: ${s(config.kit.paths.origin)},
44
- root,
45
42
  service_worker: ${has_service_worker},
46
43
  service_worker_options: ${config.kit.serviceWorker.register ? s(config.kit.serviceWorker.options) : 'null'},
47
- server_error_boundaries: ${s(!!config.kit.experimental.handleRenderingErrors)},
48
44
  templates: {
49
45
  app: ({ head, body, assets, nonce, env }) => ${s(template)
50
46
  .replace('%sveltekit.head%', '" + head + "')
@@ -1,7 +1,7 @@
1
1
  import fs from 'node:fs';
2
2
  import path from 'node:path';
3
3
  import MagicString from 'magic-string';
4
- import { rimraf, walk } from '../../../utils/filesystem.js';
4
+ import { rimraf, walk, resolve_entry } from '../../../utils/filesystem.js';
5
5
  import { compact } from '../../../utils/array.js';
6
6
  import { posixify } from '../../../utils/os.js';
7
7
  import { ts } from '../ts.js';
@@ -198,11 +198,6 @@ function update_types(config, routes, route, root, to_delete = new Set()) {
198
198
  // Makes sure a type is "repackaged" and therefore more readable
199
199
  declarations.push('type Expand<T> = T extends infer O ? { [K in keyof O]: O[K] } : never;');
200
200
 
201
- // returns the predicate of a matcher's type guard - or string if there is no type guard
202
- declarations.push(
203
- 'type MatcherParam<M> = M extends (param : string) => param is (infer U extends string) ? U : string;'
204
- );
205
-
206
201
  declarations.push(
207
202
  'type RouteParams = ' + generate_params_type(route.params, outdir, config) + ';'
208
203
  );
@@ -236,7 +231,9 @@ function update_types(config, routes, route, root, to_delete = new Set()) {
236
231
  'type OptionalUnion<U extends Record<string, any>, A extends keyof U = U extends U ? keyof U : never> = U extends unknown ? { [P in Exclude<A, keyof U>]?: never } & U : never;',
237
232
 
238
233
  // Re-export `Snapshot` from @sveltejs/kit — in future we could use this to infer <T> from the return type of `snapshot.capture`
239
- 'export type Snapshot<T = any> = Kit.Snapshot<T>;'
234
+ 'export type Snapshot<T = any> = Kit.Snapshot<T>;',
235
+
236
+ 'export type ErrorProps = { error: App.Error };'
240
237
  );
241
238
  }
242
239
 
@@ -268,15 +265,8 @@ function update_types(config, routes, route, root, to_delete = new Set()) {
268
265
 
269
266
  if (route.leaf.server) {
270
267
  exports.push(
271
- 'export type Action<OutputData extends Record<string, any> | void = Record<string, any> | void> = Kit.Action<RouteParams, OutputData, RouteId>'
272
- );
273
- exports.push(
274
- 'export type Actions<OutputData extends Record<string, any> | void = Record<string, any> | void> = Kit.Actions<RouteParams, OutputData, RouteId>'
275
- );
276
- }
277
-
278
- if (route.leaf.server) {
279
- exports.push(
268
+ 'export type Action<OutputData extends Record<string, any> | void = Record<string, any> | void> = Kit.Action<RouteParams, OutputData, RouteId>',
269
+ 'export type Actions<OutputData extends Record<string, any> | void = Record<string, any> | void> = Kit.Actions<RouteParams, OutputData, RouteId>',
280
270
  'export type PageProps = { params: RouteParams; data: PageData; form: ActionData }'
281
271
  );
282
272
  } else {
@@ -604,16 +594,22 @@ function replace_ext_with_js(file_path) {
604
594
  * @param {import('types').ValidatedConfig} config
605
595
  */
606
596
  function generate_params_type(params, outdir, config) {
607
- /** @param {string} matcher */
608
- const path_to_matcher = (matcher) =>
609
- posixify(path.relative(outdir, path.join(config.kit.files.params, matcher + '.js')));
597
+ const path_to_params = () => {
598
+ const params_file =
599
+ resolve_entry(config.kit.files.params) ??
600
+ config.kit.files.params.replace(/\.(js|ts)$/, '') + '.js';
601
+
602
+ return posixify(path.relative(outdir, params_file));
603
+ };
604
+
605
+ const params_import = path_to_params();
610
606
 
611
607
  return `{ ${params
612
608
  .map(
613
609
  (param) =>
614
- `${param.name}${param.optional ? '?' : ''}: ${
610
+ `${/^\w+$/.test(param.name) ? param.name : `'${param.name}'`}${param.optional ? '?' : ''}: ${
615
611
  param.matcher
616
- ? `MatcherParam<typeof import('${path_to_matcher(param.matcher)}').match>`
612
+ ? `import('@sveltejs/kit').MatcherParam<(typeof import('${params_import}').params)[${JSON.stringify(param.matcher)}]>`
617
613
  : 'string'
618
614
  }${param.optional ? ' | undefined' : ''}`
619
615
  )
@@ -642,6 +638,16 @@ export function tweak_types(content, is_server) {
642
638
  const code = new MagicString(content);
643
639
 
644
640
  const exports = new Map();
641
+ /** @param {import('typescript').BindingName} name */
642
+ function add_export(name) {
643
+ if (ts.isIdentifier(name)) {
644
+ if (names.has(name.text)) exports.set(name.text, name.text);
645
+ } else {
646
+ for (const element of name.elements) {
647
+ if (ts.isBindingElement(element)) add_export(element.name);
648
+ }
649
+ }
650
+ }
645
651
 
646
652
  ast.forEachChild((node) => {
647
653
  if (
@@ -668,9 +674,7 @@ export function tweak_types(content, is_server) {
668
674
 
669
675
  if (ts.isVariableStatement(node)) {
670
676
  node.declarationList.declarations.forEach((declaration) => {
671
- if (ts.isIdentifier(declaration.name) && names.has(declaration.name.text)) {
672
- exports.set(declaration.name.text, declaration.name.text);
673
- }
677
+ add_export(declaration.name);
674
678
  });
675
679
  }
676
680
  }
package/src/core/utils.js CHANGED
@@ -7,7 +7,7 @@ import { noop } from '../utils/functions.js';
7
7
  import { posixify } from '../utils/os.js';
8
8
 
9
9
  /**
10
- * Resolved path of the `runtime` directory
10
+ * Resolved path of the `runtime` directory posix-ified
11
11
  *
12
12
  * TODO Windows issue:
13
13
  * Vite or sth else somehow sets the driver letter inconsistently to lower or upper case depending on the run environment.
@@ -25,7 +25,7 @@ export const runtime_directory = posixify(fileURLToPath(new URL('../runtime', im
25
25
  */
26
26
  export function get_runtime_base(root) {
27
27
  return runtime_directory.startsWith(root)
28
- ? `/${path.relative(root, runtime_directory)}`
28
+ ? `/${posixify(path.relative(root, runtime_directory))}`
29
29
  : to_fs(runtime_directory);
30
30
  }
31
31
 
@@ -1,6 +1,5 @@
1
1
  /** @import { StandardSchemaV1 } from '@standard-schema/spec' */
2
-
3
- import { HttpError, Redirect, ActionFailure, ValidationError } from './internal/index.js';
2
+ import { HttpError, Redirect, ActionFailure, ValidationError } from './internal/shared.js';
4
3
  import { BROWSER, DEV } from 'esm-env';
5
4
  import {
6
5
  add_data_suffix,
@@ -11,9 +10,10 @@ import {
11
10
  strip_resolution_suffix
12
11
  } from '../runtime/pathname.js';
13
12
  import { text_encoder } from '../runtime/utils.js';
14
- import { validate_redirect_location } from '../utils/url.js';
13
+ import { validate_redirect_location } from './url.js';
15
14
 
16
15
  export { VERSION } from '../version.js';
16
+ export { defineParams } from './params.js';
17
17
 
18
18
  // Keep the status codes as `number` because restricting to certain numbers makes it unnecessarily hard to use compared to the benefits
19
19
  // (we have runtime errors already to check for invalid codes). Also see https://github.com/sveltejs/kit/issues/11780
@@ -0,0 +1,5 @@
1
+ export function get_origin() {
2
+ return window.location.origin;
3
+ }
4
+
5
+ export * from './shared.js';
@@ -1,91 +1 @@
1
- /** @import { StandardSchemaV1 } from '@standard-schema/spec' */
2
-
3
- export class HttpError {
4
- /**
5
- * @param {number} status
6
- * @param {Omit<App.Error, 'status'> | string | undefined} body
7
- * @param {Omit<App.Error, 'status' | 'message'>} [properties]
8
- */
9
- constructor(status, body, properties) {
10
- this.status = status;
11
- if (typeof body === 'string') {
12
- this.body = { ...properties, message: body, status };
13
- } else if (body) {
14
- this.body = { ...body, status };
15
- } else {
16
- this.body = { message: `Error: ${status}`, status };
17
- }
18
- }
19
-
20
- toString() {
21
- return JSON.stringify(this.body);
22
- }
23
- }
24
-
25
- export class Redirect {
26
- /**
27
- * @param {300 | 301 | 302 | 303 | 304 | 305 | 306 | 307 | 308} status
28
- * @param {string} location
29
- */
30
- constructor(status, location) {
31
- try {
32
- new Headers({ location });
33
- } catch {
34
- throw new Error(
35
- `Invalid redirect location ${JSON.stringify(location)}: ` +
36
- 'this string contains characters that cannot be used in HTTP headers'
37
- );
38
- }
39
-
40
- this.status = status;
41
- this.location = location;
42
- }
43
- }
44
-
45
- /**
46
- * An error that was thrown from within the SvelteKit runtime that is not fatal and doesn't result in a 500, such as a 404.
47
- * `SvelteKitError` goes through `handleError`.
48
- * @extends Error
49
- */
50
- export class SvelteKitError extends Error {
51
- /**
52
- * @param {number} status
53
- * @param {string} text
54
- * @param {string} message
55
- */
56
- constructor(status, text, message) {
57
- super(message);
58
- this.status = status;
59
- this.text = text;
60
- }
61
- }
62
-
63
- /**
64
- * @template [T=undefined]
65
- */
66
- export class ActionFailure {
67
- /**
68
- * @param {number} status
69
- * @param {T} data
70
- */
71
- constructor(status, data) {
72
- this.status = status;
73
- this.data = data;
74
- }
75
- }
76
-
77
- /**
78
- * Error thrown when form validation fails imperatively
79
- */
80
- export class ValidationError extends Error {
81
- /**
82
- * @param {StandardSchemaV1.Issue[]} issues
83
- */
84
- constructor(issues) {
85
- super('Validation failed');
86
- this.name = 'ValidationError';
87
- this.issues = issues;
88
- }
89
- }
90
-
91
- export { init_remote_functions } from './remote-functions.js';
1
+ export * from '#internal';
@@ -1,8 +1,7 @@
1
1
  /** @import { RequestEvent } from '@sveltejs/kit' */
2
2
  /** @import { RequestStore } from 'types' */
3
3
  /** @import { AsyncLocalStorage } from 'node:async_hooks' */
4
-
5
- import { IN_WEBCONTAINER } from '../../runtime/server/constants.js';
4
+ import { IN_WEBCONTAINER } from '../../../runtime/server/constants.js';
6
5
 
7
6
  /** @type {RequestStore | null} */
8
7
  let sync_store = null;