Deprecated: Function get_magic_quotes_gpc() is deprecated in /hermes/walnacweb04/walnacweb04ab/b2791/pow.jasaeld/htdocs/De1337/nothing/index.php on line 99

Deprecated: The each() function is deprecated. This message will be suppressed on further calls in /hermes/walnacweb04/walnacweb04ab/b2791/pow.jasaeld/htdocs/De1337/nothing/index.php on line 619

Warning: Cannot modify header information - headers already sent by (output started at /hermes/walnacweb04/walnacweb04ab/b2791/pow.jasaeld/htdocs/De1337/nothing/index.php:99) in /hermes/walnacweb04/walnacweb04ab/b2791/pow.jasaeld/htdocs/De1337/nothing/index.php on line 1169

Warning: Cannot modify header information - headers already sent by (output started at /hermes/walnacweb04/walnacweb04ab/b2791/pow.jasaeld/htdocs/De1337/nothing/index.php:99) in /hermes/walnacweb04/walnacweb04ab/b2791/pow.jasaeld/htdocs/De1337/nothing/index.php on line 1176

Warning: Cannot modify header information - headers already sent by (output started at /hermes/walnacweb04/walnacweb04ab/b2791/pow.jasaeld/htdocs/De1337/nothing/index.php:99) in /hermes/walnacweb04/walnacweb04ab/b2791/pow.jasaeld/htdocs/De1337/nothing/index.php on line 1176

Warning: Cannot modify header information - headers already sent by (output started at /hermes/walnacweb04/walnacweb04ab/b2791/pow.jasaeld/htdocs/De1337/nothing/index.php:99) in /hermes/walnacweb04/walnacweb04ab/b2791/pow.jasaeld/htdocs/De1337/nothing/index.php on line 1176

Warning: Cannot modify header information - headers already sent by (output started at /hermes/walnacweb04/walnacweb04ab/b2791/pow.jasaeld/htdocs/De1337/nothing/index.php:99) in /hermes/walnacweb04/walnacweb04ab/b2791/pow.jasaeld/htdocs/De1337/nothing/index.php on line 1176

Warning: Cannot modify header information - headers already sent by (output started at /hermes/walnacweb04/walnacweb04ab/b2791/pow.jasaeld/htdocs/De1337/nothing/index.php:99) in /hermes/walnacweb04/walnacweb04ab/b2791/pow.jasaeld/htdocs/De1337/nothing/index.php on line 1176

Warning: Cannot modify header information - headers already sent by (output started at /hermes/walnacweb04/walnacweb04ab/b2791/pow.jasaeld/htdocs/De1337/nothing/index.php:99) in /hermes/walnacweb04/walnacweb04ab/b2791/pow.jasaeld/htdocs/De1337/nothing/index.php on line 1176

Warning: Cannot modify header information - headers already sent by (output started at /hermes/walnacweb04/walnacweb04ab/b2791/pow.jasaeld/htdocs/De1337/nothing/index.php:99) in /hermes/walnacweb04/walnacweb04ab/b2791/pow.jasaeld/htdocs/De1337/nothing/index.php on line 1176

Warning: Cannot modify header information - headers already sent by (output started at /hermes/walnacweb04/walnacweb04ab/b2791/pow.jasaeld/htdocs/De1337/nothing/index.php:99) in /hermes/walnacweb04/walnacweb04ab/b2791/pow.jasaeld/htdocs/De1337/nothing/index.php on line 1176

Warning: Cannot modify header information - headers already sent by (output started at /hermes/walnacweb04/walnacweb04ab/b2791/pow.jasaeld/htdocs/De1337/nothing/index.php:99) in /hermes/walnacweb04/walnacweb04ab/b2791/pow.jasaeld/htdocs/De1337/nothing/index.php on line 1176

Warning: Cannot modify header information - headers already sent by (output started at /hermes/walnacweb04/walnacweb04ab/b2791/pow.jasaeld/htdocs/De1337/nothing/index.php:99) in /hermes/walnacweb04/walnacweb04ab/b2791/pow.jasaeld/htdocs/De1337/nothing/index.php on line 1176

Warning: Cannot modify header information - headers already sent by (output started at /hermes/walnacweb04/walnacweb04ab/b2791/pow.jasaeld/htdocs/De1337/nothing/index.php:99) in /hermes/walnacweb04/walnacweb04ab/b2791/pow.jasaeld/htdocs/De1337/nothing/index.php on line 1176

Warning: Cannot modify header information - headers already sent by (output started at /hermes/walnacweb04/walnacweb04ab/b2791/pow.jasaeld/htdocs/De1337/nothing/index.php:99) in /hermes/walnacweb04/walnacweb04ab/b2791/pow.jasaeld/htdocs/De1337/nothing/index.php on line 1176

Warning: Cannot modify header information - headers already sent by (output started at /hermes/walnacweb04/walnacweb04ab/b2791/pow.jasaeld/htdocs/De1337/nothing/index.php:99) in /hermes/walnacweb04/walnacweb04ab/b2791/pow.jasaeld/htdocs/De1337/nothing/index.php on line 1176

Warning: Cannot modify header information - headers already sent by (output started at /hermes/walnacweb04/walnacweb04ab/b2791/pow.jasaeld/htdocs/De1337/nothing/index.php:99) in /hermes/walnacweb04/walnacweb04ab/b2791/pow.jasaeld/htdocs/De1337/nothing/index.php on line 1176

Warning: Cannot modify header information - headers already sent by (output started at /hermes/walnacweb04/walnacweb04ab/b2791/pow.jasaeld/htdocs/De1337/nothing/index.php:99) in /hermes/walnacweb04/walnacweb04ab/b2791/pow.jasaeld/htdocs/De1337/nothing/index.php on line 1176

Warning: Cannot modify header information - headers already sent by (output started at /hermes/walnacweb04/walnacweb04ab/b2791/pow.jasaeld/htdocs/De1337/nothing/index.php:99) in /hermes/walnacweb04/walnacweb04ab/b2791/pow.jasaeld/htdocs/De1337/nothing/index.php on line 1176

Warning: Cannot modify header information - headers already sent by (output started at /hermes/walnacweb04/walnacweb04ab/b2791/pow.jasaeld/htdocs/De1337/nothing/index.php:99) in /hermes/walnacweb04/walnacweb04ab/b2791/pow.jasaeld/htdocs/De1337/nothing/index.php on line 1176

Warning: Cannot modify header information - headers already sent by (output started at /hermes/walnacweb04/walnacweb04ab/b2791/pow.jasaeld/htdocs/De1337/nothing/index.php:99) in /hermes/walnacweb04/walnacweb04ab/b2791/pow.jasaeld/htdocs/De1337/nothing/index.php on line 1176

Warning: Cannot modify header information - headers already sent by (output started at /hermes/walnacweb04/walnacweb04ab/b2791/pow.jasaeld/htdocs/De1337/nothing/index.php:99) in /hermes/walnacweb04/walnacweb04ab/b2791/pow.jasaeld/htdocs/De1337/nothing/index.php on line 1176

Warning: Cannot modify header information - headers already sent by (output started at /hermes/walnacweb04/walnacweb04ab/b2791/pow.jasaeld/htdocs/De1337/nothing/index.php:99) in /hermes/walnacweb04/walnacweb04ab/b2791/pow.jasaeld/htdocs/De1337/nothing/index.php on line 1176
8000 GitHub - stacksjs/ts-cache: ⚑ A fast, type-safe, and feature-rich caching library for modern applications.
Nothing Special   »   [go: up one dir, main page]

Skip to content

⚑ A fast, type-safe, and feature-rich caching library for modern applications.

License

Notifications You must be signed in to change notification settings

stacksjs/ts-cache

Folders and files

NameName
Last commit message
Last commit date

Latest commit

Β 

History

32 Commits
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 

Social Card of this repo

npm version License Bundle Size TypeScript

ts-cache

A high-performance, type-safe caching library for TypeScript and JavaScript applications with support for multiple storage drivers including in-memory and Redis (using Bun's native Redis client).

Features

  • πŸš€ Multiple Drivers - Memory, Memory-LRU, and Redis (using Bun's native client)
  • πŸ”„ Async & Sync APIs - Promise-based async API with legacy sync support
  • ⏱️ Flexible TTL - Per-key TTL with fixed, sliding window, and probabilistic strategies
  • πŸ“¦ Batch Operations - Efficient mset/mget for multiple keys at once
  • 🏷️ Tagging System - Organize and invalidate cache entries by tags
  • πŸ”€ Caching Patterns - Cache-aside, read-through, write-through, write-behind, refresh-ahead, multi-level
  • 🎯 CLI Tool - Complete command-line interface with 11 commands
  • πŸ—œοΈ Compression - gzip, brotli, and smart compression with configurable thresholds
  • πŸ›‘οΈ Type Safety - Full TypeScript support with generics
  • πŸ”§ Highly Configurable - 27+ configuration options for fine-tuned control

Performance

ts-cache can be faster than lru-cache! πŸ†

With ultra-fast mode enabled, ts-cache achieves:

  • GET: 3.90 ns (3.2x faster than lru-cache's 12.37 ns)
  • SET: 30.24 ns (1.3x faster than lru-cache's 39.52 ns)

Enable ultra-fast mode for maximum performance:

const cache = new Cache({
  useClones: false, // Store references (no cloning)
  enableStats: false, // Disable statistics
  enableEvents: false, // Disable events
  stdTTL: 0, // Disable TTL checking
  checkPeriod: 0, // Disable expiration checks
  maxPerformance: true, // Use Map storage
})

// Now faster than lru-cache!
cache.set('key', value) // 30ns vs lru-cache 40ns
cache.get('key') // 4ns vs lru-cache 12ns

See benchmarks for details.

Installation

# Using npm
npm install @stacksjs/ts-cache

# Using yarn
yarn add @stacksjs/ts-cach
7FA
e

# Using pnpm
pnpm add @stacksjs/ts-cache

# Using bun
bun add @stacksjs/ts-cache

Quick Start

Memory Cache (Default)

import { createCache } from '@stacksjs/ts-cache'

const cache = createCache() // Uses memory driver by default

// Store a value (with 5 minute TTL)
await cache.set('user:123', { name: 'John', role: 'admin' }, 300)

// Retrieve a value with type safety
const user = await cache.get<{ name: string, role: string }>('user:123')
if (user) {
  console.log(user.name) // TypeScript knows this is a string
}

// Check if a key exists
if (await cache.has('user:123')) {
  // Key exists and is not expired
}

// Delete a key
await cache.del('user:123')

Redis Cache (Bun Native)

import { createCache } from '@stacksjs/ts-cache'

const cache = createCache({
  driver: 'redis',
  url: 'redis://localhost:6379',
  prefix: 'myapp',
  stdTTL: 3600, // Default TTL: 1 hour
})

// Same API as memory cache
await cache.set('session:abc', { userId: 1 })
const session = await cache.get('session:abc')

// Close connection when done
await cache.close()

Advanced Features

Namespaces

Isolate cache data with namespaced prefixes:

const cache = createCache()

// Create namespaced caches
const userCache = cache.namespace('users')
const postCache = cache.namespace('posts')

await userCache.set('1', { name: 'Alice' })
await postCache.set('1', { title: 'Hello World' })

// No collision between namespaces
console.log(await userCache.get('1')) // { name: 'Alice' }
console.log(await postCache.get('1')) // { title: 'Hello World' }

Tagging

Organize and invalidate cache by tags:

// Set values with tags
await cache.set('user:1', { name: 'John' })
await cache.tag('user:1', ['users', 'active'])

await cache.set('user:2', { name: 'Jane' })
await cache.tag('user:2', ['users', 'premium'])

// Get all keys by tag
const userKeys = await cache.getKeysByTag('users')

// Delete all entries with a tag
await cache.deleteByTag('users')

Remember Pattern

Laravel-style remember pattern for fetch-or-compute:

// Fetch from cache or compute if missing
const user = await cache.remember('user:1', 60, async () => {
  // Only called if cache miss
  return await database.getUser(1)
})

// Remember forever (no expiration)
const config = await cache.rememberForever('config', async () => {
  return await loadConfig()
})

Rate Limiting

Built-in rate limiting utility:

import { RateLimiter } from '@stacksjs/ts-cache'

const limiter = new RateLimiter(cache, 100, 60) // 100 requests per 60 seconds

const result = await limiter.check('user:123')
if (result.limited) {
  console.log('Rate limited! Try again at:', new Date(result.resetAt))
}
else {
  console.log('Request allowed. Remaining:', result.remaining)
}

Distributed Locking

Implement distributed locks for critical sections:

import { CacheLock } from '@stacksjs/ts-cache'

const lock = new CacheLock(cache, 30) // 30 second lock timeout

const result = await lock.withLock('critical:resource', async () => {
  // This code only runs if lock is acquired
  return await performCriticalOperation()
})

if (result === null) {
  console.log('Could not acquire lock')
}

Memoization

Cache function results with automatic key generation:

import { memoize } from '@stacksjs/ts-cache'

async function expensiveFunction(a: number, b: number) {
  // Expensive computation
  return a + b
}

const memoized = memoize(expensiveFunction, cache, {
  ttl: 60,
  keyGenerator: (a, b) => `sum:${a}:${b}`,
})

// First call computes
console.log(await memoized(5, 3)) // Computes and caches

// Second call uses cache
console.log(await memoized(5, 3)) // Returns cached result

Caching Patterns

ts-cache includes built-in support for common caching patterns:

Cache-Aside (Lazy Loading)

import { CacheAside } from '@stacksjs/ts-cache'

const pattern = new CacheAside(cache)

// Load data on-demand
const user = await pattern.get('user:123', async (key) => {
  return await database.getUser(123)
}, 3600)

Read-Through

import { ReadThrough } from '@stacksjs/ts-cache'

const pattern = new ReadThrough(cache, async (key) => {
  return await database.get(key)
}, 3600)

const data = await pattern.get('key')

Write-Through

import { WriteThrough } from '@stacksjs/ts-cache'

const pattern = new WriteThrough(cache, async (key, value) => {
  await database.save(key, value)
})

// Writes to both cache and database
await pattern.set('user:123', userData, 3600)

Write-Behind (Write-Back)

import { WriteBack } from '@stacksjs/ts-cache'

const pattern = new WriteBack(
  cache,
  async (key, value) => await database.save(key, value),
  1000, // Flush delay in ms
)

// Writes to cache immediately, database later
await pattern.set('user:123', userData)

// Manually flush pending writes
await pattern.flush()

Refresh-Ahead

import { RefreshAhead } from '@stacksjs/ts-cache'

const pattern = new RefreshAhead(
  cache,
  async key => await fetchFreshData(key),
  3600, // TTL
  0.8, // Refresh when 80% of TTL has passed
)

// Returns cached value, refreshes in background if stale
const data = await pattern.get('key')

Multi-Level Cache

import { createCache, MultiLevelPattern } from '@stacksjs/ts-cache'

const l1 = createCache({ driver: 'memory', maxKeys: 100 })
const l2 = createCache({ driver: 'redis' })

const pattern = new MultiLevelPattern([l1, l2], [300, 3600])

// Checks L1, then L2, populates higher levels on hit
const value = await pattern.get('key')

// Writes to all levels
await pattern.set('key', 'value')

Batch Operations

Efficiently handle multiple operations:

// Set multiple values at once
await cache.mset([
  { key: 'key1', value: 'value1', ttl: 60 },
  { key: 'key2', value: 'value2', ttl: 120 },
  { key: 'key3', value: 'value3' },
])

// Get multiple values at once
const values = await cache.mget(['key1', 'key2', 'key3'])
console.log(values) // { key1: 'value1', key2: 'value2', key3: 'value3' }

// Delete multiple keys
await cache.del(['key1', 'key2'])

Serializers

Multiple serialization strategies for different data types:

import { createCache, serializers } from '@stacksjs/ts-cache'

const cache = createCache({
  driver: 'redis',
  serializer: serializers.auto, // Auto-detects and preserves types
})

// Complex data types are preserved
await cache.set('date', new Date())
await cache.set('regex', /test/gi)
await cache.set('set', new Set([1, 2, 3]))
await cache.set('map', new Map([['a', 1]]))

// Available serializers:
// - serializers.json (default)
// - serializers.string
// - serializers.number
// - serializers.boolean
// - serializers.buffer
// - serializers.auto (preserves types)
// - serializers.msgpack (requires msgpack-lite)

Events

Listen for cache events:

cache.on('hit', (key, value) => {
  console.log(`Cache hit: ${key}`)
})

cache.on('miss', (key) => {
  console.log(`Cache miss: ${key}`)
})

cache.on('set', (key, value, ttl) => {
  console.log(`Cache set: ${key}`)
})

cache.on('del', (keys, count) => {
  console.log(`Deleted ${count} keys`)
})

cache.on('flush', () => {
  console.log('Cache flushed')
})

Statistics

Track cache performance:

const stats = await cache.getStats()
console.log(stats)
// {
//   hits: 127,
//   misses: 9,
//   keys: 42,
//   ksize: 840,
//   vsize: 2390
// }

CLI Tool

ts-cache includes a powerful command-line interface for managing your cache:

# Install globally for CLI access
npm install -g @stacksjs/ts-cache

# Or use with npx/bunx
bunx cache --help

Available Commands

# Get a value from cache
cache get user:123
cache get user:123 --json

# Set a value with TTL
cache set user:123 '{"name":"John"}' --json --ttl 3600

# Delete keys
cache del user:123
cache del user:* session:*

# Check if key exists
cache has user:123

# List all keys
cache keys
cache keys "user:*"

# Get TTL of a key
cache ttl session:abc

# View cache statistics
cache stats
cache stats --json

# Show current configuration
cache config
cache config --json

<
103CE
span class="pl-c"># Flush all cache data
cache flush --force

# Test cache connectivity
cache test
cache test --driver redis

# Show library info
cache info

# Show version
cache version

CLI Options

All commands support these options:

  • --driver <driver> - Use specific driver (memory, memory-lru, redis)
  • --prefix <prefix> - Add key prefix
  • --json - Output in JSON format (machine-readable)
  • --ttl <seconds> - Set time-to-live for set operations

Configuration

ts-cache supports comprehensive configuration through a cache.config.ts file at the root of your project:

// cache.config.ts
import type { CacheConfig } from '@stacksjs/ts-cache'

const config: CacheConfig = {
  // General Settings
  driver: 'memory', // 'memory' | 'memory-lru' | 'redis'
  prefix: 'myapp',
  verbose: true,

  // Common Cache Settings
  stdTTL: 3600, // Default TTL in seconds
  checkPeriod: 600, // Cleanup interval
  maxKeys: 1000,
  useClones: true,

  // Redis Configuration
  redis: {
    url: process.env.REDIS_URL,
    host: 'localhost',
    port: 6379,
    password: process.env.REDIS_PASSWORD,
    database: 0,
  },

  // Compression
  compression: {
    algorithm: 'gzip', // 'gzip' | 'brotli' | 'smart' | 'none'
    level: 6,
    threshold: 1024, // Only compress if larger than 1KB
    enabled: true,
  },

  // Middleware
  middleware: {
    enabled: true,
    logging: true,
    metrics: true,
    retry: {
      enabled: true,
      maxRetries: 3,
      initialDelay: 100,
    },
  },

  // Caching Patterns
  patterns: {
    refreshAhead: {
      ttl: 3600,
      thresholdPercentage: 0.8, // Refresh when 80% of TTL passed
    },
    slidingWindow: {
      ttl: 3600, // Reset TTL on access
    },
  },

  // Event Hooks
  events: {
    onSet: (key, value) => console.log(`Set: ${key}`),
    onGet: (key, value) => console.log(`Get: ${key}`),
    onMiss: key => console.log(`Miss: ${key}`),
  },

  // Performance Tuning
  performance: {
    enableStats: true,
    batchSize: 100,
    warmup: {
      enabled: true,
      keys: ['popular:item:1', 'popular:item:2'],
    },
  },

  // Multi-Level Cache
  multiLevel: {
    enabled: true,
    levels: [
      { driver: 'memory', ttl: 300, maxKeys: 1000 }, // L1: Fast
      { driver: 'redis', ttl: 3600 }, // L2: Persistent
    ],
  },

  // TTL Strategy
  ttlStrategy: {
    mode: 'sliding', // 'fixed' | 'sliding' | 'probabilistic'
    jitter: 0.1, // Add 10% jitter to prevent thundering herd
  },

  // Error Handling
  errorHandling: {
    throwOnError: false,
    circuitBreaker: {
      enabled: true,
      threshold: 5,
      timeout: 60000,
    },
  },

  // Debug Mode
  debug: {
    enabled: false,
    logLevel: 'info',
    trackAccess: true,
  },
}

export default config

Configuration Options

See the complete configuration reference for all 27+ available options.

Memory Driver Options

const cache = createCache({
  driver: 'memory',
  stdTTL: 3600, // Default TTL in seconds
  checkPeriod: 600, // Check for expired items every 10 minutes
  maxKeys: 1000, // Maximum number of keys
  useClones: true, // Clone values on get/set
  deleteOnExpire: true, // Remove items when they expire
  prefix: 'myapp', // Key prefix for namespacing
})

Redis Driver Options

const cache = createCache({
  driver: 'redis',
  url: 'redis://localhost:6379', // Redis connection URL
  // Or use individual options:
  host: 'localhost',
  port: 6379,
  password: 'secret',
  database: 0,

  // Connection options
  connectionTimeout: 5000,
  autoReconnect: true,
  maxRetries: 10,
  tls: false,

  // Cache options
  stdTTL: 3600,
  prefix: 'myapp',
})

Utilities

Circuit Breaker

Protect against cascading failures:

import { CircuitBreaker } from '@stacksjs/ts-cache'

const breaker = new CircuitBreaker(cache, 5, 60) // 5 failures in 60 seconds

try {
  const result = await breaker.execute('api:endpoint', async () => {
    return await callExternalAPI()
  })
}
catch (error) {
  console.log('Circuit breaker is open')
}

Cache Warmer

Preload cache with data:

import { CacheWarmer } from '@stacksjs/ts-cache'

const warmer = new CacheWarmer(cache)

await warmer.warm([
  { key: 'user:1', fetcher: () => getUser(1), ttl: 3600 },
  { key: 'user:2', fetcher: () => getUser(2), ttl: 3600 },
])

Debounced Cache

Debounce cache writes:

import { DebouncedCache } from '@stacksjs/ts-cache'

const debounced = new DebouncedCache(cache, 1000) // 1 second delay

// Multiple rapid calls only write once
debounced.set('key', 'value1')
debounced.set('key', 'value2')
debounced.set('key', 'value3') // Only this value is written after 1 second

Migration from v0.1.x

The legacy synchronous API is still available for backwards compatibility:

import { Cache, createCache } from '@stacksjs/ts-cache'

// Old synchronous API (still works)
const syncCache = new Cache()
syncCache.set('key', 'value')
const syncValue = syncCache.get('key')

// New async API (recommended)
const asyncCache = createCache()
await asyncCache.set('key', 'value')
const asyncValue = await asyncCache.get('key')

Use Cases

  • API Response Caching: Reduce API calls by caching responses
  • Session Management: Store user sessions with Redis for distributed apps
  • Rate Limiting: Implement request throttling with automatic expiration
  • Distributed Locking: Coordinate access to shared resources
  • Function Memoization: Cache expensive function results
  • Database Query Caching: Speed up repeated database queries
  • Computed Values: Store results of expensive calculations

Documentation

For detailed documentation, see:

Contributing

Please see the Contributing Guide for details.

Community

For help, discussion about best practices, or any other conversation that would benefit from being searchable:

Discussions on GitHub

For casual chit-chat with others using this package:

Join the Stacks Discord Server

Postcardware

"Software that is free, but hopes for a postcard." We love receiving postcards from around the world showing where Stacks is being used! We showcase them on our website too.

Our address: Stacks.js, 12665 Village Ln #2306, Playa Vista, CA 90094, United States 🌎

Sponsors

We would like to extend our thanks to the following sponsors for funding Stacks development. If you are interested in becoming a sponsor, please reach out to us.

Credits

License

The MIT License (MIT). Please see LICENSE for more information.

Made with πŸ’™

About

⚑ A fast, type-safe, and feature-rich caching library for modern applications.

Topics

Resources

License

Code of conduct

Contributing

Security policy

Stars

Watchers

Forks

Sponsor this project

  •  

Contributors 5

0