@sveltejs/kit 1.0.0-next.262 → 1.0.0-next.266

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.
@@ -1464,10 +1464,6 @@ class Renderer {
1464
1464
  * }} opts
1465
1465
  */
1466
1466
  async function start({ paths, target, session, route, spa, trailing_slash, hydrate }) {
1467
- if (import.meta.env.DEV && !target) {
1468
- throw new Error('Missing target element. See https://kit.svelte.dev/docs#configuration-target');
1469
- }
1470
-
1471
1467
  const renderer = new Renderer({
1472
1468
  Root,
1473
1469
  fallback,
@@ -7,12 +7,12 @@ function to_headers(object) {
7
7
  const value = object[key];
8
8
  if (!value) continue;
9
9
 
10
- if (typeof value === 'string') {
11
- headers.set(key, value);
12
- } else {
10
+ if (Array.isArray(value)) {
13
11
  value.forEach((value) => {
14
- headers.append(key, value);
12
+ headers.append(key, /** @type {string} */ (value));
15
13
  });
14
+ } else {
15
+ headers.set(key, /** @type {string} */ (value));
16
16
  }
17
17
  }
18
18
  }
@@ -38,6 +38,16 @@ function hash(value) {
38
38
  }
39
39
 
40
40
  /** @param {Record<string, any>} obj */
41
+ function lowercase_keys(obj) {
42
+ /** @type {Record<string, any>} */
43
+ const clone = {};
44
+
45
+ for (const key in obj) {
46
+ clone[key.toLowerCase()] = obj[key];
47
+ }
48
+
49
+ return clone;
50
+ }
41
51
 
42
52
  /** @param {Record<string, string>} params */
43
53
  function decode_params(params) {
@@ -137,7 +147,9 @@ async function render_endpoint(event, mod) {
137
147
 
138
148
  const { status = 200, body = {} } = response;
139
149
  const headers =
140
- response.headers instanceof Headers ? response.headers : to_headers(response.headers);
150
+ response.headers instanceof Headers
151
+ ? new Headers(response.headers)
152
+ : to_headers(response.headers);
141
153
 
142
154
  const type = headers.get('content-type');
143
155
 
@@ -475,6 +487,16 @@ function coalesce_to_error(err) {
475
487
 
476
488
  /** @type {Record<string, string>} */
477
489
  const escape_json_in_html_dict = {
490
+ '&': '\\u0026',
491
+ '>': '\\u003e',
492
+ '<': '\\u003c',
493
+ '\u2028': '\\u2028',
494
+ '\u2029': '\\u2029'
495
+ };
496
+
497
+ /** @type {Record<string, string>} */
498
+ const escape_json_value_in_html_dict = {
499
+ '"': '\\"',
478
500
  '<': '\\u003C',
479
501
  '>': '\\u003E',
480
502
  '/': '\\u002F',
@@ -489,53 +511,30 @@ const escape_json_in_html_dict = {
489
511
  '\u2029': '\\u2029'
490
512
  };
491
513
 
492
- /** @type {Record<string, string>} */
493
- const escape_json_string_in_html_dict = {
494
- '"': '\\"',
495
- ...escape_json_in_html_dict
496
- };
497
-
498
514
  /**
499
515
  * Escape a stringified JSON object that's going to be embedded in a `<script>` tag
500
516
  * @param {string} str
501
517
  */
502
518
  function escape_json_in_html(str) {
503
- return escape(str, escape_json_in_html_dict, (code) => `\\u${code.toString(16).toUpperCase()}`);
519
+ // adapted from https://github.com/vercel/next.js/blob/694407450638b037673c6d714bfe4126aeded740/packages/next/server/htmlescape.ts
520
+ // based on https://github.com/zertosh/htmlescape
521
+ // License: https://github.com/zertosh/htmlescape/blob/0527ca7156a524d256101bb310a9f970f63078ad/LICENSE
522
+ return str.replace(/[&><\u2028\u2029]/g, (match) => escape_json_in_html_dict[match]);
504
523
  }
505
524
 
506
525
  /**
507
526
  * Escape a string JSON value to be embedded into a `<script>` tag
508
527
  * @param {string} str
509
528
  */
510
- function escape_json_string_in_html(str) {
529
+ function escape_json_value_in_html(str) {
511
530
  return escape(
512
531
  str,
513
- escape_json_string_in_html_dict,
532
+ escape_json_value_in_html_dict,
514
533
  (code) => `\\u${code.toString(16).toUpperCase()}`
515
534
  );
516
535
  }
517
536
 
518
- /** @type {Record<string, string>} */
519
- const escape_html_attr_dict = {
520
- '<': '&lt;',
521
- '>': '&gt;',
522
- '"': '&quot;'
523
- };
524
-
525
537
  /**
526
- * use for escaping string values to be used html attributes on the page
527
- * e.g.
528
- * <script data-url="here">
529
- *
530
- * @param {string} str
531
- * @returns string escaped string
532
- */
533
- function escape_html_attr(str) {
534
- return '"' + escape(str, escape_html_attr_dict, (code) => `&#${code};`) + '"';
535
- }
536
-
537
- /**
538
- *
539
538
  * @param str {string} string to escape
540
539
  * @param dict {Record<string, string>} dictionary of character replacements
541
540
  * @param unicode_encoder {function(number): string} encoder to use for high unicode characters
@@ -568,6 +567,25 @@ function escape(str, dict, unicode_encoder) {
568
567
  return result;
569
568
  }
570
569
 
570
+ /** @type {Record<string, string>} */
571
+ const escape_html_attr_dict = {
572
+ '<': '&lt;',
573
+ '>': '&gt;',
574
+ '"': '&quot;'
575
+ };
576
+
577
+ /**
578
+ * use for escaping string values to be used html attributes on the page
579
+ * e.g.
580
+ * <script data-url="here">
581
+ *
582
+ * @param {string} str
583
+ * @returns string escaped string
584
+ */
585
+ function escape_html_attr(str) {
586
+ return '"' + escape(str, escape_html_attr_dict, (code) => `&#${code};`) + '"';
587
+ }
588
+
571
589
  const s = JSON.stringify;
572
590
 
573
591
  /** @param {URL} url */
@@ -1730,7 +1748,7 @@ async function load_node({
1730
1748
  fetched.push({
1731
1749
  url: requested,
1732
1750
  body: /** @type {string} */ (opts.body),
1733
- json: `{"status":${response.status},"statusText":${s(response.statusText)},"headers":${s(headers)},"body":"${escape_json_string_in_html(body)}"}`
1751
+ json: `{"status":${response.status},"statusText":${s(response.statusText)},"headers":${s(headers)},"body":"${escape_json_value_in_html(body)}"}`
1734
1752
  });
1735
1753
  }
1736
1754
 
@@ -1870,13 +1888,8 @@ async function load_shadow_data(route, event, prerender) {
1870
1888
 
1871
1889
  if (result.fallthrough) return result;
1872
1890
 
1873
- const { status = 200, headers = {}, body = {} } = result;
1874
-
1875
- validate_shadow_output(headers, body);
1876
-
1877
- if (headers['set-cookie']) {
1878
- /** @type {string[]} */ (data.cookies).push(...headers['set-cookie']);
1879
- }
1891
+ const { status, headers, body } = validate_shadow_output(result);
1892
+ add_cookies(/** @type {string[]} */ (data.cookies), headers);
1880
1893
 
1881
1894
  // Redirects are respected...
1882
1895
  if (status >= 300 && status < 400) {
@@ -1900,13 +1913,8 @@ async function load_shadow_data(route, event, prerender) {
1900
1913
 
1901
1914
  if (result.fallthrough) return result;
1902
1915
 
1903
- const { status = 200, headers = {}, body = {} } = result;
1904
-
1905
- validate_shadow_output(headers, body);
1906
-
1907
- if (headers['set-cookie']) {
1908
- /** @type {string[]} */ (data.cookies).push(...headers['set-cookie']);
1909
- }
1916
+ const { status, headers, body } = validate_shadow_output(result);
1917
+ add_cookies(/** @type {string[]} */ (data.cookies), headers);
1910
1918
 
1911
1919
  if (status >= 400) {
1912
1920
  return {
@@ -1937,19 +1945,42 @@ async function load_shadow_data(route, event, prerender) {
1937
1945
  }
1938
1946
 
1939
1947
  /**
1940
- * @param {Headers | Partial<import('types/helper').ResponseHeaders>} headers
1941
- * @param {import('types/helper').JSONValue} body
1948
+ * @param {string[]} target
1949
+ * @param {Partial<import('types/helper').ResponseHeaders>} headers
1942
1950
  */
1943
- function validate_shadow_output(headers, body) {
1944
- if (headers instanceof Headers && headers.has('set-cookie')) {
1945
- throw new Error(
1946
- 'Shadow endpoint request handler cannot use Headers interface with Set-Cookie headers'
1947
- );
1951
+ function add_cookies(target, headers) {
1952
+ const cookies = headers['set-cookie'];
1953
+ if (cookies) {
1954
+ if (Array.isArray(cookies)) {
1955
+ target.push(...cookies);
1956
+ } else {
1957
+ target.push(/** @type {string} */ (cookies));
1958
+ }
1959
+ }
1960
+ }
1961
+
1962
+ /**
1963
+ * @param {import('types/endpoint').ShadowEndpointOutput} result
1964
+ */
1965
+ function validate_shadow_output(result) {
1966
+ const { status = 200, body = {} } = result;
1967
+ let headers = result.headers || {};
1968
+
1969
+ if (headers instanceof Headers) {
1970
+ if (headers.has('set-cookie')) {
1971
+ throw new Error(
1972
+ 'Shadow endpoint request handler cannot use Headers interface with Set-Cookie headers'
1973
+ );
1974
+ }
1975
+ } else {
1976
+ headers = lowercase_keys(/** @type {Record<string, string>} */ (headers));
1948
1977
  }
1949
1978
 
1950
1979
  if (!is_pojo(body)) {
1951
1980
  throw new Error('Body returned from shadow endpoint request handler must be a plain object');
1952
1981
  }
1982
+
1983
+ return { status, headers, body };
1953
1984
  }
1954
1985
 
1955
1986
  /**
@@ -2282,7 +2313,7 @@ function get_page_config(leaf, options) {
2282
2313
  // TODO remove for 1.0
2283
2314
  if ('ssr' in leaf) {
2284
2315
  throw new Error(
2285
- '`export const ssr` has been removed — use the handle hook instead: https://kit.svelte.dev/docs#hooks-handle'
2316
+ '`export const ssr` has been removed — use the handle hook instead: https://kit.svelte.dev/docs/hooks#handle'
2286
2317
  );
2287
2318
  }
2288
2319
 
@@ -2453,7 +2484,7 @@ async function respond(request, options, state = {}) {
2453
2484
  });
2454
2485
  } else {
2455
2486
  const verb = allowed.length === 0 ? 'enabled' : 'allowed';
2456
- const body = `${parameter}=${method_override} is not ${verb}. See https://kit.svelte.dev/docs#configuration-methodoverride`;
2487
+ const body = `${parameter}=${method_override} is not ${verb}. See https://kit.svelte.dev/docs/configuration#methodoverride`;
2457
2488
 
2458
2489
  return new Response(body, {
2459
2490
  status: 400
@@ -211,7 +211,7 @@ async function create_plugin(config, cwd) {
211
211
  if (/** @type {any} */ (hooks).getContext) {
212
212
  // TODO remove this for 1.0
213
213
  throw new Error(
214
- 'The getContext hook has been removed. See https://kit.svelte.dev/docs#hooks'
214
+ 'The getContext hook has been removed. See https://kit.svelte.dev/docs/hooks'
215
215
  );
216
216
  }
217
217
 
@@ -333,27 +333,7 @@ function crawl(html) {
333
333
 
334
334
  /** @type {Record<string, string>} */
335
335
 
336
- /** @type {Record<string, string>} */
337
- const escape_html_attr_dict = {
338
- '<': '&lt;',
339
- '>': '&gt;',
340
- '"': '&quot;'
341
- };
342
-
343
336
  /**
344
- * use for escaping string values to be used html attributes on the page
345
- * e.g.
346
- * <script data-url="here">
347
- *
348
- * @param {string} str
349
- * @returns string escaped string
350
- */
351
- function escape_html_attr(str) {
352
- return '"' + escape(str, escape_html_attr_dict, (code) => `&#${code};`) + '"';
353
- }
354
-
355
- /**
356
- *
357
337
  * @param str {string} string to escape
358
338
  * @param dict {Record<string, string>} dictionary of character replacements
359
339
  * @param unicode_encoder {function(number): string} encoder to use for high unicode characters
@@ -386,27 +366,46 @@ function escape(str, dict, unicode_encoder) {
386
366
  return result;
387
367
  }
388
368
 
369
+ /** @type {Record<string, string>} */
370
+ const escape_html_attr_dict = {
371
+ '<': '&lt;',
372
+ '>': '&gt;',
373
+ '"': '&quot;'
374
+ };
375
+
376
+ /**
377
+ * use for escaping string values to be used html attributes on the page
378
+ * e.g.
379
+ * <script data-url="here">
380
+ *
381
+ * @param {string} str
382
+ * @returns string escaped string
383
+ */
384
+ function escape_html_attr(str) {
385
+ return '"' + escape(str, escape_html_attr_dict, (code) => `&#${code};`) + '"';
386
+ }
387
+
389
388
  /**
390
389
  * @typedef {import('types/config').PrerenderErrorHandler} PrerenderErrorHandler
391
390
  * @typedef {import('types/config').PrerenderOnErrorValue} OnError
392
391
  * @typedef {import('types/internal').Logger} Logger
393
392
  */
394
393
 
395
- /** @type {(errorDetails: Parameters<PrerenderErrorHandler>[0] ) => string} */
396
- function errorDetailsToString({ status, path, referrer, referenceType }) {
394
+ /** @type {(details: Parameters<PrerenderErrorHandler>[0] ) => string} */
395
+ function format_error({ status, path, referrer, referenceType }) {
397
396
  return `${status} ${path}${referrer ? ` (${referenceType} from ${referrer})` : ''}`;
398
397
  }
399
398
 
400
399
  /** @type {(log: Logger, onError: OnError) => PrerenderErrorHandler} */
401
- function chooseErrorHandler(log, onError) {
400
+ function normalise_error_handler(log, onError) {
402
401
  switch (onError) {
403
402
  case 'continue':
404
- return (errorDetails) => {
405
- log.error(errorDetailsToString(errorDetails));
403
+ return (details) => {
404
+ log.error(format_error(details));
406
405
  };
407
406
  case 'fail':
408
- return (errorDetails) => {
409
- throw new Error(errorDetailsToString(errorDetails));
407
+ return (details) => {
408
+ throw new Error(format_error(details));
410
409
  };
411
410
  default:
412
411
  return onError;
@@ -456,7 +455,7 @@ async function prerender({ cwd, out, log, config, build_data, fallback, all }) {
456
455
 
457
456
  const app = new App(manifest);
458
457
 
459
- const error = chooseErrorHandler(log, config.kit.prerender.onError);
458
+ const error = normalise_error_handler(log, config.kit.prerender.onError);
460
459
 
461
460
  const files = new Set([
462
461
  ...build_data.static,
@@ -493,12 +492,15 @@ async function prerender({ cwd, out, log, config, build_data, fallback, all }) {
493
492
  * @param {boolean} is_html
494
493
  */
495
494
  function output_filename(path, is_html) {
495
+ path = path.slice(config.kit.paths.base.length) || '/';
496
+
496
497
  if (path === '/') {
497
498
  return '/index.html';
498
499
  }
500
+
499
501
  const parts = path.split('/');
500
502
  if (is_html && parts[parts.length - 1] !== 'index.html') {
501
- if (config.kit.prerender.createIndexFiles) {
503
+ if (config.kit.trailingSlash === 'always') {
502
504
  parts.push('index.html');
503
505
  } else {
504
506
  parts[parts.length - 1] += '.html';
@@ -526,114 +528,113 @@ async function prerender({ cwd, out, log, config, build_data, fallback, all }) {
526
528
  * @param {string?} referrer
527
529
  */
528
530
  async function visit(path, decoded_path, referrer) {
531
+ if (!path.startsWith(config.kit.paths.base)) {
532
+ error({ status: 404, path, referrer, referenceType: 'linked' });
533
+ return;
534
+ }
535
+
529
536
  /** @type {Map<string, import('types/internal').PrerenderDependency>} */
530
537
  const dependencies = new Map();
531
538
 
532
- const render_path = config.kit.paths?.base
533
- ? `http://sveltekit-prerender${config.kit.paths.base}${path === '/' ? '' : path}`
534
- : `http://sveltekit-prerender${path}`;
535
-
536
- const rendered = await app.render(new Request(render_path), {
539
+ const rendered = await app.render(new Request(`http://sveltekit-prerender${path}`), {
537
540
  prerender: {
538
541
  all,
539
542
  dependencies
540
543
  }
541
544
  });
542
545
 
543
- if (rendered) {
544
- const response_type = Math.floor(rendered.status / 100);
545
- const type = rendered.headers.get('content-type');
546
- const is_html = response_type === REDIRECT || type === 'text/html';
546
+ const response_type = Math.floor(rendered.status / 100);
547
+ const type = rendered.headers.get('content-type');
548
+ const is_html = response_type === REDIRECT || type === 'text/html';
547
549
 
548
- const file = `${out}${output_filename(decoded_path, is_html)}`;
550
+ const file = `${out}${output_filename(decoded_path, is_html)}`;
549
551
 
550
- if (response_type === REDIRECT) {
551
- const location = rendered.headers.get('location');
552
+ if (response_type === REDIRECT) {
553
+ const location = rendered.headers.get('location');
552
554
 
553
- if (location) {
554
- mkdirp(dirname(file));
555
+ if (location) {
556
+ mkdirp(dirname(file));
555
557
 
556
- log.warn(`${rendered.status} ${decoded_path} -> ${location}`);
558
+ log.warn(`${rendered.status} ${decoded_path} -> ${location}`);
557
559
 
558
- writeFileSync(
559
- file,
560
- `<meta http-equiv="refresh" content=${escape_html_attr(`0;url=${location}`)}>`
561
- );
560
+ writeFileSync(
561
+ file,
562
+ `<meta http-equiv="refresh" content=${escape_html_attr(`0;url=${location}`)}>`
563
+ );
562
564
 
563
- const resolved = resolve(path, location);
564
- if (is_root_relative(resolved)) {
565
- enqueue(resolved, path);
566
- }
567
- } else {
568
- log.warn(`location header missing on redirect received from ${decoded_path}`);
565
+ const resolved = resolve(path, location);
566
+ if (is_root_relative(resolved)) {
567
+ enqueue(resolved, path);
569
568
  }
570
-
571
- return;
569
+ } else {
570
+ log.warn(`location header missing on redirect received from ${decoded_path}`);
572
571
  }
573
572
 
574
- const text = await rendered.text();
573
+ return;
574
+ }
575
575
 
576
- if (rendered.status === 200) {
577
- mkdirp(dirname(file));
576
+ const text = await rendered.text();
578
577
 
579
- log.info(`${rendered.status} ${decoded_path}`);
580
- writeFileSync(file, text);
581
- paths.push(normalize(decoded_path));
582
- } else if (response_type !== OK) {
583
- error({ status: rendered.status, path, referrer, referenceType: 'linked' });
584
- }
578
+ if (rendered.status === 200) {
579
+ mkdirp(dirname(file));
585
580
 
586
- for (const [dependency_path, result] of dependencies) {
587
- const { status, headers } = result.response;
581
+ log.info(`${rendered.status} ${decoded_path}`);
582
+ writeFileSync(file, text);
583
+ paths.push(normalize(decoded_path));
584
+ } else if (response_type !== OK) {
585
+ error({ status: rendered.status, path, referrer, referenceType: 'linked' });
586
+ }
588
587
 
589
- const response_type = Math.floor(status / 100);
588
+ for (const [dependency_path, result] of dependencies) {
589
+ const { status, headers } = result.response;
590
590
 
591
- const is_html = headers.get('content-type') === 'text/html';
591
+ const response_type = Math.floor(status / 100);
592
592
 
593
- const file = `${out}${output_filename(dependency_path, is_html)}`;
594
- mkdirp(dirname(file));
593
+ const is_html = headers.get('content-type') === 'text/html';
595
594
 
596
- writeFileSync(
597
- file,
598
- result.body === null ? new Uint8Array(await result.response.arrayBuffer()) : result.body
599
- );
600
- paths.push(dependency_path);
601
-
602
- if (response_type === OK) {
603
- log.info(`${status} ${dependency_path}`);
604
- } else {
605
- error({
606
- status,
607
- path: dependency_path,
608
- referrer: path,
609
- referenceType: 'fetched'
610
- });
611
- }
595
+ const file = `${out}${output_filename(dependency_path, is_html)}`;
596
+ mkdirp(dirname(file));
597
+
598
+ writeFileSync(
599
+ file,
600
+ result.body === null ? new Uint8Array(await result.response.arrayBuffer()) : result.body
601
+ );
602
+ paths.push(dependency_path);
603
+
604
+ if (response_type === OK) {
605
+ log.info(`${status} ${dependency_path}`);
606
+ } else {
607
+ error({
608
+ status,
609
+ path: dependency_path,
610
+ referrer: path,
611
+ referenceType: 'fetched'
612
+ });
612
613
  }
614
+ }
613
615
 
614
- if (is_html && config.kit.prerender.crawl) {
615
- for (const href of crawl(text)) {
616
- if (href.startsWith('data:') || href.startsWith('#')) continue;
616
+ if (is_html && config.kit.prerender.crawl) {
617
+ for (const href of crawl(text)) {
618
+ if (href.startsWith('data:') || href.startsWith('#')) continue;
617
619
 
618
- const resolved = resolve(path, href);
619
- if (!is_root_relative(resolved)) continue;
620
+ const resolved = resolve(path, href);
621
+ if (!is_root_relative(resolved)) continue;
620
622
 
621
- const parsed = new URL(resolved, 'http://localhost');
623
+ const parsed = new URL(resolved, 'http://localhost');
622
624
 
623
- let pathname = decodeURI(parsed.pathname);
625
+ let pathname = decodeURI(parsed.pathname);
624
626
 
625
- if (config.kit.paths.base) {
626
- if (!pathname.startsWith(config.kit.paths.base)) continue;
627
- pathname = pathname.slice(config.kit.paths.base.length) || '/';
628
- }
627
+ if (config.kit.paths.base) {
628
+ if (!pathname.startsWith(config.kit.paths.base)) continue;
629
+ pathname = pathname.slice(config.kit.paths.base.length) || '/';
630
+ }
629
631
 
630
- const file = pathname.slice(1);
631
- if (files.has(file)) continue;
632
+ const file = pathname.slice(1);
633
+ if (files.has(file)) continue;
632
634
 
633
- if (parsed.search) ;
635
+ if (parsed.search) ;
634
636
 
635
- enqueue(pathname, path);
636
- }
637
+ enqueue(pathname, path);
637
638
  }
638
639
  }
639
640
  }
@@ -642,10 +643,10 @@ async function prerender({ cwd, out, log, config, build_data, fallback, all }) {
642
643
  for (const entry of config.kit.prerender.entries) {
643
644
  if (entry === '*') {
644
645
  for (const entry of build_data.entries) {
645
- enqueue(entry, null);
646
+ enqueue(config.kit.paths.base + entry, null);
646
647
  }
647
648
  } else {
648
- enqueue(entry, null);
649
+ enqueue(config.kit.paths.base + entry, null);
649
650
  }
650
651
  }
651
652
 
@@ -701,6 +702,7 @@ function create_builder({ cwd, config, build_data, log }) {
701
702
  copy,
702
703
 
703
704
  appDir: config.kit.appDir,
705
+ trailingSlash: config.kit.trailingSlash,
704
706
 
705
707
  createEntries(fn) {
706
708
  generated_manifest = true;
@@ -15296,14 +15296,16 @@ async function make_package(config, cwd = process.cwd()) {
15296
15296
  const svelte_ext = config.extensions.find((ext) => file.endsWith(ext)); // unlike `ext`, could be e.g. `.svelte.md`
15297
15297
 
15298
15298
  if (!config.kit.package.files(normalized)) {
15299
- const dts_file = (svelte_ext ? file : file.slice(0, -ext.length)) + '.d.ts';
15300
- const dts_path = path.join(package_dir, dts_file);
15301
- if (fs.existsSync(dts_path)) {
15302
- fs.unlinkSync(dts_path);
15303
-
15304
- const dir = path.dirname(dts_path);
15305
- if (fs.readdirSync(dir).length === 0) {
15306
- fs.rmdirSync(dir);
15299
+ const base = svelte_ext ? file : file.slice(0, -ext.length);
15300
+ for (const e of ['.d.ts', '.d.mts', '.d.cts']) {
15301
+ const dts_path = path.join(package_dir, base + e);
15302
+ if (fs.existsSync(dts_path)) {
15303
+ fs.unlinkSync(dts_path);
15304
+
15305
+ const dir = path.dirname(dts_path);
15306
+ if (fs.readdirSync(dir).length === 0) {
15307
+ fs.rmdirSync(dir);
15308
+ }
15307
15309
  }
15308
15310
  }
15309
15311
  continue;
@@ -15573,7 +15575,7 @@ async function try_load_svelte2tsx() {
15573
15575
  return await import('svelte2tsx');
15574
15576
  } catch (e) {
15575
15577
  throw new Error(
15576
- 'You need svelte2tsx and typescript if you want to generate type definitions. Install it through your package manager, or disable generation which is highly discouraged. See https://kit.svelte.dev/docs#packaging'
15578
+ 'You need svelte2tsx and typescript if you want to generate type definitions. Install it through your package manager, or disable generation which is highly discouraged. See https://kit.svelte.dev/docs/packaging'
15577
15579
  );
15578
15580
  }
15579
15581
  }
package/dist/cli.js CHANGED
@@ -466,7 +466,7 @@ const options = object(
466
466
  message += ', rather than the name of an adapter';
467
467
  }
468
468
 
469
- throw new Error(`${message}. See https://kit.svelte.dev/docs#adapters`);
469
+ throw new Error(`${message}. See https://kit.svelte.dev/docs/adapters`);
470
470
  }
471
471
 
472
472
  return input;
@@ -480,7 +480,7 @@ const options = object(
480
480
  if (input) {
481
481
  if (input.startsWith('/') || input.endsWith('/')) {
482
482
  throw new Error(
483
- "config.kit.appDir cannot start or end with '/'. See https://kit.svelte.dev/docs#configuration"
483
+ "config.kit.appDir cannot start or end with '/'. See https://kit.svelte.dev/docs/configuration"
484
484
  );
485
485
  }
486
486
  } else {
@@ -589,7 +589,7 @@ const options = object(
589
589
 
590
590
  if (input !== '' && (input.endsWith('/') || !input.startsWith('/'))) {
591
591
  throw new Error(
592
- `${keypath} option must be a root-relative path that starts but doesn't end with '/'. See https://kit.svelte.dev/docs#configuration-paths`
592
+ `${keypath} option must be a root-relative path that starts but doesn't end with '/'. See https://kit.svelte.dev/docs/configuration#paths`
593
593
  );
594
594
  }
595
595
 
@@ -601,13 +601,13 @@ const options = object(
601
601
  if (input) {
602
602
  if (!/^[a-z]+:\/\//.test(input)) {
603
603
  throw new Error(
604
- `${keypath} option must be an absolute path, if specified. See https://kit.svelte.dev/docs#configuration-paths`
604
+ `${keypath} option must be an absolute path, if specified. See https://kit.svelte.dev/docs/configuration#paths`
605
605
  );
606
606
  }
607
607
 
608
608
  if (input.endsWith('/')) {
609
609
  throw new Error(
610
- `${keypath} option must not end with '/'. See https://kit.svelte.dev/docs#configuration-paths`
610
+ `${keypath} option must not end with '/'. See https://kit.svelte.dev/docs/configuration#paths`
611
611
  );
612
612
  }
613
613
  }
@@ -619,7 +619,10 @@ const options = object(
619
619
  prerender: object({
620
620
  concurrency: number(1),
621
621
  crawl: boolean(true),
622
- createIndexFiles: boolean(true),
622
+ createIndexFiles: error(
623
+ (keypath) =>
624
+ `${keypath} has been removed — it is now controlled by the trailingSlash option. See https://kit.svelte.dev/docs/configuration#trailingslash`
625
+ ),
623
626
  enabled: boolean(true),
624
627
  entries: validate(['*'], (input, keypath) => {
625
628
  if (!Array.isArray(input) || !input.every((page) => typeof page === 'string')) {
@@ -675,13 +678,13 @@ const options = object(
675
678
 
676
679
  serviceWorker: object({
677
680
  register: boolean(true),
678
- files: fun((filename) => !/\.DS_STORE/.test(filename))
681
+ files: fun((filename) => !/\.DS_Store/.test(filename))
679
682
  }),
680
683
 
681
684
  // TODO remove this for 1.0
682
685
  ssr: error(
683
686
  (keypath) =>
684
- `${keypath} has been removed — use the handle hook instead: https://kit.svelte.dev/docs#hooks-handle'`
687
+ `${keypath} has been removed — use the handle hook instead: https://kit.svelte.dev/docs/hooks#handle'`
685
688
  ),
686
689
 
687
690
  // TODO remove this for 1.0
@@ -904,7 +907,7 @@ async function load_config({ cwd = process.cwd() } = {}) {
904
907
 
905
908
  if (!fs__default.existsSync(config_file)) {
906
909
  throw new Error(
907
- 'You need to create a svelte.config.js file. See https://kit.svelte.dev/docs#configuration'
910
+ 'You need to create a svelte.config.js file. See https://kit.svelte.dev/docs/configuration'
908
911
  );
909
912
  }
910
913
 
@@ -929,7 +932,7 @@ async function load_config({ cwd = process.cwd() } = {}) {
929
932
  function validate_config(config) {
930
933
  if (typeof config !== 'object') {
931
934
  throw new Error(
932
- 'svelte.config.js must have a configuration object as its default export. See https://kit.svelte.dev/docs#configuration'
935
+ 'svelte.config.js must have a configuration object as its default export. See https://kit.svelte.dev/docs/configuration'
933
936
  );
934
937
  }
935
938
 
@@ -995,7 +998,7 @@ async function launch(port, https) {
995
998
  exec(`${cmd} ${https ? 'https' : 'http'}://localhost:${port}`);
996
999
  }
997
1000
 
998
- const prog = sade('svelte-kit').version('1.0.0-next.262');
1001
+ const prog = sade('svelte-kit').version('1.0.0-next.266');
999
1002
 
1000
1003
  prog
1001
1004
  .command('dev')
@@ -1066,7 +1069,7 @@ prog
1066
1069
 
1067
1070
  // prettier-ignore
1068
1071
  console.log(
1069
- `See ${$.bold().cyan('https://kit.svelte.dev/docs#adapters')} to learn how to configure your app to run on the platform of your choosing`
1072
+ `See ${$.bold().cyan('https://kit.svelte.dev/docs/adapters')} to learn how to configure your app to run on the platform of your choosing`
1070
1073
  );
1071
1074
  } catch (error) {
1072
1075
  handle_error(error);
@@ -1153,7 +1156,7 @@ async function check_port(port) {
1153
1156
  function welcome({ port, host, https, open, loose, allow, cwd }) {
1154
1157
  if (open) launch(port, https);
1155
1158
 
1156
- console.log($.bold().cyan(`\n SvelteKit v${'1.0.0-next.262'}\n`));
1159
+ console.log($.bold().cyan(`\n SvelteKit v${'1.0.0-next.266'}\n`));
1157
1160
 
1158
1161
  const protocol = https ? 'https:' : 'http:';
1159
1162
  const exposed = typeof host !== 'undefined' && host !== 'localhost' && host !== '127.0.0.1';
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@sveltejs/kit",
3
- "version": "1.0.0-next.262",
3
+ "version": "1.0.0-next.266",
4
4
  "repository": {
5
5
  "type": "git",
6
6
  "url": "https://github.com/sveltejs/kit",
@@ -84,8 +84,9 @@
84
84
  "check-format": "prettier --check . --config ../../.prettierrc --ignore-path .gitignore",
85
85
  "test": "npm run test:unit && npm run test:packaging && npm run test:prerendering && npm run test:integration",
86
86
  "test:unit": "uvu src \"(spec\\.js|test[\\\\/]index\\.js)\" -i packaging",
87
- "test:prerendering": "pnpm test:prerendering:basics",
87
+ "test:prerendering": "pnpm test:prerendering:basics && pnpm test:prerendering:options",
88
88
  "test:prerendering:basics": "cd test/prerendering/basics && pnpm test",
89
+ "test:prerendering:options": "cd test/prerendering/options && pnpm test",
89
90
  "test:packaging": "uvu src/packaging \"(spec\\.js|test[\\\\/]index\\.js)\"",
90
91
  "test:integration": "pnpm test:integration:amp && pnpm test:integration:basics && pnpm test:integration:options && pnpm test:integration:options-2",
91
92
  "test:integration:amp": "cd test/apps/amp && pnpm test",
package/types/config.d.ts CHANGED
@@ -41,6 +41,7 @@ export interface Builder {
41
41
  mkdirp(dir: string): void;
42
42
 
43
43
  appDir: string;
44
+ trailingSlash: 'always' | 'never' | 'ignore';
44
45
 
45
46
  /**
46
47
  * Create entry points that map to individual functions
@@ -153,7 +154,6 @@ export interface Config {
153
154
  prerender?: {
154
155
  concurrency?: number;
155
156
  crawl?: boolean;
156
- createIndexFiles?: boolean;
157
157
  enabled?: boolean;
158
158
  entries?: string[];
159
159
  onError?: PrerenderOnErrorValue;
package/types/helper.d.ts CHANGED
@@ -4,7 +4,7 @@ export type JSONObject = { [key: string]: JSONValue };
4
4
  export type JSONValue = string | number | boolean | null | ToJSON | JSONValue[] | JSONObject;
5
5
 
6
6
  /** `string[]` is only for set-cookie, everything else must be type of `string` */
7
- export type ResponseHeaders = Record<string, string | string[]>;
7
+ export type ResponseHeaders = Record<string, string | number | string[]>;
8
8
 
9
9
  // <-- Utility Types -->
10
10
  type Only<T, U> = { [P in keyof T]: T[P] } & { [P in Exclude<keyof U, keyof T>]?: never };