@tanstack/router-core 0.0.1-beta.19 → 0.0.1-beta.190

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 (82) hide show
  1. package/LICENSE +21 -0
  2. package/build/cjs/defer.js +39 -0
  3. package/build/cjs/defer.js.map +1 -0
  4. package/build/cjs/fileRoute.js +29 -0
  5. package/build/cjs/fileRoute.js.map +1 -0
  6. package/build/cjs/history.js +228 -0
  7. package/build/cjs/history.js.map +1 -0
  8. package/build/cjs/index.js +86 -0
  9. package/build/cjs/{packages/router-core/src/index.js.map → index.js.map} +1 -1
  10. package/build/cjs/{packages/router-core/src/path.js → path.js} +45 -56
  11. package/build/cjs/path.js.map +1 -0
  12. package/build/cjs/{packages/router-core/src/qss.js → qss.js} +10 -16
  13. package/build/cjs/qss.js.map +1 -0
  14. package/build/cjs/route.js +114 -0
  15. package/build/cjs/route.js.map +1 -0
  16. package/build/cjs/router.js +1267 -0
  17. package/build/cjs/router.js.map +1 -0
  18. package/build/cjs/scroll-restoration.js +139 -0
  19. package/build/cjs/scroll-restoration.js.map +1 -0
  20. package/build/cjs/{packages/router-core/src/searchParams.js → searchParams.js} +32 -19
  21. package/build/cjs/searchParams.js.map +1 -0
  22. package/build/cjs/{packages/router-core/src/utils.js → utils.js} +69 -64
  23. package/build/cjs/utils.js.map +1 -0
  24. package/build/esm/index.js +1746 -2121
  25. package/build/esm/index.js.map +1 -1
  26. package/build/stats-html.html +59 -49
  27. package/build/stats-react.json +197 -211
  28. package/build/types/defer.d.ts +19 -0
  29. package/build/types/fileRoute.d.ts +35 -0
  30. package/build/types/history.d.ts +36 -0
  31. package/build/types/index.d.ts +13 -609
  32. package/build/types/link.d.ts +96 -0
  33. package/build/types/path.d.ts +16 -0
  34. package/build/types/qss.d.ts +2 -0
  35. package/build/types/route.d.ts +251 -0
  36. package/build/types/routeInfo.d.ts +22 -0
  37. package/build/types/router.d.ts +260 -0
  38. package/build/types/scroll-restoration.d.ts +6 -0
  39. package/build/types/searchParams.d.ts +5 -0
  40. package/build/types/utils.d.ts +44 -0
  41. package/build/umd/index.development.js +1978 -2243
  42. package/build/umd/index.development.js.map +1 -1
  43. package/build/umd/index.production.js +13 -2
  44. package/build/umd/index.production.js.map +1 -1
  45. package/package.json +11 -7
  46. package/src/defer.ts +55 -0
  47. package/src/fileRoute.ts +161 -0
  48. package/src/history.ts +300 -0
  49. package/src/index.ts +5 -10
  50. package/src/link.ts +136 -125
  51. package/src/path.ts +37 -17
  52. package/src/qss.ts +1 -2
  53. package/src/route.ts +948 -218
  54. package/src/routeInfo.ts +45 -211
  55. package/src/router.ts +1778 -1075
  56. package/src/scroll-restoration.ts +179 -0
  57. package/src/searchParams.ts +31 -9
  58. package/src/utils.ts +84 -49
  59. package/build/cjs/_virtual/_rollupPluginBabelHelpers.js +0 -33
  60. package/build/cjs/_virtual/_rollupPluginBabelHelpers.js.map +0 -1
  61. package/build/cjs/node_modules/@babel/runtime/helpers/esm/extends.js +0 -33
  62. package/build/cjs/node_modules/@babel/runtime/helpers/esm/extends.js.map +0 -1
  63. package/build/cjs/node_modules/history/index.js +0 -815
  64. package/build/cjs/node_modules/history/index.js.map +0 -1
  65. package/build/cjs/node_modules/tiny-invariant/dist/esm/tiny-invariant.js +0 -30
  66. package/build/cjs/node_modules/tiny-invariant/dist/esm/tiny-invariant.js.map +0 -1
  67. package/build/cjs/packages/router-core/src/index.js +0 -58
  68. package/build/cjs/packages/router-core/src/path.js.map +0 -1
  69. package/build/cjs/packages/router-core/src/qss.js.map +0 -1
  70. package/build/cjs/packages/router-core/src/route.js +0 -147
  71. package/build/cjs/packages/router-core/src/route.js.map +0 -1
  72. package/build/cjs/packages/router-core/src/routeConfig.js +0 -69
  73. package/build/cjs/packages/router-core/src/routeConfig.js.map +0 -1
  74. package/build/cjs/packages/router-core/src/routeMatch.js +0 -220
  75. package/build/cjs/packages/router-core/src/routeMatch.js.map +0 -1
  76. package/build/cjs/packages/router-core/src/router.js +0 -870
  77. package/build/cjs/packages/router-core/src/router.js.map +0 -1
  78. package/build/cjs/packages/router-core/src/searchParams.js.map +0 -1
  79. package/build/cjs/packages/router-core/src/utils.js.map +0 -1
  80. package/src/frameworks.ts +0 -11
  81. package/src/routeConfig.ts +0 -511
  82. package/src/routeMatch.ts +0 -312
@@ -1,5 +1,5 @@
1
1
  /**
2
- * router-core
2
+ * @tanstack/router-core/src/index.ts
3
3
  *
4
4
  * Copyright (c) TanStack
5
5
  *
@@ -9,2280 +9,1575 @@
9
9
  * @license MIT
10
10
  */
11
11
  (function (global, factory) {
12
- typeof exports === 'object' && typeof module !== 'undefined' ? factory(exports) :
13
- typeof define === 'function' && define.amd ? define(['exports'], factory) :
14
- (global = typeof globalThis !== 'undefined' ? globalThis : global || self, factory(global.RouterCore = {}));
12
+ typeof exports === 'object' && typeof module !== 'undefined' ? factory(exports) :
13
+ typeof define === 'function' && define.amd ? define(['exports'], factory) :
14
+ (global = typeof globalThis !== 'undefined' ? globalThis : global || self, factory(global.RouterCore = {}));
15
15
  })(this, (function (exports) { 'use strict';
16
16
 
17
- function _extends$1() {
18
- _extends$1 = Object.assign ? Object.assign.bind() : function (target) {
19
- for (var i = 1; i < arguments.length; i++) {
20
- var source = arguments[i];
21
-
22
- for (var key in source) {
23
- if (Object.prototype.hasOwnProperty.call(source, key)) {
24
- target[key] = source[key];
25
- }
17
+ var prefix = 'Invariant failed';
18
+ function invariant(condition, message) {
19
+ if (condition) {
20
+ return;
26
21
  }
27
- }
28
-
29
- return target;
30
- };
31
- return _extends$1.apply(this, arguments);
32
- }
33
-
34
- /**
35
- * Actions represent the type of change to a location value.
36
- *
37
- * @see https://github.com/remix-run/history/tree/main/docs/api-reference.md#action
38
- */
39
- var Action;
40
-
41
- (function (Action) {
42
- /**
43
- * A POP indicates a change to an arbitrary index in the history stack, such
44
- * as a back or forward navigation. It does not describe the direction of the
45
- * navigation, only that the current index changed.
46
- *
47
- * Note: This is the default action for newly created history objects.
48
- */
49
- Action["Pop"] = "POP";
50
- /**
51
- * A PUSH indicates a new entry being added to the history stack, such as when
52
- * a link is clicked and a new page loads. When this happens, all subsequent
53
- * entries in the stack are lost.
54
- */
55
-
56
- Action["Push"] = "PUSH";
57
- /**
58
- * A REPLACE indicates the entry at the current index in the history stack
59
- * being replaced by a new one.
60
- */
61
-
62
- Action["Replace"] = "REPLACE";
63
- })(Action || (Action = {}));
64
-
65
- var readOnly = function (obj) {
66
- return Object.freeze(obj);
67
- } ;
68
-
69
- function warning$1(cond, message) {
70
- if (!cond) {
71
- // eslint-disable-next-line no-console
72
- if (typeof console !== 'undefined') console.warn(message);
73
-
74
- try {
75
- // Welcome to debugging history!
76
- //
77
- // This error is thrown as a convenience so you can more easily
78
- // find the source for a warning that appears in the console by
79
- // enabling "pause on exceptions" in your JavaScript debugger.
80
- throw new Error(message); // eslint-disable-next-line no-empty
81
- } catch (e) {}
82
- }
83
- }
84
-
85
- var BeforeUnloadEventType = 'beforeunload';
86
- var HashChangeEventType = 'hashchange';
87
- var PopStateEventType = 'popstate';
88
- /**
89
- * Browser history stores the location in regular URLs. This is the standard for
90
- * most web apps, but it requires some configuration on the server to ensure you
91
- * serve the same app at multiple URLs.
92
- *
93
- * @see https://github.com/remix-run/history/tree/main/docs/api-reference.md#createbrowserhistory
94
- */
95
-
96
- function createBrowserHistory(options) {
97
- if (options === void 0) {
98
- options = {};
22
+ var provided = typeof message === 'function' ? message() : message;
23
+ var value = provided ? "".concat(prefix, ": ").concat(provided) : prefix;
24
+ throw new Error(value);
99
25
  }
100
26
 
101
- var _options = options,
102
- _options$window = _options.window,
103
- window = _options$window === void 0 ? document.defaultView : _options$window;
104
- var globalHistory = window.history;
105
-
106
- function getIndexAndLocation() {
107
- var _window$location = window.location,
108
- pathname = _window$location.pathname,
109
- search = _window$location.search,
110
- hash = _window$location.hash;
111
- var state = globalHistory.state || {};
112
- return [state.idx, readOnly({
113
- pathname: pathname,
114
- search: search,
115
- hash: hash,
116
- state: state.usr || null,
117
- key: state.key || 'default'
118
- })];
119
- }
27
+ function warning(condition, message) {
28
+ {
29
+ if (condition) {
30
+ return;
31
+ }
120
32
 
121
- var blockedPopTx = null;
33
+ var text = "Warning: " + message;
122
34
 
123
- function handlePop() {
124
- if (blockedPopTx) {
125
- blockers.call(blockedPopTx);
126
- blockedPopTx = null;
127
- } else {
128
- var nextAction = Action.Pop;
35
+ if (typeof console !== 'undefined') {
36
+ console.warn(text);
37
+ }
129
38
 
130
- var _getIndexAndLocation = getIndexAndLocation(),
131
- nextIndex = _getIndexAndLocation[0],
132
- nextLocation = _getIndexAndLocation[1];
39
+ try {
40
+ throw Error(text);
41
+ } catch (x) {}
42
+ }
43
+ }
133
44
 
45
+ // While the public API was clearly inspired by the "history" npm package,
46
+ // This implementation attempts to be more lightweight by
47
+ // making assumptions about the way TanStack Router works
48
+
49
+ const pushStateEvent = 'pushstate';
50
+ const popStateEvent = 'popstate';
51
+ const beforeUnloadEvent = 'beforeunload';
52
+ const beforeUnloadListener = event => {
53
+ event.preventDefault();
54
+ // @ts-ignore
55
+ return event.returnValue = '';
56
+ };
57
+ const stopBlocking = () => {
58
+ removeEventListener(beforeUnloadEvent, beforeUnloadListener, {
59
+ capture: true
60
+ });
61
+ };
62
+ function createHistory(opts) {
63
+ let location = opts.getLocation();
64
+ let unsub = () => {};
65
+ let subscribers = new Set();
66
+ let blockers = [];
67
+ let queue = [];
68
+ const tryFlush = () => {
134
69
  if (blockers.length) {
135
- if (nextIndex != null) {
136
- var delta = index - nextIndex;
137
-
138
- if (delta) {
139
- // Revert the POP
140
- blockedPopTx = {
141
- action: nextAction,
142
- location: nextLocation,
143
- retry: function retry() {
144
- go(delta * -1);
145
- }
146
- };
147
- go(delta);
70
+ blockers[0]?.(tryFlush, () => {
71
+ blockers = [];
72
+ stopBlocking();
73
+ });
74
+ return;
75
+ }
76
+ while (queue.length) {
77
+ queue.shift()?.();
78
+ }
79
+ if (!opts.subscriber) {
80
+ onUpdate();
81
+ }
82
+ };
83
+ const queueTask = task => {
84
+ queue.push(task);
85
+ tryFlush();
86
+ };
87
+ const onUpdate = () => {
88
+ location = opts.getLocation();
89
+ subscribers.forEach(subscriber => subscriber());
90
+ };
91
+ return {
92
+ get location() {
93
+ return location;
94
+ },
95
+ subscribe: cb => {
96
+ if (subscribers.size === 0) {
97
+ unsub = typeof opts.subscriber === 'function' ? opts.subscriber(onUpdate) : () => {};
98
+ }
99
+ subscribers.add(cb);
100
+ return () => {
101
+ subscribers.delete(cb);
102
+ if (subscribers.size === 0) {
103
+ unsub();
148
104
  }
149
- } else {
150
- // Trying to POP to a location with no index. We did not create
151
- // this location, so we can't effectively block the navigation.
152
- warning$1(false, // TODO: Write up a doc that explains our blocking strategy in
153
- // detail and link to it here so people can understand better what
154
- // is going on and how to avoid it.
155
- "You are trying to block a POP navigation to a location that was not " + "created by the history library. The block will fail silently in " + "production, but in general you should do all navigation with the " + "history library (instead of using window.history.pushState directly) " + "to avoid this situation.") ;
105
+ };
106
+ },
107
+ push: (path, state) => {
108
+ assignKey(state);
109
+ queueTask(() => {
110
+ opts.pushState(path, state);
111
+ });
112
+ },
113
+ replace: (path, state) => {
114
+ assignKey(state);
115
+ queueTask(() => {
116
+ opts.replaceState(path, state);
117
+ });
118
+ },
119
+ go: index => {
120
+ queueTask(() => {
121
+ opts.go(index);
122
+ });
123
+ },
124
+ back: () => {
125
+ queueTask(() => {
126
+ opts.back();
127
+ });
128
+ },
129
+ forward: () => {
130
+ queueTask(() => {
131
+ opts.forward();
132
+ });
133
+ },
134
+ createHref: str => opts.createHref(str),
135
+ block: cb => {
136
+ blockers.push(cb);
137
+ if (blockers.length === 1) {
138
+ addEventListener(beforeUnloadEvent, beforeUnloadListener, {
139
+ capture: true
140
+ });
156
141
  }
157
- } else {
158
- applyTx(nextAction);
142
+ return () => {
143
+ blockers = blockers.filter(b => b !== cb);
144
+ if (!blockers.length) {
145
+ stopBlocking();
146
+ }
147
+ };
159
148
  }
160
- }
161
- }
162
-
163
- window.addEventListener(PopStateEventType, handlePop);
164
- var action = Action.Pop;
165
-
166
- var _getIndexAndLocation2 = getIndexAndLocation(),
167
- index = _getIndexAndLocation2[0],
168
- location = _getIndexAndLocation2[1];
169
-
170
- var listeners = createEvents();
171
- var blockers = createEvents();
172
-
173
- if (index == null) {
174
- index = 0;
175
- globalHistory.replaceState(_extends$1({}, globalHistory.state, {
176
- idx: index
177
- }), '');
149
+ };
178
150
  }
179
-
180
- function createHref(to) {
181
- return typeof to === 'string' ? to : createPath(to);
182
- } // state defaults to `null` because `window.history.state` does
183
-
184
-
185
- function getNextLocation(to, state) {
186
- if (state === void 0) {
187
- state = null;
188
- }
189
-
190
- return readOnly(_extends$1({
191
- pathname: location.pathname,
192
- hash: '',
193
- search: ''
194
- }, typeof to === 'string' ? parsePath(to) : to, {
195
- state: state,
196
- key: createKey()
197
- }));
151
+ function assignKey(state) {
152
+ state.key = createRandomKey();
153
+ // if (state.__actualLocation) {
154
+ // state.__actualLocation.state = {
155
+ // ...state.__actualLocation.state,
156
+ // key,
157
+ // }
158
+ // }
198
159
  }
199
160
 
200
- function getHistoryStateAndUrl(nextLocation, index) {
201
- return [{
202
- usr: nextLocation.state,
203
- key: nextLocation.key,
204
- idx: index
205
- }, createHref(nextLocation)];
161
+ function createBrowserHistory(opts) {
162
+ const getHref = opts?.getHref ?? (() => `${window.location.pathname}${window.location.search}${window.location.hash}`);
163
+ const createHref = opts?.createHref ?? (path => path);
164
+ const getLocation = () => parseLocation(getHref(), window.history.state);
165
+ return createHistory({
166
+ getLocation,
167
+ subscriber: onUpdate => {
168
+ window.addEventListener(pushStateEvent, onUpdate);
169
+ window.addEventListener(popStateEvent, onUpdate);
170
+ var pushState = window.history.pushState;
171
+ window.history.pushState = function () {
172
+ let res = pushState.apply(history, arguments);
173
+ onUpdate();
174
+ return res;
175
+ };
176
+ var replaceState = window.history.replaceState;
177
+ window.history.replaceState = function () {
178
+ let res = replaceState.apply(history, arguments);
179
+ onUpdate();
180
+ return res;
181
+ };
182
+ return () => {
183
+ window.history.pushState = pushState;
184
+ window.history.replaceState = replaceState;
185
+ window.removeEventListener(pushStateEvent, onUpdate);
186
+ window.removeEventListener(popStateEvent, onUpdate);
187
+ };
188
+ },
189
+ pushState: (path, state) => {
190
+ window.history.pushState(state, '', createHref(path));
191
+ },
192
+ replaceState: (path, state) => {
193
+ window.history.replaceState(state, '', createHref(path));
194
+ },
195
+ back: () => window.history.back(),
196
+ forward: () => window.history.forward(),
197
+ go: n => window.history.go(n),
198
+ createHref: path => createHref(path)
199
+ });
206
200
  }
207
-
208
- function allowTx(action, location, retry) {
209
- return !blockers.length || (blockers.call({
210
- action: action,
211
- location: location,
212
- retry: retry
213
- }), false);
201
+ function createHashHistory() {
202
+ return createBrowserHistory({
203
+ getHref: () => window.location.hash.substring(1),
204
+ createHref: path => `#${path}`
205
+ });
214
206
  }
215
-
216
- function applyTx(nextAction) {
217
- action = nextAction;
218
-
219
- var _getIndexAndLocation3 = getIndexAndLocation();
220
-
221
- index = _getIndexAndLocation3[0];
222
- location = _getIndexAndLocation3[1];
223
- listeners.call({
224
- action: action,
225
- location: location
207
+ function createMemoryHistory(opts = {
208
+ initialEntries: ['/']
209
+ }) {
210
+ const entries = opts.initialEntries;
211
+ let index = opts.initialIndex ?? entries.length - 1;
212
+ let currentState = {
213
+ key: createRandomKey()
214
+ };
215
+ const getLocation = () => parseLocation(entries[index], currentState);
216
+ return createHistory({
217
+ getLocation,
218
+ subscriber: false,
219
+ pushState: (path, state) => {
220
+ currentState = state;
221
+ entries.push(path);
222
+ index++;
223
+ },
224
+ replaceState: (path, state) => {
225
+ currentState = state;
226
+ entries[index] = path;
227
+ },
228
+ back: () => {
229
+ index--;
230
+ },
231
+ forward: () => {
232
+ index = Math.min(index + 1, entries.length - 1);
233
+ },
234
+ go: n => window.history.go(n),
235
+ createHref: path => path
226
236
  });
227
237
  }
228
-
229
- function push(to, state) {
230
- var nextAction = Action.Push;
231
- var nextLocation = getNextLocation(to, state);
232
-
233
- function retry() {
234
- push(to, state);
235
- }
236
-
237
- if (allowTx(nextAction, nextLocation, retry)) {
238
- var _getHistoryStateAndUr = getHistoryStateAndUrl(nextLocation, index + 1),
239
- historyState = _getHistoryStateAndUr[0],
240
- url = _getHistoryStateAndUr[1]; // TODO: Support forced reloading
241
- // try...catch because iOS limits us to 100 pushState calls :/
242
-
243
-
244
- try {
245
- globalHistory.pushState(historyState, '', url);
246
- } catch (error) {
247
- // They are going to lose state here, but there is no real
248
- // way to warn them about it since the page will refresh...
249
- window.location.assign(url);
250
- }
251
-
252
- applyTx(nextAction);
253
- }
238
+ function parseLocation(href, state) {
239
+ let hashIndex = href.indexOf('#');
240
+ let searchIndex = href.indexOf('?');
241
+ return {
242
+ href,
243
+ pathname: href.substring(0, hashIndex > 0 ? searchIndex > 0 ? Math.min(hashIndex, searchIndex) : hashIndex : searchIndex > 0 ? searchIndex : href.length),
244
+ hash: hashIndex > -1 ? href.substring(hashIndex) : '',
245
+ search: searchIndex > -1 ? href.slice(searchIndex, hashIndex === -1 ? undefined : hashIndex) : '',
246
+ state: state || {}
247
+ };
254
248
  }
255
249
 
256
- function replace(to, state) {
257
- var nextAction = Action.Replace;
258
- var nextLocation = getNextLocation(to, state);
259
-
260
- function retry() {
261
- replace(to, state);
262
- }
263
-
264
- if (allowTx(nextAction, nextLocation, retry)) {
265
- var _getHistoryStateAndUr2 = getHistoryStateAndUrl(nextLocation, index),
266
- historyState = _getHistoryStateAndUr2[0],
267
- url = _getHistoryStateAndUr2[1]; // TODO: Support forced reloading
268
-
269
-
270
- globalHistory.replaceState(historyState, '', url);
271
- applyTx(nextAction);
272
- }
250
+ // Thanks co-pilot!
251
+ function createRandomKey() {
252
+ return (Math.random() + 1).toString(36).substring(7);
273
253
  }
274
254
 
275
- function go(delta) {
276
- globalHistory.go(delta);
255
+ // type Compute<T> = { [K in keyof T]: T[K] } | never
256
+
257
+ // type AllKeys<T> = T extends any ? keyof T : never
258
+
259
+ // export type MergeUnion<T, Keys extends keyof T = keyof T> = Compute<
260
+ // {
261
+ // [K in Keys]: T[Keys]
262
+ // } & {
263
+ // [K in AllKeys<T>]?: T extends any
264
+ // ? K extends keyof T
265
+ // ? T[K]
266
+ // : never
267
+ // : never
268
+ // }
269
+ // >
270
+ function last(arr) {
271
+ return arr[arr.length - 1];
277
272
  }
278
-
279
- var history = {
280
- get action() {
281
- return action;
282
- },
283
-
284
- get location() {
285
- return location;
286
- },
287
-
288
- createHref: createHref,
289
- push: push,
290
- replace: replace,
291
- go: go,
292
- back: function back() {
293
- go(-1);
294
- },
295
- forward: function forward() {
296
- go(1);
297
- },
298
- listen: function listen(listener) {
299
- return listeners.push(listener);
300
- },
301
- block: function block(blocker) {
302
- var unblock = blockers.push(blocker);
303
-
304
- if (blockers.length === 1) {
305
- window.addEventListener(BeforeUnloadEventType, promptBeforeUnload);
306
- }
307
-
308
- return function () {
309
- unblock(); // Remove the beforeunload listener so the document may
310
- // still be salvageable in the pagehide event.
311
- // See https://html.spec.whatwg.org/#unloading-documents
312
-
313
- if (!blockers.length) {
314
- window.removeEventListener(BeforeUnloadEventType, promptBeforeUnload);
315
- }
316
- };
273
+ function isFunction(d) {
274
+ return typeof d === 'function';
275
+ }
276
+ function functionalUpdate(updater, previous) {
277
+ if (isFunction(updater)) {
278
+ return updater(previous);
317
279
  }
318
- };
319
- return history;
320
- }
321
- /**
322
- * Hash history stores the location in window.location.hash. This makes it ideal
323
- * for situations where you don't want to send the location to the server for
324
- * some reason, either because you do cannot configure it or the URL space is
325
- * reserved for something else.
326
- *
327
- * @see https://github.com/remix-run/history/tree/main/docs/api-reference.md#createhashhistory
328
- */
329
-
330
- function createHashHistory(options) {
331
- if (options === void 0) {
332
- options = {};
280
+ return updater;
333
281
  }
334
-
335
- var _options2 = options,
336
- _options2$window = _options2.window,
337
- window = _options2$window === void 0 ? document.defaultView : _options2$window;
338
- var globalHistory = window.history;
339
-
340
- function getIndexAndLocation() {
341
- var _parsePath = parsePath(window.location.hash.substr(1)),
342
- _parsePath$pathname = _parsePath.pathname,
343
- pathname = _parsePath$pathname === void 0 ? '/' : _parsePath$pathname,
344
- _parsePath$search = _parsePath.search,
345
- search = _parsePath$search === void 0 ? '' : _parsePath$search,
346
- _parsePath$hash = _parsePath.hash,
347
- hash = _parsePath$hash === void 0 ? '' : _parsePath$hash;
348
-
349
- var state = globalHistory.state || {};
350
- return [state.idx, readOnly({
351
- pathname: pathname,
352
- search: search,
353
- hash: hash,
354
- state: state.usr || null,
355
- key: state.key || 'default'
356
- })];
282
+ function pick(parent, keys) {
283
+ return keys.reduce((obj, key) => {
284
+ obj[key] = parent[key];
285
+ return obj;
286
+ }, {});
357
287
  }
358
288
 
359
- var blockedPopTx = null;
360
-
361
- function handlePop() {
362
- if (blockedPopTx) {
363
- blockers.call(blockedPopTx);
364
- blockedPopTx = null;
365
- } else {
366
- var nextAction = Action.Pop;
367
-
368
- var _getIndexAndLocation4 = getIndexAndLocation(),
369
- nextIndex = _getIndexAndLocation4[0],
370
- nextLocation = _getIndexAndLocation4[1];
371
-
372
- if (blockers.length) {
373
- if (nextIndex != null) {
374
- var delta = index - nextIndex;
375
-
376
- if (delta) {
377
- // Revert the POP
378
- blockedPopTx = {
379
- action: nextAction,
380
- location: nextLocation,
381
- retry: function retry() {
382
- go(delta * -1);
383
- }
384
- };
385
- go(delta);
386
- }
387
- } else {
388
- // Trying to POP to a location with no index. We did not create
389
- // this location, so we can't effectively block the navigation.
390
- warning$1(false, // TODO: Write up a doc that explains our blocking strategy in
391
- // detail and link to it here so people can understand better
392
- // what is going on and how to avoid it.
393
- "You are trying to block a POP navigation to a location that was not " + "created by the history library. The block will fail silently in " + "production, but in general you should do all navigation with the " + "history library (instead of using window.history.pushState directly) " + "to avoid this situation.") ;
289
+ /**
290
+ * This function returns `a` if `b` is deeply equal.
291
+ * If not, it will replace any deeply equal children of `b` with those of `a`.
292
+ * This can be used for structural sharing between immutable JSON values for example.
293
+ * Do not use this with signals
294
+ */
295
+ function replaceEqualDeep(prev, _next) {
296
+ if (prev === _next) {
297
+ return prev;
298
+ }
299
+ const next = _next;
300
+ const array = Array.isArray(prev) && Array.isArray(next);
301
+ if (array || isPlainObject(prev) && isPlainObject(next)) {
302
+ const prevSize = array ? prev.length : Object.keys(prev).length;
303
+ const nextItems = array ? next : Object.keys(next);
304
+ const nextSize = nextItems.length;
305
+ const copy = array ? [] : {};
306
+ let equalItems = 0;
307
+ for (let i = 0; i < nextSize; i++) {
308
+ const key = array ? i : nextItems[i];
309
+ copy[key] = replaceEqualDeep(prev[key], next[key]);
310
+ if (copy[key] === prev[key]) {
311
+ equalItems++;
394
312
  }
395
- } else {
396
- applyTx(nextAction);
397
313
  }
314
+ return prevSize === nextSize && equalItems === prevSize ? prev : copy;
398
315
  }
316
+ return next;
399
317
  }
400
318
 
401
- window.addEventListener(PopStateEventType, handlePop); // popstate does not fire on hashchange in IE 11 and old (trident) Edge
402
- // https://developer.mozilla.org/de/docs/Web/API/Window/popstate_event
403
-
404
- window.addEventListener(HashChangeEventType, function () {
405
- var _getIndexAndLocation5 = getIndexAndLocation(),
406
- nextLocation = _getIndexAndLocation5[1]; // Ignore extraneous hashchange events.
407
-
408
-
409
- if (createPath(nextLocation) !== createPath(location)) {
410
- handlePop();
319
+ // Copied from: https://github.com/jonschlinkert/is-plain-object
320
+ function isPlainObject(o) {
321
+ if (!hasObjectPrototype(o)) {
322
+ return false;
411
323
  }
412
- });
413
- var action = Action.Pop;
414
-
415
- var _getIndexAndLocation6 = getIndexAndLocation(),
416
- index = _getIndexAndLocation6[0],
417
- location = _getIndexAndLocation6[1];
418
324
 
419
- var listeners = createEvents();
420
- var blockers = createEvents();
421
-
422
- if (index == null) {
423
- index = 0;
424
- globalHistory.replaceState(_extends$1({}, globalHistory.state, {
425
- idx: index
426
- }), '');
427
- }
325
+ // If has modified constructor
326
+ const ctor = o.constructor;
327
+ if (typeof ctor === 'undefined') {
328
+ return true;
329
+ }
428
330
 
429
- function getBaseHref() {
430
- var base = document.querySelector('base');
431
- var href = '';
331
+ // If has modified prototype
332
+ const prot = ctor.prototype;
333
+ if (!hasObjectPrototype(prot)) {
334
+ return false;
335
+ }
432
336
 
433
- if (base && base.getAttribute('href')) {
434
- var url = window.location.href;
435
- var hashIndex = url.indexOf('#');
436
- href = hashIndex === -1 ? url : url.slice(0, hashIndex);
337
+ // If constructor does not have an Object-specific method
338
+ if (!prot.hasOwnProperty('isPrototypeOf')) {
339
+ return false;
437
340
  }
438
341
 
439
- return href;
342
+ // Most likely a plain Object
343
+ return true;
440
344
  }
441
-
442
- function createHref(to) {
443
- return getBaseHref() + '#' + (typeof to === 'string' ? to : createPath(to));
345
+ function hasObjectPrototype(o) {
346
+ return Object.prototype.toString.call(o) === '[object Object]';
444
347
  }
445
-
446
- function getNextLocation(to, state) {
447
- if (state === void 0) {
448
- state = null;
348
+ function partialDeepEqual(a, b) {
349
+ if (a === b) {
350
+ return true;
449
351
  }
450
-
451
- return readOnly(_extends$1({
452
- pathname: location.pathname,
453
- hash: '',
454
- search: ''
455
- }, typeof to === 'string' ? parsePath(to) : to, {
456
- state: state,
457
- key: createKey()
458
- }));
352
+ if (typeof a !== typeof b) {
353
+ return false;
354
+ }
355
+ if (isPlainObject(a) && isPlainObject(b)) {
356
+ return !Object.keys(b).some(key => !partialDeepEqual(a[key], b[key]));
357
+ }
358
+ if (Array.isArray(a) && Array.isArray(b)) {
359
+ return a.length === b.length && a.every((item, index) => partialDeepEqual(item, b[index]));
360
+ }
361
+ return false;
459
362
  }
460
363
 
461
- function getHistoryStateAndUrl(nextLocation, index) {
462
- return [{
463
- usr: nextLocation.state,
464
- key: nextLocation.key,
465
- idx: index
466
- }, createHref(nextLocation)];
364
+ function joinPaths(paths) {
365
+ return cleanPath(paths.filter(Boolean).join('/'));
467
366
  }
468
-
469
- function allowTx(action, location, retry) {
470
- return !blockers.length || (blockers.call({
471
- action: action,
472
- location: location,
473
- retry: retry
474
- }), false);
367
+ function cleanPath(path) {
368
+ // remove double slashes
369
+ return path.replace(/\/{2,}/g, '/');
475
370
  }
476
-
477
- function applyTx(nextAction) {
478
- action = nextAction;
479
-
480
- var _getIndexAndLocation7 = getIndexAndLocation();
481
-
482
- index = _getIndexAndLocation7[0];
483
- location = _getIndexAndLocation7[1];
484
- listeners.call({
485
- action: action,
486
- location: location
371
+ function trimPathLeft(path) {
372
+ return path === '/' ? path : path.replace(/^\/{1,}/, '');
373
+ }
374
+ function trimPathRight(path) {
375
+ return path === '/' ? path : path.replace(/\/{1,}$/, '');
376
+ }
377
+ function trimPath(path) {
378
+ return trimPathRight(trimPathLeft(path));
379
+ }
380
+ function resolvePath(basepath, base, to) {
381
+ base = base.replace(new RegExp(`^${basepath}`), '/');
382
+ to = to.replace(new RegExp(`^${basepath}`), '/');
383
+ let baseSegments = parsePathname(base);
384
+ const toSegments = parsePathname(to);
385
+ toSegments.forEach((toSegment, index) => {
386
+ if (toSegment.value === '/') {
387
+ if (!index) {
388
+ // Leading slash
389
+ baseSegments = [toSegment];
390
+ } else if (index === toSegments.length - 1) {
391
+ // Trailing Slash
392
+ baseSegments.push(toSegment);
393
+ } else ;
394
+ } else if (toSegment.value === '..') {
395
+ // Extra trailing slash? pop it off
396
+ if (baseSegments.length > 1 && last(baseSegments)?.value === '/') {
397
+ baseSegments.pop();
398
+ }
399
+ baseSegments.pop();
400
+ } else if (toSegment.value === '.') {
401
+ return;
402
+ } else {
403
+ baseSegments.push(toSegment);
404
+ }
487
405
  });
406
+ const joined = joinPaths([basepath, ...baseSegments.map(d => d.value)]);
407
+ return cleanPath(joined);
488
408
  }
489
-
490
- function push(to, state) {
491
- var nextAction = Action.Push;
492
- var nextLocation = getNextLocation(to, state);
493
-
494
- function retry() {
495
- push(to, state);
409
+ function parsePathname(pathname) {
410
+ if (!pathname) {
411
+ return [];
412
+ }
413
+ pathname = cleanPath(pathname);
414
+ const segments = [];
415
+ if (pathname.slice(0, 1) === '/') {
416
+ pathname = pathname.substring(1);
417
+ segments.push({
418
+ type: 'pathname',
419
+ value: '/'
420
+ });
421
+ }
422
+ if (!pathname) {
423
+ return segments;
496
424
  }
497
425
 
498
- warning$1(nextLocation.pathname.charAt(0) === '/', "Relative pathnames are not supported in hash history.push(" + JSON.stringify(to) + ")") ;
499
-
500
- if (allowTx(nextAction, nextLocation, retry)) {
501
- var _getHistoryStateAndUr3 = getHistoryStateAndUrl(nextLocation, index + 1),
502
- historyState = _getHistoryStateAndUr3[0],
503
- url = _getHistoryStateAndUr3[1]; // TODO: Support forced reloading
504
- // try...catch because iOS limits us to 100 pushState calls :/
505
-
506
-
507
- try {
508
- globalHistory.pushState(historyState, '', url);
509
- } catch (error) {
510
- // They are going to lose state here, but there is no real
511
- // way to warn them about it since the page will refresh...
512
- window.location.assign(url);
426
+ // Remove empty segments and '.' segments
427
+ const split = pathname.split('/').filter(Boolean);
428
+ segments.push(...split.map(part => {
429
+ if (part === '$' || part === '*') {
430
+ return {
431
+ type: 'wildcard',
432
+ value: part
433
+ };
513
434
  }
514
-
515
- applyTx(nextAction);
435
+ if (part.charAt(0) === '$') {
436
+ return {
437
+ type: 'param',
438
+ value: part
439
+ };
440
+ }
441
+ return {
442
+ type: 'pathname',
443
+ value: part
444
+ };
445
+ }));
446
+ if (pathname.slice(-1) === '/') {
447
+ pathname = pathname.substring(1);
448
+ segments.push({
449
+ type: 'pathname',
450
+ value: '/'
451
+ });
516
452
  }
453
+ return segments;
517
454
  }
455
+ function interpolatePath(path, params, leaveWildcards = false) {
456
+ const interpolatedPathSegments = parsePathname(path);
457
+ return joinPaths(interpolatedPathSegments.map(segment => {
458
+ if (segment.type === 'wildcard') {
459
+ const value = params[segment.value];
460
+ if (leaveWildcards) return `${segment.value}${value ?? ''}`;
461
+ return value;
462
+ }
463
+ if (segment.type === 'param') {
464
+ return params[segment.value.substring(1)] ?? '';
465
+ }
466
+ return segment.value;
467
+ }));
468
+ }
469
+ function matchPathname(basepath, currentPathname, matchLocation) {
470
+ const pathParams = matchByPath(basepath, currentPathname, matchLocation);
471
+ // const searchMatched = matchBySearch(location.search, matchLocation)
518
472
 
519
- function replace(to, state) {
520
- var nextAction = Action.Replace;
521
- var nextLocation = getNextLocation(to, state);
522
-
523
- function retry() {
524
- replace(to, state);
525
- }
526
-
527
- warning$1(nextLocation.pathname.charAt(0) === '/', "Relative pathnames are not supported in hash history.replace(" + JSON.stringify(to) + ")") ;
528
-
529
- if (allowTx(nextAction, nextLocation, retry)) {
530
- var _getHistoryStateAndUr4 = getHistoryStateAndUrl(nextLocation, index),
531
- historyState = _getHistoryStateAndUr4[0],
532
- url = _getHistoryStateAndUr4[1]; // TODO: Support forced reloading
533
-
534
-
535
- globalHistory.replaceState(historyState, '', url);
536
- applyTx(nextAction);
473
+ if (matchLocation.to && !pathParams) {
474
+ return;
537
475
  }
476
+ return pathParams ?? {};
538
477
  }
539
-
540
- function go(delta) {
541
- globalHistory.go(delta);
478
+ function matchByPath(basepath, from, matchLocation) {
479
+ // Remove the base path from the pathname
480
+ from = basepath != '/' ? from.substring(basepath.length) : from;
481
+ // Default to to $ (wildcard)
482
+ const to = `${matchLocation.to ?? '$'}`;
483
+ // Parse the from and to
484
+ const baseSegments = parsePathname(from);
485
+ const routeSegments = parsePathname(to);
486
+ if (!from.startsWith('/')) {
487
+ baseSegments.unshift({
488
+ type: 'pathname',
489
+ value: '/'
490
+ });
491
+ }
492
+ if (!to.startsWith('/')) {
493
+ routeSegments.unshift({
494
+ type: 'pathname',
495
+ value: '/'
496
+ });
497
+ }
498
+ const params = {};
499
+ let isMatch = (() => {
500
+ for (let i = 0; i < Math.max(baseSegments.length, routeSegments.length); i++) {
501
+ const baseSegment = baseSegments[i];
502
+ const routeSegment = routeSegments[i];
503
+ const isLastBaseSegment = i >= baseSegments.length - 1;
504
+ const isLastRouteSegment = i >= routeSegments.length - 1;
505
+ if (routeSegment) {
506
+ if (routeSegment.type === 'wildcard') {
507
+ if (baseSegment?.value) {
508
+ params['*'] = joinPaths(baseSegments.slice(i).map(d => d.value));
509
+ return true;
510
+ }
511
+ return false;
512
+ }
513
+ if (routeSegment.type === 'pathname') {
514
+ if (routeSegment.value === '/' && !baseSegment?.value) {
515
+ return true;
516
+ }
517
+ if (baseSegment) {
518
+ if (matchLocation.caseSensitive) {
519
+ if (routeSegment.value !== baseSegment.value) {
520
+ return false;
521
+ }
522
+ } else if (routeSegment.value.toLowerCase() !== baseSegment.value.toLowerCase()) {
523
+ return false;
524
+ }
525
+ }
526
+ }
527
+ if (!baseSegment) {
528
+ return false;
529
+ }
530
+ if (routeSegment.type === 'param') {
531
+ if (baseSegment?.value === '/') {
532
+ return false;
533
+ }
534
+ if (baseSegment.value.charAt(0) !== '$') {
535
+ params[routeSegment.value.substring(1)] = baseSegment.value;
536
+ }
537
+ }
538
+ }
539
+ if (!isLastBaseSegment && isLastRouteSegment) {
540
+ return !!matchLocation.fuzzy;
541
+ }
542
+ }
543
+ return true;
544
+ })();
545
+ return isMatch ? params : undefined;
542
546
  }
543
547
 
544
- var history = {
545
- get action() {
546
- return action;
547
- },
548
-
549
- get location() {
550
- return location;
551
- },
552
-
553
- createHref: createHref,
554
- push: push,
555
- replace: replace,
556
- go: go,
557
- back: function back() {
558
- go(-1);
559
- },
560
- forward: function forward() {
561
- go(1);
562
- },
563
- listen: function listen(listener) {
564
- return listeners.push(listener);
565
- },
566
- block: function block(blocker) {
567
- var unblock = blockers.push(blocker);
568
-
569
- if (blockers.length === 1) {
570
- window.addEventListener(BeforeUnloadEventType, promptBeforeUnload);
571
- }
548
+ // @ts-nocheck
572
549
 
573
- return function () {
574
- unblock(); // Remove the beforeunload listener so the document may
575
- // still be salvageable in the pagehide event.
576
- // See https://html.spec.whatwg.org/#unloading-documents
550
+ // qss has been slightly modified and inlined here for our use cases (and compression's sake). We've included it as a hard dependency for MIT license attribution.
577
551
 
578
- if (!blockers.length) {
579
- window.removeEventListener(BeforeUnloadEventType, promptBeforeUnload);
552
+ function encode(obj, pfx) {
553
+ var k,
554
+ i,
555
+ tmp,
556
+ str = '';
557
+ for (k in obj) {
558
+ if ((tmp = obj[k]) !== void 0) {
559
+ if (Array.isArray(tmp)) {
560
+ for (i = 0; i < tmp.length; i++) {
561
+ str && (str += '&');
562
+ str += encodeURIComponent(k) + '=' + encodeURIComponent(tmp[i]);
563
+ }
564
+ } else {
565
+ str && (str += '&');
566
+ str += encodeURIComponent(k) + '=' + encodeURIComponent(tmp);
580
567
  }
581
- };
568
+ }
582
569
  }
583
- };
584
- return history;
585
- }
586
- /**
587
- * Memory history stores the current location in memory. It is designed for use
588
- * in stateful non-browser environments like tests and React Native.
589
- *
590
- * @see https://github.com/remix-run/history/tree/main/docs/api-reference.md#creatememoryhistory
591
- */
592
-
593
- function createMemoryHistory(options) {
594
- if (options === void 0) {
595
- options = {};
570
+ return (pfx || '') + str;
596
571
  }
597
-
598
- var _options3 = options,
599
- _options3$initialEntr = _options3.initialEntries,
600
- initialEntries = _options3$initialEntr === void 0 ? ['/'] : _options3$initialEntr,
601
- initialIndex = _options3.initialIndex;
602
- var entries = initialEntries.map(function (entry) {
603
- var location = readOnly(_extends$1({
604
- pathname: '/',
605
- search: '',
606
- hash: '',
607
- state: null,
608
- key: createKey()
609
- }, typeof entry === 'string' ? parsePath(entry) : entry));
610
- warning$1(location.pathname.charAt(0) === '/', "Relative pathnames are not supported in createMemoryHistory({ initialEntries }) (invalid entry: " + JSON.stringify(entry) + ")") ;
611
- return location;
612
- });
613
- var index = clamp(initialIndex == null ? entries.length - 1 : initialIndex, 0, entries.length - 1);
614
- var action = Action.Pop;
615
- var location = entries[index];
616
- var listeners = createEvents();
617
- var blockers = createEvents();
618
-
619
- function createHref(to) {
620
- return typeof to === 'string' ? to : createPath(to);
572
+ function toValue(mix) {
573
+ if (!mix) return '';
574
+ var str = decodeURIComponent(mix);
575
+ if (str === 'false') return false;
576
+ if (str === 'true') return true;
577
+ return +str * 0 === 0 && +str + '' === str ? +str : str;
621
578
  }
622
-
623
- function getNextLocation(to, state) {
624
- if (state === void 0) {
625
- state = null;
579
+ function decode(str) {
580
+ var tmp,
581
+ k,
582
+ out = {},
583
+ arr = str.split('&');
584
+ while (tmp = arr.shift()) {
585
+ tmp = tmp.split('=');
586
+ k = tmp.shift();
587
+ if (out[k] !== void 0) {
588
+ out[k] = [].concat(out[k], toValue(tmp.shift()));
589
+ } else {
590
+ out[k] = toValue(tmp.shift());
591
+ }
626
592
  }
627
-
628
- return readOnly(_extends$1({
629
- pathname: location.pathname,
630
- search: '',
631
- hash: ''
632
- }, typeof to === 'string' ? parsePath(to) : to, {
633
- state: state,
634
- key: createKey()
635
- }));
636
- }
637
-
638
- function allowTx(action, location, retry) {
639
- return !blockers.length || (blockers.call({
640
- action: action,
641
- location: location,
642
- retry: retry
643
- }), false);
593
+ return out;
644
594
  }
645
595
 
646
- function applyTx(nextAction, nextLocation) {
647
- action = nextAction;
648
- location = nextLocation;
649
- listeners.call({
650
- action: action,
651
- location: location
652
- });
653
- }
596
+ const rootRouteId = '__root__';
654
597
 
655
- function push(to, state) {
656
- var nextAction = Action.Push;
657
- var nextLocation = getNextLocation(to, state);
598
+ // The parse type here allows a zod schema to be passed directly to the validator
658
599
 
659
- function retry() {
660
- push(to, state);
661
- }
600
+ // T extends Record<PropertyKey, infer U>
601
+ // ? {
602
+ // [K in keyof T]: UseLoaderResultPromise<T[K]>
603
+ // }
604
+ // : UseLoaderResultPromise<T>
662
605
 
663
- warning$1(location.pathname.charAt(0) === '/', "Relative pathnames are not supported in memory history.push(" + JSON.stringify(to) + ")") ;
606
+ // export type UseLoaderResultPromise<T> = T extends Promise<infer U>
607
+ // ? StreamedPromise<U>
608
+ // : T
609
+ class Route {
610
+ // Set up in this.init()
664
611
 
665
- if (allowTx(nextAction, nextLocation, retry)) {
666
- index += 1;
667
- entries.splice(index, entries.length, nextLocation);
668
- applyTx(nextAction, nextLocation);
669
- }
670
- }
612
+ // customId!: TCustomId
671
613
 
672
- function replace(to, state) {
673
- var nextAction = Action.Replace;
674
- var nextLocation = getNextLocation(to, state);
614
+ // Optional
675
615
 
676
- function retry() {
677
- replace(to, state);
616
+ constructor(options) {
617
+ this.options = options || {};
618
+ this.isRoot = !options?.getParentRoute;
619
+ Route.__onInit(this);
678
620
  }
621
+ init = opts => {
622
+ this.originalIndex = opts.originalIndex;
623
+ this.router = opts.router;
624
+ const options = this.options;
625
+ const isRoot = !options?.path && !options?.id;
626
+ this.parentRoute = this.options?.getParentRoute?.();
627
+ if (isRoot) {
628
+ this.path = rootRouteId;
629
+ } else {
630
+ invariant(this.parentRoute, `Child Route instances must pass a 'getParentRoute: () => ParentRoute' option that returns a Route instance.`);
631
+ }
632
+ let path = isRoot ? rootRouteId : options.path;
679
633
 
680
- warning$1(location.pathname.charAt(0) === '/', "Relative pathnames are not supported in memory history.replace(" + JSON.stringify(to) + ")") ;
634
+ // If the path is anything other than an index path, trim it up
635
+ if (path && path !== '/') {
636
+ path = trimPath(path);
637
+ }
638
+ const customId = options?.id || path;
681
639
 
682
- if (allowTx(nextAction, nextLocation, retry)) {
683
- entries[index] = nextLocation;
684
- applyTx(nextAction, nextLocation);
685
- }
640
+ // Strip the parentId prefix from the first level of children
641
+ let id = isRoot ? rootRouteId : joinPaths([this.parentRoute.id === rootRouteId ? '' : this.parentRoute.id, customId]);
642
+ if (path === rootRouteId) {
643
+ path = '/';
644
+ }
645
+ if (id !== rootRouteId) {
646
+ id = joinPaths(['/', id]);
647
+ }
648
+ const fullPath = id === rootRouteId ? '/' : joinPaths([this.parentRoute.fullPath, path]);
649
+ this.path = path;
650
+ this.id = id;
651
+ // this.customId = customId as TCustomId
652
+ this.fullPath = fullPath;
653
+ this.to = fullPath;
654
+ };
655
+ addChildren = children => {
656
+ this.children = children;
657
+ return this;
658
+ };
659
+ update = options => {
660
+ Object.assign(this.options, options);
661
+ return this;
662
+ };
663
+ static __onInit = route => {
664
+ // This is a dummy static method that should get
665
+ // replaced by a framework specific implementation if necessary
666
+ };
686
667
  }
687
-
688
- function go(delta) {
689
- var nextIndex = clamp(index + delta, 0, entries.length - 1);
690
- var nextAction = Action.Pop;
691
- var nextLocation = entries[nextIndex];
692
-
693
- function retry() {
694
- go(delta);
668
+ class RouterContext {
669
+ constructor() {}
670
+ createRootRoute = options => {
671
+ return new RootRoute(options);
672
+ };
673
+ }
674
+ class RootRoute extends Route {
675
+ constructor(options) {
676
+ super(options);
695
677
  }
678
+ }
679
+ function createRouteMask(opts) {
680
+ return opts;
681
+ }
696
682
 
697
- if (allowTx(nextAction, nextLocation, retry)) {
698
- index = nextIndex;
699
- applyTx(nextAction, nextLocation);
683
+ class FileRoute {
684
+ constructor(path) {
685
+ this.path = path;
700
686
  }
687
+ createRoute = options => {
688
+ const route = new Route(options);
689
+ route.isRoot = false;
690
+ return route;
691
+ };
701
692
  }
702
693
 
703
- var history = {
704
- get index() {
705
- return index;
706
- },
707
-
708
- get action() {
709
- return action;
710
- },
711
-
712
- get location() {
713
- return location;
714
- },
715
-
716
- createHref: createHref,
717
- push: push,
718
- replace: replace,
719
- go: go,
720
- back: function back() {
721
- go(-1);
722
- },
723
- forward: function forward() {
724
- go(1);
725
- },
726
- listen: function listen(listener) {
727
- return listeners.push(listener);
728
- },
729
- block: function block(blocker) {
730
- return blockers.push(blocker);
731
- }
732
- };
733
- return history;
734
- } ////////////////////////////////////////////////////////////////////////////////
735
- // UTILS
736
- ////////////////////////////////////////////////////////////////////////////////
737
-
738
- function clamp(n, lowerBound, upperBound) {
739
- return Math.min(Math.max(n, lowerBound), upperBound);
740
- }
741
-
742
- function promptBeforeUnload(event) {
743
- // Cancel the event.
744
- event.preventDefault(); // Chrome (and legacy IE) requires returnValue to be set.
745
-
746
- event.returnValue = '';
747
- }
748
-
749
- function createEvents() {
750
- var handlers = [];
751
- return {
752
- get length() {
753
- return handlers.length;
754
- },
755
-
756
- push: function push(fn) {
757
- handlers.push(fn);
758
- return function () {
759
- handlers = handlers.filter(function (handler) {
760
- return handler !== fn;
761
- });
762
- };
763
- },
764
- call: function call(arg) {
765
- handlers.forEach(function (fn) {
766
- return fn && fn(arg);
767
- });
768
- }
769
- };
770
- }
771
-
772
- function createKey() {
773
- return Math.random().toString(36).substr(2, 8);
774
- }
775
- /**
776
- * Creates a string URL path from the given pathname, search, and hash components.
777
- *
778
- * @see https://github.com/remix-run/history/tree/main/docs/api-reference.md#createpath
779
- */
780
-
781
-
782
- function createPath(_ref) {
783
- var _ref$pathname = _ref.pathname,
784
- pathname = _ref$pathname === void 0 ? '/' : _ref$pathname,
785
- _ref$search = _ref.search,
786
- search = _ref$search === void 0 ? '' : _ref$search,
787
- _ref$hash = _ref.hash,
788
- hash = _ref$hash === void 0 ? '' : _ref$hash;
789
- if (search && search !== '?') pathname += search.charAt(0) === '?' ? search : '?' + search;
790
- if (hash && hash !== '#') pathname += hash.charAt(0) === '#' ? hash : '#' + hash;
791
- return pathname;
792
- }
793
- /**
794
- * Parses a string URL path into its separate pathname, search, and hash components.
795
- *
796
- * @see https://github.com/remix-run/history/tree/main/docs/api-reference.md#parsepath
797
- */
798
-
799
- function parsePath(path) {
800
- var parsedPath = {};
801
-
802
- if (path) {
803
- var hashIndex = path.indexOf('#');
804
-
805
- if (hashIndex >= 0) {
806
- parsedPath.hash = path.substr(hashIndex);
807
- path = path.substr(0, hashIndex);
808
- }
809
-
810
- var searchIndex = path.indexOf('?');
811
-
812
- if (searchIndex >= 0) {
813
- parsedPath.search = path.substr(searchIndex);
814
- path = path.substr(0, searchIndex);
815
- }
816
-
817
- if (path) {
818
- parsedPath.pathname = path;
819
- }
820
- }
821
-
822
- return parsedPath;
823
- }
824
-
825
- var prefix = 'Invariant failed';
826
- function invariant(condition, message) {
827
- if (condition) {
828
- return;
829
- }
830
- var provided = typeof message === 'function' ? message() : message;
831
- var value = provided ? "".concat(prefix, ": ").concat(provided) : prefix;
832
- throw new Error(value);
833
- }
834
-
835
- // type UnionToIntersection<U> = (U extends any ? (k: U) => void : never) extends (
836
- // k: infer I,
837
- // ) => any
838
- // ? I
839
- // : never
840
-
841
- /**
842
- * This function returns `a` if `b` is deeply equal.
843
- * If not, it will replace any deeply equal children of `b` with those of `a`.
844
- * This can be used for structural sharing between JSON values for example.
845
- */
846
- function replaceEqualDeep(prev, next) {
847
- if (prev === next) {
848
- return prev;
849
- }
850
-
851
- const array = Array.isArray(prev) && Array.isArray(next);
852
-
853
- if (array || isPlainObject(prev) && isPlainObject(next)) {
854
- const aSize = array ? prev.length : Object.keys(prev).length;
855
- const bItems = array ? next : Object.keys(next);
856
- const bSize = bItems.length;
857
- const copy = array ? [] : {};
858
- let equalItems = 0;
859
-
860
- for (let i = 0; i < bSize; i++) {
861
- const key = array ? i : bItems[i];
862
- copy[key] = replaceEqualDeep(prev[key], next[key]);
863
-
864
- if (copy[key] === prev[key]) {
865
- equalItems++;
866
- }
867
- }
868
-
869
- return aSize === bSize && equalItems === aSize ? prev : copy;
870
- }
871
-
872
- return next;
873
- } // Copied from: https://github.com/jonschlinkert/is-plain-object
874
-
875
- function isPlainObject(o) {
876
- if (!hasObjectPrototype(o)) {
877
- return false;
878
- } // If has modified constructor
879
-
880
-
881
- const ctor = o.constructor;
882
-
883
- if (typeof ctor === 'undefined') {
884
- return true;
885
- } // If has modified prototype
886
-
887
-
888
- const prot = ctor.prototype;
889
-
890
- if (!hasObjectPrototype(prot)) {
891
- return false;
892
- } // If constructor does not have an Object-specific method
893
-
894
-
895
- if (!prot.hasOwnProperty('isPrototypeOf')) {
896
- return false;
897
- } // Most likely a plain Object
898
-
899
-
900
- return true;
901
- }
902
-
903
- function hasObjectPrototype(o) {
904
- return Object.prototype.toString.call(o) === '[object Object]';
905
- }
906
-
907
- function last(arr) {
908
- return arr[arr.length - 1];
909
- }
910
- function warning(cond, message) {
911
- if (cond) {
912
- if (typeof console !== 'undefined') console.warn(message);
913
-
914
- try {
915
- throw new Error(message);
916
- } catch (_unused) {}
917
- }
918
-
919
- return true;
920
- }
921
-
922
- function isFunction(d) {
923
- return typeof d === 'function';
924
- }
925
-
926
- function functionalUpdate(updater, previous) {
927
- if (isFunction(updater)) {
928
- return updater(previous);
929
- }
930
-
931
- return updater;
932
- }
933
- function pick(parent, keys) {
934
- return keys.reduce((obj, key) => {
935
- obj[key] = parent[key];
936
- return obj;
937
- }, {});
938
- }
939
-
940
- function joinPaths(paths) {
941
- return cleanPath(paths.filter(Boolean).join('/'));
942
- }
943
- function cleanPath(path) {
944
- // remove double slashes
945
- return path.replace(/\/{2,}/g, '/');
946
- }
947
- function trimPathLeft(path) {
948
- return path === '/' ? path : path.replace(/^\/{1,}/, '');
949
- }
950
- function trimPathRight(path) {
951
- return path === '/' ? path : path.replace(/\/{1,}$/, '');
952
- }
953
- function trimPath(path) {
954
- return trimPathRight(trimPathLeft(path));
955
- }
956
- function resolvePath(basepath, base, to) {
957
- base = base.replace(new RegExp("^" + basepath), '/');
958
- to = to.replace(new RegExp("^" + basepath), '/');
959
- let baseSegments = parsePathname(base);
960
- const toSegments = parsePathname(to);
961
- toSegments.forEach((toSegment, index) => {
962
- if (toSegment.value === '/') {
963
- if (!index) {
964
- // Leading slash
965
- baseSegments = [toSegment];
966
- } else if (index === toSegments.length - 1) {
967
- // Trailing Slash
968
- baseSegments.push(toSegment);
969
- } else ;
970
- } else if (toSegment.value === '..') {
971
- var _last;
972
-
973
- // Extra trailing slash? pop it off
974
- if (baseSegments.length > 1 && ((_last = last(baseSegments)) == null ? void 0 : _last.value) === '/') {
975
- baseSegments.pop();
976
- }
977
-
978
- baseSegments.pop();
979
- } else if (toSegment.value === '.') {
980
- return;
981
- } else {
982
- baseSegments.push(toSegment);
983
- }
984
- });
985
- const joined = joinPaths([basepath, ...baseSegments.map(d => d.value)]);
986
- return cleanPath(joined);
987
- }
988
- function parsePathname(pathname) {
989
- if (!pathname) {
990
- return [];
991
- }
992
-
993
- pathname = cleanPath(pathname);
994
- const segments = [];
995
-
996
- if (pathname.slice(0, 1) === '/') {
997
- pathname = pathname.substring(1);
998
- segments.push({
999
- type: 'pathname',
1000
- value: '/'
1001
- });
1002
- }
1003
-
1004
- if (!pathname) {
1005
- return segments;
1006
- } // Remove empty segments and '.' segments
1007
-
1008
-
1009
- const split = pathname.split('/').filter(Boolean);
1010
- segments.push(...split.map(part => {
1011
- if (part.startsWith('*')) {
1012
- return {
1013
- type: 'wildcard',
1014
- value: part
1015
- };
694
+ /**
695
+ * @tanstack/store/src/index.ts
696
+ *
697
+ * Copyright (c) TanStack
698
+ *
699
+ * This source code is licensed under the MIT license found in the
700
+ * LICENSE.md file in the root directory of this source tree.
701
+ *
702
+ * @license MIT
703
+ */
704
+ class Store {
705
+ listeners = new Set();
706
+ _batching = false;
707
+ _flushing = 0;
708
+ _nextPriority = null;
709
+ constructor(initialState, options) {
710
+ this.state = initialState;
711
+ this.options = options;
1016
712
  }
1017
-
1018
- if (part.charAt(0) === ':') {
1019
- return {
1020
- type: 'param',
1021
- value: part
713
+ subscribe = listener => {
714
+ this.listeners.add(listener);
715
+ const unsub = this.options?.onSubscribe?.(listener, this);
716
+ return () => {
717
+ this.listeners.delete(listener);
718
+ unsub?.();
1022
719
  };
1023
- }
1024
-
1025
- return {
1026
- type: 'pathname',
1027
- value: part
1028
720
  };
1029
- }));
1030
-
1031
- if (pathname.slice(-1) === '/') {
1032
- pathname = pathname.substring(1);
1033
- segments.push({
1034
- type: 'pathname',
1035
- value: '/'
1036
- });
1037
- }
1038
-
1039
- return segments;
1040
- }
1041
- function interpolatePath(path, params, leaveWildcard) {
1042
- const interpolatedPathSegments = parsePathname(path);
1043
- return joinPaths(interpolatedPathSegments.map(segment => {
1044
- if (segment.value === '*' && !leaveWildcard) {
1045
- return '';
1046
- }
1047
-
1048
- if (segment.type === 'param') {
1049
- var _segment$value$substr;
1050
-
1051
- return (_segment$value$substr = params[segment.value.substring(1)]) != null ? _segment$value$substr : '';
1052
- }
1053
-
1054
- return segment.value;
1055
- }));
1056
- }
1057
- function matchPathname(currentPathname, matchLocation) {
1058
- const pathParams = matchByPath(currentPathname, matchLocation); // const searchMatched = matchBySearch(currentLocation.search, matchLocation)
1059
-
1060
- if (matchLocation.to && !pathParams) {
1061
- return;
1062
- } // if (matchLocation.search && !searchMatched) {
1063
- // return
1064
- // }
1065
-
1066
-
1067
- return pathParams != null ? pathParams : {};
1068
- }
1069
- function matchByPath(from, matchLocation) {
1070
- var _matchLocation$to;
1071
-
1072
- const baseSegments = parsePathname(from);
1073
- const routeSegments = parsePathname("" + ((_matchLocation$to = matchLocation.to) != null ? _matchLocation$to : '*'));
1074
- const params = {};
1075
-
1076
- let isMatch = (() => {
1077
- for (let i = 0; i < Math.max(baseSegments.length, routeSegments.length); i++) {
1078
- const baseSegment = baseSegments[i];
1079
- const routeSegment = routeSegments[i];
1080
- const isLastRouteSegment = i === routeSegments.length - 1;
1081
- const isLastBaseSegment = i === baseSegments.length - 1;
1082
-
1083
- if (routeSegment) {
1084
- if (routeSegment.type === 'wildcard') {
1085
- if (baseSegment != null && baseSegment.value) {
1086
- params['*'] = joinPaths(baseSegments.slice(i).map(d => d.value));
1087
- return true;
1088
- }
1089
-
1090
- return false;
1091
- }
1092
-
1093
- if (routeSegment.type === 'pathname') {
1094
- if (routeSegment.value === '/' && !(baseSegment != null && baseSegment.value)) {
1095
- return true;
1096
- }
1097
-
1098
- if (baseSegment) {
1099
- if (matchLocation.caseSensitive) {
1100
- if (routeSegment.value !== baseSegment.value) {
1101
- return false;
1102
- }
1103
- } else if (routeSegment.value.toLowerCase() !== baseSegment.value.toLowerCase()) {
1104
- return false;
1105
- }
1106
- }
1107
- }
1108
-
1109
- if (!baseSegment) {
1110
- return false;
1111
- }
1112
-
1113
- if (routeSegment.type === 'param') {
1114
- if ((baseSegment == null ? void 0 : baseSegment.value) === '/') {
1115
- return false;
1116
- }
1117
-
1118
- if (!baseSegment.value.startsWith(':')) {
1119
- params[routeSegment.value.substring(1)] = baseSegment.value;
1120
- }
1121
- }
1122
- }
1123
-
1124
- if (isLastRouteSegment && !isLastBaseSegment) {
1125
- return !!matchLocation.fuzzy;
1126
- }
1127
- }
1128
-
1129
- return true;
1130
- })();
1131
-
1132
- return isMatch ? params : undefined;
1133
- }
1134
-
1135
- // @ts-nocheck
1136
- // qss has been slightly modified and inlined here for our use cases (and compression's sake). We've included it as a hard dependency for MIT license attribution.
1137
- function encode(obj, pfx) {
1138
- var k,
1139
- i,
1140
- tmp,
1141
- str = '';
1142
-
1143
- for (k in obj) {
1144
- if ((tmp = obj[k]) !== void 0) {
1145
- if (Array.isArray(tmp)) {
1146
- for (i = 0; i < tmp.length; i++) {
1147
- str && (str += '&');
1148
- str += encodeURIComponent(k) + '=' + encodeURIComponent(tmp[i]);
1149
- }
721
+ setState = (updater, opts) => {
722
+ const previous = this.state;
723
+ this.state = this.options?.updateFn ? this.options.updateFn(previous)(updater) : updater(previous);
724
+ const priority = opts?.priority ?? this.options?.defaultPriority ?? 'high';
725
+ if (this._nextPriority === null) {
726
+ this._nextPriority = priority;
727
+ } else if (this._nextPriority === 'high') {
728
+ this._nextPriority = priority;
1150
729
  } else {
1151
- str && (str += '&');
1152
- str += encodeURIComponent(k) + '=' + encodeURIComponent(tmp);
730
+ this._nextPriority = this.options?.defaultPriority ?? 'high';
1153
731
  }
1154
- }
1155
- }
1156
-
1157
- return (pfx || '') + str;
1158
- }
1159
-
1160
- function toValue(mix) {
1161
- if (!mix) return '';
1162
- var str = decodeURIComponent(mix);
1163
- if (str === 'false') return false;
1164
- if (str === 'true') return true;
1165
- if (str.charAt(0) === '0') return str;
1166
- return +str * 0 === 0 ? +str : str;
1167
- }
1168
732
 
1169
- function decode(str) {
1170
- var tmp,
1171
- k,
1172
- out = {},
1173
- arr = str.split('&');
1174
-
1175
- while (tmp = arr.shift()) {
1176
- tmp = tmp.split('=');
1177
- k = tmp.shift();
733
+ // Always run onUpdate, regardless of batching
734
+ this.options?.onUpdate?.({
735
+ priority: this._nextPriority
736
+ });
1178
737
 
1179
- if (out[k] !== void 0) {
1180
- out[k] = [].concat(out[k], toValue(tmp.shift()));
1181
- } else {
1182
- out[k] = toValue(tmp.shift());
1183
- }
738
+ // Attempt to flush
739
+ this._flush();
740
+ };
741
+ _flush = () => {
742
+ if (this._batching) return;
743
+ const flushId = ++this._flushing;
744
+ this.listeners.forEach(listener => {
745
+ if (this._flushing !== flushId) return;
746
+ listener({
747
+ priority: this._nextPriority ?? 'high'
748
+ });
749
+ });
750
+ };
751
+ batch = cb => {
752
+ if (this._batching) return cb();
753
+ this._batching = true;
754
+ cb();
755
+ this._batching = false;
756
+ this._flush();
757
+ };
1184
758
  }
1185
759
 
1186
- return out;
1187
- }
1188
-
1189
- function _extends() {
1190
- _extends = Object.assign ? Object.assign.bind() : function (target) {
1191
- for (var i = 1; i < arguments.length; i++) {
1192
- var source = arguments[i];
1193
-
1194
- for (var key in source) {
1195
- if (Object.prototype.hasOwnProperty.call(source, key)) {
1196
- target[key] = source[key];
1197
- }
760
+ const defaultParseSearch = parseSearchWith(JSON.parse);
761
+ const defaultStringifySearch = stringifySearchWith(JSON.stringify, JSON.parse);
762
+ function parseSearchWith(parser) {
763
+ return searchStr => {
764
+ if (searchStr.substring(0, 1) === '?') {
765
+ searchStr = searchStr.substring(1);
1198
766
  }
1199
- }
1200
-
1201
- return target;
1202
- };
1203
- return _extends.apply(this, arguments);
1204
- }
1205
-
1206
- function createRoute(routeConfig, options, parent, router) {
1207
- const {
1208
- id,
1209
- routeId,
1210
- path: routePath,
1211
- fullPath
1212
- } = routeConfig;
1213
-
1214
- const action = router.state.actions[id] || (() => {
1215
- router.state.actions[id] = {
1216
- submissions: [],
1217
- submit: async (submission, actionOpts) => {
1218
- var _actionOpts$invalidat;
1219
-
1220
- if (!route) {
1221
- return;
1222
- }
1223
-
1224
- const invalidate = (_actionOpts$invalidat = actionOpts == null ? void 0 : actionOpts.invalidate) != null ? _actionOpts$invalidat : true;
1225
-
1226
- if (!(actionOpts != null && actionOpts.multi)) {
1227
- action.submissions = action.submissions.filter(d => d.isMulti);
1228
- }
1229
-
1230
- const actionState = {
1231
- submittedAt: Date.now(),
1232
- status: 'pending',
1233
- submission,
1234
- isMulti: !!(actionOpts != null && actionOpts.multi)
1235
- };
1236
- action.current = actionState;
1237
- action.latest = actionState;
1238
- action.submissions.push(actionState);
1239
- router.notify();
767
+ let query = decode(searchStr);
1240
768
 
1241
- try {
1242
- const res = await (route.options.action == null ? void 0 : route.options.action(submission));
1243
- actionState.data = res;
1244
-
1245
- if (invalidate) {
1246
- router.invalidateRoute({
1247
- to: '.',
1248
- fromCurrent: true
1249
- });
1250
- await router.reload();
769
+ // Try to parse any query params that might be json
770
+ for (let key in query) {
771
+ const value = query[key];
772
+ if (typeof value === 'string') {
773
+ try {
774
+ query[key] = parser(value);
775
+ } catch (err) {
776
+ //
1251
777
  }
1252
-
1253
- actionState.status = 'success';
1254
- return res;
1255
- } catch (err) {
1256
- console.error(err);
1257
- actionState.error = err;
1258
- actionState.status = 'error';
1259
- } finally {
1260
- router.notify();
1261
778
  }
1262
779
  }
780
+ return query;
1263
781
  };
1264
- return router.state.actions[id];
1265
- })();
1266
-
1267
- const loader = router.state.loaders[id] || (() => {
1268
- router.state.loaders[id] = {
1269
- pending: [],
1270
- fetch: async loaderContext => {
1271
- if (!route) {
1272
- return;
1273
- }
1274
-
1275
- const loaderState = {
1276
- loadedAt: Date.now(),
1277
- loaderContext
1278
- };
1279
- loader.current = loaderState;
1280
- loader.latest = loaderState;
1281
- loader.pending.push(loaderState); // router.state = {
1282
- // ...router.state,
1283
- // currentAction: loaderState,
1284
- // latestAction: loaderState,
1285
- // }
1286
-
1287
- router.notify();
1288
-
1289
- try {
1290
- return await (route.options.loader == null ? void 0 : route.options.loader(loaderContext));
1291
- } finally {
1292
- loader.pending = loader.pending.filter(d => d !== loaderState); // router.removeActionQueue.push({ loader, loaderState })
1293
-
1294
- router.notify();
1295
- }
1296
- }
1297
- };
1298
- return router.state.loaders[id];
1299
- })();
1300
-
1301
- let route = {
1302
- routeId: id,
1303
- routeRouteId: routeId,
1304
- routePath,
1305
- fullPath,
1306
- options,
1307
- router,
1308
- childRoutes: undefined,
1309
- parentRoute: parent,
1310
- action,
1311
- loader: loader,
1312
- buildLink: options => {
1313
- return router.buildLink(_extends({}, options, {
1314
- from: fullPath
1315
- }));
1316
- },
1317
- navigate: options => {
1318
- return router.navigate(_extends({}, options, {
1319
- from: fullPath
1320
- }));
1321
- },
1322
- matchRoute: (matchLocation, opts) => {
1323
- return router.matchRoute(_extends({}, matchLocation, {
1324
- from: fullPath
1325
- }), opts);
1326
- }
1327
- };
1328
- router.options.createRoute == null ? void 0 : router.options.createRoute({
1329
- router,
1330
- route
1331
- });
1332
- return route;
1333
- }
1334
-
1335
- const rootRouteId = '__root__';
1336
- const createRouteConfig = function createRouteConfig(options, children, isRoot, parentId, parentPath) {
1337
- if (options === void 0) {
1338
- options = {};
1339
- }
1340
-
1341
- if (isRoot === void 0) {
1342
- isRoot = true;
1343
- }
1344
-
1345
- if (isRoot) {
1346
- options.path = rootRouteId;
1347
- } // Strip the root from parentIds
1348
-
1349
-
1350
- if (parentId === rootRouteId) {
1351
- parentId = '';
1352
- }
1353
-
1354
- let path = isRoot ? rootRouteId : options.path; // If the path is anything other than an index path, trim it up
1355
-
1356
- if (path && path !== '/') {
1357
- path = trimPath(path);
1358
- }
1359
-
1360
- const routeId = path || options.id;
1361
- let id = joinPaths([parentId, routeId]);
1362
-
1363
- if (path === rootRouteId) {
1364
- path = '/';
1365
- }
1366
-
1367
- if (id !== rootRouteId) {
1368
- id = joinPaths(['/', id]);
1369
782
  }
1370
-
1371
- const fullPath = id === rootRouteId ? '/' : trimPathRight(joinPaths([parentPath, path]));
1372
- return {
1373
- id: id,
1374
- routeId: routeId,
1375
- path: path,
1376
- fullPath: fullPath,
1377
- options: options,
1378
- children,
1379
- createChildren: cb => createRouteConfig(options, cb(childOptions => createRouteConfig(childOptions, undefined, false, id, fullPath)), false, parentId, parentPath),
1380
- addChildren: children => createRouteConfig(options, children, false, parentId, parentPath),
1381
- createRoute: childOptions => createRouteConfig(childOptions, undefined, false, id, fullPath)
1382
- };
1383
- };
1384
-
1385
- const componentTypes = ['component', 'errorComponent', 'pendingComponent'];
1386
- function createRouteMatch(router, route, opts) {
1387
- const routeMatch = _extends({}, route, opts, {
1388
- router,
1389
- routeSearch: {},
1390
- search: {},
1391
- childMatches: [],
1392
- status: 'idle',
1393
- routeLoaderData: {},
1394
- loaderData: {},
1395
- isFetching: false,
1396
- isInvalid: false,
1397
- invalidAt: Infinity,
1398
- // pendingActions: [],
1399
- getIsInvalid: () => {
1400
- const now = Date.now();
1401
- return routeMatch.isInvalid || routeMatch.invalidAt < now;
1402
- },
1403
- __: {
1404
- abortController: new AbortController(),
1405
- latestId: '',
1406
- resolve: () => {},
1407
- notify: () => {
1408
- routeMatch.__.resolve();
1409
-
1410
- routeMatch.router.notify();
1411
- },
1412
- validate: () => {
1413
- var _routeMatch$parentMat, _routeMatch$parentMat2;
1414
-
1415
- // Validate the search params and stabilize them
1416
- const parentSearch = (_routeMatch$parentMat = (_routeMatch$parentMat2 = routeMatch.parentMatch) == null ? void 0 : _routeMatch$parentMat2.search) != null ? _routeMatch$parentMat : router.location.search;
1417
-
783
+ function stringifySearchWith(stringify, parser) {
784
+ function stringifyValue(val) {
785
+ if (typeof val === 'object' && val !== null) {
1418
786
  try {
1419
- var _validator;
1420
-
1421
- const prevSearch = routeMatch.routeSearch;
1422
- const validator = typeof routeMatch.options.validateSearch === 'object' ? routeMatch.options.validateSearch.parse : routeMatch.options.validateSearch;
1423
- let nextSearch = replaceEqualDeep(prevSearch, (_validator = validator == null ? void 0 : validator(parentSearch)) != null ? _validator : {}); // Invalidate route matches when search param stability changes
1424
-
1425
- if (prevSearch !== nextSearch) {
1426
- routeMatch.isInvalid = true;
1427
- }
1428
-
1429
- routeMatch.routeSearch = nextSearch;
1430
- routeMatch.search = replaceEqualDeep(parentSearch, _extends({}, parentSearch, nextSearch));
1431
- componentTypes.map(async type => {
1432
- const component = routeMatch.options[type];
1433
-
1434
- if (typeof routeMatch.__[type] !== 'function') {
1435
- routeMatch.__[type] = component;
1436
- }
1437
- });
787
+ return stringify(val);
1438
788
  } catch (err) {
1439
- console.error(err);
1440
- const error = new Error('Invalid search params found', {
1441
- cause: err
1442
- });
1443
- error.code = 'INVALID_SEARCH_PARAMS';
1444
- routeMatch.status = 'error';
1445
- routeMatch.error = error; // Do not proceed with loading the route
1446
-
1447
- return;
789
+ // silent
1448
790
  }
1449
- }
1450
- },
1451
- cancel: () => {
1452
- var _routeMatch$__$abortC;
1453
-
1454
- (_routeMatch$__$abortC = routeMatch.__.abortController) == null ? void 0 : _routeMatch$__$abortC.abort();
1455
- },
1456
- invalidate: () => {
1457
- routeMatch.isInvalid = true;
1458
- },
1459
- hasLoaders: () => {
1460
- return !!(route.options.loader || componentTypes.some(d => {
1461
- var _route$options$d;
1462
-
1463
- return (_route$options$d = route.options[d]) == null ? void 0 : _route$options$d.preload;
1464
- }));
1465
- },
1466
- load: async loaderOpts => {
1467
- const now = Date.now();
1468
- const minMaxAge = loaderOpts != null && loaderOpts.preload ? Math.max(loaderOpts == null ? void 0 : loaderOpts.maxAge, loaderOpts == null ? void 0 : loaderOpts.gcMaxAge) : 0; // If this is a preload, add it to the preload cache
1469
-
1470
- if (loaderOpts != null && loaderOpts.preload && minMaxAge > 0) {
1471
- // If the match is currently active, don't preload it
1472
- if (router.state.matches.find(d => d.matchId === routeMatch.matchId)) {
1473
- return;
791
+ } else if (typeof val === 'string' && typeof parser === 'function') {
792
+ try {
793
+ // Check if it's a valid parseable string.
794
+ // If it is, then stringify it again.
795
+ parser(val);
796
+ return stringify(val);
797
+ } catch (err) {
798
+ // silent
1474
799
  }
1475
-
1476
- router.matchCache[routeMatch.matchId] = {
1477
- gc: now + loaderOpts.gcMaxAge,
1478
- match: routeMatch
1479
- };
1480
- } // If the match is invalid, errored or idle, trigger it to load
1481
-
1482
-
1483
- if (routeMatch.status === 'success' && routeMatch.getIsInvalid() || routeMatch.status === 'error' || routeMatch.status === 'idle') {
1484
- const maxAge = loaderOpts != null && loaderOpts.preload ? loaderOpts == null ? void 0 : loaderOpts.maxAge : undefined;
1485
- await routeMatch.fetch({
1486
- maxAge
1487
- });
1488
800
  }
1489
- },
1490
- fetch: async opts => {
1491
- const loadId = '' + Date.now() + Math.random();
1492
- routeMatch.__.latestId = loadId;
1493
-
1494
- const checkLatest = async () => {
1495
- if (loadId !== routeMatch.__.latestId) {
1496
- // warning(true, 'Data loader is out of date!')
1497
- return new Promise(() => {});
1498
- }
1499
- }; // If the match was in an error state, set it
1500
- // to a loading state again. Otherwise, keep it
1501
- // as loading or resolved
1502
-
1503
-
1504
- if (routeMatch.status === 'idle') {
1505
- routeMatch.status = 'loading';
1506
- } // We started loading the route, so it's no longer invalid
1507
-
1508
-
1509
- routeMatch.isInvalid = false;
1510
- routeMatch.__.loadPromise = new Promise(async resolve => {
1511
- // We are now fetching, even if it's in the background of a
1512
- // resolved state
1513
- routeMatch.isFetching = true;
1514
- routeMatch.__.resolve = resolve;
1515
-
1516
- routeMatch.__.componentsPromise = (async () => {
1517
- // then run all component and data loaders in parallel
1518
- // For each component type, potentially load it asynchronously
1519
- await Promise.all(componentTypes.map(async type => {
1520
- var _routeMatch$__$type;
1521
-
1522
- const component = routeMatch.options[type];
1523
-
1524
- if ((_routeMatch$__$type = routeMatch.__[type]) != null && _routeMatch$__$type.preload) {
1525
- routeMatch.__[type] = await router.options.loadComponent(component);
1526
- }
1527
- }));
1528
- })();
1529
-
1530
- routeMatch.__.dataPromise = Promise.resolve().then(async () => {
1531
- try {
1532
- var _ref, _ref2, _opts$maxAge;
1533
-
1534
- if (routeMatch.options.loader) {
1535
- const data = await router.loadMatchData(routeMatch);
1536
- await checkLatest();
1537
- routeMatch.routeLoaderData = replaceEqualDeep(routeMatch.routeLoaderData, data);
1538
- }
1539
-
1540
- routeMatch.error = undefined;
1541
- routeMatch.status = 'success';
1542
- routeMatch.updatedAt = Date.now();
1543
- routeMatch.invalidAt = routeMatch.updatedAt + ((_ref = (_ref2 = (_opts$maxAge = opts == null ? void 0 : opts.maxAge) != null ? _opts$maxAge : routeMatch.options.loaderMaxAge) != null ? _ref2 : router.options.defaultLoaderMaxAge) != null ? _ref : 0);
1544
- return routeMatch.routeLoaderData;
1545
- } catch (err) {
1546
- await checkLatest();
1547
-
1548
- {
1549
- console.error(err);
1550
- }
1551
-
1552
- routeMatch.error = err;
1553
- routeMatch.status = 'error';
1554
- routeMatch.updatedAt = Date.now();
1555
- throw err;
801
+ return val;
802
+ }
803
+ return search => {
804
+ search = {
805
+ ...search
806
+ };
807
+ if (search) {
808
+ Object.keys(search).forEach(key => {
809
+ const val = search[key];
810
+ if (typeof val === 'undefined' || val === undefined) {
811
+ delete search[key];
812
+ } else {
813
+ search[key] = stringifyValue(val);
1556
814
  }
1557
815
  });
1558
-
1559
- const after = async () => {
1560
- await checkLatest();
1561
- routeMatch.isFetching = false;
1562
- delete routeMatch.__.loadPromise;
1563
-
1564
- routeMatch.__.notify();
1565
- };
1566
-
1567
- try {
1568
- await Promise.all([routeMatch.__.componentsPromise, routeMatch.__.dataPromise.catch(() => {})]);
1569
- after();
1570
- } catch (_unused) {
1571
- after();
1572
- }
1573
- });
1574
- await routeMatch.__.loadPromise;
1575
- await checkLatest();
1576
- }
1577
- });
1578
-
1579
- if (!routeMatch.hasLoaders()) {
1580
- routeMatch.status = 'success';
816
+ }
817
+ const searchStr = encode(search).toString();
818
+ return searchStr ? `?${searchStr}` : '';
819
+ };
1581
820
  }
1582
821
 
1583
- return routeMatch;
1584
- }
1585
-
1586
- const defaultParseSearch = parseSearchWith(JSON.parse);
1587
- const defaultStringifySearch = stringifySearchWith(JSON.stringify);
1588
- function parseSearchWith(parser) {
1589
- return searchStr => {
1590
- if (searchStr.substring(0, 1) === '?') {
1591
- searchStr = searchStr.substring(1);
1592
- }
1593
-
1594
- let query = decode(searchStr); // Try to parse any query params that might be json
1595
-
1596
- for (let key in query) {
1597
- const value = query[key];
1598
-
1599
- if (typeof value === 'string') {
1600
- try {
1601
- query[key] = parser(value);
1602
- } catch (err) {//
1603
- }
1604
- }
1605
- }
822
+ //
823
+
824
+ const componentTypes = ['component', 'errorComponent', 'pendingComponent'];
825
+ const visibilityChangeEvent = 'visibilitychange';
826
+ const focusEvent = 'focus';
827
+ const preloadWarning = 'Error preloading route! ☝️';
828
+ class Router {
829
+ #unsubHistory;
830
+ resetNextScroll = false;
831
+ tempLocationKey = `${Math.round(Math.random() * 10000000)}`;
832
+ // nextTemporaryLocation?: ParsedLocation<FullSearchSchema<TRouteTree>>
833
+
834
+ constructor(options) {
835
+ this.options = {
836
+ defaultPreloadDelay: 50,
837
+ context: undefined,
838
+ ...options,
839
+ stringifySearch: options?.stringifySearch ?? defaultStringifySearch,
840
+ parseSearch: options?.parseSearch ?? defaultParseSearch
841
+ // fetchServerDataFn: options?.fetchServerDataFn ?? defaultFetchServerDataFn,
842
+ };
1606
843
 
1607
- return query;
1608
- };
1609
- }
1610
- function stringifySearchWith(stringify) {
1611
- return search => {
1612
- search = _extends({}, search);
1613
-
1614
- if (search) {
1615
- Object.keys(search).forEach(key => {
1616
- const val = search[key];
1617
-
1618
- if (typeof val === 'undefined' || val === undefined) {
1619
- delete search[key];
1620
- } else if (val && typeof val === 'object' && val !== null) {
1621
- try {
1622
- search[key] = stringify(val);
1623
- } catch (err) {// silent
844
+ this.__store = new Store(getInitialRouterState(), {
845
+ onUpdate: () => {
846
+ const prev = this.state;
847
+ const next = this.__store.state;
848
+ const matchesByIdChanged = prev.matchesById !== next.matchesById;
849
+ let matchesChanged;
850
+ let pendingMatchesChanged;
851
+ if (!matchesByIdChanged) {
852
+ matchesChanged = prev.matchIds.length !== next.matchIds.length || prev.matchIds.some((d, i) => d !== next.matchIds[i]);
853
+ pendingMatchesChanged = prev.pendingMatchIds.length !== next.pendingMatchIds.length || prev.pendingMatchIds.some((d, i) => d !== next.pendingMatchIds[i]);
1624
854
  }
1625
- }
855
+ if (matchesByIdChanged || matchesChanged) {
856
+ next.matches = next.matchIds.map(id => {
857
+ return next.matchesById[id];
858
+ });
859
+ }
860
+ if (matchesByIdChanged || pendingMatchesChanged) {
861
+ next.pendingMatches = next.pendingMatchIds.map(id => {
862
+ return next.matchesById[id];
863
+ });
864
+ }
865
+ if (matchesByIdChanged || matchesChanged || pendingMatchesChanged) {
866
+ const hasPendingComponent = next.pendingMatches.some(d => {
867
+ const route = this.getRoute(d.routeId);
868
+ return !!route?.options.pendingComponent;
869
+ });
870
+ next.renderedMatchIds = hasPendingComponent ? next.pendingMatchIds : next.matchIds;
871
+ next.renderedMatches = next.renderedMatchIds.map(id => {
872
+ return next.matchesById[id];
873
+ });
874
+ }
875
+ next.isFetching = [...next.matches, ...next.pendingMatches].some(d => d.isFetching);
876
+ this.state = next;
877
+ },
878
+ defaultPriority: 'low'
879
+ });
880
+ this.state = this.__store.state;
881
+ this.update(options);
882
+ const nextLocation = this.buildLocation({
883
+ search: true,
884
+ params: true,
885
+ hash: true,
886
+ state: true
1626
887
  });
888
+ if (this.state.location.href !== nextLocation.href) {
889
+ this.#commitLocation({
890
+ ...nextLocation,
891
+ replace: true
892
+ });
893
+ }
1627
894
  }
1628
-
1629
- const searchStr = encode(search).toString();
1630
- return searchStr ? "?" + searchStr : '';
1631
- };
1632
- }
1633
-
1634
- var _window$document;
1635
- // Detect if we're in the DOM
1636
- const isServer = typeof window === 'undefined' || !((_window$document = window.document) != null && _window$document.createElement); // This is the default history object if none is defined
1637
-
1638
- const createDefaultHistory = () => isServer ? createMemoryHistory() : createBrowserHistory();
1639
-
1640
- function getInitialRouterState() {
1641
- return {
1642
- status: 'idle',
1643
- location: null,
1644
- matches: [],
1645
- actions: {},
1646
- loaders: {},
1647
- lastUpdated: Date.now(),
1648
- isFetching: false,
1649
- isPreloading: false
1650
- };
1651
- }
1652
-
1653
- function createRouter(userOptions) {
1654
- var _userOptions$stringif, _userOptions$parseSea;
1655
-
1656
- const history = (userOptions == null ? void 0 : userOptions.history) || createDefaultHistory();
1657
-
1658
- const originalOptions = _extends({
1659
- defaultLoaderGcMaxAge: 5 * 60 * 1000,
1660
- defaultLoaderMaxAge: 0,
1661
- defaultPreloadMaxAge: 2000,
1662
- defaultPreloadDelay: 50
1663
- }, userOptions, {
1664
- stringifySearch: (_userOptions$stringif = userOptions == null ? void 0 : userOptions.stringifySearch) != null ? _userOptions$stringif : defaultStringifySearch,
1665
- parseSearch: (_userOptions$parseSea = userOptions == null ? void 0 : userOptions.parseSearch) != null ? _userOptions$parseSea : defaultParseSearch
1666
- });
1667
-
1668
- let router = {
1669
- types: undefined,
1670
- // public api
1671
- history,
1672
- options: originalOptions,
1673
- listeners: [],
1674
- // Resolved after construction
1675
- basepath: '',
1676
- routeTree: undefined,
1677
- routesById: {},
1678
- location: undefined,
1679
- //
1680
- navigationPromise: Promise.resolve(),
1681
- resolveNavigation: () => {},
1682
- matchCache: {},
1683
- state: getInitialRouterState(),
1684
- reset: () => {
1685
- router.state = getInitialRouterState();
1686
- router.notify();
1687
- },
1688
- startedLoadingAt: Date.now(),
1689
- subscribe: listener => {
1690
- router.listeners.push(listener);
895
+ subscribers = new Set();
896
+ subscribe = (eventType, fn) => {
897
+ const listener = {
898
+ eventType,
899
+ fn
900
+ };
901
+ this.subscribers.add(listener);
1691
902
  return () => {
1692
- router.listeners = router.listeners.filter(x => x !== listener);
903
+ this.subscribers.delete(listener);
1693
904
  };
1694
- },
1695
- getRoute: id => {
1696
- return router.routesById[id];
1697
- },
1698
- notify: () => {
1699
- const isFetching = router.state.status === 'loading' || router.state.matches.some(d => d.isFetching);
1700
- const isPreloading = Object.values(router.matchCache).some(d => d.match.isFetching && !router.state.matches.find(dd => dd.matchId === d.match.matchId));
1701
-
1702
- if (router.state.isFetching !== isFetching || router.state.isPreloading !== isPreloading) {
1703
- router.state = _extends({}, router.state, {
1704
- isFetching,
1705
- isPreloading
1706
- });
1707
- }
1708
-
1709
- cascadeLoaderData(router.state.matches);
1710
- router.listeners.forEach(listener => listener(router));
1711
- },
1712
- dehydrateState: () => {
1713
- return _extends({}, pick(router.state, ['status', 'location', 'lastUpdated']), {
1714
- matches: router.state.matches.map(match => pick(match, ['matchId', 'status', 'routeLoaderData', 'loaderData', 'isInvalid', 'invalidAt']))
1715
- });
1716
- },
1717
- hydrateState: dehydratedState => {
1718
- // Match the routes
1719
- const matches = router.matchRoutes(router.location.pathname, {
1720
- strictParseParams: true
1721
- });
1722
- matches.forEach((match, index) => {
1723
- const dehydratedMatch = dehydratedState.matches[index];
1724
- invariant(dehydratedMatch, 'Oh no! Dehydrated route matches did not match the active state of the router 😬');
1725
- Object.assign(match, dehydratedMatch);
1726
- });
1727
- matches.forEach(match => match.__.validate());
1728
- router.state = _extends({}, router.state, dehydratedState, {
1729
- matches
905
+ };
906
+ #emit = routerEvent => {
907
+ this.subscribers.forEach(listener => {
908
+ if (listener.eventType === routerEvent.type) {
909
+ listener.fn(routerEvent);
910
+ }
1730
911
  });
1731
- },
1732
- mount: () => {
1733
- const next = router.__.buildLocation({
1734
- to: '.',
1735
- search: true,
1736
- hash: true
1737
- }); // If the current location isn't updated, trigger a navigation
1738
- // to the current location. Otherwise, load the current location.
1739
-
1740
-
1741
- if (next.href !== router.location.href) {
1742
- router.__.commitLocation(next, true);
1743
- }
1744
-
1745
- if (!router.state.matches.length) {
1746
- router.load();
1747
- }
1748
-
1749
- const unsub = router.history.listen(event => {
1750
- router.load(router.__.parseLocation(event.location, router.location));
1751
- }); // addEventListener does not exist in React Native, but window does
912
+ };
913
+ reset = () => {
914
+ this.__store.setState(s => Object.assign(s, getInitialRouterState()));
915
+ };
916
+ mount = () => {
917
+ // addEventListener does not exist in React Native, but window does
918
+ // In the future, we might need to invert control here for more adapters
1752
919
  // eslint-disable-next-line @typescript-eslint/no-unnecessary-condition
1753
-
1754
- if (!isServer && window.addEventListener) {
1755
- // Listen to visibillitychange and focus
1756
- window.addEventListener('visibilitychange', router.onFocus, false);
1757
- window.addEventListener('focus', router.onFocus, false);
920
+ if (typeof window !== 'undefined' && window.addEventListener) {
921
+ window.addEventListener(visibilityChangeEvent, this.#onFocus, false);
922
+ window.addEventListener(focusEvent, this.#onFocus, false);
1758
923
  }
1759
-
924
+ this.safeLoad();
1760
925
  return () => {
1761
- unsub();
1762
-
1763
- if (!isServer && window.removeEventListener) {
1764
- // Be sure to unsubscribe if a new handler is set
1765
- window.removeEventListener('visibilitychange', router.onFocus);
1766
- window.removeEventListener('focus', router.onFocus);
926
+ if (typeof window !== 'undefined' && window.removeEventListener) {
927
+ window.removeEventListener(visibilityChangeEvent, this.#onFocus);
928
+ window.removeEventListener(focusEvent, this.#onFocus);
1767
929
  }
1768
930
  };
1769
- },
1770
- onFocus: () => {
1771
- router.load();
1772
- },
1773
- update: opts => {
1774
- const newHistory = (opts == null ? void 0 : opts.history) !== router.history;
1775
-
1776
- if (!router.location || newHistory) {
1777
- if (opts != null && opts.history) {
1778
- router.history = opts.history;
931
+ };
932
+ #onFocus = () => {
933
+ if (this.options.reloadOnWindowFocus ?? true) {
934
+ this.invalidate({
935
+ __fromFocus: true
936
+ });
937
+ }
938
+ };
939
+ update = opts => {
940
+ this.options = {
941
+ ...this.options,
942
+ ...opts,
943
+ context: {
944
+ ...this.options.context,
945
+ ...opts?.context
1779
946
  }
1780
-
1781
- router.location = router.__.parseLocation(router.history.location);
1782
- router.state.location = router.location;
947
+ };
948
+ if (!this.history || this.options.history && this.options.history !== this.history) {
949
+ if (this.#unsubHistory) {
950
+ this.#unsubHistory();
951
+ }
952
+ this.history = this.options.history ?? (isServer ? createMemoryHistory() : createBrowserHistory());
953
+ const parsedLocation = this.#parseLocation();
954
+ this.__store.setState(s => ({
955
+ ...s,
956
+ resolvedLocation: parsedLocation,
957
+ location: parsedLocation
958
+ }));
959
+ this.#unsubHistory = this.history.subscribe(() => {
960
+ this.safeLoad({
961
+ next: this.#parseLocation(this.state.location)
962
+ });
963
+ });
1783
964
  }
1784
-
1785
- Object.assign(router.options, opts);
1786
965
  const {
1787
966
  basepath,
1788
- routeConfig
1789
- } = router.options;
1790
- router.basepath = cleanPath("/" + (basepath != null ? basepath : ''));
1791
-
1792
- if (routeConfig) {
1793
- router.routesById = {};
1794
- router.routeTree = router.__.buildRouteTree(routeConfig);
967
+ routeTree
968
+ } = this.options;
969
+ this.basepath = `/${trimPath(basepath ?? '') ?? ''}`;
970
+ if (routeTree && routeTree !== this.routeTree) {
971
+ this.#processRoutes(routeTree);
1795
972
  }
1796
-
1797
- return router;
1798
- },
1799
- cancelMatches: () => {
1800
- var _router$state$pending, _router$state$pending2;
1801
- [...router.state.matches, ...((_router$state$pending = (_router$state$pending2 = router.state.pending) == null ? void 0 : _router$state$pending2.matches) != null ? _router$state$pending : [])].forEach(match => {
1802
- match.cancel();
1803
- });
1804
- },
1805
- load: async next => {
1806
- const id = Math.random();
1807
- router.startedLoadingAt = id;
1808
-
1809
- if (next) {
1810
- // Ingest the new location
1811
- router.location = next;
1812
- } // Cancel any pending matches
1813
-
1814
-
1815
- router.cancelMatches(); // Match the routes
1816
-
1817
- const matches = router.matchRoutes(router.location.pathname, {
1818
- strictParseParams: true
973
+ return this;
974
+ };
975
+ cancelMatches = () => {
976
+ this.state.matches.forEach(match => {
977
+ this.cancelMatch(match.id);
1819
978
  });
1820
-
1821
- if (typeof document !== 'undefined') {
1822
- router.state = _extends({}, router.state, {
1823
- pending: {
1824
- matches: matches,
1825
- location: router.location
1826
- },
1827
- status: 'loading'
1828
- });
1829
- } else {
1830
- router.state = _extends({}, router.state, {
1831
- matches: matches,
1832
- location: router.location,
1833
- status: 'loading'
1834
- });
979
+ };
980
+ cancelMatch = id => {
981
+ this.getRouteMatch(id)?.abortController?.abort();
982
+ };
983
+ safeLoad = async opts => {
984
+ try {
985
+ return this.load(opts);
986
+ } catch (err) {
987
+ // Don't do anything
1835
988
  }
989
+ };
990
+ latestLoadPromise = Promise.resolve();
991
+ load = async opts => {
992
+ const promise = new Promise(async (resolve, reject) => {
993
+ const prevLocation = this.state.resolvedLocation;
994
+ const pathDidChange = !!(opts?.next && prevLocation.href !== opts.next.href);
995
+ let latestPromise;
996
+ const checkLatest = () => {
997
+ return this.latestLoadPromise !== promise ? this.latestLoadPromise : undefined;
998
+ };
1836
999
 
1837
- router.notify(); // Load the matches
1000
+ // Cancel any pending matches
1838
1001
 
1839
- await router.loadMatches(matches);
1002
+ let pendingMatches;
1003
+ this.#emit({
1004
+ type: 'onBeforeLoad',
1005
+ from: prevLocation,
1006
+ to: opts?.next ?? this.state.location,
1007
+ pathChanged: pathDidChange
1008
+ });
1009
+ this.__store.batch(() => {
1010
+ if (opts?.next) {
1011
+ // Ingest the new location
1012
+ this.__store.setState(s => ({
1013
+ ...s,
1014
+ location: opts.next
1015
+ }));
1016
+ }
1840
1017
 
1841
- if (router.startedLoadingAt !== id) {
1842
- // Ignore side-effects of match loading
1843
- return router.navigationPromise;
1844
- }
1018
+ // Match the routes
1019
+ pendingMatches = this.matchRoutes(this.state.location.pathname, this.state.location.search, {
1020
+ throwOnError: opts?.throwOnError,
1021
+ debug: true
1022
+ });
1023
+ this.__store.setState(s => ({
1024
+ ...s,
1025
+ status: 'pending',
1026
+ pendingMatchIds: pendingMatches.map(d => d.id),
1027
+ matchesById: this.#mergeMatches(s.matchesById, pendingMatches)
1028
+ }));
1029
+ });
1030
+ try {
1031
+ // Load the matches
1032
+ try {
1033
+ await this.loadMatches(pendingMatches.map(d => d.id));
1034
+ } catch (err) {
1035
+ // swallow this error, since we'll display the
1036
+ // errors on the route components
1037
+ }
1845
1038
 
1846
- const previousMatches = router.state.matches;
1847
- const exiting = [],
1848
- staying = [];
1849
- previousMatches.forEach(d => {
1850
- if (matches.find(dd => dd.matchId === d.matchId)) {
1851
- staying.push(d);
1852
- } else {
1853
- exiting.push(d);
1039
+ // Only apply the latest transition
1040
+ if (latestPromise = checkLatest()) {
1041
+ return latestPromise;
1042
+ }
1043
+ const exitingMatchIds = this.state.matchIds.filter(id => !this.state.pendingMatchIds.includes(id));
1044
+ const enteringMatchIds = this.state.pendingMatchIds.filter(id => !this.state.matchIds.includes(id));
1045
+ const stayingMatchIds = this.state.matchIds.filter(id => this.state.pendingMatchIds.includes(id));
1046
+ this.__store.setState(s => ({
1047
+ ...s,
1048
+ status: 'idle',
1049
+ resolvedLocation: s.location,
1050
+ matchIds: s.pendingMatchIds,
1051
+ pendingMatchIds: []
1052
+ }));
1053
+ [[exitingMatchIds, 'onLeave'], [enteringMatchIds, 'onEnter'], [stayingMatchIds, 'onTransition']].forEach(([matchIds, hook]) => {
1054
+ matchIds.forEach(id => {
1055
+ const match = this.getRouteMatch(id);
1056
+ const route = this.getRoute(match.routeId);
1057
+ route.options[hook]?.(match);
1058
+ });
1059
+ });
1060
+ this.#emit({
1061
+ type: 'onLoad',
1062
+ from: prevLocation,
1063
+ to: this.state.location,
1064
+ pathChanged: pathDidChange
1065
+ });
1066
+ resolve();
1067
+ } catch (err) {
1068
+ // Only apply the latest transition
1069
+ if (latestPromise = checkLatest()) {
1070
+ return latestPromise;
1071
+ }
1072
+ reject(err);
1854
1073
  }
1855
1074
  });
1856
- const entering = matches.filter(d => {
1857
- return !previousMatches.find(dd => dd.matchId === d.matchId);
1075
+ this.latestLoadPromise = promise;
1076
+ this.latestLoadPromise.then(() => {
1077
+ this.cleanMatches();
1858
1078
  });
1859
- const now = Date.now();
1860
- exiting.forEach(d => {
1861
- var _ref, _d$options$loaderGcMa, _ref2, _d$options$loaderMaxA;
1862
-
1863
- d.__.onExit == null ? void 0 : d.__.onExit({
1864
- params: d.params,
1865
- search: d.routeSearch
1866
- }); // Clear idle error states when match leaves
1867
-
1868
- if (d.status === 'error' && !d.isFetching) {
1869
- d.status = 'idle';
1870
- d.error = undefined;
1871
- }
1872
-
1873
- const gc = Math.max((_ref = (_d$options$loaderGcMa = d.options.loaderGcMaxAge) != null ? _d$options$loaderGcMa : router.options.defaultLoaderGcMaxAge) != null ? _ref : 0, (_ref2 = (_d$options$loaderMaxA = d.options.loaderMaxAge) != null ? _d$options$loaderMaxA : router.options.defaultLoaderMaxAge) != null ? _ref2 : 0);
1874
-
1875
- if (gc > 0) {
1876
- router.matchCache[d.matchId] = {
1877
- gc: gc == Infinity ? Number.MAX_SAFE_INTEGER : now + gc,
1878
- match: d
1879
- };
1079
+ return this.latestLoadPromise;
1080
+ };
1081
+ #mergeMatches = (prevMatchesById, nextMatches) => {
1082
+ let matchesById = {
1083
+ ...prevMatchesById
1084
+ };
1085
+ nextMatches.forEach(match => {
1086
+ if (!matchesById[match.id]) {
1087
+ matchesById[match.id] = match;
1880
1088
  }
1089
+ matchesById[match.id] = {
1090
+ ...matchesById[match.id],
1091
+ ...match
1092
+ };
1881
1093
  });
1882
- staying.forEach(d => {
1883
- d.options.onTransition == null ? void 0 : d.options.onTransition({
1884
- params: d.params,
1885
- search: d.routeSearch
1886
- });
1887
- });
1888
- entering.forEach(d => {
1889
- d.__.onExit = d.options.onMatch == null ? void 0 : d.options.onMatch({
1890
- params: d.params,
1891
- search: d.search
1892
- });
1893
- delete router.matchCache[d.matchId];
1094
+ return matchesById;
1095
+ };
1096
+ getRoute = id => {
1097
+ const route = this.routesById[id];
1098
+ invariant(route, `Route with id "${id}" not found`);
1099
+ return route;
1100
+ };
1101
+ preloadRoute = async (navigateOpts = this.state.location) => {
1102
+ let next = this.buildLocation(navigateOpts);
1103
+ const matches = this.matchRoutes(next.pathname, next.search, {
1104
+ throwOnError: true
1894
1105
  });
1895
-
1896
- if (router.startedLoadingAt !== id) {
1897
- // Ignore side-effects of match loading
1898
- return;
1899
- }
1900
-
1901
- matches.forEach(match => {
1902
- // Clear actions
1903
- if (match.action) {
1904
- match.action.current = undefined;
1905
- match.action.submissions = [];
1906
- }
1106
+ this.__store.setState(s => {
1107
+ return {
1108
+ ...s,
1109
+ matchesById: this.#mergeMatches(s.matchesById, matches)
1110
+ };
1907
1111
  });
1908
- router.state = _extends({}, router.state, {
1909
- location: router.location,
1910
- matches,
1911
- pending: undefined,
1912
- status: 'idle'
1112
+ await this.loadMatches(matches.map(d => d.id), {
1113
+ preload: true,
1114
+ maxAge: navigateOpts.maxAge
1913
1115
  });
1914
- router.notify();
1915
- router.resolveNavigation();
1916
- },
1917
- cleanMatchCache: () => {
1116
+ return [last(matches), matches];
1117
+ };
1118
+ cleanMatches = () => {
1918
1119
  const now = Date.now();
1919
- Object.keys(router.matchCache).forEach(matchId => {
1920
- const entry = router.matchCache[matchId]; // Don't remove loading matches
1921
-
1922
- if (entry.match.status === 'loading') {
1923
- return;
1924
- } // Do not remove successful matches that are still valid
1925
-
1926
-
1927
- if (entry.gc > 0 && entry.gc > now) {
1928
- return;
1929
- } // Everything else gets removed
1930
-
1931
-
1932
- delete router.matchCache[matchId];
1933
- });
1934
- },
1935
- loadRoute: async function loadRoute(navigateOpts) {
1936
- if (navigateOpts === void 0) {
1937
- navigateOpts = router.location;
1938
- }
1939
-
1940
- const next = router.buildNext(navigateOpts);
1941
- const matches = router.matchRoutes(next.pathname, {
1942
- strictParseParams: true
1943
- });
1944
- await router.loadMatches(matches);
1945
- return matches;
1946
- },
1947
- preloadRoute: async function preloadRoute(navigateOpts, loaderOpts) {
1948
- var _ref3, _ref4, _loaderOpts$maxAge, _ref5, _ref6, _loaderOpts$gcMaxAge;
1949
-
1950
- if (navigateOpts === void 0) {
1951
- navigateOpts = router.location;
1120
+ const outdatedMatchIds = Object.values(this.state.matchesById).filter(match => {
1121
+ const route = this.getRoute(match.routeId);
1122
+ return !this.state.matchIds.includes(match.id) && !this.state.pendingMatchIds.includes(match.id) && (match.preloadMaxAge > -1 ? match.updatedAt + match.preloadMaxAge < now : true) && (route.options.gcMaxAge ? match.updatedAt + route.options.gcMaxAge < now : true);
1123
+ }).map(d => d.id);
1124
+ if (outdatedMatchIds.length) {
1125
+ this.__store.setState(s => {
1126
+ const matchesById = {
1127
+ ...s.matchesById
1128
+ };
1129
+ outdatedMatchIds.forEach(id => {
1130
+ delete matchesById[id];
1131
+ });
1132
+ return {
1133
+ ...s,
1134
+ matchesById
1135
+ };
1136
+ });
1952
1137
  }
1953
-
1954
- const next = router.buildNext(navigateOpts);
1955
- const matches = router.matchRoutes(next.pathname, {
1956
- strictParseParams: true
1957
- });
1958
- await router.loadMatches(matches, {
1959
- preload: true,
1960
- maxAge: (_ref3 = (_ref4 = (_loaderOpts$maxAge = loaderOpts.maxAge) != null ? _loaderOpts$maxAge : router.options.defaultPreloadMaxAge) != null ? _ref4 : router.options.defaultLoaderMaxAge) != null ? _ref3 : 0,
1961
- gcMaxAge: (_ref5 = (_ref6 = (_loaderOpts$gcMaxAge = loaderOpts.gcMaxAge) != null ? _loaderOpts$gcMaxAge : router.options.defaultPreloadGcMaxAge) != null ? _ref6 : router.options.defaultLoaderGcMaxAge) != null ? _ref5 : 0
1138
+ };
1139
+ matchRoutes = (pathname, locationSearch, opts) => {
1140
+ let routeParams = {};
1141
+ let foundRoute = this.flatRoutes.find(route => {
1142
+ const matchedParams = matchPathname(this.basepath, trimPathRight(pathname), {
1143
+ to: route.fullPath,
1144
+ caseSensitive: route.options.caseSensitive ?? this.options.caseSensitive
1145
+ });
1146
+ if (matchedParams) {
1147
+ routeParams = matchedParams;
1148
+ return true;
1149
+ }
1150
+ return false;
1962
1151
  });
1963
- return matches;
1964
- },
1965
- matchRoutes: (pathname, opts) => {
1966
- var _router$state$pending3, _router$state$pending4;
1967
-
1968
- router.cleanMatchCache();
1969
- const matches = [];
1970
-
1971
- if (!router.routeTree) {
1972
- return matches;
1152
+ let routeCursor = foundRoute || this.routesById['__root__'];
1153
+ let matchedRoutes = [routeCursor];
1154
+ // let includingLayouts = true
1155
+ while (routeCursor?.parentRoute) {
1156
+ routeCursor = routeCursor.parentRoute;
1157
+ if (routeCursor) matchedRoutes.unshift(routeCursor);
1973
1158
  }
1974
1159
 
1975
- const existingMatches = [...router.state.matches, ...((_router$state$pending3 = (_router$state$pending4 = router.state.pending) == null ? void 0 : _router$state$pending4.matches) != null ? _router$state$pending3 : [])];
1976
-
1977
- const recurse = async routes => {
1978
- var _parentMatch$params, _router$options$filte, _foundRoute$childRout;
1160
+ // Existing matches are matches that are already loaded along with
1161
+ // pending matches that are still loading
1979
1162
 
1980
- const parentMatch = last(matches);
1981
- let params = (_parentMatch$params = parentMatch == null ? void 0 : parentMatch.params) != null ? _parentMatch$params : {};
1982
- const filteredRoutes = (_router$options$filte = router.options.filterRoutes == null ? void 0 : router.options.filterRoutes(routes)) != null ? _router$options$filte : routes;
1983
- let foundRoutes = [];
1984
-
1985
- const findMatchInRoutes = (parentRoutes, routes) => {
1986
- routes.some(route => {
1987
- var _route$childRoutes, _route$childRoutes2, _route$options$caseSe;
1988
-
1989
- if (!route.routePath && (_route$childRoutes = route.childRoutes) != null && _route$childRoutes.length) {
1990
- return findMatchInRoutes([...foundRoutes, route], route.childRoutes);
1991
- }
1992
-
1993
- const fuzzy = !!(route.routePath !== '/' || (_route$childRoutes2 = route.childRoutes) != null && _route$childRoutes2.length);
1994
- const matchParams = matchPathname(pathname, {
1995
- to: route.fullPath,
1996
- fuzzy,
1997
- caseSensitive: (_route$options$caseSe = route.options.caseSensitive) != null ? _route$options$caseSe : router.options.caseSensitive
1163
+ const parseErrors = matchedRoutes.map(route => {
1164
+ let parsedParamsError;
1165
+ if (route.options.parseParams) {
1166
+ try {
1167
+ const parsedParams = route.options.parseParams(routeParams);
1168
+ // Add the parsed params to the accumulated params bag
1169
+ Object.assign(routeParams, parsedParams);
1170
+ } catch (err) {
1171
+ parsedParamsError = new PathParamError(err.message, {
1172
+ cause: err
1998
1173
  });
1999
-
2000
- if (matchParams) {
2001
- let parsedParams;
2002
-
2003
- try {
2004
- var _route$options$parseP;
2005
-
2006
- parsedParams = (_route$options$parseP = route.options.parseParams == null ? void 0 : route.options.parseParams(matchParams)) != null ? _route$options$parseP : matchParams;
2007
- } catch (err) {
2008
- if (opts != null && opts.strictParseParams) {
2009
- throw err;
2010
- }
2011
- }
2012
-
2013
- params = _extends({}, params, parsedParams);
2014
- }
2015
-
2016
- if (!!matchParams) {
2017
- foundRoutes = [...parentRoutes, route];
1174
+ if (opts?.throwOnError) {
1175
+ throw parsedParamsError;
2018
1176
  }
2019
-
2020
- return !!foundRoutes.length;
2021
- });
2022
- return !!foundRoutes.length;
2023
- };
2024
-
2025
- findMatchInRoutes([], filteredRoutes);
2026
-
2027
- if (!foundRoutes.length) {
2028
- return;
2029
- }
2030
-
2031
- foundRoutes.forEach(foundRoute => {
2032
- var _router$matchCache$ma;
2033
-
2034
- const interpolatedPath = interpolatePath(foundRoute.routePath, params);
2035
- const matchId = interpolatePath(foundRoute.routeId, params, true);
2036
- const match = existingMatches.find(d => d.matchId === matchId) || ((_router$matchCache$ma = router.matchCache[matchId]) == null ? void 0 : _router$matchCache$ma.match) || createRouteMatch(router, foundRoute, {
2037
- parentMatch,
2038
- matchId,
2039
- params,
2040
- pathname: joinPaths([pathname, interpolatedPath])
2041
- });
2042
- matches.push(match);
2043
- });
2044
- const foundRoute = last(foundRoutes);
2045
-
2046
- if ((_foundRoute$childRout = foundRoute.childRoutes) != null && _foundRoute$childRout.length) {
2047
- recurse(foundRoute.childRoutes);
1177
+ return parsedParamsError;
1178
+ }
2048
1179
  }
2049
- };
2050
-
2051
- recurse([router.routeTree]);
2052
- cascadeLoaderData(matches);
2053
- return matches;
2054
- },
2055
- loadMatches: async (resolvedMatches, loaderOpts) => {
2056
- const matchPromises = resolvedMatches.map(async match => {
2057
- // Validate the match (loads search params etc)
2058
- match.__.validate();
2059
-
2060
- match.load(loaderOpts);
2061
- const search = match.search;
2062
-
2063
- if (search.__data && search.__data.matchId !== match.matchId) {
2064
- return;
1180
+ return;
1181
+ });
1182
+ const matches = matchedRoutes.map((route, index) => {
1183
+ const interpolatedPath = interpolatePath(route.path, routeParams);
1184
+ const key = route.options.key ? route.options.key({
1185
+ params: routeParams,
1186
+ search: locationSearch
1187
+ }) ?? '' : '';
1188
+ const stringifiedKey = key ? JSON.stringify(key) : '';
1189
+ const matchId = interpolatePath(route.id, routeParams, true) + stringifiedKey;
1190
+
1191
+ // Waste not, want not. If we already have a match for this route,
1192
+ // reuse it. This is important for layout routes, which might stick
1193
+ // around between navigation actions that only change leaf routes.
1194
+ const existingMatch = this.getRouteMatch(matchId);
1195
+ if (existingMatch) {
1196
+ return {
1197
+ ...existingMatch
1198
+ };
2065
1199
  }
2066
1200
 
2067
- if (match.__.loadPromise) {
2068
- // Wait for the first sign of activity from the match
2069
- await match.__.loadPromise;
2070
- }
1201
+ // Create a fresh route match
1202
+ const hasLoaders = !!(route.options.loader || componentTypes.some(d => route.options[d]?.preload));
1203
+ const routeMatch = {
1204
+ id: matchId,
1205
+ key: stringifiedKey,
1206
+ routeId: route.id,
1207
+ params: routeParams,
1208
+ pathname: joinPaths([this.basepath, interpolatedPath]),
1209
+ updatedAt: Date.now(),
1210
+ maxAge: -1,
1211
+ preloadMaxAge: -1,
1212
+ routeSearch: {},
1213
+ search: {},
1214
+ status: hasLoaders ? 'pending' : 'success',
1215
+ isFetching: false,
1216
+ invalid: false,
1217
+ error: undefined,
1218
+ paramsError: parseErrors[index],
1219
+ searchError: undefined,
1220
+ loaderData: undefined,
1221
+ loadPromise: Promise.resolve(),
1222
+ routeContext: undefined,
1223
+ context: undefined,
1224
+ abortController: new AbortController(),
1225
+ fetchedAt: 0
1226
+ };
1227
+ return routeMatch;
2071
1228
  });
2072
- router.notify();
2073
- await Promise.all(matchPromises);
2074
- },
2075
- loadMatchData: async routeMatch => {
2076
- if (isServer || !router.options.useServerData) {
2077
- var _await$routeMatch$opt;
2078
-
2079
- return (_await$routeMatch$opt = await (routeMatch.options.loader == null ? void 0 : routeMatch.options.loader({
2080
- // parentLoaderPromise: routeMatch.parentMatch?.__.dataPromise,
2081
- params: routeMatch.params,
2082
- search: routeMatch.routeSearch,
2083
- signal: routeMatch.__.abortController.signal
2084
- }))) != null ? _await$routeMatch$opt : {};
2085
- } else {
2086
- const next = router.buildNext({
2087
- to: '.',
2088
- search: d => _extends({}, d != null ? d : {}, {
2089
- __data: {
2090
- matchId: routeMatch.matchId
2091
- }
2092
- })
2093
- });
2094
- const res = await fetch(next.href, {
2095
- method: 'GET' // signal: routeMatch.__.abortController.signal,
2096
1229
 
1230
+ // Take each match and resolve its search params and context
1231
+ // This has to happen after the matches are created or found
1232
+ // so that we can use the parent match's search params and context
1233
+ matches.forEach((match, i) => {
1234
+ const parentMatch = matches[i - 1];
1235
+ const route = this.getRoute(match.routeId);
1236
+ const searchInfo = (() => {
1237
+ // Validate the search params and stabilize them
1238
+ const parentSearchInfo = {
1239
+ search: parentMatch?.search ?? locationSearch,
1240
+ routeSearch: parentMatch?.routeSearch ?? locationSearch
1241
+ };
1242
+ try {
1243
+ const validator = typeof route.options.validateSearch === 'object' ? route.options.validateSearch.parse : route.options.validateSearch;
1244
+ let routeSearch = validator?.(parentSearchInfo.search) ?? {};
1245
+ let search = {
1246
+ ...parentSearchInfo.search,
1247
+ ...routeSearch
1248
+ };
1249
+ routeSearch = replaceEqualDeep(match.routeSearch, routeSearch);
1250
+ search = replaceEqualDeep(match.search, search);
1251
+ return {
1252
+ routeSearch,
1253
+ search,
1254
+ searchDidChange: match.routeSearch !== routeSearch
1255
+ };
1256
+ } catch (err) {
1257
+ match.searchError = new SearchParamError(err.message, {
1258
+ cause: err
1259
+ });
1260
+ if (opts?.throwOnError) {
1261
+ throw match.searchError;
1262
+ }
1263
+ return parentSearchInfo;
1264
+ }
1265
+ })();
1266
+ Object.assign(match, searchInfo);
1267
+ });
1268
+ return matches;
1269
+ };
1270
+ loadMatches = async (matchIds, opts) => {
1271
+ const getFreshMatches = () => matchIds.map(d => this.getRouteMatch(d));
1272
+ if (!opts?.preload) {
1273
+ getFreshMatches().forEach(match => {
1274
+ // Update each match with its latest route data
1275
+ this.setRouteMatch(match.id, s => ({
1276
+ ...s,
1277
+ routeSearch: match.routeSearch,
1278
+ search: match.search,
1279
+ routeContext: match.routeContext,
1280
+ context: match.context,
1281
+ error: match.error,
1282
+ paramsError: match.paramsError,
1283
+ searchError: match.searchError,
1284
+ params: match.params,
1285
+ preloadMaxAge: 0
1286
+ }));
2097
1287
  });
1288
+ }
1289
+ let firstBadMatchIndex;
2098
1290
 
2099
- if (res.ok) {
2100
- return res.json();
2101
- }
1291
+ // Check each match middleware to see if the route can be accessed
1292
+ try {
1293
+ for (const [index, match] of getFreshMatches().entries()) {
1294
+ const parentMatch = getFreshMatches()[index - 1];
1295
+ const route = this.getRoute(match.routeId);
1296
+ const handleError = (err, code) => {
1297
+ err.routerCode = code;
1298
+ firstBadMatchIndex = firstBadMatchIndex ?? index;
1299
+ if (isRedirect(err)) {
1300
+ throw err;
1301
+ }
1302
+ try {
1303
+ route.options.onError?.(err);
1304
+ } catch (errorHandlerErr) {
1305
+ err = errorHandlerErr;
1306
+ if (isRedirect(errorHandlerErr)) {
1307
+ throw errorHandlerErr;
1308
+ }
1309
+ }
1310
+ this.setRouteMatch(match.id, s => ({
1311
+ ...s,
1312
+ error: err,
1313
+ status: 'error',
1314
+ updatedAt: Date.now()
1315
+ }));
1316
+ };
1317
+ if (match.paramsError) {
1318
+ handleError(match.paramsError, 'PARSE_PARAMS');
1319
+ }
1320
+ if (match.searchError) {
1321
+ handleError(match.searchError, 'VALIDATE_SEARCH');
1322
+ }
1323
+ let didError = false;
1324
+ try {
1325
+ const routeContext = (await route.options.beforeLoad?.({
1326
+ ...match,
1327
+ preload: !!opts?.preload,
1328
+ parentContext: parentMatch?.routeContext ?? {},
1329
+ context: parentMatch?.context ?? this?.options.context ?? {}
1330
+ })) ?? {};
1331
+ const context = {
1332
+ ...(parentMatch?.context ?? this?.options.context),
1333
+ ...routeContext
1334
+ };
1335
+ this.setRouteMatch(match.id, s => ({
1336
+ ...s,
1337
+ context,
1338
+ routeContext
1339
+ }));
1340
+ } catch (err) {
1341
+ handleError(err, 'BEFORE_LOAD');
1342
+ didError = true;
1343
+ }
2102
1344
 
2103
- throw new Error('Failed to fetch match data');
2104
- }
2105
- },
2106
- invalidateRoute: opts => {
2107
- var _router$state$pending5, _router$state$pending6;
2108
-
2109
- const next = router.buildNext(opts);
2110
- const unloadedMatchIds = router.matchRoutes(next.pathname).map(d => d.matchId);
2111
- [...router.state.matches, ...((_router$state$pending5 = (_router$state$pending6 = router.state.pending) == null ? void 0 : _router$state$pending6.matches) != null ? _router$state$pending5 : [])].forEach(match => {
2112
- if (unloadedMatchIds.includes(match.matchId)) {
2113
- match.invalidate();
1345
+ // If we errored, do not run the next matches' middleware
1346
+ if (didError) {
1347
+ break;
1348
+ }
2114
1349
  }
2115
- });
2116
- },
2117
- reload: () => router.__.navigate({
2118
- fromCurrent: true,
2119
- replace: true,
2120
- search: true
2121
- }),
2122
- resolvePath: (from, path) => {
2123
- return resolvePath(router.basepath, from, cleanPath(path));
2124
- },
2125
- matchRoute: (location, opts) => {
2126
- var _location$from;
2127
-
2128
- // const location = router.buildNext(opts)
2129
- location = _extends({}, location, {
2130
- to: location.to ? router.resolvePath((_location$from = location.from) != null ? _location$from : '', location.to) : undefined
2131
- });
2132
- const next = router.buildNext(location);
2133
-
2134
- if (opts != null && opts.pending) {
2135
- var _router$state$pending7;
2136
-
2137
- if (!((_router$state$pending7 = router.state.pending) != null && _router$state$pending7.location)) {
2138
- return false;
1350
+ } catch (err) {
1351
+ if (isRedirect(err)) {
1352
+ if (!opts?.preload) this.navigate(err);
1353
+ return;
2139
1354
  }
2140
-
2141
- return !!matchPathname(router.state.pending.location.pathname, _extends({}, opts, {
2142
- to: next.pathname
2143
- }));
1355
+ throw err;
2144
1356
  }
2145
-
2146
- return !!matchPathname(router.state.location.pathname, _extends({}, opts, {
2147
- to: next.pathname
2148
- }));
2149
- },
2150
- navigate: async _ref7 => {
2151
- let {
2152
- from,
2153
- to = '.',
2154
- search,
2155
- hash,
2156
- replace,
2157
- params
2158
- } = _ref7;
1357
+ const validResolvedMatches = getFreshMatches().slice(0, firstBadMatchIndex);
1358
+ const matchPromises = [];
1359
+ validResolvedMatches.forEach((match, index) => {
1360
+ matchPromises.push((async () => {
1361
+ const parentMatchPromise = matchPromises[index - 1];
1362
+ const route = this.getRoute(match.routeId);
1363
+ if (match.isFetching || match.status === 'success' && !isMatchInvalid(match, {
1364
+ preload: opts?.preload
1365
+ })) {
1366
+ return this.getRouteMatch(match.id)?.loadPromise;
1367
+ }
1368
+ const fetchedAt = Date.now();
1369
+ const checkLatest = () => {
1370
+ const latest = this.getRouteMatch(match.id);
1371
+ return latest && latest.fetchedAt !== fetchedAt ? latest.loadPromise : undefined;
1372
+ };
1373
+ const handleIfRedirect = err => {
1374
+ if (isRedirect(err)) {
1375
+ if (!opts?.preload) {
1376
+ this.navigate(err);
1377
+ }
1378
+ return true;
1379
+ }
1380
+ return false;
1381
+ };
1382
+ const load = async () => {
1383
+ let latestPromise;
1384
+ try {
1385
+ const componentsPromise = Promise.all(componentTypes.map(async type => {
1386
+ const component = route.options[type];
1387
+ if (component?.preload) {
1388
+ await component.preload();
1389
+ }
1390
+ }));
1391
+ const loaderPromise = route.options.loader?.({
1392
+ ...match,
1393
+ preload: !!opts?.preload,
1394
+ parentMatchPromise
1395
+ });
1396
+ const [_, loader] = await Promise.all([componentsPromise, loaderPromise]);
1397
+ if (latestPromise = checkLatest()) return await latestPromise;
1398
+ this.setRouteMatchData(match.id, () => loader, opts);
1399
+ } catch (error) {
1400
+ if (latestPromise = checkLatest()) return await latestPromise;
1401
+ if (handleIfRedirect(error)) return;
1402
+ try {
1403
+ route.options.onError?.(error);
1404
+ } catch (onErrorError) {
1405
+ error = onErrorError;
1406
+ if (handleIfRedirect(onErrorError)) return;
1407
+ }
1408
+ this.setRouteMatch(match.id, s => ({
1409
+ ...s,
1410
+ error,
1411
+ status: 'error',
1412
+ isFetching: false,
1413
+ updatedAt: Date.now()
1414
+ }));
1415
+ }
1416
+ };
1417
+ let loadPromise;
1418
+ this.__store.batch(() => {
1419
+ this.setRouteMatch(match.id, s => ({
1420
+ ...s,
1421
+ // status: s.status !== 'success' ? 'pending' : s.status,
1422
+ isFetching: true,
1423
+ fetchedAt,
1424
+ invalid: false
1425
+ }));
1426
+ loadPromise = load();
1427
+ this.setRouteMatch(match.id, s => ({
1428
+ ...s,
1429
+ loadPromise
1430
+ }));
1431
+ });
1432
+ await loadPromise;
1433
+ })());
1434
+ });
1435
+ await Promise.all(matchPromises);
1436
+ };
1437
+ resolvePath = (from, path) => {
1438
+ return resolvePath(this.basepath, from, cleanPath(path));
1439
+ };
1440
+ navigate = async ({
1441
+ from,
1442
+ to = '',
1443
+ ...rest
1444
+ }) => {
2159
1445
  // If this link simply reloads the current route,
2160
1446
  // make sure it has a new key so it will trigger a data refresh
1447
+
2161
1448
  // If this `to` is a valid external URL, return
2162
1449
  // null for LinkUtils
2163
1450
  const toString = String(to);
2164
- const fromString = String(from);
1451
+ const fromString = typeof from === 'undefined' ? from : String(from);
2165
1452
  let isExternal;
2166
-
2167
1453
  try {
2168
- new URL("" + toString);
1454
+ new URL(`${toString}`);
2169
1455
  isExternal = true;
2170
1456
  } catch (e) {}
2171
-
2172
- invariant(!isExternal, 'Attempting to navigate to external url with router.navigate!');
2173
- return router.__.navigate({
1457
+ invariant(!isExternal, 'Attempting to navigate to external url with this.navigate!');
1458
+ return this.#buildAndCommitLocation({
1459
+ ...rest,
2174
1460
  from: fromString,
2175
- to: toString,
2176
- search,
2177
- hash,
2178
- replace,
2179
- params
1461
+ to: toString
2180
1462
  });
2181
- },
2182
- buildLink: _ref8 => {
2183
- var _preload, _ref9;
2184
-
2185
- let {
2186
- from,
2187
- to = '.',
2188
- search,
2189
- params,
2190
- hash,
2191
- target,
2192
- replace,
2193
- activeOptions,
2194
- preload,
2195
- preloadMaxAge: userPreloadMaxAge,
2196
- preloadGcMaxAge: userPreloadGcMaxAge,
2197
- preloadDelay: userPreloadDelay,
2198
- disabled
2199
- } = _ref8;
2200
-
1463
+ };
1464
+ matchRoute = (location, opts) => {
1465
+ location = {
1466
+ ...location,
1467
+ to: location.to ? this.resolvePath(location.from ?? '', location.to) : undefined
1468
+ };
1469
+ const next = this.buildLocation(location);
1470
+ if (opts?.pending && this.state.status !== 'pending') {
1471
+ return false;
1472
+ }
1473
+ const baseLocation = opts?.pending ? this.state.location : this.state.resolvedLocation;
1474
+ if (!baseLocation) {
1475
+ return false;
1476
+ }
1477
+ const match = matchPathname(this.basepath, baseLocation.pathname, {
1478
+ ...opts,
1479
+ to: next.pathname
1480
+ });
1481
+ if (!match) {
1482
+ return false;
1483
+ }
1484
+ if (opts?.includeSearch ?? true) {
1485
+ return partialDeepEqual(baseLocation.search, next.search) ? match : false;
1486
+ }
1487
+ return match;
1488
+ };
1489
+ buildLink = dest => {
2201
1490
  // If this link simply reloads the current route,
2202
1491
  // make sure it has a new key so it will trigger a data refresh
1492
+
2203
1493
  // If this `to` is a valid external URL, return
2204
1494
  // null for LinkUtils
1495
+
1496
+ const {
1497
+ to,
1498
+ preload: userPreload,
1499
+ preloadDelay: userPreloadDelay,
1500
+ activeOptions,
1501
+ disabled,
1502
+ target,
1503
+ replace,
1504
+ resetScroll
1505
+ } = dest;
2205
1506
  try {
2206
- new URL("" + to);
1507
+ new URL(`${to}`);
2207
1508
  return {
2208
1509
  type: 'external',
2209
1510
  href: to
2210
1511
  };
2211
1512
  } catch (e) {}
1513
+ const nextOpts = dest;
1514
+ const next = this.buildLocation(nextOpts);
1515
+ const preload = userPreload ?? this.options.defaultPreload;
1516
+ const preloadDelay = userPreloadDelay ?? this.options.defaultPreloadDelay ?? 0;
2212
1517
 
2213
- const nextOpts = {
2214
- from,
2215
- to,
2216
- search,
2217
- params,
2218
- hash,
2219
- replace
2220
- };
2221
- const next = router.buildNext(nextOpts);
2222
- preload = (_preload = preload) != null ? _preload : router.options.defaultPreload;
2223
- const preloadDelay = (_ref9 = userPreloadDelay != null ? userPreloadDelay : router.options.defaultPreloadDelay) != null ? _ref9 : 0; // Compare path/hash for matches
2224
-
2225
- const pathIsEqual = router.state.location.pathname === next.pathname;
2226
- const currentPathSplit = router.state.location.pathname.split('/');
1518
+ // Compare path/hash for matches
1519
+ const currentPathSplit = this.state.location.pathname.split('/');
2227
1520
  const nextPathSplit = next.pathname.split('/');
2228
1521
  const pathIsFuzzyEqual = nextPathSplit.every((d, i) => d === currentPathSplit[i]);
2229
- const hashIsEqual = router.state.location.hash === next.hash; // Combine the matches based on user options
2230
-
2231
- const pathTest = activeOptions != null && activeOptions.exact ? pathIsEqual : pathIsFuzzyEqual;
2232
- const hashTest = activeOptions != null && activeOptions.includeHash ? hashIsEqual : true; // The final "active" test
1522
+ // Combine the matches based on user options
1523
+ const pathTest = activeOptions?.exact ? this.state.location.pathname === next.pathname : pathIsFuzzyEqual;
1524
+ const hashTest = activeOptions?.includeHash ? this.state.location.hash === next.hash : true;
1525
+ const searchTest = activeOptions?.includeSearch ?? true ? partialDeepEqual(this.state.location.search, next.search) : true;
2233
1526
 
2234
- const isActive = pathTest && hashTest; // The click handler
1527
+ // The final "active" test
1528
+ const isActive = pathTest && hashTest && searchTest;
2235
1529
 
1530
+ // The click handler
2236
1531
  const handleClick = e => {
2237
1532
  if (!disabled && !isCtrlEvent(e) && !e.defaultPrevented && (!target || target === '_self') && e.button === 0) {
2238
1533
  e.preventDefault();
2239
1534
 
2240
- if (pathIsEqual && !search && !hash) {
2241
- router.invalidateRoute(nextOpts);
2242
- } // All is well? Navigate!)
2243
-
2244
-
2245
- router.__.navigate(nextOpts);
1535
+ // All is well? Navigate!
1536
+ this.#commitLocation({
1537
+ ...next,
1538
+ replace,
1539
+ resetScroll
1540
+ });
2246
1541
  }
2247
- }; // The click handler
2248
-
1542
+ };
2249
1543
 
1544
+ // The click handler
2250
1545
  const handleFocus = e => {
2251
1546
  if (preload) {
2252
- router.preloadRoute(nextOpts, {
2253
- maxAge: userPreloadMaxAge,
2254
- gcMaxAge: userPreloadGcMaxAge
1547
+ this.preloadRoute(nextOpts).catch(err => {
1548
+ console.warn(err);
1549
+ console.warn(preloadWarning);
2255
1550
  });
2256
1551
  }
2257
1552
  };
2258
-
1553
+ const handleTouchStart = e => {
1554
+ this.preloadRoute(nextOpts).catch(err => {
1555
+ console.warn(err);
1556
+ console.warn(preloadWarning);
1557
+ });
1558
+ };
2259
1559
  const handleEnter = e => {
2260
1560
  const target = e.target || {};
2261
-
2262
1561
  if (preload) {
2263
1562
  if (target.preloadTimeout) {
2264
1563
  return;
2265
1564
  }
2266
-
2267
1565
  target.preloadTimeout = setTimeout(() => {
2268
1566
  target.preloadTimeout = null;
2269
- router.preloadRoute(nextOpts, {
2270
- maxAge: userPreloadMaxAge,
2271
- gcMaxAge: userPreloadGcMaxAge
1567
+ this.preloadRoute(nextOpts).catch(err => {
1568
+ console.warn(err);
1569
+ console.warn(preloadWarning);
2272
1570
  });
2273
1571
  }, preloadDelay);
2274
1572
  }
2275
1573
  };
2276
-
2277
1574
  const handleLeave = e => {
2278
1575
  const target = e.target || {};
2279
-
2280
1576
  if (target.preloadTimeout) {
2281
1577
  clearTimeout(target.preloadTimeout);
2282
1578
  target.preloadTimeout = null;
2283
1579
  }
2284
1580
  };
2285
-
2286
1581
  return {
2287
1582
  type: 'internal',
2288
1583
  next,
@@ -2290,224 +1585,664 @@
2290
1585
  handleClick,
2291
1586
  handleEnter,
2292
1587
  handleLeave,
1588
+ handleTouchStart,
2293
1589
  isActive,
2294
1590
  disabled
2295
1591
  };
2296
- },
2297
- buildNext: opts => {
2298
- const next = router.__.buildLocation(opts);
2299
-
2300
- const matches = router.matchRoutes(next.pathname);
2301
-
2302
- const __preSearchFilters = matches.map(match => {
2303
- var _match$options$preSea;
2304
-
2305
- return (_match$options$preSea = match.options.preSearchFilters) != null ? _match$options$preSea : [];
2306
- }).flat().filter(Boolean);
2307
-
2308
- const __postSearchFilters = matches.map(match => {
2309
- var _match$options$postSe;
2310
-
2311
- return (_match$options$postSe = match.options.postSearchFilters) != null ? _match$options$postSe : [];
2312
- }).flat().filter(Boolean);
2313
-
2314
- return router.__.buildLocation(_extends({}, opts, {
2315
- __preSearchFilters,
2316
- __postSearchFilters
2317
- }));
2318
- },
2319
- __: {
2320
- buildRouteTree: rootRouteConfig => {
2321
- const recurseRoutes = (routeConfigs, parent) => {
2322
- return routeConfigs.map(routeConfig => {
2323
- const routeOptions = routeConfig.options;
2324
- const route = createRoute(routeConfig, routeOptions, parent, router);
2325
- const existingRoute = router.routesById[route.routeId];
2326
-
2327
- if (existingRoute) {
2328
- {
2329
- console.warn("Duplicate routes found with id: " + String(route.routeId), router.routesById, route);
2330
- }
2331
-
2332
- throw new Error();
2333
- }
2334
- router.routesById[route.routeId] = route;
2335
- const children = routeConfig.children;
2336
- route.childRoutes = children != null && children.length ? recurseRoutes(children, route) : undefined;
2337
- return route;
2338
- });
1592
+ };
1593
+ dehydrate = () => {
1594
+ return {
1595
+ state: {
1596
+ matchIds: this.state.matchIds,
1597
+ dehydratedMatches: this.state.matches.map(d => pick(d, ['fetchedAt', 'invalid', 'preloadMaxAge', 'maxAge', 'id', 'loaderData', 'status', 'updatedAt']))
1598
+ }
1599
+ };
1600
+ };
1601
+ hydrate = async __do_not_use_server_ctx => {
1602
+ let _ctx = __do_not_use_server_ctx;
1603
+ // Client hydrates from window
1604
+ if (typeof document !== 'undefined') {
1605
+ _ctx = window.__TSR_DEHYDRATED__;
1606
+ }
1607
+ invariant(_ctx, 'Expected to find a __TSR_DEHYDRATED__ property on window... but we did not. Did you forget to render <DehydrateRouter /> in your app?');
1608
+ const ctx = _ctx;
1609
+ this.dehydratedData = ctx.payload;
1610
+ this.options.hydrate?.(ctx.payload);
1611
+ const dehydratedState = ctx.router.state;
1612
+ let matches = this.matchRoutes(this.state.location.pathname, this.state.location.search).map(match => {
1613
+ const dehydratedMatch = dehydratedState.dehydratedMatches.find(d => d.id === match.id);
1614
+ invariant(dehydratedMatch, `Could not find a client-side match for dehydrated match with id: ${match.id}!`);
1615
+ if (dehydratedMatch) {
1616
+ return {
1617
+ ...match,
1618
+ ...dehydratedMatch
1619
+ };
1620
+ }
1621
+ return match;
1622
+ });
1623
+ this.__store.setState(s => {
1624
+ return {
1625
+ ...s,
1626
+ matchIds: dehydratedState.matchIds,
1627
+ matches,
1628
+ matchesById: this.#mergeMatches(s.matchesById, matches)
2339
1629
  };
1630
+ });
1631
+ };
1632
+ injectedHtml = [];
1633
+ injectHtml = async html => {
1634
+ this.injectedHtml.push(html);
1635
+ };
1636
+ dehydrateData = (key, getData) => {
1637
+ if (typeof document === 'undefined') {
1638
+ const strKey = typeof key === 'string' ? key : JSON.stringify(key);
1639
+ this.injectHtml(async () => {
1640
+ const id = `__TSR_DEHYDRATED__${strKey}`;
1641
+ const data = typeof getData === 'function' ? await getData() : getData;
1642
+ return `<script id='${id}' suppressHydrationWarning>window["__TSR_DEHYDRATED__${escapeJSON(strKey)}"] = ${JSON.stringify(data)}
1643
+ ;(() => {
1644
+ var el = document.getElementById('${id}')
1645
+ el.parentElement.removeChild(el)
1646
+ })()
1647
+ </script>`;
1648
+ });
1649
+ return () => this.hydrateData(key);
1650
+ }
1651
+ return () => undefined;
1652
+ };
1653
+ hydrateData = key => {
1654
+ if (typeof document !== 'undefined') {
1655
+ const strKey = typeof key === 'string' ? key : JSON.stringify(key);
1656
+ return window[`__TSR_DEHYDRATED__${strKey}`];
1657
+ }
1658
+ return undefined;
1659
+ };
2340
1660
 
2341
- const routes = recurseRoutes([rootRouteConfig]);
2342
- return routes[0];
2343
- },
2344
- parseLocation: (location, previousLocation) => {
2345
- var _location$hash$split$;
2346
-
2347
- const parsedSearch = router.options.parseSearch(location.search);
1661
+ // resolveMatchPromise = (matchId: string, key: string, value: any) => {
1662
+ // this.state.matches
1663
+ // .find((d) => d.id === matchId)
1664
+ // ?.__promisesByKey[key]?.resolve(value)
1665
+ // }
1666
+
1667
+ #processRoutes = routeTree => {
1668
+ this.routeTree = routeTree;
1669
+ this.routesById = {};
1670
+ this.routesByPath = {};
1671
+ this.flatRoutes = [];
1672
+ const recurseRoutes = routes => {
1673
+ routes.forEach((route, i) => {
1674
+ route.init({
1675
+ originalIndex: i,
1676
+ router: this
1677
+ });
1678
+ const existingRoute = this.routesById[route.id];
1679
+ invariant(!existingRoute, `Duplicate routes found with id: ${String(route.id)}`);
1680
+ this.routesById[route.id] = route;
1681
+ if (!route.isRoot && route.path) {
1682
+ const trimmedFullPath = trimPathRight(route.fullPath);
1683
+ if (!this.routesByPath[trimmedFullPath] || route.fullPath.endsWith('/')) {
1684
+ this.routesByPath[trimmedFullPath] = route;
1685
+ }
1686
+ }
1687
+ const children = route.children;
1688
+ if (children?.length) {
1689
+ recurseRoutes(children);
1690
+ }
1691
+ });
1692
+ };
1693
+ recurseRoutes([routeTree]);
1694
+ this.flatRoutes = Object.values(this.routesByPath).map((d, i) => {
1695
+ const trimmed = trimPath(d.fullPath);
1696
+ const parsed = parsePathname(trimmed);
1697
+ while (parsed.length > 1 && parsed[0]?.value === '/') {
1698
+ parsed.shift();
1699
+ }
1700
+ const score = parsed.map(d => {
1701
+ if (d.type === 'param') {
1702
+ return 0.5;
1703
+ }
1704
+ if (d.type === 'wildcard') {
1705
+ return 0.25;
1706
+ }
1707
+ return 1;
1708
+ });
2348
1709
  return {
2349
- pathname: location.pathname,
2350
- searchStr: location.search,
2351
- search: replaceEqualDeep(previousLocation == null ? void 0 : previousLocation.search, parsedSearch),
2352
- hash: (_location$hash$split$ = location.hash.split('#').reverse()[0]) != null ? _location$hash$split$ : '',
2353
- href: "" + location.pathname + location.search + location.hash,
2354
- state: location.state,
2355
- key: location.key
1710
+ child: d,
1711
+ trimmed,
1712
+ parsed,
1713
+ index: i,
1714
+ score
2356
1715
  };
2357
- },
2358
- navigate: location => {
2359
- const next = router.buildNext(location);
2360
- return router.__.commitLocation(next, location.replace);
2361
- },
2362
- buildLocation: function buildLocation(dest) {
2363
- var _dest$from, _router$basepath, _dest$to, _last, _dest$params, _dest$__preSearchFilt, _functionalUpdate, _dest$__preSearchFilt2, _dest$__postSearchFil;
2364
-
2365
- if (dest === void 0) {
2366
- dest = {};
1716
+ }).sort((a, b) => {
1717
+ let isIndex = a.trimmed === '/' ? 1 : b.trimmed === '/' ? -1 : 0;
1718
+ if (isIndex !== 0) return isIndex;
1719
+ const length = Math.min(a.score.length, b.score.length);
1720
+
1721
+ // Sort by length of score
1722
+ if (a.score.length !== b.score.length) {
1723
+ return b.score.length - a.score.length;
2367
1724
  }
2368
1725
 
2369
- // const resolvedFrom: Location = {
2370
- // ...router.location,
2371
- const fromPathname = dest.fromCurrent ? router.location.pathname : (_dest$from = dest.from) != null ? _dest$from : router.location.pathname;
2372
-
2373
- let pathname = resolvePath((_router$basepath = router.basepath) != null ? _router$basepath : '/', fromPathname, "" + ((_dest$to = dest.to) != null ? _dest$to : '.'));
2374
-
2375
- const fromMatches = router.matchRoutes(router.location.pathname, {
2376
- strictParseParams: true
2377
- });
2378
- const toMatches = router.matchRoutes(pathname);
1726
+ // Sort by min available score
1727
+ for (let i = 0; i < length; i++) {
1728
+ if (a.score[i] !== b.score[i]) {
1729
+ return b.score[i] - a.score[i];
1730
+ }
1731
+ }
2379
1732
 
2380
- const prevParams = _extends({}, (_last = last(fromMatches)) == null ? void 0 : _last.params);
1733
+ // Sort by min available parsed value
1734
+ for (let i = 0; i < length; i++) {
1735
+ if (a.parsed[i].value !== b.parsed[i].value) {
1736
+ return a.parsed[i].value > b.parsed[i].value ? 1 : -1;
1737
+ }
1738
+ }
2381
1739
 
2382
- let nextParams = ((_dest$params = dest.params) != null ? _dest$params : true) === true ? prevParams : functionalUpdate(dest.params, prevParams);
1740
+ // Sort by length of trimmed full path
1741
+ if (a.trimmed !== b.trimmed) {
1742
+ return a.trimmed > b.trimmed ? 1 : -1;
1743
+ }
2383
1744
 
1745
+ // Sort by original index
1746
+ return a.index - b.index;
1747
+ }).map((d, i) => {
1748
+ d.child.rank = i;
1749
+ return d.child;
1750
+ });
1751
+ };
1752
+ #parseLocation = previousLocation => {
1753
+ const parse = ({
1754
+ pathname,
1755
+ search,
1756
+ hash,
1757
+ state
1758
+ }) => {
1759
+ const parsedSearch = this.options.parseSearch(search);
1760
+ return {
1761
+ pathname: pathname,
1762
+ searchStr: search,
1763
+ search: replaceEqualDeep(previousLocation?.search, parsedSearch),
1764
+ hash: hash.split('#').reverse()[0] ?? '',
1765
+ href: `${pathname}${search}${hash}`,
1766
+ state: replaceEqualDeep(previousLocation?.state, state)
1767
+ };
1768
+ };
1769
+ const location = parse(this.history.location);
1770
+ let {
1771
+ __tempLocation,
1772
+ __tempKey
1773
+ } = location.state;
1774
+ if (__tempLocation && (!__tempKey || __tempKey === this.tempLocationKey)) {
1775
+ // Sync up the location keys
1776
+ const parsedTempLocation = parse(__tempLocation);
1777
+ parsedTempLocation.state.key = location.state.key;
1778
+ delete parsedTempLocation.state.__tempLocation;
1779
+ return {
1780
+ ...parsedTempLocation,
1781
+ maskedLocation: location
1782
+ };
1783
+ }
1784
+ return location;
1785
+ };
1786
+ buildLocation = (opts = {}) => {
1787
+ const build = (dest = {}, matches) => {
1788
+ const from = this.state.location;
1789
+ const fromPathname = dest.from ?? from.pathname;
1790
+ let pathname = resolvePath(this.basepath ?? '/', fromPathname, `${dest.to ?? ''}`);
1791
+ const fromMatches = this.matchRoutes(fromPathname, from.search);
1792
+ const prevParams = {
1793
+ ...last(fromMatches)?.params
1794
+ };
1795
+ let nextParams = (dest.params ?? true) === true ? prevParams : functionalUpdate(dest.params, prevParams);
2384
1796
  if (nextParams) {
2385
- toMatches.map(d => d.options.stringifyParams).filter(Boolean).forEach(fn => {
2386
- Object.assign({}, nextParams, fn(nextParams));
1797
+ matches?.map(d => this.getRoute(d.routeId).options.stringifyParams).filter(Boolean).forEach(fn => {
1798
+ nextParams = {
1799
+ ...nextParams,
1800
+ ...fn(nextParams)
1801
+ };
2387
1802
  });
2388
1803
  }
1804
+ pathname = interpolatePath(pathname, nextParams ?? {});
1805
+ const preSearchFilters = matches?.map(match => this.getRoute(match.routeId).options.preSearchFilters ?? []).flat().filter(Boolean) ?? [];
1806
+ const postSearchFilters = matches?.map(match => this.getRoute(match.routeId).options.postSearchFilters ?? []).flat().filter(Boolean) ?? [];
2389
1807
 
2390
- pathname = interpolatePath(pathname, nextParams != null ? nextParams : {}); // Pre filters first
2391
-
2392
- const preFilteredSearch = (_dest$__preSearchFilt = dest.__preSearchFilters) != null && _dest$__preSearchFilt.length ? dest.__preSearchFilters.reduce((prev, next) => next(prev), router.location.search) : router.location.search; // Then the link/navigate function
1808
+ // Pre filters first
1809
+ const preFilteredSearch = preSearchFilters?.length ? preSearchFilters?.reduce((prev, next) => next(prev), from.search) : from.search;
2393
1810
 
1811
+ // Then the link/navigate function
2394
1812
  const destSearch = dest.search === true ? preFilteredSearch // Preserve resolvedFrom true
2395
- : dest.search ? (_functionalUpdate = functionalUpdate(dest.search, preFilteredSearch)) != null ? _functionalUpdate : {} // Updater
2396
- : (_dest$__preSearchFilt2 = dest.__preSearchFilters) != null && _dest$__preSearchFilt2.length ? preFilteredSearch // Preserve resolvedFrom filters
2397
- : {}; // Then post filters
2398
-
2399
- const postFilteredSearch = (_dest$__postSearchFil = dest.__postSearchFilters) != null && _dest$__postSearchFil.length ? dest.__postSearchFilters.reduce((prev, next) => next(prev), destSearch) : destSearch;
2400
- const search = replaceEqualDeep(router.location.search, postFilteredSearch);
2401
- const searchStr = router.options.stringifySearch(search);
2402
- let hash = dest.hash === true ? router.location.hash : functionalUpdate(dest.hash, router.location.hash);
2403
- hash = hash ? "#" + hash : '';
1813
+ : dest.search ? functionalUpdate(dest.search, preFilteredSearch) ?? {} // Updater
1814
+ : preSearchFilters?.length ? preFilteredSearch // Preserve resolvedFrom filters
1815
+ : {};
1816
+
1817
+ // Then post filters
1818
+ const postFilteredSearch = postSearchFilters?.length ? postSearchFilters.reduce((prev, next) => next(prev), destSearch) : destSearch;
1819
+ const search = replaceEqualDeep(from.search, postFilteredSearch);
1820
+ const searchStr = this.options.stringifySearch(search);
1821
+ const hash = dest.hash === true ? from.hash : dest.hash ? functionalUpdate(dest.hash, from.hash) : from.hash;
1822
+ const hashStr = hash ? `#${hash}` : '';
1823
+ let nextState = dest.state === true ? from.state : dest.state ? functionalUpdate(dest.state, from.state) : from.state;
1824
+ nextState = replaceEqualDeep(from.state, nextState);
2404
1825
  return {
2405
1826
  pathname,
2406
1827
  search,
2407
1828
  searchStr,
2408
- state: router.location.state,
1829
+ state: nextState,
2409
1830
  hash,
2410
- href: "" + pathname + searchStr + hash,
2411
- key: dest.key
1831
+ href: this.history.createHref(`${pathname}${searchStr}${hashStr}`),
1832
+ unmaskOnReload: dest.unmaskOnReload
2412
1833
  };
2413
- },
2414
- commitLocation: (next, replace) => {
2415
- const id = '' + Date.now() + Math.random();
2416
- if (router.navigateTimeout) clearTimeout(router.navigateTimeout);
2417
- let nextAction = 'replace';
2418
-
2419
- if (!replace) {
2420
- nextAction = 'push';
1834
+ };
1835
+ const buildWithMatches = (dest = {}, maskedDest) => {
1836
+ let next = build(dest);
1837
+ let maskedNext = maskedDest ? build(maskedDest) : undefined;
1838
+ if (!maskedNext) {
1839
+ let params = {};
1840
+ let foundMask = this.options.routeMasks?.find(d => {
1841
+ const match = matchPathname(this.basepath, next.pathname, {
1842
+ to: d.from,
1843
+ fuzzy: false
1844
+ });
1845
+ if (match) {
1846
+ params = match;
1847
+ return true;
1848
+ }
1849
+ return false;
1850
+ });
1851
+ if (foundMask) {
1852
+ foundMask = {
1853
+ ...foundMask,
1854
+ from: interpolatePath(foundMask.from, params)
1855
+ };
1856
+ maskedDest = foundMask;
1857
+ maskedNext = build(maskedDest);
1858
+ }
2421
1859
  }
2422
-
2423
- const isSameUrl = router.__.parseLocation(history.location).href === next.href;
2424
-
2425
- if (isSameUrl && !next.key) {
2426
- nextAction = 'replace';
1860
+ const nextMatches = this.matchRoutes(next.pathname, next.search);
1861
+ const maskedMatches = maskedNext ? this.matchRoutes(maskedNext.pathname, maskedNext.search) : undefined;
1862
+ const maskedFinal = maskedNext ? build(maskedDest, maskedMatches) : undefined;
1863
+ const final = build(dest, nextMatches);
1864
+ if (maskedFinal) {
1865
+ final.maskedLocation = maskedFinal;
2427
1866
  }
2428
-
2429
- if (nextAction === 'replace') {
2430
- history.replace({
2431
- pathname: next.pathname,
2432
- hash: next.hash,
2433
- search: next.searchStr
2434
- }, _extends({
2435
- id
2436
- }, next.state));
2437
- } else {
2438
- history.push({
2439
- pathname: next.pathname,
2440
- hash: next.hash,
2441
- search: next.searchStr
2442
- }, {
2443
- id
1867
+ return final;
1868
+ };
1869
+ if (opts.mask) {
1870
+ return buildWithMatches(opts, {
1871
+ ...pick(opts, ['from']),
1872
+ ...opts.mask
1873
+ });
1874
+ }
1875
+ return buildWithMatches(opts);
1876
+ };
1877
+ #buildAndCommitLocation = ({
1878
+ replace,
1879
+ resetScroll,
1880
+ ...rest
1881
+ } = {}) => {
1882
+ const location = this.buildLocation(rest);
1883
+ return this.#commitLocation({
1884
+ ...location,
1885
+ replace,
1886
+ resetScroll
1887
+ });
1888
+ };
1889
+ #commitLocation = async next => {
1890
+ if (this.navigateTimeout) clearTimeout(this.navigateTimeout);
1891
+ let nextAction = 'replace';
1892
+ if (!next.replace) {
1893
+ nextAction = 'push';
1894
+ }
1895
+ const isSameUrl = this.state.location.href === next.href;
1896
+ if (isSameUrl) {
1897
+ nextAction = 'replace';
1898
+ }
1899
+ let {
1900
+ maskedLocation,
1901
+ ...nextHistory
1902
+ } = next;
1903
+ if (maskedLocation) {
1904
+ nextHistory = {
1905
+ ...maskedLocation,
1906
+ state: {
1907
+ ...maskedLocation.state,
1908
+ __tempKey: undefined,
1909
+ __tempLocation: {
1910
+ ...nextHistory,
1911
+ search: nextHistory.searchStr,
1912
+ state: {
1913
+ ...nextHistory.state,
1914
+ __tempKey: undefined,
1915
+ __tempLocation: undefined,
1916
+ key: undefined
1917
+ }
1918
+ }
1919
+ }
1920
+ };
1921
+ if (nextHistory.unmaskOnReload ?? this.options.unmaskOnReload ?? false) {
1922
+ nextHistory.state.__tempKey = this.tempLocationKey;
1923
+ }
1924
+ }
1925
+ this.history[nextAction === 'push' ? 'push' : 'replace'](nextHistory.href, nextHistory.state);
1926
+ this.resetNextScroll = next.resetScroll ?? true;
1927
+ return this.latestLoadPromise;
1928
+ };
1929
+ getRouteMatch = id => {
1930
+ return this.state.matchesById[id];
1931
+ };
1932
+ setRouteMatch = (id, updater) => {
1933
+ this.__store.setState(prev => {
1934
+ if (!prev.matchesById[id]) {
1935
+ return prev;
1936
+ }
1937
+ return {
1938
+ ...prev,
1939
+ matchesById: {
1940
+ ...prev.matchesById,
1941
+ [id]: updater(prev.matchesById[id])
1942
+ }
1943
+ };
1944
+ });
1945
+ };
1946
+ setRouteMatchData = (id, updater, opts) => {
1947
+ const match = this.getRouteMatch(id);
1948
+ if (!match) return;
1949
+ const route = this.getRoute(match.routeId);
1950
+ const updatedAt = opts?.updatedAt ?? Date.now();
1951
+ const preloadMaxAge = opts?.maxAge ?? route.options.preloadMaxAge ?? this.options.defaultPreloadMaxAge ?? 5000;
1952
+ const maxAge = opts?.maxAge ?? route.options.maxAge ?? this.options.defaultMaxAge ?? -1;
1953
+ this.setRouteMatch(id, s => ({
1954
+ ...s,
1955
+ error: undefined,
1956
+ status: 'success',
1957
+ isFetching: false,
1958
+ updatedAt: updatedAt,
1959
+ loaderData: functionalUpdate(updater, s.loaderData),
1960
+ preloadMaxAge,
1961
+ maxAge
1962
+ }));
1963
+ };
1964
+ invalidate = async opts => {
1965
+ if (opts?.matchId) {
1966
+ this.setRouteMatch(opts.matchId, s => ({
1967
+ ...s,
1968
+ invalid: true
1969
+ }));
1970
+ const matchIndex = this.state.matches.findIndex(d => d.id === opts.matchId);
1971
+ const childMatch = this.state.matches[matchIndex + 1];
1972
+ if (childMatch) {
1973
+ return this.invalidate({
1974
+ matchId: childMatch.id,
1975
+ reload: false,
1976
+ __fromFocus: opts.__fromFocus
2444
1977
  });
2445
1978
  }
1979
+ } else {
1980
+ this.__store.batch(() => {
1981
+ Object.values(this.state.matchesById).forEach(match => {
1982
+ const route = this.getRoute(match.routeId);
1983
+ const shouldInvalidate = opts?.__fromFocus ? route.options.reloadOnWindowFocus ?? true : true;
1984
+ if (shouldInvalidate) {
1985
+ this.setRouteMatch(match.id, s => ({
1986
+ ...s,
1987
+ invalid: true
1988
+ }));
1989
+ }
1990
+ });
1991
+ });
1992
+ }
1993
+ if (opts?.reload ?? true) {
1994
+ return this.load();
1995
+ }
1996
+ };
1997
+ }
1998
+
1999
+ // Detect if we're in the DOM
2000
+ const isServer = typeof window === 'undefined' || !window.document.createElement;
2001
+ function getInitialRouterState() {
2002
+ return {
2003
+ status: 'idle',
2004
+ isFetching: false,
2005
+ resolvedLocation: null,
2006
+ location: null,
2007
+ matchesById: {},
2008
+ matchIds: [],
2009
+ pendingMatchIds: [],
2010
+ matches: [],
2011
+ pendingMatches: [],
2012
+ renderedMatchIds: [],
2013
+ renderedMatches: [],
2014
+ lastUpdated: Date.now()
2015
+ };
2016
+ }
2017
+ function isCtrlEvent(e) {
2018
+ return !!(e.metaKey || e.altKey || e.ctrlKey || e.shiftKey);
2019
+ }
2020
+ function redirect(opts) {
2021
+ opts.isRedirect = true;
2022
+ return opts;
2023
+ }
2024
+ function isRedirect(obj) {
2025
+ return !!obj?.isRedirect;
2026
+ }
2027
+ class SearchParamError extends Error {}
2028
+ class PathParamError extends Error {}
2029
+ function escapeJSON(jsonString) {
2030
+ return jsonString.replace(/\\/g, '\\\\') // Escape backslashes
2031
+ .replace(/'/g, "\\'") // Escape single quotes
2032
+ .replace(/"/g, '\\"'); // Escape double quotes
2033
+ }
2446
2034
 
2447
- router.navigationPromise = new Promise(resolve => {
2448
- const previousNavigationResolve = router.resolveNavigation;
2035
+ // A function that takes an import() argument which is a function and returns a new function that will
2036
+ // proxy arguments from the caller to the imported function, retaining all type
2037
+ // information along the way
2038
+ function lazyFn(fn, key) {
2039
+ return async (...args) => {
2040
+ const imported = await fn();
2041
+ return imported[key || 'default'](...args);
2042
+ };
2043
+ }
2044
+ function isMatchInvalid(match, opts) {
2045
+ const now = Date.now();
2046
+ if (match.invalid) {
2047
+ return true;
2048
+ }
2049
+ if (opts?.preload) {
2050
+ return match.preloadMaxAge < 0 ? false : match.updatedAt + match.preloadMaxAge < now;
2051
+ }
2052
+ return match.maxAge < 0 ? false : match.updatedAt + match.maxAge < now;
2053
+ }
2449
2054
 
2450
- router.resolveNavigation = () => {
2451
- previousNavigationResolve();
2452
- resolve();
2055
+ const windowKey = 'window';
2056
+ const delimiter = '___';
2057
+ let weakScrolledElementsByRestoreKey = {};
2058
+ let cache;
2059
+ let pathDidChange = false;
2060
+ const sessionsStorage = typeof window !== 'undefined' && window.sessionStorage;
2061
+ const defaultGetKey = location => location.state.key;
2062
+ function watchScrollPositions(router, opts) {
2063
+ const getKey = opts?.getKey || defaultGetKey;
2064
+ if (sessionsStorage) {
2065
+ if (!cache) {
2066
+ cache = (() => {
2067
+ const storageKey = 'tsr-scroll-restoration-v1';
2068
+ const current = JSON.parse(window.sessionStorage.getItem(storageKey) || '{}');
2069
+ return {
2070
+ current,
2071
+ set: (key, value) => {
2072
+ current[key] = value;
2073
+ window.sessionStorage.setItem(storageKey, JSON.stringify(cache));
2074
+ }
2453
2075
  };
2076
+ })();
2077
+ }
2078
+ }
2079
+ const {
2080
+ history
2081
+ } = window;
2082
+ if (history.scrollRestoration) {
2083
+ history.scrollRestoration = 'manual';
2084
+ }
2085
+ const onScroll = event => {
2086
+ const restoreKey = getKey(router.state.resolvedLocation);
2087
+ if (!weakScrolledElementsByRestoreKey[restoreKey]) {
2088
+ weakScrolledElementsByRestoreKey[restoreKey] = new WeakSet();
2089
+ }
2090
+ const set = weakScrolledElementsByRestoreKey[restoreKey];
2091
+ if (set.has(event.target)) return;
2092
+ set.add(event.target);
2093
+ const cacheKey = [restoreKey, event.target === document || event.target === window ? windowKey : getCssSelector(event.target)].join(delimiter);
2094
+ if (!cache.current[cacheKey]) {
2095
+ cache.set(cacheKey, {
2096
+ scrollX: NaN,
2097
+ scrollY: NaN
2454
2098
  });
2455
- return router.navigationPromise;
2456
2099
  }
2100
+ };
2101
+ const getCssSelector = el => {
2102
+ let path = [],
2103
+ parent;
2104
+ while (parent = el.parentNode) {
2105
+ path.unshift(`${el.tagName}:nth-child(${[].indexOf.call(parent.children, el) + 1})`);
2106
+ el = parent;
2107
+ }
2108
+ return `${path.join(' > ')}`.toLowerCase();
2109
+ };
2110
+ const onPathWillChange = from => {
2111
+ const restoreKey = getKey(from);
2112
+ for (const cacheKey in cache.current) {
2113
+ const entry = cache.current[cacheKey];
2114
+ const [key, elementSelector] = cacheKey.split(delimiter);
2115
+ if (restoreKey === key) {
2116
+ if (elementSelector === windowKey) {
2117
+ entry.scrollX = window.scrollX || 0;
2118
+ entry.scrollY = window.scrollY || 0;
2119
+ } else if (elementSelector) {
2120
+ const element = document.querySelector(elementSelector);
2121
+ entry.scrollX = element?.scrollLeft || 0;
2122
+ entry.scrollY = element?.scrollTop || 0;
2123
+ }
2124
+ cache.set(cacheKey, entry);
2125
+ }
2126
+ }
2127
+ };
2128
+ const onPathChange = () => {
2129
+ pathDidChange = true;
2130
+ };
2131
+ if (typeof document !== 'undefined') {
2132
+ document.addEventListener('scroll', onScroll, true);
2457
2133
  }
2458
- };
2459
- router.update(userOptions); // Allow frameworks to hook into the router creation
2460
-
2461
- router.options.createRouter == null ? void 0 : router.options.createRouter(router);
2462
- return router;
2463
- }
2464
-
2465
- function isCtrlEvent(e) {
2466
- return !!(e.metaKey || e.altKey || e.ctrlKey || e.shiftKey);
2467
- }
2468
-
2469
- function cascadeLoaderData(matches) {
2470
- matches.forEach((match, index) => {
2471
- const parent = matches[index - 1];
2134
+ const unsubOnBeforeLoad = router.subscribe('onBeforeLoad', event => {
2135
+ if (event.pathChanged) onPathWillChange(event.from);
2136
+ });
2137
+ const unsubOnLoad = router.subscribe('onLoad', event => {
2138
+ if (event.pathChanged) onPathChange();
2139
+ });
2140
+ return () => {
2141
+ document.removeEventListener('scroll', onScroll);
2142
+ unsubOnBeforeLoad();
2143
+ unsubOnLoad();
2144
+ };
2145
+ }
2146
+ function restoreScrollPositions(router, opts) {
2147
+ if (pathDidChange) {
2148
+ if (!router.resetNextScroll) {
2149
+ return;
2150
+ }
2151
+ const getKey = opts?.getKey || defaultGetKey;
2152
+ pathDidChange = false;
2153
+ const restoreKey = getKey(router.state.location);
2154
+ let windowRestored = false;
2155
+ for (const cacheKey in cache.current) {
2156
+ const entry = cache.current[cacheKey];
2157
+ const [key, elementSelector] = cacheKey.split(delimiter);
2158
+ if (key === restoreKey) {
2159
+ if (elementSelector === windowKey) {
2160
+ windowRestored = true;
2161
+ window.scrollTo(entry.scrollX, entry.scrollY);
2162
+ } else if (elementSelector) {
2163
+ const element = document.querySelector(elementSelector);
2164
+ if (element) {
2165
+ element.scrollLeft = entry.scrollX;
2166
+ element.scrollTop = entry.scrollY;
2167
+ }
2168
+ }
2169
+ }
2170
+ }
2171
+ if (!windowRestored) {
2172
+ window.scrollTo(0, 0);
2173
+ }
2174
+ }
2175
+ }
2472
2176
 
2473
- if (parent) {
2474
- match.loaderData = replaceEqualDeep(match.loaderData, _extends({}, parent.loaderData, match.routeLoaderData));
2177
+ function defer(_promise) {
2178
+ const promise = _promise;
2179
+ if (!promise.__deferredState) {
2180
+ promise.__deferredState = {
2181
+ uid: Math.random().toString(36).slice(2),
2182
+ status: 'pending'
2183
+ };
2184
+ const state = promise.__deferredState;
2185
+ promise.then(data => {
2186
+ state.status = 'success';
2187
+ state.data = data;
2188
+ }).catch(error => {
2189
+ state.status = 'error';
2190
+ state.error = error;
2191
+ });
2475
2192
  }
2476
- });
2477
- }
2478
-
2479
- exports.cleanPath = cleanPath;
2480
- exports.createBrowserHistory = createBrowserHistory;
2481
- exports.createHashHistory = createHashHistory;
2482
- exports.createMemoryHistory = createMemoryHistory;
2483
- exports.createRoute = createRoute;
2484
- exports.createRouteConfig = createRouteConfig;
2485
- exports.createRouteMatch = createRouteMatch;
2486
- exports.createRouter = createRouter;
2487
- exports.decode = decode;
2488
- exports.defaultParseSearch = defaultParseSearch;
2489
- exports.defaultStringifySearch = defaultStringifySearch;
2490
- exports.encode = encode;
2491
- exports.functionalUpdate = functionalUpdate;
2492
- exports.interpolatePath = interpolatePath;
2493
- exports.invariant = invariant;
2494
- exports.joinPaths = joinPaths;
2495
- exports.last = last;
2496
- exports.matchByPath = matchByPath;
2497
- exports.matchPathname = matchPathname;
2498
- exports.parsePathname = parsePathname;
2499
- exports.parseSearchWith = parseSearchWith;
2500
- exports.pick = pick;
2501
- exports.replaceEqualDeep = replaceEqualDeep;
2502
- exports.resolvePath = resolvePath;
2503
- exports.rootRouteId = rootRouteId;
2504
- exports.stringifySearchWith = stringifySearchWith;
2505
- exports.trimPath = trimPath;
2506
- exports.trimPathLeft = trimPathLeft;
2507
- exports.trimPathRight = trimPathRight;
2508
- exports.warning = warning;
2509
-
2510
- Object.defineProperty(exports, '__esModule', { value: true });
2193
+ return promise;
2194
+ }
2195
+ function isDehydratedDeferred(obj) {
2196
+ return typeof obj === 'object' && obj !== null && !(obj instanceof Promise) && !obj.then && '__deferredState' in obj;
2197
+ }
2198
+
2199
+ exports.FileRoute = FileRoute;
2200
+ exports.PathParamError = PathParamError;
2201
+ exports.RootRoute = RootRoute;
2202
+ exports.Route = Route;
2203
+ exports.Router = Router;
2204
+ exports.RouterContext = RouterContext;
2205
+ exports.SearchParamError = SearchParamError;
2206
+ exports.cleanPath = cleanPath;
2207
+ exports.componentTypes = componentTypes;
2208
+ exports.createBrowserHistory = createBrowserHistory;
2209
+ exports.createHashHistory = createHashHistory;
2210
+ exports.createMemoryHistory = createMemoryHistory;
2211
+ exports.createRouteMask = createRouteMask;
2212
+ exports.decode = decode;
2213
+ exports.defaultParseSearch = defaultParseSearch;
2214
+ exports.defaultStringifySearch = defaultStringifySearch;
2215
+ exports.defer = defer;
2216
+ exports.encode = encode;
2217
+ exports.functionalUpdate = functionalUpdate;
2218
+ exports.interpolatePath = interpolatePath;
2219
+ exports.invariant = invariant;
2220
+ exports.isDehydratedDeferred = isDehydratedDeferred;
2221
+ exports.isMatchInvalid = isMatchInvalid;
2222
+ exports.isPlainObject = isPlainObject;
2223
+ exports.isRedirect = isRedirect;
2224
+ exports.joinPaths = joinPaths;
2225
+ exports.last = last;
2226
+ exports.lazyFn = lazyFn;
2227
+ exports.matchByPath = matchByPath;
2228
+ exports.matchPathname = matchPathname;
2229
+ exports.parsePathname = parsePathname;
2230
+ exports.parseSearchWith = parseSearchWith;
2231
+ exports.partialDeepEqual = partialDeepEqual;
2232
+ exports.pick = pick;
2233
+ exports.redirect = redirect;
2234
+ exports.replaceEqualDeep = replaceEqualDeep;
2235
+ exports.resolvePath = resolvePath;
2236
+ exports.restoreScrollPositions = restoreScrollPositions;
2237
+ exports.rootRouteId = rootRouteId;
2238
+ exports.stringifySearchWith = stringifySearchWith;
2239
+ exports.trimPath = trimPath;
2240
+ exports.trimPathLeft = trimPathLeft;
2241
+ exports.trimPathRight = trimPathRight;
2242
+ exports.warning = warning;
2243
+ exports.watchScrollPositions = watchScrollPositions;
2244
+
2245
+ Object.defineProperty(exports, '__esModule', { value: true });
2511
2246
 
2512
2247
  }));
2513
2248
  //# sourceMappingURL=index.development.js.map