@tanstack/router-core 0.0.1-beta.45 → 0.0.1-beta.49

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 (44) hide show
  1. package/build/cjs/actions.js +94 -0
  2. package/build/cjs/actions.js.map +1 -0
  3. package/build/cjs/history.js +163 -0
  4. package/build/cjs/history.js.map +1 -0
  5. package/build/cjs/index.js +18 -20
  6. package/build/cjs/index.js.map +1 -1
  7. package/build/cjs/interop.js +175 -0
  8. package/build/cjs/interop.js.map +1 -0
  9. package/build/cjs/path.js +4 -5
  10. package/build/cjs/path.js.map +1 -1
  11. package/build/cjs/route.js +16 -138
  12. package/build/cjs/route.js.map +1 -1
  13. package/build/cjs/routeConfig.js +1 -7
  14. package/build/cjs/routeConfig.js.map +1 -1
  15. package/build/cjs/routeMatch.js +194 -199
  16. package/build/cjs/routeMatch.js.map +1 -1
  17. package/build/cjs/router.js +726 -703
  18. package/build/cjs/router.js.map +1 -1
  19. package/build/cjs/store.js +54 -0
  20. package/build/cjs/store.js.map +1 -0
  21. package/build/esm/index.js +1305 -1114
  22. package/build/esm/index.js.map +1 -1
  23. package/build/stats-html.html +1 -1
  24. package/build/stats-react.json +229 -192
  25. package/build/types/index.d.ts +172 -109
  26. package/build/umd/index.development.js +1381 -2331
  27. package/build/umd/index.development.js.map +1 -1
  28. package/build/umd/index.production.js +1 -1
  29. package/build/umd/index.production.js.map +1 -1
  30. package/package.json +3 -3
  31. package/src/actions.ts +157 -0
  32. package/src/history.ts +199 -0
  33. package/src/index.ts +4 -7
  34. package/src/interop.ts +169 -0
  35. package/src/link.ts +2 -2
  36. package/src/route.ts +34 -239
  37. package/src/routeConfig.ts +3 -34
  38. package/src/routeInfo.ts +6 -21
  39. package/src/routeMatch.ts +270 -285
  40. package/src/router.ts +967 -963
  41. package/src/store.ts +52 -0
  42. package/build/cjs/sharedClone.js +0 -122
  43. package/build/cjs/sharedClone.js.map +0 -1
  44. package/src/sharedClone.ts +0 -118
@@ -9,1901 +9,783 @@
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() {
18
- _extends = Object.assign ? Object.assign.bind() : function (target) {
19
- for (var i = 1; i < arguments.length; i++) {
20
- var source = arguments[i];
21
- for (var key in source) {
22
- if (Object.prototype.hasOwnProperty.call(source, key)) {
23
- target[key] = source[key];
24
- }
17
+ var prefix = 'Invariant failed';
18
+ function invariant(condition, message) {
19
+ if (condition) {
20
+ return;
25
21
  }
26
- }
27
- return target;
28
- };
29
- return _extends.apply(this, arguments);
30
- }
31
-
32
- /**
33
- * Actions represent the type of change to a location value.
34
- *
35
- * @see https://github.com/remix-run/history/tree/main/docs/api-reference.md#action
36
- */
37
- var Action;
38
-
39
- (function (Action) {
40
- /**
41
- * A POP indicates a change to an arbitrary index in the history stack, such
42
- * as a back or forward navigation. It does not describe the direction of the
43
- * navigation, only that the current index changed.
44
- *
45
- * Note: This is the default action for newly created history objects.
46
- */
47
- Action["Pop"] = "POP";
48
- /**
49
- * A PUSH indicates a new entry being added to the history stack, such as when
50
- * a link is clicked and a new page loads. When this happens, all subsequent
51
- * entries in the stack are lost.
52
- */
53
-
54
- Action["Push"] = "PUSH";
55
- /**
56
- * A REPLACE indicates the entry at the current index in the history stack
57
- * being replaced by a new one.
58
- */
59
-
60
- Action["Replace"] = "REPLACE";
61
- })(Action || (Action = {}));
62
-
63
- var readOnly = function (obj) {
64
- return Object.freeze(obj);
65
- } ;
66
-
67
- function warning$1(cond, message) {
68
- if (!cond) {
69
- // eslint-disable-next-line no-console
70
- if (typeof console !== 'undefined') console.warn(message);
71
-
72
- try {
73
- // Welcome to debugging history!
74
- //
75
- // This error is thrown as a convenience so you can more easily
76
- // find the source for a warning that appears in the console by
77
- // enabling "pause on exceptions" in your JavaScript debugger.
78
- throw new Error(message); // eslint-disable-next-line no-empty
79
- } catch (e) {}
80
- }
81
- }
82
-
83
- var BeforeUnloadEventType = 'beforeunload';
84
- var HashChangeEventType = 'hashchange';
85
- var PopStateEventType = 'popstate';
86
- /**
87
- * Browser history stores the location in regular URLs. This is the standard for
88
- * most web apps, but it requires some configuration on the server to ensure you
89
- * serve the same app at multiple URLs.
90
- *
91
- * @see https://github.com/remix-run/history/tree/main/docs/api-reference.md#createbrowserhistory
92
- */
93
-
94
- function createBrowserHistory(options) {
95
- if (options === void 0) {
96
- options = {};
97
- }
98
-
99
- var _options = options,
100
- _options$window = _options.window,
101
- window = _options$window === void 0 ? document.defaultView : _options$window;
102
- var globalHistory = window.history;
103
-
104
- function getIndexAndLocation() {
105
- var _window$location = window.location,
106
- pathname = _window$location.pathname,
107
- search = _window$location.search,
108
- hash = _window$location.hash;
109
- var state = globalHistory.state || {};
110
- return [state.idx, readOnly({
111
- pathname: pathname,
112
- search: search,
113
- hash: hash,
114
- state: state.usr || null,
115
- key: state.key || 'default'
116
- })];
117
- }
118
-
119
- var blockedPopTx = null;
120
-
121
- function handlePop() {
122
- if (blockedPopTx) {
123
- blockers.call(blockedPopTx);
124
- blockedPopTx = null;
125
- } else {
126
- var nextAction = Action.Pop;
127
-
128
- var _getIndexAndLocation = getIndexAndLocation(),
129
- nextIndex = _getIndexAndLocation[0],
130
- nextLocation = _getIndexAndLocation[1];
131
-
132
- if (blockers.length) {
133
- if (nextIndex != null) {
134
- var delta = index - nextIndex;
135
-
136
- if (delta) {
137
- // Revert the POP
138
- blockedPopTx = {
139
- action: nextAction,
140
- location: nextLocation,
141
- retry: function retry() {
142
- go(delta * -1);
143
- }
144
- };
145
- go(delta);
146
- }
147
- } else {
148
- // Trying to POP to a location with no index. We did not create
149
- // this location, so we can't effectively block the navigation.
150
- warning$1(false, // TODO: Write up a doc that explains our blocking strategy in
151
- // detail and link to it here so people can understand better what
152
- // is going on and how to avoid it.
153
- "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.") ;
22
+ var provided = typeof message === 'function' ? message() : message;
23
+ var value = provided ? "".concat(prefix, ": ").concat(provided) : prefix;
24
+ throw new Error(value);
25
+ }
26
+
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);
154
47
  }
155
- } else {
156
- 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();
157
75
  }
158
- }
159
- }
160
-
161
- window.addEventListener(PopStateEventType, handlePop);
162
- var action = Action.Pop;
163
-
164
- var _getIndexAndLocation2 = getIndexAndLocation(),
165
- index = _getIndexAndLocation2[0],
166
- location = _getIndexAndLocation2[1];
167
-
168
- var listeners = createEvents();
169
- var blockers = createEvents();
170
-
171
- if (index == null) {
172
- index = 0;
173
- globalHistory.replaceState(_extends({}, globalHistory.state, {
174
- idx: index
175
- }), '');
176
- }
177
-
178
- function createHref(to) {
179
- return typeof to === 'string' ? to : createPath(to);
180
- } // state defaults to `null` because `window.history.state` does
181
-
182
-
183
- function getNextLocation(to, state) {
184
- if (state === void 0) {
185
- state = null;
186
- }
187
-
188
- return readOnly(_extends({
189
- pathname: location.pathname,
190
- hash: '',
191
- search: ''
192
- }, typeof to === 'string' ? parsePath(to) : to, {
193
- state: state,
194
- key: createKey()
195
- }));
76
+ };
196
77
  }
197
-
198
- function getHistoryStateAndUrl(nextLocation, index) {
199
- return [{
200
- usr: nextLocation.state,
201
- key: nextLocation.key,
202
- idx: index
203
- }, 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
+ });
204
106
  }
205
-
206
- function allowTx(action, location, retry) {
207
- return !blockers.length || (blockers.call({
208
- action: action,
209
- location: location,
210
- retry: retry
211
- }), false);
107
+ function createHashHistory() {
108
+ return createBrowserHistory({
109
+ getHref: () => window.location.hash.substring(1),
110
+ createHref: path => `#${path}`
111
+ });
212
112
  }
213
-
214
- function applyTx(nextAction) {
215
- action = nextAction;
216
-
217
- var _getIndexAndLocation3 = getIndexAndLocation();
218
-
219
- index = _getIndexAndLocation3[0];
220
- location = _getIndexAndLocation3[1];
221
- listeners.call({
222
- action: action,
223
- 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)
224
152
  });
225
153
  }
226
-
227
- function push(to, state) {
228
- var nextAction = Action.Push;
229
- var nextLocation = getNextLocation(to, state);
230
-
231
- function retry() {
232
- push(to, state);
233
- }
234
-
235
- if (allowTx(nextAction, nextLocation, retry)) {
236
- var _getHistoryStateAndUr = getHistoryStateAndUrl(nextLocation, index + 1),
237
- historyState = _getHistoryStateAndUr[0],
238
- url = _getHistoryStateAndUr[1]; // TODO: Support forced reloading
239
- // try...catch because iOS limits us to 100 pushState calls :/
240
-
241
-
242
- try {
243
- globalHistory.pushState(historyState, '', url);
244
- } catch (error) {
245
- // They are going to lose state here, but there is no real
246
- // way to warn them about it since the page will refresh...
247
- window.location.assign(url);
248
- }
249
-
250
- applyTx(nextAction);
251
- }
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
+ };
252
165
  }
253
166
 
254
- function replace(to, state) {
255
- var nextAction = Action.Replace;
256
- var nextLocation = getNextLocation(to, state);
257
-
258
- function retry() {
259
- replace(to, state);
260
- }
261
-
262
- if (allowTx(nextAction, nextLocation, retry)) {
263
- var _getHistoryStateAndUr2 = getHistoryStateAndUrl(nextLocation, index),
264
- historyState = _getHistoryStateAndUr2[0],
265
- url = _getHistoryStateAndUr2[1]; // TODO: Support forced reloading
266
-
267
-
268
- globalHistory.replaceState(historyState, '', url);
269
- applyTx(nextAction);
270
- }
167
+ // Thanks co-pilot!
168
+ function createRandomKey() {
169
+ return (Math.random() + 1).toString(36).substring(7);
271
170
  }
272
171
 
273
- function go(delta) {
274
- globalHistory.go(delta);
172
+ function last(arr) {
173
+ return arr[arr.length - 1];
275
174
  }
276
-
277
- var history = {
278
- get action() {
279
- return action;
280
- },
281
-
282
- get location() {
283
- return location;
284
- },
285
-
286
- createHref: createHref,
287
- push: push,
288
- replace: replace,
289
- go: go,
290
- back: function back() {
291
- go(-1);
292
- },
293
- forward: function forward() {
294
- go(1);
295
- },
296
- listen: function listen(listener) {
297
- return listeners.push(listener);
298
- },
299
- block: function block(blocker) {
300
- var unblock = blockers.push(blocker);
301
-
302
- if (blockers.length === 1) {
303
- window.addEventListener(BeforeUnloadEventType, promptBeforeUnload);
304
- }
305
-
306
- return function () {
307
- unblock(); // Remove the beforeunload listener so the document may
308
- // still be salvageable in the pagehide event.
309
- // See https://html.spec.whatwg.org/#unloading-documents
310
-
311
- if (!blockers.length) {
312
- window.removeEventListener(BeforeUnloadEventType, promptBeforeUnload);
313
- }
314
- };
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 {}
315
181
  }
316
- };
317
- return history;
318
- }
319
- /**
320
- * Hash history stores the location in window.location.hash. This makes it ideal
321
- * for situations where you don't want to send the location to the server for
322
- * some reason, either because you do cannot configure it or the URL space is
323
- * reserved for something else.
324
- *
325
- * @see https://github.com/remix-run/history/tree/main/docs/api-reference.md#createhashhistory
326
- */
327
-
328
- function createHashHistory(options) {
329
- if (options === void 0) {
330
- options = {};
331
- }
332
-
333
- var _options2 = options,
334
- _options2$window = _options2.window,
335
- window = _options2$window === void 0 ? document.defaultView : _options2$window;
336
- var globalHistory = window.history;
337
-
338
- function getIndexAndLocation() {
339
- var _parsePath = parsePath(window.location.hash.substr(1)),
340
- _parsePath$pathname = _parsePath.pathname,
341
- pathname = _parsePath$pathname === void 0 ? '/' : _parsePath$pathname,
342
- _parsePath$search = _parsePath.search,
343
- search = _parsePath$search === void 0 ? '' : _parsePath$search,
344
- _parsePath$hash = _parsePath.hash,
345
- hash = _parsePath$hash === void 0 ? '' : _parsePath$hash;
346
-
347
- var state = globalHistory.state || {};
348
- return [state.idx, readOnly({
349
- pathname: pathname,
350
- search: search,
351
- hash: hash,
352
- state: state.usr || null,
353
- key: state.key || 'default'
354
- })];
182
+ return true;
355
183
  }
356
-
357
- var blockedPopTx = null;
358
-
359
- function handlePop() {
360
- if (blockedPopTx) {
361
- blockers.call(blockedPopTx);
362
- blockedPopTx = null;
363
- } else {
364
- var nextAction = Action.Pop;
365
-
366
- var _getIndexAndLocation4 = getIndexAndLocation(),
367
- nextIndex = _getIndexAndLocation4[0],
368
- nextLocation = _getIndexAndLocation4[1];
369
-
370
- if (blockers.length) {
371
- if (nextIndex != null) {
372
- var delta = index - nextIndex;
373
-
374
- if (delta) {
375
- // Revert the POP
376
- blockedPopTx = {
377
- action: nextAction,
378
- location: nextLocation,
379
- retry: function retry() {
380
- go(delta * -1);
381
- }
382
- };
383
- go(delta);
384
- }
385
- } else {
386
- // Trying to POP to a location with no index. We did not create
387
- // this location, so we can't effectively block the navigation.
388
- warning$1(false, // TODO: Write up a doc that explains our blocking strategy in
389
- // detail and link to it here so people can understand better
390
- // what is going on and how to avoid it.
391
- "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.") ;
184
+ function isFunction(d) {
185
+ return typeof d === 'function';
186
+ }
187
+ function functionalUpdate(updater, previous) {
188
+ if (isFunction(updater)) {
189
+ return updater(previous);
190
+ }
191
+ return updater;
192
+ }
193
+ function pick(parent, keys) {
194
+ return keys.reduce((obj, key) => {
195
+ obj[key] = parent[key];
196
+ return obj;
197
+ }, {});
198
+ }
199
+
200
+ function joinPaths(paths) {
201
+ return cleanPath(paths.filter(Boolean).join('/'));
202
+ }
203
+ function cleanPath(path) {
204
+ // remove double slashes
205
+ return path.replace(/\/{2,}/g, '/');
206
+ }
207
+ function trimPathLeft(path) {
208
+ return path === '/' ? path : path.replace(/^\/{1,}/, '');
209
+ }
210
+ function trimPathRight(path) {
211
+ return path === '/' ? path : path.replace(/\/{1,}$/, '');
212
+ }
213
+ function trimPath(path) {
214
+ return trimPathRight(trimPathLeft(path));
215
+ }
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();
392
234
  }
235
+ baseSegments.pop();
236
+ } else if (toSegment.value === '.') {
237
+ return;
393
238
  } else {
394
- applyTx(nextAction);
239
+ baseSegments.push(toSegment);
395
240
  }
396
- }
397
- }
398
-
399
- window.addEventListener(PopStateEventType, handlePop); // popstate does not fire on hashchange in IE 11 and old (trident) Edge
400
- // https://developer.mozilla.org/de/docs/Web/API/Window/popstate_event
401
-
402
- window.addEventListener(HashChangeEventType, function () {
403
- var _getIndexAndLocation5 = getIndexAndLocation(),
404
- nextLocation = _getIndexAndLocation5[1]; // Ignore extraneous hashchange events.
405
-
406
-
407
- if (createPath(nextLocation) !== createPath(location)) {
408
- handlePop();
409
- }
410
- });
411
- var action = Action.Pop;
412
-
413
- var _getIndexAndLocation6 = getIndexAndLocation(),
414
- index = _getIndexAndLocation6[0],
415
- location = _getIndexAndLocation6[1];
416
-
417
- var listeners = createEvents();
418
- var blockers = createEvents();
419
-
420
- if (index == null) {
421
- index = 0;
422
- globalHistory.replaceState(_extends({}, globalHistory.state, {
423
- idx: index
424
- }), '');
425
- }
426
-
427
- function getBaseHref() {
428
- var base = document.querySelector('base');
429
- var href = '';
430
-
431
- if (base && base.getAttribute('href')) {
432
- var url = window.location.href;
433
- var hashIndex = url.indexOf('#');
434
- href = hashIndex === -1 ? url : url.slice(0, hashIndex);
435
- }
436
-
437
- return href;
438
- }
439
-
440
- function createHref(to) {
441
- return getBaseHref() + '#' + (typeof to === 'string' ? to : createPath(to));
442
- }
443
-
444
- function getNextLocation(to, state) {
445
- if (state === void 0) {
446
- state = null;
447
- }
448
-
449
- return readOnly(_extends({
450
- pathname: location.pathname,
451
- hash: '',
452
- search: ''
453
- }, typeof to === 'string' ? parsePath(to) : to, {
454
- state: state,
455
- key: createKey()
456
- }));
457
- }
458
-
459
- function getHistoryStateAndUrl(nextLocation, index) {
460
- return [{
461
- usr: nextLocation.state,
462
- key: nextLocation.key,
463
- idx: index
464
- }, createHref(nextLocation)];
465
- }
466
-
467
- function allowTx(action, location, retry) {
468
- return !blockers.length || (blockers.call({
469
- action: action,
470
- location: location,
471
- retry: retry
472
- }), false);
473
- }
474
-
475
- function applyTx(nextAction) {
476
- action = nextAction;
477
-
478
- var _getIndexAndLocation7 = getIndexAndLocation();
479
-
480
- index = _getIndexAndLocation7[0];
481
- location = _getIndexAndLocation7[1];
482
- listeners.call({
483
- action: action,
484
- location: location
485
241
  });
486
- }
487
-
488
- function push(to, state) {
489
- var nextAction = Action.Push;
490
- var nextLocation = getNextLocation(to, state);
491
-
492
- function retry() {
493
- push(to, state);
494
- }
495
-
496
- warning$1(nextLocation.pathname.charAt(0) === '/', "Relative pathnames are not supported in hash history.push(" + JSON.stringify(to) + ")") ;
497
-
498
- if (allowTx(nextAction, nextLocation, retry)) {
499
- var _getHistoryStateAndUr3 = getHistoryStateAndUrl(nextLocation, index + 1),
500
- historyState = _getHistoryStateAndUr3[0],
501
- url = _getHistoryStateAndUr3[1]; // TODO: Support forced reloading
502
- // try...catch because iOS limits us to 100 pushState calls :/
503
-
504
-
505
- try {
506
- globalHistory.pushState(historyState, '', url);
507
- } catch (error) {
508
- // They are going to lose state here, but there is no real
509
- // way to warn them about it since the page will refresh...
510
- window.location.assign(url);
511
- }
512
-
513
- applyTx(nextAction);
242
+ const joined = joinPaths([basepath, ...baseSegments.map(d => d.value)]);
243
+ return cleanPath(joined);
244
+ }
245
+ function parsePathname(pathname) {
246
+ if (!pathname) {
247
+ return [];
248
+ }
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
+ });
514
257
  }
515
- }
516
-
517
- function replace(to, state) {
518
- var nextAction = Action.Replace;
519
- var nextLocation = getNextLocation(to, state);
520
-
521
- function retry() {
522
- replace(to, state);
258
+ if (!pathname) {
259
+ return segments;
523
260
  }
524
261
 
525
- warning$1(nextLocation.pathname.charAt(0) === '/', "Relative pathnames are not supported in hash history.replace(" + JSON.stringify(to) + ")") ;
526
-
527
- if (allowTx(nextAction, nextLocation, retry)) {
528
- var _getHistoryStateAndUr4 = getHistoryStateAndUrl(nextLocation, index),
529
- historyState = _getHistoryStateAndUr4[0],
530
- url = _getHistoryStateAndUr4[1]; // TODO: Support forced reloading
531
-
532
-
533
- globalHistory.replaceState(historyState, '', url);
534
- applyTx(nextAction);
535
- }
536
- }
537
-
538
- function go(delta) {
539
- globalHistory.go(delta);
540
- }
541
-
542
- var history = {
543
- get action() {
544
- return action;
545
- },
546
-
547
- get location() {
548
- return location;
549
- },
550
-
551
- createHref: createHref,
552
- push: push,
553
- replace: replace,
554
- go: go,
555
- back: function back() {
556
- go(-1);
557
- },
558
- forward: function forward() {
559
- go(1);
560
- },
561
- listen: function listen(listener) {
562
- return listeners.push(listener);
563
- },
564
- block: function block(blocker) {
565
- var unblock = blockers.push(blocker);
566
-
567
- if (blockers.length === 1) {
568
- 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
+ };
569
270
  }
570
-
571
- return function () {
572
- unblock(); // Remove the beforeunload listener so the document may
573
- // still be salvageable in the pagehide event.
574
- // See https://html.spec.whatwg.org/#unloading-documents
575
-
576
- if (!blockers.length) {
577
- window.removeEventListener(BeforeUnloadEventType, promptBeforeUnload);
578
- }
271
+ if (part.charAt(0) === '$') {
272
+ return {
273
+ type: 'param',
274
+ value: part
275
+ };
276
+ }
277
+ return {
278
+ type: 'pathname',
279
+ value: part
579
280
  };
580
- }
581
- };
582
- return history;
583
- }
584
- /**
585
- * Memory history stores the current location in memory. It is designed for use
586
- * in stateful non-browser environments like tests and React Native.
587
- *
588
- * @see https://github.com/remix-run/history/tree/main/docs/api-reference.md#creatememoryhistory
589
- */
590
-
591
- function createMemoryHistory(options) {
592
- if (options === void 0) {
593
- options = {};
594
- }
595
-
596
- var _options3 = options,
597
- _options3$initialEntr = _options3.initialEntries,
598
- initialEntries = _options3$initialEntr === void 0 ? ['/'] : _options3$initialEntr,
599
- initialIndex = _options3.initialIndex;
600
- var entries = initialEntries.map(function (entry) {
601
- var location = readOnly(_extends({
602
- pathname: '/',
603
- search: '',
604
- hash: '',
605
- state: null,
606
- key: createKey()
607
- }, typeof entry === 'string' ? parsePath(entry) : entry));
608
- warning$1(location.pathname.charAt(0) === '/', "Relative pathnames are not supported in createMemoryHistory({ initialEntries }) (invalid entry: " + JSON.stringify(entry) + ")") ;
609
- return location;
610
- });
611
- var index = clamp(initialIndex == null ? entries.length - 1 : initialIndex, 0, entries.length - 1);
612
- var action = Action.Pop;
613
- var location = entries[index];
614
- var listeners = createEvents();
615
- var blockers = createEvents();
616
-
617
- function createHref(to) {
618
- return typeof to === 'string' ? to : createPath(to);
619
- }
620
-
621
- function getNextLocation(to, state) {
622
- if (state === void 0) {
623
- state = null;
624
- }
625
-
626
- return readOnly(_extends({
627
- pathname: location.pathname,
628
- search: '',
629
- hash: ''
630
- }, typeof to === 'string' ? parsePath(to) : to, {
631
- state: state,
632
- key: createKey()
633
281
  }));
634
- }
635
-
636
- function allowTx(action, location, retry) {
637
- return !blockers.length || (blockers.call({
638
- action: action,
639
- location: location,
640
- retry: retry
641
- }), false);
642
- }
643
-
644
- function applyTx(nextAction, nextLocation) {
645
- action = nextAction;
646
- location = nextLocation;
647
- listeners.call({
648
- action: action,
649
- location: location
650
- });
651
- }
652
-
653
- function push(to, state) {
654
- var nextAction = Action.Push;
655
- var nextLocation = getNextLocation(to, state);
656
-
657
- function retry() {
658
- push(to, state);
659
- }
660
-
661
- warning$1(location.pathname.charAt(0) === '/', "Relative pathnames are not supported in memory history.push(" + JSON.stringify(to) + ")") ;
662
-
663
- if (allowTx(nextAction, nextLocation, retry)) {
664
- index += 1;
665
- entries.splice(index, entries.length, nextLocation);
666
- applyTx(nextAction, nextLocation);
667
- }
668
- }
669
-
670
- function replace(to, state) {
671
- var nextAction = Action.Replace;
672
- var nextLocation = getNextLocation(to, state);
673
-
674
- function retry() {
675
- replace(to, state);
676
- }
677
-
678
- warning$1(location.pathname.charAt(0) === '/', "Relative pathnames are not supported in memory history.replace(" + JSON.stringify(to) + ")") ;
679
-
680
- if (allowTx(nextAction, nextLocation, retry)) {
681
- entries[index] = nextLocation;
682
- applyTx(nextAction, nextLocation);
683
- }
684
- }
685
-
686
- function go(delta) {
687
- var nextIndex = clamp(index + delta, 0, entries.length - 1);
688
- var nextAction = Action.Pop;
689
- var nextLocation = entries[nextIndex];
690
-
691
- function retry() {
692
- go(delta);
693
- }
694
-
695
- if (allowTx(nextAction, nextLocation, retry)) {
696
- index = nextIndex;
697
- applyTx(nextAction, nextLocation);
698
- }
699
- }
700
-
701
- var history = {
702
- get index() {
703
- return index;
704
- },
705
-
706
- get action() {
707
- return action;
708
- },
709
-
710
- get location() {
711
- return location;
712
- },
713
-
714
- createHref: createHref,
715
- push: push,
716
- replace: replace,
717
- go: go,
718
- back: function back() {
719
- go(-1);
720
- },
721
- forward: function forward() {
722
- go(1);
723
- },
724
- listen: function listen(listener) {
725
- return listeners.push(listener);
726
- },
727
- block: function block(blocker) {
728
- return blockers.push(blocker);
729
- }
730
- };
731
- return history;
732
- } ////////////////////////////////////////////////////////////////////////////////
733
- // UTILS
734
- ////////////////////////////////////////////////////////////////////////////////
735
-
736
- function clamp(n, lowerBound, upperBound) {
737
- return Math.min(Math.max(n, lowerBound), upperBound);
738
- }
739
-
740
- function promptBeforeUnload(event) {
741
- // Cancel the event.
742
- event.preventDefault(); // Chrome (and legacy IE) requires returnValue to be set.
743
-
744
- event.returnValue = '';
745
- }
746
-
747
- function createEvents() {
748
- var handlers = [];
749
- return {
750
- get length() {
751
- return handlers.length;
752
- },
753
-
754
- push: function push(fn) {
755
- handlers.push(fn);
756
- return function () {
757
- handlers = handlers.filter(function (handler) {
758
- return handler !== fn;
759
- });
760
- };
761
- },
762
- call: function call(arg) {
763
- handlers.forEach(function (fn) {
764
- return fn && fn(arg);
282
+ if (pathname.slice(-1) === '/') {
283
+ pathname = pathname.substring(1);
284
+ segments.push({
285
+ type: 'pathname',
286
+ value: '/'
765
287
  });
766
288
  }
767
- };
768
- }
769
-
770
- function createKey() {
771
- return Math.random().toString(36).substr(2, 8);
772
- }
773
- /**
774
- * Creates a string URL path from the given pathname, search, and hash components.
775
- *
776
- * @see https://github.com/remix-run/history/tree/main/docs/api-reference.md#createpath
777
- */
778
-
779
-
780
- function createPath(_ref) {
781
- var _ref$pathname = _ref.pathname,
782
- pathname = _ref$pathname === void 0 ? '/' : _ref$pathname,
783
- _ref$search = _ref.search,
784
- search = _ref$search === void 0 ? '' : _ref$search,
785
- _ref$hash = _ref.hash,
786
- hash = _ref$hash === void 0 ? '' : _ref$hash;
787
- if (search && search !== '?') pathname += search.charAt(0) === '?' ? search : '?' + search;
788
- if (hash && hash !== '#') pathname += hash.charAt(0) === '#' ? hash : '#' + hash;
789
- return pathname;
790
- }
791
- /**
792
- * Parses a string URL path into its separate pathname, search, and hash components.
793
- *
794
- * @see https://github.com/remix-run/history/tree/main/docs/api-reference.md#parsepath
795
- */
796
-
797
- function parsePath(path) {
798
- var parsedPath = {};
799
-
800
- if (path) {
801
- var hashIndex = path.indexOf('#');
802
-
803
- if (hashIndex >= 0) {
804
- parsedPath.hash = path.substr(hashIndex);
805
- path = path.substr(0, hashIndex);
806
- }
807
-
808
- var searchIndex = path.indexOf('?');
809
-
810
- if (searchIndex >= 0) {
811
- parsedPath.search = path.substr(searchIndex);
812
- path = path.substr(0, searchIndex);
813
- }
814
-
815
- if (path) {
816
- parsedPath.pathname = path;
817
- }
818
- }
819
-
820
- return parsedPath;
821
- }
822
-
823
- var prefix = 'Invariant failed';
824
- function invariant(condition, message) {
825
- if (condition) {
826
- return;
827
- }
828
- var provided = typeof message === 'function' ? message() : message;
829
- var value = provided ? "".concat(prefix, ": ").concat(provided) : prefix;
830
- throw new Error(value);
831
- }
832
-
833
- function last(arr) {
834
- return arr[arr.length - 1];
835
- }
836
- function warning(cond, message) {
837
- if (cond) {
838
- if (typeof console !== 'undefined') console.warn(message);
839
- try {
840
- throw new Error(message);
841
- } catch {}
842
- }
843
- return true;
844
- }
845
- function isFunction(d) {
846
- return typeof d === 'function';
847
- }
848
- function functionalUpdate(updater, previous) {
849
- if (isFunction(updater)) {
850
- return updater(previous);
289
+ return segments;
851
290
  }
852
- return updater;
853
- }
854
- function pick(parent, keys) {
855
- return keys.reduce((obj, key) => {
856
- obj[key] = parent[key];
857
- return obj;
858
- }, {});
859
- }
860
-
861
- function joinPaths(paths) {
862
- return cleanPath(paths.filter(Boolean).join('/'));
863
- }
864
- function cleanPath(path) {
865
- // remove double slashes
866
- return path.replace(/\/{2,}/g, '/');
867
- }
868
- function trimPathLeft(path) {
869
- return path === '/' ? path : path.replace(/^\/{1,}/, '');
870
- }
871
- function trimPathRight(path) {
872
- return path === '/' ? path : path.replace(/\/{1,}$/, '');
873
- }
874
- function trimPath(path) {
875
- return trimPathRight(trimPathLeft(path));
876
- }
877
- function resolvePath(basepath, base, to) {
878
- base = base.replace(new RegExp(`^${basepath}`), '/');
879
- to = to.replace(new RegExp(`^${basepath}`), '/');
880
- let baseSegments = parsePathname(base);
881
- const toSegments = parsePathname(to);
882
- toSegments.forEach((toSegment, index) => {
883
- if (toSegment.value === '/') {
884
- if (!index) {
885
- // Leading slash
886
- baseSegments = [toSegment];
887
- } else if (index === toSegments.length - 1) {
888
- // Trailing Slash
889
- baseSegments.push(toSegment);
890
- } else ;
891
- } else if (toSegment.value === '..') {
892
- var _last;
893
- // Extra trailing slash? pop it off
894
- if (baseSegments.length > 1 && ((_last = last(baseSegments)) == null ? void 0 : _last.value) === '/') {
895
- baseSegments.pop();
291
+ function interpolatePath(path, params, leaveWildcard) {
292
+ const interpolatedPathSegments = parsePathname(path);
293
+ return joinPaths(interpolatedPathSegments.map(segment => {
294
+ if (segment.value === '*' && !leaveWildcard) {
295
+ return '';
896
296
  }
897
- baseSegments.pop();
898
- } else if (toSegment.value === '.') {
899
- return;
900
- } else {
901
- baseSegments.push(toSegment);
902
- }
903
- });
904
- const joined = joinPaths([basepath, ...baseSegments.map(d => d.value)]);
905
- return cleanPath(joined);
906
- }
907
- function parsePathname(pathname) {
908
- if (!pathname) {
909
- return [];
910
- }
911
- pathname = cleanPath(pathname);
912
- const segments = [];
913
- if (pathname.slice(0, 1) === '/') {
914
- pathname = pathname.substring(1);
915
- segments.push({
916
- type: 'pathname',
917
- value: '/'
918
- });
919
- }
920
- if (!pathname) {
921
- return segments;
297
+ if (segment.type === 'param') {
298
+ return params[segment.value.substring(1)] ?? '';
299
+ }
300
+ return segment.value;
301
+ }));
922
302
  }
303
+ function matchPathname(basepath, currentPathname, matchLocation) {
304
+ const pathParams = matchByPath(basepath, currentPathname, matchLocation);
305
+ // const searchMatched = matchBySearch(currentLocation.search, matchLocation)
923
306
 
924
- // Remove empty segments and '.' segments
925
- const split = pathname.split('/').filter(Boolean);
926
- segments.push(...split.map(part => {
927
- if (part.startsWith('*')) {
928
- return {
929
- type: 'wildcard',
930
- value: part
931
- };
932
- }
933
- if (part.charAt(0) === '$') {
934
- return {
935
- type: 'param',
936
- value: part
937
- };
938
- }
939
- return {
940
- type: 'pathname',
941
- value: part
942
- };
943
- }));
944
- if (pathname.slice(-1) === '/') {
945
- pathname = pathname.substring(1);
946
- segments.push({
947
- type: 'pathname',
948
- value: '/'
949
- });
950
- }
951
- return segments;
952
- }
953
- function interpolatePath(path, params, leaveWildcard) {
954
- const interpolatedPathSegments = parsePathname(path);
955
- return joinPaths(interpolatedPathSegments.map(segment => {
956
- if (segment.value === '*' && !leaveWildcard) {
957
- return '';
958
- }
959
- if (segment.type === 'param') {
960
- return params[segment.value.substring(1)] ?? '';
307
+ if (matchLocation.to && !pathParams) {
308
+ return;
961
309
  }
962
- return segment.value;
963
- }));
964
- }
965
- function matchPathname(basepath, currentPathname, matchLocation) {
966
- const pathParams = matchByPath(basepath, currentPathname, matchLocation);
967
- // const searchMatched = matchBySearch(currentLocation.search, matchLocation)
968
-
969
- if (matchLocation.to && !pathParams) {
970
- return;
971
- }
972
- return pathParams ?? {};
973
- }
974
- function matchByPath(basepath, from, matchLocation) {
975
- if (!from.startsWith(basepath)) {
976
- return undefined;
977
- }
978
- from = basepath != '/' ? from.substring(basepath.length) : from;
979
- const baseSegments = parsePathname(from);
980
- const to = `${matchLocation.to ?? '*'}`;
981
- const routeSegments = parsePathname(to);
982
- const params = {};
983
- let isMatch = (() => {
984
- for (let i = 0; i < Math.max(baseSegments.length, routeSegments.length); i++) {
985
- const baseSegment = baseSegments[i];
986
- const routeSegment = routeSegments[i];
987
- const isLastRouteSegment = i === routeSegments.length - 1;
988
- const isLastBaseSegment = i === baseSegments.length - 1;
989
- if (routeSegment) {
990
- if (routeSegment.type === 'wildcard') {
991
- if (baseSegment != null && baseSegment.value) {
992
- params['*'] = joinPaths(baseSegments.slice(i).map(d => d.value));
993
- return true;
994
- }
995
- return false;
996
- }
997
- if (routeSegment.type === 'pathname') {
998
- if (routeSegment.value === '/' && !(baseSegment != null && baseSegment.value)) {
999
- return true;
310
+ return pathParams ?? {};
311
+ }
312
+ function matchByPath(basepath, from, matchLocation) {
313
+ if (!from.startsWith(basepath)) {
314
+ return undefined;
315
+ }
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;
1000
334
  }
1001
- if (baseSegment) {
1002
- if (matchLocation.caseSensitive) {
1003
- 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()) {
1004
345
  return false;
1005
346
  }
1006
- } else if (routeSegment.value.toLowerCase() !== baseSegment.value.toLowerCase()) {
1007
- return false;
1008
347
  }
1009
348
  }
1010
- }
1011
- if (!baseSegment) {
1012
- return false;
1013
- }
1014
- if (routeSegment.type === 'param') {
1015
- if ((baseSegment == null ? void 0 : baseSegment.value) === '/') {
349
+ if (!baseSegment) {
1016
350
  return false;
1017
351
  }
1018
- if (baseSegment.value.charAt(0) !== '$') {
1019
- 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
+ }
1020
359
  }
1021
360
  }
1022
- }
1023
- if (isLastRouteSegment && !isLastBaseSegment) {
1024
- return !!matchLocation.fuzzy;
1025
- }
1026
- }
1027
- return true;
1028
- })();
1029
- return isMatch ? params : undefined;
1030
- }
1031
-
1032
- // @ts-nocheck
1033
-
1034
- // 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.
1035
-
1036
- function encode(obj, pfx) {
1037
- var k,
1038
- i,
1039
- tmp,
1040
- str = '';
1041
- for (k in obj) {
1042
- if ((tmp = obj[k]) !== void 0) {
1043
- if (Array.isArray(tmp)) {
1044
- for (i = 0; i < tmp.length; i++) {
1045
- str && (str += '&');
1046
- str += encodeURIComponent(k) + '=' + encodeURIComponent(tmp[i]);
1047
- }
1048
- } else {
1049
- str && (str += '&');
1050
- str += encodeURIComponent(k) + '=' + encodeURIComponent(tmp);
1051
- }
1052
- }
1053
- }
1054
- return (pfx || '') + str;
1055
- }
1056
- function toValue(mix) {
1057
- if (!mix) return '';
1058
- var str = decodeURIComponent(mix);
1059
- if (str === 'false') return false;
1060
- if (str === 'true') return true;
1061
- if (str.charAt(0) === '0') return str;
1062
- return +str * 0 === 0 ? +str : str;
1063
- }
1064
- function decode(str) {
1065
- var tmp,
1066
- k,
1067
- out = {},
1068
- arr = str.split('&');
1069
- while (tmp = arr.shift()) {
1070
- tmp = tmp.split('=');
1071
- k = tmp.shift();
1072
- if (out[k] !== void 0) {
1073
- out[k] = [].concat(out[k], toValue(tmp.shift()));
1074
- } else {
1075
- out[k] = toValue(tmp.shift());
1076
- }
1077
- }
1078
- return out;
1079
- }
1080
-
1081
- // src/core.ts
1082
- var CurrentReaction = void 0;
1083
- var CurrentGets = null;
1084
- var CurrentGetsIndex = 0;
1085
- var EffectQueue = null;
1086
- var CacheClean = 0;
1087
- var CacheCheck = 1;
1088
- var CacheDirty = 2;
1089
- var Reactive = class {
1090
- value;
1091
- fn;
1092
- observers = null;
1093
- sources = null;
1094
- state;
1095
- effect;
1096
- cleanups = null;
1097
- alwaysUpdate = false;
1098
- constructor(fnOrValue, type) {
1099
- if (type != 0 /* Signal */) {
1100
- this.fn = fnOrValue;
1101
- this.value = void 0;
1102
- this.state = CacheDirty;
1103
- console.error("Memos and effects must be wrapped in a createRoot");
1104
- this.effect = type == 2 /* Effect */;
1105
- if (this.effect)
1106
- this.update();
1107
- } else {
1108
- this.fn = void 0;
1109
- this.value = fnOrValue;
1110
- this.state = CacheClean;
1111
- this.effect = false;
1112
- }
1113
- }
1114
- get() {
1115
- if (CurrentReaction) {
1116
- if (!CurrentGets && CurrentReaction.sources && CurrentReaction.sources[CurrentGetsIndex] == this) {
1117
- CurrentGetsIndex++;
1118
- } else {
1119
- if (!CurrentGets)
1120
- CurrentGets = [this];
1121
- else
1122
- CurrentGets.push(this);
1123
- }
1124
- }
1125
- if (this.fn)
1126
- this.updateIfNecessary();
1127
- return this.value;
1128
- }
1129
- set(value) {
1130
- const notInBatch = !EffectQueue;
1131
- const newValue = typeof value === "function" ? value(this.value) : value;
1132
- if ((this.value !== newValue || this.alwaysUpdate) && this.observers) {
1133
- for (let i = 0; i < this.observers.length; i++) {
1134
- this.observers[i].stale(CacheDirty);
1135
- }
1136
- }
1137
- this.value = newValue;
1138
- if (notInBatch)
1139
- stabilize();
1140
- return newValue;
1141
- }
1142
- stale(state) {
1143
- if (this.state < state) {
1144
- if (this.state === CacheClean && this.effect) {
1145
- if (EffectQueue)
1146
- EffectQueue.push(this);
1147
- else
1148
- EffectQueue = [this];
1149
- }
1150
- this.state = state;
1151
- if (this.observers) {
1152
- for (let i = 0; i < this.observers.length; i++) {
1153
- this.observers[i].stale(CacheCheck);
361
+ if (isLastRouteSegment && !isLastBaseSegment) {
362
+ return !!matchLocation.fuzzy;
1154
363
  }
1155
364
  }
1156
- }
365
+ return true;
366
+ })();
367
+ return isMatch ? params : undefined;
1157
368
  }
1158
- update() {
1159
- const oldValue = this.value;
1160
- const prevReaction = CurrentReaction;
1161
- const prevGets = CurrentGets;
1162
- const prevIndex = CurrentGetsIndex;
1163
- CurrentReaction = this;
1164
- CurrentGets = null;
1165
- CurrentGetsIndex = 0;
1166
- try {
1167
- if (this.cleanups) {
1168
- this.cleanups.forEach((c) => c());
1169
- this.cleanups = null;
1170
- }
1171
- this.value = this.fn();
1172
- if (CurrentGets) {
1173
- this.removeParentObservers(CurrentGetsIndex);
1174
- if (this.sources && CurrentGetsIndex > 0) {
1175
- this.sources.length = CurrentGetsIndex + CurrentGets.length;
1176
- for (let i = 0; i < CurrentGets.length; i++) {
1177
- this.sources[CurrentGetsIndex + i] = CurrentGets[i];
369
+
370
+ // @ts-nocheck
371
+
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.
373
+
374
+ function encode(obj, pfx) {
375
+ var k,
376
+ i,
377
+ tmp,
378
+ str = '';
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]);
1178
385
  }
1179
386
  } else {
1180
- this.sources = CurrentGets;
1181
- }
1182
- for (let i = CurrentGetsIndex; i < this.sources.length; i++) {
1183
- const source = this.sources[i];
1184
- if (!source.observers) {
1185
- source.observers = [this];
1186
- } else {
1187
- source.observers.push(this);
1188
- }
387
+ str && (str += '&');
388
+ str += encodeURIComponent(k) + '=' + encodeURIComponent(tmp);
1189
389
  }
1190
- } else if (this.sources && CurrentGetsIndex < this.sources.length) {
1191
- this.removeParentObservers(CurrentGetsIndex);
1192
- this.sources.length = CurrentGetsIndex;
1193
390
  }
1194
- } finally {
1195
- CurrentGets = prevGets;
1196
- CurrentReaction = prevReaction;
1197
- CurrentGetsIndex = prevIndex;
1198
391
  }
1199
- if ((oldValue !== this.value || this.alwaysUpdate) && this.observers) {
1200
- for (let i = 0; i < this.observers.length; i++) {
1201
- this.observers[i].state = CacheDirty;
392
+ return (pfx || '') + str;
393
+ }
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,
404
+ k,
405
+ out = {},
406
+ arr = str.split('&');
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());
1202
414
  }
1203
415
  }
1204
- this.state = CacheClean;
416
+ return out;
1205
417
  }
1206
- updateIfNecessary() {
1207
- if (this.state === CacheCheck) {
1208
- for (const source of this.sources) {
1209
- source.updateIfNecessary();
1210
- if (this.state === CacheDirty) {
1211
- break;
1212
- }
1213
- }
1214
- }
1215
- if (this.state === CacheDirty) {
1216
- this.update();
1217
- }
1218
- this.state = CacheClean;
1219
- }
1220
- removeParentObservers(index) {
1221
- if (!this.sources)
1222
- return;
1223
- for (let i = index; i < this.sources.length; i++) {
1224
- const source = this.sources[i];
1225
- const swap = source.observers.findIndex((v) => v === this);
1226
- source.observers[swap] = source.observers[source.observers.length - 1];
1227
- source.observers.pop();
1228
- }
1229
- }
1230
- destroy() {
1231
- if (this.cleanups) {
1232
- this.cleanups.forEach((c) => c());
1233
- this.cleanups = null;
418
+
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
+ });
1234
433
  }
1235
- this.removeParentObservers(0);
1236
- }
1237
- };
1238
- function stabilize() {
1239
- if (!EffectQueue)
1240
- return;
1241
- for (let i = 0; i < EffectQueue.length; i++) {
1242
- EffectQueue[i].get();
1243
434
  }
1244
- EffectQueue = null;
1245
- }
1246
- function batch(fn) {
1247
- EffectQueue = [];
1248
- let out = fn();
1249
- stabilize();
1250
- return out;
1251
- }
1252
-
1253
- // src/store.ts
1254
- var $RAW = Symbol("store-raw");
1255
- var $TRACK = Symbol("track");
1256
- var $PROXY = Symbol("store-proxy");
1257
- var $NODE = Symbol("store-node");
1258
- function wrap(value) {
1259
- let p = value[$PROXY];
1260
- if (!p) {
1261
- Object.defineProperty(value, $PROXY, {
1262
- value: p = new Proxy(value, proxyTraps)
1263
- });
1264
- if (!Array.isArray(value)) {
1265
- const keys = Object.keys(value);
1266
- const desc = Object.getOwnPropertyDescriptors(value);
1267
- for (let i = 0, l = keys.length; i < l; i++) {
1268
- const prop = keys[i];
1269
- if (desc[prop].get) {
1270
- const get = desc[prop].get.bind(p);
1271
- Object.defineProperty(value, prop, {
1272
- enumerable: desc[prop].enumerable,
1273
- get
1274
- });
1275
- }
1276
- }
435
+
436
+ const rootRouteId = '__root__';
437
+ const createRouteConfig = (options = {}, children = [], isRoot = true, parentId, parentPath) => {
438
+ if (isRoot) {
439
+ options.path = rootRouteId;
1277
440
  }
1278
- }
1279
- return p;
1280
- }
1281
- function isWrappable(obj) {
1282
- let proto;
1283
- return obj != null && typeof obj === "object" && (obj[$PROXY] || !(proto = Object.getPrototypeOf(obj)) || proto === Object.prototype || Array.isArray(obj));
1284
- }
1285
- function unwrap(item, set = /* @__PURE__ */ new Set()) {
1286
- let result, unwrapped, v, prop;
1287
- if (result = item != null && item[$RAW])
1288
- return result;
1289
- if (!isWrappable(item) || set.has(item))
1290
- return item;
1291
- if (Array.isArray(item)) {
1292
- if (Object.isFrozen(item))
1293
- item = item.slice(0);
1294
- else
1295
- set.add(item);
1296
- for (let i = 0, l = item.length; i < l; i++) {
1297
- v = item[i];
1298
- if ((unwrapped = unwrap(v, set)) !== v)
1299
- item[i] = unwrapped;
441
+
442
+ // Strip the root from parentIds
443
+ if (parentId === rootRouteId) {
444
+ parentId = '';
1300
445
  }
1301
- } else {
1302
- if (Object.isFrozen(item))
1303
- item = Object.assign({}, item);
1304
- else
1305
- set.add(item);
1306
- const keys = Object.keys(item);
1307
- const desc = Object.getOwnPropertyDescriptors(item);
1308
- for (let i = 0, l = keys.length; i < l; i++) {
1309
- prop = keys[i];
1310
- if (desc[prop].get)
1311
- continue;
1312
- v = item[prop];
1313
- if ((unwrapped = unwrap(v, set)) !== v)
1314
- item[prop] = unwrapped;
446
+ let path = isRoot ? rootRouteId : options.path;
447
+
448
+ // If the path is anything other than an index path, trim it up
449
+ if (path && path !== '/') {
450
+ path = trimPath(path);
1315
451
  }
1316
- }
1317
- return item;
1318
- }
1319
- function getDataNodes(target) {
1320
- let nodes = target[$NODE];
1321
- if (!nodes)
1322
- Object.defineProperty(target, $NODE, { value: nodes = {} });
1323
- return nodes;
1324
- }
1325
- function getDataNode(nodes, property, value) {
1326
- return nodes[property] || (nodes[property] = createDataNode(value));
1327
- }
1328
- function proxyDescriptor(target, property) {
1329
- const desc = Reflect.getOwnPropertyDescriptor(target, property);
1330
- if (!desc || desc.get || !desc.configurable || property === $PROXY || property === $NODE)
1331
- return desc;
1332
- delete desc.value;
1333
- delete desc.writable;
1334
- desc.get = () => target[$PROXY][property];
1335
- return desc;
1336
- }
1337
- function trackSelf(target) {
1338
- if (CurrentReaction) {
1339
- const nodes = getDataNodes(target);
1340
- (nodes._ || (nodes._ = createDataNode())).get();
1341
- }
1342
- }
1343
- function ownKeys(target) {
1344
- trackSelf(target);
1345
- return Reflect.ownKeys(target);
1346
- }
1347
- function createDataNode(value) {
1348
- const s = new Reactive(value, 0);
1349
- s.alwaysUpdate = true;
1350
- return s;
1351
- }
1352
- var Writing = false;
1353
- var proxyTraps = {
1354
- get(target, property, receiver) {
1355
- if (property === $RAW)
1356
- return target;
1357
- if (property === $PROXY)
1358
- return receiver;
1359
- if (property === $TRACK) {
1360
- trackSelf(target);
1361
- return receiver;
452
+ const routeId = path || options.id;
453
+ let id = joinPaths([parentId, routeId]);
454
+ if (path === rootRouteId) {
455
+ path = '/';
1362
456
  }
1363
- const nodes = getDataNodes(target);
1364
- const tracked = nodes.hasOwnProperty(property);
1365
- let value = tracked ? nodes[property].get() : target[property];
1366
- if (property === $NODE || property === "__proto__")
1367
- return value;
1368
- if (!tracked) {
1369
- const desc = Object.getOwnPropertyDescriptor(target, property);
1370
- if (CurrentReaction && (typeof value !== "function" || target.hasOwnProperty(property)) && !(desc && desc.get))
1371
- value = getDataNode(nodes, property, value).get();
457
+ if (id !== rootRouteId) {
458
+ id = joinPaths(['/', id]);
1372
459
  }
1373
- return isWrappable(value) ? wrap(value) : value;
1374
- },
1375
- has(target, property) {
1376
- if (property === $RAW || property === $PROXY || property === $TRACK || property === $NODE || property === "__proto__")
1377
- return true;
1378
- this.get(target, property, target);
1379
- return property in target;
1380
- },
1381
- set(target, property, value) {
1382
- Writing && setProperty(target, property, unwrap(value));
1383
- return true;
1384
- },
1385
- deleteProperty(target, property) {
1386
- Writing && setProperty(target, property, void 0, true);
1387
- return true;
1388
- },
1389
- ownKeys,
1390
- getOwnPropertyDescriptor: proxyDescriptor
1391
- };
1392
- function setProperty(state, property, value, deleting = false) {
1393
- if (!deleting && state[property] === value)
1394
- return;
1395
- const prev = state[property];
1396
- const len = state.length;
1397
- if (deleting)
1398
- delete state[property];
1399
- else
1400
- state[property] = value;
1401
- const nodes = getDataNodes(state);
1402
- let node;
1403
- if (node = getDataNode(nodes, property, prev))
1404
- node.set(() => value);
1405
- if (Array.isArray(state) && state.length !== len)
1406
- (node = getDataNode(nodes, "length", len)) && node.set(state.length);
1407
- (node = nodes._) && node.set();
1408
- }
1409
- function createStore(store) {
1410
- const unwrappedStore = unwrap(store);
1411
- const wrappedStore = wrap(unwrappedStore);
1412
- const setStore = (fn) => {
1413
- batch(() => {
1414
- try {
1415
- Writing = true;
1416
- fn(wrappedStore);
1417
- } finally {
1418
- Writing = false;
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. `);
1419
472
  }
1420
- });
1421
- };
1422
- return [wrappedStore, setStore];
1423
- }
1424
-
1425
- function createRoute(routeConfig, options, originalIndex, parent, router) {
1426
- const {
1427
- id,
1428
- routeId,
1429
- path: routePath,
1430
- fullPath
1431
- } = routeConfig;
1432
- let route = {
1433
- routeInfo: undefined,
1434
- routeId: id,
1435
- routeRouteId: routeId,
1436
- originalIndex,
1437
- routePath,
1438
- fullPath,
1439
- options,
1440
- router,
1441
- childRoutes: undefined,
1442
- parentRoute: parent,
1443
- get action() {
1444
- let action = router.store.actions[id] || (() => {
1445
- router.setStore(s => {
1446
- s.actions[id] = {
1447
- submissions: [],
1448
- submit: async (submission, actionOpts) => {
1449
- if (!route) {
1450
- return;
1451
- }
1452
- const invalidate = (actionOpts == null ? void 0 : actionOpts.invalidate) ?? true;
1453
- const [actionStore, setActionStore] = createStore({
1454
- submittedAt: Date.now(),
1455
- status: 'pending',
1456
- submission,
1457
- isMulti: !!(actionOpts != null && actionOpts.multi)
1458
- });
1459
- router.setStore(s => {
1460
- if (!(actionOpts != null && actionOpts.multi)) {
1461
- s.actions[id].submissions = action.submissions.filter(d => d.isMulti);
1462
- }
1463
- s.actions[id].current = actionStore;
1464
- s.actions[id].latest = actionStore;
1465
- s.actions[id].submissions.push(actionStore);
1466
- });
1467
- try {
1468
- const res = await (route.options.action == null ? void 0 : route.options.action(submission));
1469
- setActionStore(s => {
1470
- s.data = res;
1471
- });
1472
- if (invalidate) {
1473
- router.invalidateRoute({
1474
- to: '.',
1475
- fromCurrent: true
1476
- });
1477
- await router.reload();
1478
- }
1479
- setActionStore(s => {
1480
- s.status = 'success';
1481
- });
1482
- return res;
1483
- } catch (err) {
1484
- console.error(err);
1485
- setActionStore(s => {
1486
- s.error = err;
1487
- s.status = 'error';
1488
- });
1489
- }
1490
- }
1491
- };
1492
- });
1493
- return router.store.actions[id];
1494
- })();
1495
- return action;
1496
- },
1497
- get loader() {
1498
- let loader = router.store.loaders[id] || (() => {
1499
- router.setStore(s => {
1500
- s.loaders[id] = {
1501
- pending: [],
1502
- fetch: async loaderContext => {
1503
- if (!route) {
1504
- return;
1505
- }
1506
- const loaderState = {
1507
- loadedAt: Date.now(),
1508
- loaderContext
1509
- };
1510
- router.setStore(s => {
1511
- s.loaders[id].current = loaderState;
1512
- s.loaders[id].latest = loaderState;
1513
- s.loaders[id].pending.push(loaderState);
1514
- });
1515
- try {
1516
- return await (route.options.loader == null ? void 0 : route.options.loader(loaderContext));
1517
- } finally {
1518
- router.setStore(s => {
1519
- s.loaders[id].pending = s.loaders[id].pending.filter(d => d !== loaderState);
1520
- });
1521
- }
1522
- }
1523
- };
1524
- });
1525
- return router.store.loaders[id];
1526
- })();
1527
- return loader;
1528
- }
1529
-
1530
- // buildLink: (options) => {
1531
- // return router.buildLink({
1532
- // ...options,
1533
- // from: fullPath,
1534
- // } as any) as any
1535
- // },
1536
-
1537
- // navigate: (options) => {
1538
- // return router.navigate({
1539
- // ...options,
1540
- // from: fullPath,
1541
- // } as any) as any
1542
- // },
1543
-
1544
- // matchRoute: (matchLocation, opts) => {
1545
- // return router.matchRoute(
1546
- // {
1547
- // ...matchLocation,
1548
- // from: fullPath,
1549
- // } as any,
1550
- // opts,
1551
- // ) as any
1552
- // },
473
+ };
1553
474
  };
1554
475
 
1555
- router.options.createRoute == null ? void 0 : router.options.createRoute({
1556
- router,
1557
- route
1558
- });
1559
- return route;
1560
- }
1561
-
1562
- const rootRouteId = '__root__';
1563
- const createRouteConfig = function (options, children, isRoot, parentId, parentPath) {
1564
- if (options === void 0) {
1565
- options = {};
1566
- }
1567
- if (isRoot === void 0) {
1568
- isRoot = true;
1569
- }
1570
- if (isRoot) {
1571
- options.path = rootRouteId;
1572
- }
1573
-
1574
- // Strip the root from parentIds
1575
- if (parentId === rootRouteId) {
1576
- parentId = '';
1577
- }
1578
- let path = isRoot ? rootRouteId : options.path;
1579
-
1580
- // If the path is anything other than an index path, trim it up
1581
- if (path && path !== '/') {
1582
- path = trimPath(path);
1583
- }
1584
- const routeId = path || options.id;
1585
- let id = joinPaths([parentId, routeId]);
1586
- if (path === rootRouteId) {
1587
- path = '/';
1588
- }
1589
- if (id !== rootRouteId) {
1590
- id = joinPaths(['/', id]);
1591
- }
1592
- const fullPath = id === rootRouteId ? '/' : trimPathRight(joinPaths([parentPath, path]));
1593
- return {
1594
- id: id,
1595
- routeId: routeId,
1596
- path: path,
1597
- fullPath: fullPath,
1598
- options: options,
1599
- children,
1600
- addChildren: children => createRouteConfig(options, children, false, parentId, parentPath),
1601
- createRoute: childOptions => createRouteConfig(childOptions, undefined, false, id, fullPath),
1602
- generate: () => {
1603
- invariant(false, `routeConfig.generate() is used by TanStack Router's file-based routing code generation and should not actually be called during runtime. `);
1604
- }
1605
- };
1606
- };
1607
-
1608
- /**
1609
- * This function returns `a` if `b` is deeply equal.
1610
- * If not, it will replace any deeply equal children of `b` with those of `a`.
1611
- * This can be used for structural sharing between JSON values for example.
1612
- */
1613
- function sharedClone(prev, next, touchAll) {
1614
- const things = new Map();
1615
- function recurse(prev, next) {
1616
- if (prev === next) {
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);
477
+
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();
502
+ }
503
+ };
504
+ return store;
505
+ }
506
+ function batch(cb) {
507
+ batching = true;
508
+ cb();
509
+ batching = false;
510
+ flush();
511
+ }
512
+
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
+ // }
596
+
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) {
1617
605
  return prev;
1618
606
  }
1619
- if (things.has(next)) {
1620
- return things.get(next);
1621
- }
1622
- const prevIsArray = Array.isArray(prev);
1623
- const nextIsArray = Array.isArray(next);
1624
- const prevIsObj = isPlainObject(prev);
1625
- const nextIsObj = isPlainObject(next);
1626
- const isArray = prevIsArray && nextIsArray;
1627
- const isObj = prevIsObj && nextIsObj;
1628
- const isSameStructure = isArray || isObj;
1629
-
1630
- // Both are arrays or objects
1631
- if (isSameStructure) {
1632
- const aSize = isArray ? prev.length : Object.keys(prev).length;
1633
- const bItems = isArray ? next : Object.keys(next);
1634
- const bSize = bItems.length;
1635
- const copy = isArray ? [] : {};
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 ? [] : {};
1636
614
  let equalItems = 0;
1637
- for (let i = 0; i < bSize; i++) {
1638
- const key = isArray ? i : bItems[i];
615
+ for (let i = 0; i < nextSize; i++) {
616
+ const key = array ? i : nextItems[i];
617
+ copy[key] = replaceEqualDeep(prev[key], next[key]);
1639
618
  if (copy[key] === prev[key]) {
1640
619
  equalItems++;
1641
620
  }
1642
621
  }
1643
- if (aSize === bSize && equalItems === aSize) {
1644
- things.set(next, prev);
1645
- return prev;
1646
- }
1647
- things.set(next, copy);
1648
- for (let i = 0; i < bSize; i++) {
1649
- const key = isArray ? i : bItems[i];
1650
- if (typeof bItems[i] === 'function') {
1651
- copy[key] = prev[key];
1652
- } else {
1653
- copy[key] = recurse(prev[key], next[key]);
1654
- }
1655
- if (copy[key] === prev[key]) {
1656
- equalItems++;
1657
- }
1658
- }
1659
- return copy;
1660
- }
1661
- if (nextIsArray) {
1662
- const copy = [];
1663
- things.set(next, copy);
1664
- for (let i = 0; i < next.length; i++) {
1665
- copy[i] = recurse(undefined, next[i]);
1666
- }
1667
- return copy;
1668
- }
1669
- if (nextIsObj) {
1670
- const copy = {};
1671
- things.set(next, copy);
1672
- const nextKeys = Object.keys(next);
1673
- for (let i = 0; i < nextKeys.length; i++) {
1674
- const key = nextKeys[i];
1675
- copy[key] = recurse(undefined, next[key]);
1676
- }
1677
- return copy;
622
+ return prevSize === nextSize && equalItems === prevSize ? prev : copy;
1678
623
  }
1679
624
  return next;
1680
625
  }
1681
- return recurse(prev, next);
1682
- }
1683
626
 
1684
- // Copied from: https://github.com/jonschlinkert/is-plain-object
1685
- function isPlainObject(o) {
1686
- if (!hasObjectPrototype(o)) {
1687
- return false;
1688
- }
627
+ // Copied from: https://github.com/jonschlinkert/is-plain-object
628
+ function isPlainObject(o) {
629
+ if (!hasObjectPrototype(o)) {
630
+ return false;
631
+ }
1689
632
 
1690
- // If has modified constructor
1691
- const ctor = o.constructor;
1692
- if (typeof ctor === 'undefined') {
1693
- return true;
1694
- }
633
+ // If has modified constructor
634
+ const ctor = o.constructor;
635
+ if (typeof ctor === 'undefined') {
636
+ return true;
637
+ }
1695
638
 
1696
- // If has modified prototype
1697
- const prot = ctor.prototype;
1698
- if (!hasObjectPrototype(prot)) {
1699
- return false;
1700
- }
639
+ // If has modified prototype
640
+ const prot = ctor.prototype;
641
+ if (!hasObjectPrototype(prot)) {
642
+ return false;
643
+ }
1701
644
 
1702
- // If constructor does not have an Object-specific method
1703
- if (!prot.hasOwnProperty('isPrototypeOf')) {
1704
- return false;
1705
- }
645
+ // If constructor does not have an Object-specific method
646
+ if (!prot.hasOwnProperty('isPrototypeOf')) {
647
+ return false;
648
+ }
1706
649
 
1707
- // Most likely a plain Object
1708
- return true;
1709
- }
1710
- function hasObjectPrototype(o) {
1711
- return Object.prototype.toString.call(o) === '[object Object]';
1712
- }
1713
-
1714
- const componentTypes = ['component', 'errorComponent', 'pendingComponent'];
1715
- function createRouteMatch(router, route, opts) {
1716
- let componentsPromise;
1717
- let dataPromise;
1718
- let latestId = '';
1719
- let resolve = () => {};
1720
- function setLoaderData(loaderData) {
1721
- batch(() => {
1722
- setStore(s => {
1723
- s.routeLoaderData = sharedClone(s.routeLoaderData, loaderData);
1724
- });
1725
- updateLoaderData();
1726
- });
650
+ // Most likely a plain Object
651
+ return true;
1727
652
  }
1728
- function updateLoaderData() {
1729
- setStore(s => {
1730
- var _store$parentMatch;
1731
- s.loaderData = sharedClone(s.loaderData, {
1732
- ...((_store$parentMatch = store.parentMatch) == null ? void 0 : _store$parentMatch.store.loaderData),
1733
- ...s.routeLoaderData
1734
- });
653
+ function hasObjectPrototype(o) {
654
+ return Object.prototype.toString.call(o) === '[object Object]';
655
+ }
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;
1735
667
  });
668
+ return obj;
1736
669
  }
1737
- const [store, setStore] = createStore({
1738
- routeSearch: {},
1739
- search: {},
1740
- status: 'idle',
1741
- routeLoaderData: {},
1742
- loaderData: {},
1743
- isFetching: false,
1744
- invalid: false,
1745
- invalidAt: Infinity,
1746
- get isInvalid() {
1747
- const now = Date.now();
1748
- return this.invalid || this.invalidAt < now;
1749
- }
1750
- });
1751
- const routeMatch = {
1752
- ...route,
1753
- ...opts,
1754
- store,
1755
- // setStore,
1756
- router,
1757
- childMatches: [],
1758
- __: {
1759
- setParentMatch: parentMatch => {
1760
- batch(() => {
1761
- setStore(s => {
1762
- s.parentMatch = parentMatch;
1763
- });
1764
- updateLoaderData();
1765
- });
1766
- },
1767
- abortController: new AbortController(),
1768
- validate: () => {
1769
- var _store$parentMatch2;
1770
- // Validate the search params and stabilize them
1771
- const parentSearch = ((_store$parentMatch2 = store.parentMatch) == null ? void 0 : _store$parentMatch2.store.search) ?? router.store.currentLocation.search;
1772
- try {
1773
- const prevSearch = store.routeSearch;
1774
- const validator = typeof routeMatch.options.validateSearch === 'object' ? routeMatch.options.validateSearch.parse : routeMatch.options.validateSearch;
1775
- let nextSearch = sharedClone(prevSearch, (validator == null ? void 0 : validator(parentSearch)) ?? {});
1776
- batch(() => {
1777
- // Invalidate route matches when search param stability changes
1778
- if (prevSearch !== nextSearch) {
1779
- setStore(s => s.invalid = true);
1780
- }
1781
670
 
1782
- // TODO: Alright, do we need batch() here?
1783
- setStore(s => {
1784
- s.routeSearch = nextSearch;
1785
- s.search = sharedClone(parentSearch, {
1786
- ...parentSearch,
1787
- ...nextSearch
1788
- });
1789
- });
1790
- });
1791
- componentTypes.map(async type => {
1792
- const component = routeMatch.options[type];
1793
- if (typeof routeMatch.__[type] !== 'function') {
1794
- routeMatch.__[type] = component;
1795
- }
1796
- });
1797
- } catch (err) {
1798
- console.error(err);
1799
- const error = new Error('Invalid search params found', {
1800
- cause: err
1801
- });
1802
- error.code = 'INVALID_SEARCH_PARAMS';
1803
- setStore(s => {
1804
- s.status = 'error';
1805
- s.error = error;
1806
- });
1807
-
1808
- // Do not proceed with loading the route
1809
- return;
1810
- }
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');
1811
697
  }
1812
- },
1813
- cancel: () => {
1814
- var _routeMatch$__$abortC;
1815
- (_routeMatch$__$abortC = routeMatch.__.abortController) == null ? void 0 : _routeMatch$__$abortC.abort();
1816
- },
1817
- invalidate: () => {
1818
- setStore(s => s.invalid = true);
1819
- },
1820
- hasLoaders: () => {
1821
- return !!(route.options.loader || componentTypes.some(d => {
1822
- var _route$options$d;
1823
- return (_route$options$d = route.options[d]) == null ? void 0 : _route$options$d.preload;
1824
- }));
1825
- },
1826
- 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 => {
1827
711
  const now = Date.now();
1828
- const minMaxAge = loaderOpts != null && loaderOpts.preload ? Math.max(loaderOpts == null ? void 0 : loaderOpts.maxAge, loaderOpts == null ? void 0 : loaderOpts.gcMaxAge) : 0;
712
+ const minMaxAge = loaderOpts?.preload ? Math.max(loaderOpts?.maxAge, loaderOpts?.gcMaxAge) : 0;
1829
713
 
1830
714
  // If this is a preload, add it to the preload cache
1831
- if (loaderOpts != null && loaderOpts.preload && minMaxAge > 0) {
715
+ if (loaderOpts?.preload && minMaxAge > 0) {
1832
716
  // If the match is currently active, don't preload it
1833
- if (router.store.currentMatches.find(d => d.matchId === routeMatch.matchId)) {
717
+ if (this.router.store.state.currentMatches.find(d => d.id === this.id)) {
1834
718
  return;
1835
719
  }
1836
- router.store.matchCache[routeMatch.matchId] = {
1837
- gc: now + loaderOpts.gcMaxAge,
1838
- match: routeMatch
1839
- };
720
+ this.router.store.setState(s => {
721
+ s.matchCache[this.id] = {
722
+ gc: now + loaderOpts.gcMaxAge,
723
+ match: this
724
+ };
725
+ });
1840
726
  }
1841
727
 
1842
728
  // If the match is invalid, errored or idle, trigger it to load
1843
- if (store.status === 'success' && store.isInvalid || store.status === 'error' || store.status === 'idle') {
1844
- const maxAge = loaderOpts != null && loaderOpts.preload ? loaderOpts == null ? void 0 : loaderOpts.maxAge : undefined;
1845
- await routeMatch.fetch({
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({
1846
732
  maxAge
1847
733
  });
1848
734
  }
1849
- },
1850
- fetch: async opts => {
1851
- const loadId = '' + Date.now() + Math.random();
1852
- latestId = loadId;
1853
- const checkLatest = async () => {
1854
- if (loadId !== latestId) {
1855
- // warning(true, 'Data loader is out of date!')
1856
- return new Promise(() => {});
1857
- }
1858
- };
1859
- batch(() => {
1860
- // If the match was in an error state, set it
1861
- // to a loading state again. Otherwise, keep it
1862
- // as loading or resolved
1863
- if (store.status === 'idle') {
1864
- setStore(s => s.status = 'loading');
1865
- }
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
+ }
749
+
750
+ // We started loading the route, so it's no longer invalid
751
+ this.store.setState(s => s.invalid = false);
752
+ });
1866
753
 
1867
- // We started loading the route, so it's no longer invalid
1868
- setStore(s => s.invalid = false);
1869
- });
1870
- routeMatch.__.loadPromise = new Promise(async r => {
1871
754
  // We are now fetching, even if it's in the background of a
1872
755
  // resolved state
1873
- setStore(s => s.isFetching = true);
1874
- resolve = r;
1875
- componentsPromise = (async () => {
756
+ this.store.setState(s => s.isFetching = true);
757
+ this.#resolve = resolve;
758
+ const componentsPromise = (async () => {
1876
759
  // then run all component and data loaders in parallel
1877
760
  // For each component type, potentially load it asynchronously
1878
761
 
1879
762
  await Promise.all(componentTypes.map(async type => {
1880
- var _routeMatch$__$type;
1881
- const component = routeMatch.options[type];
1882
- if ((_routeMatch$__$type = routeMatch.__[type]) != null && _routeMatch$__$type.preload) {
1883
- routeMatch.__[type] = await router.options.loadComponent(component);
763
+ const component = this.route.options[type];
764
+ if (this[type]?.preload) {
765
+ this[type] = await this.router.options.loadComponent(component);
1884
766
  }
1885
767
  }));
1886
768
  })();
1887
- dataPromise = Promise.resolve().then(async () => {
769
+ const dataPromise = Promise.resolve().then(async () => {
1888
770
  try {
1889
- if (routeMatch.options.loader) {
1890
- const data = await router.loadMatchData(routeMatch);
1891
- await checkLatest();
1892
- setLoaderData(data);
771
+ if (this.route.options.loader) {
772
+ const data = await this.router.loadMatchData(this);
773
+ if (latestPromise = checkLatest()) return latestPromise;
774
+ this.#setLoaderData(data);
1893
775
  }
1894
- setStore(s => {
776
+ this.store.setState(s => {
1895
777
  s.error = undefined;
1896
778
  s.status = 'success';
1897
779
  s.updatedAt = Date.now();
1898
- s.invalidAt = s.updatedAt + ((opts == null ? void 0 : opts.maxAge) ?? routeMatch.options.loaderMaxAge ?? router.options.defaultLoaderMaxAge ?? 0);
780
+ s.invalidAt = s.updatedAt + (opts?.maxAge ?? this.route.options.loaderMaxAge ?? this.router.options.defaultLoaderMaxAge ?? 0);
1899
781
  });
1900
- return store.routeLoaderData;
782
+ return this.store.state.routeLoaderData;
1901
783
  } catch (err) {
1902
- await checkLatest();
784
+ if (latestPromise = checkLatest()) return latestPromise;
1903
785
  {
1904
786
  console.error(err);
1905
787
  }
1906
- setStore(s => {
788
+ this.store.setState(s => {
1907
789
  s.error = err;
1908
790
  s.status = 'error';
1909
791
  s.updatedAt = Date.now();
@@ -1912,10 +794,10 @@
1912
794
  }
1913
795
  });
1914
796
  const after = async () => {
1915
- await checkLatest();
1916
- setStore(s => s.isFetching = false);
1917
- delete routeMatch.__.loadPromise;
1918
- resolve();
797
+ if (latestPromise = checkLatest()) return latestPromise;
798
+ this.store.setState(s => s.isFetching = false);
799
+ this.#resolve();
800
+ delete this.__loadPromise;
1919
801
  };
1920
802
  try {
1921
803
  await Promise.all([componentsPromise, dataPromise.catch(() => {})]);
@@ -1924,439 +806,359 @@
1924
806
  after();
1925
807
  }
1926
808
  });
1927
- await routeMatch.__.loadPromise;
1928
- await checkLatest();
1929
- }
1930
- };
1931
- if (!routeMatch.hasLoaders()) {
1932
- setStore(s => s.status = 'success');
1933
- }
1934
- return routeMatch;
1935
- }
1936
-
1937
- const defaultParseSearch = parseSearchWith(JSON.parse);
1938
- const defaultStringifySearch = stringifySearchWith(JSON.stringify);
1939
- function parseSearchWith(parser) {
1940
- return searchStr => {
1941
- if (searchStr.substring(0, 1) === '?') {
1942
- searchStr = searchStr.substring(1);
1943
- }
1944
- let query = decode(searchStr);
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
+ };
1945
845
 
1946
- // Try to parse any query params that might be json
1947
- for (let key in query) {
1948
- const value = query[key];
1949
- if (typeof value === 'string') {
1950
- try {
1951
- query[key] = parser(value);
1952
- } catch (err) {
1953
- //
1954
- }
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
+ });
882
+
883
+ // Do not proceed with loading the route
884
+ return;
1955
885
  }
1956
- }
1957
- return query;
1958
- };
1959
- }
1960
- function stringifySearchWith(stringify) {
1961
- return search => {
1962
- search = {
1963
- ...search
1964
886
  };
1965
- if (search) {
1966
- Object.keys(search).forEach(key => {
1967
- const val = search[key];
1968
- if (typeof val === 'undefined' || val === undefined) {
1969
- delete search[key];
1970
- } else if (val && typeof val === 'object' && val !== null) {
887
+ }
888
+
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);
895
+ }
896
+ let query = decode(searchStr);
897
+
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') {
1971
902
  try {
1972
- search[key] = stringify(val);
903
+ query[key] = parser(value);
1973
904
  } catch (err) {
1974
- // silent
1975
- }
1976
- }
1977
- });
1978
- }
1979
- const searchStr = encode(search).toString();
1980
- return searchStr ? `?${searchStr}` : '';
1981
- };
1982
- }
1983
-
1984
- var _window$document;
1985
- // Detect if we're in the DOM
1986
- const isServer = typeof window === 'undefined' || !((_window$document = window.document) != null && _window$document.createElement);
1987
-
1988
- // This is the default history object if none is defined
1989
- const createDefaultHistory = () => isServer ? createMemoryHistory() : createBrowserHistory();
1990
- function getInitialRouterState() {
1991
- return {
1992
- status: 'idle',
1993
- latestLocation: null,
1994
- currentLocation: null,
1995
- currentMatches: [],
1996
- actions: {},
1997
- loaders: {},
1998
- lastUpdated: Date.now(),
1999
- matchCache: {},
2000
- get isFetching() {
2001
- return this.status === 'loading' || this.currentMatches.some(d => d.store.isFetching);
2002
- },
2003
- get isPreloading() {
2004
- return Object.values(this.matchCache).some(d => d.match.store.isFetching && !this.currentMatches.find(dd => dd.matchId === d.match.matchId));
2005
- }
2006
- };
2007
- }
2008
- function createRouter(userOptions) {
2009
- const originalOptions = {
2010
- defaultLoaderGcMaxAge: 5 * 60 * 1000,
2011
- defaultLoaderMaxAge: 0,
2012
- defaultPreloadMaxAge: 2000,
2013
- defaultPreloadDelay: 50,
2014
- context: undefined,
2015
- ...userOptions,
2016
- stringifySearch: (userOptions == null ? void 0 : userOptions.stringifySearch) ?? defaultStringifySearch,
2017
- parseSearch: (userOptions == null ? void 0 : userOptions.parseSearch) ?? defaultParseSearch
2018
- };
2019
- const [store, setStore] = createStore(getInitialRouterState());
2020
- let navigationPromise;
2021
- let startedLoadingAt = Date.now();
2022
- let resolveNavigation = () => {};
2023
- function onFocus() {
2024
- router.load();
2025
- }
2026
- function buildRouteTree(rootRouteConfig) {
2027
- const recurseRoutes = (routeConfigs, parent) => {
2028
- return routeConfigs.map((routeConfig, i) => {
2029
- const routeOptions = routeConfig.options;
2030
- const route = createRoute(routeConfig, routeOptions, i, parent, router);
2031
- const existingRoute = router.routesById[route.routeId];
2032
- if (existingRoute) {
2033
- {
2034
- console.warn(`Duplicate routes found with id: ${String(route.routeId)}`, router.routesById, route);
905
+ //
2035
906
  }
2036
- throw new Error();
2037
907
  }
2038
- router.routesById[route.routeId] = route;
2039
- const children = routeConfig.children;
2040
- route.childRoutes = children != null && children.length ? recurseRoutes(children, route) : undefined;
2041
- return route;
2042
- });
2043
- };
2044
- const routes = recurseRoutes([rootRouteConfig]);
2045
- return routes[0];
2046
- }
2047
- function parseLocation(location, previousLocation) {
2048
- const parsedSearch = router.options.parseSearch(location.search);
2049
- return {
2050
- pathname: location.pathname,
2051
- searchStr: location.search,
2052
- search: sharedClone(previousLocation == null ? void 0 : previousLocation.search, parsedSearch),
2053
- hash: location.hash.split('#').reverse()[0] ?? '',
2054
- href: `${location.pathname}${location.search}${location.hash}`,
2055
- state: location.state,
2056
- key: location.key
908
+ }
909
+ return query;
2057
910
  };
2058
911
  }
2059
- function navigate(location) {
2060
- const next = router.buildNext(location);
2061
- return commitLocation(next, location.replace);
2062
- }
2063
- function buildLocation(dest) {
2064
- var _last, _dest$__preSearchFilt, _dest$__preSearchFilt2, _dest$__postSearchFil;
2065
- if (dest === void 0) {
2066
- dest = {};
2067
- }
2068
- const fromPathname = dest.fromCurrent ? store.latestLocation.pathname : dest.from ?? store.latestLocation.pathname;
2069
- let pathname = resolvePath(router.basepath ?? '/', fromPathname, `${dest.to ?? '.'}`);
2070
- const fromMatches = router.matchRoutes(store.latestLocation.pathname, {
2071
- strictParseParams: true
2072
- });
2073
- const toMatches = router.matchRoutes(pathname);
2074
- const prevParams = {
2075
- ...((_last = last(fromMatches)) == null ? void 0 : _last.params)
2076
- };
2077
- let nextParams = (dest.params ?? true) === true ? prevParams : functionalUpdate(dest.params, prevParams);
2078
- if (nextParams) {
2079
- toMatches.map(d => d.options.stringifyParams).filter(Boolean).forEach(fn => {
2080
- Object.assign({}, nextParams, fn(nextParams));
2081
- });
2082
- }
2083
- pathname = interpolatePath(pathname, nextParams ?? {});
2084
-
2085
- // Pre filters first
2086
- const preFilteredSearch = (_dest$__preSearchFilt = dest.__preSearchFilters) != null && _dest$__preSearchFilt.length ? dest.__preSearchFilters.reduce((prev, next) => next(prev), store.latestLocation.search) : store.latestLocation.search;
2087
-
2088
- // Then the link/navigate function
2089
- const destSearch = dest.search === true ? preFilteredSearch // Preserve resolvedFrom true
2090
- : dest.search ? functionalUpdate(dest.search, preFilteredSearch) ?? {} // Updater
2091
- : (_dest$__preSearchFilt2 = dest.__preSearchFilters) != null && _dest$__preSearchFilt2.length ? preFilteredSearch // Preserve resolvedFrom filters
2092
- : {};
2093
-
2094
- // Then post filters
2095
- const postFilteredSearch = (_dest$__postSearchFil = dest.__postSearchFilters) != null && _dest$__postSearchFil.length ? dest.__postSearchFilters.reduce((prev, next) => next(prev), destSearch) : destSearch;
2096
- const search = sharedClone(store.latestLocation.search, postFilteredSearch);
2097
- const searchStr = router.options.stringifySearch(search);
2098
- let hash = dest.hash === true ? store.latestLocation.hash : functionalUpdate(dest.hash, store.latestLocation.hash);
2099
- hash = hash ? `#${hash}` : '';
2100
- return {
2101
- pathname,
2102
- search,
2103
- searchStr,
2104
- state: store.latestLocation.state,
2105
- hash,
2106
- href: `${pathname}${searchStr}${hash}`,
2107
- key: dest.key
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
+ });
930
+ }
931
+ const searchStr = encode(search).toString();
932
+ return searchStr ? `?${searchStr}` : '';
2108
933
  };
2109
934
  }
2110
- function commitLocation(next, replace) {
2111
- const id = '' + Date.now() + Math.random();
2112
- let nextAction = 'replace';
2113
- if (!replace) {
2114
- nextAction = 'push';
2115
- }
2116
- const isSameUrl = parseLocation(router.history.location).href === next.href;
2117
- if (isSameUrl && !next.key) {
2118
- nextAction = 'replace';
2119
- }
2120
- router.history[nextAction]({
2121
- pathname: next.pathname,
2122
- hash: next.hash,
2123
- search: next.searchStr
2124
- }, {
2125
- id,
2126
- ...next.state
935
+
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
+ })
2127
948
  });
2128
- return navigationPromise = new Promise(resolve => {
2129
- const previousNavigationResolve = resolveNavigation;
2130
- resolveNavigation = () => {
2131
- previousNavigationResolve();
2132
- resolve();
2133
- };
949
+ const res = await fetch(next.href, {
950
+ method: 'GET',
951
+ signal: routeMatch.abortController.signal
2134
952
  });
2135
- }
2136
- const router = {
2137
- types: undefined,
2138
- // public api
2139
- history: (userOptions == null ? void 0 : userOptions.history) || createDefaultHistory(),
2140
- store,
2141
- setStore,
2142
- options: originalOptions,
2143
- basepath: '',
2144
- routeTree: undefined,
2145
- routesById: {},
2146
- reset: () => {
2147
- setStore(s => Object.assign(s, getInitialRouterState()));
2148
- },
2149
- getRoute: id => {
2150
- return router.routesById[id];
2151
- },
2152
- dehydrate: () => {
2153
- return {
2154
- store: {
2155
- ...pick(store, ['latestLocation', 'currentLocation', 'status', 'lastUpdated']),
2156
- currentMatches: store.currentMatches.map(match => ({
2157
- matchId: match.matchId,
2158
- store: pick(match.store, ['status', 'routeLoaderData', 'isInvalid', 'invalidAt'])
2159
- }))
2160
- },
2161
- context: router.options.context
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
2162
974
  };
2163
- },
2164
- hydrate: dehydratedRouter => {
2165
- setStore(s => {
2166
- // Update the context TODO: make this part of state?
2167
- router.options.context = dehydratedRouter.context;
975
+ this.history = this.options?.history ?? isServer ? createMemoryHistory() : createBrowserHistory();
976
+ this.store = createStore(getInitialRouterState());
977
+ this.basepath = '';
978
+ this.update(options);
2168
979
 
2169
- // Match the routes
2170
- const currentMatches = router.matchRoutes(dehydratedRouter.store.latestLocation.pathname, {
2171
- strictParseParams: true
2172
- });
2173
- currentMatches.forEach((match, index) => {
2174
- const dehydratedMatch = dehydratedRouter.store.currentMatches[index];
2175
- invariant(dehydratedMatch && dehydratedMatch.matchId === match.matchId, 'Oh no! There was a hydration mismatch when attempting to restore the state of the router! 😬');
2176
- Object.assign(match, dehydratedMatch);
2177
- });
2178
- currentMatches.forEach(match => match.__.validate());
2179
- Object.assign(s, {
2180
- ...dehydratedRouter.store,
2181
- currentMatches
2182
- });
2183
- });
2184
- },
2185
- mount: () => {
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 = () => {
2186
987
  // Mount only does anything on the client
2187
988
  if (!isServer) {
2188
989
  // If the router matches are empty, load the matches
2189
- if (!store.currentMatches.length) {
2190
- router.load();
990
+ if (!this.store.state.currentMatches.length) {
991
+ this.load();
2191
992
  }
2192
- const unsub = router.history.listen(event => {
2193
- router.load(parseLocation(event.location, store.latestLocation));
993
+ const unsubHistory = this.history.listen(() => {
994
+ this.load(this.#parseLocation(this.store.state.latestLocation));
2194
995
  });
996
+ const visibilityChangeEvent = 'visibilitychange';
997
+ const focusEvent = 'focus';
2195
998
 
2196
999
  // addEventListener does not exist in React Native, but window does
2197
1000
  // In the future, we might need to invert control here for more adapters
2198
1001
  // eslint-disable-next-line @typescript-eslint/no-unnecessary-condition
2199
1002
  if (window.addEventListener) {
2200
1003
  // Listen to visibilitychange and focus
2201
- window.addEventListener('visibilitychange', onFocus, false);
2202
- window.addEventListener('focus', onFocus, false);
1004
+ window.addEventListener(visibilityChangeEvent, this.#onFocus, false);
1005
+ window.addEventListener(focusEvent, this.#onFocus, false);
2203
1006
  }
2204
1007
  return () => {
2205
- unsub();
1008
+ unsubHistory();
2206
1009
  if (window.removeEventListener) {
2207
1010
  // Be sure to unsubscribe if a new handler is set
2208
- window.removeEventListener('visibilitychange', onFocus);
2209
- window.removeEventListener('focus', onFocus);
1011
+
1012
+ window.removeEventListener(visibilityChangeEvent, this.#onFocus);
1013
+ window.removeEventListener(focusEvent, this.#onFocus);
2210
1014
  }
2211
1015
  };
2212
1016
  }
2213
1017
  return () => {};
2214
- },
2215
- update: opts => {
2216
- const newHistory = (opts == null ? void 0 : opts.history) !== router.history;
2217
- if (!store.latestLocation || newHistory) {
2218
- if (opts != null && opts.history) {
2219
- router.history = opts.history;
2220
- }
2221
- setStore(s => {
2222
- s.latestLocation = parseLocation(router.history.location);
1018
+ };
1019
+ update = opts => {
1020
+ if (!this.store.state.latestLocation) {
1021
+ this.store.setState(s => {
1022
+ s.latestLocation = this.#parseLocation();
2223
1023
  s.currentLocation = s.latestLocation;
2224
1024
  });
2225
1025
  }
2226
- Object.assign(router.options, opts);
1026
+ Object.assign(this.options, opts);
2227
1027
  const {
2228
1028
  basepath,
2229
1029
  routeConfig
2230
- } = router.options;
2231
- router.basepath = `/${trimPath(basepath ?? '') ?? ''}`;
1030
+ } = this.options;
1031
+ this.basepath = `/${trimPath(basepath ?? '') ?? ''}`;
2232
1032
  if (routeConfig) {
2233
- router.routesById = {};
2234
- router.routeTree = buildRouteTree(routeConfig);
1033
+ this.routesById = {};
1034
+ this.routeTree = this.#buildRouteTree(routeConfig);
2235
1035
  }
2236
- return router;
2237
- },
2238
- cancelMatches: () => {
2239
- [...store.currentMatches, ...(store.pendingMatches || [])].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 => {
2240
1051
  match.cancel();
2241
1052
  });
2242
- },
2243
- load: async next => {
1053
+ };
1054
+ load = async next => {
2244
1055
  let now = Date.now();
2245
1056
  const startedAt = now;
2246
- startedLoadingAt = startedAt;
1057
+ this.startedLoadingAt = startedAt;
2247
1058
 
2248
1059
  // Cancel any pending matches
2249
- router.cancelMatches();
1060
+ this.cancelMatches();
2250
1061
  let matches;
2251
1062
  batch(() => {
2252
1063
  if (next) {
2253
1064
  // Ingest the new location
2254
- setStore(s => {
1065
+ this.store.setState(s => {
2255
1066
  s.latestLocation = next;
2256
1067
  });
2257
1068
  }
2258
1069
 
2259
1070
  // Match the routes
2260
- matches = router.matchRoutes(store.latestLocation.pathname, {
1071
+ matches = this.matchRoutes(this.store.state.latestLocation.pathname, {
2261
1072
  strictParseParams: true
2262
1073
  });
2263
- console.log('set loading', matches);
2264
- setStore(s => {
1074
+ this.store.setState(s => {
2265
1075
  s.status = 'loading';
2266
1076
  s.pendingMatches = matches;
2267
- s.pendingLocation = store.latestLocation;
1077
+ s.pendingLocation = this.store.state.latestLocation;
2268
1078
  });
2269
1079
  });
2270
1080
 
2271
1081
  // Load the matches
2272
1082
  try {
2273
- await router.loadMatches(matches);
1083
+ await this.loadMatches(matches);
2274
1084
  } catch (err) {
2275
- console.log(err);
1085
+ console.warn(err);
2276
1086
  invariant(false, 'Matches failed to load due to error above ☝️. Navigation cancelled!');
2277
1087
  }
2278
- if (startedLoadingAt !== startedAt) {
1088
+ if (this.startedLoadingAt !== startedAt) {
2279
1089
  // Ignore side-effects of outdated side-effects
2280
- return navigationPromise;
1090
+ return this.navigationPromise;
2281
1091
  }
2282
- const previousMatches = store.currentMatches;
1092
+ const previousMatches = this.store.state.currentMatches;
2283
1093
  const exiting = [],
2284
1094
  staying = [];
2285
1095
  previousMatches.forEach(d => {
2286
- if (matches.find(dd => dd.matchId === d.matchId)) {
1096
+ if (matches.find(dd => dd.id === d.id)) {
2287
1097
  staying.push(d);
2288
1098
  } else {
2289
1099
  exiting.push(d);
2290
1100
  }
2291
1101
  });
2292
1102
  const entering = matches.filter(d => {
2293
- return !previousMatches.find(dd => dd.matchId === d.matchId);
1103
+ return !previousMatches.find(dd => dd.id === d.id);
2294
1104
  });
2295
1105
  now = Date.now();
2296
1106
  exiting.forEach(d => {
2297
- d.__.onExit == null ? void 0 : d.__.onExit({
1107
+ d.__onExit?.({
2298
1108
  params: d.params,
2299
- search: d.store.routeSearch
1109
+ search: d.store.state.routeSearch
2300
1110
  });
2301
1111
 
2302
- // Clear idle error states when match leaves
2303
- if (d.store.status === 'error' && !d.store.isFetching) {
2304
- d.store.status = 'idle';
2305
- d.store.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
+ });
2306
1118
  }
2307
- const gc = Math.max(d.options.loaderGcMaxAge ?? router.options.defaultLoaderGcMaxAge ?? 0, d.options.loaderMaxAge ?? router.options.defaultLoaderMaxAge ?? 0);
1119
+ const gc = Math.max(d.route.options.loaderGcMaxAge ?? this.options.defaultLoaderGcMaxAge ?? 0, d.route.options.loaderMaxAge ?? this.options.defaultLoaderMaxAge ?? 0);
2308
1120
  if (gc > 0) {
2309
- store.matchCache[d.matchId] = {
2310
- gc: gc == Infinity ? Number.MAX_SAFE_INTEGER : now + gc,
2311
- match: d
2312
- };
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
+ });
2313
1127
  }
2314
1128
  });
2315
1129
  staying.forEach(d => {
2316
- d.options.onTransition == null ? void 0 : d.options.onTransition({
1130
+ d.route.options.onTransition?.({
2317
1131
  params: d.params,
2318
- search: d.store.routeSearch
1132
+ search: d.store.state.routeSearch
2319
1133
  });
2320
1134
  });
2321
1135
  entering.forEach(d => {
2322
- d.__.onExit = d.options.onLoaded == null ? void 0 : d.options.onLoaded({
1136
+ d.__onExit = d.route.options.onLoaded?.({
2323
1137
  params: d.params,
2324
- search: d.store.search
1138
+ search: d.store.state.search
2325
1139
  });
2326
- delete store.matchCache[d.matchId];
2327
- });
2328
- if (startedLoadingAt !== startedAt) {
2329
- // Ignore side-effects of match loading
2330
- return;
2331
- }
2332
- matches.forEach(match => {
2333
- // Clear actions
2334
- if (match.action) {
2335
- // TODO: Check reactivity here
2336
- match.action.current = undefined;
2337
- match.action.submissions = [];
2338
- }
1140
+ delete this.store.state.matchCache[d.id];
2339
1141
  });
2340
- setStore(s => {
2341
- console.log('set', matches);
1142
+ this.store.setState(s => {
2342
1143
  Object.assign(s, {
2343
1144
  status: 'idle',
2344
- currentLocation: store.latestLocation,
1145
+ currentLocation: this.store.state.latestLocation,
2345
1146
  currentMatches: matches,
2346
1147
  pendingLocation: undefined,
2347
1148
  pendingMatches: undefined
2348
1149
  });
2349
1150
  });
2350
- resolveNavigation();
2351
- },
2352
- cleanMatchCache: () => {
1151
+ this.options.onRouteChange?.();
1152
+ this.resolveNavigation();
1153
+ };
1154
+ cleanMatchCache = () => {
2353
1155
  const now = Date.now();
2354
- setStore(s => {
1156
+ this.store.setState(s => {
2355
1157
  Object.keys(s.matchCache).forEach(matchId => {
2356
1158
  const entry = s.matchCache[matchId];
2357
1159
 
2358
1160
  // Don't remove loading matches
2359
- if (entry.match.store.status === 'loading') {
1161
+ if (entry.match.store.state.status === 'loading') {
2360
1162
  return;
2361
1163
  }
2362
1164
 
@@ -2369,64 +1171,60 @@
2369
1171
  delete s.matchCache[matchId];
2370
1172
  });
2371
1173
  });
2372
- },
2373
- loadRoute: async function (navigateOpts) {
2374
- if (navigateOpts === void 0) {
2375
- navigateOpts = store.latestLocation;
2376
- }
2377
- const next = router.buildNext(navigateOpts);
2378
- 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, {
2379
1183
  strictParseParams: true
2380
1184
  });
2381
- await router.loadMatches(matches);
1185
+ await this.loadMatches(matches);
2382
1186
  return matches;
2383
- },
2384
- preloadRoute: async function (navigateOpts, loaderOpts) {
2385
- if (navigateOpts === void 0) {
2386
- navigateOpts = store.latestLocation;
2387
- }
2388
- const next = router.buildNext(navigateOpts);
2389
- 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, {
2390
1191
  strictParseParams: true
2391
1192
  });
2392
- await router.loadMatches(matches, {
1193
+ await this.loadMatches(matches, {
2393
1194
  preload: true,
2394
- maxAge: loaderOpts.maxAge ?? router.options.defaultPreloadMaxAge ?? router.options.defaultLoaderMaxAge ?? 0,
2395
- gcMaxAge: loaderOpts.gcMaxAge ?? router.options.defaultPreloadGcMaxAge ?? router.options.defaultLoaderGcMaxAge ?? 0
1195
+ maxAge: loaderOpts.maxAge ?? this.options.defaultPreloadMaxAge ?? this.options.defaultLoaderMaxAge ?? 0,
1196
+ gcMaxAge: loaderOpts.gcMaxAge ?? this.options.defaultPreloadGcMaxAge ?? this.options.defaultLoaderGcMaxAge ?? 0
2396
1197
  });
2397
1198
  return matches;
2398
- },
2399
- matchRoutes: (pathname, opts) => {
2400
- router.cleanMatchCache();
1199
+ };
1200
+ matchRoutes = (pathname, opts) => {
2401
1201
  const matches = [];
2402
- if (!router.routeTree) {
1202
+ if (!this.routeTree) {
2403
1203
  return matches;
2404
1204
  }
2405
- const existingMatches = [...store.currentMatches, ...(store.pendingMatches ?? [])];
1205
+ const existingMatches = [...this.store.state.currentMatches, ...(this.store.state.pendingMatches ?? [])];
2406
1206
  const recurse = async routes => {
2407
- var _foundRoute$childRout;
2408
1207
  const parentMatch = last(matches);
2409
- let params = (parentMatch == null ? void 0 : parentMatch.params) ?? {};
2410
- const filteredRoutes = (router.options.filterRoutes == null ? void 0 : router.options.filterRoutes(routes)) ?? routes;
1208
+ let params = parentMatch?.params ?? {};
1209
+ const filteredRoutes = this.options.filterRoutes?.(routes) ?? routes;
2411
1210
  let foundRoutes = [];
2412
1211
  const findMatchInRoutes = (parentRoutes, routes) => {
2413
1212
  routes.some(route => {
2414
- var _route$childRoutes, _route$childRoutes2;
2415
- if (!route.routePath && (_route$childRoutes = route.childRoutes) != null && _route$childRoutes.length) {
1213
+ if (!route.path && route.childRoutes?.length) {
2416
1214
  return findMatchInRoutes([...foundRoutes, route], route.childRoutes);
2417
1215
  }
2418
- const fuzzy = !!(route.routePath !== '/' || (_route$childRoutes2 = route.childRoutes) != null && _route$childRoutes2.length);
2419
- const matchParams = matchPathname(router.basepath, pathname, {
1216
+ const fuzzy = !!(route.path !== '/' || route.childRoutes?.length);
1217
+ const matchParams = matchPathname(this.basepath, pathname, {
2420
1218
  to: route.fullPath,
2421
1219
  fuzzy,
2422
- caseSensitive: route.options.caseSensitive ?? router.options.caseSensitive
1220
+ caseSensitive: route.options.caseSensitive ?? this.options.caseSensitive
2423
1221
  });
2424
1222
  if (matchParams) {
2425
1223
  let parsedParams;
2426
1224
  try {
2427
- parsedParams = (route.options.parseParams == null ? void 0 : route.options.parseParams(matchParams)) ?? matchParams;
1225
+ parsedParams = route.options.parseParams?.(matchParams) ?? matchParams;
2428
1226
  } catch (err) {
2429
- if (opts != null && opts.strictParseParams) {
1227
+ if (opts?.strictParseParams) {
2430
1228
  throw err;
2431
1229
  }
2432
1230
  }
@@ -2447,79 +1245,71 @@
2447
1245
  return;
2448
1246
  }
2449
1247
  foundRoutes.forEach(foundRoute => {
2450
- var _store$matchCache$mat;
2451
- const interpolatedPath = interpolatePath(foundRoute.routePath, params);
2452
- const matchId = interpolatePath(foundRoute.routeId, params, true);
2453
- const match = existingMatches.find(d => d.matchId === matchId) || ((_store$matchCache$mat = store.matchCache[matchId]) == null ? void 0 : _store$matchCache$mat.match) || createRouteMatch(router, foundRoute, {
2454
- parentMatch,
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, {
2455
1251
  matchId,
2456
1252
  params,
2457
- pathname: joinPaths([router.basepath, interpolatedPath])
1253
+ pathname: joinPaths([this.basepath, interpolatedPath])
2458
1254
  });
2459
1255
  matches.push(match);
2460
1256
  });
2461
1257
  const foundRoute = last(foundRoutes);
2462
- if ((_foundRoute$childRout = foundRoute.childRoutes) != null && _foundRoute$childRout.length) {
1258
+ if (foundRoute.childRoutes?.length) {
2463
1259
  recurse(foundRoute.childRoutes);
2464
1260
  }
2465
1261
  };
2466
- recurse([router.routeTree]);
1262
+ recurse([this.routeTree]);
2467
1263
  linkMatches(matches);
2468
1264
  return matches;
2469
- },
2470
- loadMatches: async (resolvedMatches, loaderOpts) => {
1265
+ };
1266
+ loadMatches = async (resolvedMatches, loaderOpts) => {
1267
+ this.cleanMatchCache();
2471
1268
  resolvedMatches.forEach(async match => {
2472
1269
  // Validate the match (loads search params etc)
2473
- match.__.validate();
1270
+ match.__validate();
2474
1271
  });
2475
1272
 
2476
1273
  // Check each match middleware to see if the route can be accessed
2477
1274
  await Promise.all(resolvedMatches.map(async match => {
2478
1275
  try {
2479
- await (match.options.beforeLoad == null ? void 0 : match.options.beforeLoad({
2480
- router: router,
1276
+ await match.route.options.beforeLoad?.({
1277
+ router: this,
2481
1278
  match
2482
- }));
1279
+ });
2483
1280
  } catch (err) {
2484
- if (!(loaderOpts != null && loaderOpts.preload)) {
2485
- match.options.onLoadError == null ? void 0 : match.options.onLoadError(err);
1281
+ if (!loaderOpts?.preload) {
1282
+ match.route.options.onLoadError?.(err);
2486
1283
  }
2487
1284
  throw err;
2488
1285
  }
2489
1286
  }));
2490
- const matchPromises = resolvedMatches.map(async match => {
2491
- var _search$__data;
2492
- const search = match.store.search;
2493
- if ((_search$__data = search.__data) != null && _search$__data.matchId && search.__data.matchId !== match.matchId) {
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) {
2494
1291
  return;
2495
1292
  }
2496
1293
  match.load(loaderOpts);
2497
- if (match.store.status !== 'success' && match.__.loadPromise) {
1294
+ if (match.store.state.status !== 'success' && match.__loadPromise) {
2498
1295
  // Wait for the first sign of activity from the match
2499
- await match.__.loadPromise;
1296
+ await match.__loadPromise;
1297
+ }
1298
+ if (prevMatch) {
1299
+ await prevMatch.__loadPromise;
2500
1300
  }
2501
1301
  });
2502
1302
  await Promise.all(matchPromises);
2503
- },
2504
- loadMatchData: async routeMatch => {
2505
- if (isServer || !router.options.useServerData) {
2506
- return (await (routeMatch.options.loader == null ? void 0 : routeMatch.options.loader({
2507
- // parentLoaderPromise: routeMatch.parentMatch?.__.dataPromise,
1303
+ };
1304
+ loadMatchData = async routeMatch => {
1305
+ if (isServer || !this.options.useServerData) {
1306
+ return (await routeMatch.route.options.loader?.({
1307
+ // parentLoaderPromise: routeMatch.parentMatch.dataPromise,
2508
1308
  params: routeMatch.params,
2509
- search: routeMatch.store.routeSearch,
2510
- signal: routeMatch.__.abortController.signal
2511
- }))) || {};
1309
+ search: routeMatch.store.state.routeSearch,
1310
+ signal: routeMatch.abortController.signal
1311
+ })) || {};
2512
1312
  } else {
2513
- const next = router.buildNext({
2514
- to: '.',
2515
- search: d => ({
2516
- ...(d ?? {}),
2517
- __data: {
2518
- matchId: routeMatch.matchId
2519
- }
2520
- })
2521
- });
2522
-
2523
1313
  // Refresh:
2524
1314
  // '/dashboard'
2525
1315
  // '/dashboard/invoices/'
@@ -2530,65 +1320,39 @@
2530
1320
 
2531
1321
  // TODO: batch requests when possible
2532
1322
 
2533
- const res = await fetch(next.href, {
2534
- method: 'GET'
2535
- // signal: routeMatch.__.abortController.signal,
1323
+ return this.options.fetchServerDataFn({
1324
+ router: this,
1325
+ routeMatch
2536
1326
  });
2537
-
2538
- if (res.ok) {
2539
- return res.json();
2540
- }
2541
- throw new Error('Failed to fetch match data');
2542
1327
  }
2543
- },
2544
- invalidateRoute: opts => {
2545
- const next = router.buildNext(opts);
2546
- const unloadedMatchIds = router.matchRoutes(next.pathname).map(d => d.matchId);
2547
- [...store.currentMatches, ...(store.pendingMatches ?? [])].forEach(match => {
2548
- if (unloadedMatchIds.includes(match.matchId)) {
2549
- match.invalidate();
2550
- }
2551
- });
2552
- },
2553
- reload: () => navigate({
2554
- fromCurrent: true,
2555
- replace: true,
2556
- search: true
2557
- }),
2558
- resolvePath: (from, path) => {
2559
- return resolvePath(router.basepath, from, cleanPath(path));
2560
- },
2561
- matchRoute: (location, opts) => {
2562
- // const location = router.buildNext(opts)
2563
-
2564
- location = {
2565
- ...location,
2566
- to: location.to ? router.resolvePath(location.from ?? '', location.to) : undefined
2567
- };
2568
- const next = router.buildNext(location);
2569
- if (opts != null && opts.pending) {
2570
- if (!store.pendingLocation) {
2571
- return false;
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();
2572
1335
  }
2573
- return !!matchPathname(router.basepath, store.pendingLocation.pathname, {
2574
- ...opts,
2575
- to: next.pathname
2576
- });
2577
- }
2578
- return matchPathname(router.basepath, store.currentLocation.pathname, {
2579
- ...opts,
2580
- to: next.pathname
1336
+ }));
1337
+ };
1338
+ reload = () => {
1339
+ this.navigate({
1340
+ fromCurrent: true,
1341
+ replace: true,
1342
+ search: true
2581
1343
  });
2582
- },
2583
- navigate: async _ref => {
2584
- let {
2585
- from,
2586
- to = '.',
2587
- search,
2588
- hash,
2589
- replace,
2590
- params
2591
- } = _ref;
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
+ }) => {
2592
1356
  // If this link simply reloads the current route,
2593
1357
  // make sure it has a new key so it will trigger a data refresh
2594
1358
 
@@ -2601,8 +1365,8 @@
2601
1365
  new URL(`${toString}`);
2602
1366
  isExternal = true;
2603
1367
  } catch (e) {}
2604
- invariant(!isExternal, 'Attempting to navigate to external url with router.navigate!');
2605
- return navigate({
1368
+ invariant(!isExternal, 'Attempting to navigate to external url with this.navigate!');
1369
+ return this.#commitLocation({
2606
1370
  from: fromString,
2607
1371
  to: toString,
2608
1372
  search,
@@ -2610,23 +1374,42 @@
2610
1374
  replace,
2611
1375
  params
2612
1376
  });
2613
- },
2614
- buildLink: _ref2 => {
2615
- let {
2616
- from,
2617
- to = '.',
2618
- search,
2619
- params,
2620
- hash,
2621
- target,
2622
- replace,
2623
- activeOptions,
2624
- preload,
2625
- preloadMaxAge: userPreloadMaxAge,
2626
- preloadGcMaxAge: userPreloadGcMaxAge,
2627
- preloadDelay: userPreloadDelay,
2628
- disabled
2629
- } = _ref2;
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
+ }) => {
2630
1413
  // If this link simply reloads the current route,
2631
1414
  // make sure it has a new key so it will trigger a data refresh
2632
1415
 
@@ -2648,19 +1431,19 @@
2648
1431
  hash,
2649
1432
  replace
2650
1433
  };
2651
- const next = router.buildNext(nextOpts);
2652
- preload = preload ?? router.options.defaultPreload;
2653
- const preloadDelay = userPreloadDelay ?? router.options.defaultPreloadDelay ?? 0;
1434
+ const next = this.buildNext(nextOpts);
1435
+ preload = preload ?? this.options.defaultPreload;
1436
+ const preloadDelay = userPreloadDelay ?? this.options.defaultPreloadDelay ?? 0;
2654
1437
 
2655
1438
  // Compare path/hash for matches
2656
- const pathIsEqual = store.currentLocation.pathname === next.pathname;
2657
- const currentPathSplit = store.currentLocation.pathname.split('/');
1439
+ const pathIsEqual = this.store.state.currentLocation.pathname === next.pathname;
1440
+ const currentPathSplit = this.store.state.currentLocation.pathname.split('/');
2658
1441
  const nextPathSplit = next.pathname.split('/');
2659
1442
  const pathIsFuzzyEqual = nextPathSplit.every((d, i) => d === currentPathSplit[i]);
2660
- const hashIsEqual = store.currentLocation.hash === next.hash;
1443
+ const hashIsEqual = this.store.state.currentLocation.hash === next.hash;
2661
1444
  // Combine the matches based on user options
2662
- const pathTest = activeOptions != null && activeOptions.exact ? pathIsEqual : pathIsFuzzyEqual;
2663
- const hashTest = activeOptions != null && activeOptions.includeHash ? hashIsEqual : true;
1445
+ const pathTest = activeOptions?.exact ? pathIsEqual : pathIsFuzzyEqual;
1446
+ const hashTest = activeOptions?.includeHash ? hashIsEqual : true;
2664
1447
 
2665
1448
  // The final "active" test
2666
1449
  const isActive = pathTest && hashTest;
@@ -2670,22 +1453,22 @@
2670
1453
  if (!disabled && !isCtrlEvent(e) && !e.defaultPrevented && (!target || target === '_self') && e.button === 0) {
2671
1454
  e.preventDefault();
2672
1455
  if (pathIsEqual && !search && !hash) {
2673
- router.invalidateRoute(nextOpts);
1456
+ this.invalidateRoute(nextOpts);
2674
1457
  }
2675
1458
 
2676
1459
  // All is well? Navigate!
2677
- navigate(nextOpts);
1460
+ this.#commitLocation(nextOpts);
2678
1461
  }
2679
1462
  };
2680
1463
 
2681
1464
  // The click handler
2682
1465
  const handleFocus = e => {
2683
1466
  if (preload) {
2684
- router.preloadRoute(nextOpts, {
1467
+ this.preloadRoute(nextOpts, {
2685
1468
  maxAge: userPreloadMaxAge,
2686
1469
  gcMaxAge: userPreloadGcMaxAge
2687
1470
  }).catch(err => {
2688
- console.log(err);
1471
+ console.warn(err);
2689
1472
  console.warn('Error preloading route! ☝️');
2690
1473
  });
2691
1474
  }
@@ -2698,11 +1481,11 @@
2698
1481
  }
2699
1482
  target.preloadTimeout = setTimeout(() => {
2700
1483
  target.preloadTimeout = null;
2701
- router.preloadRoute(nextOpts, {
1484
+ this.preloadRoute(nextOpts, {
2702
1485
  maxAge: userPreloadMaxAge,
2703
1486
  gcMaxAge: userPreloadGcMaxAge
2704
1487
  }).catch(err => {
2705
- console.log(err);
1488
+ console.warn(err);
2706
1489
  console.warn('Error preloading route! ☝️');
2707
1490
  });
2708
1491
  }, preloadDelay);
@@ -2725,71 +1508,338 @@
2725
1508
  isActive,
2726
1509
  disabled
2727
1510
  };
2728
- },
2729
- buildNext: opts => {
2730
- const next = buildLocation(opts);
2731
- const matches = router.matchRoutes(next.pathname);
2732
- const __preSearchFilters = matches.map(match => match.options.preSearchFilters ?? []).flat().filter(Boolean);
2733
- const __postSearchFilters = matches.map(match => match.options.postSearchFilters ?? []).flat().filter(Boolean);
2734
- return buildLocation({
2735
- ...opts,
2736
- __preSearchFilters,
2737
- __postSearchFilters
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;
1530
+
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
+ });
2738
1545
  });
2739
- }
2740
- };
2741
- router.update(userOptions);
2742
-
2743
- // Allow frameworks to hook into the router creation
2744
- router.options.createRouter == null ? void 0 : router.options.createRouter(router);
2745
- return router;
2746
- }
2747
- function isCtrlEvent(e) {
2748
- return !!(e.metaKey || e.altKey || e.ctrlKey || e.shiftKey);
2749
- }
2750
- function linkMatches(matches) {
2751
- matches.forEach((match, index) => {
2752
- const parent = matches[index - 1];
2753
- if (parent) {
2754
- match.__.setParentMatch(parent);
2755
- } else {
2756
- match.__.setParentMatch(undefined);
2757
- }
2758
- });
2759
- }
2760
-
2761
- exports.cleanPath = cleanPath;
2762
- exports.createBrowserHistory = createBrowserHistory;
2763
- exports.createHashHistory = createHashHistory;
2764
- exports.createMemoryHistory = createMemoryHistory;
2765
- exports.createRoute = createRoute;
2766
- exports.createRouteConfig = createRouteConfig;
2767
- exports.createRouteMatch = createRouteMatch;
2768
- exports.createRouter = createRouter;
2769
- exports.decode = decode;
2770
- exports.defaultParseSearch = defaultParseSearch;
2771
- exports.defaultStringifySearch = defaultStringifySearch;
2772
- exports.encode = encode;
2773
- exports.functionalUpdate = functionalUpdate;
2774
- exports.interpolatePath = interpolatePath;
2775
- exports.invariant = invariant;
2776
- exports.joinPaths = joinPaths;
2777
- exports.last = last;
2778
- exports.matchByPath = matchByPath;
2779
- exports.matchPathname = matchPathname;
2780
- exports.parsePathname = parsePathname;
2781
- exports.parseSearchWith = parseSearchWith;
2782
- exports.pick = pick;
2783
- exports.resolvePath = resolvePath;
2784
- exports.rootRouteId = rootRouteId;
2785
- exports.sharedClone = sharedClone;
2786
- exports.stringifySearchWith = stringifySearchWith;
2787
- exports.trimPath = trimPath;
2788
- exports.trimPathLeft = trimPathLeft;
2789
- exports.trimPathRight = trimPathRight;
2790
- exports.warning = warning;
2791
-
2792
- Object.defineProperty(exports, '__esModule', { value: true });
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
+ });
1574
+ }
1575
+ }
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
+ console.log({
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
+ return {
1621
+ pathname: pathname,
1622
+ searchStr: search,
1623
+ search: replaceEqualDeep(previousLocation?.search, parsedSearch),
1624
+ hash: hash.split('#').reverse()[0] ?? '',
1625
+ href: `${pathname}${search}${hash}`,
1626
+ state: state,
1627
+ key: state?.key || '__init__'
1628
+ };
1629
+ };
1630
+ #onFocus = () => {
1631
+ this.load();
1632
+ };
1633
+ #buildLocation = (dest = {}) => {
1634
+ const fromPathname = dest.fromCurrent ? this.store.state.latestLocation.pathname : dest.from ?? this.store.state.latestLocation.pathname;
1635
+ let pathname = resolvePath(this.basepath ?? '/', fromPathname, `${dest.to ?? '.'}`);
1636
+ const fromMatches = this.matchRoutes(this.store.state.latestLocation.pathname, {
1637
+ strictParseParams: true
1638
+ });
1639
+ const toMatches = this.matchRoutes(pathname);
1640
+ const prevParams = {
1641
+ ...last(fromMatches)?.params
1642
+ };
1643
+ let nextParams = (dest.params ?? true) === true ? prevParams : functionalUpdate(dest.params, prevParams);
1644
+ if (nextParams) {
1645
+ toMatches.map(d => d.route.options.stringifyParams).filter(Boolean).forEach(fn => {
1646
+ Object.assign({}, nextParams, fn(nextParams));
1647
+ });
1648
+ }
1649
+ pathname = interpolatePath(pathname, nextParams ?? {});
1650
+
1651
+ // Pre filters first
1652
+ const preFilteredSearch = dest.__preSearchFilters?.length ? dest.__preSearchFilters?.reduce((prev, next) => next(prev), this.store.state.latestLocation.search) : this.store.state.latestLocation.search;
1653
+
1654
+ // Then the link/navigate function
1655
+ const destSearch = dest.search === true ? preFilteredSearch // Preserve resolvedFrom true
1656
+ : dest.search ? functionalUpdate(dest.search, preFilteredSearch) ?? {} // Updater
1657
+ : dest.__preSearchFilters?.length ? preFilteredSearch // Preserve resolvedFrom filters
1658
+ : {};
1659
+
1660
+ // Then post filters
1661
+ const postFilteredSearch = dest.__postSearchFilters?.length ? dest.__postSearchFilters.reduce((prev, next) => next(prev), destSearch) : destSearch;
1662
+ const search = replaceEqualDeep(this.store.state.latestLocation.search, postFilteredSearch);
1663
+ const searchStr = this.options.stringifySearch(search);
1664
+ let hash = dest.hash === true ? this.store.state.latestLocation.hash : functionalUpdate(dest.hash, this.store.state.latestLocation.hash);
1665
+ hash = hash ? `#${hash}` : '';
1666
+ return {
1667
+ pathname,
1668
+ search,
1669
+ searchStr,
1670
+ state: this.store.state.latestLocation.state,
1671
+ hash,
1672
+ href: `${pathname}${searchStr}${hash}`,
1673
+ key: dest.key
1674
+ };
1675
+ };
1676
+ #commitLocation = location => {
1677
+ const next = this.buildNext(location);
1678
+ const id = '' + Date.now() + Math.random();
1679
+ if (this.navigateTimeout) clearTimeout(this.navigateTimeout);
1680
+ let nextAction = 'replace';
1681
+ if (!location.replace) {
1682
+ nextAction = 'push';
1683
+ }
1684
+ const isSameUrl = this.store.state.latestLocation.href === next.href;
1685
+ if (isSameUrl && !next.key) {
1686
+ nextAction = 'replace';
1687
+ }
1688
+ const href = `${next.pathname}${next.searchStr}${next.hash ? `#${next.hash}` : ''}`;
1689
+ this.history[nextAction === 'push' ? 'push' : 'replace'](href, {
1690
+ id,
1691
+ ...next.state
1692
+ });
1693
+ this.load(this.#parseLocation(this.store.state.latestLocation));
1694
+ return this.navigationPromise = new Promise(resolve => {
1695
+ const previousNavigationResolve = this.resolveNavigation;
1696
+ this.resolveNavigation = () => {
1697
+ previousNavigationResolve();
1698
+ resolve();
1699
+ };
1700
+ });
1701
+ };
1702
+ }
1703
+
1704
+ // Detect if we're in the DOM
1705
+ const isServer = typeof window === 'undefined' || !window.document.createElement;
1706
+ function getInitialRouterState() {
1707
+ return {
1708
+ status: 'idle',
1709
+ latestLocation: null,
1710
+ currentLocation: null,
1711
+ currentMatches: [],
1712
+ loaders: {},
1713
+ lastUpdated: Date.now(),
1714
+ matchCache: {},
1715
+ get isFetching() {
1716
+ return this.status === 'loading' || this.currentMatches.some(d => d.store.state.isFetching);
1717
+ },
1718
+ get isPreloading() {
1719
+ return Object.values(this.matchCache).some(d => d.match.store.state.isFetching && !this.currentMatches.find(dd => dd.id === d.match.id));
1720
+ }
1721
+ };
1722
+ }
1723
+ function isCtrlEvent(e) {
1724
+ return !!(e.metaKey || e.altKey || e.ctrlKey || e.shiftKey);
1725
+ }
1726
+ function linkMatches(matches) {
1727
+ matches.forEach((match, index) => {
1728
+ const parent = matches[index - 1];
1729
+ if (parent) {
1730
+ match.__setParentMatch(parent);
1731
+ }
1732
+ });
1733
+ }
1734
+
1735
+ // createRouterAction is a constrained identify function that takes options: key, action, onSuccess, onError, onSettled, etc
1736
+ function createAction(options) {
1737
+ const store = createStore({
1738
+ submissions: []
1739
+ }, options.debug);
1740
+ return {
1741
+ options,
1742
+ store,
1743
+ reset: () => {
1744
+ store.setState(s => {
1745
+ s.submissions = [];
1746
+ });
1747
+ },
1748
+ submit: async payload => {
1749
+ const submission = {
1750
+ submittedAt: Date.now(),
1751
+ status: 'pending',
1752
+ payload: payload,
1753
+ invalidate: () => {
1754
+ setSubmission(s => {
1755
+ s.isInvalid = true;
1756
+ });
1757
+ },
1758
+ getIsLatest: () => store.state.submissions[store.state.submissions.length - 1]?.submittedAt === submission.submittedAt
1759
+ };
1760
+ const setSubmission = updater => {
1761
+ store.setState(s => {
1762
+ const a = s.submissions.find(d => d.submittedAt === submission.submittedAt);
1763
+ invariant(a, 'Could not find submission in store');
1764
+ updater(a);
1765
+ });
1766
+ };
1767
+ store.setState(s => {
1768
+ s.submissions.push(submission);
1769
+ s.submissions.reverse();
1770
+ s.submissions = s.submissions.slice(0, options.maxSubmissions ?? 10);
1771
+ s.submissions.reverse();
1772
+ });
1773
+ const after = async () => {
1774
+ options.onEachSettled?.(submission);
1775
+ if (submission.getIsLatest()) await options.onLatestSettled?.(submission);
1776
+ };
1777
+ try {
1778
+ const res = await options.action?.(submission.payload);
1779
+ setSubmission(s => {
1780
+ s.response = res;
1781
+ });
1782
+ await options.onEachSuccess?.(submission);
1783
+ if (submission.getIsLatest()) await options.onLatestSuccess?.(submission);
1784
+ await after();
1785
+ setSubmission(s => {
1786
+ s.status = 'success';
1787
+ });
1788
+ return res;
1789
+ } catch (err) {
1790
+ console.error(err);
1791
+ setSubmission(s => {
1792
+ s.error = err;
1793
+ });
1794
+ await options.onEachError?.(submission);
1795
+ if (submission.getIsLatest()) await options.onLatestError?.(submission);
1796
+ await after();
1797
+ setSubmission(s => {
1798
+ s.status = 'error';
1799
+ });
1800
+ throw err;
1801
+ }
1802
+ }
1803
+ };
1804
+ }
1805
+
1806
+ exports.Route = Route;
1807
+ exports.RouteMatch = RouteMatch;
1808
+ exports.Router = Router;
1809
+ exports.batch = batch;
1810
+ exports.cleanPath = cleanPath;
1811
+ exports.createAction = createAction;
1812
+ exports.createBrowserHistory = createBrowserHistory;
1813
+ exports.createHashHistory = createHashHistory;
1814
+ exports.createMemoryHistory = createMemoryHistory;
1815
+ exports.createRouteConfig = createRouteConfig;
1816
+ exports.createStore = createStore;
1817
+ exports.decode = decode;
1818
+ exports.defaultFetchServerDataFn = defaultFetchServerDataFn;
1819
+ exports.defaultParseSearch = defaultParseSearch;
1820
+ exports.defaultStringifySearch = defaultStringifySearch;
1821
+ exports.encode = encode;
1822
+ exports.functionalUpdate = functionalUpdate;
1823
+ exports.interpolatePath = interpolatePath;
1824
+ exports.invariant = invariant;
1825
+ exports.joinPaths = joinPaths;
1826
+ exports.last = last;
1827
+ exports.matchByPath = matchByPath;
1828
+ exports.matchPathname = matchPathname;
1829
+ exports.parsePathname = parsePathname;
1830
+ exports.parseSearchWith = parseSearchWith;
1831
+ exports.pick = pick;
1832
+ exports.replaceEqualDeep = replaceEqualDeep;
1833
+ exports.resolvePath = resolvePath;
1834
+ exports.rootRouteId = rootRouteId;
1835
+ exports.stringifySearchWith = stringifySearchWith;
1836
+ exports.trackDeep = trackDeep;
1837
+ exports.trimPath = trimPath;
1838
+ exports.trimPathLeft = trimPathLeft;
1839
+ exports.trimPathRight = trimPathRight;
1840
+ exports.warning = warning;
1841
+
1842
+ Object.defineProperty(exports, '__esModule', { value: true });
2793
1843
 
2794
1844
  }));
2795
1845
  //# sourceMappingURL=index.development.js.map