From 750fe5b162698b9238c871324e8b3403ceee7c80 Mon Sep 17 00:00:00 2001 From: Shiba <44804845+DeepDoge@users.noreply.github.com> Date: Thu, 25 Jul 2024 10:37:32 +0000 Subject: [PATCH] ok fixed that --- modules/app/src/features/post/FeedViewer.ts | 25 ++++++---- modules/app/src/features/post/types.ts | 8 ---- modules/contracts/compile.ts | 10 ++-- modules/contracts/package.json | 3 +- .../artifacts/EternisDefaultIndexer.abi.json | 1 - .../src/artifacts/EternisDefaultIndexer.ts | 2 - .../artifacts/EternisProxy_SSTORE.abi.json | 1 - .../src/artifacts/EternisProxy_SSTORE.ts | 2 - .../src/artifacts/IEternisIndexer.abi.json | 1 - .../src/artifacts/IEternisIndexer.ts | 2 - .../src/artifacts/IEternisProxy.abi.json | 1 - .../contracts/src/artifacts/IEternisProxy.ts | 2 - modules/service/scripts/generate-routes.ts | 48 +++++++++++++------ modules/service/src/exports.ts | 2 +- .../service/src/routes/posts/feed/+expose.ts | 27 +++++++---- modules/service/tsconfig.json | 2 +- modules/shared/package.json | 4 ++ modules/shared/tsconfig.json | 19 ++++++++ modules/shared/utils/memoize.ts | 36 ++++++++++++++ package-lock.json | 14 ++++-- package.json | 3 +- 21 files changed, 147 insertions(+), 66 deletions(-) delete mode 100644 modules/app/src/features/post/types.ts delete mode 100644 modules/contracts/src/artifacts/EternisDefaultIndexer.abi.json delete mode 100644 modules/contracts/src/artifacts/EternisDefaultIndexer.ts delete mode 100644 modules/contracts/src/artifacts/EternisProxy_SSTORE.abi.json delete mode 100644 modules/contracts/src/artifacts/EternisProxy_SSTORE.ts delete mode 100644 modules/contracts/src/artifacts/IEternisIndexer.abi.json delete mode 100644 modules/contracts/src/artifacts/IEternisIndexer.ts delete mode 100644 modules/contracts/src/artifacts/IEternisProxy.abi.json delete mode 100644 modules/contracts/src/artifacts/IEternisProxy.ts create mode 100644 modules/shared/package.json create mode 100644 modules/shared/tsconfig.json create mode 100644 modules/shared/utils/memoize.ts diff --git a/modules/app/src/features/post/FeedViewer.ts b/modules/app/src/features/post/FeedViewer.ts index 2a3a249..a9301b2 100644 --- a/modules/app/src/features/post/FeedViewer.ts +++ b/modules/app/src/features/post/FeedViewer.ts @@ -1,10 +1,11 @@ +import { posts_feed } from "@root/service"; import { fragment, tags } from "purify-js"; import { globalSheet } from "~/styles"; import { sw } from "~/sw"; import { Bytes32Hex } from "~/utils/hex"; import { style } from "~/utils/style"; import { PostViewer } from "./PostViewer"; -import { FeedPost } from "./types"; + const { div, ul, li } = tags; export function FeedViewer(feedId: Bytes32Hex, startIndexInclusive: bigint = 0n) { @@ -14,8 +15,8 @@ export function FeedViewer(feedId: Bytes32Hex, startIndexInclusive: bigint = 0n) const posts = ul(); - let oldestPost: FeedPost | null | undefined; - let newestPost: FeedPost | undefined; + let oldestPost: posts_feed.FeedPost | null | undefined; + let newestPost: posts_feed.FeedPost | undefined; let busy = false; loadMore(); async function loadMore() { @@ -23,9 +24,12 @@ export function FeedViewer(feedId: Bytes32Hex, startIndexInclusive: bigint = 0n) busy = true; try { if (oldestPost === null) return; - const response = await sw - .use("/posts/feed") - .getFeed(feedId, oldestPost ? oldestPost.index - 1n : null, -1n, 256n); + const response = await sw.use("/posts/feed").getFeed({ + feedId, + cursor: oldestPost ? oldestPost.index - 1n : null, + direction: -1n, + limit: 256n, + }); posts.children(response.map((post) => li().children(PostViewer(post)))); oldestPost = response.at(-1) ?? null; @@ -41,9 +45,12 @@ export function FeedViewer(feedId: Bytes32Hex, startIndexInclusive: bigint = 0n) if (busy) return; busy = true; try { - const response = await sw - .use("/posts/feed") - .getFeed(feedId, newestPost ? newestPost.index + 1n : 0n, 1n, 256n); + const response = await sw.use("/posts/feed").getFeed({ + feedId, + cursor: newestPost ? newestPost.index + 1n : 0n, + direction: 1n, + limit: 256n, + }); response.sort((a, b) => b.time - a.time); posts.element.prepend(...response.map((post) => li().children(PostViewer(post)).element)); diff --git a/modules/app/src/features/post/types.ts b/modules/app/src/features/post/types.ts deleted file mode 100644 index d1ad73a..0000000 --- a/modules/app/src/features/post/types.ts +++ /dev/null @@ -1,8 +0,0 @@ -export type FeedPost = { - origin: `0x${string}`; - sender: `0x${string}`; - id: string; - index: bigint; - time: number; - contentBytesHex: string; -}; diff --git a/modules/contracts/compile.ts b/modules/contracts/compile.ts index e121f47..42138b4 100644 --- a/modules/contracts/compile.ts +++ b/modules/contracts/compile.ts @@ -5,6 +5,7 @@ import { compileSol } from "solc-typed-ast"; const CONTRACTS_DIR = path.resolve("./src"); const NODE_MODULES_DIR = path.resolve("../../node_modules"); +const ARTIFACTS_DIR = path.resolve("./artifacts"); async function findSolidityFilesRecursive(dir: string): Promise { const files = await fs.readdir(dir, { withFileTypes: true }); @@ -35,9 +36,8 @@ const solidityFilesByDir = solidityFiles.reduce( ); for (const [dirPath, solidityFiles] of Object.entries(solidityFilesByDir)) { - const artifactsDirPath = path.resolve(`${dirPath}/artifacts`); - await fs.rm(artifactsDirPath, { recursive: true }).catch(() => {}); - await fs.mkdir(artifactsDirPath, { recursive: true }); + await fs.rm(ARTIFACTS_DIR, { recursive: true }).catch(() => {}); + await fs.mkdir(ARTIFACTS_DIR, { recursive: true }); for (const filePath of solidityFiles) { const name = path.basename(filePath, ".sol"); console.log(`> Compiling ${bold(name)} in ${bold(dirPath)}`); @@ -51,7 +51,7 @@ for (const [dirPath, solidityFiles] of Object.entries(solidityFilesByDir)) { const bin: string = result.data["contracts"][filePath][name]["evm"]["bytecode"]["object"]; await fs.writeFile( - path.join(artifactsDirPath, `${name}.ts`), + path.join(ARTIFACTS_DIR, `${name}.ts`), [ `export type ${name}_ABI = typeof ${name}_ABI;`, `export const ${name}_ABI = ${JSON.stringify(abi)} as const;`, @@ -59,7 +59,7 @@ for (const [dirPath, solidityFiles] of Object.entries(solidityFilesByDir)) { ].join("\n"), ); - await fs.writeFile(path.join(artifactsDirPath, `${name}.abi.json`), JSON.stringify(abi)); + await fs.writeFile(path.join(ARTIFACTS_DIR, `${name}.abi.json`), JSON.stringify(abi)); console.log(green(`>> ${bold(name)} compiled successfully!`)); } diff --git a/modules/contracts/package.json b/modules/contracts/package.json index eafd01d..0dbc465 100644 --- a/modules/contracts/package.json +++ b/modules/contracts/package.json @@ -2,7 +2,8 @@ "type": "module", "name": "@root/contracts", "scripts": { - "compile": "tsx ./compile.ts" + "compile": "tsx ./compile.ts", + "dev": "tsx --watch-path ./src ./compile.ts" }, "exports": { "./connect": "./connect.ts" diff --git a/modules/contracts/src/artifacts/EternisDefaultIndexer.abi.json b/modules/contracts/src/artifacts/EternisDefaultIndexer.abi.json deleted file mode 100644 index 8e66957..0000000 --- a/modules/contracts/src/artifacts/EternisDefaultIndexer.abi.json +++ /dev/null @@ -1 +0,0 @@ -[{"anonymous":false,"inputs":[{"indexed":true,"internalType":"bytes32","name":"feedId","type":"bytes32"},{"indexed":false,"internalType":"uint96","name":"postId","type":"uint96"}],"name":"EternisPost","type":"event"},{"inputs":[{"internalType":"bytes32","name":"","type":"bytes32"},{"internalType":"uint256","name":"","type":"uint256"}],"name":"feeds","outputs":[{"internalType":"address","name":"origin","type":"address"},{"internalType":"uint96","name":"postId","type":"uint96"},{"internalType":"address","name":"sender","type":"address"},{"internalType":"uint96","name":"time","type":"uint96"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"bytes32","name":"feedId","type":"bytes32"},{"internalType":"uint256","name":"postIndex","type":"uint256"}],"name":"get","outputs":[{"internalType":"address","name":"origin","type":"address"},{"internalType":"address","name":"sender","type":"address"},{"internalType":"uint96","name":"postId","type":"uint96"},{"internalType":"uint256","name":"time","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"bytes32[]","name":"feedIds","type":"bytes32[]"},{"internalType":"uint96","name":"postId","type":"uint96"}],"name":"index","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"bytes32","name":"feedId","type":"bytes32"}],"name":"length","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"}] \ No newline at end of file diff --git a/modules/contracts/src/artifacts/EternisDefaultIndexer.ts b/modules/contracts/src/artifacts/EternisDefaultIndexer.ts deleted file mode 100644 index 86cb7d4..0000000 --- a/modules/contracts/src/artifacts/EternisDefaultIndexer.ts +++ /dev/null @@ -1,2 +0,0 @@ -export type EternisDefaultIndexer_ABI = typeof EternisDefaultIndexer_ABI; -export const EternisDefaultIndexer_ABI = [{"anonymous":false,"inputs":[{"indexed":true,"internalType":"bytes32","name":"feedId","type":"bytes32"},{"indexed":false,"internalType":"uint96","name":"postId","type":"uint96"}],"name":"EternisPost","type":"event"},{"inputs":[{"internalType":"bytes32","name":"","type":"bytes32"},{"internalType":"uint256","name":"","type":"uint256"}],"name":"feeds","outputs":[{"internalType":"address","name":"origin","type":"address"},{"internalType":"uint96","name":"postId","type":"uint96"},{"internalType":"address","name":"sender","type":"address"},{"internalType":"uint96","name":"time","type":"uint96"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"bytes32","name":"feedId","type":"bytes32"},{"internalType":"uint256","name":"postIndex","type":"uint256"}],"name":"get","outputs":[{"internalType":"address","name":"origin","type":"address"},{"internalType":"address","name":"sender","type":"address"},{"internalType":"uint96","name":"postId","type":"uint96"},{"internalType":"uint256","name":"time","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"bytes32[]","name":"feedIds","type":"bytes32[]"},{"internalType":"uint96","name":"postId","type":"uint96"}],"name":"index","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"bytes32","name":"feedId","type":"bytes32"}],"name":"length","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"}] as const; \ No newline at end of file diff --git a/modules/contracts/src/artifacts/EternisProxy_SSTORE.abi.json b/modules/contracts/src/artifacts/EternisProxy_SSTORE.abi.json deleted file mode 100644 index 78657eb..0000000 --- a/modules/contracts/src/artifacts/EternisProxy_SSTORE.abi.json +++ /dev/null @@ -1 +0,0 @@ -[{"inputs":[],"name":"counter","outputs":[{"internalType":"uint96","name":"","type":"uint96"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint96","name":"postId","type":"uint96"}],"name":"get","outputs":[{"internalType":"bytes","name":"postData","type":"bytes"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"contract IEternisIndexer","name":"indexer","type":"address"},{"internalType":"bytes32[]","name":"feedIds","type":"bytes32[]"},{"internalType":"bytes","name":"postData","type":"bytes"}],"name":"post","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint96","name":"","type":"uint96"}],"name":"store","outputs":[{"internalType":"bytes","name":"","type":"bytes"}],"stateMutability":"view","type":"function"}] \ No newline at end of file diff --git a/modules/contracts/src/artifacts/EternisProxy_SSTORE.ts b/modules/contracts/src/artifacts/EternisProxy_SSTORE.ts deleted file mode 100644 index 1d8d7cb..0000000 --- a/modules/contracts/src/artifacts/EternisProxy_SSTORE.ts +++ /dev/null @@ -1,2 +0,0 @@ -export type EternisProxy_SSTORE_ABI = typeof EternisProxy_SSTORE_ABI; -export const EternisProxy_SSTORE_ABI = [{"inputs":[],"name":"counter","outputs":[{"internalType":"uint96","name":"","type":"uint96"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint96","name":"postId","type":"uint96"}],"name":"get","outputs":[{"internalType":"bytes","name":"postData","type":"bytes"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"contract IEternisIndexer","name":"indexer","type":"address"},{"internalType":"bytes32[]","name":"feedIds","type":"bytes32[]"},{"internalType":"bytes","name":"postData","type":"bytes"}],"name":"post","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint96","name":"","type":"uint96"}],"name":"store","outputs":[{"internalType":"bytes","name":"","type":"bytes"}],"stateMutability":"view","type":"function"}] as const; \ No newline at end of file diff --git a/modules/contracts/src/artifacts/IEternisIndexer.abi.json b/modules/contracts/src/artifacts/IEternisIndexer.abi.json deleted file mode 100644 index bfabcc4..0000000 --- a/modules/contracts/src/artifacts/IEternisIndexer.abi.json +++ /dev/null @@ -1 +0,0 @@ -[{"anonymous":false,"inputs":[{"indexed":true,"internalType":"bytes32","name":"feedId","type":"bytes32"},{"indexed":false,"internalType":"uint96","name":"postId","type":"uint96"}],"name":"EternisPost","type":"event"},{"inputs":[{"internalType":"bytes32","name":"feedId","type":"bytes32"},{"internalType":"uint256","name":"index","type":"uint256"}],"name":"get","outputs":[{"internalType":"address","name":"origin","type":"address"},{"internalType":"address","name":"sender","type":"address"},{"internalType":"uint96","name":"postId","type":"uint96"},{"internalType":"uint256","name":"time","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"bytes32[]","name":"feedIds","type":"bytes32[]"},{"internalType":"uint96","name":"postId","type":"uint96"}],"name":"index","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"bytes32","name":"feedId","type":"bytes32"}],"name":"length","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"}] \ No newline at end of file diff --git a/modules/contracts/src/artifacts/IEternisIndexer.ts b/modules/contracts/src/artifacts/IEternisIndexer.ts deleted file mode 100644 index 6304af3..0000000 --- a/modules/contracts/src/artifacts/IEternisIndexer.ts +++ /dev/null @@ -1,2 +0,0 @@ -export type IEternisIndexer_ABI = typeof IEternisIndexer_ABI; -export const IEternisIndexer_ABI = [{"anonymous":false,"inputs":[{"indexed":true,"internalType":"bytes32","name":"feedId","type":"bytes32"},{"indexed":false,"internalType":"uint96","name":"postId","type":"uint96"}],"name":"EternisPost","type":"event"},{"inputs":[{"internalType":"bytes32","name":"feedId","type":"bytes32"},{"internalType":"uint256","name":"index","type":"uint256"}],"name":"get","outputs":[{"internalType":"address","name":"origin","type":"address"},{"internalType":"address","name":"sender","type":"address"},{"internalType":"uint96","name":"postId","type":"uint96"},{"internalType":"uint256","name":"time","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"bytes32[]","name":"feedIds","type":"bytes32[]"},{"internalType":"uint96","name":"postId","type":"uint96"}],"name":"index","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"bytes32","name":"feedId","type":"bytes32"}],"name":"length","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"}] as const; \ No newline at end of file diff --git a/modules/contracts/src/artifacts/IEternisProxy.abi.json b/modules/contracts/src/artifacts/IEternisProxy.abi.json deleted file mode 100644 index f1ec114..0000000 --- a/modules/contracts/src/artifacts/IEternisProxy.abi.json +++ /dev/null @@ -1 +0,0 @@ -[{"inputs":[{"internalType":"uint96","name":"postId","type":"uint96"}],"name":"get","outputs":[{"internalType":"bytes","name":"postData","type":"bytes"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"contract IEternisIndexer","name":"indexer","type":"address"},{"internalType":"bytes32[]","name":"feedIds","type":"bytes32[]"},{"internalType":"bytes","name":"postData","type":"bytes"}],"name":"post","outputs":[],"stateMutability":"nonpayable","type":"function"}] \ No newline at end of file diff --git a/modules/contracts/src/artifacts/IEternisProxy.ts b/modules/contracts/src/artifacts/IEternisProxy.ts deleted file mode 100644 index 407ee6f..0000000 --- a/modules/contracts/src/artifacts/IEternisProxy.ts +++ /dev/null @@ -1,2 +0,0 @@ -export type IEternisProxy_ABI = typeof IEternisProxy_ABI; -export const IEternisProxy_ABI = [{"inputs":[{"internalType":"uint96","name":"postId","type":"uint96"}],"name":"get","outputs":[{"internalType":"bytes","name":"postData","type":"bytes"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"contract IEternisIndexer","name":"indexer","type":"address"},{"internalType":"bytes32[]","name":"feedIds","type":"bytes32[]"},{"internalType":"bytes","name":"postData","type":"bytes"}],"name":"post","outputs":[],"stateMutability":"nonpayable","type":"function"}] as const; \ No newline at end of file diff --git a/modules/service/scripts/generate-routes.ts b/modules/service/scripts/generate-routes.ts index f3d0675..b028d6b 100644 --- a/modules/service/scripts/generate-routes.ts +++ b/modules/service/scripts/generate-routes.ts @@ -6,21 +6,39 @@ const __dirname = path.dirname(fileURLToPath(import.meta.url)); const routesPath = path.join(__dirname, "../src/routes"); const outputFilePath = path.join(__dirname, "../src/routes.ts"); -const files = await getFiles(routesPath); - -const output = `export type Routes = { -${files - .filter((filepath) => { - const basename = path.basename(filepath); - return basename === "+expose.ts"; - }) - .map((filepath) => { - const key = filepath.slice(routesPath.length, -("+expose.ts".length + 1)); - return `${JSON.stringify(key)}: typeof import(${JSON.stringify(path.resolve(filepath))})`; - }) - .join(",\n")} -} -`; +const files = (await getFiles(routesPath)).filter((filepath) => { + const basename = path.basename(filepath); + return basename === "+expose.ts"; +}); + +const output = [ + files + .map((filepath, index) => { + const from = JSON.stringify(path.resolve(filepath).slice(0, -3)); + return `import type * as _${index} from ${from}`; + }) + .join("\n"), + [ + "export type Routes = {\n\t", + files + .map((filepath, index) => { + const key = filepath.slice(routesPath.length, -("+expose.ts".length + 1)); + return `${JSON.stringify(key)}: typeof _${index}`; + }) + .join(",\n\t"), + "\n}", + ].join(""), + [ + "export {\n\t", + files + .map((filepath, index) => { + const key = filepath.slice(routesPath.length + 1, -("+expose.ts".length + 1)).replaceAll("/", "_"); + return `_${index} as ${key}`; + }) + .join(",\n\t"), + "\n}", + ].join(""), +].join("\n\n"); fs.writeFileSync(outputFilePath, output, "utf-8"); diff --git a/modules/service/src/exports.ts b/modules/service/src/exports.ts index 0aaa0d2..565b59c 100644 --- a/modules/service/src/exports.ts +++ b/modules/service/src/exports.ts @@ -1,2 +1,2 @@ export * from "./exposed/types"; -export type { Routes } from "./routes"; +export * from "./routes"; diff --git a/modules/service/src/routes/posts/feed/+expose.ts b/modules/service/src/routes/posts/feed/+expose.ts index 25ba9c1..13af418 100644 --- a/modules/service/src/routes/posts/feed/+expose.ts +++ b/modules/service/src/routes/posts/feed/+expose.ts @@ -1,16 +1,27 @@ -import { FeedPost } from "@root/app/src/features/post/types"; import { Bytes32Hex } from "@root/app/src/utils/hex"; import { IEternisIndexer, IEternisProxy } from "@root/contracts/connect"; +import { memoizeUntilSettled } from "@root/shared/utils/memoize"; import { JsonRpcProvider, toBeHex } from "ethers"; import { db } from "~/db"; import { Config } from "~/routes/config/module"; -export async function getFeed( - feedId: Bytes32Hex, - cursor: bigint | null, - direction: -1n | 1n, - limit: bigint, -): Promise { +export type GetFeedParameters = { + feedId: Bytes32Hex; + cursor: bigint | null; + direction: -1n | 1n; + limit: bigint; +}; + +export type FeedPost = { + origin: `0x${string}`; + sender: `0x${string}`; + id: string; + index: bigint; + time: number; + contentBytesHex: string; +}; + +export const getFeed = memoizeUntilSettled(async ({ feedId, cursor, direction, limit }): Promise => { const config = await Config.get(); const provider = new JsonRpcProvider(config.networks[0].providers[0]); const indexerContract = IEternisIndexer.connect(provider, config.networks[0].contracts.EternisIndexer); @@ -53,4 +64,4 @@ export async function getFeed( } return await Promise.all(postPromises); -} +}); diff --git a/modules/service/tsconfig.json b/modules/service/tsconfig.json index 39d9fc3..1bb5956 100644 --- a/modules/service/tsconfig.json +++ b/modules/service/tsconfig.json @@ -15,5 +15,5 @@ "~/*": ["./src/*"] } }, - "include": ["src", "../app/src/features/post/types.ts", "../app/src/features/config/broadcastChannels.ts"] + "include": ["src"] } diff --git a/modules/shared/package.json b/modules/shared/package.json new file mode 100644 index 0000000..f58d61e --- /dev/null +++ b/modules/shared/package.json @@ -0,0 +1,4 @@ +{ + "type": "module", + "name": "@root/shared" +} diff --git a/modules/shared/tsconfig.json b/modules/shared/tsconfig.json new file mode 100644 index 0000000..88abf53 --- /dev/null +++ b/modules/shared/tsconfig.json @@ -0,0 +1,19 @@ +{ + "extends": "../../tsconfig.base.json", + "compilerOptions": { + "lib": ["WebWorker", "DOM", "ESNext"], + "types": ["vite/client", "@total-typescript/ts-reset"], // Both service and client use the vite/client + + "module": "ESNext", + "target": "ESNext", + + "moduleResolution": "Bundler", + "moduleDetection": "force", + "noEmit": true, + + "paths": { + "~/*": ["./*"] + } + }, + "include": ["."] +} diff --git a/modules/shared/utils/memoize.ts b/modules/shared/utils/memoize.ts new file mode 100644 index 0000000..510f37d --- /dev/null +++ b/modules/shared/utils/memoize.ts @@ -0,0 +1,36 @@ +export function memoize( + fn: (...args: TParams) => TReturns, + key: (...args: TParams) => unknown = (...args) => JSON.stringify(args, (_, value) => String(value)), +) { + const caches = new Map(); + return (...args: TParams): TReturns => { + const cacheKey = key(...args); + const cache = caches.get(cacheKey); + if (cache) { + return cache; + } + + const result = fn(...args); + caches.set(cacheKey, result); + return result; + }; +} + +export function memoizeUntilSettled>( + fn: (...args: TParams) => TReturns, + key: (...args: TParams) => unknown = (...args) => JSON.stringify(args, (_, value) => String(value)), +) { + const caches = new Map(); + return (...args: TParams): TReturns => { + const cacheKey = key(...args); + const cache = caches.get(cacheKey); + if (cache) { + return cache; + } + + const result = fn(...args); + caches.set(cacheKey, result); + result.then(() => caches.delete(cacheKey)); + return result; + }; +} diff --git a/package-lock.json b/package-lock.json index a9954c6..2d3dc62 100644 --- a/package-lock.json +++ b/package-lock.json @@ -30,7 +30,8 @@ "name": "@root/app" }, "modules/common": { - "name": "@root/common" + "name": "@root/common", + "extraneous": true }, "modules/contracts": { "name": "@root/contracts" @@ -41,6 +42,9 @@ "modules/service": { "name": "@root/service" }, + "modules/shared": { + "name": "@root/shared" + }, "node_modules/@adraffy/ens-normalize": { "version": "1.10.1", "dev": true, @@ -120,10 +124,6 @@ "resolved": "modules/app", "link": true }, - "node_modules/@root/common": { - "resolved": "modules/common", - "link": true - }, "node_modules/@root/contracts": { "resolved": "modules/contracts", "link": true @@ -136,6 +136,10 @@ "resolved": "modules/service", "link": true }, + "node_modules/@root/shared": { + "resolved": "modules/shared", + "link": true + }, "node_modules/@scure/base": { "version": "1.1.7", "dev": true, diff --git a/package.json b/package.json index d03d89f..dcf31d2 100644 --- a/package.json +++ b/package.json @@ -5,7 +5,7 @@ "./modules/*" ], "scripts": { - "dev": "npm-run-all --parallel *:dev", + "dev": "npm run contracts:compile && npm-run-all --parallel *:dev", "build": "npm run service:build && npm run app:build", "preview": "npm run preview --prefix ./modules/app", "postinstall": "npm run contracts:compile", @@ -15,6 +15,7 @@ "app:build": "npm run build --prefix ./modules/app", "service:dev": "npm run dev --prefix ./modules/service", "service:build": "npm run build --prefix ./modules/service", + "contracts:dev": "npm run dev --prefix ./modules/contracts", "contracts:compile": "npm run compile --prefix ./modules/contracts" }, "devDependencies": {