@sveltejs/kit 1.0.0-next.28 → 1.0.0-next.282

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 (79) hide show
  1. package/README.md +12 -9
  2. package/assets/app/env.js +20 -0
  3. package/assets/app/navigation.js +79 -0
  4. package/assets/app/paths.js +1 -0
  5. package/assets/app/stores.js +97 -0
  6. package/assets/chunks/utils.js +13 -0
  7. package/assets/client/singletons.js +21 -0
  8. package/assets/client/start.js +1561 -0
  9. package/assets/components/error.svelte +18 -2
  10. package/assets/env.js +8 -0
  11. package/assets/paths.js +13 -0
  12. package/assets/server/index.js +2759 -0
  13. package/dist/chunks/amp_hook.js +56 -0
  14. package/dist/chunks/build.js +658 -0
  15. package/dist/chunks/cert.js +28154 -0
  16. package/dist/chunks/index.js +473 -0
  17. package/dist/chunks/index2.js +836 -0
  18. package/dist/chunks/index3.js +643 -0
  19. package/dist/chunks/index4.js +120 -0
  20. package/dist/chunks/index5.js +881 -0
  21. package/dist/chunks/index6.js +170 -0
  22. package/dist/chunks/index7.js +15584 -0
  23. package/dist/chunks/index8.js +4207 -0
  24. package/dist/chunks/misc.js +3 -0
  25. package/dist/chunks/multipart-parser.js +449 -0
  26. package/dist/cli.js +1132 -86
  27. package/dist/hooks.js +28 -0
  28. package/dist/install-fetch.js +6518 -0
  29. package/dist/node.js +95 -0
  30. package/package.json +97 -54
  31. package/svelte-kit.js +2 -0
  32. package/types/ambient.d.ts +208 -0
  33. package/types/index.d.ts +391 -0
  34. package/types/internal.d.ts +372 -0
  35. package/CHANGELOG.md +0 -326
  36. package/assets/runtime/app/navigation.js +0 -23
  37. package/assets/runtime/app/navigation.js.map +0 -1
  38. package/assets/runtime/app/paths.js +0 -2
  39. package/assets/runtime/app/paths.js.map +0 -1
  40. package/assets/runtime/app/stores.js +0 -78
  41. package/assets/runtime/app/stores.js.map +0 -1
  42. package/assets/runtime/internal/singletons.js +0 -15
  43. package/assets/runtime/internal/singletons.js.map +0 -1
  44. package/assets/runtime/internal/start.js +0 -591
  45. package/assets/runtime/internal/start.js.map +0 -1
  46. package/assets/runtime/utils-85ebcc60.js +0 -18
  47. package/assets/runtime/utils-85ebcc60.js.map +0 -1
  48. package/dist/api.js +0 -44
  49. package/dist/api.js.map +0 -1
  50. package/dist/build.js +0 -246
  51. package/dist/build.js.map +0 -1
  52. package/dist/cli.js.map +0 -1
  53. package/dist/colors.js +0 -37
  54. package/dist/colors.js.map +0 -1
  55. package/dist/create_app.js +0 -580
  56. package/dist/create_app.js.map +0 -1
  57. package/dist/index.js +0 -368
  58. package/dist/index.js.map +0 -1
  59. package/dist/index2.js +0 -12035
  60. package/dist/index2.js.map +0 -1
  61. package/dist/index3.js +0 -549
  62. package/dist/index3.js.map +0 -1
  63. package/dist/index4.js +0 -74
  64. package/dist/index4.js.map +0 -1
  65. package/dist/index5.js +0 -464
  66. package/dist/index5.js.map +0 -1
  67. package/dist/index6.js +0 -735
  68. package/dist/index6.js.map +0 -1
  69. package/dist/logging.js +0 -43
  70. package/dist/logging.js.map +0 -1
  71. package/dist/package.js +0 -432
  72. package/dist/package.js.map +0 -1
  73. package/dist/renderer.js +0 -2425
  74. package/dist/renderer.js.map +0 -1
  75. package/dist/standard.js +0 -101
  76. package/dist/standard.js.map +0 -1
  77. package/dist/utils.js +0 -58
  78. package/dist/utils.js.map +0 -1
  79. package/svelte-kit +0 -3
@@ -0,0 +1,1561 @@
1
+ import Root from '__GENERATED__/root.svelte';
2
+ import { fallback, routes } from '__GENERATED__/manifest.js';
3
+ import { onMount, tick } from 'svelte';
4
+ import { g as get_base_uri } from '../chunks/utils.js';
5
+ import { writable } from 'svelte/store';
6
+ import { base, set_paths } from '../paths.js';
7
+ import { init } from './singletons.js';
8
+
9
+ /**
10
+ * @param {string} path
11
+ * @param {'always' | 'never' | 'ignore'} trailing_slash
12
+ */
13
+ function normalize_path(path, trailing_slash) {
14
+ if (path === '/' || trailing_slash === 'ignore') return path;
15
+
16
+ if (trailing_slash === 'never') {
17
+ return path.endsWith('/') ? path.slice(0, -1) : path;
18
+ } else if (trailing_slash === 'always' && /\/[^./]+$/.test(path)) {
19
+ return path + '/';
20
+ }
21
+
22
+ return path;
23
+ }
24
+
25
+ // We track the scroll position associated with each history entry in sessionStorage,
26
+ // rather than on history.state itself, because when navigation is driven by
27
+ // popstate it's too late to update the scroll position associated with the
28
+ // state we're navigating from
29
+ const SCROLL_KEY = 'sveltekit:scroll';
30
+
31
+ /** @typedef {{ x: number, y: number }} ScrollPosition */
32
+ /** @type {Record<number, ScrollPosition>} */
33
+ let scroll_positions = {};
34
+ try {
35
+ scroll_positions = JSON.parse(sessionStorage[SCROLL_KEY]);
36
+ } catch {
37
+ // do nothing
38
+ }
39
+
40
+ /** @param {number} index */
41
+ function update_scroll_positions(index) {
42
+ scroll_positions[index] = scroll_state();
43
+ }
44
+
45
+ function scroll_state() {
46
+ return {
47
+ x: pageXOffset,
48
+ y: pageYOffset
49
+ };
50
+ }
51
+
52
+ /**
53
+ * @param {Event} event
54
+ * @returns {HTMLAnchorElement | SVGAElement | undefined}
55
+ */
56
+ function find_anchor(event) {
57
+ const node = event
58
+ .composedPath()
59
+ .find((e) => e instanceof Node && e.nodeName.toUpperCase() === 'A'); // SVG <a> elements have a lowercase name
60
+ return /** @type {HTMLAnchorElement | SVGAElement | undefined} */ (node);
61
+ }
62
+
63
+ /**
64
+ * @param {HTMLAnchorElement | SVGAElement} node
65
+ * @returns {URL}
66
+ */
67
+ function get_href(node) {
68
+ return node instanceof SVGAElement
69
+ ? new URL(node.href.baseVal, document.baseURI)
70
+ : new URL(node.href);
71
+ }
72
+
73
+ class Router {
74
+ /**
75
+ * @param {{
76
+ * base: string;
77
+ * routes: import('types').CSRRoute[];
78
+ * trailing_slash: import('types').TrailingSlash;
79
+ * renderer: import('./renderer').Renderer
80
+ * }} opts
81
+ */
82
+ constructor({ base, routes, trailing_slash, renderer }) {
83
+ this.base = base;
84
+ this.routes = routes;
85
+ this.trailing_slash = trailing_slash;
86
+ /** Keeps tracks of multiple navigations caused by redirects during rendering */
87
+ this.navigating = 0;
88
+
89
+ /** @type {import('./renderer').Renderer} */
90
+ this.renderer = renderer;
91
+ renderer.router = this;
92
+
93
+ this.enabled = true;
94
+ this.initialized = false;
95
+
96
+ // make it possible to reset focus
97
+ document.body.setAttribute('tabindex', '-1');
98
+
99
+ // keeping track of the history index in order to prevent popstate navigation events if needed
100
+ this.current_history_index = history.state?.['sveltekit:index'] ?? 0;
101
+
102
+ if (this.current_history_index === 0) {
103
+ // create initial history entry, so we can return here
104
+ history.replaceState({ ...history.state, 'sveltekit:index': 0 }, '', location.href);
105
+ }
106
+
107
+ // if we reload the page, or Cmd-Shift-T back to it,
108
+ // recover scroll position
109
+ const scroll = scroll_positions[this.current_history_index];
110
+ if (scroll) scrollTo(scroll.x, scroll.y);
111
+
112
+ this.hash_navigating = false;
113
+
114
+ this.callbacks = {
115
+ /** @type {Array<({ from, to, cancel }: { from: URL, to: URL | null, cancel: () => void }) => void>} */
116
+ before_navigate: [],
117
+
118
+ /** @type {Array<({ from, to }: { from: URL | null, to: URL }) => void>} */
119
+ after_navigate: []
120
+ };
121
+ }
122
+
123
+ init_listeners() {
124
+ history.scrollRestoration = 'manual';
125
+
126
+ // Adopted from Nuxt.js
127
+ // Reset scrollRestoration to auto when leaving page, allowing page reload
128
+ // and back-navigation from other pages to use the browser to restore the
129
+ // scrolling position.
130
+ addEventListener('beforeunload', (e) => {
131
+ let should_block = false;
132
+
133
+ const intent = {
134
+ from: this.renderer.current.url,
135
+ to: null,
136
+ cancel: () => (should_block = true)
137
+ };
138
+
139
+ this.callbacks.before_navigate.forEach((fn) => fn(intent));
140
+
141
+ if (should_block) {
142
+ e.preventDefault();
143
+ e.returnValue = '';
144
+ } else {
145
+ history.scrollRestoration = 'auto';
146
+ }
147
+ });
148
+
149
+ addEventListener('visibilitychange', () => {
150
+ if (document.visibilityState === 'hidden') {
151
+ update_scroll_positions(this.current_history_index);
152
+
153
+ try {
154
+ sessionStorage[SCROLL_KEY] = JSON.stringify(scroll_positions);
155
+ } catch {
156
+ // do nothing
157
+ }
158
+ }
159
+ });
160
+
161
+ /** @param {Event} event */
162
+ const trigger_prefetch = (event) => {
163
+ const a = find_anchor(event);
164
+ if (a && a.href && a.hasAttribute('sveltekit:prefetch')) {
165
+ this.prefetch(get_href(a));
166
+ }
167
+ };
168
+
169
+ /** @type {NodeJS.Timeout} */
170
+ let mousemove_timeout;
171
+
172
+ /** @param {MouseEvent|TouchEvent} event */
173
+ const handle_mousemove = (event) => {
174
+ clearTimeout(mousemove_timeout);
175
+ mousemove_timeout = setTimeout(() => {
176
+ // event.composedPath(), which is used in find_anchor, will be empty if the event is read in a timeout
177
+ // add a layer of indirection to address that
178
+ event.target?.dispatchEvent(
179
+ new CustomEvent('sveltekit:trigger_prefetch', { bubbles: true })
180
+ );
181
+ }, 20);
182
+ };
183
+
184
+ addEventListener('touchstart', trigger_prefetch);
185
+ addEventListener('mousemove', handle_mousemove);
186
+ addEventListener('sveltekit:trigger_prefetch', trigger_prefetch);
187
+
188
+ /** @param {MouseEvent} event */
189
+ addEventListener('click', (event) => {
190
+ if (!this.enabled) return;
191
+
192
+ // Adapted from https://github.com/visionmedia/page.js
193
+ // MIT license https://github.com/visionmedia/page.js#license
194
+ if (event.button || event.which !== 1) return;
195
+ if (event.metaKey || event.ctrlKey || event.shiftKey || event.altKey) return;
196
+ if (event.defaultPrevented) return;
197
+
198
+ const a = find_anchor(event);
199
+ if (!a) return;
200
+
201
+ if (!a.href) return;
202
+
203
+ const url = get_href(a);
204
+ const url_string = url.toString();
205
+ if (url_string === location.href) {
206
+ if (!location.hash) event.preventDefault();
207
+ return;
208
+ }
209
+
210
+ // Ignore if tag has
211
+ // 1. 'download' attribute
212
+ // 2. 'rel' attribute includes external
213
+ const rel = (a.getAttribute('rel') || '').split(/\s+/);
214
+
215
+ if (a.hasAttribute('download') || (rel && rel.includes('external'))) {
216
+ return;
217
+ }
218
+
219
+ // Ignore if <a> has a target
220
+ if (a instanceof SVGAElement ? a.target.baseVal : a.target) return;
221
+
222
+ // Check if new url only differs by hash and use the browser default behavior in that case
223
+ // This will ensure the `hashchange` event is fired
224
+ // Removing the hash does a full page navigation in the browser, so make sure a hash is present
225
+ const [base, hash] = url.href.split('#');
226
+ if (hash !== undefined && base === location.href.split('#')[0]) {
227
+ // set this flag to distinguish between navigations triggered by
228
+ // clicking a hash link and those triggered by popstate
229
+ this.hash_navigating = true;
230
+
231
+ update_scroll_positions(this.current_history_index);
232
+ this.renderer.update_page_store(new URL(url.href));
233
+
234
+ return;
235
+ }
236
+
237
+ this._navigate({
238
+ url,
239
+ scroll: a.hasAttribute('sveltekit:noscroll') ? scroll_state() : null,
240
+ keepfocus: false,
241
+ chain: [],
242
+ details: {
243
+ state: {},
244
+ replaceState: false
245
+ },
246
+ accepted: () => event.preventDefault(),
247
+ blocked: () => event.preventDefault()
248
+ });
249
+ });
250
+
251
+ addEventListener('popstate', (event) => {
252
+ if (event.state && this.enabled) {
253
+ // if a popstate-driven navigation is cancelled, we need to counteract it
254
+ // with history.go, which means we end up back here, hence this check
255
+ if (event.state['sveltekit:index'] === this.current_history_index) return;
256
+
257
+ this._navigate({
258
+ url: new URL(location.href),
259
+ scroll: scroll_positions[event.state['sveltekit:index']],
260
+ keepfocus: false,
261
+ chain: [],
262
+ details: null,
263
+ accepted: () => {
264
+ this.current_history_index = event.state['sveltekit:index'];
265
+ },
266
+ blocked: () => {
267
+ const delta = this.current_history_index - event.state['sveltekit:index'];
268
+ history.go(delta);
269
+ }
270
+ });
271
+ }
272
+ });
273
+
274
+ addEventListener('hashchange', () => {
275
+ // if the hashchange happened as a result of clicking on a link,
276
+ // we need to update history, otherwise we have to leave it alone
277
+ if (this.hash_navigating) {
278
+ this.hash_navigating = false;
279
+ history.replaceState(
280
+ { ...history.state, 'sveltekit:index': ++this.current_history_index },
281
+ '',
282
+ location.href
283
+ );
284
+ }
285
+ });
286
+
287
+ this.initialized = true;
288
+ }
289
+
290
+ /**
291
+ * Returns true if `url` has the same origin and basepath as the app
292
+ * @param {URL} url
293
+ */
294
+ owns(url) {
295
+ return url.origin === location.origin && url.pathname.startsWith(this.base);
296
+ }
297
+
298
+ /**
299
+ * @param {URL} url
300
+ * @returns {import('./types').NavigationInfo | undefined}
301
+ */
302
+ parse(url) {
303
+ if (this.owns(url)) {
304
+ const path = decodeURI(url.pathname.slice(this.base.length) || '/');
305
+
306
+ return {
307
+ id: url.pathname + url.search,
308
+ routes: this.routes.filter(([pattern]) => pattern.test(path)),
309
+ url,
310
+ path,
311
+ initial: !this.initialized
312
+ };
313
+ }
314
+ }
315
+
316
+ /**
317
+ * @typedef {Parameters<typeof import('$app/navigation').goto>} GotoParams
318
+ *
319
+ * @param {GotoParams[0]} href
320
+ * @param {GotoParams[1]} opts
321
+ * @param {string[]} chain
322
+ */
323
+ async goto(
324
+ href,
325
+ { noscroll = false, replaceState = false, keepfocus = false, state = {} } = {},
326
+ chain
327
+ ) {
328
+ const url = new URL(href, get_base_uri(document));
329
+
330
+ if (this.enabled) {
331
+ return this._navigate({
332
+ url,
333
+ scroll: noscroll ? scroll_state() : null,
334
+ keepfocus,
335
+ chain,
336
+ details: {
337
+ state,
338
+ replaceState
339
+ },
340
+ accepted: () => {},
341
+ blocked: () => {}
342
+ });
343
+ }
344
+
345
+ location.href = url.href;
346
+ return new Promise(() => {
347
+ /* never resolves */
348
+ });
349
+ }
350
+
351
+ enable() {
352
+ this.enabled = true;
353
+ }
354
+
355
+ disable() {
356
+ this.enabled = false;
357
+ }
358
+
359
+ /**
360
+ * @param {URL} url
361
+ * @returns {Promise<import('./types').NavigationResult | undefined>}
362
+ */
363
+ async prefetch(url) {
364
+ const info = this.parse(url);
365
+
366
+ if (!info) {
367
+ throw new Error('Attempted to prefetch a URL that does not belong to this app');
368
+ }
369
+
370
+ return this.renderer.load(info);
371
+ }
372
+
373
+ /** @param {({ from, to }: { from: URL | null, to: URL }) => void} fn */
374
+ after_navigate(fn) {
375
+ onMount(() => {
376
+ this.callbacks.after_navigate.push(fn);
377
+
378
+ return () => {
379
+ const i = this.callbacks.after_navigate.indexOf(fn);
380
+ this.callbacks.after_navigate.splice(i, 1);
381
+ };
382
+ });
383
+ }
384
+
385
+ /**
386
+ * @param {({ from, to, cancel }: { from: URL, to: URL | null, cancel: () => void }) => void} fn
387
+ */
388
+ before_navigate(fn) {
389
+ onMount(() => {
390
+ this.callbacks.before_navigate.push(fn);
391
+
392
+ return () => {
393
+ const i = this.callbacks.before_navigate.indexOf(fn);
394
+ this.callbacks.before_navigate.splice(i, 1);
395
+ };
396
+ });
397
+ }
398
+
399
+ /**
400
+ * @param {{
401
+ * url: URL;
402
+ * scroll: { x: number, y: number } | null;
403
+ * keepfocus: boolean;
404
+ * chain: string[];
405
+ * details: {
406
+ * replaceState: boolean;
407
+ * state: any;
408
+ * } | null;
409
+ * accepted: () => void;
410
+ * blocked: () => void;
411
+ * }} opts
412
+ */
413
+ async _navigate({ url, scroll, keepfocus, chain, details, accepted, blocked }) {
414
+ const from = this.renderer.current.url;
415
+ let should_block = false;
416
+
417
+ const intent = {
418
+ from,
419
+ to: url,
420
+ cancel: () => (should_block = true)
421
+ };
422
+
423
+ this.callbacks.before_navigate.forEach((fn) => fn(intent));
424
+
425
+ if (should_block) {
426
+ blocked();
427
+ return;
428
+ }
429
+
430
+ const info = this.parse(url);
431
+ if (!info) {
432
+ location.href = url.href;
433
+ return new Promise(() => {
434
+ // never resolves
435
+ });
436
+ }
437
+
438
+ update_scroll_positions(this.current_history_index);
439
+
440
+ accepted();
441
+
442
+ if (!this.navigating) {
443
+ dispatchEvent(new CustomEvent('sveltekit:navigation-start'));
444
+ }
445
+ this.navigating++;
446
+
447
+ const pathname = normalize_path(url.pathname, this.trailing_slash);
448
+
449
+ info.url = new URL(url.origin + pathname + url.search + url.hash);
450
+
451
+ if (details) {
452
+ const change = details.replaceState ? 0 : 1;
453
+ details.state['sveltekit:index'] = this.current_history_index += change;
454
+ history[details.replaceState ? 'replaceState' : 'pushState'](details.state, '', info.url);
455
+ }
456
+
457
+ await this.renderer.handle_navigation(info, chain, false, {
458
+ scroll,
459
+ keepfocus
460
+ });
461
+
462
+ this.navigating--;
463
+ if (!this.navigating) {
464
+ dispatchEvent(new CustomEvent('sveltekit:navigation-end'));
465
+
466
+ const navigation = { from, to: url };
467
+ this.callbacks.after_navigate.forEach((fn) => fn(navigation));
468
+ }
469
+ }
470
+ }
471
+
472
+ /**
473
+ * @param {unknown} err
474
+ * @return {Error}
475
+ */
476
+ function coalesce_to_error(err) {
477
+ return err instanceof Error ||
478
+ (err && /** @type {any} */ (err).name && /** @type {any} */ (err).message)
479
+ ? /** @type {Error} */ (err)
480
+ : new Error(JSON.stringify(err));
481
+ }
482
+
483
+ /**
484
+ * Hash using djb2
485
+ * @param {import('types').StrictBody} value
486
+ */
487
+ function hash(value) {
488
+ let hash = 5381;
489
+ let i = value.length;
490
+
491
+ if (typeof value === 'string') {
492
+ while (i) hash = (hash * 33) ^ value.charCodeAt(--i);
493
+ } else {
494
+ while (i) hash = (hash * 33) ^ value[--i];
495
+ }
496
+
497
+ return (hash >>> 0).toString(36);
498
+ }
499
+
500
+ /**
501
+ * @param {import('types').LoadOutput} loaded
502
+ * @returns {import('types').NormalizedLoadOutput}
503
+ */
504
+ function normalize(loaded) {
505
+ const has_error_status =
506
+ loaded.status && loaded.status >= 400 && loaded.status <= 599 && !loaded.redirect;
507
+ if (loaded.error || has_error_status) {
508
+ const status = loaded.status;
509
+
510
+ if (!loaded.error && has_error_status) {
511
+ return {
512
+ status: status || 500,
513
+ error: new Error()
514
+ };
515
+ }
516
+
517
+ const error = typeof loaded.error === 'string' ? new Error(loaded.error) : loaded.error;
518
+
519
+ if (!(error instanceof Error)) {
520
+ return {
521
+ status: 500,
522
+ error: new Error(
523
+ `"error" property returned from load() must be a string or instance of Error, received type "${typeof error}"`
524
+ )
525
+ };
526
+ }
527
+
528
+ if (!status || status < 400 || status > 599) {
529
+ console.warn('"error" returned from load() without a valid status code — defaulting to 500');
530
+ return { status: 500, error };
531
+ }
532
+
533
+ return { status, error };
534
+ }
535
+
536
+ if (loaded.redirect) {
537
+ if (!loaded.status || Math.floor(loaded.status / 100) !== 3) {
538
+ return {
539
+ status: 500,
540
+ error: new Error(
541
+ '"redirect" property returned from load() must be accompanied by a 3xx status code'
542
+ )
543
+ };
544
+ }
545
+
546
+ if (typeof loaded.redirect !== 'string') {
547
+ return {
548
+ status: 500,
549
+ error: new Error('"redirect" property returned from load() must be a string')
550
+ };
551
+ }
552
+ }
553
+
554
+ // TODO remove before 1.0
555
+ if (/** @type {any} */ (loaded).context) {
556
+ throw new Error(
557
+ 'You are returning "context" from a load function. ' +
558
+ '"context" was renamed to "stuff", please adjust your code accordingly.'
559
+ );
560
+ }
561
+
562
+ return /** @type {import('types').NormalizedLoadOutput} */ (loaded);
563
+ }
564
+
565
+ /**
566
+ * @typedef {import('types').CSRComponent} CSRComponent
567
+ * @typedef {{ from: URL; to: URL }} Navigating
568
+ */
569
+
570
+ /** @param {any} value */
571
+ function notifiable_store(value) {
572
+ const store = writable(value);
573
+ let ready = true;
574
+
575
+ function notify() {
576
+ ready = true;
577
+ store.update((val) => val);
578
+ }
579
+
580
+ /** @param {any} new_value */
581
+ function set(new_value) {
582
+ ready = false;
583
+ store.set(new_value);
584
+ }
585
+
586
+ /** @param {(value: any) => void} run */
587
+ function subscribe(run) {
588
+ /** @type {any} */
589
+ let old_value;
590
+ return store.subscribe((new_value) => {
591
+ if (old_value === undefined || (ready && new_value !== old_value)) {
592
+ run((old_value = new_value));
593
+ }
594
+ });
595
+ }
596
+
597
+ return { notify, set, subscribe };
598
+ }
599
+
600
+ function create_updated_store() {
601
+ const { set, subscribe } = writable(false);
602
+
603
+ const interval = +(
604
+ /** @type {string} */ (import.meta.env.VITE_SVELTEKIT_APP_VERSION_POLL_INTERVAL)
605
+ );
606
+ const initial = import.meta.env.VITE_SVELTEKIT_APP_VERSION;
607
+
608
+ /** @type {NodeJS.Timeout} */
609
+ let timeout;
610
+
611
+ async function check() {
612
+ if (import.meta.env.DEV || import.meta.env.SSR) return false;
613
+
614
+ clearTimeout(timeout);
615
+
616
+ if (interval) timeout = setTimeout(check, interval);
617
+
618
+ const file = import.meta.env.VITE_SVELTEKIT_APP_VERSION_FILE;
619
+
620
+ const res = await fetch(`${base}/${file}`, {
621
+ headers: {
622
+ pragma: 'no-cache',
623
+ 'cache-control': 'no-cache'
624
+ }
625
+ });
626
+
627
+ if (res.ok) {
628
+ const { version } = await res.json();
629
+ const updated = version !== initial;
630
+
631
+ if (updated) {
632
+ set(true);
633
+ clearTimeout(timeout);
634
+ }
635
+
636
+ return updated;
637
+ } else {
638
+ throw new Error(`Version check failed: ${res.status}`);
639
+ }
640
+ }
641
+
642
+ if (interval) timeout = setTimeout(check, interval);
643
+
644
+ return {
645
+ subscribe,
646
+ check
647
+ };
648
+ }
649
+
650
+ /**
651
+ * @param {RequestInfo} resource
652
+ * @param {RequestInit} [opts]
653
+ */
654
+ function initial_fetch(resource, opts) {
655
+ const url = typeof resource === 'string' ? resource : resource.url;
656
+
657
+ let selector = `script[data-type="svelte-data"][data-url=${JSON.stringify(url)}]`;
658
+
659
+ if (opts && typeof opts.body === 'string') {
660
+ selector += `[data-body="${hash(opts.body)}"]`;
661
+ }
662
+
663
+ const script = document.querySelector(selector);
664
+ if (script && script.textContent) {
665
+ const { body, ...init } = JSON.parse(script.textContent);
666
+ return Promise.resolve(new Response(body, init));
667
+ }
668
+
669
+ return fetch(resource, opts);
670
+ }
671
+
672
+ class Renderer {
673
+ /**
674
+ * @param {{
675
+ * Root: CSRComponent;
676
+ * fallback: [CSRComponent, CSRComponent];
677
+ * target: Node;
678
+ * session: any;
679
+ * }} opts
680
+ */
681
+ constructor({ Root, fallback, target, session }) {
682
+ this.Root = Root;
683
+ this.fallback = fallback;
684
+
685
+ /** @type {import('./router').Router | undefined} */
686
+ this.router;
687
+
688
+ this.target = target;
689
+
690
+ this.started = false;
691
+
692
+ this.session_id = 1;
693
+ this.invalid = new Set();
694
+ this.invalidating = null;
695
+ this.autoscroll = true;
696
+ this.updating = false;
697
+
698
+ /** @type {import('./types').NavigationState} */
699
+ this.current = {
700
+ // @ts-ignore - we need the initial value to be null
701
+ url: null,
702
+ session_id: 0,
703
+ branch: []
704
+ };
705
+
706
+ /** @type {Map<string, import('./types').NavigationResult>} */
707
+ this.cache = new Map();
708
+
709
+ /** @type {{id: string | null, promise: Promise<import('./types').NavigationResult | undefined> | null}} */
710
+ this.loading = {
711
+ id: null,
712
+ promise: null
713
+ };
714
+
715
+ this.stores = {
716
+ url: notifiable_store({}),
717
+ page: notifiable_store({}),
718
+ navigating: writable(/** @type {Navigating | null} */ (null)),
719
+ session: writable(session),
720
+ updated: create_updated_store()
721
+ };
722
+
723
+ this.$session = null;
724
+
725
+ this.root = null;
726
+
727
+ let ready = false;
728
+ this.stores.session.subscribe(async (value) => {
729
+ this.$session = value;
730
+
731
+ if (!ready || !this.router) return;
732
+ this.session_id += 1;
733
+
734
+ const info = this.router.parse(new URL(location.href));
735
+ if (info) this.update(info, [], true);
736
+ });
737
+ ready = true;
738
+ }
739
+
740
+ disable_scroll_handling() {
741
+ if (import.meta.env.DEV && this.started && !this.updating) {
742
+ throw new Error('Can only disable scroll handling during navigation');
743
+ }
744
+
745
+ if (this.updating || !this.started) {
746
+ this.autoscroll = false;
747
+ }
748
+ }
749
+
750
+ /**
751
+ * @param {{
752
+ * status: number;
753
+ * error: Error;
754
+ * nodes: Array<Promise<CSRComponent>>;
755
+ * params: Record<string, string>;
756
+ * }} selected
757
+ */
758
+ async start({ status, error, nodes, params }) {
759
+ const url = new URL(location.href);
760
+
761
+ /** @type {Array<import('./types').BranchNode | undefined>} */
762
+ const branch = [];
763
+
764
+ /** @type {Record<string, any>} */
765
+ let stuff = {};
766
+
767
+ /** @type {import('./types').NavigationResult | undefined} */
768
+ let result;
769
+
770
+ let error_args;
771
+
772
+ try {
773
+ for (let i = 0; i < nodes.length; i += 1) {
774
+ const is_leaf = i === nodes.length - 1;
775
+
776
+ let props;
777
+
778
+ if (is_leaf) {
779
+ const serialized = document.querySelector('[data-type="svelte-props"]');
780
+ if (serialized) {
781
+ props = JSON.parse(/** @type {string} */ (serialized.textContent));
782
+ }
783
+ }
784
+
785
+ const node = await this._load_node({
786
+ module: await nodes[i],
787
+ url,
788
+ params,
789
+ stuff,
790
+ status: is_leaf ? status : undefined,
791
+ error: is_leaf ? error : undefined,
792
+ props
793
+ });
794
+
795
+ if (props) {
796
+ node.uses.dependencies.add(url.href);
797
+ node.uses.url = true;
798
+ }
799
+
800
+ branch.push(node);
801
+
802
+ if (node && node.loaded) {
803
+ if (node.loaded.error) {
804
+ if (error) throw node.loaded.error;
805
+ error_args = {
806
+ status: node.loaded.status,
807
+ error: node.loaded.error,
808
+ url
809
+ };
810
+ } else if (node.loaded.stuff) {
811
+ stuff = {
812
+ ...stuff,
813
+ ...node.loaded.stuff
814
+ };
815
+ }
816
+ }
817
+ }
818
+
819
+ result = error_args
820
+ ? await this._load_error(error_args)
821
+ : await this._get_navigation_result_from_branch({
822
+ url,
823
+ params,
824
+ stuff,
825
+ branch,
826
+ status,
827
+ error
828
+ });
829
+ } catch (e) {
830
+ if (error) throw e;
831
+
832
+ result = await this._load_error({
833
+ status: 500,
834
+ error: coalesce_to_error(e),
835
+ url
836
+ });
837
+ }
838
+
839
+ if (result.redirect) {
840
+ // this is a real edge case — `load` would need to return
841
+ // a redirect but only in the browser
842
+ location.href = new URL(result.redirect, location.href).href;
843
+ return;
844
+ }
845
+
846
+ this._init(result);
847
+ }
848
+
849
+ /**
850
+ * @param {import('./types').NavigationInfo} info
851
+ * @param {string[]} chain
852
+ * @param {boolean} no_cache
853
+ * @param {{hash?: string, scroll: { x: number, y: number } | null, keepfocus: boolean}} [opts]
854
+ */
855
+ async handle_navigation(info, chain, no_cache, opts) {
856
+ if (this.started) {
857
+ this.stores.navigating.set({
858
+ from: this.current.url,
859
+ to: info.url
860
+ });
861
+ }
862
+
863
+ await this.update(info, chain, no_cache, opts);
864
+ }
865
+
866
+ /**
867
+ * @param {import('./types').NavigationInfo} info
868
+ * @param {string[]} chain
869
+ * @param {boolean} no_cache
870
+ * @param {{hash?: string, scroll: { x: number, y: number } | null, keepfocus: boolean}} [opts]
871
+ */
872
+ async update(info, chain, no_cache, opts) {
873
+ const token = (this.token = {});
874
+ let navigation_result = await this._get_navigation_result(info, no_cache);
875
+
876
+ if (!navigation_result) {
877
+ location.href = info.url.href;
878
+ return;
879
+ }
880
+
881
+ // abort if user navigated during update
882
+ if (token !== this.token) return;
883
+
884
+ this.invalid.clear();
885
+
886
+ if (navigation_result.redirect) {
887
+ if (chain.length > 10 || chain.includes(info.url.pathname)) {
888
+ navigation_result = await this._load_error({
889
+ status: 500,
890
+ error: new Error('Redirect loop'),
891
+ url: info.url
892
+ });
893
+ } else {
894
+ if (this.router) {
895
+ this.router.goto(
896
+ new URL(navigation_result.redirect, info.url).href,
897
+ { replaceState: true },
898
+ [...chain, info.url.pathname]
899
+ );
900
+ } else {
901
+ location.href = new URL(navigation_result.redirect, location.href).href;
902
+ }
903
+
904
+ return;
905
+ }
906
+ } else if (navigation_result.props?.page?.status >= 400) {
907
+ const updated = await this.stores.updated.check();
908
+ if (updated) {
909
+ location.href = info.url.href;
910
+ return;
911
+ }
912
+ }
913
+
914
+ this.updating = true;
915
+
916
+ if (this.started) {
917
+ this.current = navigation_result.state;
918
+
919
+ this.root.$set(navigation_result.props);
920
+ this.stores.navigating.set(null);
921
+ } else {
922
+ this._init(navigation_result);
923
+ }
924
+
925
+ // opts must be passed if we're navigating
926
+ if (opts) {
927
+ const { scroll, keepfocus } = opts;
928
+
929
+ if (!keepfocus) {
930
+ getSelection()?.removeAllRanges();
931
+ document.body.focus();
932
+ }
933
+
934
+ // need to render the DOM before we can scroll to the rendered elements
935
+ await tick();
936
+
937
+ if (this.autoscroll) {
938
+ const deep_linked = info.url.hash && document.getElementById(info.url.hash.slice(1));
939
+ if (scroll) {
940
+ scrollTo(scroll.x, scroll.y);
941
+ } else if (deep_linked) {
942
+ // Here we use `scrollIntoView` on the element instead of `scrollTo`
943
+ // because it natively supports the `scroll-margin` and `scroll-behavior`
944
+ // CSS properties.
945
+ deep_linked.scrollIntoView();
946
+ } else {
947
+ scrollTo(0, 0);
948
+ }
949
+ }
950
+ } else {
951
+ // in this case we're simply invalidating
952
+ await tick();
953
+ }
954
+
955
+ this.loading.promise = null;
956
+ this.loading.id = null;
957
+ this.autoscroll = true;
958
+ this.updating = false;
959
+
960
+ if (navigation_result.props.page) {
961
+ this.page = navigation_result.props.page;
962
+ }
963
+
964
+ if (!this.router) return;
965
+
966
+ const leaf_node = navigation_result.state.branch[navigation_result.state.branch.length - 1];
967
+ if (leaf_node && leaf_node.module.router === false) {
968
+ this.router.disable();
969
+ } else {
970
+ this.router.enable();
971
+ }
972
+ }
973
+
974
+ /**
975
+ * @param {import('./types').NavigationInfo} info
976
+ * @returns {Promise<import('./types').NavigationResult | undefined>}
977
+ */
978
+ load(info) {
979
+ this.loading.promise = this._get_navigation_result(info, false);
980
+ this.loading.id = info.id;
981
+
982
+ return this.loading.promise;
983
+ }
984
+
985
+ /** @param {string} href */
986
+ invalidate(href) {
987
+ this.invalid.add(href);
988
+
989
+ if (!this.invalidating) {
990
+ this.invalidating = Promise.resolve().then(async () => {
991
+ const info = this.router && this.router.parse(new URL(location.href));
992
+ if (info) await this.update(info, [], true);
993
+
994
+ this.invalidating = null;
995
+ });
996
+ }
997
+
998
+ return this.invalidating;
999
+ }
1000
+
1001
+ /** @param {URL} url */
1002
+ update_page_store(url) {
1003
+ this.stores.page.set({ ...this.page, url });
1004
+ this.stores.page.notify();
1005
+ }
1006
+
1007
+ /** @param {import('./types').NavigationResult} result */
1008
+ _init(result) {
1009
+ this.current = result.state;
1010
+
1011
+ const style = document.querySelector('style[data-svelte]');
1012
+ if (style) style.remove();
1013
+
1014
+ this.page = result.props.page;
1015
+
1016
+ this.root = new this.Root({
1017
+ target: this.target,
1018
+ props: {
1019
+ stores: this.stores,
1020
+ ...result.props
1021
+ },
1022
+ hydrate: true
1023
+ });
1024
+
1025
+ this.started = true;
1026
+
1027
+ if (this.router) {
1028
+ const navigation = { from: null, to: new URL(location.href) };
1029
+ this.router.callbacks.after_navigate.forEach((fn) => fn(navigation));
1030
+ }
1031
+ }
1032
+
1033
+ /**
1034
+ * @param {import('./types').NavigationInfo} info
1035
+ * @param {boolean} no_cache
1036
+ * @returns {Promise<import('./types').NavigationResult | undefined>}
1037
+ */
1038
+ async _get_navigation_result(info, no_cache) {
1039
+ if (this.loading.id === info.id && this.loading.promise) {
1040
+ return this.loading.promise;
1041
+ }
1042
+
1043
+ for (let i = 0; i < info.routes.length; i += 1) {
1044
+ const route = info.routes[i];
1045
+
1046
+ // load code for subsequent routes immediately, if they are as
1047
+ // likely to match the current path/query as the current one
1048
+ let j = i + 1;
1049
+ while (j < info.routes.length) {
1050
+ const next = info.routes[j];
1051
+ if (next[0].toString() === route[0].toString()) {
1052
+ next[1].forEach((loader) => loader());
1053
+ j += 1;
1054
+ } else {
1055
+ break;
1056
+ }
1057
+ }
1058
+
1059
+ const result = await this._load(
1060
+ {
1061
+ route,
1062
+ info
1063
+ },
1064
+ no_cache
1065
+ );
1066
+ if (result) return result;
1067
+ }
1068
+
1069
+ if (info.initial) {
1070
+ return await this._load_error({
1071
+ status: 404,
1072
+ error: new Error(`Not found: ${info.url.pathname}`),
1073
+ url: info.url
1074
+ });
1075
+ }
1076
+ }
1077
+
1078
+ /**
1079
+ *
1080
+ * @param {{
1081
+ * url: URL;
1082
+ * params: Record<string, string>;
1083
+ * stuff: Record<string, any>;
1084
+ * branch: Array<import('./types').BranchNode | undefined>;
1085
+ * status: number;
1086
+ * error?: Error;
1087
+ * }} opts
1088
+ */
1089
+ async _get_navigation_result_from_branch({ url, params, stuff, branch, status, error }) {
1090
+ const filtered = /** @type {import('./types').BranchNode[] } */ (branch.filter(Boolean));
1091
+ const redirect = filtered.find((f) => f.loaded && f.loaded.redirect);
1092
+
1093
+ /** @type {import('./types').NavigationResult} */
1094
+ const result = {
1095
+ redirect: redirect && redirect.loaded ? redirect.loaded.redirect : undefined,
1096
+ state: {
1097
+ url,
1098
+ params,
1099
+ branch,
1100
+ session_id: this.session_id
1101
+ },
1102
+ props: {
1103
+ components: filtered.map((node) => node.module.default)
1104
+ }
1105
+ };
1106
+
1107
+ for (let i = 0; i < filtered.length; i += 1) {
1108
+ const loaded = filtered[i].loaded;
1109
+ result.props[`props_${i}`] = loaded ? await loaded.props : null;
1110
+ }
1111
+
1112
+ if (!this.current.url || url.href !== this.current.url.href) {
1113
+ result.props.page = { url, params, status, error, stuff };
1114
+
1115
+ // TODO remove this for 1.0
1116
+ /**
1117
+ * @param {string} property
1118
+ * @param {string} replacement
1119
+ */
1120
+ const print_error = (property, replacement) => {
1121
+ Object.defineProperty(result.props.page, property, {
1122
+ get: () => {
1123
+ throw new Error(`$page.${property} has been replaced by $page.url.${replacement}`);
1124
+ }
1125
+ });
1126
+ };
1127
+
1128
+ print_error('origin', 'origin');
1129
+ print_error('path', 'pathname');
1130
+ print_error('query', 'searchParams');
1131
+ }
1132
+
1133
+ const leaf = filtered[filtered.length - 1];
1134
+ const maxage = leaf.loaded && leaf.loaded.maxage;
1135
+
1136
+ if (maxage) {
1137
+ const key = url.pathname + url.search; // omit hash
1138
+ let ready = false;
1139
+
1140
+ const clear = () => {
1141
+ if (this.cache.get(key) === result) {
1142
+ this.cache.delete(key);
1143
+ }
1144
+
1145
+ unsubscribe();
1146
+ clearTimeout(timeout);
1147
+ };
1148
+
1149
+ const timeout = setTimeout(clear, maxage * 1000);
1150
+
1151
+ const unsubscribe = this.stores.session.subscribe(() => {
1152
+ if (ready) clear();
1153
+ });
1154
+
1155
+ ready = true;
1156
+
1157
+ this.cache.set(key, result);
1158
+ }
1159
+
1160
+ return result;
1161
+ }
1162
+
1163
+ /**
1164
+ * @param {{
1165
+ * status?: number;
1166
+ * error?: Error;
1167
+ * module: CSRComponent;
1168
+ * url: URL;
1169
+ * params: Record<string, string>;
1170
+ * stuff: Record<string, any>;
1171
+ * props?: Record<string, any>;
1172
+ * }} options
1173
+ * @returns
1174
+ */
1175
+ async _load_node({ status, error, module, url, params, stuff, props }) {
1176
+ /** @type {import('./types').BranchNode} */
1177
+ const node = {
1178
+ module,
1179
+ uses: {
1180
+ params: new Set(),
1181
+ url: false,
1182
+ session: false,
1183
+ stuff: false,
1184
+ dependencies: new Set()
1185
+ },
1186
+ loaded: null,
1187
+ stuff
1188
+ };
1189
+
1190
+ if (props) {
1191
+ // shadow endpoint props means we need to mark this URL as a dependency of itself
1192
+ node.uses.dependencies.add(url.href);
1193
+ }
1194
+
1195
+ /** @type {Record<string, string>} */
1196
+ const uses_params = {};
1197
+ for (const key in params) {
1198
+ Object.defineProperty(uses_params, key, {
1199
+ get() {
1200
+ node.uses.params.add(key);
1201
+ return params[key];
1202
+ },
1203
+ enumerable: true
1204
+ });
1205
+ }
1206
+
1207
+ const session = this.$session;
1208
+
1209
+ if (module.load) {
1210
+ const { started } = this;
1211
+
1212
+ /** @type {import('types').LoadInput | import('types').ErrorLoadInput} */
1213
+ const load_input = {
1214
+ params: uses_params,
1215
+ props: props || {},
1216
+ get url() {
1217
+ node.uses.url = true;
1218
+ return url;
1219
+ },
1220
+ get session() {
1221
+ node.uses.session = true;
1222
+ return session;
1223
+ },
1224
+ get stuff() {
1225
+ node.uses.stuff = true;
1226
+ return { ...stuff };
1227
+ },
1228
+ fetch(resource, info) {
1229
+ const requested = typeof resource === 'string' ? resource : resource.url;
1230
+ const { href } = new URL(requested, url);
1231
+ node.uses.dependencies.add(href);
1232
+
1233
+ return started ? fetch(resource, info) : initial_fetch(resource, info);
1234
+ }
1235
+ };
1236
+
1237
+ if (import.meta.env.DEV) {
1238
+ // TODO remove this for 1.0
1239
+ Object.defineProperty(load_input, 'page', {
1240
+ get: () => {
1241
+ throw new Error('`page` in `load` functions has been replaced by `url` and `params`');
1242
+ }
1243
+ });
1244
+ }
1245
+
1246
+ if (error) {
1247
+ /** @type {import('types').ErrorLoadInput} */ (load_input).status = status;
1248
+ /** @type {import('types').ErrorLoadInput} */ (load_input).error = error;
1249
+ }
1250
+
1251
+ const loaded = await module.load.call(null, load_input);
1252
+
1253
+ if (!loaded) {
1254
+ throw new Error('load function must return a value');
1255
+ }
1256
+
1257
+ node.loaded = normalize(loaded);
1258
+ if (node.loaded.stuff) node.stuff = node.loaded.stuff;
1259
+ } else if (props) {
1260
+ node.loaded = normalize({ props });
1261
+ }
1262
+
1263
+ return node;
1264
+ }
1265
+
1266
+ /**
1267
+ * @param {import('./types').NavigationCandidate} selected
1268
+ * @param {boolean} no_cache
1269
+ * @returns {Promise<import('./types').NavigationResult | undefined>} undefined if fallthrough
1270
+ */
1271
+ async _load({ route, info: { url, path } }, no_cache) {
1272
+ const key = url.pathname + url.search;
1273
+
1274
+ if (!no_cache) {
1275
+ const cached = this.cache.get(key);
1276
+ if (cached) return cached;
1277
+ }
1278
+
1279
+ const [pattern, a, b, get_params, has_shadow] = route;
1280
+ const params = get_params
1281
+ ? // the pattern is for the route which we've already matched to this path
1282
+ get_params(/** @type {RegExpExecArray} */ (pattern.exec(path)))
1283
+ : {};
1284
+
1285
+ const changed = this.current.url && {
1286
+ url: key !== this.current.url.pathname + this.current.url.search,
1287
+ params: Object.keys(params).filter((key) => this.current.params[key] !== params[key]),
1288
+ session: this.session_id !== this.current.session_id
1289
+ };
1290
+
1291
+ /** @type {Array<import('./types').BranchNode | undefined>} */
1292
+ let branch = [];
1293
+
1294
+ /** @type {Record<string, any>} */
1295
+ let stuff = {};
1296
+ let stuff_changed = false;
1297
+
1298
+ /** @type {number | undefined} */
1299
+ let status = 200;
1300
+
1301
+ /** @type {Error | undefined} */
1302
+ let error;
1303
+
1304
+ // preload modules
1305
+ a.forEach((loader) => loader());
1306
+
1307
+ load: for (let i = 0; i < a.length; i += 1) {
1308
+ /** @type {import('./types').BranchNode | undefined} */
1309
+ let node;
1310
+
1311
+ try {
1312
+ if (!a[i]) continue;
1313
+
1314
+ const module = await a[i]();
1315
+ const previous = this.current.branch[i];
1316
+
1317
+ const changed_since_last_render =
1318
+ !previous ||
1319
+ module !== previous.module ||
1320
+ (changed.url && previous.uses.url) ||
1321
+ changed.params.some((param) => previous.uses.params.has(param)) ||
1322
+ (changed.session && previous.uses.session) ||
1323
+ Array.from(previous.uses.dependencies).some((dep) => this.invalid.has(dep)) ||
1324
+ (stuff_changed && previous.uses.stuff);
1325
+
1326
+ if (changed_since_last_render) {
1327
+ /** @type {Record<string, any>} */
1328
+ let props = {};
1329
+
1330
+ const is_shadow_page = has_shadow && i === a.length - 1;
1331
+
1332
+ if (is_shadow_page) {
1333
+ const res = await fetch(
1334
+ `${url.pathname}${url.pathname.endsWith('/') ? '' : '/'}__data.json${url.search}`,
1335
+ {
1336
+ headers: {
1337
+ 'x-sveltekit-load': 'true'
1338
+ }
1339
+ }
1340
+ );
1341
+
1342
+ if (res.ok) {
1343
+ const redirect = res.headers.get('x-sveltekit-location');
1344
+
1345
+ if (redirect) {
1346
+ return {
1347
+ redirect,
1348
+ props: {},
1349
+ state: this.current
1350
+ };
1351
+ }
1352
+
1353
+ props = await res.json();
1354
+ } else {
1355
+ status = res.status;
1356
+ error = new Error('Failed to load data');
1357
+ }
1358
+ }
1359
+
1360
+ if (!error) {
1361
+ node = await this._load_node({
1362
+ module,
1363
+ url,
1364
+ params,
1365
+ props,
1366
+ stuff
1367
+ });
1368
+ }
1369
+
1370
+ if (node) {
1371
+ if (is_shadow_page) {
1372
+ node.uses.url = true;
1373
+ }
1374
+
1375
+ if (node.loaded) {
1376
+ if (node.loaded.fallthrough) {
1377
+ return;
1378
+ }
1379
+ if (node.loaded.error) {
1380
+ status = node.loaded.status;
1381
+ error = node.loaded.error;
1382
+ }
1383
+
1384
+ if (node.loaded.redirect) {
1385
+ return {
1386
+ redirect: node.loaded.redirect,
1387
+ props: {},
1388
+ state: this.current
1389
+ };
1390
+ }
1391
+
1392
+ if (node.loaded.stuff) {
1393
+ stuff_changed = true;
1394
+ }
1395
+ }
1396
+ }
1397
+ } else {
1398
+ node = previous;
1399
+ }
1400
+ } catch (e) {
1401
+ status = 500;
1402
+ error = coalesce_to_error(e);
1403
+ }
1404
+
1405
+ if (error) {
1406
+ while (i--) {
1407
+ if (b[i]) {
1408
+ let error_loaded;
1409
+
1410
+ /** @type {import('./types').BranchNode | undefined} */
1411
+ let node_loaded;
1412
+ let j = i;
1413
+ while (!(node_loaded = branch[j])) {
1414
+ j -= 1;
1415
+ }
1416
+
1417
+ try {
1418
+ error_loaded = await this._load_node({
1419
+ status,
1420
+ error,
1421
+ module: await b[i](),
1422
+ url,
1423
+ params,
1424
+ stuff: node_loaded.stuff
1425
+ });
1426
+
1427
+ if (error_loaded && error_loaded.loaded && error_loaded.loaded.error) {
1428
+ continue;
1429
+ }
1430
+
1431
+ if (error_loaded && error_loaded.loaded && error_loaded.loaded.stuff) {
1432
+ stuff = {
1433
+ ...stuff,
1434
+ ...error_loaded.loaded.stuff
1435
+ };
1436
+ }
1437
+
1438
+ branch = branch.slice(0, j + 1).concat(error_loaded);
1439
+ break load;
1440
+ } catch (e) {
1441
+ continue;
1442
+ }
1443
+ }
1444
+ }
1445
+
1446
+ return await this._load_error({
1447
+ status,
1448
+ error,
1449
+ url
1450
+ });
1451
+ } else {
1452
+ if (node && node.loaded && node.loaded.stuff) {
1453
+ stuff = {
1454
+ ...stuff,
1455
+ ...node.loaded.stuff
1456
+ };
1457
+ }
1458
+
1459
+ branch.push(node);
1460
+ }
1461
+ }
1462
+
1463
+ return await this._get_navigation_result_from_branch({
1464
+ url,
1465
+ params,
1466
+ stuff,
1467
+ branch,
1468
+ status,
1469
+ error
1470
+ });
1471
+ }
1472
+
1473
+ /**
1474
+ * @param {{
1475
+ * status: number;
1476
+ * error: Error;
1477
+ * url: URL;
1478
+ * }} opts
1479
+ */
1480
+ async _load_error({ status, error, url }) {
1481
+ /** @type {Record<string, string>} */
1482
+ const params = {}; // error page does not have params
1483
+
1484
+ const node = await this._load_node({
1485
+ module: await this.fallback[0],
1486
+ url,
1487
+ params,
1488
+ stuff: {}
1489
+ });
1490
+ const error_node = await this._load_node({
1491
+ status,
1492
+ error,
1493
+ module: await this.fallback[1],
1494
+ url,
1495
+ params,
1496
+ stuff: (node && node.loaded && node.loaded.stuff) || {}
1497
+ });
1498
+
1499
+ const branch = [node, error_node];
1500
+ const stuff = { ...node?.loaded?.stuff, ...error_node?.loaded?.stuff };
1501
+
1502
+ return await this._get_navigation_result_from_branch({
1503
+ url,
1504
+ params,
1505
+ stuff,
1506
+ branch,
1507
+ status,
1508
+ error
1509
+ });
1510
+ }
1511
+ }
1512
+
1513
+ /**
1514
+ * @param {{
1515
+ * paths: {
1516
+ * assets: string;
1517
+ * base: string;
1518
+ * },
1519
+ * target: Node;
1520
+ * session: any;
1521
+ * route: boolean;
1522
+ * spa: boolean;
1523
+ * trailing_slash: import('types').TrailingSlash;
1524
+ * hydrate: {
1525
+ * status: number;
1526
+ * error: Error;
1527
+ * nodes: Array<Promise<import('types').CSRComponent>>;
1528
+ * params: Record<string, string>;
1529
+ * };
1530
+ * }} opts
1531
+ */
1532
+ async function start({ paths, target, session, route, spa, trailing_slash, hydrate }) {
1533
+ const renderer = new Renderer({
1534
+ Root,
1535
+ fallback,
1536
+ target,
1537
+ session
1538
+ });
1539
+
1540
+ const router = route
1541
+ ? new Router({
1542
+ base: paths.base,
1543
+ routes,
1544
+ trailing_slash,
1545
+ renderer
1546
+ })
1547
+ : null;
1548
+
1549
+ init({ router, renderer });
1550
+ set_paths(paths);
1551
+
1552
+ if (hydrate) await renderer.start(hydrate);
1553
+ if (router) {
1554
+ if (spa) router.goto(location.href, { replaceState: true }, []);
1555
+ router.init_listeners();
1556
+ }
1557
+
1558
+ dispatchEvent(new CustomEvent('sveltekit:start'));
1559
+ }
1560
+
1561
+ export { start };