feat: sorted sets, dual ESM/CJS build, sweepDelay; drop defaultTtl#1
Merged
Conversation
Switch the build pipeline from raw tsc to tsup. tsup emits both dist/index.js (ESM) and dist/index.cjs (CommonJS) plus a .d.ts/.d.cts type pair from a single source. Updates the package.json exports map so consumers get the right format whether they import or require, keeps TypeScript handling the test-side typecheck. The named-cache registry (Symbol.for on globalThis) still works across both copies if a process happens to load suncache as both ESM and CJS — the symbol identity is preserved. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Adds Redis-style sorted-set methods on Cache (zadd/zrem/zscore/zrange/ zrevrange/zrangebyscore/zincrby/zcard) and the supporting infrastructure for storing multiple value kinds in one cache instance: - Internal SortedSet (Map<member, score> + sorted array, binary search) - Tagged-union Entry<T> = ValueEntry<T> | ZSetEntry - WrongTypeError thrown on cross-kind access (e.g. get() on a zset key, zadd() on a string key). Mirrors a Redis WRONGTYPE response, including the structured key/has/wanted properties for catch blocks. - Empty zsets are auto-deleted on the last zrem() so has()/keys() stay honest. Three private helpers consolidate duplication that grew with the new kind handling: - getLiveEntry(key) — fetch + lazy-sweep expired entries - lruBump(key, e) — re-insert in Map order to mark MRU - assertKind(e, k, w) — TS assertion function, throws WrongTypeError on mismatch and narrows the union for callers Adds the sweepDelay option (default 1000ms): the single sweep timer now fires sweepDelay ms after the soonest pending expiry, so neighbors that fall in the window are pruned in the same pass. Pass 0 to disable coalescing. get()/has()/mget()/keys() and zset reads still observe expiry immediately via lazy cleanup, regardless of sweepDelay. BREAKING CHANGE: defaultTtl was removed. The option only applied to set() and surprised users when incr/zadd ignored it. TTL is now strictly per-call via SetOptions.ttl. Callers who relied on a global default can wrap set() in a project-local helper. Other fixes folded in: - getOrCompute no longer treats a cached undefined as a miss - zrangebyscore validates NaN (still accepts +/-Infinity for open ranges) - incr uses getLiveEntry + assertKind (no ValueEntry<number> cast) Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Reflects the new feature surface and aligns with the sibling project's conventions: - npm/license/types/zero-deps badges - Multi-package-manager install (npm/pnpm/yarn/bun) and dual-format import/require example - Richer intro showing named caches, getOrCompute, counters+TTL refresh, and sorted sets in one block - Sorted set Usage section with a leaderboard example - New 'Sorted set API' top-level section (h2 parallel to API) so the zset methods aren't visually nested as peers of their own introducer - Big-O notation on every API method, plus a brief note on when the O(n) zset writes become a problem - Errors section explaining WrongTypeError with an instanceof catch - 'How expiry works' updated to cover sweepDelay coalescing - Each method now has at least one focused example for consistency - Removed product-name mentions (Redis, specific dev tools) from prose - Dropped the empty-zset gotcha (now auto-deleted in code) Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
Cache(Redis-style):zadd/zrem/zscore/zrange/zrevrange/zrangebyscore/zincrby/zcard, backed by an internalSortedSet(Map + sorted array, binary search).WrongTypeErroron cross-kind access (withkey/has/wantedproperties for branching). Auto-deletes empty zsets on the lastzrem.sweepDelayoption (default1000ms): the single sweep timer firessweepDelayms past the soonest expiry so neighbors coalesce into one pass.get/has/mget/keysand zset reads still observe expiry immediately via lazy cleanup.getLiveEntry,lruBump,assertKind(TS assertion function).tsup. SameSymbol.for("suncache.registry")keeps the named-cache registry shared across both copies.WrongTypeErrorexample.Breaking
defaultTtlremoved. It only applied toset()and silently surprised users whenincr/zaddignored it. TTL is now strictly per-call viaSetOptions.ttl.Other fixes (from code review)
getOrComputeno longer treats a cachedundefinedas a miss.zrangebyscorevalidatesNaN(still accepts±Infinity).incrusesgetLiveEntry+assertKindinstead of anas ValueEntry<number>cast.