@sveltejs/kit 1.0.0-next.410 → 1.0.0-next.413

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@sveltejs/kit",
3
- "version": "1.0.0-next.410",
3
+ "version": "1.0.0-next.413",
4
4
  "repository": {
5
5
  "type": "git",
6
6
  "url": "https://github.com/sveltejs/kit",
@@ -25,7 +25,7 @@
25
25
  "undici": "^5.8.1"
26
26
  },
27
27
  "devDependencies": {
28
- "@playwright/test": "^1.23.4",
28
+ "@playwright/test": "^1.25.0",
29
29
  "@types/connect": "^3.4.35",
30
30
  "@types/cookie": "^0.5.1",
31
31
  "@types/marked": "^4.0.3",
@@ -1,3 +1,5 @@
1
1
  // in `vite dev` and `vite preview`, we use a fake asset path so that we can
2
2
  // serve local assets while verifying that requests are correctly prefixed
3
3
  export const SVELTE_KIT_ASSETS = '/_svelte_kit_assets';
4
+
5
+ export const GENERATED_COMMENT = '// this file is generated — do not edit it\n';
@@ -0,0 +1,91 @@
1
+ import { GENERATED_COMMENT } from './constants.js';
2
+
3
+ /**
4
+ * @param {string} id
5
+ * @param {Record<string, string>} env
6
+ * @returns {string}
7
+ */
8
+ export function create_module(id, env) {
9
+ /** @type {string[]} */
10
+ const declarations = [];
11
+
12
+ for (const key in env) {
13
+ if (!valid_identifier.test(key) || reserved.has(key)) {
14
+ continue;
15
+ }
16
+
17
+ const comment = `/** @type {import('${id}').${key}} */`;
18
+ const declaration = `export const ${key} = ${JSON.stringify(env[key])};`;
19
+
20
+ declarations.push(`${comment}\n${declaration}`);
21
+ }
22
+
23
+ return GENERATED_COMMENT + declarations.join('\n\n');
24
+ }
25
+
26
+ /**
27
+ * @param {string} id
28
+ * @param {Record<string, string>} env
29
+ * @returns {string}
30
+ */
31
+ export function create_types(id, env) {
32
+ const declarations = Object.keys(env)
33
+ .filter((k) => valid_identifier.test(k))
34
+ .map((k) => `\texport const ${k}: string;`)
35
+ .join('\n');
36
+
37
+ return `declare module '${id}' {\n${declarations}\n}`;
38
+ }
39
+
40
+ export const reserved = new Set([
41
+ 'do',
42
+ 'if',
43
+ 'in',
44
+ 'for',
45
+ 'let',
46
+ 'new',
47
+ 'try',
48
+ 'var',
49
+ 'case',
50
+ 'else',
51
+ 'enum',
52
+ 'eval',
53
+ 'null',
54
+ 'this',
55
+ 'true',
56
+ 'void',
57
+ 'with',
58
+ 'await',
59
+ 'break',
60
+ 'catch',
61
+ 'class',
62
+ 'const',
63
+ 'false',
64
+ 'super',
65
+ 'throw',
66
+ 'while',
67
+ 'yield',
68
+ 'delete',
69
+ 'export',
70
+ 'import',
71
+ 'public',
72
+ 'return',
73
+ 'static',
74
+ 'switch',
75
+ 'typeof',
76
+ 'default',
77
+ 'extends',
78
+ 'finally',
79
+ 'package',
80
+ 'private',
81
+ 'continue',
82
+ 'debugger',
83
+ 'function',
84
+ 'arguments',
85
+ 'interface',
86
+ 'protected',
87
+ 'implements',
88
+ 'instanceof'
89
+ ]);
90
+
91
+ export const valid_identifier = /^[a-zA-Z_$][a-zA-Z0-9_$]*$/;
@@ -67,14 +67,7 @@ export default function create_manifest_data({
67
67
 
68
68
  if (file[0] !== '+') return; // not a route file
69
69
 
70
- const item = analyze(file, config.extensions, config.kit.moduleExtensions);
71
-
72
- if (!item) {
73
- throw new Error(
74
- `Files and directories prefixed with + are reserved (saw ${project_relative})`
75
- );
76
- }
77
-
70
+ const item = analyze(project_relative, file, config.extensions, config.kit.moduleExtensions);
78
71
  const id = segments.join('/');
79
72
 
80
73
  if (/\]\[/.test(id)) {
@@ -275,19 +268,22 @@ export default function create_manifest_data({
275
268
  }
276
269
 
277
270
  /**
271
+ * @param {string} project_relative
278
272
  * @param {string} file
279
273
  * @param {string[]} component_extensions
280
274
  * @param {string[]} module_extensions
281
- * @returns {import('./types').RouteFile | null}
275
+ * @returns {import('./types').RouteFile}
282
276
  */
283
- function analyze(file, component_extensions, module_extensions) {
277
+ function analyze(project_relative, file, component_extensions, module_extensions) {
284
278
  const component_extension = component_extensions.find((ext) => file.endsWith(ext));
285
279
  if (component_extension) {
286
280
  const name = file.slice(0, -component_extension.length);
287
281
  const pattern =
288
282
  /^\+(?:(page(?:@([a-zA-Z0-9_-]+))?)|(layout(?:-([a-zA-Z0-9_-]+))?(?:@([a-zA-Z0-9_-]+))?)|(error))$/;
289
283
  const match = pattern.exec(name);
290
- if (!match) return null;
284
+ if (!match) {
285
+ throw new Error(`Files prefixed with + are reserved (saw ${project_relative})`);
286
+ }
291
287
 
292
288
  return {
293
289
  kind: 'component',
@@ -302,21 +298,29 @@ function analyze(file, component_extensions, module_extensions) {
302
298
  const module_extension = module_extensions.find((ext) => file.endsWith(ext));
303
299
  if (module_extension) {
304
300
  const name = file.slice(0, -module_extension.length);
305
- const pattern = /^\+(?:(server)|(page(\.server)?)|(layout(?:-([a-zA-Z0-9_-]+))?(\.server)?))$/;
301
+ const pattern =
302
+ /^\+(?:(server)|(page(?:@([a-zA-Z0-9_-]+))?(\.server)?)|(layout(?:-([a-zA-Z0-9_-]+))?(?:@([a-zA-Z0-9_-]+))?(\.server)?))$/;
306
303
  const match = pattern.exec(name);
307
- if (!match) return null;
304
+ if (!match) {
305
+ throw new Error(`Files prefixed with + are reserved (saw ${project_relative})`);
306
+ } else if (match[3] || match[7]) {
307
+ throw new Error(
308
+ // prettier-ignore
309
+ `Only Svelte files can reference named layouts. Remove '@${match[3] || match[7]}' from ${file} (at ${project_relative})`
310
+ );
311
+ }
308
312
 
309
- const kind = !!(match[1] || match[3] || match[6]) ? 'server' : 'shared';
313
+ const kind = !!(match[1] || match[4] || match[8]) ? 'server' : 'shared';
310
314
 
311
315
  return {
312
316
  kind,
313
317
  is_page: !!match[2],
314
- is_layout: !!match[4],
315
- declares_layout: match[5]
318
+ is_layout: !!match[5],
319
+ declares_layout: match[6]
316
320
  };
317
321
  }
318
322
 
319
- return null;
323
+ throw new Error(`Files and directories prefixed with + are reserved (saw ${project_relative})`);
320
324
  }
321
325
 
322
326
  /**
@@ -42,56 +42,3 @@ export function trim(str) {
42
42
  const pattern = new RegExp(`^${indentation}`, 'gm');
43
43
  return str.replace(pattern, '').trim();
44
44
  }
45
-
46
- export const reserved = new Set([
47
- 'do',
48
- 'if',
49
- 'in',
50
- 'for',
51
- 'let',
52
- 'new',
53
- 'try',
54
- 'var',
55
- 'case',
56
- 'else',
57
- 'enum',
58
- 'eval',
59
- 'null',
60
- 'this',
61
- 'true',
62
- 'void',
63
- 'with',
64
- 'await',
65
- 'break',
66
- 'catch',
67
- 'class',
68
- 'const',
69
- 'false',
70
- 'super',
71
- 'throw',
72
- 'while',
73
- 'yield',
74
- 'delete',
75
- 'export',
76
- 'import',
77
- 'public',
78
- 'return',
79
- 'static',
80
- 'switch',
81
- 'typeof',
82
- 'default',
83
- 'extends',
84
- 'finally',
85
- 'package',
86
- 'private',
87
- 'continue',
88
- 'debugger',
89
- 'function',
90
- 'arguments',
91
- 'interface',
92
- 'protected',
93
- 'implements',
94
- 'instanceof'
95
- ]);
96
-
97
- export const valid_identifier = /^[a-zA-Z_$][a-zA-Z0-9_$]*$/;
@@ -1,9 +1,9 @@
1
1
  import path from 'path';
2
- import colors from 'kleur';
3
2
  import { get_env } from '../../vite/utils.js';
4
- import { write_if_changed, reserved, valid_identifier } from './utils.js';
3
+ import { GENERATED_COMMENT } from '../constants.js';
4
+ import { create_types } from '../env.js';
5
+ import { write_if_changed } from './utils.js';
5
6
 
6
- const autogen_comment = '// this file is generated — do not edit it\n';
7
7
  const types_reference = '/// <reference types="@sveltejs/kit" />\n\n';
8
8
 
9
9
  /**
@@ -16,72 +16,12 @@ const types_reference = '/// <reference types="@sveltejs/kit" />\n\n';
16
16
  export function write_ambient(config, mode) {
17
17
  const env = get_env(mode, config.env.publicPrefix);
18
18
 
19
- // TODO when testing src, `$app` points at `src/runtime/app`... will
20
- // probably need to fiddle with aliases
21
- write_if_changed(
22
- path.join(config.outDir, 'runtime/env/static/public.js'),
23
- create_env_module('$env/static/public', env.public)
24
- );
25
-
26
- write_if_changed(
27
- path.join(config.outDir, 'runtime/env/static/private.js'),
28
- create_env_module('$env/static/private', env.private)
29
- );
30
-
31
19
  write_if_changed(
32
20
  path.join(config.outDir, 'ambient.d.ts'),
33
- autogen_comment +
21
+ GENERATED_COMMENT +
34
22
  types_reference +
35
- create_env_types('$env/static/public', env.public) +
23
+ create_types('$env/static/public', env.public) +
36
24
  '\n\n' +
37
- create_env_types('$env/static/private', env.private)
25
+ create_types('$env/static/private', env.private)
38
26
  );
39
27
  }
40
-
41
- /**
42
- * @param {string} id
43
- * @param {Record<string, string>} env
44
- * @returns {string}
45
- */
46
- function create_env_module(id, env) {
47
- /** @type {string[]} */
48
- const declarations = [];
49
-
50
- for (const key in env) {
51
- const warning = !valid_identifier.test(key)
52
- ? 'not a valid identifier'
53
- : reserved.has(key)
54
- ? 'a reserved word'
55
- : null;
56
-
57
- if (warning) {
58
- console.error(
59
- colors
60
- .bold()
61
- .yellow(`Omitting environment variable "${key}" from ${id} as it is ${warning}`)
62
- );
63
- continue;
64
- }
65
-
66
- const comment = `/** @type {import('${id}').${key}} */`;
67
- const declaration = `export const ${key} = ${JSON.stringify(env[key])};`;
68
-
69
- declarations.push(`${comment}\n${declaration}`);
70
- }
71
-
72
- return autogen_comment + declarations.join('\n\n');
73
- }
74
-
75
- /**
76
- * @param {string} id
77
- * @param {Record<string, string>} env
78
- * @returns {string}
79
- */
80
- function create_env_types(id, env) {
81
- const declarations = Object.keys(env)
82
- .filter((k) => valid_identifier.test(k))
83
- .map((k) => `\texport const ${k}: string;`)
84
- .join('\n');
85
-
86
- return `declare module '${id}' {\n${declarations}\n}`;
87
- }
@@ -616,7 +616,11 @@ export function tweak_types(ts, content, names) {
616
616
 
617
617
  const rhs = declaration.initializer;
618
618
 
619
- if (rhs && (ts.isArrowFunction(rhs) || ts.isFunctionExpression(rhs))) {
619
+ if (
620
+ rhs &&
621
+ (ts.isArrowFunction(rhs) || ts.isFunctionExpression(rhs)) &&
622
+ rhs.parameters.length
623
+ ) {
620
624
  const arg = rhs.parameters[0];
621
625
 
622
626
  const add_parens = content[arg.pos - 1] !== '(';
@@ -389,6 +389,7 @@ export function create_client({ target, session, base, trailing_slash }) {
389
389
  * status: number;
390
390
  * error: HttpError | Error | null;
391
391
  * routeId: string | null;
392
+ * validation_errors?: string | undefined;
392
393
  * }} opts
393
394
  */
394
395
  async function get_navigation_result_from_branch({
@@ -397,7 +398,8 @@ export function create_client({ target, session, base, trailing_slash }) {
397
398
  branch,
398
399
  status,
399
400
  error,
400
- routeId
401
+ routeId,
402
+ validation_errors
401
403
  }) {
402
404
  const filtered = /** @type {import('./types').BranchNode[] } */ (branch.filter(Boolean));
403
405
 
@@ -412,7 +414,8 @@ export function create_client({ target, session, base, trailing_slash }) {
412
414
  session_id
413
415
  },
414
416
  props: {
415
- components: filtered.map((branch_node) => branch_node.node.component)
417
+ components: filtered.map((branch_node) => branch_node.node.component),
418
+ errors: validation_errors
416
419
  }
417
420
  };
418
421
 
@@ -1211,8 +1214,16 @@ export function create_client({ target, session, base, trailing_slash }) {
1211
1214
  let result;
1212
1215
 
1213
1216
  try {
1214
- const script = document.querySelector(`script[sveltekit\\:data-type="server_data"]`);
1215
- const server_data = script?.textContent ? JSON.parse(script.textContent) : [];
1217
+ /**
1218
+ * @param {string} type
1219
+ * @param {any} fallback
1220
+ */
1221
+ const parse = (type, fallback) => {
1222
+ const script = document.querySelector(`script[sveltekit\\:data-type="${type}"]`);
1223
+ return script?.textContent ? JSON.parse(script.textContent) : fallback;
1224
+ };
1225
+ const server_data = parse('server_data', []);
1226
+ const validation_errors = parse('validation_errors', undefined);
1216
1227
 
1217
1228
  const branch_promises = node_ids.map(async (n, i) => {
1218
1229
  return load_node({
@@ -1243,6 +1254,7 @@ export function create_client({ target, session, base, trailing_slash }) {
1243
1254
  error.message
1244
1255
  )
1245
1256
  : error,
1257
+ validation_errors,
1246
1258
  routeId
1247
1259
  });
1248
1260
  } catch (e) {
@@ -52,6 +52,7 @@ export function create_fetch({ event, options, state, route }) {
52
52
  if (
53
53
  key !== 'authorization' &&
54
54
  key !== 'connection' &&
55
+ key !== 'content-length' &&
55
56
  key !== 'cookie' &&
56
57
  key !== 'host' &&
57
58
  key !== 'if-none-match' &&
@@ -79,20 +79,6 @@ export async function render_response({
79
79
  }
80
80
 
81
81
  if (resolve_opts.ssr) {
82
- for (const { node } of branch) {
83
- if (node.imports) {
84
- node.imports.forEach((url) => modulepreloads.add(url));
85
- }
86
-
87
- if (node.stylesheets) {
88
- node.stylesheets.forEach((url) => stylesheets.add(url));
89
- }
90
-
91
- if (node.inline_styles) {
92
- Object.entries(await node.inline_styles()).forEach(([k, v]) => inline_styles.set(k, v));
93
- }
94
- }
95
-
96
82
  const session = writable($session);
97
83
 
98
84
  /** @type {Record<string, any>} */
@@ -112,7 +98,7 @@ export async function render_response({
112
98
  url: state.prerendering ? new PrerenderingURL(event.url) : event.url,
113
99
  data: branch.reduce((acc, { data }) => (Object.assign(acc, data), acc), {})
114
100
  },
115
- components: branch.map(({ node }) => node.component)
101
+ components: await Promise.all(branch.map(({ node }) => node.component()))
116
102
  };
117
103
 
118
104
  // TODO remove this for 1.0
@@ -143,6 +129,20 @@ export async function render_response({
143
129
  }
144
130
 
145
131
  rendered = options.root.render(props);
132
+
133
+ for (const { node } of branch) {
134
+ if (node.imports) {
135
+ node.imports.forEach((url) => modulepreloads.add(url));
136
+ }
137
+
138
+ if (node.stylesheets) {
139
+ node.stylesheets.forEach((url) => stylesheets.add(url));
140
+ }
141
+
142
+ if (node.inline_styles) {
143
+ Object.entries(await node.inline_styles()).forEach(([k, v]) => inline_styles.set(k, v));
144
+ }
145
+ }
146
146
  } else {
147
147
  rendered = { head: '', html: '', css: { code: '', map: null } };
148
148
  }
@@ -266,6 +266,12 @@ export async function render_response({
266
266
  );
267
267
  }
268
268
 
269
+ if (validation_errors) {
270
+ serialized_data.push(
271
+ render_json_payload_script({ type: 'validation_errors' }, validation_errors)
272
+ );
273
+ }
274
+
269
275
  body += `\n\t${serialized_data.join('\n\t')}`;
270
276
  }
271
277
 
@@ -239,6 +239,8 @@ export async function build_server(options, client) {
239
239
  /** @type {string[]} */
240
240
  const imports = [];
241
241
 
242
+ // String representation of
243
+ /** @type {import('types').SSRNode} */
242
244
  /** @type {string[]} */
243
245
  const exports = [`export const index = ${i};`];
244
246
 
@@ -255,7 +257,9 @@ export async function build_server(options, client) {
255
257
  stylesheets.push(...entry.stylesheets);
256
258
 
257
259
  exports.push(
258
- `export { default as component } from '../${vite_manifest[node.component].file}';`,
260
+ `export const component = async () => (await import('../${
261
+ vite_manifest[node.component].file
262
+ }')).default;`,
259
263
  `export const file = '${entry.file}';` // TODO what is this?
260
264
  );
261
265
  }
@@ -82,19 +82,23 @@ export async function dev(vite, vite_config, svelte_config, illegal_imports) {
82
82
  result.stylesheets = [];
83
83
 
84
84
  if (node.component) {
85
- const { module, module_node, url } = await resolve(node.component);
86
-
87
- module_nodes.push(module_node);
88
-
89
- result.component = module.default;
90
- result.file = url.endsWith('.svelte') ? url : url + '?import'; // TODO what is this for?
91
-
92
- prevent_illegal_vite_imports(
93
- module_node,
94
- illegal_imports,
95
- extensions,
96
- svelte_config.kit.outDir
97
- );
85
+ result.component = async () => {
86
+ const { module_node, module, url } = await resolve(
87
+ /** @type {string} */ (node.component)
88
+ );
89
+
90
+ module_nodes.push(module_node);
91
+ result.file = url.endsWith('.svelte') ? url : url + '?import'; // TODO what is this for?
92
+
93
+ prevent_illegal_vite_imports(
94
+ module_node,
95
+ illegal_imports,
96
+ extensions,
97
+ svelte_config.kit.outDir
98
+ );
99
+
100
+ return module.default;
101
+ };
98
102
  }
99
103
 
100
104
  if (node.shared) {
package/src/vite/index.js CHANGED
@@ -14,8 +14,9 @@ import { generate_manifest } from '../core/generate_manifest/index.js';
14
14
  import { runtime_directory, logger } from '../core/utils.js';
15
15
  import { find_deps, get_default_config as get_default_build_config } from './build/utils.js';
16
16
  import { preview } from './preview/index.js';
17
- import { get_aliases, resolve_entry, prevent_illegal_rollup_imports } from './utils.js';
17
+ import { get_aliases, resolve_entry, prevent_illegal_rollup_imports, get_env } from './utils.js';
18
18
  import { fileURLToPath } from 'node:url';
19
+ import { create_module } from '../core/env.js';
19
20
 
20
21
  const cwd = process.cwd();
21
22
 
@@ -107,6 +108,9 @@ function kit() {
107
108
  /** @type {string | undefined} */
108
109
  let deferred_warning;
109
110
 
111
+ /** @type {{ public: Record<string, string>; private: Record<string, string> }} */
112
+ let env;
113
+
110
114
  /**
111
115
  * @type {{
112
116
  * build_dir: string;
@@ -191,13 +195,13 @@ function kit() {
191
195
  * @see https://vitejs.dev/guide/api-plugin.html#config
192
196
  */
193
197
  async config(config, config_env) {
194
- // The config is created in build_server for SSR mode and passed inline
195
- if (config.build?.ssr) {
196
- return;
197
- }
198
-
199
198
  vite_config_env = config_env;
200
199
  svelte_config = await load_config();
200
+ env = get_env(vite_config_env.mode, svelte_config.kit.env.publicPrefix);
201
+
202
+ // The config is created in build_server for SSR mode and passed inline
203
+ if (config.build?.ssr) return;
204
+
201
205
  is_build = config_env.command === 'build';
202
206
 
203
207
  paths = {
@@ -269,6 +273,20 @@ function kit() {
269
273
  return result;
270
274
  },
271
275
 
276
+ async resolveId(id) {
277
+ // treat $env/static/[public|private] as virtual
278
+ if (id.startsWith('$env/static/')) return `\0${id}`;
279
+ },
280
+
281
+ async load(id) {
282
+ switch (id) {
283
+ case '\0$env/static/private':
284
+ return create_module('$env/static/private', env.private);
285
+ case '\0$env/static/public':
286
+ return create_module('$env/static/public', env.public);
287
+ }
288
+ },
289
+
272
290
  /**
273
291
  * Stores the final config.
274
292
  */
@@ -432,9 +450,10 @@ function kit() {
432
450
  await adapt(svelte_config, build_data, prerendered, { log });
433
451
  } else {
434
452
  console.log(colors.bold().yellow('\nNo adapter specified'));
435
- // prettier-ignore
453
+
454
+ const link = colors.bold().cyan('https://kit.svelte.dev/docs/adapters');
436
455
  console.log(
437
- `See ${colors.bold().cyan('https://kit.svelte.dev/docs/adapters')} to learn how to configure your app to run on the platform of your choosing`
456
+ `See ${link} to learn how to configure your app to run on the platform of your choosing`
438
457
  );
439
458
  }
440
459
 
package/src/vite/utils.js CHANGED
@@ -105,6 +105,8 @@ export function get_aliases(config) {
105
105
  const alias = [
106
106
  { find: '__GENERATED__', replacement: path.posix.join(config.outDir, 'generated') },
107
107
  { find: '$app', replacement: `${runtime_directory}/app` },
108
+ { find: '$env/dynamic/public', replacement: `${runtime_directory}/env/dynamic/public.js` },
109
+ { find: '$env/dynamic/private', replacement: `${runtime_directory}/env/dynamic/private.js` },
108
110
  // For now, we handle `$lib` specially here rather than make it a default value for
109
111
  // `config.kit.alias` since it has special meaning for packaging, etc.
110
112
  { find: '$lib', replacement: config.files.lib }
@@ -128,21 +130,6 @@ export function get_aliases(config) {
128
130
  }
129
131
  }
130
132
 
131
- alias.push(
132
- {
133
- find: '$env/static/public',
134
- replacement: path.posix.join(config.outDir, 'runtime/env/static/public.js')
135
- },
136
- {
137
- find: '$env/static/private',
138
- replacement: path.posix.join(config.outDir, 'runtime/env/static/private.js')
139
- },
140
- {
141
- find: '$env',
142
- replacement: `${runtime_directory}/env`
143
- }
144
- );
145
-
146
133
  return alias;
147
134
  }
148
135
 
@@ -141,7 +141,8 @@ export interface PageData {
141
141
 
142
142
  export type PayloadScriptAttributes =
143
143
  | { type: 'data'; url: string; body?: string }
144
- | { type: 'server_data' };
144
+ | { type: 'server_data' }
145
+ | { type: 'validation_errors' };
145
146
 
146
147
  export interface PrerenderDependency {
147
148
  response: Response;
@@ -195,7 +196,7 @@ export interface SSREndpoint {
195
196
  }
196
197
 
197
198
  export interface SSRNode {
198
- component: SSRComponent;
199
+ component: SSRComponentLoader;
199
200
  /** index into the `components` array in client-manifest.js */
200
201
  index: number;
201
202
  /** client-side module URL for this component */
@@ -280,11 +281,6 @@ export interface SSRErrorPage {
280
281
  id: '__error';
281
282
  }
282
283
 
283
- export interface SSRPagePart {
284
- id: string;
285
- load: SSRComponentLoader;
286
- }
287
-
288
284
  export type SSRRoute = SSREndpoint | SSRPage;
289
285
 
290
286
  export interface SSRState {