diff --git a/packages/sushi/package.json b/packages/sushi/package.json index 83d71a609b..13d5264f0d 100644 --- a/packages/sushi/package.json +++ b/packages/sushi/package.json @@ -202,6 +202,7 @@ "date-fns": "3.3.1", "decimal.js-light": "2.5.1", "lodash.flatmap": "4.5.0", + "memoize-fs": "github:rouzwelt/memoize-fs#e5fcc9f6effc4ad087514372a53a49d380520ad5", "numbro": "2.5.0", "seedrandom": "3.0.5", "serialijse": "0.3.0", diff --git a/packages/sushi/src/router/memoizer.test.ts b/packages/sushi/src/router/memoizer.test.ts new file mode 100644 index 0000000000..d1f9a07eaa --- /dev/null +++ b/packages/sushi/src/router/memoizer.test.ts @@ -0,0 +1,53 @@ +import fs from 'fs' +import { describe, expect, it } from 'vitest' +import { memoizer } from './memoizer.js' + +describe('Memoizer', async () => { + it('should serialize, memoize, read from cache, deserialize', async () => { + let didHitCacheOnce = false + const testFn = (value1: any) => { + didHitCacheOnce = !didHitCacheOnce + return { + ...value1, + someOtherValue: 'some data', + } + } + const testMemoizer = await memoizer.fn(testFn) + + const testValue = { + bigint: 12345n, + string: 'some text', + number: 123, + bool: true, + obj: { + prop: 'some prop', + }, + } + const noCacheHitReturnedValue = await testMemoizer(testValue) + const cacheHitReturnedValue = await testMemoizer(testValue) + const expectedReturnedValue = { + bigint: 12345n, + string: 'some text', + number: 123, + bool: true, + obj: { + prop: 'some prop', + }, + someOtherValue: 'some data', + } + + expect(didHitCacheOnce).toEqual(true) + expect(noCacheHitReturnedValue).toStrictEqual(expectedReturnedValue) + expect(cacheHitReturnedValue).toStrictEqual(expectedReturnedValue) + + // read cached file content + const cacheFileContent = fs.readFileSync( + `./mem-cache/${fs.readdirSync('./mem-cache')[0]}`, + { encoding: 'utf-8' }, + ) + const expectedCachedContent = + '{"data":{"bigint":"12345n","string":"some text","number":123,"bool":true,"obj":{"prop":"some prop"},"someOtherValue":"some data"}}' + + expect(cacheFileContent).toEqual(expectedCachedContent) + }) +}) diff --git a/packages/sushi/src/router/memoizer.ts b/packages/sushi/src/router/memoizer.ts new file mode 100644 index 0000000000..a8810d85f4 --- /dev/null +++ b/packages/sushi/src/router/memoizer.ts @@ -0,0 +1,34 @@ +import memoize from 'memoize-fs' + +const serialize = (val: any) => { + const circRefColl: any[] = [] + return JSON.stringify(val, (_name, value) => { + if (typeof value === 'function') { + return // ignore arguments and attributes of type function silently + } + if (typeof value === 'object' && value !== null) { + if (circRefColl.indexOf(value) !== -1) { + // circular reference has been found, discard key + return + } + // store value in collection + circRefColl.push(value) + } + if (typeof value === 'bigint') return `${value.toString()}n` + return value + }) +} + +const deserialize = (val: string) => { + return JSON.parse(val, (_key, value) => { + if (typeof value === 'string' && /^\d+n$/.test(value)) { + return BigInt(value.slice(0, -1)) + } else return value + }).data +} + +export const memoizer = memoize({ + cachePath: './mem-cache', + serialize, + deserialize, +}) diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index eafb65cc1a..2988565ef7 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -1814,6 +1814,9 @@ importers: lodash.flatmap: specifier: 4.5.0 version: 4.5.0 + memoize-fs: + specifier: github:rouzwelt/memoize-fs#e5fcc9f6effc4ad087514372a53a49d380520ad5 + version: github.com/rouzwelt/memoize-fs/e5fcc9f6effc4ad087514372a53a49d380520ad5 numbro: specifier: 2.5.0 version: 2.5.0 @@ -32185,6 +32188,11 @@ packages: resolution: {integrity: sha512-8q7VEgMJW4J8tcfVPy8g09NcQwZdbwFEqhe/WZkoIzjn/3TGDwtOCYtXGxA3O8tPzpczCCDgv+P2P5y00ZJOOg==} engines: {node: '>= 8'} + /meriyah@4.4.2: + resolution: {integrity: sha512-fENZIbs4tscI3IGRGtPrCoW4H4oGzVQrQCVCGRv+92kFXKkvxr52ZNR684ICvDC/UBWg9ioGc2X6pMnWOtRYwA==} + engines: {node: '>=10.4.0'} + dev: false + /merkle-patricia-tree@2.3.2: resolution: {integrity: sha512-81PW5m8oz/pz3GvsAwbauj7Y00rqm81Tzad77tHBwU7pIAtN+TJnMSOJhxBKflSVYhptMMb9RskhqHqrSm1V+g==} dependencies: @@ -41300,6 +41308,7 @@ packages: /web3-provider-engine@14.2.1: resolution: {integrity: sha512-iSv31h2qXkr9vrL6UZDm4leZMc32SjWJFGOp/D92JXfcEboCqraZyuExDkpxKw8ziTufXieNM7LSXNHzszYdJw==} + deprecated: 'This package has been deprecated, see the README for details: https://github.com/MetaMask/web3-provider-engine' dependencies: async: 2.6.4 backoff: 2.5.0 @@ -42339,3 +42348,14 @@ packages: dependencies: bn.js: 4.12.0 ethereumjs-util: 6.2.1 + + github.com/rouzwelt/memoize-fs/e5fcc9f6effc4ad087514372a53a49d380520ad5: + resolution: {tarball: https://codeload.github.com/rouzwelt/memoize-fs/tar.gz/e5fcc9f6effc4ad087514372a53a49d380520ad5} + name: memoize-fs + version: 3.0.0 + engines: {node: '>= 10.13.0', npm: '>= 6.0.0'} + prepare: true + requiresBuild: true + dependencies: + meriyah: 4.4.2 + dev: false