{"id":31703627,"url":"https://github.com/nasriyasoftware/cachify","last_synced_at":"2026-01-20T17:01:30.472Z","repository":{"id":325766440,"uuid":"1102306133","full_name":"nasriyasoftware/Cachify","owner":"nasriyasoftware","description":"A lightweight, extensible in-memory caching library for storing anything, with built-in TTL and customizable cache types.","archived":false,"fork":false,"pushed_at":"2025-11-23T08:08:27.000Z","size":168,"stargazers_count":0,"open_issues_count":0,"forks_count":0,"subscribers_count":0,"default_branch":"main","last_synced_at":"2025-11-23T10:05:11.557Z","etag":null,"topics":["cache","caching","file-cache","key-value-store","lock","persistence","sessions"],"latest_commit_sha":null,"homepage":"https://www.npmjs.com/package/@nasriya/cachify","language":"TypeScript","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"other","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/nasriyasoftware.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":".github/FUNDING.yml","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},"funding":{"custom":["https://fund.nasriya.net"]}},"created_at":"2025-11-23T07:52:57.000Z","updated_at":"2025-11-23T08:35:01.000Z","dependencies_parsed_at":null,"dependency_job_id":null,"html_url":"https://github.com/nasriyasoftware/Cachify","commit_stats":null,"previous_names":["nasriyasoftware/cachify"],"tags_count":2,"template":false,"template_full_name":null,"purl":"pkg:github/nasriyasoftware/Cachify","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/nasriyasoftware%2FCachify","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/nasriyasoftware%2FCachify/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/nasriyasoftware%2FCachify/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/nasriyasoftware%2FCachify/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/nasriyasoftware","download_url":"https://codeload.github.com/nasriyasoftware/Cachify/tar.gz/refs/heads/main","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/nasriyasoftware%2FCachify/sbom","scorecard":null,"host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":286080680,"owners_count":28607624,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2026-01-20T16:10:39.856Z","status":"ssl_error","status_checked_at":"2026-01-20T16:10:39.493Z","response_time":117,"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","caching","file-cache","key-value-store","lock","persistence","sessions"],"created_at":"2025-10-08T22:06:26.896Z","updated_at":"2026-01-20T17:01:30.464Z","avatar_url":"https://github.com/nasriyasoftware.png","language":"TypeScript","funding_links":["https://fund.nasriya.net"],"categories":[],"sub_categories":[],"readme":"\u003cimg src=\"./.github/assets/Cachify_Full_Logo.svg\" height=\"80px\" alt=\"Cachify Logo\" center\u003e\n\n# Cachify\nCachify is a fast, flexible caching library for Node.js supporting key-value and file caching with multi-storage and lifecycle management.\n\n[![NPM License](https://img.shields.io/npm/l/%40nasriya%2Fcachify?color=lightgreen)](https://github.com/nasriyasoftware/Cachify?tab=License-1-ov-file) ![NPM Version](https://img.shields.io/npm/v/%40nasriya%2Fcachify) ![NPM Unpacked Size](https://img.shields.io/npm/unpacked-size/%40nasriya%2Fcachify) ![Last Commit](https://img.shields.io/github/last-commit/nasriyasoftware/Cachify.svg) [![Status](https://img.shields.io/badge/Status-Stable-lightgreen.svg)](link-to-your-status-page)\n\n##### Visit us at [www.nasriya.net](https://nasriya.net).\n\nMade with ❤️ in **Palestine** 🇵🇸\n\n___\n## Overview\n\nCachify is a fast, flexible caching library for Node.js that supports both key-value and file caching across multiple storage backends, with built-in lifecycle management and persistence.  \nThis documentation covers the essential concepts, setup, and best practices to get started quickly and efficiently.\n\n### Contents\n  - [Why Cachify and When to Use It](#why-cachify-and-when-to-use-it)\n    - [Key Advantages](#key-advantages)\n    - [When to Use Cachify Instead of Just Redis](#when-to-use-cachify-instead-of-just-redis)\n  - [Installation \\\u0026 Importing](#installation--importing)\n    - [Installation](#installation)\n  - [Importing](#importing)\n  - [Usage](#usage)\n    - [1. Creating Clients (Isolation)](#1-creating-clients-isolation)\n    - [2. Registering Storage Engines](#2-registering-storage-engines)\n    - [3. Default Storage Engines](#3-default-storage-engines)\n    - [4. Caching (KVS \\\u0026 Files)](#4-caching-kvs--files)\n    - [5. Persistence \\\u0026 Cold Start Recovery](#5-persistence--cold-start-recovery)\n    - [6. Lock Sessions \\\u0026 Safe Concurrency](#6-lock-sessions--safe-concurrency)\n  - [Testing](#testing)\n    - [Required Environment Variables](#required-environment-variables)\n    - [Running Tests](#running-tests)\n  - [Benchmarking](#benchmarking)\n    - [Environment Setup](#environment-setup)\n    - [Optional Environment Variables](#optional-environment-variables)\n    - [Running Benchmarks](#running-benchmarks)\n  - [License](#license)\n\n\n\u003e [!IMPORTANT]\n\u003e \n\u003e 🌟 **Support Our Open-Source Development!** 🌟\n\u003e We need your support to keep our projects going! If you find our work valuable, please consider contributing. Your support helps us continue to develop and maintain these tools.\n\u003e \n\u003e **[Click here to support us!](https://fund.nasriya.net/)**\n\u003e \n\u003e Every contribution, big or small, makes a difference. Thank you for your generosity and support!\n\n___\n\n## Why Cachify and When to Use It\n\nCachify goes **beyond traditional key-value caching** like Redis, offering a unified, flexible, and highly extensible caching solution for Node.js.\n\n### Key Advantages\n\n- **Unified caching for keys and files**: Cache key-value pairs and files in memory, Redis, or other backends seamlessly.  \n- **Multi-storage support**: Combine memory, Redis, and custom engines for redundancy, failover, and multi-region setups.  \n- **Automated file lifecycle management**: Automatic revalidation, eviction, and TTL handling.  \n- **Persistence \u0026 cold-start recovery**: Backup and restore your cache to survive application restarts without rebuilding.  \n- **Extensibility**: Easily plug in custom storage engines or adapters.  \n- **Fastest read-first strategy**: Queries multiple backends and returns the first successful result to optimize latency.  \n- **Isolation**: Multiple cache clients can coexist safely, even when sharing storage engines like Redis.\n\n### When to Use Cachify Instead of Just Redis\n\n- You need **file caching in memory or Redis**, with **automatic retrieval by file path**.  \n- You want **automatic file revalidation** without writing extra watchers.  \n- Your application requires **multi-storage redundancy** or **fastest-response reads** across multiple backends.  \n- You need **persistent caching** that survives cold starts without rebuilding.  \n- You want a **Node.js-native, highly extensible caching library** that complements or goes beyond Redis.\n\n\n___\n## Installation \u0026 Importing\n### Installation\n\n```bash\nnpm install @nasriya/cachify\n```\n\n## Importing\nImporting in **ESM** modules\n```js\nimport cachify from '@nasriya/cachify';\n```\n\nImporting in **CommonJS** modules\n```js\nconst cachify = require('@nasriya/cachify').default;\n```\n___\n\n## Usage\nThis section guides you through Cachify’s core usage in a logical order.\n\n### 1. Creating Clients (Isolation)\n\nThe imported `cachify` object is an instance of the **`Cachify`** class,  \nwhich **extends `CachifyClient`**. It behaves like a cache client but also provides global utilities such as debugging, configuration, and client creation.\n\nYou can create **isolated clients** for independent caches — useful for multi-tenant systems, different environments, or testing.\n\n\n```js\nimport cachify from '@nasriya/cachify';\n\n// Create an isolated instance\nconst isolated = cachify.createClient();\n\n// Each instance maintains its own managers, engines, and configurations\nawait isolated.kvs.set('1', 'value');\nawait cachify.kvs.read('1'); // ❌ undefined — isolated from the other instance\n\n// Both share the same API surface, but only `cachify` includes utilities like:\nconsole.log(cachify.debug);         // Access global debug utilities\nconsole.log(cachify.createClient);  // Create new isolated clients\n```\n\n**Notes:**\n- Isolated clients behave like `CachifyClient` instances but also include additional properties and methods from `Cachify`, such as `debug` and `createClient`.\n- All usage patterns shown for the global `cachify` instance apply to isolated clients.\n- Useful for multi-tenant systems, testing, or environments requiring independent caches.\n\n### 2. Registering Storage Engines\nBefore storing or reading records in a backend like Redis, you must register your storage engines:\n\n```js\nimport { createClient } from '@redis/client';\n\n// Create Redis clients\nconst redisEU = createClient({ url: process.env.REDIS_EU });\nconst redisUS = createClient({ url: process.env.REDIS_US });\n\n// Register the clients with Cachify\ncachify.engines.useRedis('redis-eu', redisEU);\ncachify.engines.useRedis('redis-us', redisUS);\n\n// Register a custom engine\ncachify.engines.defineEngine('custom-engine', {\n    onSet: async (record, value, context) =\u003e {\n        context.set(record.key, value);\n    },\n    onRead: async (record, context): Promise\u003cany\u003e =\u003e {\n        return context.get(record.key);\n    },\n    onRemove: async (record, context): Promise\u003cvoid\u003e =\u003e {\n        if (context.has(record.key)) { context.delete(record.key) }\n    }\n});\n```\n\n**Notes:**\n- Any backend (e.g., Redis) must be registered with Cachify before use.\n- Names used in `storeIn` or `defaultEngines` must exactly match registered engine names.\n- Attempting to use an unregistered engine will throw an error at runtime.\n- Redis integration is optional; Cachify defaults to in-memory storage if no backend is configured.\n\n### 3. Default Storage Engines\nYou can set default engines for any record manager (kvs, files, etc.) to avoid specifying storeIn on every operation:\n\n```js\n// For key-value records\ncachify.kvs.defaultEngines = 'redis-eu';\n\n// Or multiple engines\ncachify.kvs.defaultEngines = ['redis-eu'];\n\n// Redundant / multi-region setup\ncachify.kvs.defaultEngines = ['redis-eu', 'redis-us'];\n\n// For file records\ncachify.files.defaultEngines = 'redis-eu';\ncachify.files.defaultEngines = ['redis-eu', 'redis-us'];\n```\n\n**Notes:**\n- Operations without a `storeIn` option automatically use the defined `defaultEngines`.\n- Applies to all record managers (`kvs`, `files`, and custom managers).\n- Multiple engines allow redundancy, failover, or multi-region caching.\n- Engines must be registered before assigning them as defaults.\n- Simplifies code and ensures consistent storage behavior across operations.\n\n### 4. Caching (KVS \u0026 Files)\nKey-Value Caching (KVS)\n\n```js\n// Recommended: set a record in the \"users\" scope\nawait cachify.kvs.set('1', { name: 'Ahmad' }, { scope: 'users' });\n\n// Retrieve from the same scope\nconst user = await cachify.kvs.read('1', 'users');\nconsole.log(user); // { name: 'Ahmad' }\n\n// Optional: store in multiple backends\nawait cachify.kvs.set('2', { name: 'Omar' }, { scope: 'users', storeIn: ['memory', 'redis-eu'] });\nconst user2 = await cachify.kvs.read('2', 'users');\nconsole.log(user2); // { name: 'Omar' }\n\n// Scopes are optional — default is \"global\"\nawait cachify.kvs.set('site', { name: 'Cachify' });\nconst site = await cachify.kvs.read('site');\nconsole.log(site); // { name: 'Cachify' }\n```\n\nFile Caching\n\n```js\nconst filePath = 'path/to/file.txt';\n\n// Cache a file in the \"documents\" scope\nawait cachify.files.set(filePath, { scope: 'documents' });\n\n// Inspect file metadata\nconst fileRecord = cachify.files.inspect({ filePath, scope: 'documents' });\nconsole.log(fileRecord);\n\n// Read file content (status: \"miss\" if loaded from disk, \"hit\" if cached)\nconst readResult = await cachify.files.read({ filePath, scope: 'documents' });\nconsole.log(readResult);\n\n// Scopes are optional — caches in default \"global\" scope\nawait cachify.files.set(filePath);\n```\n\n**Notes:**\n- **Scopes are optional**; if omitted, the `\"global\"` scope is used.\n- Scopes allow logical separation of data without polluting record keys (e.g., `\"users\"`,`\"orders\"`, `\"documents\"`).\n- `kvs` is the plural API for key-value operations.\n- File caching separates **metadata** from **content**, which is loaded on read.\n- `storeIn` allows targeting multiple backends for redundancy, failover, or multi-region caching.\n  \n### 5. Persistence \u0026 Cold Start Recovery\nCachify supports persistent caching via adapters (e.g., local, S3) to backup and restore caches:\n```js\nimport path from 'path';\n\nconst backupName = 'cars';\nconst testFilePath = path.join(process.cwd(), 'test', 'sample.txt');\n\n// Register persistence adapters\ncachify.persistence.use('local', { path: process.cwd() });\n\n// Set some records\nawait cachify.kvs.set('a', 1);\nawait cachify.files.set(testFilePath);\n\n// Backup cache\nawait cachify.persistence.backup('local', backupName);\n\n// Clear memory\nawait cachify.clear();\n\n// Restore cache\nawait cachify.persistence.restore('local', backupName);\n\n// Access restored data\nconsole.log(await cachify.kvs.read('a')); // 1\nconst fileResponse = await cachify.files.read({ filePath: testFilePath });\nconsole.log(fileResponse); // { status: 'hit' | 'miss', content: Buffer }\n```\n\n**Notes:**\n- Backup saves all key-value and file caches to the configured persistence adapter.\n- Restore reloads all cached data, enabling fast recovery after cold starts.\n- Works with multiple cache flavors and storage backends.\n- Cloud adapters (e.g., S3) can be registered similarly to local adapters for persistent storage.\n\n### 6. Lock Sessions \u0026 Safe Concurrency\nCachify supports **lock sessions**, which allow you to safely acquire and modify cache records in concurrent environments.  \n\nA **session** ensures that only the session which acquires a record can **update** or **remove** it. By default, **reads are blocked** for records acquired by another session, but you can override this behavior with the `blockRead: false` policy.  \n\nSessions also support configurable **timeouts** to prevent records from being locked indefinitely, and the **exclusive** policy prevents other sessions from acquiring certain records at all.  \n\nBelow are short examples illustrating default and custom session behaviors.\n\n\n```ts\nimport cachify from '@nasriya/cachify';\n\nconst alice = { key: \"alice\", scope: \"users\" };\n\n// ------------------------\n// 1. Default timeout (10s)\n// ------------------------\nconst session1 = cachify.kvs.createLockSession();\nawait session1.acquire([alice]);\n// session1 will auto-release after 10 seconds if not released manually\nsession1.release();\n\n// ------------------------\n// 2. Infinite timeout\n// ------------------------\nconst session2 = cachify.kvs.createLockSession({ timeout: 0 });\nawait session2.acquire([alice]);\n// session2 will not expire automatically\nsession2.release();\n\n// ------------------------\n// 3. Custom timeout (5s)\n// ------------------------\nconst session3 = cachify.kvs.createLockSession({ timeout: 5000 });\nawait session3.acquire([alice]);\n// session3 will auto-release after 5 seconds if not released manually\nsession3.release();\n\n// ------------------------\n// 4. blockRead: false\n// ------------------------\nconst session4 = cachify.kvs.createLockSession({ policy: { blockRead: false } });\nawait session4.acquire([alice]);\n// Other sessions can read 'alice' even while session4 owns it\nsession4.release();\n\n// ------------------------\n// 5. Exclusive session\n// ------------------------\nconst session5 = cachify.kvs.createLockSession({ policy: { exclusive: true } });\nawait session5.acquire([alice]);\n// Any other session trying to acquire 'alice' will throw immediately\nsession5.release();\n```\n\n\u003e [!NOTE]\n\u003e For more detailed examples and usage patterns, check out the [Cachify Wiki](https://github.com/nasriyasoftware/Cachify/wiki).\n\n**Notes:**\n- `acquire(records)` ensures **exclusive write access**; only the session that acquires a record can `update` or `remove` it.\n- By default, **reads from other sessions are blocked** until the record is released. Use `policy.blockRead: false` to bypass this behavior.\n- The **exclusive** policy prevents other sessions from acquiring a record. Attempting to acquire an exclusive record throws an error.\n- Sessions have **timeouts** to prevent indefinite locking:\n  - Default: 10 seconds\n  - Custom: any positive number of milliseconds\n  - Infinite: set `timeout: 0`\n- Multiple sessions attempting to acquire the same record are **queued and served in order**.\n- **Release** a session to free its records for other sessions.\n\n#### Example Use Cases\n\n- **Basic concurrency:** session `S1` acquires record `A`; session `S2` waits to read or acquire until `S1` releases.\n- **Blocked reads:** session `S1` acquires a record; other sessions attempting to read will block unless `blockRead: false`.\n- **Exclusive records:** records marked as `exclusive` cannot be acquired by other sessions; attempting to do so throws an error.\n- **Timeouts:** session automatically releases records when its timeout expires; can be default (10s), custom, or infinite (`timeout: 0`).\n- **Safe writes:** only the session that acquired a record can `update` or `remove` it; other sessions attempting these operations will throw an error.\n\n___\n## Testing\nTo run Cachify tests locally, you need to create an environment file at `tests/setup/test.env`\n\n\n### Required Environment Variables\n\n- **Redis Testing**\n  - `REDIS_TEST_URL` — The URL of a Redis server for running tests.\n  - ⚠️ The Redis server will be flushed before tests start, so **do not use a production Redis instance**.\n\n- **Amazon S3 Persistence Testing (Optional)**\n  - `S3_TEST_BUCKET` — The bucket name to use for tests.\n  - `S3_TEST_REGION` — The AWS region of the bucket.\n  - `S3_TEST_KEY` — AWS access key ID.\n  - `S3_TEST_SECRET` — AWS secret access key.\n\n### Running Tests\n\nAfter creating and populating the env file, simply run:\n\n```bash\nnpm test\n```\n\n___\n\n## Benchmarking\n\nCachify provides a built-in benchmarking suite to measure the performance of key-value and file caching across different storage engines.\n\n### Environment Setup\n\nYou can optionally create an environment file at `benchmarks/benchmarks.env`. This file allows you to customize benchmark parameters. If it’s missing, Cachify will automatically fall back to safe defaults.\n\n### Optional Environment Variables\n\n- `BENCHMARK_KV_COUNT` — Number of key-value records to benchmark. Default: `100000`\n- `BENCHMARK_FILES_COUNT` — Number of file records to benchmark. Default: `1000`\n- `BENCHMARK_OUT_DIR` — Directory to store benchmark results. Default: `${process.cwd()}/cachify/benchmarks-results`\n- `REDIS_BENCHMARK_URL` — Redis connection URL to include Redis in the benchmarks.  \n  If omitted, all benchmarks will run in-memory only.\n\n\u003e [!WARNING]\n\u003e **Redis Safety Notice**  \n\u003e When `REDIS_BENCHMARK_URL` is defined, Cachify will **flush the Redis database** before starting the benchmarks to ensure accurate results.  \n\u003e \n\u003e ⚠️ **Never use a production Redis server for benchmarking!**  \n\u003e Use a dedicated or disposable Redis instance instead, as **all data will be permanently deleted**.\n\u003e \n### Running Benchmarks\n\nOnce ready, simply run:\n\n```bash\nnpm run benchmark\n```\n\nThis command runs the full benchmark suite and outputs performance results — including read/write throughput and engine comparison — to the directory defined in `BENCHMARK_OUT_DIR` (or the default if not set).\n___\n## License\nThis software is licensed under the **Nasriya Personal \u0026 Commercial License (NPCL)**, version 1.0.\nPlease read the license from [here](https://github.com/nasriyasoftware/Cachify?tab=License-1-ov-file).","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fnasriyasoftware%2Fcachify","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fnasriyasoftware%2Fcachify","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fnasriyasoftware%2Fcachify/lists"}