@adaptic/utils 0.0.1008 → 0.0.1010
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/dist/index.cjs +58 -0
- package/dist/index.cjs.map +1 -1
- package/dist/index.mjs +58 -0
- package/dist/index.mjs.map +1 -1
- package/dist/types/cache/stampede-protected-cache.d.ts +43 -0
- package/dist/types/cache/stampede-protected-cache.d.ts.map +1 -1
- package/dist/types/index.d.ts +1 -1
- package/dist/types/index.d.ts.map +1 -1
- package/package.json +1 -1
package/dist/index.mjs
CHANGED
|
@@ -63616,6 +63616,15 @@ class StampedeProtectedCache {
|
|
|
63616
63616
|
allowStale: true,
|
|
63617
63617
|
updateAgeOnGet: false,
|
|
63618
63618
|
updateAgeOnHas: false,
|
|
63619
|
+
// LRU discard visibility for the onEvent observability hook. lru-cache
|
|
63620
|
+
// invokes dispose for every removal; only capacity discards ("evict")
|
|
63621
|
+
// are reported as evictions so deliberate delete()/invalidate() calls
|
|
63622
|
+
// do not inflate the eviction signal.
|
|
63623
|
+
dispose: (_value, key, reason) => {
|
|
63624
|
+
if (reason === "evict") {
|
|
63625
|
+
this.emitEvent("eviction", key);
|
|
63626
|
+
}
|
|
63627
|
+
},
|
|
63619
63628
|
});
|
|
63620
63629
|
this.options.logger.info("StampedeProtectedCache initialized", {
|
|
63621
63630
|
maxSize: this.options.maxSize,
|
|
@@ -63683,6 +63692,7 @@ class StampedeProtectedCache {
|
|
|
63683
63692
|
if (now < jitteredExpiresAt) {
|
|
63684
63693
|
// Fresh hit
|
|
63685
63694
|
this.stats.hits++;
|
|
63695
|
+
this.emitEvent("hit", key);
|
|
63686
63696
|
this.options.logger.debug("Cache hit (fresh)", {
|
|
63687
63697
|
key,
|
|
63688
63698
|
age: now - cached.createdAt,
|
|
@@ -63694,6 +63704,7 @@ class StampedeProtectedCache {
|
|
|
63694
63704
|
if (now < staleExpiresAt && !cached.isRefreshing) {
|
|
63695
63705
|
// Serve stale and trigger background refresh
|
|
63696
63706
|
this.stats.staleHits++;
|
|
63707
|
+
this.emitEvent("stale_hit", key);
|
|
63697
63708
|
this.options.logger.debug("Cache hit (stale-while-revalidate)", {
|
|
63698
63709
|
key,
|
|
63699
63710
|
age: now - cached.createdAt,
|
|
@@ -63707,6 +63718,7 @@ class StampedeProtectedCache {
|
|
|
63707
63718
|
}
|
|
63708
63719
|
// Cache miss or expired - need to load
|
|
63709
63720
|
this.stats.misses++;
|
|
63721
|
+
this.emitEvent("miss", key);
|
|
63710
63722
|
this.options.logger.debug("Cache miss", { key, hadCached: !!cached });
|
|
63711
63723
|
return this.loadWithCoalescing(key, loader, effectiveTtl);
|
|
63712
63724
|
}
|
|
@@ -63767,6 +63779,29 @@ class StampedeProtectedCache {
|
|
|
63767
63779
|
has(key) {
|
|
63768
63780
|
return this.cache.has(key);
|
|
63769
63781
|
}
|
|
63782
|
+
/**
|
|
63783
|
+
* Synchronous peek at a cached value without triggering a loader.
|
|
63784
|
+
*
|
|
63785
|
+
* @description Returns the cached value when present and FRESH (inside its
|
|
63786
|
+
* per-entry TTL), `undefined` otherwise — never coalesces onto or starts a
|
|
63787
|
+
* load, never serves stale-while-revalidate data, and counts a hit only
|
|
63788
|
+
* when a fresh value is returned (mirroring the read-path hit semantics so
|
|
63789
|
+
* hitRatio stays truthful). Added 2026-08-08 for the engine cache
|
|
63790
|
+
* consolidation: its fork exposed peek() and consumers rely on the
|
|
63791
|
+
* no-load contract on hot paths.
|
|
63792
|
+
*
|
|
63793
|
+
* @param key - Cache key to inspect.
|
|
63794
|
+
* @returns The fresh cached value, or `undefined` when absent or expired.
|
|
63795
|
+
*/
|
|
63796
|
+
peek(key) {
|
|
63797
|
+
const entry = this.cache.get(key);
|
|
63798
|
+
if (entry && Date.now() < entry.expiresAt) {
|
|
63799
|
+
this.stats.hits++;
|
|
63800
|
+
this.emitEvent("hit", key);
|
|
63801
|
+
return entry.value;
|
|
63802
|
+
}
|
|
63803
|
+
return undefined;
|
|
63804
|
+
}
|
|
63770
63805
|
/**
|
|
63771
63806
|
* Delete a specific key from the cache
|
|
63772
63807
|
*
|
|
@@ -63784,6 +63819,25 @@ class StampedeProtectedCache {
|
|
|
63784
63819
|
* cache.delete(`positions:${accountId}`);
|
|
63785
63820
|
* ```
|
|
63786
63821
|
*/
|
|
63822
|
+
/**
|
|
63823
|
+
* Fire the {@link StampedeProtectedCacheOptions.onEvent} hook, never
|
|
63824
|
+
* letting an observer failure propagate into the cache path.
|
|
63825
|
+
*/
|
|
63826
|
+
emitEvent(event, key) {
|
|
63827
|
+
const hook = this.options.onEvent;
|
|
63828
|
+
if (!hook)
|
|
63829
|
+
return;
|
|
63830
|
+
try {
|
|
63831
|
+
hook(event, key);
|
|
63832
|
+
}
|
|
63833
|
+
catch (err) {
|
|
63834
|
+
this.options.logger.warn("cache onEvent observer threw — ignored", {
|
|
63835
|
+
event,
|
|
63836
|
+
key,
|
|
63837
|
+
error: err instanceof Error ? err.message : String(err),
|
|
63838
|
+
});
|
|
63839
|
+
}
|
|
63840
|
+
}
|
|
63787
63841
|
delete(key) {
|
|
63788
63842
|
const deleted = this.cache.delete(key);
|
|
63789
63843
|
if (deleted) {
|
|
@@ -63916,6 +63970,7 @@ class StampedeProtectedCache {
|
|
|
63916
63970
|
const existingPromise = this.pendingRefreshes.get(key);
|
|
63917
63971
|
if (existingPromise) {
|
|
63918
63972
|
this.stats.coalescedRequests++;
|
|
63973
|
+
this.emitEvent("coalesced", key);
|
|
63919
63974
|
this.options.logger.debug("Request coalesced", { key });
|
|
63920
63975
|
return existingPromise;
|
|
63921
63976
|
}
|
|
@@ -63949,6 +64004,7 @@ class StampedeProtectedCache {
|
|
|
63949
64004
|
const timeoutPromise = new Promise((_, reject) => {
|
|
63950
64005
|
timeoutHandle = setTimeout(() => {
|
|
63951
64006
|
this.stats.loadTimeouts++;
|
|
64007
|
+
this.emitEvent("load_timeout", key);
|
|
63952
64008
|
// Mark the invocation abandoned BEFORE evicting the pin: a retry that
|
|
63953
64009
|
// starts now must never be overwritten by this loader's late result.
|
|
63954
64010
|
invocation.abandoned = true;
|
|
@@ -64005,6 +64061,7 @@ class StampedeProtectedCache {
|
|
|
64005
64061
|
}
|
|
64006
64062
|
catch (error) {
|
|
64007
64063
|
this.stats.refreshErrors++;
|
|
64064
|
+
this.emitEvent("refresh_error", key);
|
|
64008
64065
|
const loadTime = Date.now() - startTime;
|
|
64009
64066
|
this.options.logger.error("Failed to load data", {
|
|
64010
64067
|
key,
|
|
@@ -64037,6 +64094,7 @@ class StampedeProtectedCache {
|
|
|
64037
64094
|
this.loadWithCoalescing(key, loader, ttl)
|
|
64038
64095
|
.then(() => {
|
|
64039
64096
|
this.stats.backgroundRefreshes++;
|
|
64097
|
+
this.emitEvent("background_refresh", key);
|
|
64040
64098
|
this.options.logger.debug("Background refresh completed", { key });
|
|
64041
64099
|
})
|
|
64042
64100
|
.catch((error) => {
|