native-conductor-cache.ts 2.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105
  1. import { isPageCacheEnabled } from 'app/lib/cache/cache-flags'
  2. const SEP = '\u0000'
  3. const conductorCache = new Map()
  4. /** normalizedUrl → Set of full conductor keys (all layouts). */
  5. const keysByUrl = new Map()
  6. function sanitizeCachedRoutes(routes: any) {
  7. if (!Array.isArray(routes)) return routes || []
  8. return routes.map((route) => ({
  9. ...route,
  10. data: (route?.data || []).filter((item: any) => item?.type === 'block'),
  11. }))
  12. }
  13. function normalizeConductorCacheUrl(url: string) {
  14. return String(url || '').replace(/^\/+/, '').replace(/\/+$/, '')
  15. }
  16. function conductorCacheKey(layoutName: string, url: string) {
  17. return `${layoutName}${SEP}${url}`
  18. }
  19. function indexAdd(url: string, key: string) {
  20. let set = keysByUrl.get(url)
  21. if (!set) {
  22. set = new Set()
  23. keysByUrl.set(url, set)
  24. }
  25. set.add(key)
  26. }
  27. function indexRemove(url: string, key: string) {
  28. const set = keysByUrl.get(url)
  29. if (!set) return
  30. set.delete(key)
  31. if (set.size === 0) keysByUrl.delete(url)
  32. }
  33. export function getCachedConductorState(layoutName: string, url: string) {
  34. if (!isPageCacheEnabled()) return null
  35. if (!layoutName || !url) return null
  36. const normalized = normalizeConductorCacheUrl(url)
  37. const state = conductorCache.get(conductorCacheKey(layoutName, normalized)) ?? null
  38. if (!state?.routes?.length) return state
  39. return {
  40. ...state,
  41. routes: sanitizeCachedRoutes(state.routes),
  42. }
  43. }
  44. export function setCachedConductorState(layoutName: string, url: string, state: any) {
  45. if (!isPageCacheEnabled()) return
  46. if (!layoutName || !url || !state?.routes?.length) return
  47. const normalized = normalizeConductorCacheUrl(url)
  48. const key = conductorCacheKey(layoutName, normalized)
  49. conductorCache.set(key, {
  50. ...state,
  51. routes: sanitizeCachedRoutes(state.routes),
  52. })
  53. indexAdd(normalized, key)
  54. }
  55. /**
  56. * Drop a conductor list snapshot. Prefer url-only (omit layoutName) so both
  57. * `navigator` and `notif` page layouts are covered.
  58. */
  59. export function clearCachedConductorState(layoutName: string, url: string) {
  60. if (!url) return
  61. const normalized = normalizeConductorCacheUrl(url)
  62. if (!normalized) return
  63. if (layoutName) {
  64. const key = conductorCacheKey(layoutName, normalized)
  65. conductorCache.delete(key)
  66. indexRemove(normalized, key)
  67. return
  68. }
  69. const keys = keysByUrl.get(normalized)
  70. if (!keys) return
  71. for (const key of keys) {
  72. conductorCache.delete(key)
  73. }
  74. keysByUrl.delete(normalized)
  75. }
  76. let notificationsConductorStale = false
  77. export function markNotificationsConductorStale() {
  78. notificationsConductorStale = true
  79. }
  80. export function consumeNotificationsConductorStale() {
  81. if (!notificationsConductorStale) return false
  82. notificationsConductorStale = false
  83. return true
  84. }
  85. export function clearConductorCache() {
  86. conductorCache.clear()
  87. keysByUrl.clear()
  88. notificationsConductorStale = false
  89. }