From 0d97da2e1025a0d9e9be75c76326b8bcbb84cc2d Mon Sep 17 00:00:00 2001 From: Jared Wray Date: Thu, 4 Apr 2024 22:36:44 -0700 Subject: [PATCH] initial mono repo changes (#656) * initial mono repo changes * Update test.yml * Create README.md --- .github/workflows/test.yml | 12 +- README.md | 292 +++--------------- package.json | 71 +---- packages/cache-manager/README.md | 276 +++++++++++++++++ .../cache-manager/READMEv4.md | 0 packages/cache-manager/package.json | 69 +++++ .../cache-manager/src}/caching.ts | 0 {src => packages/cache-manager/src}/index.ts | 0 .../cache-manager/src}/multi-caching.ts | 0 .../cache-manager/src}/stores/index.ts | 0 .../cache-manager/src}/stores/memory.ts | 0 .../cache-manager/test}/caching.test.ts | 0 .../cache-manager/test}/multi-caching.test.ts | 0 .../cache-manager/test}/stores/memory.test.ts | 0 .../cache-manager/test}/utils.ts | 0 .../cache-manager/tsconfig.build.json | 0 .../cache-manager/tsconfig.json | 0 .../cache-manager/vite.config.ts | 0 pnpm-workspace.yaml | 2 + 19 files changed, 413 insertions(+), 309 deletions(-) create mode 100644 packages/cache-manager/README.md rename READMEv4.md => packages/cache-manager/READMEv4.md (100%) create mode 100644 packages/cache-manager/package.json rename {src => packages/cache-manager/src}/caching.ts (100%) rename {src => packages/cache-manager/src}/index.ts (100%) rename {src => packages/cache-manager/src}/multi-caching.ts (100%) rename {src => packages/cache-manager/src}/stores/index.ts (100%) rename {src => packages/cache-manager/src}/stores/memory.ts (100%) rename {test => packages/cache-manager/test}/caching.test.ts (100%) rename {test => packages/cache-manager/test}/multi-caching.test.ts (100%) rename {test => packages/cache-manager/test}/stores/memory.test.ts (100%) rename {test => packages/cache-manager/test}/utils.ts (100%) rename tsconfig.build.json => packages/cache-manager/tsconfig.build.json (100%) rename tsconfig.json => packages/cache-manager/tsconfig.json (100%) rename vite.config.ts => packages/cache-manager/vite.config.ts (100%) create mode 100644 pnpm-workspace.yaml diff --git a/.github/workflows/test.yml b/.github/workflows/test.yml index 4cb74ab0..62502048 100644 --- a/.github/workflows/test.yml +++ b/.github/workflows/test.yml @@ -6,7 +6,6 @@ on: pull_request: branches: [ main ] - jobs: test: runs-on: ubuntu-latest @@ -21,18 +20,21 @@ jobs: uses: actions/setup-node@v3 with: node-version: ${{ matrix.node-version }} + + - name: Install pnpm + run: npm install -g pnpm - name: Install dependencies - run: npm install + run: pnpm install - name: Build - run: npm run build + run: pnpm build - name: Test - run: npm run test + run: pnpm test:ci - name: Codecov uses: codecov/codecov-action@v3 with: - files: ./coverage/coverage-final.json + files: ./coverage/lcov.info token: ${{ secrets.CODECOV_TOKEN }} diff --git a/README.md b/README.md index 2dd82bd2..eb135970 100644 --- a/README.md +++ b/README.md @@ -1,276 +1,82 @@ -# node-cache-manager -[![codecov](https://codecov.io/gh/node-cache-manager/cache-manager/branch/main/graph/badge.svg?token=ZV3G5IFigq)](https://codecov.io/gh/node-cache-manager/cache-manager) -[![tests](https://github.com/node-cache-manager/cache-manager/actions/workflows/test.yml/badge.svg)](https://github.com/node-cache-manager/cache-manager/actions/workflows/test.yml) -[![license](https://img.shields.io/github/license/node-cache-manager/cache-manager)](https://github.com/node-cache-manager/cache-manager/blob/main/LICENSE) -[![npm](https://img.shields.io/npm/dm/cache-manager)](https://npmjs.com/package/cache-manager) -![npm](https://img.shields.io/npm/v/cache-manager) +# Cache Manager -# Flexible NodeJS cache module +This is the cache manager mono repo that has the following packages: +* `cache-manager` - The core package that provides the cache manager library. +* `cache-manager-redis-yet` - The redis store for cache manager. +* `cache-manager-ioredis-yet` - The ioredis store for cache manager. -A cache module for nodejs that allows easy wrapping of functions in cache, tiered caches, and a consistent interface. +## Getting Started -## Table of Contents -* [Features](#features) -* [Installation](#installation) -* [Usage Examples](#usage-examples) - * [Single Store](#single-store) - * [Multi-Store](#multi-store) - * [Cache Manager Options](#cache-manager-options) - * [Refresh cache keys in background](#refresh-cache-keys-in-background) - * [Error Handling](#error-handling) - * [Store Engines](#store-engines) -* [Contribute](#contribute) -* [License](#license) +To get started you can visit the [cache-manager](/packages/cache-manager/README.md) package and learn how to use it. In addition here are some other documents: -## Features +* [CODE_OF_CONDUCT.md](CODE_OF_CONDUCT.md) - Our code of conduct +* [CONTRIBUTING.md](CONTRIBUTING.md) - How to contribute to this project +* [SECURITY.md](SECURITY.md) - Security guidelines and supported versions -- Made with Typescript and compatible with [ESModules](https://nodejs.org/docs/latest-v14.x/api/esm.html) -- Easy way to wrap any function in cache. -- Tiered caches -- data gets stored in each cache and fetched from the highest. - priority cache(s) first. -- Use any cache you want, as long as it has the same API. -- 100% test coverage via [vitest](https://github.com/vitest-dev/vitest). +## Getting Started with the Mono Repo -## Installation +Start by installing `pnpm` globally: - pnpm install cache-manager - -## Usage Examples - -### Single Store - -```typescript -import { caching } from 'cache-manager'; - -const memoryCache = await caching('memory', { - max: 100, - ttl: 10 * 1000 /*milliseconds*/, -}); - -const ttl = 5 * 1000; /*milliseconds*/ -await memoryCache.set('foo', 'bar', ttl); - -console.log(await memoryCache.get('foo')); -// >> "bar" - -await memoryCache.del('foo'); - -console.log(await memoryCache.get('foo')); -// >> undefined - -const getUser = (id: string) => new Promise.resolve({ id: id, name: 'Bob' }); - -const userId = 123; -const key = 'user_' + userId; - -console.log(await memoryCache.wrap(key, () => getUser(userId), ttl)); -// >> { id: 123, name: 'Bob' } -``` - -See unit tests in [`test/caching.test.ts`](./test/caching.test.ts) for more information. - -#### Example setting/getting several keys with mset() and mget() - -```typescript -await memoryCache.store.mset( - [ - ['foo', 'bar'], - ['foo2', 'bar2'], - ], - ttl, -); - -console.log(await memoryCache.store.mget('foo', 'foo2')); -// >> ['bar', 'bar2'] - -// Delete keys with mdel() passing arguments... -await memoryCache.store.mdel('foo', 'foo2'); -``` - -#### [Example Express App Usage](./examples/express/src/index.mts) - -#### Custom Stores - -You can use your own custom store by creating one with the same API as the built-in memory stores. - -- [Example Custom Store lru-cache](./src/stores/memory.ts) -- [Example Custom Store redis](https://github.com/node-cache-manager/node-cache-manager-redis-yet) -- [Example Custom Store ioredis](https://github.com/node-cache-manager/node-cache-manager-ioredis-yet) - -#### Create single cache store synchronously - -As `caching()` requires async functionality to resolve some stores, this is not well-suited to use for default function/constructor parameters etc. - -If you need to create a cache store synchronously, you can instead use `createCache()`: - -```typescript -import { createCache, memoryStore } from 'node-cache-manager'; - -// Create memory cache synchronously -const memoryCache = createCache(memoryStore(), { - max: 100, - ttl: 10 * 1000 /*milliseconds*/, -}); - -// Default parameter in function -function myService(cache = createCache(memoryStore())) {} - -// Default parameter in class constructor -const DEFAULT_CACHE = createCache(memoryStore(), { ttl: 60 * 1000 }); -// ... -class MyService { - constructor(private cache = DEFAULT_CACHE) {} -} -``` - -### Multi-Store - -```typescript -import { multiCaching } from 'cache-manager'; - -const multiCache = multiCaching([memoryCache, someOtherCache]); -const userId2 = 456; -const key2 = 'user_' + userId; -const ttl = 5; - -// Sets in all caches. -await multiCache.set('foo2', 'bar2', ttl); - -// Fetches from highest priority cache that has the key. -console.log(await multiCache.get('foo2')); -// >> "bar2" - -// Delete from all caches -await multiCache.del('foo2'); - -// Sets multiple keys in all caches. -// You can pass as many key, value tuples as you want -await multiCache.mset( - [ - ['foo', 'bar'], - ['foo2', 'bar2'], - ], - ttl -); - -// mget() fetches from highest priority cache. -// If the first cache does not return all the keys, -// the next cache is fetched with the keys that were not found. -// This is done recursively until either: -// - all have been found -// - all caches has been fetched -console.log(await multiCache.mget('key', 'key2')); -// >> ['bar', 'bar2'] - -// Delete keys with mdel() passing arguments... -await multiCache.mdel('foo', 'foo2'); +```bash +npm install -g pnpm ``` -See unit tests in [`test/multi-caching.test.ts`](./test/multi-caching.test.ts) for more information. - -### Cache Manager Options - -The `caching` and `multiCaching` functions accept an options object as the second parameter. The following options are available: -* max: The maximum number of items that can be stored in the cache. If the cache is full, the least recently used item is removed. -* ttl: The time to live in milliseconds. This is the maximum amount of time that an item can be in the cache before it is removed. -* shouldCloneBeforeSet: If true, the value will be cloned before being set in the cache. This is set to `true` by default. - -```typescript -import { caching } from 'cache-manager'; +Then install the dependencies: -const memoryCache = await caching('memory', { - max: 100, - ttl: 10 * 1000 /*milliseconds*/, - shouldCloneBeforeSet: false, // this is set true by default (optional) -}); +```bash +pnpm install ``` -### Refresh cache keys in background +To run the tests: -Both the `caching` and `multicaching` modules support a mechanism to refresh expiring cache keys in background when using the `wrap` function. -This is done by adding a `refreshThreshold` attribute while creating the caching store or passing it to the `wrap` function. - -If `refreshThreshold` is set and after retrieving a value from cache the TTL will be checked. -If the remaining TTL is less than `refreshThreshold`, the system will update the value asynchronously, -following same rules as standard fetching. In the meantime, the system will return the old value until expiration. - -NOTES: - -* In case of multicaching, the store that will be checked for refresh is the one where the key will be found first (highest priority). -* If the threshold is low and the worker function is slow, the key may expire and you may encounter a racing condition with updating values. -* The background refresh mechanism currently does not support providing multiple keys to `wrap` function. -* If no `ttl` is set for the key, the refresh mechanism will not be triggered. For redis, the `ttl` is set to -1 by default. - -For example, pass the refreshThreshold to `caching` like this: - -```typescript -const memoryCache = await caching('memory', { - max: 100, - ttl: 10 * 1000 /*milliseconds*/, - refreshThreshold: 3 * 1000 /*milliseconds*/, - - /* optional, but if not set, background refresh error will be an unhandled - * promise rejection, which might crash your node process */ - onBackgroundRefreshError: (error) => { /* log or otherwise handle error */ } -}); +```bash +pnpm test ``` -When a value will be retrieved from Redis with a TTL minor than 3sec, the value will be updated in the background. - -## Error Handling - -Cache Manager now does not throw errors by default. Instead, all errors are evented through the `error` event. Here is an example on how to use it: +To build the packages: -```javascript -const memoryCache = await caching('memory', { - max: 100, - ttl: 10 * 1000 /*milliseconds*/, -}); -memoryCache.on('error', (error) => { - console.error('Cache error:', error); -}); +```bash +pnpm build ``` -## Store Engines +## Open a Pull Request -### Official and updated to last version +You can contribute changes to this repo by opening a pull request: -- [node-cache-manager-redis-yet](https://github.com/node-cache-manager/node-cache-manager-redis-yet) (uses [node_redis](https://github.com/NodeRedis/node_redis)) +1) After forking this repository to your Git account, make the proposed changes on your forked branch. +2) Run tests and linting locally. + - [Install and run Docker](https://docs.docker.com/get-docker/) if you aren't already. + - Run `pnpm test:services:start`, allow for the services to come up. + - Run `pnpm test`. +3) Commit your changes and push them to your forked repository. +4) Navigate to the main `cache-manager` repository and select the *Pull Requests* tab. +5) Click the *New pull request* button, then select the option "Compare across forks" +6) Leave the base branch set to main. Set the compare branch to your forked branch, and open the pull request. +7) Once your pull request is created, ensure that all checks have passed and that your branch has no conflicts with the base branch. If there are any issues, resolve these changes in your local repository, and then commit and push them to git. +8) Similarly, respond to any reviewer comments or requests for changes by making edits to your local repository and pushing them to Git. +9) Once the pull request has been reviewed, those with write access to the branch will be able to merge your changes into the `cache-manager` repository. -- [node-cache-manager-ioredis-yet](https://github.com/node-cache-manager/node-cache-manager-ioredis-yet) (uses [ioredis](https://github.com/luin/ioredis)) +If you need more information on the steps to create a pull request, you can find a detailed walkthrough in the [Github documentation](https://docs.github.com/en/pull-requests/collaborating-with-pull-requests/proposing-changes-to-your-work-with-pull-requests/creating-a-pull-request-from-a-fork) -### Third party +## Post an Issue -- [node-cache-manager-redis](https://github.com/dial-once/node-cache-manager-redis) (uses [sol-redis-pool](https://github.com/joshuah/sol-redis-pool)) +To post an issue, navigate to the "Issues" tab in the main repository, and then select "New Issue." Enter a clear title describing the issue, as well as a description containing additional relevant information. Also select the label that best describes your issue type. For a bug report, for example, create an issue with the label "bug." In the description field, Be sure to include replication steps, as well as any relevant error messages. -- [node-cache-manager-redis-store](https://github.com/dabroek/node-cache-manager-redis-store) (uses [node_redis](https://github.com/NodeRedis/node_redis)) +If you're reporting a security violation, be sure to check out the project's [security policy](SECURITY.md). -- [node-cache-manager-ioredis](https://github.com/Tirke/node-cache-manager-ioredis) (uses [ioredis](https://github.com/luin/ioredis)) +Please also refer to our [Code of Conduct](CODE_OF_CONDUCT.md) for more information on how to report issues. -- [node-cache-manager-mongodb](https://github.com/v4l3r10/node-cache-manager-mongodb) +## Ask a Question -- [node-cache-manager-mongoose](https://github.com/disjunction/node-cache-manager-mongoose) +To ask a question, create an issue with the label "question." In the issue description, include the related code and any context that can help us answer your question. -- [node-cache-manager-fs-binary](https://github.com/sheershoff/node-cache-manager-fs-binary) +## Request the Addition of a Storage Adapter -- [node-cache-manager-fs-hash](https://github.com/rolandstarke/node-cache-manager-fs-hash) +To request a new storage adapter, create an issue with the label "storage adapter." In the issue description, include any relevant information about the storage adapter that you would like to be added. -- [node-cache-manager-hazelcast](https://github.com/marudor/node-cache-manager-hazelcast) +Once this request has been submitted in "issues" we will give it 30-60 days for any upvotes to take place. If there is little interest in the request, it will be closed. -- [node-cache-manager-memcached-store](https://github.com/theogravity/node-cache-manager-memcached-store) - -- [node-cache-manager-memory-store](https://github.com/theogravity/node-cache-manager-memory-store) - -- [node-cache-manager-couchbase](https://github.com/davidepellegatta/node-cache-manager-couchbase) - -- [node-cache-manager-sqlite](https://github.com/maxpert/node-cache-manager-sqlite) - -- [@resolid/cache-manager-sqlite](https://github.com/huijiewei/cache-manager-sqlite) (uses [better-sqlite3](https://github.com/WiseLibs/better-sqlite3)) - -## Contribute - -If you would like to contribute to the project, please read how to contribute here [CONTRIBUTING.md](./CONTRIBUTING.md). +If there is already an adapter that you would like to add, please post an issue with the label "storage adapter" and include the name of the adapter you would like to add with the description and any relevant information. ## License - -cache-manager is licensed under the [MIT license](./LICENSE). +MIT [LISCENCE](LICENSE) diff --git a/package.json b/package.json index f4cd9cad..bc3bf2e1 100644 --- a/package.json +++ b/package.json @@ -1,68 +1,17 @@ { - "name": "cache-manager", - "version": "5.5.0", - "description": "Cache module for Node.js", - "main": "dist/index.js", - "types": "dist/index.d.ts", - "files": [ - "dist/**/*.js", - "dist/**/*.d.ts" - ], + "name": "cache-manager-mono-repo", + "version": "1.0.0", + "description": "Cache Manager Mono Repo", "scripts": { - "build": "rimraf dist && tsc -p tsconfig.build.json", - "clean": "rimraf ./dist ./coverage ./node_modules ./package-lock.json ./yarn.lock ./pnpm-lock.yaml", - "test": "xo --fix && vitest run --coverage", - "prepare": "npm run build" + "test": "pnpm recursive run test", + "test:ci": "c8 --reporter=lcov pnpm recursive run test:ci", + "build": "pnpm recursive run build", + "clean": "pnpm recursive run clean" }, - "repository": { - "type": "git", - "url": "https://github.com/node-cache-manager/cache-manager.git" - }, - "keywords": [ - "cache", - "redis", - "lru-cache", - "memory cache", - "multiple cache" - ], - "authors": [ - { - "name": "Jared Wray", - "email": "me@jaredwray.com" - }, - { - "name": "Bryan Donovan" - }, - { - "name": "Juan Aguilar Santillana", - "email": "mhpoin@gmail.com" - } - ], + "keywords": [], + "author": "Jared Wray ", "license": "MIT", - "dependencies": { - "eventemitter3": "^5.0.1", - "lodash.clonedeep": "^4.5.0", - "lru-cache": "^10.2.0", - "promise-coalesce": "^1.1.2" - }, "devDependencies": { - "@faker-js/faker": "^8.4.1", - "@types/lodash.clonedeep": "^4.5.9", - "@types/node": "^20.11.30", - "@typescript-eslint/eslint-plugin": "^7.4.0", - "@typescript-eslint/parser": "^7.4.0", - "@vitest/coverage-v8": "^1.4.0", - "eslint-config-xo-typescript": "^4.0.0", - "rimraf": "^5.0.5", - "typescript": "^5.4.3", - "vitest": "^1.4.0", - "xo": "^0.58.0" - }, - "xo": { - "extends": "xo-typescript", - "extensions": [ - "ts", - "tsx" - ] + "c8": "^9.1.0" } } diff --git a/packages/cache-manager/README.md b/packages/cache-manager/README.md new file mode 100644 index 00000000..2dd82bd2 --- /dev/null +++ b/packages/cache-manager/README.md @@ -0,0 +1,276 @@ +# node-cache-manager +[![codecov](https://codecov.io/gh/node-cache-manager/cache-manager/branch/main/graph/badge.svg?token=ZV3G5IFigq)](https://codecov.io/gh/node-cache-manager/cache-manager) +[![tests](https://github.com/node-cache-manager/cache-manager/actions/workflows/test.yml/badge.svg)](https://github.com/node-cache-manager/cache-manager/actions/workflows/test.yml) +[![license](https://img.shields.io/github/license/node-cache-manager/cache-manager)](https://github.com/node-cache-manager/cache-manager/blob/main/LICENSE) +[![npm](https://img.shields.io/npm/dm/cache-manager)](https://npmjs.com/package/cache-manager) +![npm](https://img.shields.io/npm/v/cache-manager) + +# Flexible NodeJS cache module + +A cache module for nodejs that allows easy wrapping of functions in cache, tiered caches, and a consistent interface. + +## Table of Contents +* [Features](#features) +* [Installation](#installation) +* [Usage Examples](#usage-examples) + * [Single Store](#single-store) + * [Multi-Store](#multi-store) + * [Cache Manager Options](#cache-manager-options) + * [Refresh cache keys in background](#refresh-cache-keys-in-background) + * [Error Handling](#error-handling) + * [Store Engines](#store-engines) +* [Contribute](#contribute) +* [License](#license) + +## Features + +- Made with Typescript and compatible with [ESModules](https://nodejs.org/docs/latest-v14.x/api/esm.html) +- Easy way to wrap any function in cache. +- Tiered caches -- data gets stored in each cache and fetched from the highest. + priority cache(s) first. +- Use any cache you want, as long as it has the same API. +- 100% test coverage via [vitest](https://github.com/vitest-dev/vitest). + +## Installation + + pnpm install cache-manager + +## Usage Examples + +### Single Store + +```typescript +import { caching } from 'cache-manager'; + +const memoryCache = await caching('memory', { + max: 100, + ttl: 10 * 1000 /*milliseconds*/, +}); + +const ttl = 5 * 1000; /*milliseconds*/ +await memoryCache.set('foo', 'bar', ttl); + +console.log(await memoryCache.get('foo')); +// >> "bar" + +await memoryCache.del('foo'); + +console.log(await memoryCache.get('foo')); +// >> undefined + +const getUser = (id: string) => new Promise.resolve({ id: id, name: 'Bob' }); + +const userId = 123; +const key = 'user_' + userId; + +console.log(await memoryCache.wrap(key, () => getUser(userId), ttl)); +// >> { id: 123, name: 'Bob' } +``` + +See unit tests in [`test/caching.test.ts`](./test/caching.test.ts) for more information. + +#### Example setting/getting several keys with mset() and mget() + +```typescript +await memoryCache.store.mset( + [ + ['foo', 'bar'], + ['foo2', 'bar2'], + ], + ttl, +); + +console.log(await memoryCache.store.mget('foo', 'foo2')); +// >> ['bar', 'bar2'] + +// Delete keys with mdel() passing arguments... +await memoryCache.store.mdel('foo', 'foo2'); +``` + +#### [Example Express App Usage](./examples/express/src/index.mts) + +#### Custom Stores + +You can use your own custom store by creating one with the same API as the built-in memory stores. + +- [Example Custom Store lru-cache](./src/stores/memory.ts) +- [Example Custom Store redis](https://github.com/node-cache-manager/node-cache-manager-redis-yet) +- [Example Custom Store ioredis](https://github.com/node-cache-manager/node-cache-manager-ioredis-yet) + +#### Create single cache store synchronously + +As `caching()` requires async functionality to resolve some stores, this is not well-suited to use for default function/constructor parameters etc. + +If you need to create a cache store synchronously, you can instead use `createCache()`: + +```typescript +import { createCache, memoryStore } from 'node-cache-manager'; + +// Create memory cache synchronously +const memoryCache = createCache(memoryStore(), { + max: 100, + ttl: 10 * 1000 /*milliseconds*/, +}); + +// Default parameter in function +function myService(cache = createCache(memoryStore())) {} + +// Default parameter in class constructor +const DEFAULT_CACHE = createCache(memoryStore(), { ttl: 60 * 1000 }); +// ... +class MyService { + constructor(private cache = DEFAULT_CACHE) {} +} +``` + +### Multi-Store + +```typescript +import { multiCaching } from 'cache-manager'; + +const multiCache = multiCaching([memoryCache, someOtherCache]); +const userId2 = 456; +const key2 = 'user_' + userId; +const ttl = 5; + +// Sets in all caches. +await multiCache.set('foo2', 'bar2', ttl); + +// Fetches from highest priority cache that has the key. +console.log(await multiCache.get('foo2')); +// >> "bar2" + +// Delete from all caches +await multiCache.del('foo2'); + +// Sets multiple keys in all caches. +// You can pass as many key, value tuples as you want +await multiCache.mset( + [ + ['foo', 'bar'], + ['foo2', 'bar2'], + ], + ttl +); + +// mget() fetches from highest priority cache. +// If the first cache does not return all the keys, +// the next cache is fetched with the keys that were not found. +// This is done recursively until either: +// - all have been found +// - all caches has been fetched +console.log(await multiCache.mget('key', 'key2')); +// >> ['bar', 'bar2'] + +// Delete keys with mdel() passing arguments... +await multiCache.mdel('foo', 'foo2'); +``` + +See unit tests in [`test/multi-caching.test.ts`](./test/multi-caching.test.ts) for more information. + +### Cache Manager Options + +The `caching` and `multiCaching` functions accept an options object as the second parameter. The following options are available: +* max: The maximum number of items that can be stored in the cache. If the cache is full, the least recently used item is removed. +* ttl: The time to live in milliseconds. This is the maximum amount of time that an item can be in the cache before it is removed. +* shouldCloneBeforeSet: If true, the value will be cloned before being set in the cache. This is set to `true` by default. + +```typescript +import { caching } from 'cache-manager'; + +const memoryCache = await caching('memory', { + max: 100, + ttl: 10 * 1000 /*milliseconds*/, + shouldCloneBeforeSet: false, // this is set true by default (optional) +}); +``` + +### Refresh cache keys in background + +Both the `caching` and `multicaching` modules support a mechanism to refresh expiring cache keys in background when using the `wrap` function. +This is done by adding a `refreshThreshold` attribute while creating the caching store or passing it to the `wrap` function. + +If `refreshThreshold` is set and after retrieving a value from cache the TTL will be checked. +If the remaining TTL is less than `refreshThreshold`, the system will update the value asynchronously, +following same rules as standard fetching. In the meantime, the system will return the old value until expiration. + +NOTES: + +* In case of multicaching, the store that will be checked for refresh is the one where the key will be found first (highest priority). +* If the threshold is low and the worker function is slow, the key may expire and you may encounter a racing condition with updating values. +* The background refresh mechanism currently does not support providing multiple keys to `wrap` function. +* If no `ttl` is set for the key, the refresh mechanism will not be triggered. For redis, the `ttl` is set to -1 by default. + +For example, pass the refreshThreshold to `caching` like this: + +```typescript +const memoryCache = await caching('memory', { + max: 100, + ttl: 10 * 1000 /*milliseconds*/, + refreshThreshold: 3 * 1000 /*milliseconds*/, + + /* optional, but if not set, background refresh error will be an unhandled + * promise rejection, which might crash your node process */ + onBackgroundRefreshError: (error) => { /* log or otherwise handle error */ } +}); +``` + +When a value will be retrieved from Redis with a TTL minor than 3sec, the value will be updated in the background. + +## Error Handling + +Cache Manager now does not throw errors by default. Instead, all errors are evented through the `error` event. Here is an example on how to use it: + +```javascript +const memoryCache = await caching('memory', { + max: 100, + ttl: 10 * 1000 /*milliseconds*/, +}); +memoryCache.on('error', (error) => { + console.error('Cache error:', error); +}); +``` + +## Store Engines + +### Official and updated to last version + +- [node-cache-manager-redis-yet](https://github.com/node-cache-manager/node-cache-manager-redis-yet) (uses [node_redis](https://github.com/NodeRedis/node_redis)) + +- [node-cache-manager-ioredis-yet](https://github.com/node-cache-manager/node-cache-manager-ioredis-yet) (uses [ioredis](https://github.com/luin/ioredis)) + +### Third party + +- [node-cache-manager-redis](https://github.com/dial-once/node-cache-manager-redis) (uses [sol-redis-pool](https://github.com/joshuah/sol-redis-pool)) + +- [node-cache-manager-redis-store](https://github.com/dabroek/node-cache-manager-redis-store) (uses [node_redis](https://github.com/NodeRedis/node_redis)) + +- [node-cache-manager-ioredis](https://github.com/Tirke/node-cache-manager-ioredis) (uses [ioredis](https://github.com/luin/ioredis)) + +- [node-cache-manager-mongodb](https://github.com/v4l3r10/node-cache-manager-mongodb) + +- [node-cache-manager-mongoose](https://github.com/disjunction/node-cache-manager-mongoose) + +- [node-cache-manager-fs-binary](https://github.com/sheershoff/node-cache-manager-fs-binary) + +- [node-cache-manager-fs-hash](https://github.com/rolandstarke/node-cache-manager-fs-hash) + +- [node-cache-manager-hazelcast](https://github.com/marudor/node-cache-manager-hazelcast) + +- [node-cache-manager-memcached-store](https://github.com/theogravity/node-cache-manager-memcached-store) + +- [node-cache-manager-memory-store](https://github.com/theogravity/node-cache-manager-memory-store) + +- [node-cache-manager-couchbase](https://github.com/davidepellegatta/node-cache-manager-couchbase) + +- [node-cache-manager-sqlite](https://github.com/maxpert/node-cache-manager-sqlite) + +- [@resolid/cache-manager-sqlite](https://github.com/huijiewei/cache-manager-sqlite) (uses [better-sqlite3](https://github.com/WiseLibs/better-sqlite3)) + +## Contribute + +If you would like to contribute to the project, please read how to contribute here [CONTRIBUTING.md](./CONTRIBUTING.md). + +## License + +cache-manager is licensed under the [MIT license](./LICENSE). diff --git a/READMEv4.md b/packages/cache-manager/READMEv4.md similarity index 100% rename from READMEv4.md rename to packages/cache-manager/READMEv4.md diff --git a/packages/cache-manager/package.json b/packages/cache-manager/package.json new file mode 100644 index 00000000..c2df9386 --- /dev/null +++ b/packages/cache-manager/package.json @@ -0,0 +1,69 @@ +{ + "name": "cache-manager", + "version": "5.5.0", + "description": "Cache module for Node.js", + "main": "dist/index.js", + "types": "dist/index.d.ts", + "files": [ + "dist/**/*.js", + "dist/**/*.d.ts" + ], + "scripts": { + "build": "rimraf dist && tsc -p tsconfig.build.json", + "clean": "rimraf ./dist ./coverage ./node_modules ./package-lock.json ./yarn.lock ./pnpm-lock.yaml", + "test": "xo --fix && vitest run --coverage", + "test:ci": "xo --fix && vitest run", + "prepare": "npm run build" + }, + "repository": { + "type": "git", + "url": "https://github.com/node-cache-manager/cache-manager.git" + }, + "keywords": [ + "cache", + "redis", + "lru-cache", + "memory cache", + "multiple cache" + ], + "authors": [ + { + "name": "Jared Wray", + "email": "me@jaredwray.com" + }, + { + "name": "Bryan Donovan" + }, + { + "name": "Juan Aguilar Santillana", + "email": "mhpoin@gmail.com" + } + ], + "license": "MIT", + "dependencies": { + "eventemitter3": "^5.0.1", + "lodash.clonedeep": "^4.5.0", + "lru-cache": "^10.2.0", + "promise-coalesce": "^1.1.2" + }, + "devDependencies": { + "@faker-js/faker": "^8.4.1", + "@types/lodash.clonedeep": "^4.5.9", + "@types/node": "^20.11.30", + "@typescript-eslint/eslint-plugin": "^7.4.0", + "@typescript-eslint/parser": "^7.4.0", + "@vitest/coverage-v8": "^1.4.0", + "eslint-config-xo-typescript": "^4.0.0", + "rimraf": "^5.0.5", + "typescript": "^5.4.3", + "vitest": "^1.4.0", + "xo": "^0.58.0" + }, + "xo": { + "extends": "xo-typescript", + "extensions": [ + "ts", + "tsx" + ] + } +} diff --git a/src/caching.ts b/packages/cache-manager/src/caching.ts similarity index 100% rename from src/caching.ts rename to packages/cache-manager/src/caching.ts diff --git a/src/index.ts b/packages/cache-manager/src/index.ts similarity index 100% rename from src/index.ts rename to packages/cache-manager/src/index.ts diff --git a/src/multi-caching.ts b/packages/cache-manager/src/multi-caching.ts similarity index 100% rename from src/multi-caching.ts rename to packages/cache-manager/src/multi-caching.ts diff --git a/src/stores/index.ts b/packages/cache-manager/src/stores/index.ts similarity index 100% rename from src/stores/index.ts rename to packages/cache-manager/src/stores/index.ts diff --git a/src/stores/memory.ts b/packages/cache-manager/src/stores/memory.ts similarity index 100% rename from src/stores/memory.ts rename to packages/cache-manager/src/stores/memory.ts diff --git a/test/caching.test.ts b/packages/cache-manager/test/caching.test.ts similarity index 100% rename from test/caching.test.ts rename to packages/cache-manager/test/caching.test.ts diff --git a/test/multi-caching.test.ts b/packages/cache-manager/test/multi-caching.test.ts similarity index 100% rename from test/multi-caching.test.ts rename to packages/cache-manager/test/multi-caching.test.ts diff --git a/test/stores/memory.test.ts b/packages/cache-manager/test/stores/memory.test.ts similarity index 100% rename from test/stores/memory.test.ts rename to packages/cache-manager/test/stores/memory.test.ts diff --git a/test/utils.ts b/packages/cache-manager/test/utils.ts similarity index 100% rename from test/utils.ts rename to packages/cache-manager/test/utils.ts diff --git a/tsconfig.build.json b/packages/cache-manager/tsconfig.build.json similarity index 100% rename from tsconfig.build.json rename to packages/cache-manager/tsconfig.build.json diff --git a/tsconfig.json b/packages/cache-manager/tsconfig.json similarity index 100% rename from tsconfig.json rename to packages/cache-manager/tsconfig.json diff --git a/vite.config.ts b/packages/cache-manager/vite.config.ts similarity index 100% rename from vite.config.ts rename to packages/cache-manager/vite.config.ts diff --git a/pnpm-workspace.yaml b/pnpm-workspace.yaml new file mode 100644 index 00000000..4340350e --- /dev/null +++ b/pnpm-workspace.yaml @@ -0,0 +1,2 @@ +packages: + - 'packages/*' \ No newline at end of file