From ec940286975321e95c9d927b96c7bdc1575ff2d3 Mon Sep 17 00:00:00 2001 From: Michael Di Prisco Date: Mon, 16 Jan 2023 11:36:53 +0100 Subject: [PATCH 1/6] chore: keepAliveTimeoutCache changed to timeFrameTimeoutCache --- src/internal.ts | 34 +++++++++++++++++----------------- src/lib.ts | 8 ++++---- src/models.ts | 2 +- 3 files changed, 22 insertions(+), 22 deletions(-) diff --git a/src/internal.ts b/src/internal.ts index 9948313..38eda06 100644 --- a/src/internal.ts +++ b/src/internal.ts @@ -4,7 +4,7 @@ import { cacheCandidateDependencyManager } from './manager'; import { CacheCandidateOptions, Events, - KeepAliveCache, + TimeFrameTimeoutCache, RunningQueryCache, TimeFrameCache } from './models'; @@ -111,7 +111,7 @@ function handleResult({ executionStart, options, timeframeCache, - keepAliveTimeoutCache, + timeFrameTimeoutCache, args }: { result: unknown; @@ -120,7 +120,7 @@ function handleResult({ executionStart: number; options: CacheCandidateOptions; timeframeCache: TimeFrameCache; - keepAliveTimeoutCache: KeepAliveCache; + timeFrameTimeoutCache: TimeFrameTimeoutCache; args: any[]; }): any { const executionEnd = Date.now(); @@ -159,7 +159,7 @@ function handleResult({ }) .finally(() => { runningQueryCache.delete(key); - keepAliveTimeoutCache.set( + timeFrameTimeoutCache.set( key, setTimeout(() => { deleteDataCacheRecord({ options, key }); @@ -255,17 +255,17 @@ function getExceedingAmountFromCandidateFunction( exceedingAmount = options.requestsThreshold; return exceedingAmount; } -function refreshKeepAliveRecord({ - keepAliveTimeoutCache, +function refreshTimeframeTimeoutCacheRecord({ + timeFrameTimeoutCache, key, options }: { - keepAliveTimeoutCache: KeepAliveCache; + timeFrameTimeoutCache: TimeFrameTimeoutCache; key: string; options: CacheCandidateOptions; }) { - clearTimeout(keepAliveTimeoutCache.get(key)); - keepAliveTimeoutCache.set( + clearTimeout(timeFrameTimeoutCache.get(key)); + timeFrameTimeoutCache.set( key, setTimeout(() => { options.cache.delete(key); @@ -282,7 +282,7 @@ export function uniqid(length = 10) { export async function letsCandidate({ options, key, - keepAliveTimeoutCache, + timeFrameTimeoutCache, runningQueryCache, timeframeCache, args, @@ -290,7 +290,7 @@ export async function letsCandidate({ }: { options: CacheCandidateOptions; key: string; - keepAliveTimeoutCache: KeepAliveCache; + timeFrameTimeoutCache: TimeFrameTimeoutCache; runningQueryCache: RunningQueryCache; timeframeCache: TimeFrameCache; args: any[]; @@ -300,8 +300,8 @@ export async function letsCandidate({ const cachedData = await getDataCacheRecord({ options, key }); if (typeof cachedData !== 'undefined') { if (options.keepAlive) { - refreshKeepAliveRecord({ - keepAliveTimeoutCache, + refreshTimeframeTimeoutCacheRecord({ + timeFrameTimeoutCache, key, options }); @@ -333,7 +333,7 @@ export async function letsCandidate({ executionStart, options, timeframeCache, - keepAliveTimeoutCache, + timeFrameTimeoutCache, args }); return execution; @@ -348,7 +348,7 @@ export async function letsCandidate({ executionStart, options, timeframeCache, - keepAliveTimeoutCache, + timeFrameTimeoutCache, args }) ); @@ -366,7 +366,7 @@ export function getInitialState(_options: Partial) { // Generate a uniqid const uniqueIdentifier = uniqid(); - const keepAliveTimeoutCache: KeepAliveCache = new Map(); + const timeFrameTimeoutCache: TimeFrameTimeoutCache = new Map(); const options: CacheCandidateOptions = { ...CacheCandidateOptionsDefault, @@ -377,7 +377,7 @@ export function getInitialState(_options: Partial) { timeframeCache, runningQueryCache, uniqueIdentifier, - keepAliveTimeoutCache, + timeFrameTimeoutCache, options }; } diff --git a/src/lib.ts b/src/lib.ts index f6caacb..33a45f6 100644 --- a/src/lib.ts +++ b/src/lib.ts @@ -7,7 +7,7 @@ export function CacheCandidate(_options: Partial = {}) { timeframeCache, runningQueryCache, uniqueIdentifier, - keepAliveTimeoutCache, + timeFrameTimeoutCache, options } = getInitialState(_options); @@ -33,7 +33,7 @@ export function CacheCandidate(_options: Partial = {}) { return letsCandidate({ options, key: dataCacheKey, - keepAliveTimeoutCache, + timeFrameTimeoutCache, runningQueryCache, timeframeCache, args, @@ -51,7 +51,7 @@ export function cacheCandidate( timeframeCache, runningQueryCache, uniqueIdentifier, - keepAliveTimeoutCache, + timeFrameTimeoutCache, options } = getInitialState(_options); @@ -60,7 +60,7 @@ export function cacheCandidate( letsCandidate({ options, key: getDataCacheKey([uniqueIdentifier, JSON.stringify(args)]), - keepAliveTimeoutCache, + timeFrameTimeoutCache, runningQueryCache, timeframeCache, args, diff --git a/src/models.ts b/src/models.ts index 04a6ab5..d6a2d47 100644 --- a/src/models.ts +++ b/src/models.ts @@ -57,7 +57,7 @@ export interface TimeFrameCacheRecord { export type TimeFrameCache = Map>; export type RunningQueryCache = Map>; -export type KeepAliveCache = Map; +export type TimeFrameTimeoutCache = Map; export enum Events { RUNNING_QUERY = 'RUNNING_QUERY', From 190ca89ec0bdc6a57c019d08a0738f26da84a789 Mon Sep 17 00:00:00 2001 From: Michael Di Prisco Date: Mon, 16 Jan 2023 14:34:18 +0100 Subject: [PATCH 2/6] feat: added doctor + test script (#2) * feat: added doctor + test script * chore: added npx to doctor so we don't have to install it before using it * chore: added doctor-patient to npmignore * chore: revert fix --- .gitignore | 4 +++- .npmignore | 4 +++- doctor-patient.js | 20 ++++++++++++++++++++ package.json | 1 + 4 files changed, 27 insertions(+), 2 deletions(-) create mode 100644 doctor-patient.js diff --git a/.gitignore b/.gitignore index 0034ac9..8c728b4 100644 --- a/.gitignore +++ b/.gitignore @@ -14,4 +14,6 @@ dist *.sln *.sw? -coverage \ No newline at end of file +coverage + +.clinic \ No newline at end of file diff --git a/.npmignore b/.npmignore index ffc1146..6b1d3e7 100644 --- a/.npmignore +++ b/.npmignore @@ -1,4 +1,6 @@ .git .gitignore demo -coverage \ No newline at end of file +coverage +.clinic +doctor-patient.js \ No newline at end of file diff --git a/doctor-patient.js b/doctor-patient.js new file mode 100644 index 0000000..b9ad8a9 --- /dev/null +++ b/doctor-patient.js @@ -0,0 +1,20 @@ +const { cacheCandidate } = require('./dist/index.js'); +let counter = 0; +const mockFn = (step) => + new Promise((resolve) => { + counter += step; + resolve(counter); + }); +const wrappedMockFn = cacheCandidate(mockFn, { + requestsThreshold: 1, + ttl: 800, + keepAlive: false, +}); +(async () => { + let result = await wrappedMockFn(1); + console.log(result); // 1 + result = await wrappedMockFn(1); + console.log(result); // 1 + result = await wrappedMockFn(1); + console.log(result); // 1 +})(); \ No newline at end of file diff --git a/package.json b/package.json index 936a930..3c2e221 100644 --- a/package.json +++ b/package.json @@ -19,6 +19,7 @@ "ts-types": " tsc --emitDeclarationOnly --outDir dist", "check": "npm run prettier && npm run lint && npm test", "build": "npm run check && rimraf dist && NODE_ENV=production node esbuild.js && npm run ts-types", + "build-doctor-bubbleproof": "rimraf dist && NODE_ENV=development node esbuild.js && npx clinic bubbleproof -- node ./doctor-patient.js", "demo-test": "for file in demo/*.js; do node $file; done", "prettier": "prettier --write ./src", "lint": "eslint ./src --ext .ts", From 3c5be8aff97b5404f3769dad178db68a2ab92878 Mon Sep 17 00:00:00 2001 From: Michael Di Prisco Date: Mon, 16 Jan 2023 16:36:26 +0100 Subject: [PATCH 3/6] feat: plugins system (#12) * chore: initial plugin implementation * chore: second iteration. plugin system works without breaking tests. Co-authored-by: Carmelo Badalamenti * chore: iterating developement. tests not working yet * chore: fixed simple tests. plugins yet to test * chore: feature completed. linting and separation of concerns to do. * chore: linting and fixing open handle * chore: removed comments * chore: removed useless dependencyKeys param Co-authored-by: Carmelo Badalamenti * chore: internal refactor, async execute hooks, better types * chore: separated different packages to allow plugin mechanism * chore: separated different packages to allow plugin mechanism p2 * chore: removed additional dependency key references Co-authored-by: Carmelo Badalamenti --- package-lock.json | 36 +++++- package.json | 6 +- src/default.ts | 1 + src/index.test.ts | 243 ++++++++++++++++------------------------- src/index.ts | 3 +- src/internal.ts | 122 ++++++++++++--------- src/lib.ts | 2 - src/manager/index.ts | 73 ------------- src/models.ts | 17 +-- src/plugins/index.ts | 54 +++++++++ src/test/MockClass3.ts | 21 ---- src/test/MockClass4.ts | 36 ------ src/test/options.ts | 2 - 13 files changed, 265 insertions(+), 351 deletions(-) delete mode 100644 src/manager/index.ts create mode 100644 src/plugins/index.ts delete mode 100644 src/test/MockClass3.ts delete mode 100644 src/test/MockClass4.ts diff --git a/package-lock.json b/package-lock.json index 7cea37e..43b50e7 100644 --- a/package-lock.json +++ b/package-lock.json @@ -8,6 +8,10 @@ "name": "@jointly/cache-candidate", "version": "0.2.0", "license": "MIT", + "dependencies": { + "@jointly/cache-candidate-plugin-base": "^1.0.0", + "hook-fn": "^1.0.3" + }, "devDependencies": { "@commitlint/cli": "^17.3.0", "@commitlint/config-conventional": "^17.3.0", @@ -1931,6 +1935,11 @@ "node": "^14.15.0 || ^16.10.0 || >=18.0.0" } }, + "node_modules/@jointly/cache-candidate-plugin-base": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/@jointly/cache-candidate-plugin-base/-/cache-candidate-plugin-base-1.0.0.tgz", + "integrity": "sha512-1pJWcQVCEqbtjogcPv7yu4z+dhSomBSZbIThESi8PWAXS6OV0ro/iZxJreSp+uW1JMokeU7KaWFAMljR/YOS0w==" + }, "node_modules/@jridgewell/gen-mapping": { "version": "0.1.1", "resolved": "https://registry.npmjs.org/@jridgewell/gen-mapping/-/gen-mapping-0.1.1.tgz", @@ -4079,6 +4088,11 @@ "node": ">=8" } }, + "node_modules/hook-fn": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/hook-fn/-/hook-fn-1.0.4.tgz", + "integrity": "sha512-BGcl7mkRinWm2eEGiLvrjkmVPmJCcq4qZdYqpGsXNqebjZ9j6s0WwAM+7SPC3c4YFBBr5t543rErpkmNjJxxrQ==" + }, "node_modules/hosted-git-info": { "version": "4.1.0", "resolved": "https://registry.npmjs.org/hosted-git-info/-/hosted-git-info-4.1.0.tgz", @@ -5114,9 +5128,9 @@ "dev": true }, "node_modules/json5": { - "version": "2.2.1", - "resolved": "https://registry.npmjs.org/json5/-/json5-2.2.1.tgz", - "integrity": "sha512-1hqLFMSrGHRHxav9q9gNjJ5EXznIxGVO09xQRrwplcS8qs28pZ8s8hupZAmqDwZUmVZ2Qb2jnyPOWcDH8m8dlA==", + "version": "2.2.3", + "resolved": "https://registry.npmjs.org/json5/-/json5-2.2.3.tgz", + "integrity": "sha512-XmOWe7eyHYH14cLdVPoyg+GOH3rYX++KpzrylJwSW98t3Nk+U8XOl8FWKOgwtzdb8lXGf6zYwDUzeHMWfxasyg==", "dev": true, "bin": { "json5": "lib/cli.js" @@ -8760,6 +8774,11 @@ "chalk": "^4.0.0" } }, + "@jointly/cache-candidate-plugin-base": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/@jointly/cache-candidate-plugin-base/-/cache-candidate-plugin-base-1.0.0.tgz", + "integrity": "sha512-1pJWcQVCEqbtjogcPv7yu4z+dhSomBSZbIThESi8PWAXS6OV0ro/iZxJreSp+uW1JMokeU7KaWFAMljR/YOS0w==" + }, "@jridgewell/gen-mapping": { "version": "0.1.1", "resolved": "https://registry.npmjs.org/@jridgewell/gen-mapping/-/gen-mapping-0.1.1.tgz", @@ -10372,6 +10391,11 @@ "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==", "dev": true }, + "hook-fn": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/hook-fn/-/hook-fn-1.0.4.tgz", + "integrity": "sha512-BGcl7mkRinWm2eEGiLvrjkmVPmJCcq4qZdYqpGsXNqebjZ9j6s0WwAM+7SPC3c4YFBBr5t543rErpkmNjJxxrQ==" + }, "hosted-git-info": { "version": "4.1.0", "resolved": "https://registry.npmjs.org/hosted-git-info/-/hosted-git-info-4.1.0.tgz", @@ -11144,9 +11168,9 @@ "dev": true }, "json5": { - "version": "2.2.1", - "resolved": "https://registry.npmjs.org/json5/-/json5-2.2.1.tgz", - "integrity": "sha512-1hqLFMSrGHRHxav9q9gNjJ5EXznIxGVO09xQRrwplcS8qs28pZ8s8hupZAmqDwZUmVZ2Qb2jnyPOWcDH8m8dlA==", + "version": "2.2.3", + "resolved": "https://registry.npmjs.org/json5/-/json5-2.2.3.tgz", + "integrity": "sha512-XmOWe7eyHYH14cLdVPoyg+GOH3rYX++KpzrylJwSW98t3Nk+U8XOl8FWKOgwtzdb8lXGf6zYwDUzeHMWfxasyg==", "dev": true }, "jsonfile": { diff --git a/package.json b/package.json index 3c2e221..8658cab 100644 --- a/package.json +++ b/package.json @@ -62,5 +62,9 @@ "url": "git://github.com/JointlyTech/cache-candidate.git" }, "license": "MIT", - "author": "Jointly " + "author": "Jointly ", + "dependencies": { + "@jointly/cache-candidate-plugin-base": "^1.0.0", + "hook-fn": "^1.0.3" + } } diff --git a/src/default.ts b/src/default.ts index 1e6b619..abd6f07 100644 --- a/src/default.ts +++ b/src/default.ts @@ -7,6 +7,7 @@ export const CacheCandidateOptionsDefault: CacheCandidateOptions = { requestsThreshold: 3, cache: makeAsyncMap(), keepAlive: false, + plugins: [], events: { onCacheHit: (_) => { return _; diff --git a/src/index.test.ts b/src/index.test.ts index a5a7de8..ed35b48 100644 --- a/src/index.test.ts +++ b/src/index.test.ts @@ -1,9 +1,6 @@ import { cacheCandidate } from './lib'; -import { cacheCandidateDependencyManager } from './manager'; import { MockClass } from './test/MockClass'; import { MockClass as MockClass2 } from './test/MockClass2'; -import { MockClass as MockClass3 } from './test/MockClass3'; -import { MockClass as MockClass4 } from './test/MockClass4'; import { step, @@ -22,159 +19,111 @@ beforeEach(async () => { flushMaps(); }); -it('should verify cache is empty', async () => { - expect(eventHits.get('onCacheSet')).toBe(0); - expect(eventHits.get('onCacheHit')).toBe(0); - expect(eventHits.get('onCacheDelete')).toBe(0); -}); - -it('should separate the cache entries for MockClass and MockClass2 even if original names are equal', async () => { - const step = stepper(); - const mock = new MockClass(step, step, step, step); - const mock2 = new MockClass2(step, step, step, step); - mock.mockFunction(step); - await sleep(TTL + EXECUTION_MARGIN); - mock2.mockFunction(step); - await sleep(TTL + EXECUTION_MARGIN); - expect(eventHits.get('onCacheSet')).toBe(2); - expect(eventHits.get('onCacheHit')).toBe(0); -}); - -it('should call onCacheDelete for sync method', async () => { - const step = stepper(); - const mock = new MockClass(step, step, step, step); - mock.mockFunction(step); - await sleep(TTL + EXECUTION_MARGIN); - expect(eventHits.get('onCacheDelete')).toBe(1); -}); - -it('should call onCacheDelete for async method', async () => { - const step = stepper(); - const mock = new MockClass(step, step, step, step); - await mock.mockAsyncFunction(step); - await sleep(TTL + EXECUTION_MARGIN); - expect(eventHits.get('onCacheDelete')).toBe(1); -}); - -it('should call onCacheSet for sync method', async () => { - const step = stepper(); - const mock = new MockClass(step, step, step, step); - mock.mockFunction(step); - await sleep(EXECUTION_MARGIN); - expect(eventHits.get('onCacheSet')).toBe(1); -}); +describe('CacheCandidate - Simple', () => { + it('should verify cache is empty', async () => { + expect(eventHits.get('onCacheSet')).toBe(0); + expect(eventHits.get('onCacheHit')).toBe(0); + expect(eventHits.get('onCacheDelete')).toBe(0); + }); -it('should call onCacheHit for sync method', async () => { - const step = stepper(); - const mock = new MockClass(step, step, step, step); - mock.mockFunction(step); - await sleep(EXECUTION_MARGIN); - mock.mockFunction(step); - await sleep(EXECUTION_MARGIN); - expect(eventHits.get('onCacheHit')).toBe(1); -}); + it('should separate the cache entries for MockClass and MockClass2 even if original names are equal', async () => { + const step = stepper(); + const mock = new MockClass(step, step, step, step); + const mock2 = new MockClass2(step, step, step, step); + mock.mockFunction(step); + await sleep(TTL + EXECUTION_MARGIN); + mock2.mockFunction(step); + await sleep(TTL + EXECUTION_MARGIN); + expect(eventHits.get('onCacheSet')).toBe(2); + expect(eventHits.get('onCacheHit')).toBe(0); + }); -it('should call onCacheSet for async method', async () => { - const step = stepper(); - const mock = new MockClass(step, step, step, step); - await mock.mockAsyncFunction(step); - await sleep(EXECUTION_MARGIN); - expect(eventHits.get('onCacheSet')).toBe(1); -}); + it('should call onCacheDelete for sync method', async () => { + const step = stepper(); + const mock = new MockClass(step, step, step, step); + mock.mockFunction(step); + await sleep(TTL + EXECUTION_MARGIN); + expect(eventHits.get('onCacheDelete')).toBe(1); + }); -it('should call onCacheHit for async method', async () => { - const step = stepper(); - const mock = new MockClass(step, step, step, step); - await mock.mockAsyncFunction(step); - await sleep(EXECUTION_MARGIN); - await mock.mockAsyncFunction(step); - await sleep(EXECUTION_MARGIN); - expect(eventHits.get('onCacheHit')).toBe(1); -}); + it('should call onCacheDelete for async method', async () => { + const step = stepper(); + const mock = new MockClass(step, step, step, step); + await mock.mockAsyncFunction(step); + await sleep(TTL + EXECUTION_MARGIN); + expect(eventHits.get('onCacheDelete')).toBe(1); + }); -it('should make an item expire after TTL', async () => { - const step = stepper(); - const mock = new MockClass(step, step, step, step); - mock.mockFunction(step); - await sleep(EXECUTION_MARGIN); - mock.mockFunction(step); - await sleep(EXECUTION_MARGIN); - expect(eventHits.get('onCacheSet')).toBe(1); - expect(eventHits.get('onCacheHit')).toBe(1); - await sleep(TTL + EXECUTION_MARGIN); - expect(eventHits.get('onCacheDelete')).toBe(1); - mock.mockFunction(step); - await sleep(EXECUTION_MARGIN); - expect(eventHits.get('onCacheSet')).toBe(2); - expect(eventHits.get('onCacheHit')).toBe(1); -}); + it('should call onCacheSet for sync method', async () => { + const step = stepper(); + const mock = new MockClass(step, step, step, step); + mock.mockFunction(step); + await sleep(EXECUTION_MARGIN); + expect(eventHits.get('onCacheSet')).toBe(1); + }); -it('should expose manager', async () => { - const step = stepper(); - new MockClass(step, step, step, step); - expect(cacheCandidateDependencyManager).toBeDefined(); -}); + it('should call onCacheHit for sync method', async () => { + const step = stepper(); + const mock = new MockClass(step, step, step, step); + mock.mockFunction(step); + await sleep(EXECUTION_MARGIN); + mock.mockFunction(step); + await sleep(EXECUTION_MARGIN); + expect(eventHits.get('onCacheHit')).toBe(1); + }); -it('should fill manager map if dependencyKeys is defined as array', async () => { - const step = stepper(); - const mock = new MockClass3(step, step, step, step); - mock.mockFunction(step); - await sleep(EXECUTION_MARGIN); - expect(cacheCandidateDependencyManager.instances.size).toBe(2); - mock.mockAsyncFunction(step); - await sleep(EXECUTION_MARGIN); - expect(cacheCandidateDependencyManager.instances.size).toBe(2); -}); + it('should call onCacheSet for async method', async () => { + const step = stepper(); + const mock = new MockClass(step, step, step, step); + await mock.mockAsyncFunction(step); + await sleep(EXECUTION_MARGIN); + expect(eventHits.get('onCacheSet')).toBe(1); + }); -it('should fill manager map if dependencyKeys is defined as function', async () => { - const step = stepper(); - const mock = new MockClass4(step, step, step, step); - /*mock.mockFunction(step); - await sleep(EXECUTION_MARGIN); - expect(manager.instances.size).toBe(3);*/ - await mock.mockAsyncFunction(step); - await sleep(EXECUTION_MARGIN); - expect(cacheCandidateDependencyManager.instances.size).toBe(3); -}); + it('should call onCacheHit for async method', async () => { + const step = stepper(); + const mock = new MockClass(step, step, step, step); + await mock.mockAsyncFunction(step); + await sleep(EXECUTION_MARGIN); + await mock.mockAsyncFunction(step); + await sleep(EXECUTION_MARGIN); + expect(eventHits.get('onCacheHit')).toBe(1); + }); -it('should delete a record if invalidated', async () => { - const step = stepper(); - const mock = new MockClass3(step, step, step, step); - mock.mockFunction(step); - await sleep(EXECUTION_MARGIN); - expect(cacheCandidateDependencyManager.instances.size).toBe(2); - cacheCandidateDependencyManager.invalidate('a'); - expect(cacheCandidateDependencyManager.instances.size).toBe(2); -}); + it('should make an item expire after TTL', async () => { + const step = stepper(); + const mock = new MockClass(step, step, step, step); + mock.mockFunction(step); + await sleep(EXECUTION_MARGIN); + mock.mockFunction(step); + await sleep(EXECUTION_MARGIN); + expect(eventHits.get('onCacheSet')).toBe(1); + expect(eventHits.get('onCacheHit')).toBe(1); + await sleep(TTL + EXECUTION_MARGIN); + expect(eventHits.get('onCacheDelete')).toBe(1); + mock.mockFunction(step); + await sleep(EXECUTION_MARGIN); + expect(eventHits.get('onCacheSet')).toBe(2); + expect(eventHits.get('onCacheHit')).toBe(1); + }); -it('should behave in the same way as a decorator if the higher-order function is used', async () => { - let counter = 0; - const mockFn = (step: number) => - new Promise((resolve) => { - counter += step; - resolve(counter); + it('should behave in the same way as a decorator if the higher-order function is used', async () => { + let counter = 0; + const mockFn = (step: number) => + new Promise((resolve) => { + counter += step; + resolve(counter); + }); + const wrappedMockFn = cacheCandidate(mockFn, { + requestsThreshold: 1, + ttl: 800 }); - const wrappedMockFn = cacheCandidate(mockFn, { - requestsThreshold: 1, - dependencyKeys(result) { - return result; - } + let result: unknown; + result = await wrappedMockFn(1); + await sleep(EXECUTION_MARGIN); + expect(result).toBe(1); + result = await wrappedMockFn(1); + await sleep(EXECUTION_MARGIN); + expect(result).toBe(1); }); - let result: unknown; - result = await wrappedMockFn(1); - await sleep(EXECUTION_MARGIN); - expect(result).toBe(1); - result = await wrappedMockFn(1); - await sleep(EXECUTION_MARGIN); - expect(result).toBe(1); - result = await wrappedMockFn(1); - await sleep(EXECUTION_MARGIN); - expect(result).toBe(1); - cacheCandidateDependencyManager.invalidate(0); - await sleep(EXECUTION_MARGIN); - expect(cacheCandidateDependencyManager.instances.size).toBe(1); - cacheCandidateDependencyManager.invalidate(1); - await sleep(EXECUTION_MARGIN); - expect(cacheCandidateDependencyManager.instances.size).toBe(1); - await sleep(EXECUTION_MARGIN); }); diff --git a/src/index.ts b/src/index.ts index fb3c0ed..7794bae 100644 --- a/src/index.ts +++ b/src/index.ts @@ -1,4 +1,5 @@ export * from './default'; export * from './models'; export * from './lib'; -export * from './manager'; +export * from './plugins/poc/dependency-keys'; +export * from './plugins/poc/manager'; diff --git a/src/internal.ts b/src/internal.ts index 9948313..4de8f0c 100644 --- a/src/internal.ts +++ b/src/internal.ts @@ -1,13 +1,16 @@ import { createHash } from 'crypto'; import { CacheCandidateOptionsDefault } from './default'; -import { cacheCandidateDependencyManager } from './manager'; import { CacheCandidateOptions, + DataCacheRecordNotFound, Events, KeepAliveCache, RunningQueryCache, + RunningQueryRecordNotFound, TimeFrameCache } from './models'; +import { ExecuteHook } from './plugins'; +import { Hooks, PluginPayload } from '@jointly/cache-candidate-plugin-base'; function isTimeFrameCacheRecordExpired(executionEnd: any, options: any) { return Date.now() < executionEnd + options.timeFrame; @@ -50,7 +53,7 @@ function getRunningQueryRecord({ options.events.onLog({ key, event: Events.RUNNING_QUERY }); return runningQueryCache.get(key); } - return undefined; + return RunningQueryRecordNotFound; } export function getDataCacheKey(...args: any[]) { @@ -70,21 +73,21 @@ function isDataCacheRecordExpired({ async function getDataCacheRecord({ options, - key + key, + HookPayload }): Promise { if (await options.cache.has(key)) { const { result, birthTime } = await options.cache.get(key); // Remove the dataCache record if the time frame has passed. if (isDataCacheRecordExpired({ birthTime, options })) { - await deleteDataCacheRecord({ options, key }); - return undefined; + await deleteDataCacheRecord({ options, key, HookPayload }); + return DataCacheRecordNotFound; } else { // Return the cached data - options.events.onCacheHit({ key }); return result; } } - return undefined; + return DataCacheRecordNotFound; } async function addDataCacheRecord({ options, key, result }) { @@ -98,13 +101,22 @@ async function addDataCacheRecord({ options, key, result }) { ); } -async function deleteDataCacheRecord({ options, key }) { +async function deleteDataCacheRecord({ options, key, HookPayload }) { + await ExecuteHook( + Hooks.DATACACHE_RECORD_DELETE_PRE, + options.plugins, + HookPayload + ); await options.cache.delete(key); + await ExecuteHook( + Hooks.DATACACHE_RECORD_DELETE_POST, + options.plugins, + HookPayload + ); options.events.onCacheDelete({ key }); - cacheCandidateDependencyManager.deleteKey(key); } -function handleResult({ +async function handleResult({ result, runningQueryCache, key, @@ -112,7 +124,8 @@ function handleResult({ options, timeframeCache, keepAliveTimeoutCache, - args + args, + HookPayload }: { result: unknown; runningQueryCache: RunningQueryCache; @@ -122,7 +135,8 @@ function handleResult({ timeframeCache: TimeFrameCache; keepAliveTimeoutCache: KeepAliveCache; args: any[]; -}): any { + HookPayload: PluginPayload; +}): Promise { const executionEnd = Date.now(); const executionTime = executionEnd - executionStart; options.events.onAfterFunctionExecution({ key, executionTime }); @@ -144,55 +158,31 @@ function handleResult({ }); if (exceedingAmount >= options.requestsThreshold) { + await ExecuteHook( + Hooks.DATACACHE_RECORD_ADD_PRE, + options.plugins, + HookPayload + ); addDataCacheRecord({ options, key, result }) .then(async () => { + await ExecuteHook(Hooks.DATACACHE_RECORD_ADD_POST, options.plugins, { + ...HookPayload, + result + }); options.events.onCacheSet({ key }); - if (options.dependencyKeys !== undefined) { - let dependencyKeys: any = options.dependencyKeys; - dependencyKeys = await remapDependencyKeys(dependencyKeys, result); - cacheCandidateDependencyManager.register({ - key, - dependencyKeys, - cacheAdapter: options.cache - }); - } }) .finally(() => { runningQueryCache.delete(key); keepAliveTimeoutCache.set( key, setTimeout(() => { - deleteDataCacheRecord({ options, key }); + deleteDataCacheRecord({ options, key, HookPayload }); }, options.ttl) ); }); } } -async function remapDependencyKeys(dependencyKeys: any, result: unknown) { - if (typeof dependencyKeys === 'function') { - dependencyKeys = dependencyKeys(result); - if (dependencyKeys instanceof Promise) { - dependencyKeys = await dependencyKeys; - } - } - - if (Array.isArray(dependencyKeys)) { - dependencyKeys = dependencyKeys.map((key) => { - return typeof key === 'number' ? key.toString() : key; - }); - } - - if (typeof dependencyKeys === 'number') { - dependencyKeys = [dependencyKeys.toString()]; - } - - if (typeof dependencyKeys === 'string') { - dependencyKeys = [dependencyKeys]; - } - return dependencyKeys; -} - function getExceedingAmount({ options, key, @@ -296,9 +286,18 @@ export async function letsCandidate({ args: any[]; originalMethod: (...args: any[]) => Promise; }) { + const HookPayload = { + options: { ...options, plugins: undefined }, + key, + keepAliveTimeoutCache, + runningQueryCache, + timeframeCache, + fnArgs: args + }; + await ExecuteHook(Hooks.INIT, options.plugins, HookPayload); // Check if result exists in dataCache - const cachedData = await getDataCacheRecord({ options, key }); - if (typeof cachedData !== 'undefined') { + const cachedData = await getDataCacheRecord({ options, key, HookPayload }); + if (cachedData !== DataCacheRecordNotFound) { if (options.keepAlive) { refreshKeepAliveRecord({ keepAliveTimeoutCache, @@ -306,6 +305,12 @@ export async function letsCandidate({ options }); } + + await ExecuteHook(Hooks.CACHE_HIT, options.plugins, { + ...HookPayload, + result: cachedData + }); + options.events.onCacheHit({ key }); return Promise.resolve(cachedData); } @@ -315,15 +320,28 @@ export async function letsCandidate({ key, runningQueryCache }); - if (typeof runningQuery !== 'undefined') return runningQuery; + + if (runningQuery !== RunningQueryRecordNotFound) { + await ExecuteHook(Hooks.CACHE_HIT, options.plugins, { + ...HookPayload, + result: runningQuery + }); + options.events.onCacheHit({ key }); + return runningQuery; + } // Check the timeframeCache and delete every element that has passed the time frame. expireTimeFrameCacheRecords({ options, key, timeframeCache }); // Execute the function + await ExecuteHook(Hooks.EXECUTION_PRE, options.plugins, HookPayload); options.events.onBeforeFunctionExecution({ key }); const executionStart = Date.now(); const execution = originalMethod(...args); + await ExecuteHook(Hooks.EXECUTION_POST, options.plugins, { + ...HookPayload, + result: execution + }); // If execution is not a promise, handle the result and return it. if (!(execution instanceof Promise)) { handleResult({ @@ -334,7 +352,8 @@ export async function letsCandidate({ options, timeframeCache, keepAliveTimeoutCache, - args + args, + HookPayload }); return execution; } @@ -349,7 +368,8 @@ export async function letsCandidate({ options, timeframeCache, keepAliveTimeoutCache, - args + args, + HookPayload }) ); diff --git a/src/lib.ts b/src/lib.ts index f6caacb..8258f90 100644 --- a/src/lib.ts +++ b/src/lib.ts @@ -11,7 +11,6 @@ export function CacheCandidate(_options: Partial = {}) { options } = getInitialState(_options); - // Execute the function and get the execution times. return function ( target: any, propertyKey: string, @@ -55,7 +54,6 @@ export function cacheCandidate( options } = getInitialState(_options); - // Execute the function and get the execution times. return async (...args: any[]) => letsCandidate({ options, diff --git a/src/manager/index.ts b/src/manager/index.ts deleted file mode 100644 index 709c52c..0000000 --- a/src/manager/index.ts +++ /dev/null @@ -1,73 +0,0 @@ -import { CacheCandidateCacheAdapter } from '../models'; - -const makeDependencyManager = () => { - const instances = new Map(); - return { - register: ({ - key, - dependencyKeys, - cacheAdapter - }: { - key: unknown; - dependencyKeys: Array; - cacheAdapter: CacheCandidateCacheAdapter; - }) => { - for (const dependencyKey of dependencyKeys) { - if (!instances.has(dependencyKey)) { - instances.set(dependencyKey, [ - { - key, - cacheAdapter - } - ]); - } else { - instances.get(dependencyKey).push({ - key, - cacheAdapter - }); - } - } - }, - invalidate: (dependencyKey: string | number) => { - if (typeof dependencyKey === 'number') { - dependencyKey = dependencyKey.toString(); - } - - if (!instances.has(dependencyKey)) { - return; - } - - instances.get(dependencyKey).forEach(({ key, cacheAdapter }) => { - cacheAdapter.delete(key); - }); - }, - deleteKey: (dataCacheRecordKey: string) => { - for (const [dependencyKey, keys] of instances.entries()) { - if (keys.some((_key) => _key.key === dataCacheRecordKey)) { - if (keys.length === 1) { - instances.delete(dependencyKey); - } else { - instances.set( - dependencyKey, - keys.filter((_key) => _key.key !== dataCacheRecordKey) - ); - } - } - } - }, - instances - }; -}; - -export const cacheCandidateDependencyManager = makeDependencyManager(); - -/* -[abc][1,2,3] -[def][3,4,5] - -[1] => [abc] -[2] => [abc] -[3] => [abc, def] -[4] => [def] -[5] => [def] -*/ diff --git a/src/models.ts b/src/models.ts index 04a6ab5..a39c01a 100644 --- a/src/models.ts +++ b/src/models.ts @@ -1,3 +1,5 @@ +import { CacheCandidatePluginWithAdditionalParameters } from '@jointly/cache-candidate-plugin-base'; + export interface CandidateFunctionOptions { timeFrameCacheRecords: Array; options: CacheCandidateOptions; @@ -32,17 +34,7 @@ export interface CacheCandidateOptions { }) => void; onLog: ({ key, event }: { key: string; event: Events }) => void; }; - dependencyKeys?: - | string - | number - | Array - | (( - result: DataCacheRecord['result'] - ) => - | string - | number - | Array - | Promise | Array>); + plugins?: Array; } export interface DataCacheRecord { @@ -65,3 +57,6 @@ export enum Events { CHECKING_MILLISECOND_THRESHOLD = 'CHECKING_MILLISECOND_THRESHOLD', CHECKING_REQUESTS_THRESHOLD = 'CHECKING_REQUESTS_THRESHOLD' } + +export const DataCacheRecordNotFound = Symbol('DataCacheRecordNotFound'); +export const RunningQueryRecordNotFound = Symbol('RunningQueryRecordNotFound'); diff --git a/src/plugins/index.ts b/src/plugins/index.ts new file mode 100644 index 0000000..2c24227 --- /dev/null +++ b/src/plugins/index.ts @@ -0,0 +1,54 @@ +import { + ActionableHook, + CacheCandidatePluginWithAdditionalParameters, + Hooks, + PluginPayload +} from '@jointly/cache-candidate-plugin-base'; +import { hook } from 'hook-fn'; + +export async function ExecuteHook( + hook: Hooks, + plugins: Array = [], + payload: PluginPayload +) { + for (const plugin of plugins) { + const instanceHooks = plugin.hooks.filter((h) => h.hook === hook); + if (instanceHooks.length > 1) { + throw new Error( + `Only one hook instance per plugin is allowed. ${plugin.name} has ${instanceHooks.length} instances of ${hook}}` + ); + } + if (instanceHooks.length === 0) { + continue; + } + const instanceHook = instanceHooks[0]; + if (isActionable(instanceHook)) { + await instanceHook.action(payload, plugin.additionalParameters); + } else { + throw new Error( + `Hook ${hook} for plugin ${plugin.name} is not actionable.` + ); + } + } +} + +function isActionable(hook: ActionableHook) { + return [hook.action !== undefined, typeof hook.action === 'function'].every( + (i) => i === true + ); +} + +export function pluginHookWrap( + HookBefore: Hooks, + HookAfter: Hooks, + payload: PluginPayload +) { + return hook({ + before: ({ args }) => { + ExecuteHook(HookBefore, args[0].plugins, payload); + }, + after: ({ args, result }) => { + ExecuteHook(HookAfter, args[0].plugins, { ...payload, result }); + } + }); +} diff --git a/src/test/MockClass3.ts b/src/test/MockClass3.ts deleted file mode 100644 index 8c635a7..0000000 --- a/src/test/MockClass3.ts +++ /dev/null @@ -1,21 +0,0 @@ -import { CacheCandidate } from '../lib'; -import { options } from './options'; - -export class MockClass { - constructor( - public a: number, - public b: number, - public aAsync: number, - public bAsync: number - ) {} - - @CacheCandidate({ ...options, ...{ dependencyKeys: ['a', 'b'] } }) - async mockAsyncFunction(step: number) { - return step; - } - - @CacheCandidate({ ...options, ...{ dependencyKeys: ['a', 'b'] } }) - mockFunction(step: number) { - return step; - } -} diff --git a/src/test/MockClass4.ts b/src/test/MockClass4.ts deleted file mode 100644 index adcb1f8..0000000 --- a/src/test/MockClass4.ts +++ /dev/null @@ -1,36 +0,0 @@ -import { CacheCandidate } from '../lib'; -import { options } from './options'; - -export class MockClass { - constructor( - public a: number, - public b: number, - public aAsync: number, - public bAsync: number - ) {} - - @CacheCandidate({ - ...options, - ...{ - dependencyKeys: function (result) { - return new Promise((resolve) => { - setTimeout(() => { - resolve(result); - }, 10); - }); - } - } - }) - async mockAsyncFunction(step: number) { - return new Promise((resolve) => { - setTimeout(() => { - resolve([step, step + 1, step + 2]); - }, 10); - }); - } - - @CacheCandidate({ ...options, ...{ dependencyKeys: (result) => result } }) - mockFunction(step: number) { - return [step, step + 1, step + 2]; - } -} diff --git a/src/test/options.ts b/src/test/options.ts index 0a5c27d..27c262f 100644 --- a/src/test/options.ts +++ b/src/test/options.ts @@ -1,4 +1,3 @@ -import { cacheCandidateDependencyManager } from '../manager'; import { CacheCandidateOptions } from '../models'; export const sleep = (ms: number) => new Promise((resolve) => setTimeout(resolve, ms)); @@ -63,5 +62,4 @@ export function flushMaps() { for (const [key] of eventHits) { eventHits.set(key, 0); } - cacheCandidateDependencyManager.instances.clear(); } From 9a57d94a7739ee2202de508a908dd603be18b962 Mon Sep 17 00:00:00 2001 From: Michael Di Prisco Date: Mon, 16 Jan 2023 16:49:45 +0100 Subject: [PATCH 4/6] feat: better timeouts (unref) (#13) * feat: better timeouts (unref) Co-authored-by: Carmelo Badalamenti --- src/internal.ts | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/internal.ts b/src/internal.ts index 4de8f0c..407ec08 100644 --- a/src/internal.ts +++ b/src/internal.ts @@ -177,7 +177,7 @@ async function handleResult({ key, setTimeout(() => { deleteDataCacheRecord({ options, key, HookPayload }); - }, options.ttl) + }, options.ttl).unref() ); }); } @@ -259,7 +259,7 @@ function refreshKeepAliveRecord({ key, setTimeout(() => { options.cache.delete(key); - }, options.ttl) + }, options.ttl).unref() ); } From e7495160f9950806d9c9fb27495cf9583bdb4cac Mon Sep 17 00:00:00 2001 From: Michael Di Prisco Date: Mon, 16 Jan 2023 11:36:53 +0100 Subject: [PATCH 5/6] chore: keepAliveTimeoutCache changed to timeFrameTimeoutCache --- src/internal.ts | 34 +++++++++++++++++----------------- src/lib.ts | 8 ++++---- src/models.ts | 2 +- 3 files changed, 22 insertions(+), 22 deletions(-) diff --git a/src/internal.ts b/src/internal.ts index 407ec08..97aa6cb 100644 --- a/src/internal.ts +++ b/src/internal.ts @@ -4,7 +4,7 @@ import { CacheCandidateOptions, DataCacheRecordNotFound, Events, - KeepAliveCache, + TimeFrameTimeoutCache, RunningQueryCache, RunningQueryRecordNotFound, TimeFrameCache @@ -123,7 +123,7 @@ async function handleResult({ executionStart, options, timeframeCache, - keepAliveTimeoutCache, + timeFrameTimeoutCache, args, HookPayload }: { @@ -133,7 +133,7 @@ async function handleResult({ executionStart: number; options: CacheCandidateOptions; timeframeCache: TimeFrameCache; - keepAliveTimeoutCache: KeepAliveCache; + timeFrameTimeoutCache: TimeFrameTimeoutCache; args: any[]; HookPayload: PluginPayload; }): Promise { @@ -173,7 +173,7 @@ async function handleResult({ }) .finally(() => { runningQueryCache.delete(key); - keepAliveTimeoutCache.set( + timeFrameTimeoutCache.set( key, setTimeout(() => { deleteDataCacheRecord({ options, key, HookPayload }); @@ -245,17 +245,17 @@ function getExceedingAmountFromCandidateFunction( exceedingAmount = options.requestsThreshold; return exceedingAmount; } -function refreshKeepAliveRecord({ - keepAliveTimeoutCache, +function refreshTimeframeTimeoutCacheRecord({ + timeFrameTimeoutCache, key, options }: { - keepAliveTimeoutCache: KeepAliveCache; + timeFrameTimeoutCache: TimeFrameTimeoutCache; key: string; options: CacheCandidateOptions; }) { - clearTimeout(keepAliveTimeoutCache.get(key)); - keepAliveTimeoutCache.set( + clearTimeout(timeFrameTimeoutCache.get(key)); + timeFrameTimeoutCache.set( key, setTimeout(() => { options.cache.delete(key); @@ -272,7 +272,7 @@ export function uniqid(length = 10) { export async function letsCandidate({ options, key, - keepAliveTimeoutCache, + timeFrameTimeoutCache, runningQueryCache, timeframeCache, args, @@ -280,7 +280,7 @@ export async function letsCandidate({ }: { options: CacheCandidateOptions; key: string; - keepAliveTimeoutCache: KeepAliveCache; + timeFrameTimeoutCache: TimeFrameTimeoutCache; runningQueryCache: RunningQueryCache; timeframeCache: TimeFrameCache; args: any[]; @@ -299,8 +299,8 @@ export async function letsCandidate({ const cachedData = await getDataCacheRecord({ options, key, HookPayload }); if (cachedData !== DataCacheRecordNotFound) { if (options.keepAlive) { - refreshKeepAliveRecord({ - keepAliveTimeoutCache, + refreshTimeframeTimeoutCacheRecord({ + timeFrameTimeoutCache, key, options }); @@ -351,7 +351,7 @@ export async function letsCandidate({ executionStart, options, timeframeCache, - keepAliveTimeoutCache, + timeFrameTimeoutCache, args, HookPayload }); @@ -367,7 +367,7 @@ export async function letsCandidate({ executionStart, options, timeframeCache, - keepAliveTimeoutCache, + timeFrameTimeoutCache, args, HookPayload }) @@ -386,7 +386,7 @@ export function getInitialState(_options: Partial) { // Generate a uniqid const uniqueIdentifier = uniqid(); - const keepAliveTimeoutCache: KeepAliveCache = new Map(); + const timeFrameTimeoutCache: TimeFrameTimeoutCache = new Map(); const options: CacheCandidateOptions = { ...CacheCandidateOptionsDefault, @@ -397,7 +397,7 @@ export function getInitialState(_options: Partial) { timeframeCache, runningQueryCache, uniqueIdentifier, - keepAliveTimeoutCache, + timeFrameTimeoutCache, options }; } diff --git a/src/lib.ts b/src/lib.ts index 8258f90..ce55e84 100644 --- a/src/lib.ts +++ b/src/lib.ts @@ -7,7 +7,7 @@ export function CacheCandidate(_options: Partial = {}) { timeframeCache, runningQueryCache, uniqueIdentifier, - keepAliveTimeoutCache, + timeFrameTimeoutCache, options } = getInitialState(_options); @@ -32,7 +32,7 @@ export function CacheCandidate(_options: Partial = {}) { return letsCandidate({ options, key: dataCacheKey, - keepAliveTimeoutCache, + timeFrameTimeoutCache, runningQueryCache, timeframeCache, args, @@ -50,7 +50,7 @@ export function cacheCandidate( timeframeCache, runningQueryCache, uniqueIdentifier, - keepAliveTimeoutCache, + timeFrameTimeoutCache, options } = getInitialState(_options); @@ -58,7 +58,7 @@ export function cacheCandidate( letsCandidate({ options, key: getDataCacheKey([uniqueIdentifier, JSON.stringify(args)]), - keepAliveTimeoutCache, + timeFrameTimeoutCache, runningQueryCache, timeframeCache, args, diff --git a/src/models.ts b/src/models.ts index a39c01a..018259d 100644 --- a/src/models.ts +++ b/src/models.ts @@ -49,7 +49,7 @@ export interface TimeFrameCacheRecord { export type TimeFrameCache = Map>; export type RunningQueryCache = Map>; -export type KeepAliveCache = Map; +export type TimeFrameTimeoutCache = Map; export enum Events { RUNNING_QUERY = 'RUNNING_QUERY', From b155d5acdf76010d9d86aac3e5a876cf8e16a0be Mon Sep 17 00:00:00 2001 From: Michael Di Prisco Date: Mon, 16 Jan 2023 17:01:38 +0100 Subject: [PATCH 6/6] chore: fixed plugin base dependency --- package-lock.json | 16 +++++++++------- package.json | 4 ++-- src/internal.ts | 2 +- 3 files changed, 12 insertions(+), 10 deletions(-) diff --git a/package-lock.json b/package-lock.json index 43b50e7..fab06fb 100644 --- a/package-lock.json +++ b/package-lock.json @@ -9,12 +9,12 @@ "version": "0.2.0", "license": "MIT", "dependencies": { - "@jointly/cache-candidate-plugin-base": "^1.0.0", "hook-fn": "^1.0.3" }, "devDependencies": { "@commitlint/cli": "^17.3.0", "@commitlint/config-conventional": "^17.3.0", + "@jointly/cache-candidate-plugin-base": "^1.0.0", "@types/jest": "^29.2.4", "@types/node": "^18.11.12", "@types/redis": "^4.0.11", @@ -1936,9 +1936,10 @@ } }, "node_modules/@jointly/cache-candidate-plugin-base": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/@jointly/cache-candidate-plugin-base/-/cache-candidate-plugin-base-1.0.0.tgz", - "integrity": "sha512-1pJWcQVCEqbtjogcPv7yu4z+dhSomBSZbIThESi8PWAXS6OV0ro/iZxJreSp+uW1JMokeU7KaWFAMljR/YOS0w==" + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/@jointly/cache-candidate-plugin-base/-/cache-candidate-plugin-base-1.0.1.tgz", + "integrity": "sha512-sykw4qJ/xIVnoptRGuxLu84pLCCf7cMHvKhvwroIaKHI8gLWp7aiIooRoKVPvwjHXT9NrYcS6YUIeWLPblqWVA==", + "dev": true }, "node_modules/@jridgewell/gen-mapping": { "version": "0.1.1", @@ -8775,9 +8776,10 @@ } }, "@jointly/cache-candidate-plugin-base": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/@jointly/cache-candidate-plugin-base/-/cache-candidate-plugin-base-1.0.0.tgz", - "integrity": "sha512-1pJWcQVCEqbtjogcPv7yu4z+dhSomBSZbIThESi8PWAXS6OV0ro/iZxJreSp+uW1JMokeU7KaWFAMljR/YOS0w==" + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/@jointly/cache-candidate-plugin-base/-/cache-candidate-plugin-base-1.0.1.tgz", + "integrity": "sha512-sykw4qJ/xIVnoptRGuxLu84pLCCf7cMHvKhvwroIaKHI8gLWp7aiIooRoKVPvwjHXT9NrYcS6YUIeWLPblqWVA==", + "dev": true }, "@jridgewell/gen-mapping": { "version": "0.1.1", diff --git a/package.json b/package.json index 8658cab..280ce50 100644 --- a/package.json +++ b/package.json @@ -49,7 +49,8 @@ "prettier": "^2.8.1", "rimraf": "^3.0.2", "ts-jest": "^29.0.3", - "typescript": "^4.9.4" + "typescript": "^4.9.4", + "@jointly/cache-candidate-plugin-base": "^1.0.0" }, "lint-staged": { "src/**/*.{js,jsx,ts,tsx}": [ @@ -64,7 +65,6 @@ "license": "MIT", "author": "Jointly ", "dependencies": { - "@jointly/cache-candidate-plugin-base": "^1.0.0", "hook-fn": "^1.0.3" } } diff --git a/src/internal.ts b/src/internal.ts index 97aa6cb..74f2cf9 100644 --- a/src/internal.ts +++ b/src/internal.ts @@ -289,7 +289,7 @@ export async function letsCandidate({ const HookPayload = { options: { ...options, plugins: undefined }, key, - keepAliveTimeoutCache, + timeFrameTimeoutCache, runningQueryCache, timeframeCache, fnArgs: args