@memberjunction/core 5.37.0 → 5.39.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.
Files changed (53) hide show
  1. package/dist/generic/RegisterForStartup.d.ts +7 -0
  2. package/dist/generic/RegisterForStartup.d.ts.map +1 -1
  3. package/dist/generic/RegisterForStartup.js +26 -17
  4. package/dist/generic/RegisterForStartup.js.map +1 -1
  5. package/dist/generic/baseEngine.d.ts.map +1 -1
  6. package/dist/generic/baseEngine.js +34 -4
  7. package/dist/generic/baseEngine.js.map +1 -1
  8. package/dist/generic/baseEngineRegistry.d.ts +90 -0
  9. package/dist/generic/baseEngineRegistry.d.ts.map +1 -1
  10. package/dist/generic/baseEngineRegistry.js +100 -0
  11. package/dist/generic/baseEngineRegistry.js.map +1 -1
  12. package/dist/generic/baseEntity.d.ts.map +1 -1
  13. package/dist/generic/baseEntity.js +33 -1
  14. package/dist/generic/baseEntity.js.map +1 -1
  15. package/dist/generic/entityInfo.d.ts +36 -1
  16. package/dist/generic/entityInfo.d.ts.map +1 -1
  17. package/dist/generic/entityInfo.js +96 -4
  18. package/dist/generic/entityInfo.js.map +1 -1
  19. package/dist/generic/interfaces.d.ts +141 -0
  20. package/dist/generic/interfaces.d.ts.map +1 -1
  21. package/dist/generic/interfaces.js +9 -0
  22. package/dist/generic/interfaces.js.map +1 -1
  23. package/dist/generic/localCacheManager.d.ts.map +1 -1
  24. package/dist/generic/localCacheManager.js +3 -7
  25. package/dist/generic/localCacheManager.js.map +1 -1
  26. package/dist/generic/metadata.d.ts +48 -1
  27. package/dist/generic/metadata.d.ts.map +1 -1
  28. package/dist/generic/metadata.js +53 -0
  29. package/dist/generic/metadata.js.map +1 -1
  30. package/dist/generic/providerBase.d.ts +142 -38
  31. package/dist/generic/providerBase.d.ts.map +1 -1
  32. package/dist/generic/providerBase.js +309 -51
  33. package/dist/generic/providerBase.js.map +1 -1
  34. package/dist/generic/queryInfo.d.ts +11 -0
  35. package/dist/generic/queryInfo.d.ts.map +1 -1
  36. package/dist/generic/queryInfo.js +11 -0
  37. package/dist/generic/queryInfo.js.map +1 -1
  38. package/dist/generic/queryInfoInterfaces.d.ts +14 -0
  39. package/dist/generic/queryInfoInterfaces.d.ts.map +1 -1
  40. package/dist/generic/scoring/ReciprocalRankFusion.d.ts +11 -4
  41. package/dist/generic/scoring/ReciprocalRankFusion.d.ts.map +1 -1
  42. package/dist/generic/scoring/ReciprocalRankFusion.js +18 -6
  43. package/dist/generic/scoring/ReciprocalRankFusion.js.map +1 -1
  44. package/dist/index.d.ts +0 -1
  45. package/dist/index.d.ts.map +1 -1
  46. package/dist/index.js +0 -1
  47. package/dist/index.js.map +1 -1
  48. package/package.json +3 -3
  49. package/readme.md +164 -5
  50. package/dist/generic/QueryCacheManager.d.ts +0 -115
  51. package/dist/generic/QueryCacheManager.d.ts.map +0 -1
  52. package/dist/generic/QueryCacheManager.js +0 -329
  53. package/dist/generic/QueryCacheManager.js.map +0 -1
@@ -1,115 +0,0 @@
1
- import { QueryInfo } from './queryInfo.js';
2
- import { BaseSingleton } from '@memberjunction/global';
3
- /**
4
- * Wrapper around LocalCacheManager that translates query-specific caching concerns
5
- * (paging, count, ad-hoc keys, dependency invalidation, entity-change awareness)
6
- * into LocalCacheManager's generic RunQueryCache methods.
7
- *
8
- * Replaces the standalone QueryCache class so that query result caching participates
9
- * in LCM's unified eviction, TTL, statistics, and optional Redis persistence.
10
- *
11
- * ## IMPORTANT — Caching is intentionally BYPASSED for now
12
- *
13
- * All Get/Set methods are wired up but short-circuit to no-ops. The reason:
14
- *
15
- * Query results cannot be reliably invalidated today. Unlike RunView caching (which
16
- * tracks individual entities and can invalidate on any row-level mutation), queries
17
- * are arbitrary SQL that may join, filter, or aggregate across many tables. The
18
- * `QueryEntity` table maps queries to the entities they reference, but those mappings
19
- * are LLM-discovered and not guaranteed to be complete. A TTL-only strategy risks
20
- * serving stale data when the underlying rows change before the TTL expires.
21
- *
22
- * The full caching implementation is preserved below so that when we have a reliable
23
- * invalidation strategy (e.g., entity mutation hooks that can confidently evict all
24
- * affected query caches with complete QueryEntity coverage), we can enable caching
25
- * by removing the early returns at the top of each method. Until then, every query
26
- * execution hits the database to guarantee fresh results.
27
- */
28
- export declare class QueryCacheManager extends BaseSingleton<QueryCacheManager> {
29
- private _connectionPrefix;
30
- /** Tracks cache timestamps per fingerprint for computing CacheTTLRemaining */
31
- private _cacheTimestamps;
32
- /** Reverse index: normalized entity name → set of fingerprints that depend on it */
33
- private _queryEntityIndex;
34
- protected constructor();
35
- /**
36
- * Returns the singleton instance of QueryCacheManager.
37
- */
38
- static get Instance(): QueryCacheManager;
39
- /**
40
- * Initializes (or re-initializes) the connection prefix used for fingerprinting.
41
- * Idempotent — safe to call multiple times with the same or different prefix.
42
- */
43
- Init(connectionPrefix: string): void;
44
- private get LCM();
45
- private Fingerprint;
46
- private PagedFingerprint;
47
- private CountFingerprint;
48
- private AdhocFingerprint;
49
- /**
50
- * Retrieves cached full (unpaginated) results for a saved query.
51
- * Returns null on miss or if caching is disabled.
52
- */
53
- Get(query: QueryInfo, params: Record<string, unknown>): Promise<{
54
- results: unknown[];
55
- ttlRemainingMs: number;
56
- } | null>;
57
- /**
58
- * Stores full (unpaginated) query results in the cache.
59
- */
60
- Set(query: QueryInfo, params: Record<string, unknown>, results: unknown[]): Promise<void>;
61
- /**
62
- * Retrieves cached results for a specific page of a paged query.
63
- */
64
- GetPaged(query: QueryInfo, params: Record<string, unknown>, startRow: number, maxRows: number): Promise<{
65
- results: unknown[];
66
- ttlRemainingMs: number;
67
- } | null>;
68
- /**
69
- * Stores results for a specific page in the cache.
70
- */
71
- SetPaged(query: QueryInfo, params: Record<string, unknown>, startRow: number, maxRows: number, results: unknown[]): Promise<void>;
72
- /**
73
- * Retrieves a cached TotalRowCount for a query + params combination.
74
- */
75
- GetTotalRowCount(query: QueryInfo, params: Record<string, unknown>): Promise<number | null>;
76
- /**
77
- * Stores a TotalRowCount value in the cache, encoded as a single-row result.
78
- */
79
- SetTotalRowCount(query: QueryInfo, params: Record<string, unknown>, count: number): Promise<void>;
80
- /**
81
- * Retrieves cached results for an ad-hoc SQL query.
82
- */
83
- GetAdhoc(sql: string, ttlMinutes: number): Promise<{
84
- results: unknown[];
85
- } | null>;
86
- /**
87
- * Stores ad-hoc SQL query results in the cache.
88
- */
89
- SetAdhoc(sql: string, ttlMinutes: number, results: unknown[]): Promise<void>;
90
- /**
91
- * Invalidates all cache entries (full, paged, count) for a single query by name.
92
- */
93
- InvalidateQuery(queryName: string): Promise<void>;
94
- /**
95
- * Invalidates cache entries for a query and all queries that transitively depend on it.
96
- */
97
- InvalidateWithDependents(query: QueryInfo, visited?: Set<string>): Promise<void>;
98
- /**
99
- * Called when an entity changes (save/delete). Invalidates all query cache entries
100
- * that depend on the changed entity via QueryEntity mappings.
101
- *
102
- * While caching is bypassed the reverse index will always be empty, so this is
103
- * effectively a no-op. Kept wired up so enabling caching requires no caller changes.
104
- */
105
- HandleEntityChange(entityName: string): Promise<void>;
106
- private RegisterEntityDependencies;
107
- private GetTransitiveEntityDependencies;
108
- private FindQueryById;
109
- private computeTTLRemaining;
110
- /**
111
- * FNV-1a 32-bit hash — fast, deterministic, good distribution for cache keys.
112
- */
113
- private static Fnv1aHash;
114
- }
115
- //# sourceMappingURL=QueryCacheManager.d.ts.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"QueryCacheManager.d.ts","sourceRoot":"","sources":["../../src/generic/QueryCacheManager.ts"],"names":[],"mappings":"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"}
@@ -1,329 +0,0 @@
1
- import { LocalCacheManager } from './localCacheManager.js';
2
- import { Metadata } from './metadata.js';
3
- import { LogStatus } from './logging.js';
4
- import { BaseSingleton, UUIDsEqual } from '@memberjunction/global';
5
- /**
6
- * Wrapper around LocalCacheManager that translates query-specific caching concerns
7
- * (paging, count, ad-hoc keys, dependency invalidation, entity-change awareness)
8
- * into LocalCacheManager's generic RunQueryCache methods.
9
- *
10
- * Replaces the standalone QueryCache class so that query result caching participates
11
- * in LCM's unified eviction, TTL, statistics, and optional Redis persistence.
12
- *
13
- * ## IMPORTANT — Caching is intentionally BYPASSED for now
14
- *
15
- * All Get/Set methods are wired up but short-circuit to no-ops. The reason:
16
- *
17
- * Query results cannot be reliably invalidated today. Unlike RunView caching (which
18
- * tracks individual entities and can invalidate on any row-level mutation), queries
19
- * are arbitrary SQL that may join, filter, or aggregate across many tables. The
20
- * `QueryEntity` table maps queries to the entities they reference, but those mappings
21
- * are LLM-discovered and not guaranteed to be complete. A TTL-only strategy risks
22
- * serving stale data when the underlying rows change before the TTL expires.
23
- *
24
- * The full caching implementation is preserved below so that when we have a reliable
25
- * invalidation strategy (e.g., entity mutation hooks that can confidently evict all
26
- * affected query caches with complete QueryEntity coverage), we can enable caching
27
- * by removing the early returns at the top of each method. Until then, every query
28
- * execution hits the database to guarantee fresh results.
29
- */
30
- export class QueryCacheManager extends BaseSingleton {
31
- constructor() {
32
- super();
33
- this._connectionPrefix = '';
34
- /** Tracks cache timestamps per fingerprint for computing CacheTTLRemaining */
35
- this._cacheTimestamps = new Map();
36
- /** Reverse index: normalized entity name → set of fingerprints that depend on it */
37
- this._queryEntityIndex = new Map();
38
- }
39
- /**
40
- * Returns the singleton instance of QueryCacheManager.
41
- */
42
- static get Instance() {
43
- return super.getInstance();
44
- }
45
- /**
46
- * Initializes (or re-initializes) the connection prefix used for fingerprinting.
47
- * Idempotent — safe to call multiple times with the same or different prefix.
48
- */
49
- Init(connectionPrefix) {
50
- this._connectionPrefix = connectionPrefix;
51
- }
52
- get LCM() {
53
- return LocalCacheManager.Instance;
54
- }
55
- // ── Fingerprint generation ──────────────────────────────────────────────
56
- Fingerprint(queryId, queryName, params) {
57
- return this.LCM.GenerateRunQueryFingerprint(queryId, queryName, params, this._connectionPrefix);
58
- }
59
- PagedFingerprint(queryId, queryName, params, startRow, maxRows) {
60
- return `${this.Fingerprint(queryId, queryName, params)}|page:${startRow}:${maxRows}`;
61
- }
62
- CountFingerprint(queryId, queryName, params) {
63
- return `${this.Fingerprint(queryId, queryName, params)}|count`;
64
- }
65
- AdhocFingerprint(sql) {
66
- return `_adhoc_|_|${QueryCacheManager.Fnv1aHash(sql)}|${this._connectionPrefix}`;
67
- }
68
- // ── Full-result cache ───────────────────────────────────────────────────
69
- /**
70
- * Retrieves cached full (unpaginated) results for a saved query.
71
- * Returns null on miss or if caching is disabled.
72
- */
73
- async Get(query, params) {
74
- // BYPASSED — see class-level comment for rationale
75
- return null;
76
- /* When caching is enabled, uncomment the block below:
77
- if (!query.CacheConfig?.enabled) return null;
78
-
79
- const fp = this.Fingerprint(query.ID, query.Name, params);
80
- const cached = await this.LCM.GetRunQueryResult(fp);
81
- if (!cached) return null;
82
-
83
- const ttlRemainingMs = this.computeTTLRemaining(fp, query.CacheConfig.ttlMinutes);
84
- return { results: cached.results, ttlRemainingMs };
85
- */
86
- }
87
- /**
88
- * Stores full (unpaginated) query results in the cache.
89
- */
90
- async Set(query, params, results) {
91
- // BYPASSED — see class-level comment for rationale
92
- return;
93
- /* When caching is enabled, uncomment the block below:
94
- const config = query.CacheConfig;
95
- if (!config?.enabled) return;
96
-
97
- const fp = this.Fingerprint(query.ID, query.Name, params);
98
- const ttlMs = config.ttlMinutes * 60 * 1000;
99
-
100
- await this.LCM.SetRunQueryResult(
101
- fp, query.Name, results,
102
- new Date().toISOString(),
103
- results.length, query.ID, ttlMs,
104
- );
105
- this._cacheTimestamps.set(fp, Date.now());
106
- this.RegisterEntityDependencies(fp, query);
107
- */
108
- }
109
- // ── Paged cache ─────────────────────────────────────────────────────────
110
- /**
111
- * Retrieves cached results for a specific page of a paged query.
112
- */
113
- async GetPaged(query, params, startRow, maxRows) {
114
- // BYPASSED — see class-level comment for rationale
115
- return null;
116
- /* When caching is enabled, uncomment the block below:
117
- if (!query.CacheConfig?.enabled) return null;
118
-
119
- const fp = this.PagedFingerprint(query.ID, query.Name, params, startRow, maxRows);
120
- const cached = await this.LCM.GetRunQueryResult(fp);
121
- if (!cached) return null;
122
-
123
- const ttlRemainingMs = this.computeTTLRemaining(fp, query.CacheConfig.ttlMinutes);
124
- return { results: cached.results, ttlRemainingMs };
125
- */
126
- }
127
- /**
128
- * Stores results for a specific page in the cache.
129
- */
130
- async SetPaged(query, params, startRow, maxRows, results) {
131
- // BYPASSED — see class-level comment for rationale
132
- return;
133
- /* When caching is enabled, uncomment the block below:
134
- const config = query.CacheConfig;
135
- if (!config?.enabled) return;
136
-
137
- const fp = this.PagedFingerprint(query.ID, query.Name, params, startRow, maxRows);
138
- const ttlMs = config.ttlMinutes * 60 * 1000;
139
- const displayName = `${query.Name} [page ${startRow}+${maxRows}]`;
140
-
141
- await this.LCM.SetRunQueryResult(
142
- fp, displayName, results,
143
- new Date().toISOString(), results.length, query.ID, ttlMs,
144
- );
145
- this._cacheTimestamps.set(fp, Date.now());
146
- this.RegisterEntityDependencies(fp, query);
147
- */
148
- }
149
- // ── Count cache ─────────────────────────────────────────────────────────
150
- /**
151
- * Retrieves a cached TotalRowCount for a query + params combination.
152
- */
153
- async GetTotalRowCount(query, params) {
154
- // BYPASSED — see class-level comment for rationale
155
- return null;
156
- /* When caching is enabled, uncomment the block below:
157
- if (!query.CacheConfig?.enabled) return null;
158
-
159
- const fp = this.CountFingerprint(query.ID, query.Name, params);
160
- const cached = await this.LCM.GetRunQueryResult(fp);
161
- if (!cached) return null;
162
-
163
- const row = cached.results[0] as { TotalRowCount: number } | undefined;
164
- return row?.TotalRowCount ?? null;
165
- */
166
- }
167
- /**
168
- * Stores a TotalRowCount value in the cache, encoded as a single-row result.
169
- */
170
- async SetTotalRowCount(query, params, count) {
171
- // BYPASSED — see class-level comment for rationale
172
- return;
173
- /* When caching is enabled, uncomment the block below:
174
- const config = query.CacheConfig;
175
- if (!config?.enabled) return;
176
-
177
- const fp = this.CountFingerprint(query.ID, query.Name, params);
178
- const ttlMs = config.ttlMinutes * 60 * 1000;
179
-
180
- await this.LCM.SetRunQueryResult(
181
- fp, `${query.Name} [count]`, [{ TotalRowCount: count }],
182
- new Date().toISOString(), 1, query.ID, ttlMs,
183
- );
184
- this._cacheTimestamps.set(fp, Date.now());
185
- */
186
- }
187
- // ── Ad-hoc cache ────────────────────────────────────────────────────────
188
- /**
189
- * Retrieves cached results for an ad-hoc SQL query.
190
- */
191
- async GetAdhoc(sql, ttlMinutes) {
192
- // BYPASSED — see class-level comment for rationale
193
- return null;
194
- /* When caching is enabled, uncomment the block below:
195
- if (ttlMinutes <= 0) return null;
196
-
197
- const fp = this.AdhocFingerprint(sql);
198
- const cached = await this.LCM.GetRunQueryResult(fp);
199
- return cached ? { results: cached.results } : null;
200
- */
201
- }
202
- /**
203
- * Stores ad-hoc SQL query results in the cache.
204
- */
205
- async SetAdhoc(sql, ttlMinutes, results) {
206
- // BYPASSED — see class-level comment for rationale
207
- return;
208
- /* When caching is enabled, uncomment the block below:
209
- if (ttlMinutes <= 0) return;
210
-
211
- const fp = this.AdhocFingerprint(sql);
212
- const ttlMs = ttlMinutes * 60 * 1000;
213
-
214
- await this.LCM.SetRunQueryResult(
215
- fp, 'Ad-Hoc Query', results,
216
- new Date().toISOString(), results.length, undefined, ttlMs,
217
- );
218
- this._cacheTimestamps.set(fp, Date.now());
219
- */
220
- }
221
- // ── Invalidation ────────────────────────────────────────────────────────
222
- /**
223
- * Invalidates all cache entries (full, paged, count) for a single query by name.
224
- */
225
- async InvalidateQuery(queryName) {
226
- // No-op while caching is bypassed, but safe to call unconditionally
227
- await this.LCM.InvalidateQueryCaches(queryName);
228
- }
229
- /**
230
- * Invalidates cache entries for a query and all queries that transitively depend on it.
231
- */
232
- async InvalidateWithDependents(query, visited = new Set()) {
233
- // No-op while caching is bypassed (nothing in cache to invalidate),
234
- // but the traversal logic is preserved for when caching is enabled.
235
- if (visited.has(query.ID))
236
- return;
237
- visited.add(query.ID);
238
- await this.LCM.InvalidateQueryCaches(query.Name);
239
- const dependents = query.Dependents;
240
- if (dependents && dependents.length > 0) {
241
- for (const dep of dependents) {
242
- const depQuery = this.FindQueryById(dep.QueryID);
243
- if (depQuery) {
244
- await this.InvalidateWithDependents(depQuery, visited);
245
- }
246
- }
247
- }
248
- }
249
- // ── Entity-change invalidation ──────────────────────────────────────────
250
- /**
251
- * Called when an entity changes (save/delete). Invalidates all query cache entries
252
- * that depend on the changed entity via QueryEntity mappings.
253
- *
254
- * While caching is bypassed the reverse index will always be empty, so this is
255
- * effectively a no-op. Kept wired up so enabling caching requires no caller changes.
256
- */
257
- async HandleEntityChange(entityName) {
258
- const normalized = entityName.trim().toLowerCase();
259
- const fingerprints = this._queryEntityIndex.get(normalized);
260
- if (!fingerprints || fingerprints.size === 0)
261
- return;
262
- const fpArray = [...fingerprints];
263
- for (const fp of fpArray) {
264
- await this.LCM.InvalidateRunQueryResult(fp);
265
- this._cacheTimestamps.delete(fp);
266
- }
267
- fingerprints.clear();
268
- LogStatus(`QueryCacheManager: invalidated ${fpArray.length} cache entries for entity "${entityName}"`);
269
- }
270
- // ── Entity dependency registration (private) ────────────────────────────
271
- RegisterEntityDependencies(fingerprint, query) {
272
- const entityNames = this.GetTransitiveEntityDependencies(query);
273
- for (const name of entityNames) {
274
- const normalized = name.trim().toLowerCase();
275
- if (!this._queryEntityIndex.has(normalized)) {
276
- this._queryEntityIndex.set(normalized, new Set());
277
- }
278
- this._queryEntityIndex.get(normalized).add(fingerprint);
279
- }
280
- }
281
- GetTransitiveEntityDependencies(query, visited = new Set()) {
282
- if (visited.has(query.ID))
283
- return [];
284
- visited.add(query.ID);
285
- const entities = [];
286
- // Direct entity mappings from QueryEntity table
287
- const queryEntities = query.Entities;
288
- if (queryEntities) {
289
- for (const qe of queryEntities) {
290
- if (qe.Entity) {
291
- entities.push(qe.Entity);
292
- }
293
- }
294
- }
295
- // Walk composition dependencies for transitive entity mappings
296
- const dependencies = query.Dependencies;
297
- if (dependencies) {
298
- for (const dep of dependencies) {
299
- const depQuery = this.FindQueryById(dep.DependsOnQueryID);
300
- if (depQuery) {
301
- entities.push(...this.GetTransitiveEntityDependencies(depQuery, visited));
302
- }
303
- }
304
- }
305
- return [...new Set(entities)];
306
- }
307
- // ── Helpers ─────────────────────────────────────────────────────────────
308
- FindQueryById(queryId) {
309
- return Metadata.Provider.Queries.find(// global-provider-ok: QueryCacheManager is a singleton tracking the global query catalog
310
- (q) => UUIDsEqual(q.ID, queryId));
311
- }
312
- computeTTLRemaining(fingerprint, ttlMinutes) {
313
- const cachedAt = this._cacheTimestamps.get(fingerprint) ?? 0;
314
- const ttlMs = ttlMinutes * 60 * 1000;
315
- return Math.max(0, (cachedAt + ttlMs) - Date.now());
316
- }
317
- /**
318
- * FNV-1a 32-bit hash — fast, deterministic, good distribution for cache keys.
319
- */
320
- static Fnv1aHash(input) {
321
- let hash = 0x811c9dc5; // FNV offset basis
322
- for (let i = 0; i < input.length; i++) {
323
- hash ^= input.charCodeAt(i);
324
- hash = (hash * 0x01000193) >>> 0; // FNV prime, keep as uint32
325
- }
326
- return hash.toString(16);
327
- }
328
- }
329
- //# sourceMappingURL=QueryCacheManager.js.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"QueryCacheManager.js","sourceRoot":"","sources":["../../src/generic/QueryCacheManager.ts"],"names":[],"mappings":"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"}