From 05fbb9789d4309e535d840feaa72d830d82956f6 Mon Sep 17 00:00:00 2001 From: zsimo Date: Tue, 4 Apr 2023 12:51:17 +0200 Subject: [PATCH] fix: partially freezes internal functions (#33) (#45) Co-authored-by: Simone Sacchi --- src/index.test.ts | 58 +++++++++++++++++++++++++++++++++++++++++++++++ src/internal.ts | 41 +++++++++++++++++++++++++-------- 2 files changed, 89 insertions(+), 10 deletions(-) diff --git a/src/index.test.ts b/src/index.test.ts index d6fc2d1..901be96 100644 --- a/src/index.test.ts +++ b/src/index.test.ts @@ -416,4 +416,62 @@ describe('Plugins', () => { await sleep(EXECUTION_MARGIN); expect(counter).toBe(1); }); + + it('should throw if internal functions getDataCacheRecord is overridden', async () => { + + const myPlugin = { + name: 'myPlugin', + hooks: [ + { + hook: Hooks.INIT, + action: async (payload) => { + payload.internals.getDataCacheRecord = function () { + console.log("should not be possible"); + }; + } + } + ] + }; + + const mockFn = (step: number) => + new Promise((resolve) => { + resolve(step); + }); + + const wrappedMockFn = cacheCandidate(mockFn, { + plugins: [myPlugin] + }); + + await expect(wrappedMockFn(1)).rejects.toThrow(); + + }); + + it('should not throw if internal functions getDataCacheKey is overridden', async () => { + + const myPlugin = { + name: 'myPlugin', + hooks: [ + { + hook: Hooks.INIT, + action: async (payload) => { + payload.internals.getDataCacheKey = function () { + console.log("should be possible"); + }; + } + } + ] + }; + + const mockFn = (step: number) => + new Promise((resolve) => { + resolve(step); + }); + + const wrappedMockFn = cacheCandidate(mockFn, { + plugins: [myPlugin] + }); + + await expect(wrappedMockFn(1)).resolves.not.toThrowError(); + + }); }); diff --git a/src/internal.ts b/src/internal.ts index 1d5542f..6530c82 100644 --- a/src/internal.ts +++ b/src/internal.ts @@ -275,6 +275,35 @@ export function uniqid(length = 10) { .substring(2, length + 2); } +// returns a partially frozen object +function internalsFactory () { + const internals = { + getDataCacheKey, + getDataCacheRecord, + addDataCacheRecord, + deleteDataCacheRecord, + isDataCacheRecordExpired, + getExceedingAmount + }; + Object.defineProperty(internals, 'getDataCacheRecord', { + value: getDataCacheRecord, + writable: false + }); + Object.defineProperty(internals, 'addDataCacheRecord', { + value: addDataCacheRecord, + writable: false + }); + Object.defineProperty(internals, 'deleteDataCacheRecord', { + value: deleteDataCacheRecord, + writable: false + }); + Object.defineProperty(internals, 'isDataCacheRecordExpired', { + value: isDataCacheRecordExpired, + writable: false + }); + + return internals; +} export async function letsCandidate({ options, key, @@ -292,8 +321,7 @@ export async function letsCandidate({ args: any[]; originalMethod: (...args: any[]) => Promise; }) { - // Make options.plugins freezed - //Object.freeze(options.plugins); + const HookPayload = { options, key, @@ -301,14 +329,7 @@ export async function letsCandidate({ runningQueryCache, timeframeCache, fnArgs: args, - internals: { - getDataCacheKey, - getDataCacheRecord, - addDataCacheRecord, - deleteDataCacheRecord, - isDataCacheRecordExpired, - getExceedingAmount - } + internals: internalsFactory() }; await ExecuteHook(Hooks.INIT, options.plugins, HookPayload); // Check if result exists in dataCache