@sveltejs/kit 1.0.0-next.27 → 1.0.0-next.273

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