clear-react-router 1.9.8 → 2.0.1

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.
package/README.md CHANGED
@@ -572,6 +572,8 @@ const UserProfile = () => {
572
572
  staleTime: 60000, // 1 minute — cache is fresh for 60 seconds
573
573
  }
574
574
  ```
575
+ - Stale cache entries are cleaned up incrementally on every navigation, keeping the loader cache from growing unbounded over long sessions.
576
+
575
577
 
576
578
  ### `useInvalidate()`
577
579
 
package/dist/index.js CHANGED
@@ -113,13 +113,12 @@ var createCommitNavigation = (navigationExecutor, routeItemDataState) => (nextLo
113
113
  };
114
114
  //#endregion
115
115
  //#region utils/isCacheItemFresh.ts
116
- var createIsCacheItemFresh = (loaderMap) => ({ routeItem, pathname }) => {
117
- if (!routeItem) return true;
118
- const item = loaderMap.get(pathname);
116
+ var createIsCacheItemFresh = (loaderMap) => (path) => {
117
+ const item = loaderMap.get(path);
119
118
  if (item === void 0) return false;
120
- const staleTime = routeItem.staleTime ?? routerConfig.defaultStaleTime;
121
- if (staleTime === void 0) return true;
122
- return Date.now() - item.timestamp <= staleTime;
119
+ const resolvedStaleTime = item.staleTime ?? routerConfig.defaultStaleTime;
120
+ if (resolvedStaleTime === void 0) return true;
121
+ return Date.now() - item.timestamp <= resolvedStaleTime;
123
122
  };
124
123
  //#endregion
125
124
  //#region ../../node_modules/react/cjs/react-jsx-runtime.production.js
@@ -273,29 +272,28 @@ var createNavigate = (routerState, revalidateCache) => {
273
272
  [prevPathname]: scrollPosition
274
273
  };
275
274
  });
276
- if (routeItem?.optimistic && loaderMap.has(location.pathname)) {
275
+ const path = `${location.pathname}${location.search}`;
276
+ if (routeItem?.optimistic && loaderMap.has(path)) {
277
277
  routeItemDataState.setState({
278
278
  routeItem,
279
279
  location
280
280
  });
281
- const currentLoaderState = loaderMap.get(location.pathname)?.state;
281
+ const currentLoaderState = loaderMap.get(path)?.state;
282
282
  if (currentLoaderState) loaderStateRef.set(currentLoaderState);
283
283
  } else {
284
- const pendingShouldExist = routeItem?.loader && !isCacheItemFresh({
285
- routeItem,
286
- pathname: location.pathname
287
- });
284
+ const pendingShouldExist = routeItem?.loader && !isCacheItemFresh(path);
288
285
  pendingState.setState(pendingShouldExist ? {
289
286
  routeItem,
290
287
  location
291
288
  } : void 0);
292
289
  }
293
290
  };
294
- const afterEachLoad = (routeItem, location) => {
291
+ const polling = (routeItem, location) => {
295
292
  if (!routeItem?.pollingInterval) return;
296
293
  interval = window.setInterval(() => revalidateCache({
297
294
  routeItem,
298
- pathname: location.pathname
295
+ pathname: location.pathname,
296
+ search: location.search
299
297
  }), routeItem.pollingInterval);
300
298
  };
301
299
  const loader = async (routeItem, location) => {
@@ -306,7 +304,7 @@ var createNavigate = (routerState, revalidateCache) => {
306
304
  pathname: location.pathname,
307
305
  search: location.search
308
306
  });
309
- afterEachLoad(routeItem, location);
307
+ polling(routeItem, location);
310
308
  };
311
309
  const afterLoad = async (routeItem, params) => {
312
310
  const { defaultAfterLoad } = routerConfig;
@@ -423,15 +421,21 @@ var getRetry = (routeItem) => {
423
421
  var sleep = async (ms) => new Promise((resolve) => setTimeout(resolve, ms));
424
422
  var createRevalidateCache = (routerState) => {
425
423
  const { loaderStateRef, contextState, loaderMap } = routerState;
424
+ const removeFirstStaleItem = () => {
425
+ const deletedItem = [...loaderMap.entries()].find(([, item]) => {
426
+ const staleTime = item.staleTime ?? routerConfig.defaultStaleTime;
427
+ return staleTime && staleTime + item.timestamp < Date.now();
428
+ });
429
+ if (deletedItem) loaderMap.delete(deletedItem[0]);
430
+ };
426
431
  const revalidateCache = async ({ routeItem, pathname, search = "" }, retried = 0) => {
427
432
  if (!routeItem?.loader) return;
428
433
  const isCacheItemFresh = createIsCacheItemFresh(loaderMap);
429
- if (loadingPromises.has(pathname)) return loadingPromises.get(pathname);
430
- if (isCacheItemFresh({
431
- routeItem,
432
- pathname
433
- })) {
434
- const item = loaderMap.get(pathname);
434
+ removeFirstStaleItem();
435
+ const path = `${pathname}${search}`;
436
+ if (loadingPromises.has(path)) return loadingPromises.get(path);
437
+ if (isCacheItemFresh(path)) {
438
+ const item = loaderMap.get(path);
435
439
  if (item?.state) loaderStateRef.set(item.state);
436
440
  return;
437
441
  }
@@ -453,9 +457,10 @@ var createRevalidateCache = (routerState) => {
453
457
  data: result,
454
458
  loaderError: null
455
459
  }));
456
- loaderMap.set(`${pathname}${search}`, {
460
+ loaderMap.set(path, {
457
461
  state: loaderStateRef.value,
458
- timestamp: Date.now()
462
+ timestamp: Date.now(),
463
+ staleTime: routeItem.staleTime
459
464
  });
460
465
  return {
461
466
  data: result,
@@ -464,7 +469,7 @@ var createRevalidateCache = (routerState) => {
464
469
  } catch (error) {
465
470
  const retry = getRetry(routeItem);
466
471
  if (retry && retry.count > retried) {
467
- loadingPromises.delete(`${pathname}${search}`);
472
+ loadingPromises.delete(path);
468
473
  if (retry.delay) await sleep(retry.delay);
469
474
  await revalidateCache({
470
475
  routeItem,
@@ -487,10 +492,10 @@ var createRevalidateCache = (routerState) => {
487
492
  };
488
493
  }
489
494
  } finally {
490
- loadingPromises.delete(`${pathname}${search}`);
495
+ loadingPromises.delete(path);
491
496
  }
492
497
  })();
493
- loadingPromises.set(`${pathname}${search}`, promise);
498
+ loadingPromises.set(path, promise);
494
499
  return promise;
495
500
  };
496
501
  return revalidateCache;
package/dist/types.d.ts CHANGED
@@ -102,6 +102,7 @@ export type RouterProps = {
102
102
  export type LoaderStateItem = {
103
103
  state: LoaderState;
104
104
  timestamp: number;
105
+ staleTime: number | undefined;
105
106
  };
106
107
  export type RouterState = {
107
108
  routeItemDataState: Store<RouteItemData>;
@@ -146,7 +147,7 @@ export type InvalidateOptions = {
146
147
  withChildren?: boolean;
147
148
  withBeforeLoad?: boolean;
148
149
  };
149
- export type RevalidateCache = ({ routeItem, pathname, }: RevalidateCacheArgs) => Promise<{
150
+ export type RevalidateCache = (args: RevalidateCacheArgs) => Promise<{
150
151
  data: unknown;
151
152
  error: unknown;
152
153
  }>;
@@ -1,5 +1,2 @@
1
- import { LoaderStateItem, RouteItem } from '../types';
2
- export declare const createIsCacheItemFresh: (loaderMap: Map<string, LoaderStateItem>) => ({ routeItem, pathname }: {
3
- routeItem?: RouteItem;
4
- pathname: string;
5
- }) => boolean;
1
+ import { LoaderStateItem } from '../types';
2
+ export declare const createIsCacheItemFresh: (loaderMap: Map<string, LoaderStateItem>) => (path: string) => boolean;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "clear-react-router",
3
- "version": "1.9.8",
3
+ "version": "2.0.1",
4
4
  "description": "A lightweight, type-safe routing library for React applications",
5
5
  "author": "Andrew Bubnov",
6
6
  "scripts": {