mrkeyoor.com_
Sat 08 Aug 22:51 UTC
npmUtilsupdated 08 Aug 2026

oblivious-set

oblivious-set is a tiny in-memory set whose entries stop matching after a fixed time-to-live. It stores each value with the time it was added, refreshes that time when the same value is added again, and removes expired entries lazily without keeping one timer per value. It is useful for short-lived duplicate suppression, but it is not a general cache: there are no stored values, size limits, eviction policies, persistence, or per-entry TTLs.

Verdict

A good fit for process-local recent-ID suppression when membership and one fixed TTL are all you need. Choose a bounded cache instead if stale storage, values, capacity limits, or precise expiration matter.

API stability4/5The public behavior is only construction with a TTL plus add, has, and clear, and the tests pin down lazy expiry and refresh-on-readd semantics. Version 2.0.0 did raise the Node floor to 16 and adjusted packaging in October 2025, so consumers should not treat major upgrades as automatically frictionless even though the operational API is small.
Docs2/5The README gives a correct install-and-use example and explains why cleanup avoids per-entry timers, but it does not document lazy retention, the exported cleanup helper, the public map, refresh behavior, capacity risk, CommonJS usage, or the exact expiration comparison. The implementation and unit tests are required reading for those important semantics.
Maintenance4/5Version 2.0.0 shipped in October 2025 with fixes and a Node update, and the repository was pushed again in February 2026. GitHub currently reports no open issues or pull requests. The caution is the contribution policy: issues are closed, and the README asks users who find a bug to submit a pull request with a reproducing test.
Ecosystem3/5npm recorded 3,109,217 downloads for the latest measured week, so the package is widely present in dependency graphs despite having only eight GitHub stars. It ships TypeScript declarations and both module formats, but there is no plugin ecosystem, framework integration layer, separate documentation site, or feature family around the core set.

Use it if

  • You need to remember recently seen IDs and answer only yes or no for a single fixed TTL
  • You want lazy expiration without creating a timeout or interval for every entry
  • You need the same small TypeScript-friendly utility in ESM and CommonJS code
  • You want a dependency-free building block and are comfortable with an intentionally tiny API
Skip it if

Setup reality

Installation is only `npm install oblivious-set`; version 2 has no runtime dependencies, includes declarations, exposes ESM and CommonJS builds, and requires Node 16 or newer. Construction takes one TTL in milliseconds, and that TTL applies to every entry. The important surprise is that expiration is lazy. Calling add schedules one zero-delay cleanup pass, while has removes the requested value if its stored timestamp is too old. There is no timer for the actual expiry deadline, so an entry can remain in the public map after its TTL until it is checked or a later add triggers cleanup. This normally does not affect has, which validates age before returning, but it means map.size is not a reliable count of live values. Re-adding a value refreshes its timestamp and moves it to the end of the internal insertion order. There is no supported delete method on the wrapper, no maximum capacity, no per-item TTL, and no callback when something expires. The map property and removeTooOldValues helper are exported, but using them ties application code to implementation details. The README also says GitHub issues are closed and asks bug reporters to send a pull request with a test case, which raises the support burden for consumers. Keep the instance process-local, choose a bounded TTL, and do not use it where expiry must trigger work at an exact time.

Patterns

Remember a value for a fixed TTLtrack-recent-value

import { ObliviousSet } from 'oblivious-set';

const recent = new ObliviousSet<string>(30_000);
recent.add('event-42');

console.log(recent.has('event-42')); // true

The constructor value is milliseconds and applies to every entry in this instance.

Suppress duplicate event IDssuppress-duplicates

const seen = new ObliviousSet<string>(5 * 60_000);

function acceptEvent(id: string): boolean {
  if (seen.has(id)) return false;
  seen.add(id);
  return true;
}

This is process-local and best-effort; separate processes have separate sets, and a restart forgets every ID.

Refresh an entry by adding it againrefresh-entry-ttl

const active = new ObliviousSet<string>(60_000);

active.add('session-a');
// Later activity resets the stored timestamp.
active.add('session-a');

Re-adding deletes and reinserts the map entry, which both refreshes its TTL and moves it to the newest position.

Clear all remembered valuesclear-all-entries

const recent = new ObliviousSet<string>(10_000);
recent.add('a');
recent.add('b');

recent.clear();
console.log(recent.has('a')); // false

clear removes all entries at once; the wrapper does not expose a supported method for deleting only one value.

Let has reject an expired valuecheck-after-expiry

const shortLived = new ObliviousSet<string>(100);
shortLived.add('token');

setTimeout(() => {
  console.log(shortLived.has('token')); // false
}, 150);

The entry is checked and deleted when has runs; no timer fires at the 100 ms expiry point.

Run the exported cleanup helperclean-expired-entries

import { ObliviousSet, removeTooOldValues } from 'oblivious-set';

const recent = new ObliviousSet<string>(1_000);
recent.add('job-1');

removeTooOldValues(recent);

Normal add calls already schedule this helper for the next tick. Calling it directly is mainly useful before inspecting the underlying map.

Clean before reading the internal sizeinspect-live-count

import { ObliviousSet, removeTooOldValues } from 'oblivious-set';

const recent = new ObliviousSet<string>(10_000);
recent.add('a');
recent.add('b');

removeTooOldValues(recent);
const approximateLiveCount = recent.map.size;

map is public, but it is an implementation detail and can include expired entries until cleanup runs. There is no official size getter.

Understand object identity membershipuse-object-identity

const recentObjects = new ObliviousSet<{ id: number }>(5_000);
const item = { id: 1 };
recentObjects.add(item);

console.log(recentObjects.has(item)); // true
console.log(recentObjects.has({ id: 1 })); // false

The internal Map compares objects by reference, not by their fields. Store a stable primitive ID when value equality is required.

Load the CommonJS builduse-commonjs

const { ObliviousSet } = require('oblivious-set');

const recent = new ObliviousSet(30_000);
recent.add('request-7');

Version 2 exports both ESM and CommonJS entry points, but requires Node 16 or newer.

Use separate sets for separate TTLsseparate-ttl-windows

const recentRequests = new ObliviousSet<string>(5_000);
const recentLogins = new ObliviousSet<string>(15 * 60_000);

recentRequests.add('request-1');
recentLogins.add('user-9');

TTL is configured per set, not per entry. Multiple windows require multiple instances.

Alternatives

PackageRegistryPick it when
lru-cachenpmUse it when entries have values and you need TTLs, a maximum size, disposal hooks, or LRU eviction
quick-lrunpmUse it for a compact key-value cache with a maximum size and optional expiration
mnemonistnpmUse it when you need a broader collection library with structures such as LRU caches, heaps, queues, and specialized sets