@asteby/metacore-runtime-react 9.2.0 → 10.0.0

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.
@@ -14,6 +14,31 @@ export interface MetadataApiClient {
14
14
  get: (url: string, config?: any) => Promise<{ data: any }>
15
15
  }
16
16
 
17
+ /**
18
+ * Predicate matching a cache key against an addon. The default
19
+ * implementation (see {@link defaultAddonKeyMatcher}) treats `addonKey`
20
+ * itself plus any key beginning with `${addonKey}.`, `${addonKey}:` or
21
+ * `${addonKey}/` as belonging to the addon. Hosts that namespace their
22
+ * `model` strings differently can pass a custom matcher to
23
+ * {@link MetadataCacheState.invalidateAddon}.
24
+ */
25
+ export type AddonKeyMatcher = (cacheKey: string, addonKey: string) => boolean
26
+
27
+ /**
28
+ * Default matcher used by {@link MetadataCacheState.invalidateAddon}.
29
+ * Mirrors the convention used by the kernel installer when it scopes
30
+ * model metadata under an addon's key.
31
+ */
32
+ export function defaultAddonKeyMatcher(cacheKey: string, addonKey: string): boolean {
33
+ if (!addonKey) return false
34
+ if (cacheKey === addonKey) return true
35
+ return (
36
+ cacheKey.startsWith(`${addonKey}.`) ||
37
+ cacheKey.startsWith(`${addonKey}:`) ||
38
+ cacheKey.startsWith(`${addonKey}/`)
39
+ )
40
+ }
41
+
17
42
  interface MetadataCacheState {
18
43
  cache: Record<string, TableMetadata>
19
44
  modalCache: Record<string, TableMetadata>
@@ -26,6 +51,26 @@ interface MetadataCacheState {
26
51
  hasMetadata: (key: string) => boolean
27
52
  hasModalMetadata: (key: string) => boolean
28
53
  prefetchAll: (api: MetadataApiClient) => Promise<void>
54
+ /**
55
+ * Remove cached entries belonging to a specific addon. Used by the
56
+ * hot-swap subscriber when the kernel announces a manifest change.
57
+ *
58
+ * Returns the number of entries removed across both caches, which is
59
+ * useful for tests and observability — `0` means the cache had nothing
60
+ * to flush (the addon either hadn't been hit yet or uses a key
61
+ * convention the default matcher doesn't recognise; pass a custom
62
+ * `matcher` if your host namespaces differently).
63
+ *
64
+ * Also resets `prefetched` to `false` so the next mount re-runs
65
+ * `prefetchAll()` and the `metadataVersion` is allowed to advance to
66
+ * the kernel's freshly-bumped hash.
67
+ */
68
+ invalidateAddon: (addonKey: string, matcher?: AddonKeyMatcher) => number
69
+ /**
70
+ * Remove every cached entry. Heavier hammer for hosts that prefer a
71
+ * blanket flush on hot-swap rather than per-addon scoping.
72
+ */
73
+ clearAll: () => void
29
74
  }
30
75
 
31
76
  export const useMetadataCache = create<MetadataCacheState>()(
@@ -54,6 +99,47 @@ export const useMetadataCache = create<MetadataCacheState>()(
54
99
  hasMetadata: (key: string) => key in get().cache,
55
100
  hasModalMetadata: (key: string) => key in get().modalCache,
56
101
 
102
+ invalidateAddon: (addonKey: string, matcher = defaultAddonKeyMatcher) => {
103
+ if (!addonKey) return 0
104
+ let removed = 0
105
+ const state = get()
106
+ const nextCache: Record<string, TableMetadata> = {}
107
+ for (const [key, value] of Object.entries(state.cache)) {
108
+ if (matcher(key, addonKey)) {
109
+ removed += 1
110
+ continue
111
+ }
112
+ nextCache[key] = value
113
+ }
114
+ const nextModalCache: Record<string, TableMetadata> = {}
115
+ for (const [key, value] of Object.entries(state.modalCache)) {
116
+ if (matcher(key, addonKey)) {
117
+ removed += 1
118
+ continue
119
+ }
120
+ nextModalCache[key] = value
121
+ }
122
+ if (removed === 0) return 0
123
+ set({
124
+ cache: nextCache,
125
+ modalCache: nextModalCache,
126
+ // Allow prefetchAll() to re-run so we pick up the new
127
+ // metadataVersion the kernel emits alongside the
128
+ // bumped manifest.
129
+ prefetched: false,
130
+ })
131
+ return removed
132
+ },
133
+
134
+ clearAll: () => {
135
+ set({
136
+ cache: {},
137
+ modalCache: {},
138
+ metadataVersion: '',
139
+ prefetched: false,
140
+ })
141
+ },
142
+
57
143
  prefetchAll: async (api: MetadataApiClient) => {
58
144
  if (get().prefetched) return
59
145
  try {