@sveltejs/kit 1.18.0 → 1.19.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.
Files changed (64) hide show
  1. package/package.json +6 -1
  2. package/src/core/adapt/builder.js +3 -3
  3. package/src/core/config/index.js +2 -2
  4. package/src/core/config/options.js +3 -3
  5. package/src/core/env.js +1 -1
  6. package/src/core/generate_manifest/index.js +2 -2
  7. package/src/core/postbuild/analyse.js +3 -3
  8. package/src/core/postbuild/fallback.js +1 -1
  9. package/src/core/postbuild/prerender.js +1 -1
  10. package/src/core/sync/create_manifest_data/index.js +2 -2
  11. package/src/core/sync/write_ambient.js +1 -1
  12. package/src/core/sync/write_client_manifest.js +1 -1
  13. package/src/core/sync/write_server.js +1 -1
  14. package/src/core/sync/write_types/index.js +24 -24
  15. package/src/exports/hooks/sequence.js +71 -7
  16. package/src/exports/index.js +88 -12
  17. package/src/exports/node/index.js +14 -3
  18. package/src/exports/node/polyfills.js +8 -0
  19. package/src/exports/public.d.ts +1264 -0
  20. package/src/exports/vite/build/build_server.js +2 -2
  21. package/src/exports/vite/build/build_service_worker.js +1 -1
  22. package/src/exports/vite/dev/index.js +3 -3
  23. package/src/exports/vite/index.js +11 -6
  24. package/src/runtime/app/environment.js +3 -4
  25. package/src/runtime/app/forms.js +63 -7
  26. package/src/runtime/app/navigation.js +95 -0
  27. package/src/runtime/app/stores.js +28 -7
  28. package/src/runtime/client/client.js +26 -14
  29. package/src/runtime/client/singletons.js +6 -4
  30. package/src/runtime/client/start.js +1 -1
  31. package/src/runtime/client/types.d.ts +4 -12
  32. package/src/runtime/client/utils.js +29 -10
  33. package/src/runtime/control.js +12 -9
  34. package/src/runtime/server/ambient.d.ts +3 -3
  35. package/src/runtime/server/cookie.js +3 -3
  36. package/src/runtime/server/data/index.js +3 -3
  37. package/src/runtime/server/endpoint.js +11 -4
  38. package/src/runtime/server/fetch.js +4 -6
  39. package/src/runtime/server/index.js +2 -2
  40. package/src/runtime/server/page/actions.js +13 -13
  41. package/src/runtime/server/page/csp.js +7 -2
  42. package/src/runtime/server/page/index.js +4 -4
  43. package/src/runtime/server/page/load_data.js +7 -7
  44. package/src/runtime/server/page/render.js +11 -11
  45. package/src/runtime/server/page/respond_with_error.js +2 -2
  46. package/src/runtime/server/respond.js +6 -6
  47. package/src/runtime/server/utils.js +7 -7
  48. package/src/types/ambient-private.d.ts +11 -0
  49. package/src/types/ambient.d.ts +108 -0
  50. package/{types → src/types}/internal.d.ts +3 -13
  51. package/{types → src/types}/private.d.ts +1 -10
  52. package/src/utils/error.js +3 -3
  53. package/src/utils/exports.js +2 -2
  54. package/src/utils/routing.js +1 -39
  55. package/src/utils/streaming.js +2 -2
  56. package/types/index.d.ts +2079 -1108
  57. package/types/index.d.ts.map +165 -0
  58. package/src/internal.d.ts +0 -16
  59. package/types/ambient.d.ts +0 -486
  60. /package/{types → src/types}/synthetic/$env+dynamic+private.md +0 -0
  61. /package/{types → src/types}/synthetic/$env+dynamic+public.md +0 -0
  62. /package/{types → src/types}/synthetic/$env+static+private.md +0 -0
  63. /package/{types → src/types}/synthetic/$env+static+public.md +0 -0
  64. /package/{types → src/types}/synthetic/$lib.md +0 -0
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@sveltejs/kit",
3
- "version": "1.18.0",
3
+ "version": "1.19.0",
4
4
  "description": "The fastest way to build Svelte apps",
5
5
  "repository": {
6
6
  "type": "git",
@@ -33,6 +33,7 @@
33
33
  "@types/node": "^16.18.6",
34
34
  "@types/sade": "^1.7.4",
35
35
  "@types/set-cookie-parser": "^2.4.2",
36
+ "dts-buddy": "^0.0.9",
36
37
  "marked": "^4.2.3",
37
38
  "rollup": "^3.7.0",
38
39
  "svelte": "^3.56.0",
@@ -64,15 +65,19 @@
64
65
  "import": "./src/exports/index.js"
65
66
  },
66
67
  "./node": {
68
+ "types": "./types/index.d.ts",
67
69
  "import": "./src/exports/node/index.js"
68
70
  },
69
71
  "./node/polyfills": {
72
+ "types": "./types/index.d.ts",
70
73
  "import": "./src/exports/node/polyfills.js"
71
74
  },
72
75
  "./hooks": {
76
+ "types": "./types/index.d.ts",
73
77
  "import": "./src/exports/hooks/index.js"
74
78
  },
75
79
  "./vite": {
80
+ "types": "./types/index.d.ts",
76
81
  "import": "./src/exports/vite/index.js"
77
82
  }
78
83
  },
@@ -24,7 +24,7 @@ const pipe = promisify(pipeline);
24
24
  * prerender_map: import('types').PrerenderMap;
25
25
  * log: import('types').Logger;
26
26
  * }} opts
27
- * @returns {import('types').Builder}
27
+ * @returns {import('@sveltejs/kit').Builder}
28
28
  */
29
29
  export function create_builder({
30
30
  config,
@@ -35,7 +35,7 @@ export function create_builder({
35
35
  prerender_map,
36
36
  log
37
37
  }) {
38
- /** @type {Map<import('types').RouteDefinition, import('types').RouteData>} */
38
+ /** @type {Map<import('@sveltejs/kit').RouteDefinition, import('types').RouteData>} */
39
39
  const lookup = new Map();
40
40
 
41
41
  /**
@@ -47,7 +47,7 @@ export function create_builder({
47
47
  server_metadata.routes.get(route.id)
48
48
  );
49
49
 
50
- /** @type {import('types').RouteDefinition} */
50
+ /** @type {import('@sveltejs/kit').RouteDefinition} */
51
51
  const facade = {
52
52
  id: route.id,
53
53
  api,
@@ -73,7 +73,7 @@ export async function load_config({ cwd = process.cwd() } = {}) {
73
73
  }
74
74
 
75
75
  /**
76
- * @param {import('types').Config} config
76
+ * @param {import('@sveltejs/kit').Config} config
77
77
  * @returns {import('types').ValidatedConfig}
78
78
  */
79
79
  function process_config(config, { cwd = process.cwd() } = {}) {
@@ -95,7 +95,7 @@ function process_config(config, { cwd = process.cwd() } = {}) {
95
95
  }
96
96
 
97
97
  /**
98
- * @param {import('types').Config} config
98
+ * @param {import('@sveltejs/kit').Config} config
99
99
  * @returns {import('types').ValidatedConfig}
100
100
  */
101
101
  export function validate_config(config) {
@@ -210,7 +210,7 @@ const options = object(
210
210
  (/** @type {any} */ { message }) => {
211
211
  throw new Error(
212
212
  message +
213
- `\nTo suppress or handle this error, implement \`handleHttpError\` in https://kit.svelte.dev/docs/configuration#prerender`
213
+ '\nTo suppress or handle this error, implement `handleHttpError` in https://kit.svelte.dev/docs/configuration#prerender'
214
214
  );
215
215
  },
216
216
  (input, keypath) => {
@@ -224,7 +224,7 @@ const options = object(
224
224
  (/** @type {any} */ { message }) => {
225
225
  throw new Error(
226
226
  message +
227
- `\nTo suppress or handle this error, implement \`handleMissingId\` in https://kit.svelte.dev/docs/configuration#prerender`
227
+ '\nTo suppress or handle this error, implement `handleMissingId` in https://kit.svelte.dev/docs/configuration#prerender'
228
228
  );
229
229
  },
230
230
  (input, keypath) => {
@@ -238,7 +238,7 @@ const options = object(
238
238
  (/** @type {any} */ { message }) => {
239
239
  throw new Error(
240
240
  message +
241
- `\nTo suppress or handle this error, implement \`handleEntryGeneratorMismatch\` in https://kit.svelte.dev/docs/configuration#prerender`
241
+ '\nTo suppress or handle this error, implement `handleEntryGeneratorMismatch` in https://kit.svelte.dev/docs/configuration#prerender'
242
242
  );
243
243
  },
244
244
  (input, keypath) => {
package/src/core/env.js CHANGED
@@ -75,7 +75,7 @@ export function create_dynamic_types(id, env, prefix) {
75
75
 
76
76
  if (id === 'private') {
77
77
  properties.push(`${prefixed}: undefined;`);
78
- properties.push(`[key: string]: string | undefined;`);
78
+ properties.push('[key: string]: string | undefined;');
79
79
  } else {
80
80
  properties.push(`${prefixed}: string | undefined;`);
81
81
  }
@@ -55,7 +55,7 @@ export function generate_manifest({ build_data, relative_path, routes }) {
55
55
 
56
56
  /** @param {Array<number | undefined>} indexes */
57
57
  function get_nodes(indexes) {
58
- let string = indexes.map((n) => reindexed.get(n) ?? '').join(',');
58
+ const string = indexes.map((n) => reindexed.get(n) ?? '').join(',');
59
59
 
60
60
  // since JavaScript ignores trailing commas, we need to insert a dummy
61
61
  // comma so that the array has the correct length if the last item
@@ -65,7 +65,7 @@ export function generate_manifest({ build_data, relative_path, routes }) {
65
65
 
66
66
  // prettier-ignore
67
67
  // String representation of
68
- /** @type {import('types').SSRManifest} */
68
+ /** @type {import('@sveltejs/kit').SSRManifest} */
69
69
  return dedent`
70
70
  {
71
71
  appDir: ${s(build_data.app_dir)},
@@ -12,7 +12,7 @@ import { load_config } from '../config/index.js';
12
12
  import { forked } from '../../utils/fork.js';
13
13
  import { should_polyfill } from '../../utils/platform.js';
14
14
  import { installPolyfills } from '../../exports/node/polyfills.js';
15
- import { resolve_entry } from '../../utils/routing.js';
15
+ import { resolvePath } from '../../exports/index.js';
16
16
 
17
17
  export default forked(import.meta.url, analyse);
18
18
 
@@ -23,7 +23,7 @@ export default forked(import.meta.url, analyse);
23
23
  * }} opts
24
24
  */
25
25
  async function analyse({ manifest_path, env }) {
26
- /** @type {import('types').SSRManifest} */
26
+ /** @type {import('@sveltejs/kit').SSRManifest} */
27
27
  const manifest = (await import(pathToFileURL(manifest_path).href)).manifest;
28
28
 
29
29
  /** @type {import('types').ValidatedKitConfig} */
@@ -145,7 +145,7 @@ async function analyse({ manifest_path, env }) {
145
145
  },
146
146
  prerender,
147
147
  entries:
148
- entries && (await entries()).map((entry_object) => resolve_entry(route.id, entry_object))
148
+ entries && (await entries()).map((entry_object) => resolvePath(route.id, entry_object))
149
149
  });
150
150
  }
151
151
 
@@ -27,7 +27,7 @@ async function generate_fallback({ manifest_path, env }) {
27
27
  /** @type {import('types').ServerModule} */
28
28
  const { Server } = await import(pathToFileURL(`${server_root}/server/index.js`).href);
29
29
 
30
- /** @type {import('types').SSRManifest} */
30
+ /** @type {import('@sveltejs/kit').SSRManifest} */
31
31
  const manifest = (await import(pathToFileURL(manifest_path).href)).manifest;
32
32
 
33
33
  set_building(true);
@@ -26,7 +26,7 @@ export default forked(import.meta.url, prerender);
26
26
  * }} opts
27
27
  */
28
28
  async function prerender({ out, manifest_path, metadata, verbose, env }) {
29
- /** @type {import('types').SSRManifest} */
29
+ /** @type {import('@sveltejs/kit').SSRManifest} */
30
30
  const manifest = (await import(pathToFileURL(manifest_path).href)).manifest;
31
31
 
32
32
  /** @type {import('types').ServerInternalModule} */
@@ -456,7 +456,7 @@ function analyze(project_relative, file, component_extensions, module_extensions
456
456
  );
457
457
  }
458
458
 
459
- const kind = !!(match[1] || match[4] || match[7]) ? 'server' : 'universal';
459
+ const kind = match[1] || match[4] || match[7] ? 'server' : 'universal';
460
460
 
461
461
  return {
462
462
  kind,
@@ -513,7 +513,7 @@ function prevent_conflicts(routes) {
513
513
  const normalized = normalize_route_id(route.id);
514
514
 
515
515
  // find all permutations created by optional parameters
516
- const split = normalized.split(/<\?(.+?)\>/g);
516
+ const split = normalized.split(/<\?(.+?)>/g);
517
517
 
518
518
  let permutations = [/** @type {string} */ (split[0])];
519
519
 
@@ -8,7 +8,7 @@ import { write_if_changed } from './utils.js';
8
8
 
9
9
  // TODO these types should be described in a neutral place, rather than
10
10
  // inside either `packages/kit` or `kit.svelte.dev`
11
- const descriptions_dir = fileURLToPath(new URL('../../../types/synthetic', import.meta.url));
11
+ const descriptions_dir = fileURLToPath(new URL('../../../src/types/synthetic', import.meta.url));
12
12
 
13
13
  /** @param {string} filename */
14
14
  function read_description(filename) {
@@ -21,7 +21,7 @@ export function write_client_manifest(kit, manifest_data, output, metadata) {
21
21
  if (node.universal) {
22
22
  declarations.push(
23
23
  `import * as universal from ${s(relative_path(`${output}/nodes`, node.universal))};`,
24
- `export { universal };`
24
+ 'export { universal };'
25
25
  );
26
26
  }
27
27
 
@@ -75,7 +75,7 @@ export { set_assets, set_building, set_private_env, set_public_env };
75
75
  * @param {string} output
76
76
  */
77
77
  export function write_server(config, output) {
78
- // TODO the casting shouldn't be necessary — investigate
78
+ // TODO the casting shouldn't be necessary — investigate
79
79
  const hooks_file = /** @type {string} */ (resolve_entry(config.kit.files.hooks.server));
80
80
 
81
81
  /** @param {string} file */
@@ -52,7 +52,7 @@ export async function write_all_types(config, manifest_data) {
52
52
  // it could be invoked by another process in the meantime.
53
53
  const meta_data_file = `${types_dir}/route_meta_data.json`;
54
54
  const has_meta_data = fs.existsSync(meta_data_file);
55
- let meta_data = has_meta_data
55
+ const meta_data = has_meta_data
56
56
  ? /** @type {Record<string, string[]>} */ (JSON.parse(fs.readFileSync(meta_data_file, 'utf-8')))
57
57
  : {};
58
58
  const routes_map = create_routes_map(manifest_data);
@@ -177,7 +177,7 @@ function update_types(config, routes, route, to_delete = new Set()) {
177
177
  const outdir = path.join(config.kit.outDir, 'types', routes_dir, route.id);
178
178
 
179
179
  // now generate new types
180
- const imports = [`import type * as Kit from '@sveltejs/kit';`];
180
+ const imports = ["import type * as Kit from '@sveltejs/kit';"];
181
181
 
182
182
  /** @type {string[]} */
183
183
  const declarations = [];
@@ -196,7 +196,7 @@ function update_types(config, routes, route, to_delete = new Set()) {
196
196
 
197
197
  if (route.params.length > 0) {
198
198
  exports.push(
199
- `export type EntryGenerator = () => Promise<Array<RouteParams>> | Array<RouteParams>;`
199
+ 'export type EntryGenerator = () => Promise<Array<RouteParams>> | Array<RouteParams>;'
200
200
  );
201
201
  }
202
202
 
@@ -206,24 +206,24 @@ function update_types(config, routes, route, to_delete = new Set()) {
206
206
  if (route.layout || route.leaf) {
207
207
  declarations.push(
208
208
  // If T extends the empty object, void is also allowed as a return type
209
- `type MaybeWithVoid<T> = {} extends T ? T | void : T;`,
209
+ 'type MaybeWithVoid<T> = {} extends T ? T | void : T;',
210
210
 
211
211
  // Returns the key of the object whose values are required.
212
- `export type RequiredKeys<T> = { [K in keyof T]-?: {} extends { [P in K]: T[K] } ? never : K; }[keyof T];`,
212
+ 'export type RequiredKeys<T> = { [K in keyof T]-?: {} extends { [P in K]: T[K] } ? never : K; }[keyof T];',
213
213
 
214
214
  // Helper type to get the correct output type for load functions. It should be passed the parent type to check what types from App.PageData are still required.
215
215
  // If none, void is also allowed as a return type.
216
- `type OutputDataShape<T> = MaybeWithVoid<Omit<App.PageData, RequiredKeys<T>> & Partial<Pick<App.PageData, keyof T & keyof App.PageData>> & Record<string, any>>`,
216
+ 'type OutputDataShape<T> = MaybeWithVoid<Omit<App.PageData, RequiredKeys<T>> & Partial<Pick<App.PageData, keyof T & keyof App.PageData>> & Record<string, any>>',
217
217
 
218
218
  // null & {} == null, we need to prevent that in some situations
219
- `type EnsureDefined<T> = T extends null | undefined ? {} : T;`,
219
+ 'type EnsureDefined<T> = T extends null | undefined ? {} : T;',
220
220
 
221
221
  // Takes a union type and returns a union type where each type also has all properties
222
222
  // of all possible types (typed as undefined), making accessing them more ergonomic
223
- `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;`,
223
+ '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;',
224
224
 
225
225
  // Re-export `Snapshot` from @sveltejs/kit — in future we could use this to infer <T> from the return type of `snapshot.capture`
226
- `export type Snapshot<T = any> = Kit.Snapshot<T>;`
226
+ 'export type Snapshot<T = any> = Kit.Snapshot<T>;'
227
227
  );
228
228
  }
229
229
 
@@ -255,10 +255,10 @@ function update_types(config, routes, route, to_delete = new Set()) {
255
255
 
256
256
  if (route.leaf.server) {
257
257
  exports.push(
258
- `export type Action<OutputData extends Record<string, any> | void = Record<string, any> | void> = Kit.Action<RouteParams, OutputData, RouteId>`
258
+ 'export type Action<OutputData extends Record<string, any> | void = Record<string, any> | void> = Kit.Action<RouteParams, OutputData, RouteId>'
259
259
  );
260
260
  exports.push(
261
- `export type Actions<OutputData extends Record<string, any> | void = Record<string, any> | void> = Kit.Actions<RouteParams, OutputData, RouteId>`
261
+ 'export type Actions<OutputData extends Record<string, any> | void = Record<string, any> | void> = Kit.Actions<RouteParams, OutputData, RouteId>'
262
262
  );
263
263
  }
264
264
  }
@@ -326,11 +326,11 @@ function update_types(config, routes, route, to_delete = new Set()) {
326
326
  }
327
327
 
328
328
  if (route.endpoint) {
329
- exports.push(`export type RequestHandler = Kit.RequestHandler<RouteParams, RouteId>;`);
329
+ exports.push('export type RequestHandler = Kit.RequestHandler<RouteParams, RouteId>;');
330
330
  }
331
331
 
332
332
  if (route.leaf?.server || route.layout?.server || route.endpoint) {
333
- exports.push(`export type RequestEvent = Kit.RequestEvent<RouteParams, RouteId>;`);
333
+ exports.push('export type RequestEvent = Kit.RequestEvent<RouteParams, RouteId>;');
334
334
  }
335
335
 
336
336
  const output = [imports.join('\n'), declarations.join('\n'), exports.join('\n')]
@@ -386,7 +386,7 @@ function process_node(node, outdir, is_page, proxies, all_pages_have_load = true
386
386
  // +page.js load present -> server can return all-optional data
387
387
  const output_data_shape =
388
388
  node.universal || (!is_page && all_pages_have_load)
389
- ? `Partial<App.PageData> & Record<string, any> | void`
389
+ ? 'Partial<App.PageData> & Record<string, any> | void'
390
390
  : `OutputDataShape<${parent_type}>`;
391
391
  exports.push(
392
392
  `export type ${prefix}ServerLoad<OutputData extends ${output_data_shape} = ${output_data_shape}> = Kit.ServerLoad<${params}, ${parent_type}, OutputData, ${route_id}>;`
@@ -404,15 +404,15 @@ function process_node(node, outdir, is_page, proxies, all_pages_have_load = true
404
404
  : path_to_original(outdir, node.server);
405
405
 
406
406
  exports.push(
407
- `type ExcludeActionFailure<T> = T extends Kit.ActionFailure<any> ? never : T extends void ? never : T;`,
408
- `type ActionsSuccess<T extends Record<string, (...args: any) => any>> = { [Key in keyof T]: ExcludeActionFailure<Awaited<ReturnType<T[Key]>>>; }[keyof T];`,
409
- `type ExtractActionFailure<T> = T extends Kit.ActionFailure<infer X> ? X extends void ? never : X : never;`,
410
- `type ActionsFailure<T extends Record<string, (...args: any) => any>> = { [Key in keyof T]: Exclude<ExtractActionFailure<Awaited<ReturnType<T[Key]>>>, void>; }[keyof T];`,
407
+ 'type ExcludeActionFailure<T> = T extends Kit.ActionFailure<any> ? never : T extends void ? never : T;',
408
+ 'type ActionsSuccess<T extends Record<string, (...args: any) => any>> = { [Key in keyof T]: ExcludeActionFailure<Awaited<ReturnType<T[Key]>>>; }[keyof T];',
409
+ 'type ExtractActionFailure<T> = T extends Kit.ActionFailure<infer X> ? X extends void ? never : X : never;',
410
+ 'type ActionsFailure<T extends Record<string, (...args: any) => any>> = { [Key in keyof T]: Exclude<ExtractActionFailure<Awaited<ReturnType<T[Key]>>>, void>; }[keyof T];',
411
411
  `type ActionsExport = typeof import('${from}').actions`,
412
- `export type SubmitFunction = Kit.SubmitFunction<Expand<ActionsSuccess<ActionsExport>>, Expand<ActionsFailure<ActionsExport>>>`
412
+ 'export type SubmitFunction = Kit.SubmitFunction<Expand<ActionsSuccess<ActionsExport>>, Expand<ActionsFailure<ActionsExport>>>'
413
413
  );
414
414
 
415
- type = `Expand<Kit.AwaitedActions<ActionsExport>> | null`;
415
+ type = 'Expand<Kit.AwaitedActions<ActionsExport>> | null';
416
416
  }
417
417
  exports.push(`export type ActionData = ${type};`);
418
418
  }
@@ -440,7 +440,7 @@ function process_node(node, outdir, is_page, proxies, all_pages_have_load = true
440
440
 
441
441
  const output_data_shape =
442
442
  !is_page && all_pages_have_load
443
- ? `Partial<App.PageData> & Record<string, any> | void`
443
+ ? 'Partial<App.PageData> & Record<string, any> | void'
444
444
  : `OutputDataShape<${parent_type}>`;
445
445
  exports.push(
446
446
  `export type ${prefix}Load<OutputData extends ${output_data_shape} = ${output_data_shape}> = Kit.Load<${params}, ${prefix}ServerData, ${parent_type}, OutputData, ${route_id}>;`
@@ -688,7 +688,7 @@ export function tweak_types(content, is_server) {
688
688
  // remove type from `export const load: Load ...`
689
689
  if (declaration.type) {
690
690
  let a = declaration.type.pos;
691
- let b = declaration.type.end;
691
+ const b = declaration.type.end;
692
692
  while (/\s/.test(content[a])) a += 1;
693
693
 
694
694
  const type = content.slice(a, b);
@@ -760,7 +760,7 @@ export function tweak_types(content, is_server) {
760
760
  // remove type from `export const actions: Actions ...`
761
761
  if (declaration.type) {
762
762
  let a = declaration.type.pos;
763
- let b = declaration.type.end;
763
+ const b = declaration.type.end;
764
764
  while (/\s/.test(content[a])) a += 1;
765
765
 
766
766
  const type = content.slice(a, b);
@@ -788,7 +788,7 @@ export function tweak_types(content, is_server) {
788
788
  if (arg && !arg.type) {
789
789
  code.appendLeft(
790
790
  arg.name.end,
791
- `: import('./$types').RequestEvent` + (add_parens ? ')' : '')
791
+ ": import('./$types').RequestEvent" + (add_parens ? ')' : '')
792
792
  );
793
793
  }
794
794
  }
@@ -1,6 +1,70 @@
1
1
  /**
2
- * @param {...import('types').Handle} handlers
3
- * @returns {import('types').Handle}
2
+ * A helper function for sequencing multiple `handle` calls in a middleware-like manner.
3
+ * The behavior for the `handle` options is as follows:
4
+ * - `transformPageChunk` is applied in reverse order and merged
5
+ * - `preload` is applied in forward order, the first option "wins" and no `preload` options after it are called
6
+ * - `filterSerializedResponseHeaders` behaves the same as `preload`
7
+ *
8
+ * ```js
9
+ * /// file: src/hooks.server.js
10
+ * import { sequence } from '@sveltejs/kit/hooks';
11
+ *
12
+ * /// type: import('@sveltejs/kit').Handle
13
+ * async function first({ event, resolve }) {
14
+ * console.log('first pre-processing');
15
+ * const result = await resolve(event, {
16
+ * transformPageChunk: ({ html }) => {
17
+ * // transforms are applied in reverse order
18
+ * console.log('first transform');
19
+ * return html;
20
+ * },
21
+ * preload: () => {
22
+ * // this one wins as it's the first defined in the chain
23
+ * console.log('first preload');
24
+ * }
25
+ * });
26
+ * console.log('first post-processing');
27
+ * return result;
28
+ * }
29
+ *
30
+ * /// type: import('@sveltejs/kit').Handle
31
+ * async function second({ event, resolve }) {
32
+ * console.log('second pre-processing');
33
+ * const result = await resolve(event, {
34
+ * transformPageChunk: ({ html }) => {
35
+ * console.log('second transform');
36
+ * return html;
37
+ * },
38
+ * preload: () => {
39
+ * console.log('second preload');
40
+ * },
41
+ * filterSerializedResponseHeaders: () => {
42
+ * // this one wins as it's the first defined in the chain
43
+ * console.log('second filterSerializedResponseHeaders');
44
+ * }
45
+ * });
46
+ * console.log('second post-processing');
47
+ * return result;
48
+ * }
49
+ *
50
+ * export const handle = sequence(first, second);
51
+ * ```
52
+ *
53
+ * The example above would print:
54
+ *
55
+ * ```
56
+ * first pre-processing
57
+ * first preload
58
+ * second pre-processing
59
+ * second filterSerializedResponseHeaders
60
+ * second transform
61
+ * first transform
62
+ * second post-processing
63
+ * first post-processing
64
+ * ```
65
+ *
66
+ * @param {...import('@sveltejs/kit').Handle} handlers The chain of `handle` functions
67
+ * @returns {import('@sveltejs/kit').Handle}
4
68
  */
5
69
  export function sequence(...handlers) {
6
70
  const length = handlers.length;
@@ -11,8 +75,8 @@ export function sequence(...handlers) {
11
75
 
12
76
  /**
13
77
  * @param {number} i
14
- * @param {import('types').RequestEvent} event
15
- * @param {import('types').ResolveOptions | undefined} parent_options
78
+ * @param {import('@sveltejs/kit').RequestEvent} event
79
+ * @param {import('@sveltejs/kit').ResolveOptions | undefined} parent_options
16
80
  * @returns {import('types').MaybePromise<Response>}
17
81
  */
18
82
  function apply_handle(i, event, parent_options) {
@@ -21,7 +85,7 @@ export function sequence(...handlers) {
21
85
  return handle({
22
86
  event,
23
87
  resolve: (event, options) => {
24
- /** @type {import('types').ResolveOptions['transformPageChunk']} */
88
+ /** @type {import('@sveltejs/kit').ResolveOptions['transformPageChunk']} */
25
89
  const transformPageChunk = async ({ html, done }) => {
26
90
  if (options?.transformPageChunk) {
27
91
  html = (await options.transformPageChunk({ html, done })) ?? '';
@@ -34,12 +98,12 @@ export function sequence(...handlers) {
34
98
  return html;
35
99
  };
36
100
 
37
- /** @type {import('types').ResolveOptions['filterSerializedResponseHeaders']} */
101
+ /** @type {import('@sveltejs/kit').ResolveOptions['filterSerializedResponseHeaders']} */
38
102
  const filterSerializedResponseHeaders =
39
103
  parent_options?.filterSerializedResponseHeaders ??
40
104
  options?.filterSerializedResponseHeaders;
41
105
 
42
- /** @type {import('types').ResolveOptions['preload']} */
106
+ /** @type {import('@sveltejs/kit').ResolveOptions['preload']} */
43
107
  const preload = parent_options?.preload ?? options?.preload;
44
108
 
45
109
  return i < length - 1
@@ -1,22 +1,43 @@
1
1
  import { HttpError, Redirect, ActionFailure } from '../runtime/control.js';
2
2
  import { BROWSER, DEV } from 'esm-env';
3
+ import { get_route_segments } from '../utils/routing.js';
3
4
 
4
- // For some reason we need to type the params as well here,
5
- // JSdoc doesn't seem to like @type with function overloads
6
5
  /**
7
- * @type {import('@sveltejs/kit').error}
6
+ * @overload
8
7
  * @param {number} status
9
- * @param {any} message
8
+ * @param {App.Error} body
9
+ * @return {HttpError}
10
10
  */
11
- export function error(status, message) {
11
+
12
+ /**
13
+ * @overload
14
+ * @param {number} status
15
+ * @param {{ message: string } extends App.Error ? App.Error | string | undefined : never} [body]
16
+ * @return {HttpError}
17
+ */
18
+
19
+ /**
20
+ * Creates an `HttpError` object with an HTTP status code and an optional message.
21
+ * This object, if thrown during request handling, will cause SvelteKit to
22
+ * return an error response without invoking `handleError`.
23
+ * Make sure you're not catching the thrown error, which would prevent SvelteKit from handling it.
24
+ * @param {number} status The [HTTP status code](https://developer.mozilla.org/en-US/docs/Web/HTTP/Status#client_error_responses). Must be in the range 400-599.
25
+ * @param {{ message: string } extends App.Error ? App.Error | string | undefined : never} body An object that conforms to the App.Error type. If a string is passed, it will be used as the message property.
26
+ */
27
+ export function error(status, body) {
12
28
  if ((!BROWSER || DEV) && (isNaN(status) || status < 400 || status > 599)) {
13
29
  throw new Error(`HTTP error status codes must be between 400 and 599 — ${status} is invalid`);
14
30
  }
15
31
 
16
- return new HttpError(status, message);
32
+ return new HttpError(status, body);
17
33
  }
18
34
 
19
- /** @type {import('@sveltejs/kit').redirect} */
35
+ /**
36
+ * Create a `Redirect` object. If thrown during request handling, SvelteKit will return a redirect response.
37
+ * Make sure you're not catching the thrown redirect, which would prevent SvelteKit from handling it.
38
+ * @param {300 | 301 | 302 | 303 | 304 | 305 | 306 | 307 | 308} status The [HTTP status code](https://developer.mozilla.org/en-US/docs/Web/HTTP/Status#redirection_messages). Must be in the range 300-308.
39
+ * @param {string} location The location to redirect to.
40
+ */
20
41
  export function redirect(status, location) {
21
42
  if ((!BROWSER || DEV) && (isNaN(status) || status < 300 || status > 308)) {
22
43
  throw new Error('Invalid status code');
@@ -25,7 +46,11 @@ export function redirect(status, location) {
25
46
  return new Redirect(status, location);
26
47
  }
27
48
 
28
- /** @type {import('@sveltejs/kit').json} */
49
+ /**
50
+ * Create a JSON `Response` object from the supplied data.
51
+ * @param {any} data The value that will be serialized as JSON.
52
+ * @param {ResponseInit} [init] Options such as `status` and `headers` that will be added to the response. `Content-Type: application/json` and `Content-Length` headers will be added automatically.
53
+ */
29
54
  export function json(data, init) {
30
55
  // TODO deprecate this in favour of `Response.json` when it's
31
56
  // more widely supported
@@ -51,7 +76,11 @@ export function json(data, init) {
51
76
 
52
77
  const encoder = new TextEncoder();
53
78
 
54
- /** @type {import('@sveltejs/kit').text} */
79
+ /**
80
+ * Create a `Response` object from the supplied body.
81
+ * @param {string} body The value that will be used as-is.
82
+ * @param {ResponseInit} [init] Options such as `status` and `headers` that will be added to the response. A `Content-Length` header will be added automatically.
83
+ */
55
84
  export function text(body, init) {
56
85
  const headers = new Headers(init?.headers);
57
86
  if (!headers.has('content-length')) {
@@ -65,10 +94,57 @@ export function text(body, init) {
65
94
  }
66
95
 
67
96
  /**
68
- * Generates an `ActionFailure` object.
69
- * @param {number} status
70
- * @param {Record<string, any> | undefined} [data]
97
+ * Create an `ActionFailure` object.
98
+ * @template {Record<string, unknown> | undefined} [T=undefined]
99
+ * @param {number} status The [HTTP status code](https://developer.mozilla.org/en-US/docs/Web/HTTP/Status#client_error_responses). Must be in the range 400-599.
100
+ * @param {T} [data] Data associated with the failure (e.g. validation errors)
101
+ * @returns {ActionFailure<T>}
71
102
  */
72
103
  export function fail(status, data) {
73
104
  return new ActionFailure(status, data);
74
105
  }
106
+
107
+ const basic_param_pattern = /\[(\[)?(?:\.\.\.)?(\w+?)(?:=(\w+))?\]\]?/g;
108
+
109
+ /**
110
+ * Populate a route ID with params to resolve a pathname.
111
+ * @example
112
+ * ```js
113
+ * resolvePath(
114
+ * `/blog/[slug]/[...somethingElse]`,
115
+ * {
116
+ * slug: 'hello-world',
117
+ * somethingElse: 'something/else'
118
+ * }
119
+ * ); // `/blog/hello-world/something/else`
120
+ * ```
121
+ * @param {string} id
122
+ * @param {Record<string, string | undefined>} params
123
+ * @returns {string}
124
+ */
125
+ export function resolvePath(id, params) {
126
+ const segments = get_route_segments(id);
127
+ return (
128
+ '/' +
129
+ segments
130
+ .map((segment) =>
131
+ segment.replace(basic_param_pattern, (_, optional, name) => {
132
+ const param_value = params[name];
133
+
134
+ // This is nested so TS correctly narrows the type
135
+ if (!param_value) {
136
+ if (optional) return '';
137
+ throw new Error(`Missing parameter '${name}' in route ${id}`);
138
+ }
139
+
140
+ if (param_value.startsWith('/') || param_value.endsWith('/'))
141
+ throw new Error(
142
+ `Parameter '${name}' in route ${id} cannot start or end with a slash -- this would cause an invalid route like foo//bar`
143
+ );
144
+ return param_value;
145
+ })
146
+ )
147
+ .filter(Boolean)
148
+ .join('/')
149
+ );
150
+ }