Skip to content

Update deps (use lru-cache@11). #14

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 3 commits into from
May 22, 2025
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
89 changes: 45 additions & 44 deletions .github/workflows/main.yml
Original file line number Diff line number Diff line change
Expand Up @@ -8,66 +8,67 @@ jobs:
timeout-minutes: 10
strategy:
matrix:
node-version: [20.x]
node-version: [22.x]
steps:
- uses: actions/checkout@v2
- name: Use Node.js ${{ matrix.node-version }}
uses: actions/setup-node@v1
with:
node-version: ${{ matrix.node-version }}
- run: npm install
- name: Run eslint
run: npm run lint
- uses: actions/checkout@v4
- name: Use Node.js ${{ matrix.node-version }}
uses: actions/setup-node@v4
with:
node-version: ${{ matrix.node-version }}
- run: npm install
- name: Run eslint
run: npm run lint
test-node:
needs: lint
needs: [lint]
runs-on: ubuntu-latest
timeout-minutes: 10
strategy:
matrix:
node-version: [16.x, 18.x, 20.x]
node-version: [20.x, 22.x]
steps:
- uses: actions/checkout@v2
- name: Use Node.js ${{ matrix.node-version }}
uses: actions/setup-node@v1
with:
node-version: ${{ matrix.node-version }}
- run: npm install
- name: Run test with Node.js ${{ matrix.node-version }}
run: npm run test-node
- uses: actions/checkout@v4
- name: Use Node.js ${{ matrix.node-version }}
uses: actions/setup-node@v4
with:
node-version: ${{ matrix.node-version }}
- run: npm install
- name: Run tests with Node.js ${{ matrix.node-version }}
run: npm run test-node
test-karma:
needs: lint
needs: [lint]
runs-on: ubuntu-latest
timeout-minutes: 10
strategy:
matrix:
node-version: [20.x]
node-version: [22.x]
steps:
- uses: actions/checkout@v2
- name: Use Node.js ${{ matrix.node-version }}
uses: actions/setup-node@v1
with:
node-version: ${{ matrix.node-version }}
- run: npm install
- name: Run karma tests
run: npm run test-karma
- uses: actions/checkout@v4
- name: Use Node.js ${{ matrix.node-version }}
uses: actions/setup-node@v4
with:
node-version: ${{ matrix.node-version }}
- run: npm install
- name: Run karma tests
run: npm run test-karma
coverage:
needs: [test-node, test-karma]
runs-on: ubuntu-latest
timeout-minutes: 10
runs-on: ubuntu-latest
strategy:
matrix:
node-version: [20.x]
node-version: [22.x]
steps:
- uses: actions/checkout@v2
- name: Use Node.js ${{ matrix.node-version }}
uses: actions/setup-node@v1
with:
node-version: ${{ matrix.node-version }}
- run: npm install
- name: Generate coverage report
run: npm run coverage-ci
- name: Upload coverage to Codecov
uses: codecov/codecov-action@v2
with:
file: ./coverage/lcov.info
fail_ci_if_error: true
- uses: actions/checkout@v4
- name: Use Node.js ${{ matrix.node-version }}
uses: actions/setup-node@v4
with:
node-version: ${{ matrix.node-version }}
- run: npm install
- name: Generate coverage report
run: npm run coverage-ci
- name: Upload coverage to Codecov
uses: codecov/codecov-action@v4
with:
file: ./coverage/lcov.info
fail_ci_if_error: true
token: ${{ secrets.CODECOV_TOKEN }}
14 changes: 14 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,5 +1,19 @@
# @digitalbazaar/lru-memoize ChangeLog

## 4.0.0 - 2025-mm-dd

### Changed
- **BREAKING**: Use `lru-cache@11`. This replaces `lru-cache@6` which has a
number of breaking changes that impact any use of this library that
previously accessed the underlying cache interface. The main interface
of this module has only changed in that the options it accepts when
creating the cache need to now conform to v11 of `lru-cache` instead of
v6. The v6 `maxAge` option, if given, will be coerced to `ttl` to match
v11.
- **BREAKING**: The `delete()` method now returns `true` if the passed key was
removed from the cache and `false` if not, matching the v11 `delete()`
interface. Previously, `undefined` was returned in both cases.

## 3.0.2 - 2023-08-27

### Fixed
Expand Down
39 changes: 25 additions & 14 deletions lib/LruCache.js
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
/*!
* Copyright (c) 2020-2023 Digital Bazaar, Inc. All rights reserved.
* Copyright (c) 2020-2025 Digital Bazaar, Inc. All rights reserved.
*/
import LRU from 'lru-cache';
import {LRUCache as LRU} from 'lru-cache';

/**
* LruCache uses the npm module `lru-cache` to memoize promises.
Expand All @@ -10,8 +10,15 @@ import LRU from 'lru-cache';
* @see https://en.wikipedia.org/wiki/Memoization
* @param {object} cacheOptions - Options for `lru-cache`.
* See the npm docs for more options.
* @param {number} [cacheOptions.max] - The max size of the cache.
* @param {number} [cacheOptions.maxAge] - The maxAge of an item in ms.
* @param {number} [cacheOptions.max=1000] - The max number of items in the
* cache. If no `max` is specified and no `maxSize` is specified, then `max`
* will default to `1000`, ensuring the cache is bounded.
* @param {number} [cacheOptions.maxSize] - An optional max size for the cache;
* if provided, then the size of each item must be calculated via a provided
* `sizeCalculation` function.
* @param {number} [cacheOptions.ttl] - The time-to-live of an item in ms.
* @param {Function} [cacheOptions.sizeCalculation] - A function that will
* calculate the size of an item; see lru-cache documentation.
* @param {boolean} [cacheOptions.updateAgeOnGet=false] - When using
* time-expiring entries with maxAge, setting this to true will make
* each entry's effective time update to the current time whenever it is
Expand All @@ -23,9 +30,13 @@ import LRU from 'lru-cache';
* @returns {LruCache} The class.
*/
export class LruCache {
constructor(cacheOptions = {}) {
this.options = cacheOptions;
this.cache = new LRU(cacheOptions);
constructor(cacheOptions = {max: 1000}) {
if(cacheOptions.maxAge !== undefined) {
throw new TypeError(
'"cacheOptions.maxAge" is no longer supported; use "ttl" instead.');
}
this.options = {max: 1000, ...cacheOptions};
this.cache = new LRU(this.options);
}

/**
Expand All @@ -36,7 +47,7 @@ export class LruCache {
* @returns {undefined}
*/
delete(key) {
return this.cache.del(key);
return this.cache.delete(key);
}

/**
Expand All @@ -61,24 +72,24 @@ export class LruCache {
// cache miss
const cacheOptions = {...this.options, ...options};
promise = fn();
// this version only supports `maxAge` and `disposeOnSettle`; a future
// version will support more cache options
const {maxAge} = cacheOptions;
this.cache.set(key, promise, maxAge);
// this version only supports passing `ttl` through to the underlying
// lru-cache instance; a future version will support more cache options
const {ttl} = cacheOptions;
this.cache.set(key, promise, {ttl});

try {
await promise;
} catch(e) {
// if the promise rejects, delete it if the cache entry hasn't changed
if(promise === this.cache.get(key)) {
this.cache.del(key);
this.cache.delete(key);
}
throw e;
}

// dispose promise once settled (provided the cache entry hasn't changed)
if(cacheOptions.disposeOnSettle && promise === this.cache.get(key)) {
this.cache.del(key);
this.cache.delete(key);
}

return promise;
Expand Down
16 changes: 8 additions & 8 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -18,25 +18,25 @@
"lint": "eslint ."
},
"dependencies": {
"lru-cache": "^6.0.0"
"lru-cache": "^11.1.0"
},
"devDependencies": {
"c8": "^7.11.3",
"chai": "^4.3.6",
"c8": "^10.1.3",
"chai": "^4.5.0",
"cross-env": "^7.0.3",
"delay": "^5.0.0",
"delay": "^6.0.0",
"eslint": "^8.48.0",
"eslint-config-digitalbazaar": "^5.0.1",
"eslint-plugin-jsdoc": "^46.5.0",
"eslint-plugin-unicorn": "^48.0.1",
"eslint-plugin-jsdoc": "^50.6.17",
"eslint-plugin-unicorn": "^56.0.1",
"karma": "^6.3.20",
"karma-chai": "^0.1.0",
"karma-chrome-launcher": "^3.1.1",
"karma-mocha": "^2.0.1",
"karma-mocha-reporter": "^2.2.5",
"karma-sourcemap-loader": "^0.3.8",
"karma-sourcemap-loader": "^0.4.0",
"karma-webpack": "^5.0.0",
"mocha": "^10.0.0",
"mocha": "^11.4.0",
"mocha-lcov-reporter": "^1.3.0",
"webpack": "^5.72.1"
},
Expand Down
21 changes: 12 additions & 9 deletions tests/10-api.spec.js
Original file line number Diff line number Diff line change
@@ -1,13 +1,13 @@
/*!
* Copyright (c) 2020-2023 Digital Bazaar, Inc. All rights reserved.
* Copyright (c) 2020-2025 Digital Bazaar, Inc. All rights reserved.
*/
import delay from 'delay';
import {LruCache} from '../lib/index.js';

describe('API', () => {
it('has the proper exports', async () => {
should.exist(LruCache);
const m = new LruCache();
const m = new LruCache({ttl: 10});
should.exist(m);
m.memoize.should.be.a('function');
});
Expand Down Expand Up @@ -40,7 +40,7 @@ describe('API', () => {
result2.should.eql(result);
executedTestFn.should.be.false;
});
it('adds an item to the cache w/custom `maxAge`', async () => {
it('adds an item to the cache w/custom `ttl`', async () => {
const m = new LruCache();
let executedTestFn = false;
const testFn = async () => {
Expand All @@ -49,11 +49,11 @@ describe('API', () => {
executedTestFn = true;
return {success: true, timestamp: Date.now()};
};
const maxAge = 200;
const ttl = 200;
const result = await m.memoize({
key: 'test1',
fn: testFn,
options: {maxAge}
options: {ttl}
});
should.exist(result);
result.success.should.be.true;
Expand All @@ -71,7 +71,7 @@ describe('API', () => {
executedTestFn.should.be.false;

// third test should not find the expired result
await delay(maxAge + 1);
await delay(ttl + 1);
executedTestFn = false;
const result3 = await m.memoize({
key: 'test1',
Expand Down Expand Up @@ -114,9 +114,12 @@ describe('API', () => {
executedTestFn.should.be.false;

// delete the cached promise
const r = m.delete('test1');
// always returns undefined
should.not.exist(r);
const deleted1 = m.delete('test1');
// should return `true` because `test1` was removed
deleted1.should.equal(true);
// should now return `false` because `test1` was already removed
const deleted2 = m.delete('test1');
deleted2.should.equal(false);

// after deleting the cache entry, testFn should be executed producing
// a result with a new timestamp
Expand Down