@tanstack/router-core 0.0.1-beta.5 → 0.0.1-beta.50

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