@sveltejs/kit 1.0.0-next.45 → 1.0.0-next.450

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 (108) hide show
  1. package/README.md +12 -9
  2. package/package.json +92 -63
  3. package/src/cli.js +112 -0
  4. package/src/constants.js +7 -0
  5. package/src/core/adapt/builder.js +223 -0
  6. package/src/core/adapt/index.js +19 -0
  7. package/src/core/config/index.js +86 -0
  8. package/src/core/config/options.js +488 -0
  9. package/src/core/config/types.d.ts +1 -0
  10. package/src/core/env.js +97 -0
  11. package/src/core/generate_manifest/index.js +78 -0
  12. package/src/core/prerender/crawl.js +194 -0
  13. package/src/core/prerender/prerender.js +380 -0
  14. package/src/core/prerender/queue.js +80 -0
  15. package/src/core/sync/create_manifest_data/index.js +452 -0
  16. package/src/core/sync/create_manifest_data/types.d.ts +37 -0
  17. package/src/core/sync/sync.js +59 -0
  18. package/src/core/sync/utils.js +33 -0
  19. package/src/core/sync/write_ambient.js +27 -0
  20. package/src/core/sync/write_client_manifest.js +94 -0
  21. package/src/core/sync/write_matchers.js +25 -0
  22. package/src/core/sync/write_root.js +91 -0
  23. package/src/core/sync/write_tsconfig.js +195 -0
  24. package/src/core/sync/write_types/index.js +596 -0
  25. package/src/core/utils.js +70 -0
  26. package/src/exports/hooks/index.js +1 -0
  27. package/src/exports/hooks/sequence.js +26 -0
  28. package/src/exports/index.js +45 -0
  29. package/src/exports/node/index.js +145 -0
  30. package/src/exports/node/polyfills.js +40 -0
  31. package/src/exports/vite/build/build_server.js +348 -0
  32. package/src/exports/vite/build/build_service_worker.js +90 -0
  33. package/src/exports/vite/build/utils.js +160 -0
  34. package/src/exports/vite/dev/index.js +543 -0
  35. package/src/exports/vite/index.js +588 -0
  36. package/src/exports/vite/preview/index.js +186 -0
  37. package/src/exports/vite/types.d.ts +3 -0
  38. package/src/exports/vite/utils.js +345 -0
  39. package/src/runtime/app/env.js +1 -0
  40. package/src/runtime/app/environment.js +11 -0
  41. package/src/runtime/app/navigation.js +22 -0
  42. package/src/runtime/app/paths.js +1 -0
  43. package/src/runtime/app/stores.js +102 -0
  44. package/src/runtime/client/ambient.d.ts +24 -0
  45. package/src/runtime/client/client.js +1394 -0
  46. package/src/runtime/client/fetcher.js +60 -0
  47. package/src/runtime/client/parse.js +60 -0
  48. package/src/runtime/client/singletons.js +21 -0
  49. package/src/runtime/client/start.js +48 -0
  50. package/src/runtime/client/types.d.ts +88 -0
  51. package/src/runtime/client/utils.js +113 -0
  52. package/src/runtime/components/error.svelte +16 -0
  53. package/{assets → src/runtime}/components/layout.svelte +0 -0
  54. package/src/runtime/control.js +33 -0
  55. package/src/runtime/env/dynamic/private.js +1 -0
  56. package/src/runtime/env/dynamic/public.js +1 -0
  57. package/src/runtime/env-private.js +7 -0
  58. package/src/runtime/env-public.js +7 -0
  59. package/src/runtime/env.js +6 -0
  60. package/src/runtime/hash.js +16 -0
  61. package/src/runtime/paths.js +11 -0
  62. package/src/runtime/server/data/index.js +146 -0
  63. package/src/runtime/server/endpoint.js +50 -0
  64. package/src/runtime/server/index.js +369 -0
  65. package/src/runtime/server/page/cookie.js +25 -0
  66. package/src/runtime/server/page/crypto.js +239 -0
  67. package/src/runtime/server/page/csp.js +249 -0
  68. package/src/runtime/server/page/fetch.js +266 -0
  69. package/src/runtime/server/page/index.js +413 -0
  70. package/src/runtime/server/page/load_data.js +124 -0
  71. package/src/runtime/server/page/render.js +379 -0
  72. package/src/runtime/server/page/respond_with_error.js +94 -0
  73. package/src/runtime/server/page/types.d.ts +44 -0
  74. package/src/runtime/server/utils.js +137 -0
  75. package/src/utils/array.js +9 -0
  76. package/src/utils/error.js +22 -0
  77. package/src/utils/escape.js +104 -0
  78. package/src/utils/filesystem.js +108 -0
  79. package/src/utils/functions.js +16 -0
  80. package/src/utils/http.js +55 -0
  81. package/src/utils/misc.js +1 -0
  82. package/src/utils/routing.js +146 -0
  83. package/src/utils/url.js +142 -0
  84. package/svelte-kit.js +1 -1
  85. package/types/ambient.d.ts +366 -0
  86. package/types/index.d.ts +345 -0
  87. package/types/internal.d.ts +379 -0
  88. package/types/private.d.ts +209 -0
  89. package/CHANGELOG.md +0 -450
  90. package/assets/components/error.svelte +0 -13
  91. package/assets/runtime/app/env.js +0 -5
  92. package/assets/runtime/app/navigation.js +0 -41
  93. package/assets/runtime/app/paths.js +0 -1
  94. package/assets/runtime/app/stores.js +0 -93
  95. package/assets/runtime/chunks/utils.js +0 -19
  96. package/assets/runtime/internal/singletons.js +0 -23
  97. package/assets/runtime/internal/start.js +0 -770
  98. package/assets/runtime/paths.js +0 -12
  99. package/dist/chunks/index.js +0 -3521
  100. package/dist/chunks/index2.js +0 -587
  101. package/dist/chunks/index3.js +0 -246
  102. package/dist/chunks/index4.js +0 -536
  103. package/dist/chunks/index5.js +0 -761
  104. package/dist/chunks/index6.js +0 -322
  105. package/dist/chunks/standard.js +0 -99
  106. package/dist/chunks/utils.js +0 -83
  107. package/dist/cli.js +0 -546
  108. package/dist/ssr.js +0 -2580
@@ -0,0 +1,1394 @@
1
+ import { onMount, tick } from 'svelte';
2
+ import { normalize_error } from '../../utils/error.js';
3
+ import { make_trackable, decode_params, normalize_path } from '../../utils/url.js';
4
+ import { find_anchor, get_base_uri, get_href, scroll_state } from './utils.js';
5
+ import { lock_fetch, unlock_fetch, initial_fetch, native_fetch } from './fetcher.js';
6
+ import { parse } from './parse.js';
7
+ import { error } from '../../exports/index.js';
8
+
9
+ import Root from '__GENERATED__/root.svelte';
10
+ import { nodes, server_loads, dictionary, matchers } from '__GENERATED__/client-manifest.js';
11
+ import { HttpError, Redirect } from '../control.js';
12
+ import { stores } from './singletons.js';
13
+ import { DATA_SUFFIX } from '../../constants.js';
14
+
15
+ const SCROLL_KEY = 'sveltekit:scroll';
16
+ const INDEX_KEY = 'sveltekit:index';
17
+
18
+ const routes = parse(nodes, server_loads, dictionary, matchers);
19
+
20
+ const default_layout_loader = nodes[0];
21
+ const default_error_loader = nodes[1];
22
+
23
+ // we import the root layout/error nodes eagerly, so that
24
+ // connectivity errors after initialisation don't nuke the app
25
+ default_layout_loader();
26
+ default_error_loader();
27
+
28
+ // We track the scroll position associated with each history entry in sessionStorage,
29
+ // rather than on history.state itself, because when navigation is driven by
30
+ // popstate it's too late to update the scroll position associated with the
31
+ // state we're navigating from
32
+
33
+ /** @typedef {{ x: number, y: number }} ScrollPosition */
34
+ /** @type {Record<number, ScrollPosition>} */
35
+ let scroll_positions = {};
36
+ try {
37
+ scroll_positions = JSON.parse(sessionStorage[SCROLL_KEY]);
38
+ } catch {
39
+ // do nothing
40
+ }
41
+
42
+ /** @param {number} index */
43
+ function update_scroll_positions(index) {
44
+ scroll_positions[index] = scroll_state();
45
+ }
46
+
47
+ /**
48
+ * @param {{
49
+ * target: Element;
50
+ * base: string;
51
+ * trailing_slash: import('types').TrailingSlash;
52
+ * }} opts
53
+ * @returns {import('./types').Client}
54
+ */
55
+ export function create_client({ target, base, trailing_slash }) {
56
+ /** @type {Array<((href: string) => boolean)>} */
57
+ const invalidated = [];
58
+
59
+ /** @type {{id: string | null, promise: Promise<import('./types').NavigationResult | undefined> | null}} */
60
+ const load_cache = {
61
+ id: null,
62
+ promise: null
63
+ };
64
+
65
+ const callbacks = {
66
+ /** @type {Array<(opts: { from: URL, to: URL | null, cancel: () => void }) => void>} */
67
+ before_navigate: [],
68
+
69
+ /** @type {Array<(opts: { from: URL | null, to: URL }) => void>} */
70
+ after_navigate: []
71
+ };
72
+
73
+ /** @type {import('./types').NavigationState} */
74
+ let current = {
75
+ branch: [],
76
+ error: null,
77
+ session_id: 0,
78
+ // @ts-ignore - we need the initial value to be null
79
+ url: null
80
+ };
81
+
82
+ let started = false;
83
+ let autoscroll = true;
84
+ let updating = false;
85
+ let session_id = 1;
86
+
87
+ /** @type {Promise<void> | null} */
88
+ let invalidating = null;
89
+
90
+ /** @type {import('svelte').SvelteComponent} */
91
+ let root;
92
+
93
+ let router_enabled = true;
94
+
95
+ // keeping track of the history index in order to prevent popstate navigation events if needed
96
+ let current_history_index = history.state?.[INDEX_KEY];
97
+
98
+ if (!current_history_index) {
99
+ // we use Date.now() as an offset so that cross-document navigations
100
+ // within the app don't result in data loss
101
+ current_history_index = Date.now();
102
+
103
+ // create initial history entry, so we can return here
104
+ history.replaceState(
105
+ { ...history.state, [INDEX_KEY]: current_history_index },
106
+ '',
107
+ location.href
108
+ );
109
+ }
110
+
111
+ // if we reload the page, or Cmd-Shift-T back to it,
112
+ // recover scroll position
113
+ const scroll = scroll_positions[current_history_index];
114
+ if (scroll) {
115
+ history.scrollRestoration = 'manual';
116
+ scrollTo(scroll.x, scroll.y);
117
+ }
118
+
119
+ let hash_navigating = false;
120
+
121
+ /** @type {import('types').Page} */
122
+ let page;
123
+
124
+ /** @type {{}} */
125
+ let token;
126
+
127
+ /**
128
+ * @param {string | URL} url
129
+ * @param {{ noscroll?: boolean; replaceState?: boolean; keepfocus?: boolean; state?: any }} opts
130
+ * @param {string[]} redirect_chain
131
+ */
132
+ async function goto(
133
+ url,
134
+ { noscroll = false, replaceState = false, keepfocus = false, state = {} },
135
+ redirect_chain
136
+ ) {
137
+ if (typeof url === 'string') {
138
+ url = new URL(url, get_base_uri(document));
139
+ }
140
+
141
+ if (router_enabled) {
142
+ return navigate({
143
+ url,
144
+ scroll: noscroll ? scroll_state() : null,
145
+ keepfocus,
146
+ redirect_chain,
147
+ details: {
148
+ state,
149
+ replaceState
150
+ },
151
+ accepted: () => {},
152
+ blocked: () => {}
153
+ });
154
+ }
155
+
156
+ await native_navigation(url);
157
+ }
158
+
159
+ /** @param {URL} url */
160
+ async function prefetch(url) {
161
+ const intent = get_navigation_intent(url);
162
+
163
+ if (!intent) {
164
+ throw new Error('Attempted to prefetch a URL that does not belong to this app');
165
+ }
166
+
167
+ load_cache.promise = load_route(intent);
168
+ load_cache.id = intent.id;
169
+
170
+ return load_cache.promise;
171
+ }
172
+
173
+ /**
174
+ * Returns `true` if update completes, `false` if it is aborted
175
+ * @param {URL} url
176
+ * @param {string[]} redirect_chain
177
+ * @param {{hash?: string, scroll: { x: number, y: number } | null, keepfocus: boolean, details: { replaceState: boolean, state: any } | null}} [opts]
178
+ * @param {() => void} [callback]
179
+ */
180
+ async function update(url, redirect_chain, opts, callback) {
181
+ const intent = get_navigation_intent(url);
182
+
183
+ const current_token = (token = {});
184
+ let navigation_result = intent && (await load_route(intent));
185
+
186
+ if (
187
+ !navigation_result &&
188
+ url.origin === location.origin &&
189
+ url.pathname === location.pathname
190
+ ) {
191
+ // this could happen in SPA fallback mode if the user navigated to
192
+ // `/non-existent-page`. if we fall back to reloading the page, it
193
+ // will create an infinite loop. so whereas we normally handle
194
+ // unknown routes by going to the server, in this special case
195
+ // we render a client-side error page instead
196
+ navigation_result = await load_root_error_page({
197
+ status: 404,
198
+ error: new Error(`Not found: ${url.pathname}`),
199
+ url,
200
+ routeId: null
201
+ });
202
+ }
203
+
204
+ if (!navigation_result) {
205
+ await native_navigation(url);
206
+ return false; // unnecessary, but TypeScript prefers it this way
207
+ }
208
+
209
+ // if this is an internal navigation intent, use the normalized
210
+ // URL for the rest of the function
211
+ url = intent?.url || url;
212
+
213
+ // abort if user navigated during update
214
+ if (token !== current_token) return false;
215
+
216
+ invalidated.length = 0;
217
+
218
+ if (navigation_result.type === 'redirect') {
219
+ if (redirect_chain.length > 10 || redirect_chain.includes(url.pathname)) {
220
+ navigation_result = await load_root_error_page({
221
+ status: 500,
222
+ error: new Error('Redirect loop'),
223
+ url,
224
+ routeId: null
225
+ });
226
+ } else {
227
+ if (router_enabled) {
228
+ goto(new URL(navigation_result.location, url).href, {}, [
229
+ ...redirect_chain,
230
+ url.pathname
231
+ ]);
232
+ } else {
233
+ await native_navigation(new URL(navigation_result.location, location.href));
234
+ }
235
+
236
+ return false;
237
+ }
238
+ } else if (navigation_result.props?.page?.status >= 400) {
239
+ const updated = await stores.updated.check();
240
+ if (updated) {
241
+ await native_navigation(url);
242
+ }
243
+ }
244
+
245
+ updating = true;
246
+
247
+ if (opts && opts.details) {
248
+ const { details } = opts;
249
+ const change = details.replaceState ? 0 : 1;
250
+ details.state[INDEX_KEY] = current_history_index += change;
251
+ history[details.replaceState ? 'replaceState' : 'pushState'](details.state, '', url);
252
+ }
253
+
254
+ if (started) {
255
+ current = navigation_result.state;
256
+
257
+ if (navigation_result.props.page) {
258
+ navigation_result.props.page.url = url;
259
+ }
260
+
261
+ if (import.meta.env.DEV) {
262
+ // Nasty hack to silence harmless warnings the user can do nothing about
263
+ const warn = console.warn;
264
+ console.warn = (...args) => {
265
+ if (
266
+ args.length !== 1 ||
267
+ !/<(Layout|Page)(_[\w$]+)?> was created with unknown prop '(data|errors)'/.test(args[0])
268
+ ) {
269
+ warn(...args);
270
+ }
271
+ };
272
+ root.$set(navigation_result.props);
273
+ tick().then(() => (console.warn = warn));
274
+ } else {
275
+ root.$set(navigation_result.props);
276
+ }
277
+ } else {
278
+ initialize(navigation_result);
279
+ }
280
+
281
+ // opts must be passed if we're navigating
282
+ if (opts) {
283
+ const { scroll, keepfocus } = opts;
284
+
285
+ if (!keepfocus) {
286
+ // Reset page selection and focus
287
+ // We try to mimic browsers' behaviour as closely as possible by targeting the
288
+ // first scrollable region, but unfortunately it's not a perfect match — e.g.
289
+ // shift-tabbing won't immediately cycle up from the end of the page on Chromium
290
+ // See https://html.spec.whatwg.org/multipage/interaction.html#get-the-focusable-area
291
+ const root = document.body;
292
+ const tabindex = root.getAttribute('tabindex');
293
+
294
+ root.tabIndex = -1;
295
+ root.focus({ preventScroll: true });
296
+
297
+ setTimeout(() => {
298
+ getSelection()?.removeAllRanges();
299
+ });
300
+
301
+ // restore `tabindex` as to prevent `root` from stealing input from elements
302
+ if (tabindex !== null) {
303
+ root.setAttribute('tabindex', tabindex);
304
+ } else {
305
+ root.removeAttribute('tabindex');
306
+ }
307
+ }
308
+
309
+ // need to render the DOM before we can scroll to the rendered elements
310
+ await tick();
311
+
312
+ if (autoscroll) {
313
+ const deep_linked = url.hash && document.getElementById(url.hash.slice(1));
314
+ if (scroll) {
315
+ scrollTo(scroll.x, scroll.y);
316
+ } else if (deep_linked) {
317
+ // Here we use `scrollIntoView` on the element instead of `scrollTo`
318
+ // because it natively supports the `scroll-margin` and `scroll-behavior`
319
+ // CSS properties.
320
+ deep_linked.scrollIntoView();
321
+ } else {
322
+ scrollTo(0, 0);
323
+ }
324
+ }
325
+ } else {
326
+ // in this case we're simply invalidating
327
+ await tick();
328
+ }
329
+
330
+ load_cache.promise = null;
331
+ load_cache.id = null;
332
+ autoscroll = true;
333
+
334
+ if (navigation_result.props.page) {
335
+ page = navigation_result.props.page;
336
+ }
337
+
338
+ const leaf_node = navigation_result.state.branch[navigation_result.state.branch.length - 1];
339
+ router_enabled = leaf_node?.node.shared?.router !== false;
340
+
341
+ if (callback) callback();
342
+
343
+ updating = false;
344
+ }
345
+
346
+ /** @param {import('./types').NavigationFinished} result */
347
+ function initialize(result) {
348
+ current = result.state;
349
+
350
+ const style = document.querySelector('style[data-sveltekit]');
351
+ if (style) style.remove();
352
+
353
+ page = result.props.page;
354
+
355
+ if (import.meta.env.DEV) {
356
+ // Nasty hack to silence harmless warnings the user can do nothing about
357
+ const warn = console.warn;
358
+ console.warn = (...args) => {
359
+ if (
360
+ args.length !== 1 ||
361
+ !/<(Layout|Page)(_[\w$]+)?> was created with unknown prop '(data|errors)'/.test(args[0])
362
+ ) {
363
+ warn(...args);
364
+ }
365
+ };
366
+ root = new Root({
367
+ target,
368
+ props: { ...result.props, stores },
369
+ hydrate: true
370
+ });
371
+ console.warn = warn;
372
+ } else {
373
+ root = new Root({
374
+ target,
375
+ props: { ...result.props, stores },
376
+ hydrate: true
377
+ });
378
+ }
379
+
380
+ if (router_enabled) {
381
+ const navigation = { from: null, to: new URL(location.href) };
382
+ callbacks.after_navigate.forEach((fn) => fn(navigation));
383
+ }
384
+
385
+ started = true;
386
+ }
387
+
388
+ /**
389
+ *
390
+ * @param {{
391
+ * url: URL;
392
+ * params: Record<string, string>;
393
+ * branch: Array<import('./types').BranchNode | undefined>;
394
+ * status: number;
395
+ * error: HttpError | Error | null;
396
+ * routeId: string | null;
397
+ * validation_errors?: Record<string, any> | null;
398
+ * }} opts
399
+ */
400
+ async function get_navigation_result_from_branch({
401
+ url,
402
+ params,
403
+ branch,
404
+ status,
405
+ error,
406
+ routeId,
407
+ validation_errors
408
+ }) {
409
+ const filtered = /** @type {import('./types').BranchNode[] } */ (branch.filter(Boolean));
410
+
411
+ /** @type {import('./types').NavigationFinished} */
412
+ const result = {
413
+ type: 'loaded',
414
+ state: {
415
+ url,
416
+ params,
417
+ branch,
418
+ error,
419
+ session_id
420
+ },
421
+ props: {
422
+ components: filtered.map((branch_node) => branch_node.node.component),
423
+ errors: validation_errors
424
+ }
425
+ };
426
+
427
+ let data = {};
428
+ let data_changed = !page;
429
+ for (let i = 0; i < filtered.length; i += 1) {
430
+ const node = filtered[i];
431
+ data = { ...data, ...node.data };
432
+
433
+ // Only set props if the node actually updated. This prevents needless rerenders.
434
+ if (data_changed || !current.branch.some((previous) => previous === node)) {
435
+ result.props[`data_${i}`] = data;
436
+ data_changed = data_changed || Object.keys(node.data ?? {}).length > 0;
437
+ }
438
+ }
439
+ if (!data_changed) {
440
+ // If nothing was added, and the object entries are the same length, this means
441
+ // that nothing was removed either and therefore the data is the same as the previous one.
442
+ // This would be more readable with a separate boolean but that would cost us some bytes.
443
+ data_changed = Object.keys(page.data).length !== Object.keys(data).length;
444
+ }
445
+
446
+ const page_changed =
447
+ !current.url || url.href !== current.url.href || current.error !== error || data_changed;
448
+
449
+ if (page_changed) {
450
+ result.props.page = {
451
+ error,
452
+ params,
453
+ routeId,
454
+ status,
455
+ url,
456
+ // The whole page store is updated, but this way the object reference stays the same
457
+ data: data_changed ? data : page.data
458
+ };
459
+
460
+ // TODO remove this for 1.0
461
+ /**
462
+ * @param {string} property
463
+ * @param {string} replacement
464
+ */
465
+ const print_error = (property, replacement) => {
466
+ Object.defineProperty(result.props.page, property, {
467
+ get: () => {
468
+ throw new Error(`$page.${property} has been replaced by $page.url.${replacement}`);
469
+ }
470
+ });
471
+ };
472
+
473
+ print_error('origin', 'origin');
474
+ print_error('path', 'pathname');
475
+ print_error('query', 'searchParams');
476
+ }
477
+
478
+ return result;
479
+ }
480
+
481
+ /**
482
+ * Call the load function of the given node, if it exists.
483
+ * If `server_data` is passed, this is treated as the initial run and the page endpoint is not requested.
484
+ *
485
+ * @param {{
486
+ * loader: import('types').CSRPageNodeLoader;
487
+ * parent: () => Promise<Record<string, any>>;
488
+ * url: URL;
489
+ * params: Record<string, string>;
490
+ * routeId: string | null;
491
+ * server_data_node: import('./types').DataNode | null;
492
+ * }} options
493
+ * @returns {Promise<import('./types').BranchNode>}
494
+ */
495
+ async function load_node({ loader, parent, url, params, routeId, server_data_node }) {
496
+ /** @type {Record<string, any> | null} */
497
+ let data = null;
498
+
499
+ /** @type {import('types').Uses} */
500
+ const uses = {
501
+ dependencies: new Set(),
502
+ params: new Set(),
503
+ parent: false,
504
+ url: false
505
+ };
506
+
507
+ const node = await loader();
508
+
509
+ if (node.shared?.load) {
510
+ /** @param {string[]} deps */
511
+ function depends(...deps) {
512
+ for (const dep of deps) {
513
+ const { href } = new URL(dep, url);
514
+ uses.dependencies.add(href);
515
+ }
516
+ }
517
+
518
+ /** @type {Record<string, string>} */
519
+ const uses_params = {};
520
+ for (const key in params) {
521
+ Object.defineProperty(uses_params, key, {
522
+ get() {
523
+ uses.params.add(key);
524
+ return params[key];
525
+ },
526
+ enumerable: true
527
+ });
528
+ }
529
+
530
+ /** @type {import('types').LoadEvent} */
531
+ const load_input = {
532
+ routeId,
533
+ params: uses_params,
534
+ data: server_data_node?.data ?? null,
535
+ url: make_trackable(url, () => {
536
+ uses.url = true;
537
+ }),
538
+ async fetch(resource, init) {
539
+ let requested;
540
+
541
+ if (typeof resource === 'string') {
542
+ requested = resource;
543
+ } else {
544
+ requested = resource.url;
545
+
546
+ // we're not allowed to modify the received `Request` object, so in order
547
+ // to fixup relative urls we create a new equivalent `init` object instead
548
+ init = {
549
+ // the request body must be consumed in memory until browsers
550
+ // implement streaming request bodies and/or the body getter
551
+ body:
552
+ resource.method === 'GET' || resource.method === 'HEAD'
553
+ ? undefined
554
+ : await resource.blob(),
555
+ cache: resource.cache,
556
+ credentials: resource.credentials,
557
+ headers: resource.headers,
558
+ integrity: resource.integrity,
559
+ keepalive: resource.keepalive,
560
+ method: resource.method,
561
+ mode: resource.mode,
562
+ redirect: resource.redirect,
563
+ referrer: resource.referrer,
564
+ referrerPolicy: resource.referrerPolicy,
565
+ signal: resource.signal,
566
+ ...init
567
+ };
568
+ }
569
+
570
+ // we must fixup relative urls so they are resolved from the target page
571
+ const normalized = new URL(requested, url).href;
572
+ depends(normalized);
573
+
574
+ // prerendered pages may be served from any origin, so `initial_fetch` urls shouldn't be normalized
575
+ return started ? native_fetch(normalized, init) : initial_fetch(requested, init);
576
+ },
577
+ setHeaders: () => {}, // noop
578
+ depends,
579
+ parent() {
580
+ uses.parent = true;
581
+ return parent();
582
+ }
583
+ };
584
+
585
+ // TODO remove this for 1.0
586
+ Object.defineProperties(load_input, {
587
+ props: {
588
+ get() {
589
+ throw new Error(
590
+ '@migration task: Replace `props` with `data` stuff https://github.com/sveltejs/kit/discussions/5774#discussioncomment-3292693'
591
+ );
592
+ },
593
+ enumerable: false
594
+ },
595
+ session: {
596
+ get() {
597
+ throw new Error(
598
+ 'session is no longer available. See https://github.com/sveltejs/kit/discussions/5883'
599
+ );
600
+ },
601
+ enumerable: false
602
+ },
603
+ stuff: {
604
+ get() {
605
+ throw new Error(
606
+ '@migration task: Remove stuff https://github.com/sveltejs/kit/discussions/5774#discussioncomment-3292693'
607
+ );
608
+ },
609
+ enumerable: false
610
+ }
611
+ });
612
+
613
+ if (import.meta.env.DEV) {
614
+ try {
615
+ lock_fetch();
616
+ data = (await node.shared.load.call(null, load_input)) ?? null;
617
+ } finally {
618
+ unlock_fetch();
619
+ }
620
+ } else {
621
+ data = (await node.shared.load.call(null, load_input)) ?? null;
622
+ }
623
+ }
624
+
625
+ return {
626
+ node,
627
+ loader,
628
+ server: server_data_node,
629
+ shared: node.shared?.load ? { type: 'data', data, uses } : null,
630
+ data: data ?? server_data_node?.data ?? null
631
+ };
632
+ }
633
+
634
+ /**
635
+ * @param {import('types').Uses | undefined} uses
636
+ * @param {boolean} parent_changed
637
+ * @param {{ url: boolean, params: string[] }} changed
638
+ */
639
+ function has_changed(changed, parent_changed, uses) {
640
+ if (!uses) return false;
641
+
642
+ if (uses.parent && parent_changed) return true;
643
+ if (changed.url && uses.url) return true;
644
+
645
+ for (const param of changed.params) {
646
+ if (uses.params.has(param)) return true;
647
+ }
648
+
649
+ for (const dep of uses.dependencies) {
650
+ if (invalidated.some((fn) => fn(dep))) return true;
651
+ }
652
+
653
+ return false;
654
+ }
655
+
656
+ /**
657
+ * @param {import('types').ServerDataNode | import('types').ServerDataSkippedNode | null} node
658
+ * @param {import('./types').DataNode | null} [previous]
659
+ * @returns {import('./types').DataNode | null}
660
+ */
661
+ function create_data_node(node, previous) {
662
+ if (node?.type === 'data') {
663
+ return {
664
+ type: 'data',
665
+ data: node.data,
666
+ uses: {
667
+ dependencies: new Set(node.uses.dependencies ?? []),
668
+ params: new Set(node.uses.params ?? []),
669
+ parent: !!node.uses.parent,
670
+ url: !!node.uses.url
671
+ }
672
+ };
673
+ } else if (node?.type === 'skip') {
674
+ return previous ?? null;
675
+ }
676
+ return null;
677
+ }
678
+
679
+ /**
680
+ * @param {import('./types').NavigationIntent} intent
681
+ * @returns {Promise<import('./types').NavigationResult | undefined>}
682
+ */
683
+ async function load_route({ id, url, params, route }) {
684
+ if (load_cache.id === id && load_cache.promise) {
685
+ return load_cache.promise;
686
+ }
687
+
688
+ const { errors, layouts, leaf } = route;
689
+
690
+ const changed = current.url && {
691
+ url: id !== current.url.pathname + current.url.search,
692
+ params: Object.keys(params).filter((key) => current.params[key] !== params[key])
693
+ };
694
+
695
+ const loaders = [...layouts, leaf];
696
+
697
+ // preload modules to avoid waterfall, but handle rejections
698
+ // so they don't get reported to Sentry et al (we don't need
699
+ // to act on the failures at this point)
700
+ errors.forEach((loader) => loader?.().catch(() => {}));
701
+ loaders.forEach((loader) => loader?.[1]().catch(() => {}));
702
+
703
+ /** @type {import('types').ServerData | null} */
704
+ let server_data = null;
705
+
706
+ const invalid_server_nodes = loaders.reduce((acc, loader, i) => {
707
+ const previous = current.branch[i];
708
+ const invalid =
709
+ !!loader?.[0] &&
710
+ (previous?.loader !== loader[1] ||
711
+ has_changed(changed, acc.some(Boolean), previous.server?.uses));
712
+
713
+ acc.push(invalid);
714
+ return acc;
715
+ }, /** @type {boolean[]} */ ([]));
716
+
717
+ if (invalid_server_nodes.some(Boolean)) {
718
+ try {
719
+ server_data = await load_data(url, invalid_server_nodes);
720
+ } catch (error) {
721
+ return load_root_error_page({
722
+ status: 500,
723
+ error: /** @type {Error} */ (error),
724
+ url,
725
+ routeId: route.id
726
+ });
727
+ }
728
+
729
+ if (server_data.type === 'redirect') {
730
+ return server_data;
731
+ }
732
+ }
733
+
734
+ const server_data_nodes = server_data?.nodes;
735
+
736
+ let parent_changed = false;
737
+
738
+ const branch_promises = loaders.map(async (loader, i) => {
739
+ if (!loader) return;
740
+
741
+ /** @type {import('./types').BranchNode | undefined} */
742
+ const previous = current.branch[i];
743
+
744
+ const server_data_node = server_data_nodes?.[i] ?? null;
745
+
746
+ const can_reuse_server_data = !server_data_node || server_data_node.type === 'skip';
747
+ // re-use data from previous load if it's still valid
748
+ const valid =
749
+ can_reuse_server_data &&
750
+ loader[1] === previous?.loader &&
751
+ !has_changed(changed, parent_changed, previous.shared?.uses);
752
+ if (valid) return previous;
753
+
754
+ parent_changed = true;
755
+
756
+ if (server_data_node?.type === 'error') {
757
+ if (server_data_node.httperror) {
758
+ // reconstruct as an HttpError
759
+ throw error(server_data_node.httperror.status, server_data_node.httperror.message);
760
+ } else {
761
+ throw server_data_node.error;
762
+ }
763
+ }
764
+
765
+ return load_node({
766
+ loader: loader[1],
767
+ url,
768
+ params,
769
+ routeId: route.id,
770
+ parent: async () => {
771
+ const data = {};
772
+ for (let j = 0; j < i; j += 1) {
773
+ Object.assign(data, (await branch_promises[j])?.data);
774
+ }
775
+ return data;
776
+ },
777
+ server_data_node: create_data_node(server_data_node, previous?.server)
778
+ });
779
+ });
780
+
781
+ // if we don't do this, rejections will be unhandled
782
+ for (const p of branch_promises) p.catch(() => {});
783
+
784
+ /** @type {Array<import('./types').BranchNode | undefined>} */
785
+ const branch = [];
786
+
787
+ for (let i = 0; i < loaders.length; i += 1) {
788
+ if (loaders[i]) {
789
+ try {
790
+ branch.push(await branch_promises[i]);
791
+ } catch (e) {
792
+ const error = normalize_error(e);
793
+
794
+ if (error instanceof Redirect) {
795
+ return {
796
+ type: 'redirect',
797
+ location: error.location
798
+ };
799
+ }
800
+
801
+ const status = e instanceof HttpError ? e.status : 500;
802
+
803
+ while (i--) {
804
+ if (errors[i]) {
805
+ /** @type {import('./types').BranchNode | undefined} */
806
+ let error_loaded;
807
+
808
+ let j = i;
809
+ while (!branch[j]) j -= 1;
810
+ try {
811
+ error_loaded = {
812
+ node: await /** @type {import('types').CSRPageNodeLoader } */ (errors[i])(),
813
+ loader: /** @type {import('types').CSRPageNodeLoader } */ (errors[i]),
814
+ data: {},
815
+ server: null,
816
+ shared: null
817
+ };
818
+
819
+ return await get_navigation_result_from_branch({
820
+ url,
821
+ params,
822
+ branch: branch.slice(0, j + 1).concat(error_loaded),
823
+ status,
824
+ error,
825
+ routeId: route.id
826
+ });
827
+ } catch (e) {
828
+ continue;
829
+ }
830
+ }
831
+ }
832
+
833
+ // if we get here, it's because the root `load` function failed,
834
+ // and we need to fall back to the server
835
+ native_navigation(url);
836
+ return;
837
+ }
838
+ } else {
839
+ // push an empty slot so we can rewind past gaps to the
840
+ // layout that corresponds with an +error.svelte page
841
+ branch.push(undefined);
842
+ }
843
+ }
844
+
845
+ return await get_navigation_result_from_branch({
846
+ url,
847
+ params,
848
+ branch,
849
+ status: 200,
850
+ error: null,
851
+ routeId: route.id
852
+ });
853
+ }
854
+
855
+ /**
856
+ * @param {{
857
+ * status: number;
858
+ * error: HttpError | Error;
859
+ * url: URL;
860
+ * routeId: string | null
861
+ * }} opts
862
+ * @returns {Promise<import('./types').NavigationFinished>}
863
+ */
864
+ async function load_root_error_page({ status, error, url, routeId }) {
865
+ /** @type {Record<string, string>} */
866
+ const params = {}; // error page does not have params
867
+
868
+ const node = await default_layout_loader();
869
+
870
+ /** @type {import('types').ServerDataNode | null} */
871
+ let server_data_node = null;
872
+
873
+ if (node.server) {
874
+ // TODO post-https://github.com/sveltejs/kit/discussions/6124 we can use
875
+ // existing root layout data
876
+ try {
877
+ const server_data = await load_data(url, [true]);
878
+
879
+ if (
880
+ server_data.type !== 'data' ||
881
+ (server_data.nodes[0] && server_data.nodes[0].type !== 'data')
882
+ ) {
883
+ throw 0;
884
+ }
885
+
886
+ server_data_node = server_data.nodes[0] ?? null;
887
+ } catch {
888
+ // at this point we have no choice but to fall back to the server
889
+ native_navigation(url);
890
+
891
+ // @ts-expect-error
892
+ return;
893
+ }
894
+ }
895
+
896
+ const root_layout = await load_node({
897
+ loader: default_layout_loader,
898
+ url,
899
+ params,
900
+ routeId,
901
+ parent: () => Promise.resolve({}),
902
+ server_data_node: create_data_node(server_data_node)
903
+ });
904
+
905
+ /** @type {import('./types').BranchNode} */
906
+ const root_error = {
907
+ node: await default_error_loader(),
908
+ loader: default_error_loader,
909
+ shared: null,
910
+ server: null,
911
+ data: null
912
+ };
913
+
914
+ return await get_navigation_result_from_branch({
915
+ url,
916
+ params,
917
+ branch: [root_layout, root_error],
918
+ status,
919
+ error,
920
+ routeId
921
+ });
922
+ }
923
+
924
+ /** @param {URL} url */
925
+ function get_navigation_intent(url) {
926
+ if (url.origin !== location.origin || !url.pathname.startsWith(base)) return;
927
+
928
+ const path = decodeURI(url.pathname.slice(base.length) || '/');
929
+
930
+ for (const route of routes) {
931
+ const params = route.exec(path);
932
+
933
+ if (params) {
934
+ const normalized = new URL(
935
+ url.origin + normalize_path(url.pathname, trailing_slash) + url.search + url.hash
936
+ );
937
+ const id = normalized.pathname + normalized.search;
938
+ /** @type {import('./types').NavigationIntent} */
939
+ const intent = { id, route, params: decode_params(params), url: normalized };
940
+ return intent;
941
+ }
942
+ }
943
+ }
944
+
945
+ /**
946
+ * @param {{
947
+ * url: URL;
948
+ * scroll: { x: number, y: number } | null;
949
+ * keepfocus: boolean;
950
+ * redirect_chain: string[];
951
+ * details: {
952
+ * replaceState: boolean;
953
+ * state: any;
954
+ * } | null;
955
+ * accepted: () => void;
956
+ * blocked: () => void;
957
+ * }} opts
958
+ */
959
+ async function navigate({ url, scroll, keepfocus, redirect_chain, details, accepted, blocked }) {
960
+ const from = current.url;
961
+ let should_block = false;
962
+
963
+ const navigation = {
964
+ from,
965
+ to: url,
966
+ cancel: () => (should_block = true)
967
+ };
968
+
969
+ callbacks.before_navigate.forEach((fn) => fn(navigation));
970
+
971
+ if (should_block) {
972
+ blocked();
973
+ return;
974
+ }
975
+
976
+ update_scroll_positions(current_history_index);
977
+
978
+ accepted();
979
+
980
+ if (started) {
981
+ stores.navigating.set({
982
+ from: current.url,
983
+ to: url
984
+ });
985
+ }
986
+
987
+ await update(
988
+ url,
989
+ redirect_chain,
990
+ {
991
+ scroll,
992
+ keepfocus,
993
+ details
994
+ },
995
+ () => {
996
+ const navigation = { from, to: url };
997
+ callbacks.after_navigate.forEach((fn) => fn(navigation));
998
+
999
+ stores.navigating.set(null);
1000
+ }
1001
+ );
1002
+ }
1003
+
1004
+ /**
1005
+ * Loads `href` the old-fashioned way, with a full page reload.
1006
+ * Returns a `Promise` that never resolves (to prevent any
1007
+ * subsequent work, e.g. history manipulation, from happening)
1008
+ * @param {URL} url
1009
+ */
1010
+ function native_navigation(url) {
1011
+ location.href = url.href;
1012
+ return new Promise(() => {});
1013
+ }
1014
+
1015
+ if (import.meta.hot) {
1016
+ import.meta.hot.on('vite:beforeUpdate', () => {
1017
+ if (current.error) location.reload();
1018
+ });
1019
+ }
1020
+
1021
+ return {
1022
+ after_navigate: (fn) => {
1023
+ onMount(() => {
1024
+ callbacks.after_navigate.push(fn);
1025
+
1026
+ return () => {
1027
+ const i = callbacks.after_navigate.indexOf(fn);
1028
+ callbacks.after_navigate.splice(i, 1);
1029
+ };
1030
+ });
1031
+ },
1032
+
1033
+ before_navigate: (fn) => {
1034
+ onMount(() => {
1035
+ callbacks.before_navigate.push(fn);
1036
+
1037
+ return () => {
1038
+ const i = callbacks.before_navigate.indexOf(fn);
1039
+ callbacks.before_navigate.splice(i, 1);
1040
+ };
1041
+ });
1042
+ },
1043
+
1044
+ disable_scroll_handling: () => {
1045
+ if (import.meta.env.DEV && started && !updating) {
1046
+ throw new Error('Can only disable scroll handling during navigation');
1047
+ }
1048
+
1049
+ if (updating || !started) {
1050
+ autoscroll = false;
1051
+ }
1052
+ },
1053
+
1054
+ goto: (href, opts = {}) => goto(href, opts, []),
1055
+
1056
+ invalidate: (resource) => {
1057
+ if (resource === undefined) {
1058
+ // Force rerun of all load functions, regardless of their dependencies
1059
+ for (const node of current.branch) {
1060
+ node?.server?.uses.dependencies.add('');
1061
+ node?.shared?.uses.dependencies.add('');
1062
+ }
1063
+ invalidated.push(() => true);
1064
+ } else if (typeof resource === 'function') {
1065
+ invalidated.push(resource);
1066
+ } else {
1067
+ const { href } = new URL(resource, location.href);
1068
+ invalidated.push((dep) => dep === href);
1069
+ }
1070
+
1071
+ if (!invalidating) {
1072
+ invalidating = Promise.resolve().then(async () => {
1073
+ await update(new URL(location.href), []);
1074
+
1075
+ invalidating = null;
1076
+ });
1077
+ }
1078
+
1079
+ return invalidating;
1080
+ },
1081
+
1082
+ prefetch: async (href) => {
1083
+ const url = new URL(href, get_base_uri(document));
1084
+ await prefetch(url);
1085
+ },
1086
+
1087
+ // TODO rethink this API
1088
+ prefetch_routes: async (pathnames) => {
1089
+ const matching = pathnames
1090
+ ? routes.filter((route) => pathnames.some((pathname) => route.exec(pathname)))
1091
+ : routes;
1092
+
1093
+ const promises = matching.map((r) => {
1094
+ return Promise.all([...r.layouts, r.leaf].map((load) => load?.[1]()));
1095
+ });
1096
+
1097
+ await Promise.all(promises);
1098
+ },
1099
+
1100
+ _start_router: () => {
1101
+ history.scrollRestoration = 'manual';
1102
+
1103
+ // Adopted from Nuxt.js
1104
+ // Reset scrollRestoration to auto when leaving page, allowing page reload
1105
+ // and back-navigation from other pages to use the browser to restore the
1106
+ // scrolling position.
1107
+ addEventListener('beforeunload', (e) => {
1108
+ let should_block = false;
1109
+
1110
+ const navigation = {
1111
+ from: current.url,
1112
+ to: null,
1113
+ cancel: () => (should_block = true)
1114
+ };
1115
+
1116
+ callbacks.before_navigate.forEach((fn) => fn(navigation));
1117
+
1118
+ if (should_block) {
1119
+ e.preventDefault();
1120
+ e.returnValue = '';
1121
+ } else {
1122
+ history.scrollRestoration = 'auto';
1123
+ }
1124
+ });
1125
+
1126
+ addEventListener('visibilitychange', () => {
1127
+ if (document.visibilityState === 'hidden') {
1128
+ update_scroll_positions(current_history_index);
1129
+
1130
+ try {
1131
+ sessionStorage[SCROLL_KEY] = JSON.stringify(scroll_positions);
1132
+ } catch {
1133
+ // do nothing
1134
+ }
1135
+ }
1136
+ });
1137
+
1138
+ /** @param {Event} event */
1139
+ const trigger_prefetch = (event) => {
1140
+ const a = find_anchor(event);
1141
+ if (a && a.href && a.hasAttribute('sveltekit:prefetch')) {
1142
+ prefetch(get_href(a));
1143
+ }
1144
+ };
1145
+
1146
+ /** @type {NodeJS.Timeout} */
1147
+ let mousemove_timeout;
1148
+
1149
+ /** @param {MouseEvent|TouchEvent} event */
1150
+ const handle_mousemove = (event) => {
1151
+ clearTimeout(mousemove_timeout);
1152
+ mousemove_timeout = setTimeout(() => {
1153
+ // event.composedPath(), which is used in find_anchor, will be empty if the event is read in a timeout
1154
+ // add a layer of indirection to address that
1155
+ event.target?.dispatchEvent(
1156
+ new CustomEvent('sveltekit:trigger_prefetch', { bubbles: true })
1157
+ );
1158
+ }, 20);
1159
+ };
1160
+
1161
+ addEventListener('touchstart', trigger_prefetch);
1162
+ addEventListener('mousemove', handle_mousemove);
1163
+ addEventListener('sveltekit:trigger_prefetch', trigger_prefetch);
1164
+
1165
+ /** @param {MouseEvent} event */
1166
+ addEventListener('click', (event) => {
1167
+ if (!router_enabled) return;
1168
+
1169
+ // Adapted from https://github.com/visionmedia/page.js
1170
+ // MIT license https://github.com/visionmedia/page.js#license
1171
+ if (event.button || event.which !== 1) return;
1172
+ if (event.metaKey || event.ctrlKey || event.shiftKey || event.altKey) return;
1173
+ if (event.defaultPrevented) return;
1174
+
1175
+ const a = find_anchor(event);
1176
+ if (!a) return;
1177
+
1178
+ if (!a.href) return;
1179
+
1180
+ const is_svg_a_element = a instanceof SVGAElement;
1181
+ const url = get_href(a);
1182
+
1183
+ // Ignore non-HTTP URL protocols (e.g. `mailto:`, `tel:`, `myapp:`, etc.)
1184
+ // MEMO: Without this condition, firefox will open mailer twice.
1185
+ // See:
1186
+ // - https://github.com/sveltejs/kit/issues/4045
1187
+ // - https://github.com/sveltejs/kit/issues/5725
1188
+ if (!is_svg_a_element && !(url.protocol === 'https:' || url.protocol === 'http:')) return;
1189
+
1190
+ // Ignore if tag has
1191
+ // 1. 'download' attribute
1192
+ // 2. 'rel' attribute includes external
1193
+ const rel = (a.getAttribute('rel') || '').split(/\s+/);
1194
+
1195
+ if (
1196
+ a.hasAttribute('download') ||
1197
+ rel.includes('external') ||
1198
+ a.hasAttribute('sveltekit:reload')
1199
+ ) {
1200
+ return;
1201
+ }
1202
+
1203
+ // Ignore if <a> has a target
1204
+ if (is_svg_a_element ? a.target.baseVal : a.target) return;
1205
+
1206
+ // Check if new url only differs by hash and use the browser default behavior in that case
1207
+ // This will ensure the `hashchange` event is fired
1208
+ // Removing the hash does a full page navigation in the browser, so make sure a hash is present
1209
+ const [base, hash] = url.href.split('#');
1210
+ if (hash !== undefined && base === location.href.split('#')[0]) {
1211
+ // set this flag to distinguish between navigations triggered by
1212
+ // clicking a hash link and those triggered by popstate
1213
+ hash_navigating = true;
1214
+
1215
+ update_scroll_positions(current_history_index);
1216
+
1217
+ stores.page.set({ ...page, url });
1218
+ stores.page.notify();
1219
+
1220
+ return;
1221
+ }
1222
+
1223
+ navigate({
1224
+ url,
1225
+ scroll: a.hasAttribute('sveltekit:noscroll') ? scroll_state() : null,
1226
+ keepfocus: false,
1227
+ redirect_chain: [],
1228
+ details: {
1229
+ state: {},
1230
+ replaceState: url.href === location.href
1231
+ },
1232
+ accepted: () => event.preventDefault(),
1233
+ blocked: () => event.preventDefault()
1234
+ });
1235
+ });
1236
+
1237
+ addEventListener('popstate', (event) => {
1238
+ if (event.state && router_enabled) {
1239
+ // if a popstate-driven navigation is cancelled, we need to counteract it
1240
+ // with history.go, which means we end up back here, hence this check
1241
+ if (event.state[INDEX_KEY] === current_history_index) return;
1242
+
1243
+ navigate({
1244
+ url: new URL(location.href),
1245
+ scroll: scroll_positions[event.state[INDEX_KEY]],
1246
+ keepfocus: false,
1247
+ redirect_chain: [],
1248
+ details: null,
1249
+ accepted: () => {
1250
+ current_history_index = event.state[INDEX_KEY];
1251
+ },
1252
+ blocked: () => {
1253
+ const delta = current_history_index - event.state[INDEX_KEY];
1254
+ history.go(delta);
1255
+ }
1256
+ });
1257
+ }
1258
+ });
1259
+
1260
+ addEventListener('hashchange', () => {
1261
+ // if the hashchange happened as a result of clicking on a link,
1262
+ // we need to update history, otherwise we have to leave it alone
1263
+ if (hash_navigating) {
1264
+ hash_navigating = false;
1265
+ history.replaceState(
1266
+ { ...history.state, [INDEX_KEY]: ++current_history_index },
1267
+ '',
1268
+ location.href
1269
+ );
1270
+ }
1271
+ });
1272
+
1273
+ // fix link[rel=icon], because browsers will occasionally try to load relative
1274
+ // URLs after a pushState/replaceState, resulting in a 404 — see
1275
+ // https://github.com/sveltejs/kit/issues/3748#issuecomment-1125980897
1276
+ for (const link of document.querySelectorAll('link')) {
1277
+ if (link.rel === 'icon') link.href = link.href;
1278
+ }
1279
+
1280
+ addEventListener('pageshow', (event) => {
1281
+ // If the user navigates to another site and then uses the back button and
1282
+ // bfcache hits, we need to set navigating to null, the site doesn't know
1283
+ // the navigation away from it was successful.
1284
+ // Info about bfcache here: https://web.dev/bfcache
1285
+ if (event.persisted) {
1286
+ stores.navigating.set(null);
1287
+ }
1288
+ });
1289
+ },
1290
+
1291
+ _hydrate: async ({
1292
+ status,
1293
+ error: original_error, // TODO get rid of this
1294
+ node_ids,
1295
+ params,
1296
+ routeId,
1297
+ data: server_data_nodes,
1298
+ errors: validation_errors
1299
+ }) => {
1300
+ const url = new URL(location.href);
1301
+
1302
+ /** @type {import('./types').NavigationFinished | undefined} */
1303
+ let result;
1304
+
1305
+ try {
1306
+ const branch_promises = node_ids.map(async (n, i) => {
1307
+ const server_data_node = server_data_nodes[i];
1308
+
1309
+ return load_node({
1310
+ loader: nodes[n],
1311
+ url,
1312
+ params,
1313
+ routeId,
1314
+ parent: async () => {
1315
+ const data = {};
1316
+ for (let j = 0; j < i; j += 1) {
1317
+ Object.assign(data, (await branch_promises[j]).data);
1318
+ }
1319
+ return data;
1320
+ },
1321
+ server_data_node: create_data_node(server_data_node)
1322
+ });
1323
+ });
1324
+
1325
+ result = await get_navigation_result_from_branch({
1326
+ url,
1327
+ params,
1328
+ branch: await Promise.all(branch_promises),
1329
+ status,
1330
+ error: /** @type {import('../server/page/types').SerializedHttpError} */ (original_error)
1331
+ ?.__is_http_error
1332
+ ? new HttpError(
1333
+ /** @type {import('../server/page/types').SerializedHttpError} */ (
1334
+ original_error
1335
+ ).status,
1336
+ original_error.message
1337
+ )
1338
+ : original_error,
1339
+ validation_errors,
1340
+ routeId
1341
+ });
1342
+ } catch (e) {
1343
+ const error = normalize_error(e);
1344
+
1345
+ if (error instanceof Redirect) {
1346
+ // this is a real edge case — `load` would need to return
1347
+ // a redirect but only in the browser
1348
+ await native_navigation(new URL(/** @type {Redirect} */ (e).location, location.href));
1349
+ return;
1350
+ }
1351
+
1352
+ result = await load_root_error_page({
1353
+ status: error instanceof HttpError ? error.status : 500,
1354
+ error,
1355
+ url,
1356
+ routeId
1357
+ });
1358
+ }
1359
+
1360
+ initialize(result);
1361
+ }
1362
+ };
1363
+ }
1364
+
1365
+ let data_id = 1;
1366
+
1367
+ /**
1368
+ * @param {URL} url
1369
+ * @param {boolean[]} invalid
1370
+ * @returns {Promise<import('types').ServerData>}
1371
+ */
1372
+ async function load_data(url, invalid) {
1373
+ const data_url = new URL(url);
1374
+ data_url.pathname = url.pathname.replace(/\/$/, '') + DATA_SUFFIX;
1375
+ data_url.searchParams.set('__invalid', invalid.map((x) => (x ? 'y' : 'n')).join(''));
1376
+ data_url.searchParams.set('__id', String(data_id++));
1377
+
1378
+ // The __data.js file is generated by the server and looks like
1379
+ // `window.__sveltekit_data = ${devalue(data)}`. We do this instead
1380
+ // of `export const data` because modules are cached indefinitely,
1381
+ // and that would cause memory leaks.
1382
+ //
1383
+ // The data is read and deleted in the same tick as the promise
1384
+ // resolves, so it's not vulnerable to race conditions
1385
+ await import(/* @vite-ignore */ data_url.href);
1386
+
1387
+ // @ts-expect-error
1388
+ const server_data = window.__sveltekit_data;
1389
+
1390
+ // @ts-expect-error
1391
+ delete window.__sveltekit_data;
1392
+
1393
+ return server_data;
1394
+ }