← Back to Changelog

2026-06-27

Release

Releasing 6 packages: [email protected] (minor), @cacheable/[email protected] (minor), @cacheable/[email protected] (minor), @cacheable/[email protected] (minor), [email protected] (patch), @cacheable/[email protected] (patch).

[email protected] — 2026-06-27

Add tag-based invalidation, per-store TTLs, and a shared static instance accessor.

Features

  • tag-based invalidation via CacheTags (639e42c, #1655)

    const cache = new Cacheable({ tags: true });
    await cache.set('page:/products', html, { tags: ['entity:42'] });
    await cache.tags.invalidateTag('entity:42');
    await cache.get('page:/products'); // undefined — detected stale and removed on read
    
  • support per-store TTL per operation on set, getOrSet, and wrap (2debaff, #1656)

    // expire faster in the in-memory primary than in the shared secondary
    await cache.set('key', 'value', { ttl: { primary: '10s', secondary: '5m' } });
    await cache.getOrSet('key', async () => 'value', { ttl: { primary: '10s', secondary: '5m' } });
    
  • support per-store TTL overrides from a BEFORE_SET hook (0be0680, #1657)

    cache.onHook(CacheableHooks.BEFORE_SET, (item) => {
      item.ttl = { primary: '10s', secondary: '1h' }; // different expirations per store
    });
    
  • add getStaticInstance shared singleton accessor (917bd83, #1665)

    const cache = Cacheable.getStaticInstance({ ttl: '1h' });
    await cache.set('key', 'value');
    // anywhere else, Cacheable.getStaticInstance() returns the same instance
    

Documentation

  • correct primary/secondary iteration guidance (9178ad2, #1659)

Contributors

  • @jaredwray (5)

Full List of Changes

  • feat(cacheable): tag-based invalidation via CacheTags by @jaredwray in #1655
  • cacheable - feat: support per-store TTL per operation by @jaredwray in #1656
  • docs(cacheable): correct primary/secondary iteration guidance by @jaredwray in #1659
  • feat(cacheable): support per-store TTL overrides via hooks by @jaredwray in #1657
  • feat(cacheable): add getStaticInstance shared singleton accessor by @jaredwray in #1665

Full diff: https://github.com/jaredwray/cacheable/compare/2026-05-27...2026-06-27


@cacheable/[email protected] — 2026-06-27

Add a getOrSet cache-aside helper, opt-in statistics, and strongly-typed hooks.

Features

  • add getOrSet cache-aside helper to CacheableMemory (13da777, #1661)

    const cache = new CacheableMemory();
    const getUser = () => ({ id: 1, name: 'Alice' });
    const a = cache.getOrSet('user:1', getUser, { ttl: '1h' }); // computes + stores
    const b = cache.getOrSet('user:1', getUser, { ttl: '1h' }); // served from cache
    
  • add opt-in statistics tracking via the shared Stats engine (4c82353, #1662)

    const cache = new CacheableMemory({ stats: true });
    cache.set('a', 1);
    cache.get('a'); cache.get('b');
    cache.stats.hits;    // 1
    cache.stats.misses;  // 1
    cache.stats.hitRate; // 0.5
    
  • add a strongly-typed onHook overload and exported hook payload types (92d2784, #1663)

    cache.onHook(CacheableMemoryHooks.BEFORE_SET, (item) => {
      // item typed as CacheableMemoryHookItem — value/ttl inferred
      item.value = transform(item.value);
    });
    

Contributors

  • @jaredwray (3)

Full List of Changes

  • feat(memory): add getOrSet cache-aside helper to CacheableMemory by @jaredwray in #1661
  • feat(memory): add statistics tracking via @cacheable/utils Stats by @jaredwray in #1662
  • feat(memory): strongly-typed onHook and hooks documentation by @jaredwray in #1663

Full diff: https://github.com/jaredwray/cacheable/compare/2026-05-27...2026-06-27


@cacheable/[email protected] — 2026-06-27

Add cached WHOIS and RDAP lookups; align fetch with native semantics.

Features

  • add WHOIS (TCP 43) and RDAP (HTTPS/JSON) lookups for domains, IPs, and ASNs (f61070e, #1658)

    import { whois, rdap } from '@cacheable/net';
    const result = await whois('example.com');
    result.fields;  // parsed WHOIS, e.g. { "Domain Name": "EXAMPLE.COM", ... }
    result.server;  // authoritative server that produced the data
    const rdapResult = await rdap('1.1.1.1'); // domains, IPs, and ASNs
    rdapResult.data; // parsed RDAP object
    

Bug Fixes

  • make fetch behave like native fetch (c5eb62c, #1652)

Documentation

  • expand README with full API, Features, and Table of Contents (268d910, #1666)

Contributors

  • @jaredwray (3)

Full List of Changes

  • fix(net): make fetch behave like native fetch by @jaredwray in #1652
  • feat(net): add WHOIS and RDAP lookups to @cacheable/net by @jaredwray in #1658
  • docs(net): expand @cacheable/net README with full API, Features, and Table of Contents by @jaredwray in #1666

Full diff: https://github.com/jaredwray/cacheable/compare/2026-05-27...2026-06-27


@cacheable/[email protected] — 2026-06-27

Add a CacheTags service, event-driven Stats, and per-store TTL / sync getOrSet helpers.

Features

  • add CacheTags (CacheTagService) for tag-based invalidation on any Keyv store (7df1236, #1646; 639e42c, #1655)

    import { CacheTags } from '@cacheable/utils';
    const tags = new CacheTags({ store: keyv, enabled: true });
    await tags.setKeyTags('user:1', ['team:42']);
    await tags.invalidateTag('team:42'); // constant-time: bumps a per-tag version counter
    await tags.isKeyFresh('user:1');     // false
    
  • make Stats event-driven and fully featured — hit/miss rates, per-key tracking, events (0fca255, #1653)

    import { Stats } from '@cacheable/utils';
    const stats = new Stats({ enabled: true });
    stats.trackKeys = true;
    stats.on('hits', (s) => console.log(s.hits));
    stats.incrementHits();
    stats.hitRate; // 1
    
  • expose Stats per-key data as a public read-only trackedKeys map (51f6cea, #1660)

    for (const [key, counters] of stats.trackedKeys) {
      console.log(key, counters.hits, counters.misses);
    }
    
  • add a synchronous getOrSetSync cache-aside helper (mirrors async getOrSet; powers CacheableMemory.getOrSet) (13da777, #1661)

  • add a PerStoreTtl type and resolvePerStoreTtl helper for per-store TTLs (2debaff, #1656)

Contributors

  • @jaredwray (6)
  • @cupofjoakim (1)

Full List of Changes

  • feat: Add CacheTagService to @cacheable/utils by @cupofjoakim in #1646 (first-time contributor)
  • feat(utils): make Stats event-driven and fully featured by @jaredwray in #1653
  • feat(cacheable): tag-based invalidation via CacheTags by @jaredwray in #1655
  • cacheable - feat: support per-store TTL per operation by @jaredwray in #1656
  • refactor(utils): expose Stats per-key data as public trackedKeys map by @jaredwray in #1660
  • feat(memory): add getOrSet cache-aside helper to CacheableMemory by @jaredwray in #1661
  • feat(memory): add statistics tracking via @cacheable/utils Stats by @jaredwray in #1662

Full diff: https://github.com/jaredwray/cacheable/compare/2026-05-27...2026-06-27


[email protected] — 2026-06-27

Restore v8 reconcile and change-detection semantics.

Bug Fixes

  • restore v8 reconcile and change-detection semantics — reconcile() no longer revalidates untouched entries, repeated getFileDescriptor() keeps reporting changed: true until reconcile, and corrupt cache files no longer throw (7d58420, #1649)

Contributors

  • @jaredwray (1)

Full List of Changes

  • fix(file-entry-cache): restore v8 reconcile and change-detection semantics by @jaredwray in #1649

Full diff: https://github.com/jaredwray/cacheable/compare/2026-05-27...2026-06-27


@cacheable/[email protected] — 2026-06-27

Fix metrics-accounting issues that caused inaccurate ksize/vsize reporting.

Bug Fixes

  • fix ksize/vsize inflation on overwrite, take() of falsy values, and value-size accounting for undefined on delete/expiry (ee73e5a, #1650)

Contributors

  • @jmjones88 (1)

Full List of Changes

  • fix(node-cache): Fixing issues with metrics reporting by @jmjones88 in #1650 (first-time contributor)

Full diff: https://github.com/jaredwray/cacheable/compare/2026-05-27...2026-06-27