{"id":44423245,"url":"https://github.com/stephen-shopopop/node-cache","last_synced_at":"2026-02-12T10:11:13.351Z","repository":{"id":314112635,"uuid":"1053965877","full_name":"stephen-shopopop/node-cache","owner":"stephen-shopopop","description":" cache store implementation for nodejs","archived":false,"fork":false,"pushed_at":"2026-01-24T18:23:03.000Z","size":372,"stargazers_count":0,"open_issues_count":3,"forks_count":0,"subscribers_count":0,"default_branch":"main","last_synced_at":"2026-01-25T07:35:33.463Z","etag":null,"topics":["cache","memory","nodejs","redis","sqlite3","valkey"],"latest_commit_sha":null,"homepage":"https://stephen-shopopop.github.io/node-cache/","language":"TypeScript","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":null,"status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/stephen-shopopop.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":null,"code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null,"zenodo":null,"notice":null,"maintainers":null,"copyright":null,"agents":null,"dco":null,"cla":null}},"created_at":"2025-09-10T07:18:07.000Z","updated_at":"2026-01-24T18:23:07.000Z","dependencies_parsed_at":"2025-09-23T11:25:07.765Z","dependency_job_id":null,"html_url":"https://github.com/stephen-shopopop/node-cache","commit_stats":null,"previous_names":["stephen-shopopop/node-cache"],"tags_count":11,"template":false,"template_full_name":null,"purl":"pkg:github/stephen-shopopop/node-cache","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/stephen-shopopop%2Fnode-cache","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/stephen-shopopop%2Fnode-cache/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/stephen-shopopop%2Fnode-cache/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/stephen-shopopop%2Fnode-cache/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/stephen-shopopop","download_url":"https://codeload.github.com/stephen-shopopop/node-cache/tar.gz/refs/heads/main","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/stephen-shopopop%2Fnode-cache/sbom","scorecard":null,"host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":286080680,"owners_count":29363010,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2026-02-12T08:51:36.827Z","status":"ssl_error","status_checked_at":"2026-02-12T08:51:26.849Z","response_time":55,"last_error":"SSL_read: unexpected eof while reading","robots_txt_status":"success","robots_txt_updated_at":"2025-07-24T06:49:26.215Z","robots_txt_url":"https://github.com/robots.txt","online":false,"can_crawl_api":true,"host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["cache","memory","nodejs","redis","sqlite3","valkey"],"created_at":"2026-02-12T10:11:10.223Z","updated_at":"2026-02-12T10:11:13.345Z","avatar_url":"https://github.com/stephen-shopopop.png","language":"TypeScript","funding_links":[],"categories":[],"sub_categories":[],"readme":"[![npm version](https://img.shields.io/npm/v/@stephen-shopopop/cache.svg)](https://www.npmjs.com/package/@stephen-shopopop/cache)\n[![Coverage Status](https://img.shields.io/badge/coverage-96%25-brightgreen)](./)\n[![CI](https://github.com/stephen-shopopop/node-cache/actions/workflows/ci.yml/badge.svg?branch=main)](https://github.com/stephen-shopopop/node-cache/actions/workflows/ci.yml)\n\n# node-cache\n\nA high-performance, strongly-typed caching library for Node.js. Supports in-memory LRU and TTL caches, metadata, and persistent backends (SQLite, Redis). Designed for reliability, flexibility, and modern TypeScript/ESM workflows.\n\n- ⚡️ Fast in-memory LRU and TTL caches\n- 🗃️ Persistent cache with SQLite and Redis backends\n- 🏷️ Metadata support for all entries\n- 📏 Size and entry count limits\n- 🧑‍💻 100% TypeScript, ESM \u0026 CJS compatible\n- 🧪 Simple, robust API for all Node.js projects\n\n## Table of Contents\n\n- [node-cache](#node-cache)\n  - [Table of Contents](#table-of-contents)\n  - [Install](#install)\n  - [Setup](#setup)\n    - [ESM](#esm)\n    - [CommonJS](#commonjs)\n  - [Documentation](#documentation)\n    - [Main Classes](#main-classes)\n      - [LRUCache\\\u003cK, V\\\u003e](#lrucachek-v)\n      - [LRUCacheWithTTL\\\u003cK, V\\\u003e](#lrucachewithttlk-v)\n      - [MemoryCacheStore\\\u003cK, Metadata\\\u003e](#memorycachestorek-metadata)\n      - [SQLiteCacheStore](#sqlitecachestore)\n      - [RedisCacheStore](#rediscachestore)\n    - [Common Options](#common-options)\n    - [Usage Examples](#usage-examples)\n    - [LRU Cache - ASCII Diagram](#lru-cache---ascii-diagram)\n    - [MemoryCacheStore - ASCII Diagram](#memorycachestore---ascii-diagram)\n    - [SQLiteCacheStore - ASCII Diagram](#sqlitecachestore---ascii-diagram)\n    - [LRUCacheWithTTL - ASCII Diagram](#lrucachewithttl---ascii-diagram)\n    - [RedisCacheStore - ASCII Diagram](#rediscachestore---ascii-diagram)\n  - [Use Cases](#use-cases)\n  - [📊 Performance Comparison](#-performance-comparison)\n  - [⚠️ Performance limits by backend](#️-performance-limits-by-backend)\n  - [FAQ / Troubleshooting](#faq--troubleshooting)\n    - [Why is SQLiteCacheStore slower than in-memory caches?](#why-is-sqlitecachestore-slower-than-in-memory-caches)\n    - [How can I enable observability (tracing/metrics)?](#how-can-i-enable-observability-tracingmetrics)\n    - [I get “ExperimentalWarning: SQLite is an experimental feature”](#i-get-experimentalwarning-sqlite-is-an-experimental-feature)\n    - [How do I handle errors from SQLiteCacheStore?](#how-do-i-handle-errors-from-sqlitecachestore)\n    - [Can I use this library in a serverless environment?](#can-i-use-this-library-in-a-serverless-environment)\n  - [🤝 Contributing / Development](#-contributing--development)\n    - [Prerequisites](#prerequisites)\n    - [Project Setup](#project-setup)\n    - [Useful Scripts](#useful-scripts)\n    - [Project Structure](#project-structure)\n    - [Best Practices](#best-practices)\n      - [Minimal test example (node:test)](#minimal-test-example-nodetest)\n    - [Before Submitting a PR](#before-submitting-a-pr)\n    - [Release process](#release-process)\n    - [Need help?](#need-help)\n  - [References](#references)\n\n## Install\n\n```bash\nnpm i @stephen-shopopop/cache\n```\n\nFor Redis support, you also need to install iovalkey:\n\n```bash\nnpm i iovalkey\n```\n\n## Setup\n\nThis library requires no special configuration for basic usage.\n\n- Node.js \u003e= 20.17.0\n- Compatible with both ESM (`import`) and CommonJS (`require`)\n- TypeScript types included\n- SQLiteCacheStore available on Node.js \u003e 20.x\n- **RedisCacheStore requires `iovalkey` package to be installed separately**\n\n### ESM\n\n```js\nimport { LRUCache } from '@stephen-shopopop/cache';\n```\n\n### CommonJS\n\n```js\nconst { LRUCache } = require('@stephen-shopopop/cache');\n```\n\n## Documentation\n\nFull API documentation is available here: [📚 Generated Docs](https://stephen-shopopop.github.io/node-cache/)\n\n### Main Classes\n\n#### LRUCache\u003cK, V\u003e\n\nA fast in-memory Least Recently Used (LRU) cache. Removes the least recently used item when the maximum size is reached.\n\n- **Constructor:**\n\n  ```typescript\n  new LRUCache\u003cK, V\u003e({ maxSize?: number })\n  ```\n\n- **Methods:**\n  - `set(key, value)`: Add or update a value\n  - `get(key)`: Retrieve a value\n  - `delete(key)`: Remove a key\n  - `clear()`: Clear the cache\n  - `has(key)`: Check if a key exists\n  - `size`: Number of items\n\n#### LRUCacheWithTTL\u003cK, V\u003e\n\nLRU cache with automatic expiration (TTL) for entries. Combines LRU eviction and time-based expiration.\n\n- **Constructor:**\n\n  ```typescript\n  new LRUCacheWithTTL\u003cK, V\u003e({ maxSize?: number, ttl?: number, stayAlive?: boolean, cleanupInterval?: number })\n  ```\n\n- **Methods:**\n  - `set(key, value, ttl?)`: Add a value with optional TTL\n  - `get(key)`: Retrieve a value (or undefined if expired)\n  - `delete(key)`: Remove a key\n  - `clear()`: Clear the cache\n  - `has(key)`: Check if a key exists\n  - `size`: Number of items\n\n#### MemoryCacheStore\u003cK, Metadata\u003e\n\nIn-memory cache with LRU policy, supports max size, max entry size, max number of entries, and associated metadata.\n\n- **Constructor:**\n\n  ```typescript\n  new MemoryCacheStore\u003cK, Metadata\u003e({ maxCount?: number, maxEntrySize?: number, maxSize?: number })\n  ```\n\n- **Methods:**\n  - `set(key, value, metadata?)`: Add a value (string or Buffer) with metadata\n  - `get(key)`: Retrieve `{ value, metadata, size }` or undefined\n  - `delete(key)`: Remove a key\n  - `clear()`: Clear the cache\n  - `has(key)`: Check if a key exists\n  - `size`: Number of items\n  - `byteSize`: Total size in bytes\n\n#### SQLiteCacheStore\u003cMetadata\u003e\n\nPersistent cache using SQLite as backend, supports metadata, TTL, entry size and count limits.\n\n- **Constructor:**\n\n  ```typescript\n  new SQLiteCacheStore\u003cMetadata\u003e({ filename?: string, maxEntrySize?: number, maxCount?: number, timeout?: number })\n  ```\n\n- **Methods:**\n  - `set(key, value, metadata?, ttl?)`: Add a value (string or Buffer) with metadata and optional TTL\n  - `get(key)`: Retrieve `{ value, metadata }` or undefined\n  - `delete(key)`: Remove a key\n  - `size`: Number of items\n\n  - `close()`: Close the database connection\n\n\u003e **Note:** SQLiteCacheStore methods may throw errors related to SQLite (connection, query, file access, etc.).\n\u003e It is the responsibility of the user to handle these errors (e.g., with try/catch) according to their application's needs. The library does not catch or wrap SQLite errors by design.\n\n#### RedisCacheStore\u003cMetadata\u003e\n\nDistributed cache based on Redis, supports persistence, TTL, metadata, and entry size/count limits.\n\n\u003e **Prerequisites:** Install `iovalkey` package: `npm i iovalkey`\n\n- **Constructor:**\n\n  ```typescript\n  new RedisCacheStore\u003cMetadata\u003e({\n    url?: string,\n    maxEntrySize?: number,\n    maxCount?: number,\n    ttl?: number,\n    namespace?: string,\n    redisOptions?: object\n  })\n  ```\n\n- **Methods:**\n  - `set(key, value, metadata?, ttl?)`: Add a value (string or Buffer) with optional metadata and TTL\n  - `get(key)`: Retrieve `{ value, metadata }` or undefined\n  - `delete(key)`: Remove a key\n  - `close()`: Close the Redis connection\n\n\u003e **Note:** RedisCacheStore requires an accessible Redis server and the `iovalkey` package. Connection or operation errors are thrown as-is.\n\n### Common Options\n\n- `maxSize`: max number of items (LRUCache, LRUCacheWithTTL), max total size in bytes (MemoryCacheStore)\n- `maxCount`: max number of entries (MemoryCacheStore)\n- `maxEntrySize`: max size of a single entry (MemoryCacheStore)\n- `ttl`: time to live in ms (LRUCacheWithTTL)\n- `cleanupInterval`: automatic cleanup interval (LRUCacheWithTTL)\n- `stayAlive`: keep the timer active (LRUCacheWithTTL)\n\n- `filename`: SQLite database file name (SQLiteCacheStore)\n- `timeout`: SQLite operation timeout in ms (SQLiteCacheStore)\n- `url`: Redis server URL (RedisCacheStore)\n- `namespace`: Key namespace for RedisCacheStore (RedisCacheStore)\n- `redisOptions`: Additional options for Redis client (RedisCacheStore)\n\n### Usage Examples\n\n```typescript\nimport { LRUCache, LRUCacheWithTTL, MemoryCacheStore, RedisCacheStore } from '@stephen-shopopop/cache';\n\nconst lru = new LRUCache({ maxSize: 100 });\nlru.set('a', 1);\n\nconst lruTtl = new LRUCacheWithTTL({ maxSize: 100, ttl: 60000 });\nlruTtl.set('a', 1);\n\nconst mem = new MemoryCacheStore({ maxCount: 10, maxEntrySize: 1024 });\nmem.set('a', 'value', { meta: 123 });\n\nconst sqlite = new SQLiteCacheStore({ filename: 'cache.db', maxEntrySize: 1024 });\nsqlite.set('a', 'value', { meta: 123 }, 60000);\nconst result = sqlite.get('a');\n\nconst redis = new RedisCacheStore({ url: 'redis://localhost:6379', namespace: 'mycache:' });\nawait redis.set('a', 'value', { meta: 123 }, 60000);\nconst redisResult = await redis.get('a');\n```\n\n### LRU Cache - ASCII Diagram\n\n```shell\n[Most Recent]   [   ...   ]   [Least Recent]\n    head  \u003c-\u003e  node \u003c-\u003e ... \u003c-\u003e  tail\n      |                          |\n      +---\u003e {key,value}          +---\u003e {key,value}\n\nEviction: when maxSize is reached, 'tail' is removed (least recently used)\nAccess:   accessed node is moved to 'head' (most recently used)\n```\n\n### MemoryCacheStore - ASCII Diagram\n\n```ascii\n+-----------------------------+\n|        MemoryCacheStore     |\n+-----------------------------+\n|  #data: LRUCache\u003cK, Value\u003e  |\n|  #maxCount                  |\n|  #maxEntrySize              |\n|  #maxSize                   |\n|  #size                      |\n+-----------------------------+\n        |         |\n        |         +---\u003e [maxCount, maxEntrySize, maxSize] constraints\n        |\n        +---\u003e LRUCache (internal):\n                head \u003c-\u003e node \u003c-\u003e ... \u003c-\u003e tail\n                (evicts least recently used)\n\nEach entry:\n  {\n    key: K,\n    value: string | Buffer,\n    metadata: object,\n    size: number (bytes)\n  }\n\nEviction: when maxCount or maxSize is reached, oldest/oversized entries are removed.\n```\n\n### SQLiteCacheStore - ASCII Diagram\n\n```ascii\n+-----------------------------+\n|      SQLiteCacheStore       |\n+-----------------------------+\n|  #db: SQLite database       |\n|  #maxCount                  |\n|  #maxEntrySize              |\n|  #timeout                   |\n+-----------------------------+\n        |\n        +---\u003e [SQLite file: cache.db]\n                |\n                +---\u003e Table: cache_entries\n                        +-------------------------------+\n                        | key | value | metadata | ttl  |\n                        +-------------------------------+\n\nEach entry:\n  {\n    key: string,\n    value: string | Buffer,\n    metadata: object,\n    ttl: number (ms, optional)\n  }\n\nEviction: when maxCount or maxEntrySize is reached, or TTL expires, entries are deleted from the table.\nPersistence: all data is stored on disk in the SQLite file.\n```\n\n### LRUCacheWithTTL - ASCII Diagram\n\n```ascii\n+-----------------------------+\n|      LRUCacheWithTTL        |\n+-----------------------------+\n|  #data: LRUCache\u003cK, Entry\u003e  |\n|  #ttl                       |\n|  #cleanupInterval           |\n|  #timer                     |\n+-----------------------------+\n        |\n        +---\u003e LRUCache (internal):\n                head \u003c-\u003e node \u003c-\u003e ... \u003c-\u003e tail\n                (evicts least recently used)\n\nEach entry:\n  {\n    key: K,\n    value: V,\n    expiresAt: number (timestamp, ms)\n  }\n\nExpiration: entries are removed when their TTL expires (checked on access or by cleanup timer).\nEviction: LRU policy applies when maxSize is reached.\n```\n\n### RedisCacheStore - ASCII Diagram\n\n```ascii\n+-----------------------------+\n|      RedisCacheStore        |\n+-----------------------------+\n|  #client: Redis client      |\n|  #maxSize                   |\n|  #maxCount                  |\n|  #maxEntrySize              |\n|  #ttl                       |\n+-----------------------------+\n        |\n        +---\u003e [Redis server]\n                |\n                +---\u003e Key: {keyPrefix}{key}\n                        Value: JSON.stringify({ value, metadata })\n                        TTL: Redis expire (ms)\n\nEach entry:\n  {\n    key: string,\n    value: string | Buffer,\n    metadata: object,\n    ttl: number (ms, optional)\n  }\n\nExpiration: handled by Redis via TTL.\nEviction: handled by Redis according to its memory policy.\nPersistence: depends on Redis configuration (AOF, RDB, etc.).\n```\n\n## Use Cases\n\n- **API response caching**: Reduce latency and external API calls by caching HTTP responses in memory or on disk.\n- **Session storage**: Store user sessions or tokens with TTL for automatic expiration.\n- **File or image cache**: Cache processed files, images, or buffers with size limits.\n- **Metadata tagging**: Attach custom metadata (timestamps, user info, tags) to each cache entry for advanced logic.\n- **Persistent job queue**: Use SQLiteCacheStore to persist jobs or tasks between server restarts.\n- **Rate limiting**: Track and limit user actions over time using TTL-based caches.\n- **Temporary feature flags**: Store and expire feature flags or toggles dynamically.\n\n## 📊 Performance Comparison\n\n\u003e **Note:** Results below are indicative and may vary depending on your hardware and Node.js version. Run `npm run bench` for up-to-date results on your machine.\n\n| Store                        | set (ops/s) | get (ops/s) | delete (ops/s) | complex workflow (ops/s) |\n|------------------------------|-------------|-------------|----------------|--------------------------|\n| LRUCache                     | 1,220,000   | 2,030,000   | 1,190,000      | 675,000                  |\n| LRUCacheWithTTL              | 1,060,000   | 1,830,000   | 1,030,000      | 615,000                  |\n| MemoryCacheStore             | 1,120,000   | 1,910,000   |  182,000       | 305,000                  |\n| RedisCacheStore              |    28,000   |    39,000   |   33,000       | 16,500                   |\n| SQLiteCacheStore (mem)       |  121,000    |   442,000   |  141,000       | 52,500                   |\n| SQLiteCacheStore (file)       |   51,000    |    49,000   |  137,000       | 46,500                   |\n\n*Bench run on Apple M1, Node.js 24.7.0, `npm run bench` — complex workflow = set, get, update, delete, hit/miss, TTL, metadata.*\n\n**How are ops/s calculated?**\nFor each operation, the benchmark reports the average time per operation (e.g. `1.87 µs/iter`).\nTo get the number of operations per second (ops/s), we use:\n\n  ops/s = 1 / (average time per operation in seconds)\n\nExample: if the bench reports `856.45 ns/iter`, then:\n\n- 856.45 ns = 0.00000085645 seconds\n- ops/s = 1 / 0.00000085645 ≈ 1,168,000\n\nAll values in the table are calculated this way and rounded for readability.\n\n## ⚠️ Performance limits by backend\n\nEach backend has different performance characteristics and is suited for different use cases:\n\n| Backend                 | Typical use case                | Max ops/s (indicative) | Latency (typical) | Notes                                 |\n|-------------------------|---------------------------------|------------------------|-------------------|---------------------------------------|\n| LRUCache                | Hot-path, ultra-fast in-memory  | \u003e1,200,000             | \u003c2µs              | No persistence, no TTL                |\n| LRUCacheWithTTL         | In-memory with expiration       | \u003e1,000,000             | \u003c2µs              | TTL adds slight overhead              |\n| MemoryCacheStore        | In-memory, metadata, size limit | ~1,100,000             | \u003c2µs              | Metadata, size/count limits           |\n| SQLiteCacheStore (mem)  | Fast, ephemeral persistence     | ~120,000               | ~10µs             | Data lost on restart                  |\n| SQLiteCacheStore (file) | Durable persistence             | ~50,000                | ~20–50µs          | Disk I/O, best for cold data          |\n| RedisCacheStore         | Distributed, persistent cache   | ~27,000                | ~40–100µs         | Network I/O, Redis server, async API  |\n\n**Guidance:**\n\n- Use LRUCache/LRUCacheWithTTL for ultra-low-latency, high-throughput scenarios (API cache, session, etc.).\n- Use MemoryCacheStore if you need metadata or strict size limits.\n- Use SQLiteCacheStore (memory) for fast, non-persistent cache across processes.\n- Use SQLiteCacheStore (file) for persistent cache, but expect higher latency due to disk I/O.\n- Use RedisCacheStore for distributed caching, multi-process sharing, and when Redis features or persistence are needed.\n\n*Numbers are indicative, measured on Apple M1, Node.js 24.x. Always benchmark on your own hardware for production sizing.*\n\n## FAQ / Troubleshooting\n\n### Why is SQLiteCacheStore slower than in-memory caches?\n\nSQLite is a disk-based database. Even with optimizations (WAL, memory temp store), disk I/O and serialization add latency compared to pure in-memory caches. For ultra-low-latency needs, use LRUCache or MemoryCacheStore.\n\n### How can I enable observability (tracing/metrics)?\n\nYou can instrument the library using [diagnostic_channel](https://www.npmjs.com/package/diagnostic-channel) (Node.js). Future versions may provide built-in hooks. For now, you can wrap cache methods or use diagnostic_channel in your own code to publish events on cache operations.\n\n### I get “ExperimentalWarning: SQLite is an experimental feature”\n\nThis warning is from Node.js itself (v20+). SQLite support is stable for most use cases, but the API may change in future Node.js versions. Follow Node.js release notes for updates.\n\n### How do I handle errors from SQLiteCacheStore?\n\nAll errors from SQLite (connection, query, file access) are thrown as-is. You should use try/catch around your cache operations and handle errors according to your application’s needs.\n\n### Can I use this library in a serverless environment?\n\nYes, but persistent caches (SQLiteCacheStore with file) may not be suitable for ephemeral file systems. Use in-memory caches for stateless/serverless workloads.\n\n## 🤝 Contributing / Development\n\nWant to contribute to this library? Thank you! Here’s what you need to know to get started:\n\n### Prerequisites\n\n- Node.js \u003e= 20.17.0\n- pnpm or npm (package manager)\n- TypeScript (strictly typed everywhere)\n\n### Project Setup\n\n```bash\ngit clone https://github.com/stephen-shopopop/node-cache.git\ncd node-cache\npnpm install # or npm install\n```\n\n### Useful Scripts\n\n- `npm run build`: build TypeScript (ESM + CJS via tsup)\n- `npm run test`: run all tests (node:test)\n- `npm run lint`: check lint (biome)\n- `npm run format`: format code\n- `npm run check`: type check\n- `npm run bench`: run benchmarks\n- `npm run docs`: generate documentation (TypeDoc)\n\n### Project Structure\n\n- `src/library/`: main source code (all cache classes)\n- `src/index.ts`: entry point\n- `test/`: all unit tests (node:test)\n- `bench/`: benchmarks (mitata)\n- `docs/`: generated documentation\n\n### Best Practices\n\n- Follow the style: semicolons, single quotes, arrow functions for callbacks\n- Avoid nested ternary operators\n- Always add tests for any new feature or bugfix (see example below)\n- Use clear, conventional commit messages (see [Conventional Commits](https://www.conventionalcommits.org/))\n- PRs and code reviews are welcome in French or English\n\n#### Minimal test example (node:test)\n\n```js\nimport test from 'node:test';\nimport { LRUCache } from '../src/library/LRUCache.js';\n\ntest('LRUCache basic set/get', (t: TestContext) =\u003e {\n  // Arrange\n  const cache = new LRUCache({ maxSize: 2 });\n\n  // Act\n  cache.set('a', 1);\n\n  // Assert\n  t.assert.strictEqual(cache.get('a'), 1);\n});\n```\n\n### Before Submitting a PR\n\n1. Make sure all tests pass (`npm run test`)\n2. Check lint and formatting (`npm run lint \u0026\u0026 npm run format`)\n3. Check coverage (`npm run coverage`)\n4. Add/complete documentation if needed\n5. Clearly describe your contribution in the PR\n6. Use clear, conventional commit messages\n7. If your change impacts users, update the README and/or documentation\n\n### Release process\n\n- Releases are tagged and published manually by the maintainer. If you want to help with releases, open an issue or PR.\n\n### Need help?\n\n- Open an [issue](https://github.com/stephen-shopopop/node-cache/issues) or contact the maintainer via GitHub.\n- See [pull requests](https://github.com/stephen-shopopop/node-cache/pulls) for ongoing work.\n\n---\n\n## References\n\n- [Least Recently Used (LRU) cache - Wikipedia](https://en.wikipedia.org/wiki/Cache_replacement_policies#Least_recently_used_(LRU))\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fstephen-shopopop%2Fnode-cache","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fstephen-shopopop%2Fnode-cache","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fstephen-shopopop%2Fnode-cache/lists"}