npm package discovery and stats viewer.

Discover Tips

  • General search

    [free text search, go nuts!]

  • Package details

    pkg:[package-name]

  • User packages

    @[username]

Sponsor

Optimize Toolset

I’ve always been into building performant and accessible sites, but lately I’ve been taking it extremely seriously. So much so that I’ve been building a tool to help me optimize and monitor the sites that I build to make sure that I’m making an attempt to offer the best experience to those who visit them. If you’re into performant, accessible and SEO friendly sites, you might like it too! You can check it out at Optimize Toolset.

About

Hi, 👋, I’m Ryan Hefner  and I built this site for me, and you! The goal of this site was to provide an easy way for me to check the stats on my npm packages, both for prioritizing issues and updates, and to give me a little kick in the pants to keep up on stuff.

As I was building it, I realized that I was actually using the tool to build the tool, and figured I might as well put this out there and hopefully others will find it to be a fast and useful way to search and browse npm packages as I have.

If you’re interested in other things I’m working on, follow me on Twitter or check out the open source projects I’ve been publishing on GitHub.

I am also working on a Twitter bot for this site to tweet the most popular, newest, random packages from npm. Please follow that account now and it will start sending out packages soon–ish.

Open Software & Tools

This site wouldn’t be possible without the immense generosity and tireless efforts from the people who make contributions to the world and share their work via open source initiatives. Thank you 🙏

© 2026 – Pkg Stats / Ryan Hefner

@unrdf/caching

v26.4.8

Published

Multi-layer caching system for RDF queries with Redis and LRU

Readme

@unrdf/caching

Multi-layer caching system for RDF queries with high-performance distributed caching.

Features

  • 3-Tier Cache Architecture

    • L1: In-memory LRU (fastest, process-local)
    • L2: Redis distributed cache (shared across instances)
    • L3: Persistent RDF store (Oxigraph)
  • Intelligent Invalidation

    • Subject-based dependency tracking
    • Cascade invalidation
    • Graph-aware invalidation
    • Pattern-based invalidation
  • SPARQL Query Caching

    • Semantic cache key generation
    • Query result caching
    • Automatic dependency tracking
    • Configurable TTL

Installation

pnpm add @unrdf/caching

Quick Start

import { createCachingSystem } from '@unrdf/caching';
import { createStore } from '@unrdf/oxigraph';

// Create caching system
const store = createStore();
const caching = createCachingSystem({
  store,
  redisUrl: 'redis://localhost:6379',
  l1MaxSize: 1000,
  l2TtlSeconds: 300
});

// Execute cached SPARQL query
const results = await caching.sparqlCache.query(`
  SELECT * WHERE {
    ?s <http://example.org/name> ?o
  } LIMIT 100
`);

// Invalidate when data changes
await caching.tracker.invalidateSubject('http://example.org/resource1');

// Get statistics
const stats = caching.getStats();
console.log('Cache hit rate:', stats.sparql.hitRate);

Architecture

Multi-Layer Cache

import { MultiLayerCache } from '@unrdf/caching/layers';

const cache = new MultiLayerCache({
  store: createStore(),
  redisUrl: 'redis://localhost:6379',
  l1MaxSize: 1000,        // L1 cache max entries
  l1TtlMs: 60000,         // L1 TTL: 1 minute
  l2TtlSeconds: 300,      // L2 TTL: 5 minutes
  enableL2: true,         // Enable Redis
  keyPrefix: 'unrdf:cache:'
});

// Get with automatic L1 → L2 → L3 fallback
const value = await cache.get('key', async () => {
  // Fetcher called only on cache miss
  return expensiveOperation();
});

// Set in all layers
await cache.set('key', value, { ttl: 600 });

// Delete from all layers
await cache.delete('key');

// Pattern-based deletion
await cache.deletePattern('sparql:*');

// Statistics
const stats = cache.getStats();
console.log('L1 hit rate:', stats.l1HitRate);
console.log('L2 hit rate:', stats.l2HitRate);

Dependency Tracker

import { DependencyTracker } from '@unrdf/caching/invalidation';

const tracker = new DependencyTracker(cache);

// Track query dependencies
tracker.trackQuery('query1', [
  'http://example.org/resource1',
  'http://example.org/resource2'
], 'http://example.org/graph1');

// Invalidate all queries depending on a subject
await tracker.invalidateSubject('http://example.org/resource1');

// Invalidate all queries in a graph
await tracker.invalidateGraph('http://example.org/graph1');

// Pattern-based invalidation
await tracker.invalidatePattern('http://example.org/resource*');

// Get dependencies
const subjects = tracker.getQueryDependencies('query1');
const queries = tracker.getSubjectQueries('http://example.org/resource1');

SPARQL Cache

import { SparqlCache } from '@unrdf/caching/query';

const sparqlCache = new SparqlCache({
  store: createStore(),
  cache: multiLayerCache,
  tracker: dependencyTracker,
  enableNormalization: true,      // Normalize queries for consistent keys
  enableDependencyTracking: true, // Automatic dependency tracking
  defaultTtl: 300                 // 5 minutes
});

// Execute cached query
const results = await sparqlCache.query(`
  SELECT ?s ?o WHERE {
    ?s <http://example.org/name> ?o
  }
`);

// Query without cache
const fresh = await sparqlCache.query(query, { useCache: false });

// Custom TTL
const cached = await sparqlCache.query(query, { ttl: 600 });

// Invalidate specific query
await sparqlCache.invalidate(query);

// Pre-warm cache
await sparqlCache.prewarm([
  'SELECT * WHERE { ?s ?p ?o } LIMIT 100',
  'ASK { ?s <http://example.org/name> "test" }'
]);

// Statistics
const stats = sparqlCache.getStats();
console.log('Hit rate:', stats.hitRate);
console.log('Avg result size:', stats.avgResultSize);

Performance Benchmarks

Run the benchmark demo:

pnpm run demo

Expected Results

| Metric | Without Cache | With Cache (Warm) | Speedup | |--------|--------------|-------------------|---------| | 100 queries | ~150ms | ~10ms | 15x | | Hit rate | N/A | >95% | - | | Avg query time | 1.5ms | 0.1ms | 15x |

Performance increases dramatically with:

  • Complex SPARQL queries (joins, aggregations)
  • Larger datasets (>100K triples)
  • Distributed workloads (Redis L2 cache)

Real-World Performance

On production workloads:

  • Simple queries: 10-20x speedup
  • Complex joins: 50-100x speedup
  • Aggregations: 100-500x speedup

Configuration

Cache Configuration

{
  store: OxigraphStore;           // Required: RDF store instance
  redisUrl?: string;              // Redis connection (default: localhost:6379)
  l1MaxSize?: number;             // L1 max entries (default: 1000)
  l1TtlMs?: number;               // L1 TTL milliseconds (default: 60000)
  l2TtlSeconds?: number;          // L2 TTL seconds (default: 300)
  enableL2?: boolean;             // Enable Redis (default: true)
  keyPrefix?: string;             // Redis key prefix (default: 'unrdf:cache:')
}

Tracker Configuration

{
  cache: MultiLayerCache;         // Required: Cache instance
  enableGraphTracking?: boolean;  // Track graph dependencies (default: true)
  maxDependencies?: number;       // Max tracked dependencies (default: 10000)
}

SPARQL Cache Configuration

{
  store: OxigraphStore;           // Required: RDF store
  cache: MultiLayerCache;         // Required: Cache instance
  tracker?: DependencyTracker;    // Optional: Dependency tracker
  enableNormalization?: boolean;  // Normalize queries (default: true)
  enableDependencyTracking?: boolean; // Track dependencies (default: true)
  defaultTtl?: number;            // Default TTL seconds (default: 300)
  maxCachedResults?: number;      // Max cached results (default: 10000)
}

Integration Patterns

With YAWL Store

import { createYawlStore } from '@unrdf/yawl/store';
import { createCachingSystem } from '@unrdf/caching';

const store = createYawlStore();
const caching = createCachingSystem({ store });

// Cached SPARQL queries
const workItems = await caching.sparqlCache.query(`
  SELECT ?workItem ?status WHERE {
    GRAPH <http://yawl.org/case#case-123/graph> {
      ?workItem a yawl:WorkItem ;
                yawl:status ?status .
    }
  }
`);

// Invalidate when case updates
await caching.tracker.invalidateGraph('http://yawl.org/case#case-123/graph');

With Event-Driven Invalidation

// On data change event
store.on('quad:added', async (quad) => {
  const subject = quad.subject.value;
  await caching.tracker.invalidateSubject(subject);
});

store.on('graph:cleared', async (graph) => {
  await caching.tracker.invalidateGraph(graph.value);
});

API Reference

MultiLayerCache

  • get(key, fetcher?) - Get value with L1 → L2 → L3 fallback
  • set(key, value, options?) - Set value in all layers
  • delete(key) - Delete from all layers
  • deletePattern(pattern) - Delete matching keys
  • clear() - Clear all caches
  • getStats() - Get cache statistics
  • resetStats() - Reset statistics
  • close() - Close connections

DependencyTracker

  • trackQuery(key, subjects, graph?) - Track query dependencies
  • invalidateSubject(subject) - Invalidate by subject
  • invalidateGraph(graph) - Invalidate by graph
  • invalidatePattern(pattern) - Invalidate by pattern
  • invalidateSubjects(subjects) - Invalidate multiple subjects
  • getQueryDependencies(key) - Get query's subjects
  • getSubjectQueries(subject) - Get queries for subject
  • getGraphSubjects(graph) - Get subjects in graph
  • getStats() - Get tracker statistics
  • clear() - Clear all tracking

SparqlCache

  • query(query, options?) - Execute cached SPARQL query
  • invalidate(query) - Invalidate cached query
  • invalidatePattern(pattern) - Invalidate by pattern
  • prewarm(queries) - Pre-warm cache
  • getStats() - Get query statistics
  • resetStats() - Reset statistics
  • clear() - Clear all cached queries

License

MIT

Author

UNRDF Project