@sveltejs/kit 3.0.0-next.11 → 3.0.0-next.12

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 (61) hide show
  1. package/package.json +1 -1
  2. package/src/cli.js +8 -8
  3. package/src/constants.js +1 -1
  4. package/src/core/config/options.js +43 -35
  5. package/src/core/env.js +25 -11
  6. package/src/core/sync/sync.js +11 -14
  7. package/src/core/sync/utils.js +21 -1
  8. package/src/core/sync/{write_non_ambient.js → write_app_types.js} +23 -21
  9. package/src/core/sync/write_client_manifest.js +4 -12
  10. package/src/core/sync/write_env.js +6 -4
  11. package/src/core/sync/write_server.js +10 -15
  12. package/src/core/sync/write_tsconfig/index.js +245 -0
  13. package/src/core/sync/write_tsconfig/utils.js +162 -0
  14. package/src/core/sync/write_types/index.js +80 -88
  15. package/src/exports/internal/server/index.js +3 -1
  16. package/src/exports/public.d.ts +28 -51
  17. package/src/exports/vite/dev/index.js +88 -76
  18. package/src/exports/vite/index.js +364 -144
  19. package/src/exports/vite/module_ids.js +3 -1
  20. package/src/exports/vite/utils.js +1 -10
  21. package/src/runner.js +13 -0
  22. package/src/runtime/app/forms.js +4 -0
  23. package/src/runtime/app/manifest/index.js +1 -0
  24. package/src/runtime/app/paths/client.js +30 -30
  25. package/src/runtime/app/paths/internal/client.js +26 -0
  26. package/src/runtime/app/paths/server.js +22 -9
  27. package/src/runtime/app/paths/types.d.ts +11 -19
  28. package/src/runtime/app/server/remote/command.js +12 -7
  29. package/src/runtime/app/server/remote/form.js +29 -26
  30. package/src/runtime/app/server/remote/prerender.js +9 -2
  31. package/src/runtime/app/server/remote/query.js +5 -4
  32. package/src/runtime/app/server/remote/shared.js +48 -30
  33. package/src/runtime/app/service-worker/index.js +24 -0
  34. package/src/runtime/app/state/index.js +1 -1
  35. package/src/runtime/client/client.js +46 -9
  36. package/src/runtime/client/remote-functions/form.svelte.js +43 -51
  37. package/src/runtime/client/remote-functions/query/index.js +2 -2
  38. package/src/runtime/client/remote-functions/query-batch.svelte.js +2 -3
  39. package/src/runtime/client/remote-functions/query-live/iterator.js +5 -2
  40. package/src/runtime/client/remote-functions/shared.svelte.js +4 -1
  41. package/src/runtime/client/state.svelte.js +54 -21
  42. package/src/runtime/form-utils.js +89 -54
  43. package/src/runtime/server/cookie.js +1 -1
  44. package/src/runtime/server/data/index.js +31 -28
  45. package/src/runtime/server/errors.js +1 -1
  46. package/src/runtime/server/page/actions.js +3 -3
  47. package/src/runtime/server/page/render.js +19 -28
  48. package/src/runtime/server/remote-functions.js +66 -35
  49. package/src/runtime/server/respond.js +56 -14
  50. package/src/runtime/server/utils.js +10 -0
  51. package/src/types/ambient-private.d.ts +8 -0
  52. package/src/types/ambient.d.ts +22 -27
  53. package/src/types/global-private.d.ts +12 -0
  54. package/src/types/internal.d.ts +13 -3
  55. package/src/utils/url.js +12 -0
  56. package/src/version.js +1 -1
  57. package/types/index.d.ts +80 -98
  58. package/types/index.d.ts.map +4 -1
  59. package/src/core/sync/write_ambient.js +0 -18
  60. package/src/core/sync/write_tsconfig.js +0 -258
  61. /package/src/core/sync/{write_tsconfig_test → write_tsconfig/test-app}/package.json +0 -0
@@ -1,3 +1,4 @@
1
+ /** @import { RouteId } from '$app/types' */
1
2
  /** @import { RemoteFunctionDataNode, ServerNodesResponse, ServerRedirectNode } from 'types' */
2
3
  /** @import { NavigationIntent } from './types.js' */
3
4
  /** @import { RenderNode } from '../types.js' */
@@ -21,7 +22,7 @@ import {
21
22
  scroll_state,
22
23
  load_css
23
24
  } from './utils.js';
24
- import { base } from '$app/paths/internal/client';
25
+ import { base, set_match_implementation } from '$app/paths/internal/client';
25
26
  import * as devalue from 'devalue';
26
27
  import {
27
28
  HISTORY_INDEX,
@@ -42,7 +43,7 @@ import {
42
43
  validate_load_response
43
44
  } from '../shared.js';
44
45
  import { get_message, get_status } from '../../utils/error.js';
45
- import { page, update, navigating, updated } from './state.svelte.js';
46
+ import { page, update, navigating, updated, notify_version } from './state.svelte.js';
46
47
  import { payload } from './payload.js';
47
48
  import { add_data_suffix, add_resolution_suffix } from '../pathname.js';
48
49
  import { noop_span } from '../telemetry/noop.js';
@@ -332,6 +333,23 @@ export const query_map = new Map();
332
333
  */
333
334
  export const live_query_map = new Map();
334
335
 
336
+ set_match_implementation(async (url) => {
337
+ if (typeof url === 'string') {
338
+ url = new URL(url, location.href);
339
+ }
340
+
341
+ const intent = await get_navigation_intent(url, false);
342
+
343
+ if (intent) {
344
+ return {
345
+ id: /** @type {RouteId} */ (intent.route.id),
346
+ params: intent.params
347
+ };
348
+ }
349
+
350
+ return null;
351
+ });
352
+
335
353
  /**
336
354
  * @param {import('./types.js').SvelteKitApp} _app
337
355
  * @param {HTMLElement} _target
@@ -1197,7 +1215,8 @@ async function load_route({ id, invalidating, url, params, route, preload }) {
1197
1215
  /** @type {import('types').ServerNodesResponse | import('types').ServerRedirectNode | null} */
1198
1216
  let server_data = null;
1199
1217
  const url_changed = current.url ? id !== get_page_key(current.url) : false;
1200
- const route_changed = current.route ? route.id !== current.route.id : false;
1218
+ // current.route is null after an error-page render, so a missing route counts as changed
1219
+ const route_changed = !current.route || route.id !== current.route.id;
1201
1220
  const search_params_changed = diff_search_params(current.url, url);
1202
1221
 
1203
1222
  let parent_invalid = false;
@@ -1986,14 +2005,14 @@ async function navigate({
1986
2005
  }
1987
2006
 
1988
2007
  // we reset scroll before dealing with focus, to avoid a flash of unscrolled content
1989
- /** @type {Element | null | ''} */
2008
+ /** @type {Element | null} */
1990
2009
  let deep_linked = null;
1991
2010
 
1992
2011
  if (autoscroll) {
1993
2012
  const scroll = popped ? popped.scroll : noscroll ? scroll_state() : null;
1994
2013
  if (scroll) {
1995
2014
  scrollTo(scroll.x, scroll.y);
1996
- } else if ((deep_linked = url.hash && document.getElementById(get_id(url)))) {
2015
+ } else if ((deep_linked = get_hash_element(url))) {
1997
2016
  // Here we use `scrollIntoView` on the element instead of `scrollTo`
1998
2017
  // because it natively supports the `scroll-margin` and `scroll-behavior`
1999
2018
  // CSS properties.
@@ -2744,13 +2763,19 @@ function _start_router() {
2744
2763
  history.scrollRestoration = 'auto';
2745
2764
  }
2746
2765
  });
2747
-
2748
2766
  addEventListener('visibilitychange', () => {
2749
2767
  if (document.visibilityState === 'hidden') {
2750
2768
  persist_state();
2769
+ } else {
2770
+ // the tab just became visible — a good time to check for a new deployment
2771
+ void updated.check();
2751
2772
  }
2752
2773
  });
2753
2774
 
2775
+ addEventListener('focus', () => {
2776
+ void updated.check();
2777
+ });
2778
+
2754
2779
  // @ts-expect-error this isn't supported everywhere yet
2755
2780
  if (!navigator.connection?.saveData) {
2756
2781
  setup_preload();
@@ -3177,6 +3202,9 @@ async function load_data(url, invalid) {
3177
3202
  const fetcher = DEV ? dev_fetch : window.fetch;
3178
3203
  const res = await fetcher(data_url.href, {});
3179
3204
 
3205
+ // detect new deployments from the response header
3206
+ notify_version(res.headers.get('x-sveltekit-version'));
3207
+
3180
3208
  if (!res.ok) {
3181
3209
  // error message is a JSON-stringified string which devalue can't handle at the top level
3182
3210
  // turn it into a HttpError to not call handleError on the client again (was already handled on the server)
@@ -3294,8 +3322,8 @@ function reset_focus(url, scroll = true) {
3294
3322
 
3295
3323
  // Mimic the browsers' behaviour and set the sequential focus navigation
3296
3324
  // starting point to the fragment identifier.
3297
- const id = get_id(url);
3298
- if (id && document.getElementById(id)) {
3325
+ const element = get_hash_element(url);
3326
+ if (element) {
3299
3327
  const { x, y } = scroll_state();
3300
3328
 
3301
3329
  // `element.focus()` doesn't work on Safari and Firefox Ubuntu so we need
@@ -3304,7 +3332,7 @@ function reset_focus(url, scroll = true) {
3304
3332
  const history_state = history.state;
3305
3333
 
3306
3334
  resetting_focus = true;
3307
- location.replace(new URL(`#${id}`, location.href));
3335
+ location.replace(new URL(`#${element.id}`, location.href));
3308
3336
 
3309
3337
  // Firefox has a bug that sets the history state to `null` so we need to
3310
3338
  // restore it after. See https://bugzilla.mozilla.org/show_bug.cgi?id=1199924
@@ -3456,6 +3484,15 @@ function get_id(url) {
3456
3484
  return decodeURIComponent(id);
3457
3485
  }
3458
3486
 
3487
+ /**
3488
+ * @param {URL} url
3489
+ * @returns {Element | null}
3490
+ */
3491
+ function get_hash_element(url) {
3492
+ const id = get_id(url);
3493
+ return id ? document.getElementById(id) : null;
3494
+ }
3495
+
3459
3496
  if (DEV) {
3460
3497
  // Nasty hack to silence harmless warnings the user can do nothing about
3461
3498
  const console_warn = console.warn;
@@ -25,7 +25,9 @@ import {
25
25
  serialize_binary_form,
26
26
  deep_get,
27
27
  DELETE_KEY,
28
- BINARY_FORM_CONTENT_TYPE
28
+ BINARY_FORM_CONTENT_TYPE,
29
+ parse_form_key,
30
+ coerce_form_value
29
31
  } from '../../form-utils.js';
30
32
 
31
33
  /**
@@ -123,8 +125,8 @@ export function form(id) {
123
125
  /** @type {InternalRemoteFormIssue[] | null} */
124
126
  let unread_issues = null;
125
127
 
126
- /** @type {string | null} */
127
- let previous_submitter_name = null;
128
+ /** @type {{ name: string; type: 'number' | 'boolean' | null; is_array: boolean } | null} */
129
+ let previous_submitter = null;
128
130
 
129
131
  /**
130
132
  * In dev, warn if there are validation issues going unread
@@ -160,8 +162,8 @@ export function form(id) {
160
162
  * @returns {Record<string, any>}
161
163
  */
162
164
  function convert(form_data) {
163
- const data = convert_formdata(form_data);
164
- if (key !== undefined && !form_data.has('id')) {
165
+ const data = convert_formdata(action_id_without_key, form_data);
166
+ if (key !== undefined && !('id' in data)) {
165
167
  data.id = key;
166
168
  }
167
169
  return data;
@@ -405,26 +407,30 @@ export function form(id) {
405
407
  const form_data = new FormData(form, event.submitter);
406
408
 
407
409
  if (
408
- previous_submitter_name !== null &&
409
- !Array.from(form_data.keys()).map(strip_prefix).includes(previous_submitter_name)
410
+ previous_submitter !== null &&
411
+ !Array.from(form_data.keys())
412
+ .map((k) => parse_form_key(action_id_without_key, k).name)
413
+ .includes(previous_submitter.name)
410
414
  ) {
411
- // Strip any `n:`/`b:` type prefix before clearing, otherwise
412
- // `set_nested_value` would coerce `undefined` to `NaN`/`false`
413
- // instead of clearing the previously-submitted value.
414
- set_nested_value(input, previous_submitter_name, undefined);
415
+ set_nested_value(input, previous_submitter, undefined);
415
416
  }
416
417
 
417
418
  if (event.submitter) {
418
419
  const name = event.submitter.getAttribute('name');
420
+
421
+ /** @type {null | ReturnType<typeof parse_form_key>} */
422
+ let submitter = null;
423
+
419
424
  const value = /** @type {any} */ (event.submitter).value;
420
425
 
421
426
  if (name !== null && value !== undefined) {
422
- set_nested_value(input, name, value);
427
+ submitter = parse_form_key(action_id_without_key, name);
428
+ set_nested_value(input, submitter, coerce_form_value(submitter.type, value));
423
429
  }
424
430
 
425
- previous_submitter_name = strip_prefix(name);
431
+ previous_submitter = submitter;
426
432
  } else {
427
- previous_submitter_name = null;
433
+ previous_submitter = null;
428
434
  }
429
435
 
430
436
  if (DEV) {
@@ -463,15 +469,14 @@ export function form(id) {
463
469
  // but that makes the types unnecessarily awkward
464
470
  const element = /** @type {HTMLInputElement} */ (e.target);
465
471
 
466
- let name = element.name;
472
+ const name = element.name;
467
473
  if (!name) return;
468
474
 
469
- const is_array = name.endsWith('[]');
470
- if (is_array) name = name.slice(0, -2);
475
+ const field = parse_form_key(action_id_without_key, name);
471
476
 
472
477
  const is_file = element.type === 'file';
473
478
 
474
- if (is_array) {
479
+ if (field.is_array) {
475
480
  let value;
476
481
 
477
482
  if (element.tagName === 'SELECT') {
@@ -481,7 +486,7 @@ export function form(id) {
481
486
  );
482
487
  } else {
483
488
  const elements = /** @type {HTMLInputElement[]} */ (
484
- Array.from(form.querySelectorAll(`[name="${name}[]"]`))
489
+ Array.from(form.querySelectorAll(`[name="${name}"]`))
485
490
  );
486
491
 
487
492
  if (DEV) {
@@ -502,7 +507,7 @@ export function form(id) {
502
507
  }
503
508
  }
504
509
 
505
- set_nested_value(input, name, value);
510
+ set_nested_value(input, field, value);
506
511
  } else if (is_file) {
507
512
  if (DEV && element.multiple) {
508
513
  throw new Error(
@@ -513,21 +518,19 @@ export function form(id) {
513
518
  const file = /** @type {HTMLInputElement & { files: FileList }} */ (element).files[0];
514
519
 
515
520
  if (file) {
516
- set_nested_value(input, name, file);
521
+ set_nested_value(input, field, file);
517
522
  } else {
518
- set_nested_value(input, name, DELETE_KEY);
523
+ set_nested_value(input, field, DELETE_KEY);
519
524
  }
520
525
  } else {
521
526
  set_nested_value(
522
527
  input,
523
- name,
528
+ field,
524
529
  element.type === 'checkbox' && !element.checked ? null : element.value
525
530
  );
526
531
  }
527
532
 
528
- name = strip_prefix(name);
529
-
530
- dirty[name] = true;
533
+ dirty[field.name] = true;
531
534
  };
532
535
 
533
536
  const handle_reset = async () => {
@@ -535,7 +538,7 @@ export function form(id) {
535
538
  // the inputs are actually updated (so that it can be cancelled)
536
539
  await tick();
537
540
 
538
- input = convert_formdata(new FormData(form));
541
+ input = convert_formdata(action_id_without_key, new FormData(form));
539
542
  raw_issues = [];
540
543
  touched = {};
541
544
  dirty = {};
@@ -545,15 +548,15 @@ export function form(id) {
545
548
 
546
549
  /** @param {Event} e */
547
550
  const handle_focusout = (e) => {
548
- let name = /** @type {HTMLInputElement} */ (e.target).name;
551
+ const name = /** @type {HTMLInputElement} */ (e.target).name;
549
552
  if (!name) return;
550
553
 
551
- name = strip_prefix(name).replace(/\[\]$/, '');
554
+ const field = parse_form_key(action_id_without_key, name);
552
555
 
553
- touched[name] = true;
556
+ touched[field.name] = true;
554
557
 
555
- if (Object.hasOwn(dirty, name)) {
556
- can_validate[name] = true;
558
+ if (Object.hasOwn(dirty, field.name)) {
559
+ can_validate[field.name] = true;
557
560
  }
558
561
  };
559
562
 
@@ -608,10 +611,10 @@ export function form(id) {
608
611
  },
609
612
  fields: {
610
613
  get: () =>
611
- create_field_proxy(
612
- {},
613
- () => input,
614
- (path, value) => {
614
+ create_field_proxy({
615
+ form_id: action_id_without_key,
616
+ get: () => input,
617
+ set: (path, value) => {
615
618
  if (path.length === 0) {
616
619
  input = value;
617
620
  } else if (value !== deep_get(input, path)) {
@@ -626,7 +629,7 @@ export function form(id) {
626
629
  }
627
630
  }
628
631
  },
629
- (path, all) => {
632
+ get_issues: (path, all) => {
630
633
  if (DEV && unread_issues !== null && path !== undefined) {
631
634
  unread_issues = unread_issues.filter((issue) => {
632
635
  return (
@@ -638,10 +641,9 @@ export function form(id) {
638
641
 
639
642
  return issues;
640
643
  },
641
- () => touched,
642
- () => dirty,
643
- []
644
- )
644
+ get_touched: () => touched,
645
+ get_dirty: () => dirty
646
+ })
645
647
  },
646
648
  result: {
647
649
  get: () => result
@@ -809,13 +811,3 @@ function validate_form_data(form_data, enctype) {
809
811
  }
810
812
  }
811
813
  }
812
-
813
- /**
814
- * Remove the `n:` or `b:` prefix from a field name
815
- * @template {string | null} T
816
- * @param {T} name
817
- * @returns {T}
818
- */
819
- function strip_prefix(name) {
820
- return /** @type {T} */ (name && name.replace(/^[nb]:/, ''));
821
- }
@@ -1,7 +1,7 @@
1
1
  /** @import { RemoteQueryFunction } from '@sveltejs/kit' */
2
2
  import { app_dir, base } from '$app/paths/internal/client';
3
3
  import { _goto, query_map } from '../../client.js';
4
- import { get_remote_request_headers, QUERY_FUNCTION_ID, remote_request } from '../shared.svelte.js';
4
+ import { QUERY_FUNCTION_ID, remote_request } from '../shared.svelte.js';
5
5
  import { DEV } from 'esm-env';
6
6
  import { QueryProxy } from './proxy.js';
7
7
 
@@ -26,7 +26,7 @@ export function query(id) {
26
26
  return new QueryProxy(id, arg, async (payload) => {
27
27
  const url = `${base}/${app_dir}/remote/${id}${payload ? `?payload=${payload}` : ''}`;
28
28
 
29
- const result = await remote_request(url, { headers: get_remote_request_headers() });
29
+ const result = await remote_request(url);
30
30
 
31
31
  if (result.redirect) {
32
32
  // Use internal version to allow redirects to external URLs
@@ -1,7 +1,7 @@
1
1
  /** @import { RemoteQueryFunction } from '@sveltejs/kit' */
2
2
  import { app_dir, base } from '$app/paths/internal/client';
3
3
  import { _goto } from '../client.js';
4
- import { get_remote_request_headers, QUERY_FUNCTION_ID, remote_request } from './shared.svelte.js';
4
+ import { QUERY_FUNCTION_ID, remote_request } from './shared.svelte.js';
5
5
  import { QueryProxy } from './query/proxy.js';
6
6
  import { HttpError } from '@sveltejs/kit/internal';
7
7
 
@@ -30,8 +30,7 @@ export function query_batch(id) {
30
30
  // but in different forks/async contexts and in the same macrotask?
31
31
  // If so this would potentially be buggy
32
32
  const headers = {
33
- 'Content-Type': 'application/json',
34
- ...get_remote_request_headers()
33
+ 'Content-Type': 'application/json'
35
34
  };
36
35
 
37
36
  // Wait for the next macrotask - don't use microtask as Svelte runtime uses these to collect changes and flush them,
@@ -1,6 +1,7 @@
1
1
  import { app_dir, base } from '$app/paths/internal/client';
2
2
  import { app } from '../../client.js';
3
- import { get_remote_request_headers, handle_side_channel_response } from '../shared.svelte.js';
3
+ import { notify_version } from '../../state.svelte.js';
4
+ import { handle_side_channel_response } from '../shared.svelte.js';
4
5
  import * as devalue from 'devalue';
5
6
  import { HttpError } from '@sveltejs/kit/internal';
6
7
  import { noop } from '../../../../utils/functions.js';
@@ -23,10 +24,12 @@ export async function* create_live_iterator(
23
24
  const url = `${base}/${app_dir}/remote/${id}${payload ? `?payload=${payload}` : ''}`;
24
25
 
25
26
  const response = await fetch(url, {
26
- headers: get_remote_request_headers(),
27
27
  signal: controller.signal
28
28
  });
29
29
 
30
+ // detect new deployments from the response header
31
+ notify_version(response.headers.get('x-sveltekit-version'));
32
+
30
33
  if (!response.ok) {
31
34
  const result = await response.json().catch(() => ({
32
35
  type: 'error',
@@ -6,7 +6,7 @@ import { app, _goto, live_query_map, query_map, query_responses } from '../clien
6
6
  import { HttpError, Redirect } from '@sveltejs/kit/internal';
7
7
  import { untrack } from 'svelte';
8
8
  import { create_remote_key, split_remote_key } from '../../shared.js';
9
- import { navigating, page } from '../state.svelte.js';
9
+ import { navigating, page, notify_version } from '../state.svelte.js';
10
10
 
11
11
  /** Indicates a query function, as opposed to a query instance */
12
12
  export const QUERY_FUNCTION_ID = Symbol('sveltekit.query_function_id');
@@ -113,6 +113,9 @@ export function get_remote_request_headers() {
113
113
  export async function remote_request(url, init) {
114
114
  const response = await fetch(url, init);
115
115
 
116
+ // detect new deployments from the response header
117
+ notify_version(response.headers.get('x-sveltekit-version'));
118
+
116
119
  if (!response.ok) {
117
120
  const result = await response.json().catch(() => ({
118
121
  type: 'error',
@@ -25,41 +25,74 @@ export const updated = new (class Updated {
25
25
  check = async () => false;
26
26
  })();
27
27
 
28
+ /**
29
+ * Internal: mark `updated.current` as `true` if the given version differs.
30
+ * Called from the server response header path. No-op unless version checks
31
+ * are enabled (assigned below). Not exported on the public `updated` object.
32
+ * @type {(new_version: string | null) => void}
33
+ */
34
+ export let notify_version = () => {};
35
+
28
36
  if (!DEV && BROWSER) {
29
37
  const interval = __SVELTEKIT_APP_VERSION_POLL_INTERVAL__;
30
38
 
31
- /** @type {number} */
39
+ /** @type {number | undefined} */
32
40
  let timeout;
33
41
 
42
+ /** @type {Promise<boolean> | undefined} */
43
+ let checking;
44
+
45
+ if (__SVELTEKIT_APP_VERSION_CHECKS_ENABLED__) {
46
+ /**
47
+ * Mark `updated.current` as `true` if the given version differs from the one
48
+ * the app was hydrated with. Called from the server response header path.
49
+ * Does NOT reset the poll timer — unlike `check()`, this is a passive observation
50
+ * from a single server instance's response, not an explicit version check. The
51
+ * poll timer continues on its original schedule as a backstop. This is important
52
+ * for platforms that implement skew protection, where `x-sveltekit-version`
53
+ * may be out of date — in this case we still need to poll for `version.json`.
54
+ * @param {string | null} new_version
55
+ */
56
+ notify_version = (new_version) => {
57
+ if (new_version && new_version !== version) {
58
+ updated.current = true;
59
+ }
60
+ };
61
+ }
62
+
34
63
  /** @type {() => Promise<boolean>} */
35
- async function check() {
64
+ function check() {
65
+ if (checking) return checking;
66
+
36
67
  window.clearTimeout(timeout);
37
68
 
38
- if (interval) timeout = window.setTimeout(check, interval);
69
+ return (checking = (async () => {
70
+ try {
71
+ const res = await fetch(`${assets}/${__SVELTEKIT_APP_VERSION_FILE__}`, {
72
+ headers: {
73
+ 'cache-control': 'no-cache'
74
+ }
75
+ });
39
76
 
40
- try {
41
- const res = await fetch(`${assets}/${__SVELTEKIT_APP_VERSION_FILE__}`, {
42
- headers: {
43
- 'cache-control': 'no-cache'
77
+ if (!res.ok) {
78
+ return false;
44
79
  }
45
- });
46
80
 
47
- if (!res.ok) {
48
- return false;
49
- }
81
+ const data = await res.json();
82
+ const new_update = data.version !== version;
50
83
 
51
- const data = await res.json();
52
- const new_update = data.version !== version;
84
+ if (new_update) {
85
+ updated.current = true;
86
+ }
53
87
 
54
- if (new_update) {
55
- updated.current = true;
56
- window.clearTimeout(timeout);
88
+ return new_update;
89
+ } catch {
90
+ return false;
91
+ } finally {
92
+ checking = undefined;
93
+ if (interval && !updated.current) timeout = window.setTimeout(check, interval);
57
94
  }
58
-
59
- return new_update;
60
- } catch {
61
- return false;
62
- }
95
+ })());
63
96
  }
64
97
 
65
98
  if (interval) timeout = window.setTimeout(check, interval);