From f4320e9540e10845785bf45288882125e6141a7a Mon Sep 17 00:00:00 2001 From: Alexey Immoreev Date: Tue, 23 May 2023 03:35:09 +0300 Subject: [PATCH] TRPC v10 (#1215) --- backend/package.json | 3 +- backend/src/index.ts | 8 +- backend/src/router/account/activity.ts | 22 +- backend/src/router/account/balance.ts | 12 +- backend/src/router/account/by-id.ts | 29 +- backend/src/router/account/fungible-tokens.ts | 49 +- backend/src/router/account/index.ts | 42 +- backend/src/router/account/list.ts | 20 +- .../src/router/account/non-fungible-tokens.ts | 61 +- .../src/router/account/transactions-count.ts | 10 +- backend/src/router/block/by-id.ts | 20 +- backend/src/router/block/final.ts | 20 +- backend/src/router/block/index.ts | 20 +- backend/src/router/block/list.ts | 20 +- backend/src/router/contract/by-id.ts | 12 +- backend/src/router/contract/index.ts | 8 +- backend/src/router/fungible-tokens/index.ts | 38 +- backend/src/router/index.ts | 45 +- .../router/receipt/get-transaction-hash.ts | 30 +- backend/src/router/receipt/index.ts | 17 +- backend/src/router/receipt/list.ts | 32 +- .../src/router/stats/circulating-supply.ts | 32 +- backend/src/router/stats/index.ts | 16 +- backend/src/router/stats/tokens-burnt.ts | 18 +- backend/src/router/subscriptions.ts | 220 ++-- backend/src/router/telemetry.ts | 12 +- backend/src/router/transaction/get.ts | 50 +- backend/src/router/transaction/index.ts | 20 +- backend/src/router/transaction/list.ts | 65 +- backend/src/router/trpc.ts | 15 + backend/src/router/utils/deploy.ts | 10 +- backend/src/router/utils/index.ts | 24 +- backend/src/router/utils/protocol.ts | 12 +- backend/src/router/utils/search.ts | 15 +- backend/src/router/utils/subscriptions.ts | 10 +- backend/src/server.ts | 3 +- backend/src/utils/error.ts | 16 +- common/package.json | 6 +- common/src/types/common.ts | 54 + common/src/types/procedures.ts | 17 +- common/src/types/trpc.ts | 275 ++--- frontend/jest.config.ts | 1 - frontend/package.json | 10 +- frontend/patches/@trpc+next+10.26.0.patch | 271 +++++ frontend/patches/@trpc+next+9.27.4.patch | 380 ------- .../components/accounts/AccountDetails.tsx | 10 +- .../src/components/accounts/AccountRow.tsx | 10 +- frontend/src/components/accounts/Accounts.tsx | 10 +- .../beta/accounts/AccountContract.tsx | 12 +- .../accounts/AccountFungibleTokenHistory.tsx | 13 +- .../beta/accounts/AccountFungibleTokens.tsx | 9 +- .../accounts/AccountNonFungibleTokens.tsx | 26 +- .../AccountNonFungibleTokensHistory.tsx | 11 +- .../components/beta/accounts/AccountTabs.tsx | 7 +- .../beta/accounts/AccountTransactionsView.tsx | 14 +- .../beta/transactions/InspectReceipt.tsx | 18 +- .../src/components/blocks/BlockDetails.tsx | 4 +- frontend/src/components/blocks/Blocks.tsx | 11 +- frontend/src/components/blocks/BlocksRow.tsx | 4 +- .../components/contracts/ContractDetails.tsx | 12 +- .../components/dashboard/DashboardBlock.tsx | 7 +- .../components/dashboard/DashboardNode.tsx | 7 +- .../dashboard/DashboardTransaction.tsx | 9 +- .../DashboardTransactionsHistoryChart.tsx | 10 +- frontend/src/components/nodes/NodeNav.tsx | 5 +- frontend/src/components/nodes/NodesCard.tsx | 11 +- frontend/src/components/nodes/NodesEpoch.tsx | 8 +- .../nodes/ValidatorTelemetryElements.tsx | 9 +- frontend/src/components/nodes/Validators.tsx | 4 +- .../src/components/nodes/ValidatorsList.tsx | 4 +- .../receipts/ReceiptsExecutedInBlock.tsx | 7 +- .../receipts/ReceiptsIncludedInBlock.tsx | 7 +- .../components/stats/ActiveAccountsByDate.tsx | 9 +- .../components/stats/ActiveAccountsList.tsx | 7 +- .../stats/ActiveContractsByDate.tsx | 7 +- .../components/stats/ActiveContractsList.tsx | 7 +- .../stats/CirculatingSupplyStats.tsx | 6 +- .../src/components/stats/GasUsedByDate.tsx | 8 +- .../components/stats/NewAccountsByDate.tsx | 8 +- .../components/stats/NewContractsByDate.tsx | 8 +- .../components/stats/ProtocolConfigInfo.tsx | 15 +- .../components/stats/TransactionsByDate.tsx | 5 +- .../components/transactions/ActionGroup.tsx | 4 +- .../transactions/TransactionDetails.tsx | 4 +- .../components/transactions/Transactions.tsx | 17 +- frontend/src/components/utils/DeployInfo.tsx | 2 +- frontend/src/components/utils/FlipMove.tsx | 4 +- frontend/src/components/utils/ListHandler.tsx | 8 +- .../src/components/utils/LongCardCell.tsx | 3 +- frontend/src/components/utils/Search.tsx | 2 +- .../src/components/utils/ServiceStatus.tsx | 6 +- frontend/src/hooks/use-subscription.ts | 112 +- frontend/src/libraries/subscriptions.ts | 142 ++- frontend/src/libraries/trpc.ts | 36 +- frontend/src/pages/_app.tsx | 41 +- frontend/src/pages/accounts/[...slug].tsx | 10 +- .../pages/api/circulating-supply-in-near.ts | 6 +- frontend/src/pages/api/circulating-supply.ts | 6 +- .../pages/api/fees-of-previous-7-days-utc.ts | 7 +- .../src/pages/api/fees-of-previous-day-utc.ts | 7 +- frontend/src/pages/api/metrics/indexer.ts | 4 +- frontend/src/pages/api/nodes.ts | 2 +- frontend/src/pages/api/status.ts | 2 +- .../src/pages/beta/accounts/[...slug].tsx | 5 +- .../src/pages/beta/fungible-tokens/index.tsx | 12 +- .../src/pages/beta/transactions/[hash].tsx | 3 +- frontend/src/pages/blocks/[hash].tsx | 13 +- frontend/src/pages/index.tsx | 2 +- frontend/src/pages/receipts/[id].tsx | 7 +- frontend/src/pages/transactions/[hash].tsx | 5 +- frontend/src/pages/transactions/index.tsx | 4 +- frontend/src/testing/utils.tsx | 6 +- package-lock.json | 982 ++++++++---------- 113 files changed, 1839 insertions(+), 2034 deletions(-) create mode 100644 backend/src/router/trpc.ts create mode 100644 frontend/patches/@trpc+next+10.26.0.patch delete mode 100644 frontend/patches/@trpc+next+9.27.4.patch diff --git a/backend/package.json b/backend/package.json index bbd7d9ac4..046fd0f5a 100644 --- a/backend/package.json +++ b/backend/package.json @@ -31,7 +31,7 @@ }, "homepage": "https://github.com/near/near-explorer#readme", "dependencies": { - "@trpc/server": "^9.27.4", + "@trpc/server": "^10.26.0", "cors": "^2.8.5", "date-fns": "^2.28.0", "dotenv-cli": "^5.0.0", @@ -43,7 +43,6 @@ "near-api-js": "^0.44.1", "pg": "^8.7.3", "ts-node": "^10.4.0", - "tsafe": "^0.10.0", "tsconfig-paths": "^4.1.2", "ws": "^8.6.0", "zod": "^3.16.0", diff --git a/backend/src/index.ts b/backend/src/index.ts index df432583a..9d4f7c119 100644 --- a/backend/src/index.ts +++ b/backend/src/index.ts @@ -4,7 +4,7 @@ import { config } from "@/backend/config"; import { Context } from "@/backend/context"; import { runTasks } from "@/backend/cron"; import { initGlobalState } from "@/backend/global-state"; -import { AppRouter, router } from "@/backend/router"; +import { AppRouter, appRouter } from "@/backend/router"; import { connectWebsocketServer, createApp, @@ -14,7 +14,7 @@ import { import { onError } from "@/backend/utils/error"; import { setupTelemetryDb } from "@/backend/utils/telemetry"; -async function main(appRouter: AppRouter): Promise { +async function main(indexRouter: AppRouter): Promise { // eslint-disable-next-line no-console console.log("Starting Explorer backend..."); const context: Context = { @@ -28,7 +28,7 @@ async function main(appRouter: AppRouter): Promise { // Therefore we set max listeners to limit to infinity context.subscriptionsEventEmitter.setMaxListeners(0); const trpcOptions: RouterOptions & WebsocketRouterOptions = { - router: appRouter, + router: indexRouter, createContext: ({ req, res }) => ({ ...context, req, res }), onError, }; @@ -79,4 +79,4 @@ async function main(appRouter: AppRouter): Promise { console.log("Explorer backend started"); } -void main(router); +void main(appRouter); diff --git a/backend/src/router/account/activity.ts b/backend/src/router/account/activity.ts index 77b4a8148..c286e839f 100644 --- a/backend/src/router/account/activity.ts +++ b/backend/src/router/account/activity.ts @@ -1,12 +1,11 @@ -import * as trpc from "@trpc/server"; import { z } from "zod"; -import { RequestContext } from "@/backend/context"; import { indexerActivityDatabase, indexerDatabase, } from "@/backend/database/databases"; import { div } from "@/backend/database/utils"; +import { t } from "@/backend/router/trpc"; import { validators } from "@/backend/router/validators"; import { Action, @@ -483,13 +482,15 @@ const getTransactionsByHashes = async ( }, new Map()); }; -export const router = trpc.router().query("activity", { - input: z.strictObject({ - accountId: validators.accountId, - limit: validators.limit, - cursor: validators.accountActivityCursor.optional(), - }), - resolve: async ({ input }) => { +export const procedure = t.procedure + .input( + z.strictObject({ + accountId: validators.accountId, + limit: validators.limit, + cursor: validators.accountActivityCursor.optional(), + }) + ) + .query(async ({ input }) => { const changes = await queryBalanceChanges( input.accountId, input.limit, @@ -537,5 +538,4 @@ export const router = trpc.router().query("activity", { } : undefined, }; - }, -}); + }); diff --git a/backend/src/router/account/balance.ts b/backend/src/router/account/balance.ts index 0ee9685d7..4116deb63 100644 --- a/backend/src/router/account/balance.ts +++ b/backend/src/router/account/balance.ts @@ -1,14 +1,13 @@ -import * as trpc from "@trpc/server"; import { TRPCError } from "@trpc/server"; import { z } from "zod"; -import { RequestContext } from "@/backend/context"; import { getAccountRpcData } from "@/backend/router/account/by-id"; +import { t } from "@/backend/router/trpc"; import { validators } from "@/backend/router/validators"; -export const router = trpc.router().query("nonStakedBalance", { - input: z.strictObject({ id: validators.accountId }), - resolve: async ({ input: { id } }) => { +export const procedure = t.procedure + .input(z.strictObject({ id: validators.accountId })) + .query(async ({ input: { id } }) => { const rpcData = await getAccountRpcData(id); if (!rpcData) { throw new TRPCError({ @@ -17,5 +16,4 @@ export const router = trpc.router().query("nonStakedBalance", { }); } return rpcData.amount.toString(); - }, -}); + }); diff --git a/backend/src/router/account/by-id.ts b/backend/src/router/account/by-id.ts index e9273e766..21fe4dcc1 100644 --- a/backend/src/router/account/by-id.ts +++ b/backend/src/router/account/by-id.ts @@ -1,12 +1,11 @@ -import * as trpc from "@trpc/server"; import { sha256 } from "js-sha256"; import { z } from "zod"; import { config } from "@/backend/config"; -import { RequestContext } from "@/backend/context"; import { indexerDatabase } from "@/backend/database/databases"; import { div } from "@/backend/database/utils"; import { getAccountTransactionsCount } from "@/backend/router/account/utils"; +import { t } from "@/backend/router/trpc"; import { validators } from "@/backend/router/validators"; import * as nearApi from "@/backend/utils/near"; import { ignoreIfDoesNotExist } from "@/backend/utils/near"; @@ -120,11 +119,10 @@ const getAccountInfo = async (accountId: string) => { }; }; -export const router = trpc - .router() - .query("byIdOld", { - input: z.strictObject({ id: validators.accountId }), - resolve: async ({ input: { id } }) => { +export const procedures = { + byIdOld: t.procedure + .input(z.strictObject({ id: validators.accountId })) + .query(async ({ input: { id } }) => { const [accountInfo, accountDetails] = await Promise.all([ getAccountInfo(id), getAccountDetails(id), @@ -136,13 +134,14 @@ export const router = trpc ...accountInfo, details: accountDetails, }; - }, - }) - .query("byId", { - input: z.strictObject({ - id: validators.accountId, }), - resolve: async ({ input: { id } }) => { + byId: t.procedure + .input( + z.strictObject({ + id: validators.accountId, + }) + ) + .query(async ({ input: { id } }) => { if (/[A-Z]/.test(id)) { return null; } @@ -178,5 +177,5 @@ export const router = trpc transactionsCount.outTransactionsCount : undefined, }; - }, - }); + }), +}; diff --git a/backend/src/router/account/fungible-tokens.ts b/backend/src/router/account/fungible-tokens.ts index b11ee56f6..e69221f1c 100644 --- a/backend/src/router/account/fungible-tokens.ts +++ b/backend/src/router/account/fungible-tokens.ts @@ -1,8 +1,7 @@ -import * as trpc from "@trpc/server"; import { z } from "zod"; -import { RequestContext } from "@/backend/context"; import { FungibleTokenMetadata } from "@/backend/router/fungible-tokens"; +import { t } from "@/backend/router/trpc"; import { validators } from "@/backend/router/validators"; import * as nearApi from "@/backend/utils/near"; import { notNullishGuard } from "@/common/utils/utils"; @@ -17,15 +16,16 @@ export const validateBase64Image = ( return base64ImageRegex.test(base64Image) ? base64Image : null; }; -export const router = trpc - .router() - .query("fungibleTokens", { - input: z.strictObject({ - accountId: validators.accountId, - }), - resolve: async ({ input: { accountId } }) => { +export const procedures = { + fungibleTokens: t.procedure + .input( + z.strictObject({ + accountId: validators.accountId, + }) + ) + .query(async ({ input: { accountId } }) => { // TODO: add data from Enhanced API - const selection: any[] = []; + const selection: { contractId: string }[] = []; const contractIds = selection.map((row) => row.contractId); const tokens = await Promise.all( contractIds.map(async (contractId) => { @@ -55,16 +55,25 @@ export const router = trpc }) ); return tokens.filter(notNullishGuard); - }, - }) - .query("fungibleTokenHistory", { - input: z.strictObject({ - accountId: validators.accountId, - tokenAuthorAccountId: validators.accountId, }), - resolve: async ({ input: { accountId, tokenAuthorAccountId } }) => { + fungibleTokenHistory: t.procedure + .input( + z.strictObject({ + accountId: validators.accountId, + tokenAuthorAccountId: validators.accountId, + }) + ) + .query(async ({ input: { accountId, tokenAuthorAccountId } }) => { // TODO: add data from Enhanced API - const elements: any[] = []; + const elements: { + amount: string; + prevAccountId: string; + nextAccountId: string; + receiptId: string; + timestamp: string; + transactionHash: string; + blockHeight: string; + }[] = []; const baseAmount = await nearApi.callViewMethod( tokenAuthorAccountId, "ft_balance_of", @@ -85,5 +94,5 @@ export const router = trpc timestamp: parseInt(element.timestamp, 10), })), }; - }, - }); + }), +}; diff --git a/backend/src/router/account/index.ts b/backend/src/router/account/index.ts index 485c2ff90..3998cfdfc 100644 --- a/backend/src/router/account/index.ts +++ b/backend/src/router/account/index.ts @@ -1,21 +1,25 @@ -import * as trpc from "@trpc/server"; +import { t } from "@/backend/router/trpc"; -import { RequestContext } from "@/backend/context"; +import { procedure as activity } from "./activity"; +import { procedure as nonStakedBalance } from "./balance"; +import { procedures as byIdProcedures } from "./by-id"; +import { procedures as fungibleTokensProcedures } from "./fungible-tokens"; +import { procedure as listByTimestamp } from "./list"; +import { procedures as nonFungibleTokensProcedures } from "./non-fungible-tokens"; +import { procedure as transactionsCount } from "./transactions-count"; -import { router as activityRouter } from "./activity"; -import { router as balanceRouter } from "./balance"; -import { router as byIdRouter } from "./by-id"; -import { router as fungibleTokensRouter } from "./fungible-tokens"; -import { router as listRouter } from "./list"; -import { router as nonFungibleTokensRouter } from "./non-fungible-tokens"; -import { router as transactionsCountRouter } from "./transactions-count"; - -export const router = trpc - .router() - .merge(byIdRouter) - .merge(listRouter) - .merge(transactionsCountRouter) - .merge(fungibleTokensRouter) - .merge(activityRouter) - .merge(nonFungibleTokensRouter) - .merge(balanceRouter); +export const router = t.router({ + byId: byIdProcedures.byId, + byIdOld: byIdProcedures.byIdOld, + listByTimestamp, + transactionsCount, + fungibleTokens: fungibleTokensProcedures.fungibleTokens, + fungibleTokenHistory: fungibleTokensProcedures.fungibleTokenHistory, + activity, + nonFungibleTokenContracts: + nonFungibleTokensProcedures.nonFungibleTokenContracts, + nonFungibleTokenHistory: nonFungibleTokensProcedures.nonFungibleTokenHistory, + nonFungibleTokens: nonFungibleTokensProcedures.nonFungibleTokens, + nonFungibleTokensCount: nonFungibleTokensProcedures.nonFungibleTokensCount, + nonStakedBalance, +}); diff --git a/backend/src/router/account/list.ts b/backend/src/router/account/list.ts index a4b1892d5..76c624f15 100644 --- a/backend/src/router/account/list.ts +++ b/backend/src/router/account/list.ts @@ -1,17 +1,18 @@ -import * as trpc from "@trpc/server"; import { z } from "zod"; -import { RequestContext } from "@/backend/context"; import { indexerDatabase } from "@/backend/database/databases"; import { div } from "@/backend/database/utils"; +import { t } from "@/backend/router/trpc"; import { validators } from "@/backend/router/validators"; -export const router = trpc.router().query("listByTimestamp", { - input: z.strictObject({ - limit: validators.limit, - cursor: validators.accountPagination.nullish(), - }), - resolve: async ({ input: { limit, cursor } }) => { +export const procedure = t.procedure + .input( + z.strictObject({ + limit: validators.limit, + cursor: validators.accountPagination.nullish(), + }) + ) + .query(async ({ input: { limit, cursor } }) => { let selection = indexerDatabase .selectFrom("accounts") .leftJoin("receipts as creationReceipt", (jb) => @@ -63,5 +64,4 @@ export const router = trpc.router().query("listByTimestamp", { ? parseInt(account.deletedTimestamp, 10) : undefined, })); - }, -}); + }); diff --git a/backend/src/router/account/non-fungible-tokens.ts b/backend/src/router/account/non-fungible-tokens.ts index 2547312ce..a8ff78b3f 100644 --- a/backend/src/router/account/non-fungible-tokens.ts +++ b/backend/src/router/account/non-fungible-tokens.ts @@ -1,10 +1,9 @@ -import * as trpc from "@trpc/server"; import { z } from "zod"; -import { RequestContext } from "@/backend/context"; import { indexerDatabase } from "@/backend/database/databases"; import { div } from "@/backend/database/utils"; import { validateBase64Image } from "@/backend/router/account/fungible-tokens"; +import { t } from "@/backend/router/trpc"; import { validators } from "@/backend/router/validators"; import * as nearApi from "@/backend/utils/near"; @@ -58,11 +57,10 @@ const buildMediaUrl = ( return `https://cloudflare-ipfs.com/ipfs/${media}`; }; -export const router = trpc - .router() - .query("nonFungibleTokenContracts", { - input: z.strictObject({ accountId: validators.accountId }), - resolve: async ({ input: { accountId } }) => { +export const procedures = { + nonFungibleTokenContracts: t.procedure + .input(z.strictObject({ accountId: validators.accountId })) + .query(async ({ input: { accountId } }) => { const selection = await indexerDatabase .selectFrom("assets__non_fungible_token_events") .select("emitted_by_contract_account_id as contractId") @@ -70,18 +68,17 @@ export const router = trpc .where("token_new_owner_account_id", "=", accountId) .execute(); return selection.map((row) => row.contractId); - }, - }) - .query("nonFungibleTokens", { - input: z.strictObject({ - contractId: validators.accountId, - accountId: validators.accountId, - limit: validators.limit, - cursor: z.number().optional(), }), - resolve: async ({ - input: { contractId, accountId, limit, cursor = 0 }, - }) => { + nonFungibleTokens: t.procedure + .input( + z.strictObject({ + contractId: validators.accountId, + accountId: validators.accountId, + limit: validators.limit, + cursor: z.number().optional(), + }) + ) + .query(async ({ input: { contractId, accountId, limit, cursor = 0 } }) => { const [nonFungibleTokenContractMetadata, nonFungibleTokenMetadata] = await Promise.all([ nearApi.callViewMethod( @@ -122,11 +119,10 @@ export const router = trpc items, cursor: lastItem ? lastItem.index + 1 : undefined, }; - }, - }) - .query("nonFungibleTokensCount", { - input: z.strictObject({ accountId: validators.accountId }), - resolve: async ({ input: { accountId } }) => { + }), + nonFungibleTokensCount: t.procedure + .input(z.strictObject({ accountId: validators.accountId })) + .query(async ({ input: { accountId } }) => { const selection = await indexerDatabase .selectFrom("assets__non_fungible_token_events") .select("emitted_by_contract_account_id as contractId") @@ -145,14 +141,15 @@ export const router = trpc (acc, count) => acc + parseInt(count, 10), 0 ); - }, - }) - .query("nonFungibleTokenHistory", { - input: z.strictObject({ - tokenAuthorAccountId: validators.accountId, - tokenId: validators.nonFungibleTokenId, }), - resolve: async ({ input: { tokenAuthorAccountId, tokenId } }) => { + nonFungibleTokenHistory: t.procedure + .input( + z.strictObject({ + tokenAuthorAccountId: validators.accountId, + tokenId: validators.nonFungibleTokenId, + }) + ) + .query(async ({ input: { tokenAuthorAccountId, tokenId } }) => { const selection = await indexerDatabase .selectFrom("assets__non_fungible_token_events") .innerJoin("receipts", (qb) => @@ -189,5 +186,5 @@ export const router = trpc receiptId: element.receiptId, timestamp: parseInt(element.timestamp, 10), })); - }, - }); + }), +}; diff --git a/backend/src/router/account/transactions-count.ts b/backend/src/router/account/transactions-count.ts index b505a3468..ce84e4157 100644 --- a/backend/src/router/account/transactions-count.ts +++ b/backend/src/router/account/transactions-count.ts @@ -1,11 +1,9 @@ -import * as trpc from "@trpc/server"; import { z } from "zod"; -import { RequestContext } from "@/backend/context"; import { getAccountTransactionsCount } from "@/backend/router/account/utils"; +import { t } from "@/backend/router/trpc"; import { validators } from "@/backend/router/validators"; -export const router = trpc.router().query("transactionsCount", { - input: z.strictObject({ id: validators.accountId }), - resolve: ({ input: { id } }) => getAccountTransactionsCount(id), -}); +export const procedure = t.procedure + .input(z.strictObject({ id: validators.accountId })) + .query(({ input: { id } }) => getAccountTransactionsCount(id)); diff --git a/backend/src/router/block/by-id.ts b/backend/src/router/block/by-id.ts index 7deaec850..96f00e01d 100644 --- a/backend/src/router/block/by-id.ts +++ b/backend/src/router/block/by-id.ts @@ -1,17 +1,18 @@ -import * as trpc from "@trpc/server"; import { z } from "zod"; -import { RequestContext } from "@/backend/context"; import { indexerDatabase } from "@/backend/database/databases"; import { count, div, sum } from "@/backend/database/utils"; +import { t } from "@/backend/router/trpc"; import { validators } from "@/backend/router/validators"; -export const router = trpc.router().query("byId", { - input: z.union([ - z.strictObject({ hash: validators.blockHash }), - z.strictObject({ height: validators.blockHeight }), - ]), - resolve: async ({ input }) => { +export const procedure = t.procedure + .input( + z.union([ + z.strictObject({ hash: validators.blockHash }), + z.strictObject({ height: validators.blockHeight }), + ]) + ) + .query(async ({ input }) => { const selection = await indexerDatabase .selectFrom((eb) => { let innerSelection = eb.selectFrom("blocks").select("block_hash"); @@ -83,5 +84,4 @@ export const router = trpc.router().query("byId", { gasUsed: gasUsedInChunksSelection?.gasUsed || "0", receiptsCount: receiptsCountSelection?.count || 0, }; - }, -}); + }); diff --git a/backend/src/router/block/final.ts b/backend/src/router/block/final.ts index de5d6740a..344edeb21 100644 --- a/backend/src/router/block/final.ts +++ b/backend/src/router/block/final.ts @@ -1,16 +1,17 @@ -import * as trpc from "@trpc/server"; import { z } from "zod"; -import { RequestContext } from "@/backend/context"; import { indexerDatabase } from "@/backend/database/databases"; +import { t } from "@/backend/router/trpc"; import * as nearApi from "@/backend/utils/near"; -export const router = trpc.router().query("final", { - input: z.discriminatedUnion("source", [ - z.strictObject({ source: z.literal("rpc") }), - z.strictObject({ source: z.literal("indexer") }), - ]), - resolve: async ({ input: { source } }) => { +export const procedure = t.procedure + .input( + z.discriminatedUnion("source", [ + z.strictObject({ source: z.literal("rpc") }), + z.strictObject({ source: z.literal("indexer") }), + ]) + ) + .query(async ({ input: { source } }) => { if (source === "rpc") { const block = await nearApi.sendJsonRpc("block", { finality: "final" }); return { @@ -24,5 +25,4 @@ export const router = trpc.router().query("final", { .limit(1) .executeTakeFirstOrThrow(); return block; - }, -}); + }); diff --git a/backend/src/router/block/index.ts b/backend/src/router/block/index.ts index 649a4cd16..9f1418649 100644 --- a/backend/src/router/block/index.ts +++ b/backend/src/router/block/index.ts @@ -1,13 +1,11 @@ -import * as trpc from "@trpc/server"; +import { t } from "@/backend/router/trpc"; -import { RequestContext } from "@/backend/context"; +import { procedure as byId } from "./by-id"; +import { procedure as final } from "./final"; +import { procedure as list } from "./list"; -import { router as byIdRouter } from "./by-id"; -import { router as finalRouter } from "./final"; -import { router as listRouter } from "./list"; - -export const router = trpc - .router() - .merge(finalRouter) - .merge(byIdRouter) - .merge(listRouter); +export const router = t.router({ + byId, + list, + final, +}); diff --git a/backend/src/router/block/list.ts b/backend/src/router/block/list.ts index d150fb703..3f08a1bb1 100644 --- a/backend/src/router/block/list.ts +++ b/backend/src/router/block/list.ts @@ -1,18 +1,19 @@ -import * as trpc from "@trpc/server"; import { z } from "zod"; -import { RequestContext } from "@/backend/context"; import { indexerDatabase } from "@/backend/database/databases"; import { count, div } from "@/backend/database/utils"; +import { t } from "@/backend/router/trpc"; import { validators } from "@/backend/router/validators"; import { millisecondsToNanoseconds } from "@/backend/utils/bigint"; -export const router = trpc.router().query("list", { - input: z.strictObject({ - limit: validators.limit, - cursor: validators.blockPagination.nullish(), - }), - resolve: async ({ input: { limit, cursor } }) => { +export const procedure = t.procedure + .input( + z.strictObject({ + limit: validators.limit, + cursor: validators.blockPagination.nullish(), + }) + ) + .query(async ({ input: { limit, cursor } }) => { const selection = await indexerDatabase .selectFrom((eb) => { let innerSelection = eb.selectFrom("blocks").select("block_hash"); @@ -58,5 +59,4 @@ export const router = trpc.router().query("list", { prevHash: selectionRow.prevHash!, transactionsCount: parseInt(selectionRow.transactionsCount, 10), })); - }, -}); + }); diff --git a/backend/src/router/contract/by-id.ts b/backend/src/router/contract/by-id.ts index e8987084d..a5b5516ac 100644 --- a/backend/src/router/contract/by-id.ts +++ b/backend/src/router/contract/by-id.ts @@ -1,13 +1,12 @@ -import * as trpc from "@trpc/server"; import { z } from "zod"; -import { RequestContext } from "@/backend/context"; import { analyticsDatabase, Indexer, indexerDatabase, } from "@/backend/database/databases"; import { div } from "@/backend/database/utils"; +import { t } from "@/backend/router/trpc"; import { validators } from "@/backend/router/validators"; import * as nearApi from "@/backend/utils/near"; @@ -110,9 +109,9 @@ const queryContractInfo = async (accountId: string) => { } }; -export const router = trpc.router().query("byId", { - input: z.strictObject({ id: validators.accountId }), - resolve: async ({ input: { id } }) => { +export const procedure = t.procedure + .input(z.strictObject({ id: validators.accountId })) + .query(async ({ input: { id } }) => { const account = await nearApi .sendJsonRpcQuery("view_account", { finality: "final", @@ -145,5 +144,4 @@ export const router = trpc.router().query("byId", { timestamp: parseInt(contractInfo.timestamp, 10), locked, }; - }, -}); + }); diff --git a/backend/src/router/contract/index.ts b/backend/src/router/contract/index.ts index f53e1051f..6fde7f96e 100644 --- a/backend/src/router/contract/index.ts +++ b/backend/src/router/contract/index.ts @@ -1,7 +1,5 @@ -import * as trpc from "@trpc/server"; +import { t } from "@/backend/router/trpc"; -import { RequestContext } from "@/backend/context"; +import { procedure as byId } from "./by-id"; -import { router as byIdRouter } from "./by-id"; - -export const router = trpc.router().merge(byIdRouter); +export const router = t.router({ byId }); diff --git a/backend/src/router/fungible-tokens/index.ts b/backend/src/router/fungible-tokens/index.ts index c40e3f238..d54ffcbe1 100644 --- a/backend/src/router/fungible-tokens/index.ts +++ b/backend/src/router/fungible-tokens/index.ts @@ -1,7 +1,6 @@ -import * as trpc from "@trpc/server"; import { z } from "zod"; -import { RequestContext } from "@/backend/context"; +import { t } from "@/backend/router/trpc"; import { validators } from "@/backend/router/validators"; import * as nearApi from "@/backend/utils/near"; @@ -16,23 +15,22 @@ export type FungibleTokenMetadata = { decimals: number; }; -export const router = trpc - .router() - .query("amount", { - resolve: async () => { +export const router = t.router({ + amount: t.procedure.query(async () => { + // TODO: add data from Enhanced API + const selection = { amount: "0" }; + return parseInt(selection.amount, 10); + }), + list: t.procedure + .input( + z.strictObject({ + limit: validators.limit, + cursor: z.number().optional(), + }) + ) + .query(async () => { // TODO: add data from Enhanced API - const selection = { amount: "0" }; - return parseInt(selection.amount, 10); - }, - }) - .query("list", { - input: z.strictObject({ - limit: validators.limit, - cursor: z.number().optional(), - }), - resolve: async () => { - // TODO: add data from Enhanced API - const tokens: any[] = []; + const tokens: { id: string }[] = []; const fungibleTokenContracts = tokens.map((token) => token.id); return Promise.all( fungibleTokenContracts.map(async (contract) => { @@ -57,5 +55,5 @@ export const router = trpc }; }) ); - }, - }); + }), +}); diff --git a/backend/src/router/index.ts b/backend/src/router/index.ts index 26a8f35bb..e08d9e77c 100644 --- a/backend/src/router/index.ts +++ b/backend/src/router/index.ts @@ -1,7 +1,4 @@ -import * as trpc from "@trpc/server"; - -import { RequestContext } from "@/backend/context"; -import { getEnvironment } from "@/common/utils/environment"; +import { t } from "@/backend/router/trpc"; import { router as accountRouter } from "./account"; import { router as blockRouter } from "./block"; @@ -9,31 +6,23 @@ import { router as contractRouter } from "./contract"; import { router as fungibleTokensRouter } from "./fungible-tokens"; import { router as receiptRouter } from "./receipt"; import { router as statsRouter } from "./stats"; -import { router as subscriptionsRouter } from "./subscriptions"; -import { router as telemetryRouter } from "./telemetry"; +import { subscriptionRouter, queryRouter } from "./subscriptions"; +import { procedure as upsert } from "./telemetry"; import { router as transactionRouter } from "./transaction"; import { router as utilsRouter } from "./utils"; -export const router = trpc - .router() - // Stripping out the stack on production environment - .formatError(({ shape }) => - getEnvironment() === "prod" - ? { - ...shape, - data: { ...shape.data, stack: undefined }, - } - : shape - ) - .merge(subscriptionsRouter) - .merge("utils.", utilsRouter) - .merge("stats.", statsRouter) - .merge("block.", blockRouter) - .merge("transaction.", transactionRouter) - .merge("receipt.", receiptRouter) - .merge("account.", accountRouter) - .merge("contract.", contractRouter) - .merge("telemetry.", telemetryRouter) - .merge("fungibleTokens.", fungibleTokensRouter); +export const appRouter = t.router({ + utils: utilsRouter, + stats: statsRouter, + block: blockRouter, + transaction: transactionRouter, + receipt: receiptRouter, + account: accountRouter, + contract: contractRouter, + telemetry: t.router({ upsert }), + fungibleTokens: fungibleTokensRouter, + subscriptions: subscriptionRouter, + queries: queryRouter, +}); -export type AppRouter = typeof router; +export type AppRouter = typeof appRouter; diff --git a/backend/src/router/receipt/get-transaction-hash.ts b/backend/src/router/receipt/get-transaction-hash.ts index 15f8cf7c0..0f9c94c0f 100644 --- a/backend/src/router/receipt/get-transaction-hash.ts +++ b/backend/src/router/receipt/get-transaction-hash.ts @@ -1,23 +1,19 @@ -import * as trpc from "@trpc/server"; import { z } from "zod"; -import { RequestContext } from "@/backend/context"; import { indexerDatabase } from "@/backend/database/databases"; +import { t } from "@/backend/router/trpc"; import { validators } from "@/backend/router/validators"; -export const router = trpc - .router() - .query("getTransactionHash", { - input: z.strictObject({ id: validators.receiptId }), - resolve: async ({ input: { id } }) => { - const row = await indexerDatabase - .selectFrom("receipts") - .where("receipts.receipt_id", "=", id) - .select("originated_from_transaction_hash as transactionHash") - .executeTakeFirst(); - if (!row) { - return null; - } - return row.transactionHash; - }, +export const procedure = t.procedure + .input(z.strictObject({ id: validators.receiptId })) + .query(async ({ input: { id } }) => { + const row = await indexerDatabase + .selectFrom("receipts") + .where("receipts.receipt_id", "=", id) + .select("originated_from_transaction_hash as transactionHash") + .executeTakeFirst(); + if (!row) { + return null; + } + return row.transactionHash; }); diff --git a/backend/src/router/receipt/index.ts b/backend/src/router/receipt/index.ts index a1b71137c..f4ea03cfe 100644 --- a/backend/src/router/receipt/index.ts +++ b/backend/src/router/receipt/index.ts @@ -1,11 +1,10 @@ -import * as trpc from "@trpc/server"; +import { t } from "@/backend/router/trpc"; -import { RequestContext } from "@/backend/context"; +import { procedure as getTransactionHash } from "./get-transaction-hash"; +import { procedures as listProcedures } from "./list"; -import { router as getTransactionHashRouter } from "./get-transaction-hash"; -import { router as listRouter } from "./list"; - -export const router = trpc - .router() - .merge(listRouter) - .merge(getTransactionHashRouter); +export const router = t.router({ + listExecutedByBlockHash: listProcedures.listExecutedByBlockHash, + listIncludedByBlockHash: listProcedures.listIncludedByBlockHash, + getTransactionHash, +}); diff --git a/backend/src/router/receipt/list.ts b/backend/src/router/receipt/list.ts index 3a3e63f18..8c1aa6233 100644 --- a/backend/src/router/receipt/list.ts +++ b/backend/src/router/receipt/list.ts @@ -1,4 +1,3 @@ -import * as trpc from "@trpc/server"; import { SelectQueryBuilder } from "kysely"; import { TableExpressionDatabase, @@ -6,8 +5,8 @@ import { } from "kysely/dist/cjs/parser/table-parser"; import { z } from "zod"; -import { RequestContext } from "@/backend/context"; import { IndexerDatabase, indexerDatabase } from "@/backend/database/databases"; +import { t } from "@/backend/router/trpc"; import { validators } from "@/backend/router/validators"; import { Action, @@ -123,30 +122,29 @@ const groupReceiptActionsIntoReceipts = ( acc[acc.length - 1].actions.push(mapForceDatabaseActionToAction(action)); return acc; }, []); -export const router = trpc - .router() - // As a temporary solution we split receipts list into two lists: - // included in block and executed in block - // more info here https://github.com/near/near-explorer/pull/868 - .query("listIncludedByBlockHash", { - input: z.strictObject({ blockHash: validators.blockHash }), - resolve: async ({ input: { blockHash } }) => { + +// As a temporary solution we split receipts list into two lists: +// included in block and executed in block +// more info here https://github.com/near/near-explorer/pull/868 +export const procedures = { + listIncludedByBlockHash: t.procedure + .input(z.strictObject({ blockHash: validators.blockHash })) + .query(async ({ input: { blockHash } }) => { const receiptActions = await getReceiptActions((selection) => selection .orderBy("included_in_block_hash") .where("included_in_block_hash", "=", blockHash) ); return groupReceiptActionsIntoReceipts(receiptActions); - }, - }) - .query("listExecutedByBlockHash", { - input: z.strictObject({ blockHash: validators.blockHash }), - resolve: async ({ input: { blockHash } }) => { + }), + listExecutedByBlockHash: t.procedure + .input(z.strictObject({ blockHash: validators.blockHash })) + .query(async ({ input: { blockHash } }) => { const receiptActions = await getReceiptActions((selection) => selection .orderBy("execution_outcomes.shard_id") .where("executed_in_block_hash", "=", blockHash) ); return groupReceiptActionsIntoReceipts(receiptActions); - }, - }); + }), +}; diff --git a/backend/src/router/stats/circulating-supply.ts b/backend/src/router/stats/circulating-supply.ts index 553e46564..0054dd2e2 100644 --- a/backend/src/router/stats/circulating-supply.ts +++ b/backend/src/router/stats/circulating-supply.ts @@ -1,21 +1,15 @@ -import * as trpc from "@trpc/server"; - -import { RequestContext } from "@/backend/context"; import { indexerDatabase } from "@/backend/database/databases"; +import { t } from "@/backend/router/trpc"; -export const router = trpc - .router() - .query("latestCirculatingSupply", { - resolve: async () => { - const selection = await indexerDatabase - .selectFrom("aggregated__circulating_supply") - .select([ - "circulating_tokens_supply as supply", - "computed_at_block_timestamp as timestamp", - ]) - .orderBy("computed_at_block_timestamp", "desc") - .limit(1) - .executeTakeFirstOrThrow(); - return selection; - }, - }); +export const procedure = t.procedure.query(async () => { + const selection = await indexerDatabase + .selectFrom("aggregated__circulating_supply") + .select([ + "circulating_tokens_supply as supply", + "computed_at_block_timestamp as timestamp", + ]) + .orderBy("computed_at_block_timestamp", "desc") + .limit(1) + .executeTakeFirstOrThrow(); + return selection; +}); diff --git a/backend/src/router/stats/index.ts b/backend/src/router/stats/index.ts index aca3a66a2..c36c5e71c 100644 --- a/backend/src/router/stats/index.ts +++ b/backend/src/router/stats/index.ts @@ -1,11 +1,9 @@ -import * as trpc from "@trpc/server"; +import { t } from "@/backend/router/trpc"; -import { RequestContext } from "@/backend/context"; +import { procedure as latestCirculatingSupply } from "./circulating-supply"; +import { procedure as tokensBurnt } from "./tokens-burnt"; -import { router as circulatingSupplyRouter } from "./circulating-supply"; -import { router as tokensBurntRouter } from "./tokens-burnt"; - -export const router = trpc - .router() - .merge(circulatingSupplyRouter) - .merge(tokensBurntRouter); +export const router = t.router({ + latestCirculatingSupply, + tokensBurnt, +}); diff --git a/backend/src/router/stats/tokens-burnt.ts b/backend/src/router/stats/tokens-burnt.ts index 42bb82c37..10dd5d175 100644 --- a/backend/src/router/stats/tokens-burnt.ts +++ b/backend/src/router/stats/tokens-burnt.ts @@ -1,16 +1,17 @@ -import * as trpc from "@trpc/server"; import { sql } from "kysely"; import { z } from "zod"; -import { RequestContext } from "@/backend/context"; import { indexerDatabase } from "@/backend/database/databases"; import { sum } from "@/backend/database/utils"; +import { t } from "@/backend/router/trpc"; -export const router = trpc.router().query("tokensBurnt", { - input: z.strictObject({ - daysFromNow: z.number().min(1).max(7), - }), - resolve: async ({ input: { daysFromNow } }) => { +export const procedure = t.procedure + .input( + z.strictObject({ + daysFromNow: z.number().min(1).max(7), + }) + ) + .query(async ({ input: { daysFromNow } }) => { const feesByDay = await indexerDatabase .selectFrom("execution_outcomes") .select([ @@ -49,5 +50,4 @@ export const router = trpc.router().query("tokensBurnt", { timestamp: feesByDay.date.valueOf(), tokensBurnt: feesByDay.tokensBurnt || "0", }; - }, -}); + }); diff --git a/backend/src/router/subscriptions.ts b/backend/src/router/subscriptions.ts index c89646d3d..1a8b3dc51 100644 --- a/backend/src/router/subscriptions.ts +++ b/backend/src/router/subscriptions.ts @@ -1,20 +1,31 @@ -import * as trpc from "@trpc/server"; +import type { + DefaultDataTransformer, + DefaultErrorShape, + Procedure, + ProcedureParams, + RootConfig, +} from "@trpc/server"; +import { observable } from "@trpc/server/observable"; import { isEqual } from "lodash"; import { z } from "zod"; import { RequestContext } from "@/backend/context"; +import { t } from "@/backend/router/trpc"; import { SubscriptionEventMap, SubscriptionTopicType, SubscriptionTopicTypes, } from "@/backend/router/types"; -import { - AnyRouter, - CreateProcedureSubscription, - RouterWithSubscriptionsAndQueries, -} from "@/common/types/trpc"; import { wait } from "@/common/utils/promise"; import { SSR_TIMEOUT } from "@/common/utils/queries"; +import { id } from "@/common/utils/utils"; + +type AppRouterConfig = RootConfig<{ + ctx: RequestContext; + meta: {}; + errorShape: DefaultErrorShape; + transformer: DefaultDataTransformer; +}>; const subscriptionInputs = { transactionsHistory: z.union([ @@ -47,105 +58,78 @@ type OutputMapping = { type MappedSubscriptionTopicType = T extends keyof OutputMapping ? OutputMapping[T] : SubscriptionTopicTypes[T]; -const id = (a: T) => a; +type MapFunction = ( + data: SubscriptionTopicTypes[T], + input: SubscriptionInput +) => MappedSubscriptionTopicType; +type MaybeMapFunction = + T extends keyof SubscriptionInputMap ? MapFunction : undefined; +type MapFunctions = { + [T in SubscriptionTopicType]: MaybeMapFunction; +}; + +const getInput = (topic: T) => { + if (topic in subscriptionInputs) { + return subscriptionInputs[topic as keyof SubscriptionInputMap]; + } + return z.undefined(); +}; -const withTopic = < - InitialRouter extends AnyRouter, - T extends SubscriptionTopicType ->( - prevRouter: InitialRouter, +const getSubscriptionProcedure = ( topic: T, - inputModel: SubscriptionInputModel, - mapFn: ( - data: SubscriptionTopicTypes[T], - input: SubscriptionInput - ) => MappedSubscriptionTopicType + mapFn: MapFunction ) => - prevRouter - .subscription(topic, { - input: inputModel, - resolve: ({ ctx, input }) => - new trpc.Subscription>((emit) => { - const typedInput = input as SubscriptionInput; - const onData: SubscriptionEventMap[T] = ((nextData, prevData) => { - const nextMappedData = mapFn(nextData, typedInput); - if (!prevData) { - return emit.data(nextMappedData); - } - const prevMappedData = mapFn(prevData, typedInput); - if (!isEqual(nextMappedData, prevMappedData)) { - emit.data(nextMappedData); - } - }) as SubscriptionEventMap[T]; - if (ctx.subscriptionsCache[topic]) { - const cachedData = ctx.subscriptionsCache[ - topic - ] as SubscriptionTopicTypes[T]; - onData(cachedData); - } - ctx.subscriptionsEventEmitter.on(topic, onData); - return () => { - ctx.subscriptionsEventEmitter.off(topic, onData); - }; - }), - }) - .query(topic, { - input: inputModel, - resolve: async ({ ctx, input }) => { - const typedInput = input as SubscriptionInput; - if (!ctx.subscriptionsCache[topic]) { - return new Promise((resolve) => { - const onData: SubscriptionEventMap[T] = ((data) => { - ctx.subscriptionsEventEmitter.off(topic, onData); - resolve(mapFn(data, typedInput)); - }) as SubscriptionEventMap[T]; - ctx.subscriptionsEventEmitter.on(topic, onData); - wait(SSR_TIMEOUT).then(() => - ctx.subscriptionsEventEmitter.off(topic, onData) - ); - }); + t.procedure.input(getInput(topic)).subscription(({ ctx, input }) => + observable>((emit) => { + const typedInput = input as SubscriptionInput; + const onData: SubscriptionEventMap[T] = ((nextData, prevData) => { + const nextMappedData = mapFn(nextData, typedInput); + if (!prevData) { + return emit.next(nextMappedData); + } + const prevMappedData = mapFn(prevData, typedInput); + if (!isEqual(nextMappedData, prevMappedData)) { + emit.next(nextMappedData); } + }) as SubscriptionEventMap[T]; + if (ctx.subscriptionsCache[topic]) { const cachedData = ctx.subscriptionsCache[ topic ] as SubscriptionTopicTypes[T]; - return cachedData ? mapFn(cachedData, typedInput) : undefined; - }, - }); + onData(cachedData); + } + ctx.subscriptionsEventEmitter.on(topic, onData); + return () => { + ctx.subscriptionsEventEmitter.off(topic, onData); + }; + }) + ); -const withTopics = >( - initialRouter: InitialRouter, - topicsWithMapFns: { - [Topic in SubscriptionTopicType]: Topic extends keyof SubscriptionInputMap - ? ( - value: SubscriptionTopicTypes[Topic], - input: SubscriptionInput - ) => MappedSubscriptionTopicType - : undefined; - } -): RouterWithSubscriptionsAndQueries< - InitialRouter, - { - [Topic in SubscriptionTopicType]: CreateProcedureSubscription< - InitialRouter, - MappedSubscriptionTopicType, - SubscriptionInput - >; - } -> => - Object.entries(topicsWithMapFns).reduce( - (router, [topic, mapFn = id]) => - withTopic( - router, - topic as keyof typeof topicsWithMapFns, - topic in subscriptionInputs - ? subscriptionInputs[topic as keyof typeof subscriptionInputs] - : z.undefined(), - mapFn as any - ) as any, - initialRouter - ) as any; +const getQueryProcedure = ( + topic: T, + mapFn: MapFunction +) => + t.procedure.input(getInput(topic)).query(async ({ ctx, input }) => { + const typedInput = input as SubscriptionInput; + if (!ctx.subscriptionsCache[topic]) { + return new Promise((resolve) => { + const onData: SubscriptionEventMap[T] = ((data) => { + ctx.subscriptionsEventEmitter.off(topic, onData); + resolve(mapFn(data, typedInput)); + }) as SubscriptionEventMap[T]; + ctx.subscriptionsEventEmitter.on(topic, onData); + wait(SSR_TIMEOUT).then(() => + ctx.subscriptionsEventEmitter.off(topic, onData) + ); + }); + } + const cachedData = ctx.subscriptionsCache[ + topic + ] as SubscriptionTopicTypes[T]; + return cachedData ? mapFn(cachedData, typedInput) : undefined; + }); -export const router = withTopics(trpc.router(), { +const subscriptionFilters: MapFunctions = { blockProductionSpeed: undefined, latestBlock: undefined, latestGasPrice: undefined, @@ -175,4 +159,46 @@ export const router = withTopics(trpc.router(), { rpcStatus: undefined, indexerStatus: undefined, currentValidatorsCount: undefined, -}); +}; + +const topicsFilterFnEntries = Object.entries(subscriptionFilters) as [ + keyof MapFunctions, + MapFunctions[keyof MapFunctions] +][]; + +type ProceduresMapping = { + [SpecificTopic in SubscriptionTopicType]: Procedure< + Type, + ProcedureParams< + AppRouterConfig, + unknown, + SubscriptionInput, + SubscriptionInput, + MappedSubscriptionTopicType, + MappedSubscriptionTopicType + > + >; +}; + +export const queryRouter = t.router( + topicsFilterFnEntries.reduce( + (app, [topic, mapFn = id]) => ({ + ...app, + [topic]: getQueryProcedure(topic, mapFn as MapFunction), + }), + {} as ProceduresMapping<"query"> + ) +); + +export const subscriptionRouter = t.router( + topicsFilterFnEntries.reduce( + (app, [topic, mapFn = id]) => ({ + ...app, + [topic]: getSubscriptionProcedure( + topic, + mapFn as MapFunction + ), + }), + {} as ProceduresMapping<"subscription"> + ) +); diff --git a/backend/src/router/telemetry.ts b/backend/src/router/telemetry.ts index 963b8d868..8cc18953d 100644 --- a/backend/src/router/telemetry.ts +++ b/backend/src/router/telemetry.ts @@ -1,16 +1,15 @@ -import * as trpc from "@trpc/server"; import geoip from "geoip-lite"; -import { RequestContext } from "@/backend/context"; import { extraPool, telemetryWriteDatabase, } from "@/backend/database/databases"; +import { t } from "@/backend/router/trpc"; import { validators } from "@/backend/router/validators"; -export const router = trpc.router().mutation("upsert", { - input: validators.telemetryRequest, - resolve: async ({ input: nodeInfo }) => { +export const procedure = t.procedure + .input(validators.telemetryRequest) + .mutation(async ({ input: nodeInfo }) => { if (!("agent" in nodeInfo)) { // This seems to be an old format, and all our nodes should support the new // Telemetry format as of 2020-04-14, so we just ignore those old Telemetry @@ -97,5 +96,4 @@ export const router = trpc.router().mutation("upsert", { const compiled = query.compile(); // TODO: figure out why raw query run faster than kysely query await extraPool.query(compiled.sql, compiled.parameters as any); - }, -}); + }); diff --git a/backend/src/router/transaction/get.ts b/backend/src/router/transaction/get.ts index cc8f66a04..e41c3e9be 100644 --- a/backend/src/router/transaction/get.ts +++ b/backend/src/router/transaction/get.ts @@ -1,12 +1,11 @@ -import * as trpc from "@trpc/server"; import { z } from "zod"; -import { RequestContext } from "@/backend/context"; import { indexerActivityDatabase, indexerDatabase, } from "@/backend/database/databases"; import { div } from "@/backend/database/utils"; +import { t } from "@/backend/router/trpc"; import { validators } from "@/backend/router/validators"; import { Action, mapRpcActionToAction } from "@/backend/utils/actions"; import { nanosecondsToMilliseconds } from "@/backend/utils/bigint"; @@ -171,13 +170,14 @@ const parseOutcome = ( }; }; -export const router = trpc - .router() - .query("byHashOld", { - input: z.strictObject({ - hash: validators.transactionHash, - }), - resolve: async ({ input: { hash } }) => { +export const procedures = { + byHashOld: t.procedure + .input( + z.strictObject({ + hash: validators.transactionHash, + }) + ) + .query(async ({ input: { hash } }) => { const databaseTransaction = await indexerDatabase .selectFrom("transactions") .select([ @@ -233,13 +233,14 @@ export const router = trpc tokensBurnt: rpcTransaction.transaction_outcome.outcome.tokens_burnt, }, }; - }, - }) - .query("byHash", { - input: z.strictObject({ - hash: validators.transactionHash, }), - resolve: async ({ input: { hash } }) => { + byHash: t.procedure + .input( + z.strictObject({ + hash: validators.transactionHash, + }) + ) + .query(async ({ input: { hash } }) => { const databaseTransaction = await indexerDatabase .selectFrom("transactions") .select([ @@ -317,14 +318,15 @@ export const router = trpc receiptsMap ) as NestedReceiptWithOutcome, }; - }, - }) - .query("accountBalanceChange", { - input: z.strictObject({ - accountId: validators.accountId, - receiptId: validators.receiptId, }), - resolve: async ({ input: { accountId, receiptId } }) => { + accountBalanceChange: t.procedure + .input( + z.strictObject({ + accountId: validators.accountId, + receiptId: validators.receiptId, + }) + ) + .query(async ({ input: { accountId, receiptId } }) => { const balanceChanges = await indexerActivityDatabase .selectFrom("balance_changes") .select(["absolute_nonstaked_amount as absoluteNonStakedAmount"]) @@ -337,5 +339,5 @@ export const router = trpc return null; } return balanceChanges.absoluteNonStakedAmount; - }, - }); + }), +}; diff --git a/backend/src/router/transaction/index.ts b/backend/src/router/transaction/index.ts index 7cc1dce00..b20252c99 100644 --- a/backend/src/router/transaction/index.ts +++ b/backend/src/router/transaction/index.ts @@ -1,11 +1,13 @@ -import * as trpc from "@trpc/server"; +import { t } from "@/backend/router/trpc"; -import { RequestContext } from "@/backend/context"; +import { procedures as getProcedures } from "./get"; +import { procedures as listProcedures } from "./list"; -import { router as getRouter } from "./get"; -import { router as listRouter } from "./list"; - -export const router = trpc - .router() - .merge(getRouter) - .merge(listRouter); +export const router = t.router({ + byHashOld: getProcedures.byHashOld, + byHash: getProcedures.byHash, + accountBalanceChange: getProcedures.accountBalanceChange, + listByTimestamp: listProcedures.byTimestamp, + listByAccountId: listProcedures.byAccountId, + listByBlockHash: listProcedures.byBlockHash, +}); diff --git a/backend/src/router/transaction/list.ts b/backend/src/router/transaction/list.ts index 08cde1c7a..db0b402c6 100644 --- a/backend/src/router/transaction/list.ts +++ b/backend/src/router/transaction/list.ts @@ -1,9 +1,8 @@ -import * as trpc from "@trpc/server"; import { SelectQueryBuilder } from "kysely"; import { z } from "zod"; -import { RequestContext } from "@/backend/context"; import { IndexerDatabase, indexerDatabase } from "@/backend/database/databases"; +import { t } from "@/backend/router/trpc"; import { validators } from "@/backend/router/validators"; import { Action, @@ -118,23 +117,26 @@ const getTransactionList = async ( }; }; -export const router = trpc - .router() - .query("listByTimestamp", { - input: z.strictObject({ - limit: validators.limit, - cursor: validators.transactionPagination.nullish(), - }), - resolve: async ({ input: { limit, cursor } }) => - getTransactionList(limit, cursor), - }) - .query("listByAccountId", { - input: z.strictObject({ - accountId: validators.accountId, - limit: validators.limit, - cursor: validators.transactionPagination.nullish(), - }), - resolve: async ({ input: { accountId, limit, cursor } }) => +export const procedures = { + byTimestamp: t.procedure + .input( + z.strictObject({ + limit: validators.limit, + cursor: validators.transactionPagination.nullish(), + }) + ) + .query(async ({ input: { limit, cursor } }) => + getTransactionList(limit, cursor) + ), + byAccountId: t.procedure + .input( + z.strictObject({ + accountId: validators.accountId, + limit: validators.limit, + cursor: validators.transactionPagination.nullish(), + }) + ) + .query(async ({ input: { accountId, limit, cursor } }) => getTransactionList(limit, cursor, (selection) => selection.where("transaction_hash", "in", (eb) => eb @@ -143,16 +145,19 @@ export const router = trpc .where("predecessor_account_id", "=", accountId) .orWhere("receiver_account_id", "=", accountId) ) - ), - }) - .query("listByBlockHash", { - input: z.strictObject({ - blockHash: validators.blockHash, - limit: validators.limit, - cursor: validators.transactionPagination.nullish(), - }), - resolve: async ({ input: { blockHash, limit, cursor } }) => + ) + ), + byBlockHash: t.procedure + .input( + z.strictObject({ + blockHash: validators.blockHash, + limit: validators.limit, + cursor: validators.transactionPagination.nullish(), + }) + ) + .query(async ({ input: { blockHash, limit, cursor } }) => getTransactionList(limit, cursor, (selection) => selection.where("included_in_block_hash", "=", blockHash) - ), - }); + ) + ), +}; diff --git a/backend/src/router/trpc.ts b/backend/src/router/trpc.ts new file mode 100644 index 000000000..229ee7284 --- /dev/null +++ b/backend/src/router/trpc.ts @@ -0,0 +1,15 @@ +import { initTRPC } from "@trpc/server"; + +import { RequestContext } from "@/backend/context"; +import { getEnvironment } from "@/common/utils/environment"; + +export const t = initTRPC.context().create({ + // Stripping out the stack on production environment + errorFormatter: ({ shape }) => + getEnvironment() === "prod" + ? { + ...shape, + data: { ...shape.data, stack: undefined }, + } + : shape, +}); diff --git a/backend/src/router/utils/deploy.ts b/backend/src/router/utils/deploy.ts index bdf727630..bfbdbccb7 100644 --- a/backend/src/router/utils/deploy.ts +++ b/backend/src/router/utils/deploy.ts @@ -1,9 +1,7 @@ -import * as trpc from "@trpc/server"; - import { config } from "@/backend/config"; -import { RequestContext } from "@/backend/context"; +import { t } from "@/backend/router/trpc"; import { getEnvironmentVariables } from "@/common/utils/environment"; -export const router = trpc.router().query("deployInfo", { - resolve: async () => getEnvironmentVariables(`backend/${config.networkName}`), -}); +export const procedure = t.procedure.query(async () => + getEnvironmentVariables(`backend/${config.networkName}`) +); diff --git a/backend/src/router/utils/index.ts b/backend/src/router/utils/index.ts index bd2a025f0..a7f7313ec 100644 --- a/backend/src/router/utils/index.ts +++ b/backend/src/router/utils/index.ts @@ -1,15 +1,13 @@ -import * as trpc from "@trpc/server"; +import { t } from "@/backend/router/trpc"; -import { RequestContext } from "@/backend/context"; +import { procedure as deployInfo } from "./deploy"; +import { procedure as protocolVersion } from "./protocol"; +import { procedure as search } from "./search"; +import { procedure as subscriptionsCache } from "./subscriptions"; -import { router as deployRouter } from "./deploy"; -import { router as protocolRouter } from "./protocol"; -import { router as searchRouter } from "./search"; -import { router as subscriptionsRouter } from "./subscriptions"; - -export const router = trpc - .router() - .merge(protocolRouter) - .merge(deployRouter) - .merge(searchRouter) - .merge(subscriptionsRouter); +export const router = t.router({ + protocolVersion, + deployInfo, + search, + subscriptionsCache, +}); diff --git a/backend/src/router/utils/protocol.ts b/backend/src/router/utils/protocol.ts index b23eae087..b1fc68c3d 100644 --- a/backend/src/router/utils/protocol.ts +++ b/backend/src/router/utils/protocol.ts @@ -1,11 +1,7 @@ -import * as trpc from "@trpc/server"; - -import { RequestContext } from "@/backend/context"; +import { t } from "@/backend/router/trpc"; import * as nearApi from "@/backend/utils/near"; -export const router = trpc.router().query("protocolVersion", { - resolve: async () => { - const result = await nearApi.sendJsonRpc("status", [null]); - return result.protocol_version; - }, +export const procedure = t.procedure.query(async () => { + const result = await nearApi.sendJsonRpc("status", [null]); + return result.protocol_version; }); diff --git a/backend/src/router/utils/search.ts b/backend/src/router/utils/search.ts index 068b17bdf..f2920c101 100644 --- a/backend/src/router/utils/search.ts +++ b/backend/src/router/utils/search.ts @@ -1,8 +1,7 @@ -import * as trpc from "@trpc/server"; import { z, ZodType } from "zod"; -import { RequestContext } from "@/backend/context"; import { indexerDatabase } from "@/backend/database/databases"; +import { t } from "@/backend/router/trpc"; import { validators } from "@/backend/router/validators"; const blockInput = z.union([ @@ -89,15 +88,13 @@ const validateAndFetch = async >( return fetchedResult; }; -export const router = trpc.router().mutation("search", { - input: z.strictObject({ - value: z.string(), - }), - resolve: async ({ input: { value } }) => +export const procedure = t.procedure + .input(z.strictObject({ value: z.string() })) + .mutation(({ input: { value } }) => Promise.any([ validateAndFetch(value, blockInput, getBlockHash), validateAndFetch(value, validators.transactionHash, getTransactionHash), validateAndFetch(value, validators.accountId, getAccountId), validateAndFetch(value, validators.receiptId, getReceiptId), - ]).catch(() => undefined), -}); + ]).catch(() => undefined) + ); diff --git a/backend/src/router/utils/subscriptions.ts b/backend/src/router/utils/subscriptions.ts index 7925de474..40d802e18 100644 --- a/backend/src/router/utils/subscriptions.ts +++ b/backend/src/router/utils/subscriptions.ts @@ -1,9 +1,3 @@ -import * as trpc from "@trpc/server"; +import { t } from "@/backend/router/trpc"; -import { RequestContext } from "@/backend/context"; - -export const router = trpc - .router() - .query("subscriptionsCache", { - resolve: ({ ctx }) => ctx.subscriptionsCache, - }); +export const procedure = t.procedure.query(({ ctx }) => ctx.subscriptionsCache); diff --git a/backend/src/server.ts b/backend/src/server.ts index 4f5305bc1..08a9654f6 100644 --- a/backend/src/server.ts +++ b/backend/src/server.ts @@ -35,7 +35,7 @@ export const createApp = (options: RouterOptions) => { app .use(cors()) - .use("/trpc", trpcExpress.createExpressMiddleware(options)) + .use("/trpc", trpcExpress.createExpressMiddleware(options)) .use("/ping", (_req, res) => res.send("OK")) .use("/global-state", async (req, res) => { const context = await options.createContext({ req, res }); @@ -66,6 +66,7 @@ export const connectWebsocketServer = ( const handler = trpcWsAdapter.applyWSSHandler({ wss: websocketServer, + process, ...options, }); diff --git a/backend/src/utils/error.ts b/backend/src/utils/error.ts index f7b36f439..795971806 100644 --- a/backend/src/utils/error.ts +++ b/backend/src/utils/error.ts @@ -1,10 +1,8 @@ import * as trpc from "@trpc/server"; -import type { HTTPBaseHandlerOptions } from "@trpc/server/dist/declarations/src/http/internals/types"; -import type http from "http"; import { ZodError } from "zod"; import { generateErrorMessage, ErrorMessageOptions } from "zod-error"; -import type { AppRouter } from "@/backend/router"; +import { WebsocketRouterOptions } from "@/backend/server"; const errorOptions: ErrorMessageOptions = { delimiter: { @@ -47,10 +45,13 @@ const logError = ( const ZOD_ERROR_CAUSE = "Zod validation error"; -export const onError: HTTPBaseHandlerOptions< - AppRouter, - http.IncomingMessage ->["onError"] = ({ error, ctx, type, path, input }) => { +export const onError: WebsocketRouterOptions["onError"] = ({ + error, + ctx, + type, + path, + input, +}) => { if (!ctx) { return; } @@ -62,6 +63,7 @@ export const onError: HTTPBaseHandlerOptions< message, cause: ZOD_ERROR_CAUSE, }); + // @ts-ignore } else if (error.cause !== ZOD_ERROR_CAUSE) { logError(error.code, type, path, error.message, input, error.stack); } diff --git a/common/package.json b/common/package.json index 5790e5a68..6a43e7f87 100644 --- a/common/package.json +++ b/common/package.json @@ -5,9 +5,9 @@ "lodash": "^4.17.21" }, "devDependencies": { - "@trpc/client": "^9.27.4", - "@trpc/react": "^9.27.4", + "@trpc/client": "^10.26.0", + "@trpc/react-query": "^10.26.0", "@types/lodash": "^4.14.177", - "react-query": "^3.39.0" + "@tanstack/react-query": "^4.29.7" } } diff --git a/common/src/types/common.ts b/common/src/types/common.ts index f0360a6a8..0d63495d1 100644 --- a/common/src/types/common.ts +++ b/common/src/types/common.ts @@ -10,3 +10,57 @@ export type NetworkName = export type StableOmit = { [Property in keyof Type as Exclude]: Type[Property]; }; + +type IsTerminated = + Input extends Terminator ? SuccessResult : FailureResult; + +type FlattenStepOne = { + [K in keyof X as K extends string + ? IsTerminated< + X[K], + Terminator, + K, + `${K}${Delimiter}${keyof X[K] & string}` + > + : K]: IsTerminated< + X[K], + Terminator, + X[K], + { [Key in keyof X[K]]: X[K][Key] } + >; +}; + +type Value = X[keyof X]; + +type Tail< + S, + Delimiter extends string +> = S extends `${string}${Delimiter}${infer T}` ? Tail : S; + +type FlattenStepTwo = { + [K in keyof X]: IsTerminated< + X[K], + Terminator, + X[K], + Value<{ + [M in keyof X[K] as M extends Tail ? M : never]: X[K][M]; + }> + >; +}; + +type FlattenOneLevel = FlattenStepTwo< + FlattenStepOne, + Terminator, + Delimiter +>; + +// https://stackoverflow.com/a/69322301/2017859 +export type Flatten< + X, + Terminator, + Delimiter extends string +> = X extends FlattenOneLevel + ? X + : Flatten, Terminator, Delimiter>; + +export type Unpacked = T extends (infer U)[] ? U : T; diff --git a/common/src/types/procedures.ts b/common/src/types/procedures.ts index 8dcb8ad12..df3ecafc0 100644 --- a/common/src/types/procedures.ts +++ b/common/src/types/procedures.ts @@ -1,4 +1,8 @@ -import { TRPCQueryOutput, TRPCSubscriptionOutput } from "@/common/types/trpc"; +import { + TRPCQueryOutput, + TRPCInfiniteQueryOutput, + TRPCSubscriptionOutput, +} from "@/common/types/trpc"; export type AccountOld = NonNullable>; export type Account = NonNullable>; @@ -11,13 +15,13 @@ export type AccountFungibleTokenHistory = export type AccountFungibleTokenHistoryElement = AccountFungibleTokenHistory["elements"][number]; export type AccountNonFungibleToken = - TRPCQueryOutput<"account.nonFungibleTokens">; + TRPCInfiniteQueryOutput<"account.nonFungibleTokens">; export type AccountNonFungibleTokenElement = TRPCQueryOutput<"account.nonFungibleTokens">["items"][number]; export type AccountNonFungibleTokenHistoryElement = TRPCQueryOutput<"account.nonFungibleTokenHistory">[number]; -export type AccountActivity = TRPCQueryOutput<"account.activity">; +export type AccountActivity = TRPCInfiniteQueryOutput<"account.activity">; export type AccountActivityElement = AccountActivity["items"][number]; export type AccountActivityElementAction = AccountActivityElement["action"]; type InferAccountActivityAction = @@ -53,11 +57,10 @@ export type TransactionOld = NonNullable< export type NestedReceiptWithOutcomeOld = TransactionOld["receipt"]; export type TransactionOutcomeOld = TransactionOld["outcome"]; -export type FungibleTokenItem = TRPCQueryOutput<"fungibleTokens.list">[number]; - export type DeployInfo = TRPCQueryOutput<"utils.deployInfo">; -export type ValidatorFullData = TRPCSubscriptionOutput<"validators">[number]; +export type ValidatorFullData = + TRPCSubscriptionOutput<"subscriptions.validators">[number]; export type ValidationProgress = NonNullable< ValidatorFullData["currentEpoch"] >["progress"]; @@ -67,4 +70,4 @@ export type ValidatorDescription = NonNullable< >; export type ValidatorPoolInfo = NonNullable; -export type HealthStatus = TRPCSubscriptionOutput<"rpcStatus">; +export type HealthStatus = TRPCSubscriptionOutput<"subscriptions.rpcStatus">; diff --git a/common/src/types/trpc.ts b/common/src/types/trpc.ts index e47a2f784..399db36be 100644 --- a/common/src/types/trpc.ts +++ b/common/src/types/trpc.ts @@ -1,208 +1,118 @@ -import type { TRPCClient as _TRPCClient } from "@trpc/client"; -import type { TRPCClientErrorLike } from "@trpc/react"; import type { - Procedure, - inferProcedureFromOptions, - CreateProcedureOptions, - CreateProcedureWithoutInput, - CreateProcedureWithInput, -} from "@trpc/server/dist/declarations/src/internals/procedure"; -import type { - Router, - ProcedureRecord, -} from "@trpc/server/dist/declarations/src/router"; -import type { Subscription } from "@trpc/server/dist/declarations/src/subscription"; -import type { - UseInfiniteQueryResult, UseMutationResult, UseQueryResult, -} from "react-query"; -import type { Equals } from "tsafe"; + UseInfiniteQueryResult, +} from "@tanstack/react-query"; +import type { inferRouterProxyClient } from "@trpc/client"; +import type { TRPCClientErrorLike } from "@trpc/react-query"; +import type { + inferProcedureInput, + AnyRouter, + AnyQueryProcedure, + AnyMutationProcedure, + AnySubscriptionProcedure, + AnyProcedure, + ProcedureType, +} from "@trpc/server"; +import type { inferTransformedProcedureOutput } from "@trpc/server/src/shared/jsonify"; import type { AppRouter } from "@/backend/router"; - -export type AnyRouter = Router< - any, - TContext, - any, - any, - any, - any, - any ->; -type AnyProcedure = Procedure; -type AnyProcedureRecord = ProcedureRecord; -type AnyCreateProcedureOptions = CreateProcedureOptions< - any, - any, - any, - any, - any, - any +import type { Flatten } from "@/common/types/common"; + +// Generic types +type FlattenRouter = Flatten< + { + [TKey in keyof TRouter["_def"]["record"] & + string]: TRouter["_def"]["record"][TKey] extends infer TRouterOrProcedure + ? TRouterOrProcedure extends AnyRouter + ? FlattenRouter + : TRouterOrProcedure extends AnyProcedure + ? TRouterOrProcedure + : never + : never; + }, + AnyProcedure, + "." >; -export type CreateProcedureSubscription< - R extends AnyRouter, - Output, - Input = undefined -> = R extends Router - ? Equals extends true - ? CreateProcedureWithoutInput - : CreateProcedureWithInput - : never; - -type ProcedureWithOutputSubscription< - TOptions extends CreateProcedureOptions -> = TOptions extends CreateProcedureWithInput< - infer Context, - infer Meta, - infer Input, - infer Output -> - ? CreateProcedureWithInput> - : TOptions extends CreateProcedureWithoutInput< - infer Context, - infer Meta, - infer Output, - infer Output - > - ? CreateProcedureWithoutInput< - Context, - Meta, - Subscription, - Subscription - > +type ProcedureByType = Type extends "query" + ? AnyQueryProcedure + : Type extends "mutation" + ? AnyMutationProcedure + : Type extends "subscription" + ? AnySubscriptionProcedure : never; -export type RouterWithSubscriptionsAndQueries< - R extends AnyRouter, - SubscriptionProcedures extends Record -> = R extends Router< - infer InputContext, - infer Context, - infer Meta, - infer Queries, - infer Mutations, - infer Subscriptions, - infer Error -> - ? Router< - InputContext, - Context, - Meta, - Queries & { - [Path in keyof SubscriptionProcedures]: inferProcedureFromOptions< - InputContext, - SubscriptionProcedures[Path] - >; - }, - Mutations, - Subscriptions & { - [Path in keyof SubscriptionProcedures]: inferProcedureFromOptions< - InputContext, - ProcedureWithOutputSubscription - >; - }, - Error - > - : never; - -type InferProcedureInput

= P extends Procedure< - any, - any, - any, - infer Input, - any, - any, - any -> - ? undefined extends Input - ? Input | null | void - : Input - : undefined; - -type InferProcedureOutput

= Awaited< - ReturnType ->; +type BaseFlatRouter = Record; -type InferProcedures = { - [Path in keyof Obj]: { - input: InferProcedureInput; - output: InferProcedureOutput; - }; +type FilterByType< + FRouter extends BaseFlatRouter, + PType extends ProcedureType +> = { + [K in keyof FRouter as FRouter[K] extends ProcedureByType + ? K + : never]: FRouter[K]; }; -type InferInfiniteQueryNames = { - [Path in keyof Obj]: InferProcedureInput extends { - cursor?: any; - } - ? Path - : never; -}[keyof Obj]; - -type InferHandlerInput = - TProcedure extends Procedure - ? undefined extends TInput // ? is input optional - ? unknown extends TInput // ? is input unset - ? [(null | undefined)?] // -> there is no input - : [(TInput | null | undefined)?] // -> there is optional input - : [TInput] // -> input is required - : [(undefined | null)?]; // -> there is no input - -type InferQueryNameByResult = { - [Path in keyof Obj]: InferProcedureInput extends R ? Path : never; -}[keyof Obj]; +type FilterInputs = { + [K in keyof FRouter as inferProcedureInput extends Target + ? K + : never]: FRouter[K]; +}; -type TypeKey = "queries" | "mutations" | "subscriptions"; +// Specific types +type FlatRouter = FlattenRouter; -type DefValues = InferProcedures< - R["_def"][Type] +type TRPCQueryValues = FilterByType; +type TRPCMutationValues = FilterByType; +type TRPCSubscriptionValues = FilterByType; +type TRPCInfiniteQueryValues = FilterInputs< + TRPCQueryValues, + { cursor?: unknown } >; -type DefKey = keyof R["_def"][Type]; - -type InferSubscription = S extends Subscription ? D : never; - -export type TRPCQueryKey = DefKey; - -type QueriesDefs = AppRouter["_def"]["queries"]; - -export type TRPCInfiniteQueryKey = InferInfiniteQueryNames; - -export type TRPCInferQueryKey = InferQueryNameByResult; +export type TRPCError = TRPCClientErrorLike; -export type TRPCQueryInput = DefValues< - AppRouter, - "queries" ->[Path]["input"]; +export type TRPCQueryKey = keyof TRPCQueryValues & string; -export type TRPCQueryOutput = DefValues< - AppRouter, - "queries" ->[Path]["output"]; +export type TRPCQueryInput = inferProcedureInput< + TRPCQueryValues[Path] +>; -export type TRPCInfiniteQueryOutput = - TRPCQueryOutput; +export type TRPCQueryOutput = + inferTransformedProcedureOutput; export type TRPCQueryResult = UseQueryResult< TRPCQueryOutput, TRPCError >; +export type TRPCInfiniteQueryKey = keyof TRPCInfiniteQueryValues; + +export type TRPCInfiniteQueryInput = Omit< + inferProcedureInput, + "cursor" +>; +export type TRPCInfiniteQueryOutput = + inferTransformedProcedureOutput; + +export type TRPCInfiniteQueryCursor = + inferProcedureInput extends { + cursor?: unknown; + } + ? inferProcedureInput["cursor"] + : never; + export type TRPCInfiniteQueryResult = UseInfiniteQueryResult, TRPCError>; -export type TRPCMutationKey = DefKey; +export type TRPCMutationKey = keyof TRPCMutationValues; -export type TRPCMutationInput = DefValues< - AppRouter, - "mutations" ->[Path]["input"]; +export type TRPCMutationInput = + inferProcedureInput; -export type TRPCMutationOutput = DefValues< - AppRouter, - "mutations" ->[Path]["output"]; +export type TRPCMutationOutput = + inferTransformedProcedureOutput; export type TRPCMutationResult = UseMutationResult< @@ -211,16 +121,17 @@ export type TRPCMutationResult = TRPCMutationInput >; -export type TRPCSubscriptionKey = DefKey; +export type TRPCSubscriptionKey = keyof TRPCSubscriptionValues; -export type TRPCSubscriptionOutput = - InferSubscription[Path]["output"]>; +export type TRPCSubscriptionInput = + inferProcedureInput; -export type TRPCSubscriptionInputs = - InferHandlerInput; +export type TRPCSubscriptionOutput = + inferTransformedProcedureOutput; -export type TRPCError = TRPCClientErrorLike; +export type TRPCSubscriptionResult = + UseQueryResult, TRPCError>; -export type TRPCClient = _TRPCClient; +export type TRPCClient = inferRouterProxyClient; export type { AppRouter }; diff --git a/frontend/jest.config.ts b/frontend/jest.config.ts index 7691e8ce2..fc63c6ff5 100644 --- a/frontend/jest.config.ts +++ b/frontend/jest.config.ts @@ -13,7 +13,6 @@ export default createJestConfig({ testRegex: "(\\.|/)test\\.[jt]sx?$", testPathIgnorePatterns: ["/node_modules/", "./utils/"], testEnvironment: "/src/testing/env.ts", - collectCoverage: false, timers: "modern", transform: { "^.+\\.(js|jsx|ts|tsx|mjs)$": path.join(__dirname, "./babel-jest-wrapper"), diff --git a/frontend/package.json b/frontend/package.json index 66e1d1589..9a6979ade 100644 --- a/frontend/package.json +++ b/frontend/package.json @@ -37,9 +37,10 @@ "@playwright/test": "^1.32.3", "@stitches/react": "^1.3.1-1", "@textea/json-viewer": "^2.16.0", - "@trpc/client": "^9.27.4", - "@trpc/next": "^9.27.4", - "@trpc/react": "^9.27.4", + "@trpc/client": "^10.26.0", + "@trpc/next": "^10.26.0", + "@trpc/react-query": "^10.26.0", + "@trpc/server": "^10.26.0", "@types/analytics-node": "^3.1.9", "analytics-node": "^6.2.0", "bootstrap": "^4.6.1", @@ -74,7 +75,8 @@ "react-image": "^4.0.3", "react-infinite-scroll-component": "^5.1.0", "react-paginate": "^8.1.4", - "react-query": "^3.39.0", + "@tanstack/react-query": "^4.29.7", + "@tanstack/react-query-devtools": "^4.29.7", "tslib": "^2.3.1", "universal-cookie": "^4.0.4" }, diff --git a/frontend/patches/@trpc+next+10.26.0.patch b/frontend/patches/@trpc+next+10.26.0.patch new file mode 100644 index 000000000..033ec9e8d --- /dev/null +++ b/frontend/patches/@trpc+next+10.26.0.patch @@ -0,0 +1,271 @@ +diff --git a/node_modules/@trpc/next/dist/index.js b/node_modules/@trpc/next/dist/index.js +index 644b5fc..5883512 100644 +--- a/node_modules/@trpc/next/dist/index.js ++++ b/node_modules/@trpc/next/dist/index.js +@@ -41,7 +41,9 @@ function withTRPC(opts) { + if (props.trpc) { + return props.trpc; + } +- const config = getClientConfig({}); ++ const config = getClientConfig({ ++ props ++ }); + const queryClient = shared.getQueryClient(config); + const trpcClient = trpc.createClient(config); + return { +@@ -117,7 +119,7 @@ function withTRPC(opts) { + break; + } + // wait until the query cache has settled it's promises +- await new Promise((resolve)=>{ ++ const prefetchPromise = new Promise((resolve)=>{ + const unsub = queryClient.getQueryCache().subscribe((event)=>{ + if (event?.query.getObserversCount() === 0) { + resolve(); +@@ -125,6 +127,19 @@ function withTRPC(opts) { + } + }); + }); ++ if (typeof config.ssrTimeout === 'number') { ++ await Promise.race([ ++ prefetchPromise, ++ new Promise((resolve)=>{ ++ setTimeout(()=>{ ++ void queryClient.cancelQueries(); ++ resolve(undefined); ++ }, config.ssrTimeout); ++ }) ++ ]); ++ } else { ++ await prefetchPromise; ++ } + } + const dehydratedCache = reactQuery$1.dehydrate(queryClient, { + shouldDehydrateQuery () { +diff --git a/node_modules/@trpc/next/dist/index.mjs b/node_modules/@trpc/next/dist/index.mjs +index e51a5c8..c4d7af5 100644 +--- a/node_modules/@trpc/next/dist/index.mjs ++++ b/node_modules/@trpc/next/dist/index.mjs +@@ -32,7 +32,9 @@ function withTRPC(opts) { + if (props.trpc) { + return props.trpc; + } +- const config = getClientConfig({}); ++ const config = getClientConfig({ ++ props ++ }); + const queryClient = getQueryClient(config); + const trpcClient = trpc.createClient(config); + return { +@@ -108,7 +110,7 @@ function withTRPC(opts) { + break; + } + // wait until the query cache has settled it's promises +- await new Promise((resolve)=>{ ++ const prefetchPromise = new Promise((resolve)=>{ + const unsub = queryClient.getQueryCache().subscribe((event)=>{ + if (event?.query.getObserversCount() === 0) { + resolve(); +@@ -116,6 +118,19 @@ function withTRPC(opts) { + } + }); + }); ++ if (typeof config.ssrTimeout === 'number') { ++ await Promise.race([ ++ prefetchPromise, ++ new Promise((resolve)=>{ ++ setTimeout(()=>{ ++ void queryClient.cancelQueries(); ++ resolve(undefined); ++ }, config.ssrTimeout); ++ }) ++ ]); ++ } else { ++ await prefetchPromise; ++ } + } + const dehydratedCache = dehydrate(queryClient, { + shouldDehydrateQuery () { +diff --git a/node_modules/@trpc/next/dist/withTRPC.d.ts b/node_modules/@trpc/next/dist/withTRPC.d.ts +index 8b88534..53bc330 100644 +--- a/node_modules/@trpc/next/dist/withTRPC.d.ts ++++ b/node_modules/@trpc/next/dist/withTRPC.d.ts +@@ -1,27 +1,39 @@ ++/** ++ * Heavily based on urql's ssr ++ * https://github.com/FormidableLabs/urql/blob/main/packages/next-urql/src/with-urql-client.ts ++ */ ++import { DehydratedState } from '@tanstack/react-query'; + import type { CreateTRPCClientOptions } from '@trpc/client'; + import { TRPCClientError } from '@trpc/react-query'; + import { CreateTRPCReactOptions, CreateTRPCReactQueryClientConfig } from '@trpc/react-query/shared'; + import type { AnyRouter } from '@trpc/server'; + import type { ResponseMeta } from '@trpc/server/http'; +-import { NextComponentType, NextPageContext } from 'next/dist/shared/lib/utils'; ++import { AppPropsType, NextComponentType, NextPageContext } from 'next/dist/shared/lib/utils'; ++import { NextRouter } from 'next/router'; + export declare type WithTRPCConfig = CreateTRPCClientOptions & { + abortOnUnmount?: boolean; ++ ssrTimeout?: number; + } & CreateTRPCReactQueryClientConfig; +-interface WithTRPCOptions extends CreateTRPCReactOptions { ++declare type BaseInitialProps = { ++ trpcState: DehydratedState; ++}; ++interface WithTRPCOptions extends CreateTRPCReactOptions { + config: (info: { +- ctx?: NextPageContext; ++ ctx: NextPageContext; ++ } | { ++ props: AppPropsType; + }) => WithTRPCConfig; + } +-export interface WithTRPCSSROptions extends WithTRPCOptions { ++export interface WithTRPCSSROptions extends WithTRPCOptions { + ssr: true; + responseMeta?: (opts: { + ctx: NextPageContext; + clientErrors: TRPCClientError[]; + }) => ResponseMeta; + } +-export interface WithTRPCNoSSROptions extends WithTRPCOptions { ++export interface WithTRPCNoSSROptions extends WithTRPCOptions { + ssr?: false; + } +-export declare function withTRPC(opts: WithTRPCNoSSROptions | WithTRPCSSROptions): (AppOrPage: NextComponentType) => NextComponentType; ++export declare function withTRPC(opts: WithTRPCNoSSROptions | WithTRPCSSROptions): (AppOrPage: NextComponentType) => NextComponentType; + export {}; + //# sourceMappingURL=withTRPC.d.ts.map +\ No newline at end of file +diff --git a/node_modules/@trpc/next/dist/withTRPC.d.ts.map b/node_modules/@trpc/next/dist/withTRPC.d.ts.map +index 5e11548..cf4d96b 100644 +--- a/node_modules/@trpc/next/dist/withTRPC.d.ts.map ++++ b/node_modules/@trpc/next/dist/withTRPC.d.ts.map +@@ -1 +1 @@ +-{"version":3,"file":"withTRPC.d.ts","sourceRoot":"","sources":["../src/withTRPC.tsx"],"names":[],"mappings":"AAWA,OAAO,KAAK,EAAE,uBAAuB,EAAE,MAAM,cAAc,CAAC;AAC5D,OAAO,EAEL,eAAe,EAIhB,MAAM,mBAAmB,CAAC;AAC3B,OAAO,EACL,sBAAsB,EACtB,gCAAgC,EAEjC,MAAM,0BAA0B,CAAC;AAClC,OAAO,KAAK,EAAE,SAAS,EAAe,MAAM,cAAc,CAAC;AAC3D,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,mBAAmB,CAAC;AACtD,OAAO,EAGL,iBAAiB,EACjB,eAAe,EAChB,MAAM,4BAA4B,CAAC;AA2BpC,oBAAY,cAAc,CAAC,OAAO,SAAS,SAAS,IAClD,uBAAuB,CAAC,OAAO,CAAC,GAAG;IACjC,cAAc,CAAC,EAAE,OAAO,CAAC;CAC1B,GAAG,gCAAgC,CAAC;AAEvC,UAAU,eAAe,CAAC,OAAO,SAAS,SAAS,CACjD,SAAQ,sBAAsB,CAAC,OAAO,CAAC;IACvC,MAAM,EAAE,CAAC,IAAI,EAAE;QAAE,GAAG,CAAC,EAAE,eAAe,CAAA;KAAE,KAAK,cAAc,CAAC,OAAO,CAAC,CAAC;CACtE;AAED,MAAM,WAAW,kBAAkB,CAAC,OAAO,SAAS,SAAS,CAC3D,SAAQ,eAAe,CAAC,OAAO,CAAC;IAChC,GAAG,EAAE,IAAI,CAAC;IACV,YAAY,CAAC,EAAE,CAAC,IAAI,EAAE;QACpB,GAAG,EAAE,eAAe,CAAC;QACrB,YAAY,EAAE,eAAe,CAAC,OAAO,CAAC,EAAE,CAAC;KAC1C,KAAK,YAAY,CAAC;CACpB;AACD,MAAM,WAAW,oBAAoB,CAAC,OAAO,SAAS,SAAS,CAC7D,SAAQ,eAAe,CAAC,OAAO,CAAC;IAChC,GAAG,CAAC,EAAE,KAAK,CAAC;CACb;AAED,wBAAgB,QAAQ,CACtB,OAAO,SAAS,SAAS,EACzB,WAAW,SAAS,eAAe,GAAG,eAAe,EACrD,IAAI,EAAE,oBAAoB,CAAC,OAAO,CAAC,GAAG,kBAAkB,CAAC,OAAO,CAAC,eAU9C,kBAAkB,GAAG,EAAE,GAAG,EAAE,GAAG,CAAC,KAAG,iBAAiB,CAkLxE"} +\ No newline at end of file ++{"version":3,"file":"withTRPC.d.ts","sourceRoot":"","sources":["../src/withTRPC.tsx"],"names":[],"mappings":"AAAA;;;GAGG;AACH,OAAO,EACL,eAAe,EAKhB,MAAM,uBAAuB,CAAC;AAC/B,OAAO,KAAK,EAAE,uBAAuB,EAAE,MAAM,cAAc,CAAC;AAC5D,OAAO,EAEL,eAAe,EAIhB,MAAM,mBAAmB,CAAC;AAC3B,OAAO,EACL,sBAAsB,EACtB,gCAAgC,EAEjC,MAAM,0BAA0B,CAAC;AAClC,OAAO,KAAK,EAAE,SAAS,EAAe,MAAM,cAAc,CAAC;AAC3D,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,mBAAmB,CAAC;AACtD,OAAO,EAEL,YAAY,EACZ,iBAAiB,EACjB,eAAe,EAChB,MAAM,4BAA4B,CAAC;AACpC,OAAO,EAAE,UAAU,EAAE,MAAM,aAAa,CAAC;AA0BzC,oBAAY,cAAc,CAAC,OAAO,SAAS,SAAS,IAClD,uBAAuB,CAAC,OAAO,CAAC,GAAG;IACjC,cAAc,CAAC,EAAE,OAAO,CAAC;IACzB,UAAU,CAAC,EAAE,MAAM,CAAC;CACrB,GAAG,gCAAgC,CAAC;AAEvC,aAAK,gBAAgB,GAAG;IAAC,SAAS,EAAE,eAAe,CAAA;CAAC,CAAC;AAErD,UAAU,eAAe,CACvB,OAAO,SAAS,SAAS,EACzB,MAAM,GAAG,gBAAgB,EACzB,WAAW,SAAS,UAAU,GAAG,UAAU,CAC3C,SAAQ,sBAAsB,CAAC,OAAO,CAAC;IACvC,MAAM,EAAE,CACN,IAAI,EACA;QACE,GAAG,EAAE,eAAe,CAAC;KACtB,GACD;QACE,KAAK,EAAE,YAAY,CAAC,WAAW,EAAE,MAAM,CAAC,CAAC;KAC1C,KACF,cAAc,CAAC,OAAO,CAAC,CAAC;CAC9B;AAED,MAAM,WAAW,kBAAkB,CACjC,OAAO,SAAS,SAAS,EACzB,MAAM,GAAG,gBAAgB,EACzB,WAAW,SAAS,UAAU,GAAG,UAAU,CAC3C,SAAQ,eAAe,CAAC,OAAO,EAAE,MAAM,EAAE,WAAW,CAAC;IACrD,GAAG,EAAE,IAAI,CAAC;IACV,YAAY,CAAC,EAAE,CAAC,IAAI,EAAE;QACpB,GAAG,EAAE,eAAe,CAAC;QACrB,YAAY,EAAE,eAAe,CAAC,OAAO,CAAC,EAAE,CAAC;KAC1C,KAAK,YAAY,CAAC;CACpB;AACD,MAAM,WAAW,oBAAoB,CACnC,OAAO,SAAS,SAAS,EACzB,MAAM,GAAG,gBAAgB,EACzB,WAAW,SAAS,UAAU,GAAG,UAAU,CAC3C,SAAQ,eAAe,CAAC,OAAO,EAAE,MAAM,EAAE,WAAW,CAAC;IACrD,GAAG,CAAC,EAAE,KAAK,CAAC;CACb;AAED,wBAAgB,QAAQ,CACtB,OAAO,SAAS,SAAS,EACzB,WAAW,SAAS,eAAe,GAAG,eAAe,EACrD,MAAM,GAAG,gBAAgB,EACzB,WAAW,SAAS,UAAU,GAAG,UAAU,EAE3C,IAAI,EAAE,oBAAoB,CAAC,OAAO,EAAE,MAAM,EAAE,WAAW,CAAC,GAAG,kBAAkB,CAAC,OAAO,EAAE,MAAM,EAAE,WAAW,CAAC,eAWxF,kBAAkB,GAAG,EAAE,GAAG,EAAE,GAAG,CAAC,KAAG,iBAAiB,CA+LxE"} +\ No newline at end of file +diff --git a/node_modules/@trpc/next/src/withTRPC.tsx b/node_modules/@trpc/next/src/withTRPC.tsx +index 0a89da3..b64855b 100644 +--- a/node_modules/@trpc/next/src/withTRPC.tsx ++++ b/node_modules/@trpc/next/src/withTRPC.tsx +@@ -59,30 +59,54 @@ function transformQueryOrMutationCacheErrors< + export type WithTRPCConfig = + CreateTRPCClientOptions & { + abortOnUnmount?: boolean; ++ ssrTimeout?: number; + } & CreateTRPCReactQueryClientConfig; + +-interface WithTRPCOptions +- extends CreateTRPCReactOptions { +- config: (info: { ctx?: NextPageContext }) => WithTRPCConfig; ++type BaseInitialProps = {trpcState: DehydratedState}; ++ ++interface WithTRPCOptions< ++ TRouter extends AnyRouter, ++ TProps = BaseInitialProps, ++ TNextRouter extends NextRouter = NextRouter, ++> extends CreateTRPCReactOptions { ++ config: ( ++ info: ++ | { ++ ctx: NextPageContext; ++ } ++ | { ++ props: AppPropsType; ++ }, ++ ) => WithTRPCConfig; + } + +-export interface WithTRPCSSROptions +- extends WithTRPCOptions { ++export interface WithTRPCSSROptions< ++ TRouter extends AnyRouter, ++ TProps = BaseInitialProps, ++ TNextRouter extends NextRouter = NextRouter, ++> extends WithTRPCOptions { + ssr: true; + responseMeta?: (opts: { + ctx: NextPageContext; + clientErrors: TRPCClientError[]; + }) => ResponseMeta; + } +-export interface WithTRPCNoSSROptions +- extends WithTRPCOptions { ++export interface WithTRPCNoSSROptions< ++ TRouter extends AnyRouter, ++ TProps = BaseInitialProps, ++ TNextRouter extends NextRouter = NextRouter, ++> extends WithTRPCOptions { + ssr?: false; + } + + export function withTRPC< + TRouter extends AnyRouter, + TSSRContext extends NextPageContext = NextPageContext, +->(opts: WithTRPCNoSSROptions | WithTRPCSSROptions) { ++ TProps = BaseInitialProps, ++ TNextRouter extends NextRouter = NextRouter, ++>( ++ opts: WithTRPCNoSSROptions | WithTRPCSSROptions, ++) { + const { config: getClientConfig } = opts; + + type TRPCPrepassProps = { +@@ -96,7 +120,7 @@ export function withTRPC< + const trpc = createReactQueryHooks(opts); + + const WithTRPC = ( +- props: AppPropsType & { ++ props: AppPropsType & { + trpc?: TRPCPrepassProps; + }, + ) => { +@@ -105,7 +129,7 @@ export function withTRPC< + return props.trpc; + } + +- const config = getClientConfig({}); ++ const config = getClientConfig({ props }); + const queryClient = getQueryClient(config); + const trpcClient = trpc.createClient(config); + return { +@@ -124,7 +148,7 @@ export function withTRPC< + if (props.pageProps) { + hydratedState = trpc.useDehydratedState( + trpcClient, +- props.pageProps.trpcState, ++ (props.pageProps as any).trpcState, + ); + } + +@@ -204,7 +228,7 @@ export function withTRPC< + } + + // wait until the query cache has settled it's promises +- await new Promise((resolve) => { ++ const prefetchPromise = new Promise((resolve) => { + const unsub = queryClient.getQueryCache().subscribe((event) => { + if (event?.query.getObserversCount() === 0) { + resolve(); +@@ -212,6 +236,19 @@ export function withTRPC< + } + }); + }); ++ if (typeof config.ssrTimeout === 'number') { ++ await Promise.race([ ++ prefetchPromise, ++ new Promise((resolve) => { ++ setTimeout(() => { ++ void queryClient.cancelQueries(); ++ resolve(undefined); ++ }, config.ssrTimeout); ++ }), ++ ]); ++ } else { ++ await prefetchPromise; ++ } + } + const dehydratedCache = dehydrate(queryClient, { + shouldDehydrateQuery() { diff --git a/frontend/patches/@trpc+next+9.27.4.patch b/frontend/patches/@trpc+next+9.27.4.patch deleted file mode 100644 index 64bc6a9b6..000000000 --- a/frontend/patches/@trpc+next+9.27.4.patch +++ /dev/null @@ -1,380 +0,0 @@ -diff --git a/node_modules/@trpc/next/dist/declarations/src/withTRPC.d.ts b/node_modules/@trpc/next/dist/declarations/src/withTRPC.d.ts -index 93ec4d1..3b6f704 100644 ---- a/node_modules/@trpc/next/dist/declarations/src/withTRPC.d.ts -+++ b/node_modules/@trpc/next/dist/declarations/src/withTRPC.d.ts -@@ -4,15 +4,19 @@ - */ - import { CreateTRPCClientOptions, TRPCClientError } from '@trpc/react'; - import type { AnyRouter, ResponseMeta } from '@trpc/server'; --import { NextComponentType, NextPageContext } from 'next/dist/shared/lib/utils'; -+import { NextRouter } from 'next/dist/shared/lib/router/router'; -+import { AppPropsType, NextComponentType, NextPageContext } from 'next/dist/shared/lib/utils'; - import { QueryClient } from 'react-query'; - declare type QueryClientConfig = ConstructorParameters[0]; - export declare type WithTRPCConfig = CreateTRPCClientOptions & { - queryClientConfig?: QueryClientConfig; -+ ssrTimeout?: number; - }; --export declare function withTRPC(opts: { -+export declare function withTRPC(opts: { - config: (info: { -- ctx?: NextPageContext; -+ ctx: NextPageContext; -+ } | { -+ props: AppPropsType; - }) => WithTRPCConfig; - } & ({ - ssr?: false; -diff --git a/node_modules/@trpc/next/dist/declarations/src/withTRPC.d.ts.map b/node_modules/@trpc/next/dist/declarations/src/withTRPC.d.ts.map -index 759d9d5..04d305c 100644 ---- a/node_modules/@trpc/next/dist/declarations/src/withTRPC.d.ts.map -+++ b/node_modules/@trpc/next/dist/declarations/src/withTRPC.d.ts.map -@@ -1 +1 @@ --{"version":3,"file":"withTRPC.d.ts","sourceRoot":"../../../src","sources":["withTRPC.tsx"],"names":[],"mappings":"AAAA;;;GAGG;AACH,OAAO,EACL,uBAAuB,EAEvB,eAAe,EAIhB,MAAM,aAAa,CAAC;AACrB,OAAO,KAAK,EAAE,SAAS,EAAe,YAAY,EAAE,MAAM,cAAc,CAAC;AACzE,OAAO,EAGL,iBAAiB,EACjB,eAAe,EAChB,MAAM,4BAA4B,CAAC;AAEpC,OAAO,EAGL,WAAW,EAGZ,MAAM,aAAa,CAAC;AAGrB,aAAK,iBAAiB,GAAG,qBAAqB,CAAC,OAAO,WAAW,CAAC,CAAC,CAAC,CAAC,CAAC;AAwBtE,oBAAY,cAAc,CAAC,OAAO,SAAS,SAAS,IAClD,uBAAuB,CAAC,OAAO,CAAC,GAAG;IACjC,iBAAiB,CAAC,EAAE,iBAAiB,CAAC;CACvC,CAAC;AAEJ,wBAAgB,QAAQ,CAAC,OAAO,SAAS,SAAS,EAChD,IAAI,EAAE;IACJ,MAAM,EAAE,CAAC,IAAI,EAAE;QAAE,GAAG,CAAC,EAAE,eAAe,CAAA;KAAE,KAAK,cAAc,CAAC,OAAO,CAAC,CAAC;CACtE,GAAG,CACA;IACE,GAAG,CAAC,EAAE,KAAK,CAAC;CACb,GACD;IACE,GAAG,EAAE,IAAI,CAAC;IACV,YAAY,CAAC,EAAE,CAAC,IAAI,EAAE;QACpB,GAAG,EAAE,eAAe,CAAC;QACrB,YAAY,EAAE,eAAe,CAAC,OAAO,CAAC,EAAE,CAAC;KAC1C,KAAK,YAAY,CAAC;CACpB,CACJ,eAWkB,kBAAkB,GAAG,EAAE,GAAG,EAAE,GAAG,CAAC,KAAG,iBAAiB,CAwKxE"} -\ No newline at end of file -+{"version":3,"file":"withTRPC.d.ts","sourceRoot":"../../../src","sources":["withTRPC.tsx"],"names":[],"mappings":"AAAA;;;GAGG;AACH,OAAO,EACL,uBAAuB,EAEvB,eAAe,EAIhB,MAAM,aAAa,CAAC;AACrB,OAAO,KAAK,EAAE,SAAS,EAAe,YAAY,EAAE,MAAM,cAAc,CAAC;AACzE,OAAO,EAAE,UAAU,EAAE,MAAM,oCAAoC,CAAC;AAChE,OAAO,EAEL,YAAY,EACZ,iBAAiB,EACjB,eAAe,EAChB,MAAM,4BAA4B,CAAC;AAEpC,OAAO,EAGL,WAAW,EAGZ,MAAM,aAAa,CAAC;AAGrB,aAAK,iBAAiB,GAAG,qBAAqB,CAAC,OAAO,WAAW,CAAC,CAAC,CAAC,CAAC,CAAC;AAwBtE,oBAAY,cAAc,CAAC,OAAO,SAAS,SAAS,IAClD,uBAAuB,CAAC,OAAO,CAAC,GAAG;IACjC,iBAAiB,CAAC,EAAE,iBAAiB,CAAC;IACtC,UAAU,CAAC,EAAE,MAAM,CAAC;CACrB,CAAC;AAEJ,wBAAgB,QAAQ,CACtB,OAAO,SAAS,SAAS,EACzB,CAAC,GAAG,EAAE,EACN,CAAC,SAAS,UAAU,GAAG,UAAU,EAEjC,IAAI,EAAE;IACJ,MAAM,EAAE,CACN,IAAI,EACA;QACE,GAAG,EAAE,eAAe,CAAC;KACtB,GACD;QACE,KAAK,EAAE,YAAY,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC;KAC3B,KACF,cAAc,CAAC,OAAO,CAAC,CAAC;CAC9B,GAAG,CACA;IACE,GAAG,CAAC,EAAE,KAAK,CAAC;CACb,GACD;IACE,GAAG,EAAE,IAAI,CAAC;IACV,YAAY,CAAC,EAAE,CAAC,IAAI,EAAE;QACpB,GAAG,EAAE,eAAe,CAAC;QACrB,YAAY,EAAE,eAAe,CAAC,OAAO,CAAC,EAAE,CAAC;KAC1C,KAAK,YAAY,CAAC;CACpB,CACJ,eAWkB,kBAAkB,GAAG,EAAE,GAAG,EAAE,GAAG,CAAC,KAAG,iBAAiB,CAqLxE"} -\ No newline at end of file -diff --git a/node_modules/@trpc/next/dist/trpc-next.cjs.dev.js b/node_modules/@trpc/next/dist/trpc-next.cjs.dev.js -index 5298f00..864f488 100644 ---- a/node_modules/@trpc/next/dist/trpc-next.cjs.dev.js -+++ b/node_modules/@trpc/next/dist/trpc-next.cjs.dev.js -@@ -50,7 +50,9 @@ function withTRPC(opts) { - return props.trpc; - } - -- var config = getClientConfig({}); -+ var config = getClientConfig({ -+ props: props -+ }); - var queryClient = new reactQuery.QueryClient(config.queryClientConfig); - var trpcClient = trpc.createClient(config); - return { -@@ -85,7 +87,7 @@ function withTRPC(opts) { - var _ref = _asyncToGenerator( /*#__PURE__*/_regeneratorRuntime__default['default'].mark(function _callee(appOrPageCtx) { - var _opts$responseMeta; - -- var AppTree, isApp, ctx, pageProps, _originalProps$pagePr, originalProps, originalPageProps, getAppTreeProps, config, trpcClient, queryClient, trpcProp, prepassProps, dehydratedCache, dehydratedCacheWithErrors, appTreeProps, meta, _i, _Object$entries, _Object$entries$_i, key, value, _ctx$res; -+ var AppTree, isApp, ctx, pageProps, _originalProps$pagePr, originalProps, originalPageProps, getAppTreeProps, config, trpcClient, queryClient, trpcProp, prepassProps, prefetchPromise, dehydratedCache, dehydratedCacheWithErrors, appTreeProps, meta, _i, _Object$entries, _Object$entries$_i, key, value, _ctx$res; - - return _regeneratorRuntime__default['default'].wrap(function _callee$(_context) { - while (1) { -@@ -155,11 +157,11 @@ function withTRPC(opts) { - break; - } - -- return _context.abrupt("break", 27); -+ return _context.abrupt("break", 33); - - case 23: -- _context.next = 25; -- return new Promise(function (resolve) { -+ // wait until the query cache has settled it's promises -+ prefetchPromise = new Promise(function (resolve) { - var unsub = queryClient.getQueryCache().subscribe(function (event) { - if ((event === null || event === void 0 ? void 0 : event.query.getObserversCount()) === 0) { - resolve(); -@@ -168,11 +170,32 @@ function withTRPC(opts) { - }); - }); - -- case 25: -+ if (!(typeof config.ssrTimeout === 'number')) { -+ _context.next = 29; -+ break; -+ } -+ -+ _context.next = 27; -+ return Promise.race([prefetchPromise, new Promise(function (resolve) { -+ setTimeout(function () { -+ void queryClient.cancelQueries(); -+ resolve(undefined); -+ }, config.ssrTimeout); -+ })]); -+ -+ case 27: -+ _context.next = 31; -+ break; -+ -+ case 29: -+ _context.next = 31; -+ return prefetchPromise; -+ -+ case 31: - _context.next = 18; - break; - -- case 27: -+ case 33: - dehydratedCache = reactQuery.dehydrate(queryClient, { - shouldDehydrateQuery: function shouldDehydrateQuery() { - // makes sure errors are also dehydrated -@@ -210,7 +233,7 @@ function withTRPC(opts) { - - return _context.abrupt("return", appTreeProps); - -- case 35: -+ case 41: - case "end": - return _context.stop(); - } -diff --git a/node_modules/@trpc/next/dist/trpc-next.cjs.prod.js b/node_modules/@trpc/next/dist/trpc-next.cjs.prod.js -index 5298f00..864f488 100644 ---- a/node_modules/@trpc/next/dist/trpc-next.cjs.prod.js -+++ b/node_modules/@trpc/next/dist/trpc-next.cjs.prod.js -@@ -50,7 +50,9 @@ function withTRPC(opts) { - return props.trpc; - } - -- var config = getClientConfig({}); -+ var config = getClientConfig({ -+ props: props -+ }); - var queryClient = new reactQuery.QueryClient(config.queryClientConfig); - var trpcClient = trpc.createClient(config); - return { -@@ -85,7 +87,7 @@ function withTRPC(opts) { - var _ref = _asyncToGenerator( /*#__PURE__*/_regeneratorRuntime__default['default'].mark(function _callee(appOrPageCtx) { - var _opts$responseMeta; - -- var AppTree, isApp, ctx, pageProps, _originalProps$pagePr, originalProps, originalPageProps, getAppTreeProps, config, trpcClient, queryClient, trpcProp, prepassProps, dehydratedCache, dehydratedCacheWithErrors, appTreeProps, meta, _i, _Object$entries, _Object$entries$_i, key, value, _ctx$res; -+ var AppTree, isApp, ctx, pageProps, _originalProps$pagePr, originalProps, originalPageProps, getAppTreeProps, config, trpcClient, queryClient, trpcProp, prepassProps, prefetchPromise, dehydratedCache, dehydratedCacheWithErrors, appTreeProps, meta, _i, _Object$entries, _Object$entries$_i, key, value, _ctx$res; - - return _regeneratorRuntime__default['default'].wrap(function _callee$(_context) { - while (1) { -@@ -155,11 +157,11 @@ function withTRPC(opts) { - break; - } - -- return _context.abrupt("break", 27); -+ return _context.abrupt("break", 33); - - case 23: -- _context.next = 25; -- return new Promise(function (resolve) { -+ // wait until the query cache has settled it's promises -+ prefetchPromise = new Promise(function (resolve) { - var unsub = queryClient.getQueryCache().subscribe(function (event) { - if ((event === null || event === void 0 ? void 0 : event.query.getObserversCount()) === 0) { - resolve(); -@@ -168,11 +170,32 @@ function withTRPC(opts) { - }); - }); - -- case 25: -+ if (!(typeof config.ssrTimeout === 'number')) { -+ _context.next = 29; -+ break; -+ } -+ -+ _context.next = 27; -+ return Promise.race([prefetchPromise, new Promise(function (resolve) { -+ setTimeout(function () { -+ void queryClient.cancelQueries(); -+ resolve(undefined); -+ }, config.ssrTimeout); -+ })]); -+ -+ case 27: -+ _context.next = 31; -+ break; -+ -+ case 29: -+ _context.next = 31; -+ return prefetchPromise; -+ -+ case 31: - _context.next = 18; - break; - -- case 27: -+ case 33: - dehydratedCache = reactQuery.dehydrate(queryClient, { - shouldDehydrateQuery: function shouldDehydrateQuery() { - // makes sure errors are also dehydrated -@@ -210,7 +233,7 @@ function withTRPC(opts) { - - return _context.abrupt("return", appTreeProps); - -- case 35: -+ case 41: - case "end": - return _context.stop(); - } -diff --git a/node_modules/@trpc/next/dist/trpc-next.esm.js b/node_modules/@trpc/next/dist/trpc-next.esm.js -index edf7527..9242b48 100644 ---- a/node_modules/@trpc/next/dist/trpc-next.esm.js -+++ b/node_modules/@trpc/next/dist/trpc-next.esm.js -@@ -40,7 +40,9 @@ function withTRPC(opts) { - return props.trpc; - } - -- var config = getClientConfig({}); -+ var config = getClientConfig({ -+ props: props -+ }); - var queryClient = new QueryClient(config.queryClientConfig); - var trpcClient = trpc.createClient(config); - return { -@@ -75,7 +77,7 @@ function withTRPC(opts) { - var _ref = _asyncToGenerator( /*#__PURE__*/_regeneratorRuntime.mark(function _callee(appOrPageCtx) { - var _opts$responseMeta; - -- var AppTree, isApp, ctx, pageProps, _originalProps$pagePr, originalProps, originalPageProps, getAppTreeProps, config, trpcClient, queryClient, trpcProp, prepassProps, dehydratedCache, dehydratedCacheWithErrors, appTreeProps, meta, _i, _Object$entries, _Object$entries$_i, key, value, _ctx$res; -+ var AppTree, isApp, ctx, pageProps, _originalProps$pagePr, originalProps, originalPageProps, getAppTreeProps, config, trpcClient, queryClient, trpcProp, prepassProps, prefetchPromise, dehydratedCache, dehydratedCacheWithErrors, appTreeProps, meta, _i, _Object$entries, _Object$entries$_i, key, value, _ctx$res; - - return _regeneratorRuntime.wrap(function _callee$(_context) { - while (1) { -@@ -145,11 +147,11 @@ function withTRPC(opts) { - break; - } - -- return _context.abrupt("break", 27); -+ return _context.abrupt("break", 33); - - case 23: -- _context.next = 25; -- return new Promise(function (resolve) { -+ // wait until the query cache has settled it's promises -+ prefetchPromise = new Promise(function (resolve) { - var unsub = queryClient.getQueryCache().subscribe(function (event) { - if ((event === null || event === void 0 ? void 0 : event.query.getObserversCount()) === 0) { - resolve(); -@@ -158,11 +160,32 @@ function withTRPC(opts) { - }); - }); - -- case 25: -+ if (!(typeof config.ssrTimeout === 'number')) { -+ _context.next = 29; -+ break; -+ } -+ -+ _context.next = 27; -+ return Promise.race([prefetchPromise, new Promise(function (resolve) { -+ setTimeout(function () { -+ void queryClient.cancelQueries(); -+ resolve(undefined); -+ }, config.ssrTimeout); -+ })]); -+ -+ case 27: -+ _context.next = 31; -+ break; -+ -+ case 29: -+ _context.next = 31; -+ return prefetchPromise; -+ -+ case 31: - _context.next = 18; - break; - -- case 27: -+ case 33: - dehydratedCache = dehydrate(queryClient, { - shouldDehydrateQuery: function shouldDehydrateQuery() { - // makes sure errors are also dehydrated -@@ -200,7 +223,7 @@ function withTRPC(opts) { - - return _context.abrupt("return", appTreeProps); - -- case 35: -+ case 41: - case "end": - return _context.stop(); - } -diff --git a/node_modules/@trpc/next/src/withTRPC.tsx b/node_modules/@trpc/next/src/withTRPC.tsx -index e7fdf74..c16e65a 100644 ---- a/node_modules/@trpc/next/src/withTRPC.tsx -+++ b/node_modules/@trpc/next/src/withTRPC.tsx -@@ -11,6 +11,7 @@ import { - createTRPCClient, - } from '@trpc/react'; - import type { AnyRouter, Dict, Maybe, ResponseMeta } from '@trpc/server'; -+import { NextRouter } from 'next/dist/shared/lib/router/router'; - import { - AppContextType, - AppPropsType, -@@ -54,11 +55,24 @@ function transformQueryOrMutationCacheErrors< - export type WithTRPCConfig = - CreateTRPCClientOptions & { - queryClientConfig?: QueryClientConfig; -+ ssrTimeout?: number; - }; - --export function withTRPC( -+export function withTRPC< -+ TRouter extends AnyRouter, -+ P = {}, -+ R extends NextRouter = NextRouter, -+>( - opts: { -- config: (info: { ctx?: NextPageContext }) => WithTRPCConfig; -+ config: ( -+ info: -+ | { -+ ctx: NextPageContext; -+ } -+ | { -+ props: AppPropsType; -+ }, -+ ) => WithTRPCConfig; - } & ( - | { - ssr?: false; -@@ -85,7 +99,7 @@ export function withTRPC( - const trpc = createReactQueryHooks(); - - const WithTRPC = ( -- props: AppPropsType & { -+ props: AppPropsType & { - trpc?: TRPCPrepassProps; - }, - ) => { -@@ -94,7 +108,7 @@ export function withTRPC( - if (props.trpc) { - return props.trpc; - } -- const config = getClientConfig({}); -+ const config = getClientConfig({ props }); - const queryClient = new QueryClient(config.queryClientConfig); - const trpcClient = trpc.createClient(config); - return { -@@ -108,7 +122,7 @@ export function withTRPC( - - const hydratedState = trpc.useDehydratedState( - trpcClient, -- props.pageProps?.trpcState, -+ (props.pageProps as any)?.trpcState, - ); - - return ( -@@ -185,7 +199,7 @@ export function withTRPC( - } - - // wait until the query cache has settled it's promises -- await new Promise((resolve) => { -+ const prefetchPromise = new Promise((resolve) => { - const unsub = queryClient.getQueryCache().subscribe((event) => { - if (event?.query.getObserversCount() === 0) { - resolve(); -@@ -193,6 +207,19 @@ export function withTRPC( - } - }); - }); -+ if (typeof config.ssrTimeout === 'number') { -+ await Promise.race([ -+ prefetchPromise, -+ new Promise((resolve) => { -+ setTimeout(() => { -+ void queryClient.cancelQueries(); -+ resolve(undefined); -+ }, config.ssrTimeout); -+ }), -+ ]); -+ } else { -+ await prefetchPromise; -+ } - } - const dehydratedCache = dehydrate(queryClient, { - shouldDehydrateQuery() { diff --git a/frontend/src/components/accounts/AccountDetails.tsx b/frontend/src/components/accounts/AccountDetails.tsx index 35283bb8d..715406703 100644 --- a/frontend/src/components/accounts/AccountDetails.tsx +++ b/frontend/src/components/accounts/AccountDetails.tsx @@ -171,10 +171,9 @@ export interface Props { const AccountDetails: React.FC = React.memo(({ account }) => { const { t } = useTranslation(); - const transactionsQuery = trpc.useQuery([ - "account.transactionsCount", - { id: account.accountId }, - ]); + const transactionsQuery = trpc.account.transactionsCount.useQuery({ + id: account.accountId, + }); const format = useDateFormat(); const formatNumber = useFormatNumber(); @@ -194,8 +193,7 @@ const AccountDetails: React.FC = React.memo(({ account }) => { } imgLink="/static/images/icon-m-transaction.svg" text={ - transactionsQuery.status === "loading" || - transactionsQuery.status === "idle" ? ( + transactionsQuery.status === "loading" ? ( ) : transactionsQuery.status === "error" ? ( diff --git a/frontend/src/components/accounts/AccountRow.tsx b/frontend/src/components/accounts/AccountRow.tsx index a43e28449..87202b435 100644 --- a/frontend/src/components/accounts/AccountRow.tsx +++ b/frontend/src/components/accounts/AccountRow.tsx @@ -51,10 +51,9 @@ export interface Props { const AccountRow: React.FC = React.memo(({ account }) => { const { t } = useTranslation(); - const balanceQuery = trpc.useQuery([ - "account.nonStakedBalance", - { id: account.id }, - ]); + const balanceQuery = trpc.account.nonStakedBalance.useQuery({ + id: account.id, + }); const format = useDateFormat(); return ( @@ -90,8 +89,7 @@ const AccountRow: React.FC = React.memo(({ account }) => { <> {balanceQuery.status === "success" ? ( - ) : balanceQuery.status === "loading" || - balanceQuery.status === "idle" ? ( + ) : balanceQuery.status === "loading" ? ( ) : ( diff --git a/frontend/src/components/accounts/Accounts.tsx b/frontend/src/components/accounts/Accounts.tsx index 3cd8441ad..77b22978f 100644 --- a/frontend/src/components/accounts/Accounts.tsx +++ b/frontend/src/components/accounts/Accounts.tsx @@ -1,6 +1,5 @@ import * as React from "react"; -import { AccountListInfo } from "@/common/types/procedures"; import { id } from "@/common/utils/utils"; import AccountRow from "@/frontend/components/accounts/AccountRow"; import FlipMove from "@/frontend/components/utils/FlipMove"; @@ -10,8 +9,8 @@ import { trpc } from "@/frontend/libraries/trpc"; const ACCOUNTS_PER_PAGE = 15; const Accounts: React.FC = React.memo(() => { - const query = trpc.useInfiniteQuery( - ["account.listByTimestamp", { limit: ACCOUNTS_PER_PAGE }], + const query = trpc.account.listByTimestamp.useInfiniteQuery( + { limit: ACCOUNTS_PER_PAGE }, { getNextPageParam: (lastPage) => { const lastElement = lastPage[lastPage.length - 1]; @@ -23,10 +22,7 @@ const Accounts: React.FC = React.memo(() => { } ); return ( - - query={query} - parser={id} - > + query={query} parser={id}> {(items) => ( {items.map((account) => ( diff --git a/frontend/src/components/beta/accounts/AccountContract.tsx b/frontend/src/components/beta/accounts/AccountContract.tsx index 9d28285e0..1e46c9d07 100644 --- a/frontend/src/components/beta/accounts/AccountContract.tsx +++ b/frontend/src/components/beta/accounts/AccountContract.tsx @@ -32,12 +32,8 @@ export const SmallHeader = styled("div", { const AccountContract: React.FC = React.memo(({ id }) => { const { t } = useTranslation(); - const contractQuery = trpc.useQuery(["contract.byId", { id }]); - if ( - contractQuery.status === "loading" || - contractQuery.status === "idle" || - contractQuery.data === null - ) { + const contractQuery = trpc.contract.byId.useQuery({ id }); + if (contractQuery.status === "loading" || contractQuery.data === null) { return null; } if (contractQuery.status === "error") { @@ -63,7 +59,7 @@ const AccountContract: React.FC = React.memo(({ id }) => { {t("pages.account.header.contract.codeHash")} {contractQuery.data.codeHash} - {contractQuery.data.timestamp ? ( + {"timestamp" in contractQuery.data ? (

{t("pages.account.header.contract.updatedTimestamp")} @@ -71,7 +67,7 @@ const AccountContract: React.FC = React.memo(({ id }) => {
) : null} - {contractQuery.data.transactionHash ? ( + {"transactionHash" in contractQuery.data ? (
{t("pages.account.header.contract.updatedTransaction")} diff --git a/frontend/src/components/beta/accounts/AccountFungibleTokenHistory.tsx b/frontend/src/components/beta/accounts/AccountFungibleTokenHistory.tsx index 71c2e290a..ea33bf8c9 100644 --- a/frontend/src/components/beta/accounts/AccountFungibleTokenHistory.tsx +++ b/frontend/src/components/beta/accounts/AccountFungibleTokenHistory.tsx @@ -134,14 +134,11 @@ type Props = { const AccountFungibleTokenHistory: React.FC = React.memo( ({ accountId, token }) => { - const tokenHistoryQuery = trpc.useQuery([ - "account.fungibleTokenHistory", - { accountId, tokenAuthorAccountId: token.authorAccountId }, - ]); - if ( - tokenHistoryQuery.status === "loading" || - tokenHistoryQuery.status === "idle" - ) { + const tokenHistoryQuery = trpc.account.fungibleTokenHistory.useQuery({ + accountId, + tokenAuthorAccountId: token.authorAccountId, + }); + if (tokenHistoryQuery.status === "loading") { return ; } if (tokenHistoryQuery.status === "error") { diff --git a/frontend/src/components/beta/accounts/AccountFungibleTokens.tsx b/frontend/src/components/beta/accounts/AccountFungibleTokens.tsx index 37575b60d..7f129b115 100644 --- a/frontend/src/components/beta/accounts/AccountFungibleTokens.tsx +++ b/frontend/src/components/beta/accounts/AccountFungibleTokens.tsx @@ -137,11 +137,10 @@ type Props = { }; const AccountFungibleTokensView: React.FC = React.memo(({ options }) => { - const tokensQuery = trpc.useQuery([ - "account.fungibleTokens", - { accountId: options.accountId }, - ]); - if (tokensQuery.status === "loading" || tokensQuery.status === "idle") { + const tokensQuery = trpc.account.fungibleTokens.useQuery({ + accountId: options.accountId, + }); + if (tokensQuery.status === "loading") { return ( diff --git a/frontend/src/components/beta/accounts/AccountNonFungibleTokens.tsx b/frontend/src/components/beta/accounts/AccountNonFungibleTokens.tsx index 6dbdacb4a..3303874b4 100644 --- a/frontend/src/components/beta/accounts/AccountNonFungibleTokens.tsx +++ b/frontend/src/components/beta/accounts/AccountNonFungibleTokens.tsx @@ -168,15 +168,12 @@ const AccountNonFungibleTokens: React.FC = React.memo( [setSelectedId] ); - const query = trpc.useInfiniteQuery( - [ - "account.nonFungibleTokens", - { - contractId: contract, - accountId, - limit: TOKENS_PER_PAGE, - }, - ], + const query = trpc.account.nonFungibleTokens.useInfiniteQuery( + { + contractId: contract, + accountId, + limit: TOKENS_PER_PAGE, + }, { getNextPageParam: (lastPage) => lastPage.cursor, } @@ -189,7 +186,7 @@ const AccountNonFungibleTokens: React.FC = React.memo( ) : ( [number] + TRPCInfiniteQueryOutput<"account.nonFungibleTokens">["items"][number] > query={query} parser={parser} @@ -224,11 +221,10 @@ const AccountNonFungibleTokensView: React.FC = React.memo( (contract: string) => React.MouseEventHandler >((contract) => () => setContract(contract), [setContract]); - const contractQuery = trpc.useQuery([ - "account.nonFungibleTokenContracts", - { accountId: options.accountId }, - ]); - if (contractQuery.status === "loading" || contractQuery.status === "idle") { + const contractQuery = trpc.account.nonFungibleTokenContracts.useQuery({ + accountId: options.accountId, + }); + if (contractQuery.status === "loading") { return ( diff --git a/frontend/src/components/beta/accounts/AccountNonFungibleTokensHistory.tsx b/frontend/src/components/beta/accounts/AccountNonFungibleTokensHistory.tsx index 8a44de1fb..725ba5cf9 100644 --- a/frontend/src/components/beta/accounts/AccountNonFungibleTokensHistory.tsx +++ b/frontend/src/components/beta/accounts/AccountNonFungibleTokensHistory.tsx @@ -135,10 +135,10 @@ type Props = { const AccountNonFungibleTokensHistory: React.FC = React.memo( ({ token, onClick }) => { - const tokenHistoryQuery = trpc.useQuery([ - "account.nonFungibleTokenHistory", - { tokenAuthorAccountId: token.authorAccountId, tokenId: token.tokenId }, - ]); + const tokenHistoryQuery = trpc.account.nonFungibleTokenHistory.useQuery({ + tokenAuthorAccountId: token.authorAccountId, + tokenId: token.tokenId, + }); return ( @@ -171,8 +171,7 @@ const AccountNonFungibleTokensHistory: React.FC = React.memo( {token.ownerId} History - {tokenHistoryQuery.status === "loading" || - tokenHistoryQuery.status === "idle" ? ( + {tokenHistoryQuery.status === "loading" ? ( ) : tokenHistoryQuery.status === "error" ? ( diff --git a/frontend/src/components/beta/accounts/AccountTabs.tsx b/frontend/src/components/beta/accounts/AccountTabs.tsx index 829acf95c..f72681152 100644 --- a/frontend/src/components/beta/accounts/AccountTabs.tsx +++ b/frontend/src/components/beta/accounts/AccountTabs.tsx @@ -42,10 +42,9 @@ const AccountTabs: React.FC = React.memo(({ account, options }) => { account.transactionsQuantity.toString(), 6 ); - const collectiblesCount = trpc.useQuery([ - "account.nonFungibleTokensCount", - { accountId: options.accountId }, - ]); + const collectiblesCount = trpc.account.nonFungibleTokensCount.useQuery({ + accountId: options.accountId, + }); const collectiblesQuantity = collectiblesCount.data ? formatToPowerOfTen( diff --git a/frontend/src/components/beta/accounts/AccountTransactionsView.tsx b/frontend/src/components/beta/accounts/AccountTransactionsView.tsx index 0a7d387da..abad351b5 100644 --- a/frontend/src/components/beta/accounts/AccountTransactionsView.tsx +++ b/frontend/src/components/beta/accounts/AccountTransactionsView.tsx @@ -302,21 +302,15 @@ type Props = { const parser = (result: TransactionListResponse) => result.items; const AccountTransactionsView = React.memo>(({ accountId }) => { - const query = trpc.useInfiniteQuery( - [ - "transaction.listByAccountId", - { accountId, limit: TRANSACTIONS_PER_PAGE }, - ], - React.useMemo( - () => ({ getNextPageParam: (lastPage) => lastPage.cursor }), - [] - ) + const query = trpc.transaction.listByAccountId.useInfiniteQuery( + { accountId, limit: TRANSACTIONS_PER_PAGE }, + { getNextPageParam: (lastPage) => lastPage.cursor } ); return ( [number] + TransactionListResponse["items"][number] > query={query} parser={parser} diff --git a/frontend/src/components/beta/transactions/InspectReceipt.tsx b/frontend/src/components/beta/transactions/InspectReceipt.tsx index 60b966f43..d474906ae 100644 --- a/frontend/src/components/beta/transactions/InspectReceipt.tsx +++ b/frontend/src/components/beta/transactions/InspectReceipt.tsx @@ -61,14 +61,16 @@ const getGasAttached = (actions: Action[]): JSBI => { const InspectReceipt: React.FC = React.memo( ({ receipt: { id, ...receipt } }) => { - const { data: predecessorBalance } = trpc.useQuery([ - "transaction.accountBalanceChange", - { accountId: receipt.predecessorId, receiptId: id }, - ]); - const { data: receiverBalance } = trpc.useQuery([ - "transaction.accountBalanceChange", - { accountId: receipt.receiverId, receiptId: id }, - ]); + const { data: predecessorBalance } = + trpc.transaction.accountBalanceChange.useQuery({ + accountId: receipt.predecessorId, + receiptId: id, + }); + const { data: receiverBalance } = + trpc.transaction.accountBalanceChange.useQuery({ + accountId: receipt.receiverId, + receiptId: id, + }); const gasAttached = getGasAttached(receipt.actions); const refund = diff --git a/frontend/src/components/blocks/BlockDetails.tsx b/frontend/src/components/blocks/BlockDetails.tsx index 289fafb4f..f58b4e758 100644 --- a/frontend/src/components/blocks/BlockDetails.tsx +++ b/frontend/src/components/blocks/BlockDetails.tsx @@ -17,7 +17,7 @@ import GasPrice from "@/frontend/components/utils/GasPrice"; import Term from "@/frontend/components/utils/Term"; import { useDateFormat } from "@/frontend/hooks/use-date-format"; import { useFormatNumber } from "@/frontend/hooks/use-format-number"; -import { useSubscription } from "@/frontend/hooks/use-subscription"; +import { subscriptions } from "@/frontend/hooks/use-subscription"; import { styled } from "@/frontend/libraries/styles"; const BlockInfoContainer = styled(Col, { @@ -55,7 +55,7 @@ export interface Props { const BlockDetails: React.FC = React.memo(({ block }) => { const { t } = useTranslation(); - const latestBlockSub = useSubscription(["latestBlock"]); + const latestBlockSub = subscriptions.latestBlock.useSubscription(); const gasUsed = React.useMemo( () => JSBI.BigInt(block.gasUsed), [block.gasUsed] diff --git a/frontend/src/components/blocks/Blocks.tsx b/frontend/src/components/blocks/Blocks.tsx index fa380f056..02149b9e7 100644 --- a/frontend/src/components/blocks/Blocks.tsx +++ b/frontend/src/components/blocks/Blocks.tsx @@ -2,23 +2,22 @@ import * as React from "react"; import { useTranslation } from "next-i18next"; -import { BlockBase } from "@/common/types/procedures"; import { id } from "@/common/utils/utils"; import BlocksRow from "@/frontend/components/blocks/BlocksRow"; import FlipMove from "@/frontend/components/utils/FlipMove"; import ListHandler from "@/frontend/components/utils/ListHandler"; import Placeholder from "@/frontend/components/utils/Placeholder"; -import { useSubscription } from "@/frontend/hooks/use-subscription"; +import { subscriptions } from "@/frontend/hooks/use-subscription"; import { trpc } from "@/frontend/libraries/trpc"; const BLOCKS_PER_PAGE = 15; const Blocks: React.FC = React.memo(() => { const { t } = useTranslation(); - const latestBlockSub = useSubscription(["latestBlock"]); + const latestBlockSub = subscriptions.latestBlock.useSubscription(); - const query = trpc.useInfiniteQuery( - ["block.list", { limit: BLOCKS_PER_PAGE }], + const query = trpc.block.list.useInfiniteQuery( + { limit: BLOCKS_PER_PAGE }, { getNextPageParam: (lastPage) => { const lastElement = lastPage[lastPage.length - 1]; @@ -34,7 +33,7 @@ const Blocks: React.FC = React.memo(() => { const onRefetchClick = React.useCallback(() => refetch(), [refetch]); return ( - + query={query} parser={id} prependChildren={ diff --git a/frontend/src/components/blocks/BlocksRow.tsx b/frontend/src/components/blocks/BlocksRow.tsx index 56cb729a2..1a38d67fd 100644 --- a/frontend/src/components/blocks/BlocksRow.tsx +++ b/frontend/src/components/blocks/BlocksRow.tsx @@ -6,7 +6,7 @@ import { Row, Col } from "react-bootstrap"; import { BlockBase } from "@/common/types/procedures"; import Link from "@/frontend/components/utils/Link"; import Timer from "@/frontend/components/utils/Timer"; -import { useSubscription } from "@/frontend/hooks/use-subscription"; +import { subscriptions } from "@/frontend/hooks/use-subscription"; import { styled } from "@/frontend/libraries/styles"; const TransactionRow = styled(Row, { @@ -63,7 +63,7 @@ export interface Props { const BlocksRow: React.FC = React.memo(({ block }) => { const { t } = useTranslation(); - const latestBlockSub = useSubscription(["latestBlock"]); + const latestBlockSub = subscriptions.latestBlock.useSubscription(); return ( diff --git a/frontend/src/components/contracts/ContractDetails.tsx b/frontend/src/components/contracts/ContractDetails.tsx index 9face17d1..74a2cce11 100644 --- a/frontend/src/components/contracts/ContractDetails.tsx +++ b/frontend/src/components/contracts/ContractDetails.tsx @@ -49,13 +49,9 @@ interface Props { const ContractDetails: React.FC = React.memo(({ accountId }) => { const { t } = useTranslation(); - const contractQuery = trpc.useQuery(["contract.byId", { id: accountId }]); + const contractQuery = trpc.contract.byId.useQuery({ id: accountId }); const format = useDateFormat(); - if ( - contractQuery.status === "loading" || - contractQuery.status === "idle" || - !contractQuery.data - ) { + if (contractQuery.status === "loading" || !contractQuery.data) { return null; } if (contractQuery.status === "error") { @@ -87,7 +83,7 @@ const ContractDetails: React.FC = React.memo(({ accountId }) => { /> } text={ - contractQuery.data.timestamp ? ( + "timestamp" in contractQuery.data ? ( <> {format( contractQuery.data.timestamp, @@ -118,7 +114,7 @@ const ContractDetails: React.FC = React.memo(({ accountId }) => { /> } text={ - contractQuery.data.transactionHash ? ( + "transactionHash" in contractQuery.data ? ( diff --git a/frontend/src/components/dashboard/DashboardBlock.tsx b/frontend/src/components/dashboard/DashboardBlock.tsx index 861a37e16..84b480be4 100644 --- a/frontend/src/components/dashboard/DashboardBlock.tsx +++ b/frontend/src/components/dashboard/DashboardBlock.tsx @@ -9,7 +9,7 @@ import Link from "@/frontend/components/utils/Link"; import LongCardCell from "@/frontend/components/utils/LongCardCell"; import Term from "@/frontend/components/utils/Term"; import { useFormatNumber } from "@/frontend/hooks/use-format-number"; -import { useSubscription } from "@/frontend/hooks/use-subscription"; +import { subscriptions } from "@/frontend/hooks/use-subscription"; import { styled } from "@/frontend/libraries/styles"; const ElementWrapper = styled("div", { @@ -23,8 +23,9 @@ const ElementWrapper = styled("div", { const DashboardBlock: React.FC = React.memo(() => { const { t } = useTranslation(); - const latestBlockSub = useSubscription(["latestBlock"]); - const blockProductionSpeedSub = useSubscription(["blockProductionSpeed"]); + const latestBlockSub = subscriptions.latestBlock.useSubscription(); + const blockProductionSpeedSub = + subscriptions.blockProductionSpeed.useSubscription(); const formatNumber = useFormatNumber(); return ( diff --git a/frontend/src/components/dashboard/DashboardNode.tsx b/frontend/src/components/dashboard/DashboardNode.tsx index 1ba200c79..7f36c3748 100644 --- a/frontend/src/components/dashboard/DashboardNode.tsx +++ b/frontend/src/components/dashboard/DashboardNode.tsx @@ -8,12 +8,13 @@ import LinkWrapper from "@/frontend/components/utils/Link"; import LongCardCell from "@/frontend/components/utils/LongCardCell"; import Term from "@/frontend/components/utils/Term"; import { useFormatNumber } from "@/frontend/hooks/use-format-number"; -import { useSubscription } from "@/frontend/hooks/use-subscription"; +import { subscriptions } from "@/frontend/hooks/use-subscription"; const DashboardNode: React.FC = React.memo(() => { const { t } = useTranslation(); - const currentValidatorsCountSub = useSubscription(["currentValidatorsCount"]); - const onlineNodesCountSub = useSubscription(["onlineNodesCount"]); + const currentValidatorsCountSub = + subscriptions.currentValidatorsCount.useSubscription(); + const onlineNodesCountSub = subscriptions.onlineNodesCount.useSubscription(); const formatNumber = useFormatNumber(); return ( diff --git a/frontend/src/components/dashboard/DashboardTransaction.tsx b/frontend/src/components/dashboard/DashboardTransaction.tsx index 8cd2e2a69..924a081c2 100644 --- a/frontend/src/components/dashboard/DashboardTransaction.tsx +++ b/frontend/src/components/dashboard/DashboardTransaction.tsx @@ -10,7 +10,7 @@ import Link from "@/frontend/components/utils/Link"; import LongCardCell from "@/frontend/components/utils/LongCardCell"; import Term from "@/frontend/components/utils/Term"; import { useFormatNumber } from "@/frontend/hooks/use-format-number"; -import { useSubscription } from "@/frontend/hooks/use-subscription"; +import { subscriptions } from "@/frontend/hooks/use-subscription"; import { styled } from "@/frontend/libraries/styles"; const TransactionCardNumber = styled(Row, { @@ -21,10 +21,9 @@ const TransactionCardNumber = styled(Row, { const DashboardTransaction: React.FC = React.memo(() => { const { t } = useTranslation(); - const recentTransactionsCountSub = useSubscription([ - "recentTransactionsCount", - ]); - const latestGasPriceSub = useSubscription(["latestGasPrice"]); + const recentTransactionsCountSub = + subscriptions.recentTransactionsCount.useSubscription(); + const latestGasPriceSub = subscriptions.latestGasPrice.useSubscription(); const formatNumber = useFormatNumber(); return ( diff --git a/frontend/src/components/dashboard/DashboardTransactionsHistoryChart.tsx b/frontend/src/components/dashboard/DashboardTransactionsHistoryChart.tsx index e80e22595..4c7c441b4 100644 --- a/frontend/src/components/dashboard/DashboardTransactionsHistoryChart.tsx +++ b/frontend/src/components/dashboard/DashboardTransactionsHistoryChart.tsx @@ -7,13 +7,13 @@ import { Col, Row } from "react-bootstrap"; import { TRPCSubscriptionOutput } from "@/common/types/trpc"; import PaginationSpinner from "@/frontend/components/utils/PaginationSpinner"; -import { useSubscription } from "@/frontend/hooks/use-subscription"; +import { subscriptions } from "@/frontend/hooks/use-subscription"; import { styled } from "@/frontend/libraries/styles"; const getOption = ( title: string, transactionsTitle: string, - data: TRPCSubscriptionOutput<"transactionsHistory"> + data: TRPCSubscriptionOutput<"subscriptions.transactionsHistory"> ) => ({ title: { text: title, @@ -119,10 +119,8 @@ const TransactionCharts = styled(Row, { }); const DashboardTransactionsHistoryChart: React.FC = React.memo(() => { - const transactionHistorySub = useSubscription([ - "transactionsHistory", - { amountOfDays: 14 }, - ]); + const transactionHistorySub = + subscriptions.transactionsHistory.useSubscription({ amountOfDays: 14 }); const { t } = useTranslation(); const option = React.useMemo(() => { diff --git a/frontend/src/components/nodes/NodeNav.tsx b/frontend/src/components/nodes/NodeNav.tsx index d0d24a69b..589f4048d 100644 --- a/frontend/src/components/nodes/NodeNav.tsx +++ b/frontend/src/components/nodes/NodeNav.tsx @@ -4,7 +4,7 @@ import { useTranslation } from "next-i18next"; import { Badge, Col, Row } from "react-bootstrap"; import Link from "@/frontend/components/utils/Link"; -import { useSubscription } from "@/frontend/hooks/use-subscription"; +import { subscriptions } from "@/frontend/hooks/use-subscription"; import { styled } from "@/frontend/libraries/styles"; const NodeSelector = styled(Col, { @@ -41,7 +41,8 @@ const NodeLink = styled(Link, { const NodeNav: React.FC = React.memo(() => { const { t } = useTranslation(); - const currentValidatorsCountSub = useSubscription(["currentValidatorsCount"]); + const currentValidatorsCountSub = + subscriptions.currentValidatorsCount.useSubscription(); return ( diff --git a/frontend/src/components/nodes/NodesCard.tsx b/frontend/src/components/nodes/NodesCard.tsx index 3cba16226..82be4d18e 100644 --- a/frontend/src/components/nodes/NodesCard.tsx +++ b/frontend/src/components/nodes/NodesCard.tsx @@ -15,7 +15,7 @@ import { InfoCardCell as Cell, InfoCardText, } from "@/frontend/components/utils/InfoCard"; -import { useSubscription } from "@/frontend/hooks/use-subscription"; +import { subscriptions } from "@/frontend/hooks/use-subscription"; import * as BI from "@/frontend/libraries/bigint"; import { styled } from "@/frontend/libraries/styles"; @@ -102,10 +102,11 @@ const NodeBalance: React.FC = React.memo(({ amount, type }) => { const NodesCard = React.memo(() => { const { t } = useTranslation(); - const epochStatsSub = useSubscription(["epochStats"]); - const epochStartBlockSub = useSubscription(["epochStartBlock"]); - const currentValidatorsCountSub = useSubscription(["currentValidatorsCount"]); - const validatorsSub = useSubscription(["validators"]); + const epochStatsSub = subscriptions.epochStats.useSubscription(); + const epochStartBlockSub = subscriptions.epochStartBlock.useSubscription(); + const currentValidatorsCountSub = + subscriptions.currentValidatorsCount.useSubscription(); + const validatorsSub = subscriptions.validators.useSubscription(); const totalStake = React.useMemo( () => (validatorsSub.data ? getTotalStake(validatorsSub.data) : undefined), [validatorsSub.data] diff --git a/frontend/src/components/nodes/NodesEpoch.tsx b/frontend/src/components/nodes/NodesEpoch.tsx index 7e9a47f6d..e17cd8d43 100644 --- a/frontend/src/components/nodes/NodesEpoch.tsx +++ b/frontend/src/components/nodes/NodesEpoch.tsx @@ -5,7 +5,7 @@ import { Row, Col } from "react-bootstrap"; import ProgressBar from "@/frontend/components/utils/ProgressBar"; import { useDateFormat } from "@/frontend/hooks/use-date-format"; -import { useSubscription } from "@/frontend/hooks/use-subscription"; +import { subscriptions } from "@/frontend/hooks/use-subscription"; import { styled } from "@/frontend/libraries/styles"; const NodesEpochContent = styled(Col, { @@ -42,11 +42,11 @@ const NodesEpochCircleProgressLabel = styled("span", { const NodesEpoch = React.memo(() => { const { t } = useTranslation(); - const latestBlockSub = useSubscription(["latestBlock"]); + const latestBlockSub = subscriptions.latestBlock.useSubscription(); const format = useDateFormat(); - const protocolConfigSub = useSubscription(["protocolConfig"]); - const epochStartBlockSub = useSubscription(["epochStartBlock"]); + const protocolConfigSub = subscriptions.protocolConfig.useSubscription(); + const epochStartBlockSub = subscriptions.epochStartBlock.useSubscription(); if ( latestBlockSub.status !== "success" || epochStartBlockSub.status !== "success" || diff --git a/frontend/src/components/nodes/ValidatorTelemetryElements.tsx b/frontend/src/components/nodes/ValidatorTelemetryElements.tsx index f9785cbc0..ab9dcc8a0 100644 --- a/frontend/src/components/nodes/ValidatorTelemetryElements.tsx +++ b/frontend/src/components/nodes/ValidatorTelemetryElements.tsx @@ -10,7 +10,7 @@ import { import ErrorMessage from "@/frontend/components/utils/ErrorMessage"; import Term from "@/frontend/components/utils/Term"; import Timer from "@/frontend/components/utils/Timer"; -import { useSubscription } from "@/frontend/hooks/use-subscription"; +import { subscriptions } from "@/frontend/hooks/use-subscription"; import { styled } from "@/frontend/libraries/styles"; const ValidatorNodesText = styled(Col, { @@ -34,10 +34,11 @@ interface Props { const ValidatorTelemetryRow: React.FC = React.memo(({ accountId }) => { const { t } = useTranslation(); - const latestBlockSub = useSubscription(["latestBlock"]); - const telemetrySub = useSubscription(["validatorTelemetry", accountId]); + const latestBlockSub = subscriptions.latestBlock.useSubscription(); + const telemetrySub = + subscriptions.validatorTelemetry.useSubscription(accountId); - if (telemetrySub.status === "loading" || telemetrySub.status === "idle") { + if (telemetrySub.status === "loading") { return ; } if (telemetrySub.status === "error") { diff --git a/frontend/src/components/nodes/Validators.tsx b/frontend/src/components/nodes/Validators.tsx index d738fbce0..2ae8b29c4 100644 --- a/frontend/src/components/nodes/Validators.tsx +++ b/frontend/src/components/nodes/Validators.tsx @@ -8,7 +8,7 @@ import ValidatorsList, { import { PaginateWrapper } from "@/frontend/components/utils/Pagination"; import PaginationSpinner from "@/frontend/components/utils/PaginationSpinner"; import { Table, OnPageChange } from "@/frontend/components/utils/Table"; -import { useSubscription } from "@/frontend/hooks/use-subscription"; +import { subscriptions } from "@/frontend/hooks/use-subscription"; import { styled } from "@/frontend/libraries/styles"; const ValidatorNodePagination = styled(PaginateWrapper, { @@ -30,7 +30,7 @@ const Validators: React.FC = React.memo(() => { [setSelectedPageIndex] ); - const validatorsSub = useSubscription(["validators"]); + const validatorsSub = subscriptions.validators.useSubscription(); if (validatorsSub.status !== "success") { return ; diff --git a/frontend/src/components/nodes/ValidatorsList.tsx b/frontend/src/components/nodes/ValidatorsList.tsx index 53cceaf59..ed87b1605 100644 --- a/frontend/src/components/nodes/ValidatorsList.tsx +++ b/frontend/src/components/nodes/ValidatorsList.tsx @@ -5,7 +5,7 @@ import JSBI from "jsbi"; import { ValidatorFullData } from "@/common/types/procedures"; import { notNullishGuard } from "@/common/utils/utils"; import ValidatorRow from "@/frontend/components/nodes/ValidatorRow"; -import { useSubscription } from "@/frontend/hooks/use-subscription"; +import { subscriptions } from "@/frontend/hooks/use-subscription"; import * as BI from "@/frontend/libraries/bigint"; // The share of "network holders", cumulative amount of validators @@ -89,7 +89,7 @@ const ValidatorsList: React.FC = React.memo( const startValidatorIndex = selectedPageIndex * ITEMS_PER_PAGE; - const epochStatsSub = useSubscription(["epochStats"]); + const epochStatsSub = subscriptions.epochStats.useSubscription(); return ( <> diff --git a/frontend/src/components/receipts/ReceiptsExecutedInBlock.tsx b/frontend/src/components/receipts/ReceiptsExecutedInBlock.tsx index a9e6a1546..a207ecd14 100644 --- a/frontend/src/components/receipts/ReceiptsExecutedInBlock.tsx +++ b/frontend/src/components/receipts/ReceiptsExecutedInBlock.tsx @@ -8,10 +8,9 @@ interface Props { } const ReceiptsExecutedInBlock: React.FC = React.memo(({ blockHash }) => { - const { data: receiptsList } = trpc.useQuery([ - "receipt.listExecutedByBlockHash", - { blockHash }, - ]); + const { data: receiptsList } = trpc.receipt.listExecutedByBlockHash.useQuery({ + blockHash, + }); return ; }); diff --git a/frontend/src/components/receipts/ReceiptsIncludedInBlock.tsx b/frontend/src/components/receipts/ReceiptsIncludedInBlock.tsx index 5fc24f31c..de9d0ae07 100644 --- a/frontend/src/components/receipts/ReceiptsIncludedInBlock.tsx +++ b/frontend/src/components/receipts/ReceiptsIncludedInBlock.tsx @@ -8,10 +8,9 @@ interface Props { } const ReceiptsIncludedInBlock: React.FC = React.memo(({ blockHash }) => { - const { data: receiptsList } = trpc.useQuery([ - "receipt.listIncludedByBlockHash", - { blockHash }, - ]); + const { data: receiptsList } = trpc.receipt.listIncludedByBlockHash.useQuery({ + blockHash, + }); return ; }); diff --git a/frontend/src/components/stats/ActiveAccountsByDate.tsx b/frontend/src/components/stats/ActiveAccountsByDate.tsx index 1d02edf38..89f915171 100644 --- a/frontend/src/components/stats/ActiveAccountsByDate.tsx +++ b/frontend/src/components/stats/ActiveAccountsByDate.tsx @@ -8,14 +8,14 @@ import { Tabs, Tab } from "react-bootstrap"; import { TRPCSubscriptionOutput } from "@/common/types/trpc"; import { Props } from "@/frontend/components/stats/TransactionsByDate"; import PaginationSpinner from "@/frontend/components/utils/PaginationSpinner"; -import { useSubscription } from "@/frontend/hooks/use-subscription"; +import { subscriptions } from "@/frontend/hooks/use-subscription"; const getOption = ( title: string, seriesName: string, data: - | TRPCSubscriptionOutput<"activeAccountsHistory">["byDay"] - | TRPCSubscriptionOutput<"activeAccountsHistory">["byWeek"] + | TRPCSubscriptionOutput<"subscriptions.activeAccountsHistory">["byDay"] + | TRPCSubscriptionOutput<"subscriptions.activeAccountsHistory">["byWeek"] ) => ({ title: { text: title, @@ -91,7 +91,8 @@ const getOption = ( const ActiveAccountsByDate: React.FC = React.memo(({ chartStyle }) => { const { t } = useTranslation(); - const activeAccountsHistorySub = useSubscription(["activeAccountsHistory"]); + const activeAccountsHistorySub = + subscriptions.activeAccountsHistory.useSubscription(); const options = React.useMemo(() => { if (!activeAccountsHistorySub.data) { diff --git a/frontend/src/components/stats/ActiveAccountsList.tsx b/frontend/src/components/stats/ActiveAccountsList.tsx index 633df2a0e..2f241e460 100644 --- a/frontend/src/components/stats/ActiveAccountsList.tsx +++ b/frontend/src/components/stats/ActiveAccountsList.tsx @@ -6,13 +6,13 @@ import { useTranslation } from "next-i18next"; import { TRPCSubscriptionOutput } from "@/common/types/trpc"; import { Props } from "@/frontend/components/stats/TransactionsByDate"; import PaginationSpinner from "@/frontend/components/utils/PaginationSpinner"; -import { useSubscription } from "@/frontend/hooks/use-subscription"; +import { subscriptions } from "@/frontend/hooks/use-subscription"; import { truncateAccountId } from "@/frontend/libraries/formatting"; const getOption = ( title: string, xAxisTitle: string, - data: TRPCSubscriptionOutput<"activeAccountsList"> + data: TRPCSubscriptionOutput<"subscriptions.activeAccountsList"> ) => ({ title: { text: title, @@ -45,7 +45,8 @@ const getOption = ( const ActiveAccountsList: React.FC = React.memo(({ chartStyle }) => { const { t } = useTranslation(); - const activeAccountsListSub = useSubscription(["activeAccountsList"]); + const activeAccountsListSub = + subscriptions.activeAccountsList.useSubscription(); const option = React.useMemo(() => { if (!activeAccountsListSub.data) { diff --git a/frontend/src/components/stats/ActiveContractsByDate.tsx b/frontend/src/components/stats/ActiveContractsByDate.tsx index 428c7b286..04a544094 100644 --- a/frontend/src/components/stats/ActiveContractsByDate.tsx +++ b/frontend/src/components/stats/ActiveContractsByDate.tsx @@ -7,12 +7,12 @@ import { useTranslation } from "next-i18next"; import { TRPCSubscriptionOutput } from "@/common/types/trpc"; import { Props } from "@/frontend/components/stats/TransactionsByDate"; import PaginationSpinner from "@/frontend/components/utils/PaginationSpinner"; -import { useSubscription } from "@/frontend/hooks/use-subscription"; +import { subscriptions } from "@/frontend/hooks/use-subscription"; const getOption = ( title: string, seriesName: string, - data: TRPCSubscriptionOutput<"activeContractsHistory"> + data: TRPCSubscriptionOutput<"subscriptions.activeContractsHistory"> ) => ({ title: { text: title, @@ -88,7 +88,8 @@ const getOption = ( const ActiveContractsByDate: React.FC = React.memo(({ chartStyle }) => { const { t } = useTranslation(); - const activeContractsHistorySub = useSubscription(["activeContractsHistory"]); + const activeContractsHistorySub = + subscriptions.activeContractsHistory.useSubscription(); const option = React.useMemo(() => { if (!activeContractsHistorySub.data) { diff --git a/frontend/src/components/stats/ActiveContractsList.tsx b/frontend/src/components/stats/ActiveContractsList.tsx index da2afd8f5..7e0371369 100644 --- a/frontend/src/components/stats/ActiveContractsList.tsx +++ b/frontend/src/components/stats/ActiveContractsList.tsx @@ -6,13 +6,13 @@ import { useTranslation } from "next-i18next"; import { TRPCSubscriptionOutput } from "@/common/types/trpc"; import { Props } from "@/frontend/components/stats/TransactionsByDate"; import PaginationSpinner from "@/frontend/components/utils/PaginationSpinner"; -import { useSubscription } from "@/frontend/hooks/use-subscription"; +import { subscriptions } from "@/frontend/hooks/use-subscription"; import { truncateAccountId } from "@/frontend/libraries/formatting"; const getOption = ( title: string, xAxisTitle: string, - data: TRPCSubscriptionOutput<"activeContractsList"> + data: TRPCSubscriptionOutput<"subscriptions.activeContractsList"> ) => ({ title: { text: title, @@ -45,7 +45,8 @@ const getOption = ( const ActiveContractsList: React.FC = React.memo(({ chartStyle }) => { const { t } = useTranslation(); - const activeContractsListSub = useSubscription(["activeContractsList"]); + const activeContractsListSub = + subscriptions.activeContractsList.useSubscription(); const option = React.useMemo(() => { if (activeContractsListSub.status !== "success") { diff --git a/frontend/src/components/stats/CirculatingSupplyStats.tsx b/frontend/src/components/stats/CirculatingSupplyStats.tsx index 02ac9f92e..ff22aa5be 100644 --- a/frontend/src/components/stats/CirculatingSupplyStats.tsx +++ b/frontend/src/components/stats/CirculatingSupplyStats.tsx @@ -7,13 +7,13 @@ import { useTranslation } from "next-i18next"; import { TRPCSubscriptionOutput } from "@/common/types/trpc"; import { Props } from "@/frontend/components/stats/TransactionsByDate"; import PaginationSpinner from "@/frontend/components/utils/PaginationSpinner"; -import { useSubscription } from "@/frontend/hooks/use-subscription"; +import { subscriptions } from "@/frontend/hooks/use-subscription"; import { styled } from "@/frontend/libraries/styles"; const getOption = ( totalTokenSupplyHeader: string, circulatingTokenSupplyHeader: string, - data: TRPCSubscriptionOutput<"tokensSupply"> + data: TRPCSubscriptionOutput<"subscriptions.tokensSupply"> ) => ({ tooltip: { trigger: "axis", @@ -148,7 +148,7 @@ const SupplySubHeader = styled("div", { const CirculatingSupplyStats: React.FC = React.memo(({ chartStyle }) => { const { t } = useTranslation(); - const tokensSupplySub = useSubscription(["tokensSupply"]); + const tokensSupplySub = subscriptions.tokensSupply.useSubscription(); const option = React.useMemo(() => { if (!tokensSupplySub.data) { diff --git a/frontend/src/components/stats/GasUsedByDate.tsx b/frontend/src/components/stats/GasUsedByDate.tsx index c991a2bab..4e3fbd2d5 100644 --- a/frontend/src/components/stats/GasUsedByDate.tsx +++ b/frontend/src/components/stats/GasUsedByDate.tsx @@ -9,14 +9,14 @@ import { Tabs, Tab } from "react-bootstrap"; import { TRPCSubscriptionOutput } from "@/common/types/trpc"; import { Props } from "@/frontend/components/stats/TransactionsByDate"; import PaginationSpinner from "@/frontend/components/utils/PaginationSpinner"; -import { useSubscription } from "@/frontend/hooks/use-subscription"; +import { subscriptions } from "@/frontend/hooks/use-subscription"; import * as BI from "@/frontend/libraries/bigint"; import { getCumulativeArray } from "@/frontend/libraries/stats"; const getOption = ( title: string, yAxisTitle: string, - data: TRPCSubscriptionOutput<"gasUsedHistory"> + data: TRPCSubscriptionOutput<"subscriptions.gasUsedHistory"> ) => ({ title: { text: title, @@ -117,8 +117,8 @@ const getGasCostInNear = ( const GasUsedByDateChart: React.FC = React.memo(({ chartStyle }) => { const { t } = useTranslation(); - const latestGasPriceSub = useSubscription(["latestGasPrice"]); - const gasUsedHistorySub = useSubscription(["gasUsedHistory"]); + const latestGasPriceSub = subscriptions.latestGasPrice.useSubscription(); + const gasUsedHistorySub = subscriptions.gasUsedHistory.useSubscription(); const options = React.useMemo(() => { if (!gasUsedHistorySub.data) { diff --git a/frontend/src/components/stats/NewAccountsByDate.tsx b/frontend/src/components/stats/NewAccountsByDate.tsx index 364291de0..f0fa3dce9 100644 --- a/frontend/src/components/stats/NewAccountsByDate.tsx +++ b/frontend/src/components/stats/NewAccountsByDate.tsx @@ -8,15 +8,15 @@ import { Tabs, Tab } from "react-bootstrap"; import { TRPCSubscriptionOutput } from "@/common/types/trpc"; import { Props } from "@/frontend/components/stats/TransactionsByDate"; import PaginationSpinner from "@/frontend/components/utils/PaginationSpinner"; -import { useSubscription } from "@/frontend/hooks/use-subscription"; +import { subscriptions } from "@/frontend/hooks/use-subscription"; import { getCumulativeArray } from "@/frontend/libraries/stats"; const getOption = ( title: string, seriesName: string, data: - | TRPCSubscriptionOutput<"accountsHistory">["newAccounts"] - | TRPCSubscriptionOutput<"accountsHistory">["liveAccounts"] + | TRPCSubscriptionOutput<"subscriptions.accountsHistory">["newAccounts"] + | TRPCSubscriptionOutput<"subscriptions.accountsHistory">["liveAccounts"] ) => ({ title: { text: title, @@ -92,7 +92,7 @@ const getOption = ( const NewAccountsByDate: React.FC = React.memo(({ chartStyle }) => { const { t } = useTranslation(); - const accountsHistorySub = useSubscription(["accountsHistory"]); + const accountsHistorySub = subscriptions.accountsHistory.useSubscription(); const options = React.useMemo(() => { if (!accountsHistorySub.data) { diff --git a/frontend/src/components/stats/NewContractsByDate.tsx b/frontend/src/components/stats/NewContractsByDate.tsx index 34d32f316..1f7e11242 100644 --- a/frontend/src/components/stats/NewContractsByDate.tsx +++ b/frontend/src/components/stats/NewContractsByDate.tsx @@ -8,15 +8,15 @@ import { Tabs, Tab } from "react-bootstrap"; import { TRPCSubscriptionOutput } from "@/common/types/trpc"; import { Props } from "@/frontend/components/stats/TransactionsByDate"; import PaginationSpinner from "@/frontend/components/utils/PaginationSpinner"; -import { useSubscription } from "@/frontend/hooks/use-subscription"; +import { subscriptions } from "@/frontend/hooks/use-subscription"; import { getCumulativeArray } from "@/frontend/libraries/stats"; const getOption = ( title: string, seriesName: string, data: - | TRPCSubscriptionOutput<"contractsHistory">["newContracts"] - | TRPCSubscriptionOutput<"contractsHistory">["uniqueContracts"] + | TRPCSubscriptionOutput<"subscriptions.contractsHistory">["newContracts"] + | TRPCSubscriptionOutput<"subscriptions.contractsHistory">["uniqueContracts"] ) => ({ title: { text: title, @@ -92,7 +92,7 @@ const getOption = ( const NewContractsByDate: React.FC = React.memo(({ chartStyle }) => { const { t } = useTranslation(); - const contractsHistorySub = useSubscription(["contractsHistory"]); + const contractsHistorySub = subscriptions.contractsHistory.useSubscription(); const options = React.useMemo(() => { if (!contractsHistorySub.data) { diff --git a/frontend/src/components/stats/ProtocolConfigInfo.tsx b/frontend/src/components/stats/ProtocolConfigInfo.tsx index 5e31091e0..a86925230 100644 --- a/frontend/src/components/stats/ProtocolConfigInfo.tsx +++ b/frontend/src/components/stats/ProtocolConfigInfo.tsx @@ -11,7 +11,7 @@ import { InfoCardCell as Cell, } from "@/frontend/components/utils/InfoCard"; import { useDateFormat } from "@/frontend/hooks/use-date-format"; -import { useSubscription } from "@/frontend/hooks/use-subscription"; +import { subscriptions } from "@/frontend/hooks/use-subscription"; import * as BI from "@/frontend/libraries/bigint"; import { styled } from "@/frontend/libraries/styles"; @@ -36,15 +36,14 @@ const BalanceSuffix = styled("span", { const ProtocolConfigInfo: React.FC = React.memo(() => { const { t } = useTranslation(); - const epochStartBlockSub = useSubscription(["epochStartBlock"]); - const protocolConfigSub = useSubscription(["protocolConfig"]); + const epochStartBlockSub = subscriptions.epochStartBlock.useSubscription(); + const protocolConfigSub = subscriptions.protocolConfig.useSubscription(); - const genesisConfigSub = useSubscription(["genesisConfig"]); + const genesisConfigSub = subscriptions.genesisConfig.useSubscription(); - const lastAccountsHistorySub = useSubscription([ - "accountsHistory", - { amountOfDays: 1 }, - ]); + const lastAccountsHistorySub = subscriptions.accountsHistory.useSubscription({ + amountOfDays: 1, + }); const lastDateLiveAccountsCount = lastAccountsHistorySub.data?.liveAccounts[0]?.[1]; diff --git a/frontend/src/components/stats/TransactionsByDate.tsx b/frontend/src/components/stats/TransactionsByDate.tsx index a2c20108a..2b0004414 100644 --- a/frontend/src/components/stats/TransactionsByDate.tsx +++ b/frontend/src/components/stats/TransactionsByDate.tsx @@ -6,7 +6,7 @@ import { useTranslation } from "next-i18next"; import { Tabs, Tab } from "react-bootstrap"; import PaginationSpinner from "@/frontend/components/utils/PaginationSpinner"; -import { useSubscription } from "@/frontend/hooks/use-subscription"; +import { subscriptions } from "@/frontend/hooks/use-subscription"; import { getCumulativeArray } from "@/frontend/libraries/stats"; const getOption = ( @@ -93,7 +93,8 @@ export interface Props { const TransactionsByDateChart: React.FC = React.memo( ({ chartStyle }) => { const { t } = useTranslation(); - const transactionsHistorySub = useSubscription(["transactionsHistory"]); + const transactionsHistorySub = + subscriptions.transactionsHistory.useSubscription(); const options = React.useMemo(() => { if (!transactionsHistorySub.data) { diff --git a/frontend/src/components/transactions/ActionGroup.tsx b/frontend/src/components/transactions/ActionGroup.tsx index db17da4a2..efa045017 100644 --- a/frontend/src/components/transactions/ActionGroup.tsx +++ b/frontend/src/components/transactions/ActionGroup.tsx @@ -6,7 +6,7 @@ import ActionRowBlock, { ViewMode, } from "@/frontend/components/transactions/ActionRowBlock"; import ActionsList from "@/frontend/components/transactions/ActionsList"; -import { useSubscription } from "@/frontend/hooks/use-subscription"; +import { subscriptions } from "@/frontend/hooks/use-subscription"; import BatchTransactionIcon from "@/frontend/public/static/images/icon-m-batch.svg"; interface Props { @@ -20,7 +20,7 @@ interface Props { const ActionGroup: React.FC = React.memo( ({ actionGroup, detailsLink, status, viewMode, title, icon }) => { - const latestBlockSub = useSubscription(["latestBlock"]); + const latestBlockSub = subscriptions.latestBlock.useSubscription(); if (!actionGroup?.actions) return null; diff --git a/frontend/src/components/transactions/TransactionDetails.tsx b/frontend/src/components/transactions/TransactionDetails.tsx index c12de857c..3b5f75b7d 100644 --- a/frontend/src/components/transactions/TransactionDetails.tsx +++ b/frontend/src/components/transactions/TransactionDetails.tsx @@ -18,7 +18,7 @@ import CopyToClipboard from "@/frontend/components/utils/CopyToClipboard"; import Gas from "@/frontend/components/utils/Gas"; import Term from "@/frontend/components/utils/Term"; import { useDateFormat } from "@/frontend/hooks/use-date-format"; -import { useSubscription } from "@/frontend/hooks/use-subscription"; +import { subscriptions } from "@/frontend/hooks/use-subscription"; import * as BI from "@/frontend/libraries/bigint"; import { styled } from "@/frontend/libraries/styles"; @@ -134,7 +134,7 @@ const TransactionDetails: React.FC = React.memo(({ transaction }) => { ); }, [gasUsed, transaction.actions]); - const latestBlockSub = useSubscription(["latestBlock"]); + const latestBlockSub = subscriptions.latestBlock.useSubscription(); const format = useDateFormat(); const isDelegateAction = transaction.actions.length === 1 && diff --git a/frontend/src/components/transactions/Transactions.tsx b/frontend/src/components/transactions/Transactions.tsx index 86f5e2ebd..3c5de24d2 100644 --- a/frontend/src/components/transactions/Transactions.tsx +++ b/frontend/src/components/transactions/Transactions.tsx @@ -1,13 +1,10 @@ import * as React from "react"; +import type * as ReactQuery from "@tanstack/react-query"; import { useTranslation } from "next-i18next"; -import * as ReactQuery from "react-query"; -import { - TransactionPreview, - TransactionListResponse, -} from "@/common/types/procedures"; -import { TRPCError } from "@/common/types/trpc"; +import { TransactionListResponse } from "@/common/types/procedures"; +import { TRPCInfiniteQueryResult } from "@/common/types/trpc"; import TransactionAction from "@/frontend/components/transactions/TransactionAction"; import FlipMove from "@/frontend/components/utils/FlipMove"; import ListHandler from "@/frontend/components/utils/ListHandler"; @@ -20,7 +17,11 @@ export const getNextPageParam: ReactQuery.GetNextPageParamFunction< const parser = (result: TransactionListResponse) => result.items; interface Props { - query: ReactQuery.UseInfiniteQueryResult; + query: TRPCInfiniteQueryResult< + | "transaction.listByAccountId" + | "transaction.listByTimestamp" + | "transaction.listByBlockHash" + >; } const Transactions: React.FC = React.memo(({ query }) => { @@ -31,7 +32,7 @@ const Transactions: React.FC = React.memo(({ query }) => { | "transaction.listByAccountId" | "transaction.listByTimestamp" | "transaction.listByBlockHash", - TransactionPreview + TransactionListResponse["items"][number] > query={query} parser={parser} diff --git a/frontend/src/components/utils/DeployInfo.tsx b/frontend/src/components/utils/DeployInfo.tsx index 00018c3c9..6640c50d8 100644 --- a/frontend/src/components/utils/DeployInfo.tsx +++ b/frontend/src/components/utils/DeployInfo.tsx @@ -59,7 +59,7 @@ export const DeployInfo: React.FC = ({ client }) => { React.useEffect(() => { Gleap.setEnvironment(client.environment); }, [client.environment]); - const { data: server } = trpc.useQuery(["utils.deployInfo"], { + const { data: server } = trpc.utils.deployInfo.useQuery(undefined, { enabled: expanded, }); let content: React.ReactNode = "◍"; diff --git a/frontend/src/components/utils/FlipMove.tsx b/frontend/src/components/utils/FlipMove.tsx index 7ea6f9eb7..a93706861 100644 --- a/frontend/src/components/utils/FlipMove.tsx +++ b/frontend/src/components/utils/FlipMove.tsx @@ -8,11 +8,13 @@ export interface Props { children?: React.ReactNode; } +const FixedFlipMove = FlipMove as unknown as React.FC; + const FlipMoveEx: React.FC = React.memo(({ children, ...props }) => { if (typeof document === "undefined" || document.hidden) { return
{children}
; } - return {children}; + return {children}; }); export default FlipMoveEx; diff --git a/frontend/src/components/utils/ListHandler.tsx b/frontend/src/components/utils/ListHandler.tsx index e8d3f6c19..036a05132 100644 --- a/frontend/src/components/utils/ListHandler.tsx +++ b/frontend/src/components/utils/ListHandler.tsx @@ -3,6 +3,7 @@ import * as React from "react"; import { useTranslation } from "next-i18next"; import InfiniteScroll from "react-infinite-scroll-component"; +import { Unpacked } from "@/common/types/common"; import { TRPCInfiniteQueryKey, TRPCInfiniteQueryOutput, @@ -38,7 +39,10 @@ const LoadButton = styled("button", { }, }); -export type Props = { +export type Props< + K extends TRPCInfiniteQueryKey, + T = Unpacked> +> = { query: TRPCInfiniteQueryResult; parser: (input: TRPCInfiniteQueryOutput) => T[]; children: (items: T[]) => React.ReactNode; @@ -46,7 +50,7 @@ export type Props = { }; const ListHandler = typedMemo( - ({ + >>({ query, parser, children, diff --git a/frontend/src/components/utils/LongCardCell.tsx b/frontend/src/components/utils/LongCardCell.tsx index 8e601cabd..22082302e 100644 --- a/frontend/src/components/utils/LongCardCell.tsx +++ b/frontend/src/components/utils/LongCardCell.tsx @@ -82,8 +82,7 @@ const LongCardCell = typedMemo( className="ml-auto align-self-center" css={textCss} > - {subscription.status === "loading" || - subscription.status === "idle" ? ( + {subscription.status === "loading" ? ( ) : subscription.status === "success" ? ( children(subscription.data) diff --git a/frontend/src/components/utils/Search.tsx b/frontend/src/components/utils/Search.tsx index 5f6b2c5ad..79fa0f9d4 100644 --- a/frontend/src/components/utils/Search.tsx +++ b/frontend/src/components/utils/Search.tsx @@ -250,7 +250,7 @@ const Search: React.FC = React.memo(({ dashboard }) => { // eslint-disable-next-line react-hooks/exhaustive-deps }, [inputValue]); - const searchMutation = trpc.useMutation("utils.search", { + const searchMutation = trpc.utils.search.useMutation({ onSuccess: (result) => { const page = getRedirectPage(result); if (!page) { diff --git a/frontend/src/components/utils/ServiceStatus.tsx b/frontend/src/components/utils/ServiceStatus.tsx index 0284948b1..479d52f78 100644 --- a/frontend/src/components/utils/ServiceStatus.tsx +++ b/frontend/src/components/utils/ServiceStatus.tsx @@ -8,7 +8,7 @@ import Timer from "@/frontend/components/utils/Timer"; import { usePrevious } from "@/frontend/hooks/use-previous"; import { UseSubscriptionResult, - useSubscription, + subscriptions, } from "@/frontend/hooks/use-subscription"; import { styled } from "@/frontend/libraries/styles"; import { MINUTE, SECOND } from "@/frontend/libraries/time"; @@ -180,8 +180,8 @@ const getStatusWithMessage = ( }; export const ServiceStatusView: React.FC = () => { - const rpcStatusSub = useSubscription(["rpcStatus"]); - const indexerStatusSub = useSubscription(["indexerStatus"]); + const rpcStatusSub = subscriptions.rpcStatus.useSubscription(); + const indexerStatusSub = subscriptions.indexerStatus.useSubscription(); const status = getStatusWithMessage(rpcStatusSub, indexerStatusSub); const previousStatus = usePrevious(status); diff --git a/frontend/src/hooks/use-subscription.ts b/frontend/src/hooks/use-subscription.ts index 90ad10bf7..8d09bdbcd 100644 --- a/frontend/src/hooks/use-subscription.ts +++ b/frontend/src/hooks/use-subscription.ts @@ -1,16 +1,20 @@ import * as React from "react"; -import * as ReactQuery from "react-query"; +import * as ReactQuery from "@tanstack/react-query"; +import { createRecursiveProxy } from "@trpc/server/shared"; import { StableOmit } from "@/common/types/common"; import { TRPCError, - TRPCSubscriptionInputs, + TRPCSubscriptionInput, TRPCSubscriptionKey, TRPCSubscriptionOutput, } from "@/common/types/trpc"; import { noop } from "@/common/utils/utils"; -import { subscribe } from "@/frontend/libraries/subscriptions"; +import { + TRPCShortSubscriptionKey, + getSubscriber, +} from "@/frontend/libraries/subscriptions"; import { trpc } from "@/frontend/libraries/trpc"; export type UseSubscriptionResult = StableOmit< @@ -30,37 +34,46 @@ export type UseSubscriptionResult = StableOmit< refetch: () => void; }; +type SubscriptionOpts = { + enabled?: boolean; +}; + export type UseSubscriptionResultByTopic< TPath extends TRPCSubscriptionKey & string > = UseSubscriptionResult>; -const useSubscriptionClient = ( - pathAndInput: [path: TPath, ...args: TRPCSubscriptionInputs], - opts?: { - enabled?: boolean; - } -): UseSubscriptionResultByTopic => { +const useSubscriptionClient = ( + key: K, + input: TRPCSubscriptionInput<`subscriptions.${K}`>, + opts?: SubscriptionOpts +): UseSubscriptionResultByTopic<`subscriptions.${K}`> => { const enabled = opts?.enabled ?? true; - const queryKey = ReactQuery.hashQueryKey(pathAndInput); const trpcContext = trpc.useContext(); + const cachedInput = JSON.stringify(input); // We're getting prefetched and dehydrated data from query (see above) - const cachedData = trpcContext.getQueryData( - pathAndInput as any - ) as TRPCSubscriptionOutput; + const getCachedData = React.useCallback( + () => + trpcContext.queries[key].getData(input as undefined) as + | TRPCSubscriptionOutput<`subscriptions.${K}`> + | undefined, + // We don't want to pass raw input here, because it's not usually memoized outside + // eslint-disable-next-line react-hooks/exhaustive-deps + [trpcContext, key, cachedInput] + ); const [value, setValue] = React.useState< - TRPCSubscriptionOutput | undefined - >(() => cachedData); + TRPCSubscriptionOutput<`subscriptions.${K}`> | undefined + >(getCachedData); const [dataUpdatedAt, setDataUpdatedAt] = React.useState(0); const [errorUpdatedAt, setErrorUpdatedAt] = React.useState(0); - const [loading, setLoading] = React.useState(() => !cachedData); + const [loading, setLoading] = React.useState(() => !getCachedData()); const [error, setError] = React.useState(null); const [resubscribe, setResubscribe] = React.useState<() => void>(); React.useEffect(() => { if (!enabled) { return; } - const subscribeResult = subscribe(trpcContext.client, pathAndInput, [ + const subscribeResult = getSubscriber(trpcContext, key, input, [ (nextValue) => { setLoading(false); setError(null); @@ -76,12 +89,17 @@ const useSubscriptionClient = ( subscribeResult.subscribe(); setResubscribe(() => subscribeResult.resubscribe); return subscribeResult.unsubscribe; - // queryKey substitutes pathAndInput here + // We don't want to pass raw input here, because it's not usually memoized outside + // Also, trpcContext is changed every render (TODO: create an issue in trpc repo) // eslint-disable-next-line react-hooks/exhaustive-deps - }, [queryKey, enabled, trpcContext.client, setResubscribe]); + }, [key, cachedInput, enabled, setResubscribe]); const base = { dataUpdatedAt, errorUpdatedAt, + fetchStatus: "idle" as const, + failureReason: null, + isInitialLoading: false, + isPaused: false, refetch: resubscribe || noop, }; if (loading) { @@ -90,12 +108,13 @@ const useSubscriptionClient = ( data: undefined, error: null, isError: false, - isIdle: false, isLoading: true, isLoadingError: false, isRefetchError: false, isSuccess: false, + isInitialLoading: true, status: "loading", + fetchStatus: "fetching", }; } if (error !== null) { @@ -105,7 +124,6 @@ const useSubscriptionClient = ( data: value, error, isError: true, - isIdle: false, isLoading: false, isLoadingError: false, isRefetchError: true, @@ -118,7 +136,6 @@ const useSubscriptionClient = ( data: undefined, error, isError: true, - isIdle: false, isLoading: false, isLoadingError: true, isRefetchError: false, @@ -126,13 +143,12 @@ const useSubscriptionClient = ( status: "error", }; } - if (value !== undefined) { + if (value) { return { ...base, data: value, error: null, isError: false, - isIdle: false, isLoading: false, isLoadingError: false, isRefetchError: false, @@ -140,31 +156,35 @@ const useSubscriptionClient = ( status: "success", }; } - return { - ...base, - data: undefined, - error: null, - isError: false, - isIdle: true, - isLoading: false, - isLoadingError: false, - isRefetchError: false, - isSuccess: false, - status: "idle", - }; + throw new Error("Unexpected state!"); }; -export const useSubscription = ( - pathAndInput: [path: TPath, ...args: TRPCSubscriptionInputs], - opts: { - enabled?: boolean; - } = {} -): UseSubscriptionResultByTopic => { +export const subscriptions = createRecursiveProxy(({ path, args }) => { + const key = path[0] as TRPCShortSubscriptionKey; + const input = + args[0] as TRPCSubscriptionInput<`subscriptions.${TRPCShortSubscriptionKey}`>; + const opts = args[1] as SubscriptionOpts; if (typeof window === "undefined") { // A hack to prefetch data from subscriptions for SSR - // @ts-ignore - return trpc.useQuery(pathAndInput, opts); + // @ts-expect-error + return trpc.queries[key].useQuery(input, opts); } - // eslint-disable-next-line react-hooks/rules-of-hooks - return useSubscriptionClient(pathAndInput, opts); + return useSubscriptionClient(key, input, opts); +}) as { + [K in TRPCShortSubscriptionKey]: { + useSubscription: ( + ...[ + input, + opts, + ]: undefined extends TRPCSubscriptionInput<`subscriptions.${K}`> + ? [ + input?: TRPCSubscriptionInput<`subscriptions.${K}`>, + opts?: SubscriptionOpts + ] + : [ + input: TRPCSubscriptionInput<`subscriptions.${K}`>, + opts?: SubscriptionOpts + ] + ) => UseSubscriptionResultByTopic<`subscriptions.${K}`>; + }; }; diff --git a/frontend/src/libraries/subscriptions.ts b/frontend/src/libraries/subscriptions.ts index d02550b11..1cc593a12 100644 --- a/frontend/src/libraries/subscriptions.ts +++ b/frontend/src/libraries/subscriptions.ts @@ -1,85 +1,110 @@ -import * as ReactQuery from "react-query"; +import { CreateTRPCProxyClient, getQueryKey } from "@trpc/react-query"; +import type { Unsubscribable } from "@trpc/server/observable"; import { + AppRouter, TRPCClient, TRPCError, - TRPCSubscriptionInputs, + TRPCSubscriptionInput, TRPCSubscriptionKey, TRPCSubscriptionOutput, } from "@/common/types/trpc"; +import { trpc } from "@/frontend/libraries/trpc"; -type ListenerTuple = [ - (nextValue: TRPCSubscriptionOutput) => void, +type TRPCContextLike = { + client: CreateTRPCProxyClient; +}; + +export type TRPCShortSubscriptionKey< + Topic extends TRPCSubscriptionKey = TRPCSubscriptionKey +> = Topic extends `subscriptions.${infer LocalKey}` + ? LocalKey extends keyof TRPCClient["queries"] + ? LocalKey + : never + : never; + +type ListenerTuple< + K extends TRPCShortSubscriptionKey = TRPCShortSubscriptionKey +> = [ + (nextValue: TRPCSubscriptionOutput<`subscriptions.${K}`>) => void, (error: TRPCError) => void ]; -type SubscriptionCache = { - listeners: ListenerTuple[]; - lastValue?: TRPCSubscriptionOutput; - unsubscribe?: () => void; +type SubscriptionCache< + K extends TRPCShortSubscriptionKey = TRPCShortSubscriptionKey +> = { + listeners: ListenerTuple[]; + lastValue?: TRPCSubscriptionOutput<`subscriptions.${K}`>; + subscription?: Unsubscribable; }; const subscriptionCache: Partial< - Record> + Record> > = {}; -const createSubscription = ( - cache: SubscriptionCache, - trpcClient: TRPCClient, - pathAndInput: [path: Topic, ...args: TRPCSubscriptionInputs] -): (() => void) => { - const [path, input] = pathAndInput; - return trpcClient.subscription(path, (input ?? undefined) as any, { - onError: (err) => { - cache.listeners.forEach(([, errorListener]) => errorListener(err)); - }, - onNext: (res) => { - if (res.type !== "data") { - return; - } - const typedValue = res.data as TRPCSubscriptionOutput; - cache.lastValue = typedValue; - cache.listeners.forEach(([valueListener]) => valueListener(typedValue)); - }, - }); -}; +const createSubscription = ( + cache: SubscriptionCache, + trpcContext: TRPCContextLike, + key: Key, + input: TRPCSubscriptionInput<`subscriptions.${Key}`> +): Unsubscribable => + ( + trpcContext.client.subscriptions[ + key + // An example of a subscription to get valid types on callbacks + ] as TRPCContextLike["client"]["subscriptions"]["validatorTelemetry"] + ) + // @ts-expect-error + .subscribe(input, { + onError: (err) => { + cache.listeners.forEach(([, errorListener]) => errorListener(err)); + }, + onData: (data) => { + const typedValue = + data as TRPCSubscriptionOutput<`subscriptions.${Key}`>; + cache.lastValue = typedValue; + cache.listeners.forEach(([valueListener]) => valueListener(typedValue)); + }, + }); -const removeSubscription = ( - cache: SubscriptionCache +const removeSubscription = ( + cache: SubscriptionCache ) => { - if (!cache.unsubscribe) { + if (!cache.subscription) { return; } - cache.unsubscribe(); - cache.unsubscribe = undefined; + cache.subscription.unsubscribe(); + cache.subscription = undefined; }; -const removeListeners = ( - cache: SubscriptionCache, - subscribeFns: ListenerTuple +const removeListeners = ( + cache: SubscriptionCache, + subscribeFns: ListenerTuple ) => { cache.listeners = cache.listeners.filter( (listeners) => listeners !== subscribeFns ); }; -const addListeners = ( - cache: SubscriptionCache, - subscribeFns: ListenerTuple +const addListeners = ( + cache: SubscriptionCache, + subscribeFns: ListenerTuple ) => { cache.listeners.push(subscribeFns); }; -const getWithCache = ( - pathAndInput: [path: Topic, ...args: TRPCSubscriptionInputs] +const getWithCache = ( + key: Key, + input: TRPCSubscriptionInput<`subscriptions.${Key}`> ) => { - const queryKey = ReactQuery.hashQueryKey(pathAndInput); + // @ts-expect-error + const cacheKey = getQueryKey(trpc.queries[key], input).join(","); return ( - fn: (cache: SubscriptionCache) => void, + fn: (cache: SubscriptionCache) => void, fnName: string, createCache = false ) => { - let cache = subscriptionCache[queryKey] as - | SubscriptionCache + let cache = subscriptionCache[cacheKey] as + | SubscriptionCache | undefined; if (!cache) { if (!createCache) { @@ -88,17 +113,19 @@ const getWithCache = ( return; } cache = { listeners: [] }; - subscriptionCache[queryKey] = cache; + // @ts-expect-error + subscriptionCache[cacheKey] = cache; } return fn(cache); }; }; -export const subscribe = ( - trpcClient: TRPCClient, - pathAndInput: [path: Topic, ...args: TRPCSubscriptionInputs], - subscribeFns: ListenerTuple +export const getSubscriber = ( + trpcContext: TRPCContextLike, + key: Key, + input: TRPCSubscriptionInput<`subscriptions.${Key}`>, + subscribeFns: ListenerTuple ) => { - const withCache = getWithCache(pathAndInput); + const withCache = getWithCache(key, input); return { subscribe: () => withCache( @@ -106,11 +133,12 @@ export const subscribe = ( if (cache.lastValue !== undefined) { subscribeFns[0](cache.lastValue); } - if (!cache.unsubscribe) { - cache.unsubscribe = createSubscription( + if (!cache.subscription) { + cache.subscription = createSubscription( cache, - trpcClient, - pathAndInput + trpcContext, + key, + input ); } addListeners(cache, subscribeFns); @@ -128,7 +156,7 @@ export const subscribe = ( resubscribe: () => withCache((cache) => { removeSubscription(cache); - cache.unsubscribe = createSubscription(cache, trpcClient, pathAndInput); + cache.subscription = createSubscription(cache, trpcContext, key, input); }, "resubscribe"), }; }; diff --git a/frontend/src/libraries/trpc.ts b/frontend/src/libraries/trpc.ts index 251c987d3..3d7b605ee 100644 --- a/frontend/src/libraries/trpc.ts +++ b/frontend/src/libraries/trpc.ts @@ -1,12 +1,40 @@ -import * as trpcReact from "@trpc/react"; +import * as trpcClient from "@trpc/client"; +import * as trpcReact from "@trpc/react-query"; import { NetworkName } from "@/common/types/common"; import type { AppRouter } from "@/common/types/trpc"; import { getBackendUrl } from "@/frontend/libraries/transport"; -export const trpc = trpcReact.createReactQueryHooks(); +export const trpc = trpcReact.createTRPCReact(); + +export const getLinks = ( + endpointUrl: string, + wsUrl: string +): trpcClient.TRPCLink[] => { + if (typeof window === "undefined") { + return [ + trpcClient.httpBatchLink({ + url: endpointUrl, + }), + ]; + } + return [ + trpcClient.splitLink({ + condition: (op) => op.type === "subscription", + true: trpcClient.wsLink({ + client: trpcClient.createWSClient({ url: wsUrl }), + }), + false: trpcClient.httpBatchLink({ + url: endpointUrl, + }), + }), + ]; +}; export const getTrpcClient = (networkName: NetworkName) => - trpc.createClient({ - url: getBackendUrl(networkName, "http", typeof window === "undefined"), + trpcReact.createTRPCProxyClient({ + links: getLinks( + getBackendUrl(networkName, "http", true), + getBackendUrl(networkName, "websocket", true) + ), }); diff --git a/frontend/src/pages/_app.tsx b/frontend/src/pages/_app.tsx index 465f3a2b7..723da216d 100644 --- a/frontend/src/pages/_app.tsx +++ b/frontend/src/pages/_app.tsx @@ -1,19 +1,19 @@ import "@/frontend/libraries/wdyr"; import * as React from "react"; -import { TRPCLink } from "@trpc/client"; -import { httpBatchLink } from "@trpc/client/links/httpBatchLink"; -import { splitLink } from "@trpc/client/links/splitLink"; -import { wsLink, createWSClient } from "@trpc/client/links/wsLink"; +import { ReactQueryDevtools } from "@tanstack/react-query-devtools"; import { withTRPC } from "@trpc/next"; import Gleap from "gleap"; import { NextPage } from "next"; import { AppProps } from "next/app"; -import { AppPropsType, AppType } from "next/dist/shared/lib/utils"; +import { + AppPropsType, + AppType, + NextPageContext, +} from "next/dist/shared/lib/utils"; import Head from "next/head"; import { NextRouter, useRouter } from "next/router"; import { appWithTranslation, SSRConfig } from "next-i18next"; -import { ReactQueryDevtools } from "react-query/devtools"; import type { AppRouter } from "@/backend/router"; import { NetworkName } from "@/common/types/common"; @@ -60,6 +60,7 @@ import { import { globalCss, styled } from "@/frontend/libraries/styles"; import { MINUTE, YEAR } from "@/frontend/libraries/time"; import { getBackendUrl } from "@/frontend/libraries/transport"; +import { getLinks } from "@/frontend/libraries/trpc"; const globalStyles = globalCss({ body: { @@ -356,33 +357,7 @@ App.getInitialProps = async (appContext) => { }; }; -const getLinks = ( - endpointUrl: string, - wsUrl: string -): TRPCLink[] => { - if (typeof window === "undefined") { - return [ - httpBatchLink({ - url: endpointUrl, - }), - ]; - } - return [ - splitLink({ - condition: (op) => op.type === "subscription", - true: wsLink({ - client: createWSClient({ - url: wsUrl, - }), - }), - false: httpBatchLink({ - url: endpointUrl, - }), - }), - ]; -}; - -export default withTRPC({ +export default withTRPC({ config: (info) => { let networkName = "props" in info diff --git a/frontend/src/pages/accounts/[...slug].tsx b/frontend/src/pages/accounts/[...slug].tsx index 18dccd804..c3e40a5e3 100644 --- a/frontend/src/pages/accounts/[...slug].tsx +++ b/frontend/src/pages/accounts/[...slug].tsx @@ -36,11 +36,8 @@ type TransactionProps = { }; const AccountTransactions = React.memo(({ accountId }) => { - const transactionsQuery = trpc.useInfiniteQuery( - [ - "transaction.listByAccountId", - { accountId, limit: TRANSACTIONS_PER_PAGE }, - ], + const transactionsQuery = trpc.transaction.listByAccountId.useInfiniteQuery( + { accountId, limit: TRANSACTIONS_PER_PAGE }, { getNextPageParam } ); return ; @@ -54,7 +51,6 @@ const InnerAccountDetail = React.memo(({ query }) => { const { t } = useTranslation(); switch (query.status) { case "loading": - case "idle": return ; case "success": if (!query.data) { @@ -88,7 +84,7 @@ const AccountDetail = React.memo(() => { useAnalyticsTrackOnMount("Explorer View Individual Account", { accountId, }); - const accountQuery = trpc.useQuery(["account.byIdOld", { id: accountId }]); + const accountQuery = trpc.account.byIdOld.useQuery({ id: accountId }); return ( <> diff --git a/frontend/src/pages/api/circulating-supply-in-near.ts b/frontend/src/pages/api/circulating-supply-in-near.ts index 679273d0d..31daccba1 100644 --- a/frontend/src/pages/api/circulating-supply-in-near.ts +++ b/frontend/src/pages/api/circulating-supply-in-near.ts @@ -19,9 +19,9 @@ const handler: NextApiHandler = async (req, res) => { } try { - const latestCirculatingSupply = await getTrpcClient(networkName).query( - "stats.latestCirculatingSupply" - ); + const latestCirculatingSupply = await getTrpcClient( + networkName + ).stats.latestCirculatingSupply.query(); const supplyInYoctoNEAR = latestCirculatingSupply.supply; res.send(supplyInYoctoNEAR.substr(0, supplyInYoctoNEAR.length - 24)); } catch (error) { diff --git a/frontend/src/pages/api/circulating-supply.ts b/frontend/src/pages/api/circulating-supply.ts index c2770867c..e97dae3d7 100644 --- a/frontend/src/pages/api/circulating-supply.ts +++ b/frontend/src/pages/api/circulating-supply.ts @@ -19,9 +19,9 @@ const handler: NextApiHandler = async (req, res) => { } try { - const response = await getTrpcClient(networkName).query( - "stats.latestCirculatingSupply" - ); + const response = await getTrpcClient( + networkName + ).stats.latestCirculatingSupply.query(); res.send({ timestamp: response.timestamp, circulating_supply_in_yoctonear: response.supply, diff --git a/frontend/src/pages/api/fees-of-previous-7-days-utc.ts b/frontend/src/pages/api/fees-of-previous-7-days-utc.ts index 38803270b..e2531dc49 100644 --- a/frontend/src/pages/api/fees-of-previous-7-days-utc.ts +++ b/frontend/src/pages/api/fees-of-previous-7-days-utc.ts @@ -17,10 +17,9 @@ const handler: NextApiHandler = async (req, res) => { const resp = []; for (let i = 1; i <= 7; i += 1) { // eslint-disable-next-line no-await-in-loop - const tokensBurntPerDay = await getTrpcClient(networkName).query( - "stats.tokensBurnt", - { daysFromNow: i } - ); + const tokensBurntPerDay = await getTrpcClient( + networkName + ).stats.tokensBurnt.query({ daysFromNow: i }); if (!tokensBurntPerDay) { res.status(500).end(); return; diff --git a/frontend/src/pages/api/fees-of-previous-day-utc.ts b/frontend/src/pages/api/fees-of-previous-day-utc.ts index 72ed34f27..83bd15a3a 100644 --- a/frontend/src/pages/api/fees-of-previous-day-utc.ts +++ b/frontend/src/pages/api/fees-of-previous-day-utc.ts @@ -14,10 +14,9 @@ const handler: NextApiHandler = async (req, res) => { if (isNetworkOffline(networkName)) { return respondNetworkOffline(res, networkName); } - const feeCountPerDay = await getTrpcClient(networkName).query( - "stats.tokensBurnt", - { daysFromNow: 1 } - ); + const feeCountPerDay = await getTrpcClient( + networkName + ).stats.tokensBurnt.query({ daysFromNow: 1 }); if (!feeCountPerDay) { res.status(500).end(); return; diff --git a/frontend/src/pages/api/metrics/indexer.ts b/frontend/src/pages/api/metrics/indexer.ts index 472ff5551..c97ce4831 100644 --- a/frontend/src/pages/api/metrics/indexer.ts +++ b/frontend/src/pages/api/metrics/indexer.ts @@ -15,10 +15,10 @@ const handler: NextApiHandler = async (req, res) => { return respondNetworkOffline(res, networkName); } const trpcClient = getTrpcClient(networkName); - const rpcFinalBlock = await trpcClient.query("block.final", { + const rpcFinalBlock = await trpcClient.block.final.query({ source: "rpc", }); - const indexerFinalBlock = await trpcClient.query("block.final", { + const indexerFinalBlock = await trpcClient.block.final.query({ source: "indexer", }); diff --git a/frontend/src/pages/api/nodes.ts b/frontend/src/pages/api/nodes.ts index c55e998db..03256b986 100644 --- a/frontend/src/pages/api/nodes.ts +++ b/frontend/src/pages/api/nodes.ts @@ -19,7 +19,7 @@ const handler: NextApiHandler = async (req, res) => { return respondNetworkOffline(res, networkName); } - await getTrpcClient(networkName).mutation("telemetry.upsert", { + await getTrpcClient(networkName).telemetry.upsert.mutate({ ...req.body, ipAddress, }); diff --git a/frontend/src/pages/api/status.ts b/frontend/src/pages/api/status.ts index 1267d713d..ae9bd53fe 100644 --- a/frontend/src/pages/api/status.ts +++ b/frontend/src/pages/api/status.ts @@ -13,7 +13,7 @@ const handler: NextApiHandler = async (req, res) => { if (isNetworkOffline(networkName)) { return respondNetworkOffline(res, networkName); } - await getTrpcClient(networkName).query("utils.protocolVersion"); + await getTrpcClient(networkName).utils.protocolVersion.query(); } catch (error) { res.status(502).send(error); return; diff --git a/frontend/src/pages/beta/accounts/[...slug].tsx b/frontend/src/pages/beta/accounts/[...slug].tsx index 908c23f89..8c1b435b0 100644 --- a/frontend/src/pages/beta/accounts/[...slug].tsx +++ b/frontend/src/pages/beta/accounts/[...slug].tsx @@ -62,10 +62,7 @@ const AccountPage: NextPage = React.memo(() => { useAnalyticsTrackOnMount("Explorer Beta | Account Page", { accountId: options.accountId, }); - const accountQuery = trpc.useQuery([ - "account.byId", - { id: options.accountId }, - ]); + const accountQuery = trpc.account.byId.useQuery({ id: options.accountId }); return ( <> diff --git a/frontend/src/pages/beta/fungible-tokens/index.tsx b/frontend/src/pages/beta/fungible-tokens/index.tsx index 3857312fe..bf6087083 100644 --- a/frontend/src/pages/beta/fungible-tokens/index.tsx +++ b/frontend/src/pages/beta/fungible-tokens/index.tsx @@ -4,7 +4,6 @@ import { NextPage } from "next"; import Head from "next/head"; import { Spinner } from "react-bootstrap"; -import { FungibleTokenItem } from "@/common/types/procedures"; import { id } from "@/common/utils/utils"; import Content from "@/frontend/components/utils/Content"; import ErrorMessage from "@/frontend/components/utils/ErrorMessage"; @@ -47,9 +46,9 @@ const EMPTY_IMAGE = "data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAEAAAABCAQAAAC1HAwCAAAAC0lEQVR42mNkqAcAAIUAgUW0RjgAAAAASUVORK5CYII="; const FungibleTokens: NextPage = React.memo(() => { - const tokensAmountQuery = trpc.useQuery(["fungibleTokens.amount"]); - const fungibleTokensQuery = trpc.useInfiniteQuery( - ["fungibleTokens.list", { limit: FUNGIBLE_TOKENS_PER_PAGE }], + const tokensAmountQuery = trpc.fungibleTokens.amount.useQuery(); + const fungibleTokensQuery = trpc.fungibleTokens.list.useInfiniteQuery( + { limit: FUNGIBLE_TOKENS_PER_PAGE }, { getNextPageParam: (lastPage, allPages) => { if (lastPage.length !== FUNGIBLE_TOKENS_PER_PAGE) { @@ -67,8 +66,7 @@ const FungibleTokens: NextPage = React.memo(() => { Fungible tokens}>
- {tokensAmountQuery.status === "loading" || - tokensAmountQuery.status === "idle" ? ( + {tokensAmountQuery.status === "loading" ? ( ) : tokensAmountQuery.status === "error" ? ( @@ -78,7 +76,7 @@ const FungibleTokens: NextPage = React.memo(() => { `Total of ${tokensAmountQuery.data} fungible tokens registered` )}
- + query={fungibleTokensQuery} parser={id} > diff --git a/frontend/src/pages/beta/transactions/[hash].tsx b/frontend/src/pages/beta/transactions/[hash].tsx index ad7e13af4..20a452c1e 100644 --- a/frontend/src/pages/beta/transactions/[hash].tsx +++ b/frontend/src/pages/beta/transactions/[hash].tsx @@ -34,7 +34,6 @@ const TransactionQueryView: React.FC = React.memo(({ query }) => { case "error": return <>{query.error.message}; case "loading": - case "idle": return ; } }); @@ -51,7 +50,7 @@ const TransactionPage: NextPage = React.memo(() => { transaction_hash: hash, }); - const transactionQuery = trpc.useQuery(["transaction.byHash", { hash }]); + const transactionQuery = trpc.transaction.byHash.useQuery({ hash }); return ( <> diff --git a/frontend/src/pages/blocks/[hash].tsx b/frontend/src/pages/blocks/[hash].tsx index 1f7b975b4..d0ee7aa9f 100644 --- a/frontend/src/pages/blocks/[hash].tsx +++ b/frontend/src/pages/blocks/[hash].tsx @@ -33,12 +33,9 @@ const BlockDetail = React.memo<{ hash: string }>(({ hash }) => { useAnalyticsTrackOnMount("Explorer View Individual Block", { block: hash, }); - const blockQuery = trpc.useQuery(["block.byId", { hash }]); - const query = trpc.useInfiniteQuery( - [ - "transaction.listByBlockHash", - { blockHash: hash, limit: TRANSACTIONS_PER_PAGE }, - ], + const blockQuery = trpc.block.byId.useQuery({ hash }); + const query = trpc.transaction.listByBlockHash.useInfiniteQuery( + { blockHash: hash, limit: TRANSACTIONS_PER_PAGE }, { getNextPageParam } ); @@ -57,7 +54,7 @@ const BlockDetail = React.memo<{ hash: string }>(({ hash }) => { } border={false} > - {blockQuery.status === "loading" || blockQuery.status === "idle" ? ( + {blockQuery.status === "loading" ? ( t("page.blocks.error.block_fetching") ) : blockQuery.status === "error" ? ( @@ -120,7 +117,7 @@ export const getServerSideProps: GetServerSideProps< context.query, context.req.headers.host ); - const block = await getTrpcClient(networkName).query("block.byId", { + const block = await getTrpcClient(networkName).block.byId.query({ height: Number(hashOrHeight), }); if (!block) { diff --git a/frontend/src/pages/index.tsx b/frontend/src/pages/index.tsx index ab1211da5..916fd8f35 100644 --- a/frontend/src/pages/index.tsx +++ b/frontend/src/pages/index.tsx @@ -103,7 +103,7 @@ export const getServerSideProps: GetServerSideProps = async ({ const searchQueryValue = Array.isArray(searchQuery) ? searchQuery[0] : searchQuery; - const searchResult = await trpcClient.mutation("utils.search", { + const searchResult = await trpcClient.utils.search.mutate({ value: searchQueryValue.replace(/\s/g, ""), }); const redirectPage = getRedirectPage(searchResult); diff --git a/frontend/src/pages/receipts/[id].tsx b/frontend/src/pages/receipts/[id].tsx index 1ca1b3c53..0ab54b180 100644 --- a/frontend/src/pages/receipts/[id].tsx +++ b/frontend/src/pages/receipts/[id].tsx @@ -41,10 +41,9 @@ export const getServerSideProps: GetServerSideProps< return { props: {} }; } const networkName = getNearNetworkName(query, req.headers.host); - const transactionHash = await getTrpcClient(networkName).query( - "receipt.getTransactionHash", - { id: receiptId } - ); + const transactionHash = await getTrpcClient( + networkName + ).receipt.getTransactionHash.query({ id: receiptId }); if (!transactionHash) { return { props: {} }; } diff --git a/frontend/src/pages/transactions/[hash].tsx b/frontend/src/pages/transactions/[hash].tsx index ada5a23f6..e76c6f5c7 100644 --- a/frontend/src/pages/transactions/[hash].tsx +++ b/frontend/src/pages/transactions/[hash].tsx @@ -28,7 +28,7 @@ const TransactionDetailsPage = React.memo(() => { useAnalyticsTrackOnMount("Explorer View Individual Transaction Page", { transaction_hash: hash, }); - const transactionQuery = trpc.useQuery(["transaction.byHashOld", { hash }]); + const transactionQuery = trpc.transaction.byHashOld.useQuery({ hash }); return ( <> @@ -44,8 +44,7 @@ const TransactionDetailsPage = React.memo(() => { } border={false} > - {transactionQuery.status === "loading" || - transactionQuery.status === "idle" ? ( + {transactionQuery.status === "loading" ? ( t("page.transactions.error.transaction_fetching") ) : transactionQuery.status === "error" ? ( diff --git a/frontend/src/pages/transactions/index.tsx b/frontend/src/pages/transactions/index.tsx index 5c765ceb2..79701662c 100644 --- a/frontend/src/pages/transactions/index.tsx +++ b/frontend/src/pages/transactions/index.tsx @@ -16,8 +16,8 @@ const TRANSACTIONS_PER_PAGE = 15; const TransactionsPage: NextPage = React.memo(() => { const { t } = useTranslation(); useAnalyticsTrackOnMount("Explorer View Transactions Page"); - const query = trpc.useInfiniteQuery( - ["transaction.listByTimestamp", { limit: TRANSACTIONS_PER_PAGE }], + const query = trpc.transaction.listByTimestamp.useInfiniteQuery( + { limit: TRANSACTIONS_PER_PAGE }, { getNextPageParam } ); diff --git a/frontend/src/testing/utils.tsx b/frontend/src/testing/utils.tsx index 64403691a..8c5ee06c2 100644 --- a/frontend/src/testing/utils.tsx +++ b/frontend/src/testing/utils.tsx @@ -1,10 +1,11 @@ import * as React from "react"; +import * as ReactQuery from "@tanstack/react-query"; +import { httpLink } from "@trpc/client"; import fetch from "isomorphic-fetch"; import { RouterContext } from "next/dist/shared/lib/router-context"; import { NextRouter } from "next/router"; import { setI18n } from "react-i18next"; -import * as ReactQuery from "react-query"; import renderer, { ReactTestRenderer, TestRendererOptions, @@ -59,8 +60,7 @@ export const renderElement = ( let root: ReactTestRenderer; const queryClient = new ReactQuery.QueryClient(); const client = trpc.createClient({ - url: "http://localhost/", - fetch, + links: [httpLink({ url: "http://localhost/", fetch })], }); setCachedDateLocale("cimode", global.cachedLocale); renderer.act(() => { diff --git a/package-lock.json b/package-lock.json index 0407fffe3..158605611 100644 --- a/package-lock.json +++ b/package-lock.json @@ -47,7 +47,7 @@ "version": "0.0.1", "license": "Apache-2.0", "dependencies": { - "@trpc/server": "^9.27.4", + "@trpc/server": "^10.26.0", "cors": "^2.8.5", "date-fns": "^2.28.0", "dotenv-cli": "^5.0.0", @@ -59,7 +59,6 @@ "near-api-js": "^0.44.1", "pg": "^8.7.3", "ts-node": "^10.4.0", - "tsafe": "^0.10.0", "tsconfig-paths": "^4.1.2", "ws": "^8.6.0", "zod": "^3.16.0", @@ -106,10 +105,10 @@ "lodash": "^4.17.21" }, "devDependencies": { - "@trpc/client": "^9.27.4", - "@trpc/react": "^9.27.4", - "@types/lodash": "^4.14.177", - "react-query": "^3.39.0" + "@tanstack/react-query": "^4.29.7", + "@trpc/client": "^10.26.0", + "@trpc/react-query": "^10.26.0", + "@types/lodash": "^4.14.177" } }, "frontend": { @@ -120,10 +119,13 @@ "dependencies": { "@playwright/test": "^1.32.3", "@stitches/react": "^1.3.1-1", + "@tanstack/react-query": "^4.29.7", + "@tanstack/react-query-devtools": "^4.29.7", "@textea/json-viewer": "^2.16.0", - "@trpc/client": "^9.27.4", - "@trpc/next": "^9.27.4", - "@trpc/react": "^9.27.4", + "@trpc/client": "^10.26.0", + "@trpc/next": "^10.26.0", + "@trpc/react-query": "^10.26.0", + "@trpc/server": "^10.26.0", "@types/analytics-node": "^3.1.9", "analytics-node": "^6.2.0", "bootstrap": "^4.6.1", @@ -158,7 +160,6 @@ "react-image": "^4.0.3", "react-infinite-scroll-component": "^5.1.0", "react-paginate": "^8.1.4", - "react-query": "^3.39.0", "tslib": "^2.3.1", "universal-cookie": "^4.0.4" }, @@ -195,156 +196,21 @@ "webpack-bundle-analyzer": "^4.5.0" } }, - "frontend/node_modules/@next/swc-darwin-arm64": { - "version": "13.3.1", - "resolved": "https://registry.npmjs.org/@next/swc-darwin-arm64/-/swc-darwin-arm64-13.3.1.tgz", - "integrity": "sha512-UXPtriEc/pBP8luSLSCZBcbzPeVv+SSjs9cH/KygTbhmACye8/OOXRZO13Z2Wq1G0gLmEAIHQAOuF+vafPd2lw==", - "cpu": [ - "arm64" - ], - "optional": true, - "os": [ - "darwin" - ], - "engines": { - "node": ">= 10" - } - }, - "frontend/node_modules/@next/swc-darwin-x64": { - "version": "13.3.1", - "resolved": "https://registry.npmjs.org/@next/swc-darwin-x64/-/swc-darwin-x64-13.3.1.tgz", - "integrity": "sha512-lT36yYxosCfLtplFzJWgo0hrPu6/do8+msgM7oQkPeohDNdhjtjFUgOOwdSnPublLR6Mo2Ym4P/wl5OANuD2bw==", - "cpu": [ - "x64" - ], - "optional": true, - "os": [ - "darwin" - ], - "engines": { - "node": ">= 10" - } - }, - "frontend/node_modules/@next/swc-linux-arm64-gnu": { - "version": "13.3.1", - "resolved": "https://registry.npmjs.org/@next/swc-linux-arm64-gnu/-/swc-linux-arm64-gnu-13.3.1.tgz", - "integrity": "sha512-wRb76nLWJhonH8s3kxC/1tFguEkeOPayIwe9mkaz1G/yeS3OrjeyKMJsb4+Kdg0zbTo53bNCOl59NNtDM7yyyw==", - "cpu": [ - "arm64" - ], - "optional": true, - "os": [ - "linux" - ], - "engines": { - "node": ">= 10" - } - }, - "frontend/node_modules/@next/swc-linux-arm64-musl": { - "version": "13.3.1", - "resolved": "https://registry.npmjs.org/@next/swc-linux-arm64-musl/-/swc-linux-arm64-musl-13.3.1.tgz", - "integrity": "sha512-qz3BzjJRZ16Iq/jrp+pjiYOc0jTjHlfmxQmZk9x/+5uhRP6/eWQSTAPVJ33BMo6oK5O5N4644OgTAbzXzorecg==", - "cpu": [ - "arm64" - ], - "optional": true, - "os": [ - "linux" - ], - "engines": { - "node": ">= 10" - } - }, - "frontend/node_modules/@next/swc-linux-x64-gnu": { - "version": "13.3.1", - "resolved": "https://registry.npmjs.org/@next/swc-linux-x64-gnu/-/swc-linux-x64-gnu-13.3.1.tgz", - "integrity": "sha512-6mgkLmwlyWlomQmpl21I3hxgqE5INoW4owTlcLpNsd1V4wP+J46BlI/5zV5KWWbzjfncIqzXoeGs5Eg+1GHODA==", - "cpu": [ - "x64" - ], - "optional": true, - "os": [ - "linux" - ], - "engines": { - "node": ">= 10" - } - }, - "frontend/node_modules/@next/swc-linux-x64-musl": { - "version": "13.3.1", - "resolved": "https://registry.npmjs.org/@next/swc-linux-x64-musl/-/swc-linux-x64-musl-13.3.1.tgz", - "integrity": "sha512-uqm5sielhQmKJM+qayIhgZv1KlS5pqTdQ99b+Z7hMWryXS96qE0DftTmMZowBcUL6x7s2vSXyH5wPtO1ON7LBg==", - "cpu": [ - "x64" - ], - "optional": true, - "os": [ - "linux" - ], - "engines": { - "node": ">= 10" - } - }, - "frontend/node_modules/@next/swc-win32-arm64-msvc": { - "version": "13.3.1", - "resolved": "https://registry.npmjs.org/@next/swc-win32-arm64-msvc/-/swc-win32-arm64-msvc-13.3.1.tgz", - "integrity": "sha512-WomIiTj/v3LevltlibNQKmvrOymNRYL+a0dp5R73IwPWN5FvXWwSELN/kiNALig/+T3luc4qHNTyvMCp9L6U5Q==", - "cpu": [ - "arm64" - ], - "optional": true, - "os": [ - "win32" - ], - "engines": { - "node": ">= 10" - } - }, - "frontend/node_modules/@next/swc-win32-ia32-msvc": { - "version": "13.3.1", - "resolved": "https://registry.npmjs.org/@next/swc-win32-ia32-msvc/-/swc-win32-ia32-msvc-13.3.1.tgz", - "integrity": "sha512-M+PoH+0+q658wRUbs285RIaSTYnGBSTdweH/0CdzDgA6Q4rBM0sQs4DHmO3BPP0ltCO/vViIoyG7ks66XmCA5g==", - "cpu": [ - "ia32" - ], - "optional": true, - "os": [ - "win32" - ], - "engines": { - "node": ">= 10" - } - }, - "frontend/node_modules/@next/swc-win32-x64-msvc": { - "version": "13.3.1", - "resolved": "https://registry.npmjs.org/@next/swc-win32-x64-msvc/-/swc-win32-x64-msvc-13.3.1.tgz", - "integrity": "sha512-Sl1F4Vp5Z1rNXWZYqJwMuWRRol4bqOB6+/d7KqkgQ4AcafKPN1PZmpkCoxv4UFHtFNIB7EotnuIhtXu3zScicQ==", - "cpu": [ - "x64" - ], - "optional": true, - "os": [ - "win32" - ], - "engines": { - "node": ">= 10" - } - }, "frontend/node_modules/@trpc/next": { - "version": "9.27.4", - "license": "MIT", + "version": "10.26.0", + "resolved": "https://registry.npmjs.org/@trpc/next/-/next-10.26.0.tgz", + "integrity": "sha512-p328crXBH6C228LKxjqbpDEXdLmy4+LdgsZuYK3oFMqaJEmCT22b+zcQ9IvQrcPfDxhKOpJym0QpuDNaWpG2qg==", "dependencies": { - "@babel/runtime": "^7.9.0", "react-ssr-prepass": "^1.5.0" }, "peerDependencies": { - "@trpc/client": "9.27.4", - "@trpc/react": "9.27.4", - "@trpc/server": "9.27.4", + "@tanstack/react-query": "^4.18.0", + "@trpc/client": "10.26.0", + "@trpc/react-query": "10.26.0", + "@trpc/server": "10.26.0", "next": "*", "react": ">=16.8.0", - "react-dom": ">=16.8.0", - "react-query": "^3.37.0" + "react-dom": ">=16.8.0" } }, "frontend/node_modules/ava": { @@ -413,62 +279,8 @@ } } }, - "frontend/node_modules/next": { - "version": "13.3.1", - "resolved": "https://registry.npmjs.org/next/-/next-13.3.1.tgz", - "integrity": "sha512-eByWRxPzKHs2oQz1yE41LX35umhz86ZSZ+mYyXBqn2IBi2hyUqxBA88avywdr4uyH+hCJczegGsDGWbzQA5Rqw==", - "dependencies": { - "@next/env": "13.3.1", - "@swc/helpers": "0.5.0", - "busboy": "1.6.0", - "caniuse-lite": "^1.0.30001406", - "postcss": "8.4.14", - "styled-jsx": "5.1.1" - }, - "bin": { - "next": "dist/bin/next" - }, - "engines": { - "node": ">=14.18.0" - }, - "optionalDependencies": { - "@next/swc-darwin-arm64": "13.3.1", - "@next/swc-darwin-x64": "13.3.1", - "@next/swc-linux-arm64-gnu": "13.3.1", - "@next/swc-linux-arm64-musl": "13.3.1", - "@next/swc-linux-x64-gnu": "13.3.1", - "@next/swc-linux-x64-musl": "13.3.1", - "@next/swc-win32-arm64-msvc": "13.3.1", - "@next/swc-win32-ia32-msvc": "13.3.1", - "@next/swc-win32-x64-msvc": "13.3.1" - }, - "peerDependencies": { - "@opentelemetry/api": "^1.1.0", - "fibers": ">= 3.1.0", - "node-sass": "^6.0.0 || ^7.0.0", - "react": "^18.2.0", - "react-dom": "^18.2.0", - "sass": "^1.3.0" - }, - "peerDependenciesMeta": { - "@opentelemetry/api": { - "optional": true - }, - "fibers": { - "optional": true - }, - "node-sass": { - "optional": true - }, - "sass": { - "optional": true - } - } - }, "frontend/node_modules/next-i18next": { "version": "13.2.2", - "resolved": "https://registry.npmjs.org/next-i18next/-/next-i18next-13.2.2.tgz", - "integrity": "sha512-t0WU6K+HJoq2nVQ0n6OiiEZja9GyMqtDSU74FmOafgk4ljns+iZ18bsNJiI8rOUXfFfkW96ea1N7D5kbMyT+PA==", "funding": [ { "type": "individual", @@ -483,6 +295,7 @@ "url": "https://locize.com" } ], + "license": "MIT", "dependencies": { "@babel/runtime": "^7.20.13", "@types/hoist-non-react-statics": "^3.3.1", @@ -509,28 +322,6 @@ "url": "https://opencollective.com/core-js" } }, - "frontend/node_modules/next/node_modules/postcss": { - "version": "8.4.14", - "funding": [ - { - "type": "opencollective", - "url": "https://opencollective.com/postcss/" - }, - { - "type": "tidelift", - "url": "https://tidelift.com/funding/github/npm/postcss" - } - ], - "license": "MIT", - "dependencies": { - "nanoid": "^3.3.4", - "picocolors": "^1.0.0", - "source-map-js": "^1.0.2" - }, - "engines": { - "node": "^10 || ^12 || >=14" - } - }, "frontend/node_modules/postcss": { "version": "8.4.5", "dev": true, @@ -550,15 +341,13 @@ }, "frontend/node_modules/react-is": { "version": "18.2.0", - "resolved": "https://registry.npmjs.org/react-is/-/react-is-18.2.0.tgz", - "integrity": "sha512-xWGDIW6x921xtzPkhiULtthJHoJvBbF3q26fzloPCK0hsvxtPVelvftw3zjbHWSkR2km9Z+4uxbDDK/6Zw9B8w==", - "dev": true + "dev": true, + "license": "MIT" }, "frontend/node_modules/react-test-renderer": { "version": "18.2.0", - "resolved": "https://registry.npmjs.org/react-test-renderer/-/react-test-renderer-18.2.0.tgz", - "integrity": "sha512-JWD+aQ0lh2gvh4NM3bBM42Kx+XybOxCpgYK7F8ugAlpaTSnWsX+39Z4XkOykGZAHrjwwTZT3x3KxswVWxHPUqA==", "dev": true, + "license": "MIT", "dependencies": { "react-is": "^18.2.0", "react-shallow-renderer": "^16.15.0", @@ -568,15 +357,6 @@ "react": "^18.2.0" } }, - "frontend/node_modules/scheduler": { - "version": "0.23.0", - "resolved": "https://registry.npmjs.org/scheduler/-/scheduler-0.23.0.tgz", - "integrity": "sha512-CtuThmgHNg7zIZWAXi3AsyIzA3n4xx7aNyjwC2VJldO2LMVDhFK+63xGqq6CsJH4rTAt6/M+N4GhZiDYPx9eUw==", - "dev": true, - "dependencies": { - "loose-envify": "^1.1.0" - } - }, "frontend/node_modules/wait-on": { "version": "3.3.0", "dev": true, @@ -2324,8 +2104,7 @@ }, "node_modules/@babel/runtime": { "version": "7.21.5", - "resolved": "https://registry.npmjs.org/@babel/runtime/-/runtime-7.21.5.tgz", - "integrity": "sha512-8jI69toZqqcsnqGGqwGS4Qb1VwLOEp4hz+CXPywcvjs60u3B4Pom/U/7rm4W8tMOYEB+E9wgD0mW1l3r8qlI9Q==", + "license": "MIT", "dependencies": { "regenerator-runtime": "^0.13.11" }, @@ -2419,8 +2198,7 @@ }, "node_modules/@emotion/babel-plugin": { "version": "11.10.8", - "resolved": "https://registry.npmjs.org/@emotion/babel-plugin/-/babel-plugin-11.10.8.tgz", - "integrity": "sha512-gxNky50AJL3AlkbjvTARiwAqei6/tNUxDZPSKd+3jqWVM3AmdVTTdpjHorR/an/M0VJqdsuq5oGcFH+rjtyujQ==", + "license": "MIT", "dependencies": { "@babel/helper-module-imports": "^7.16.7", "@babel/runtime": "^7.18.3", @@ -2437,26 +2215,22 @@ }, "node_modules/@emotion/babel-plugin/node_modules/@emotion/memoize": { "version": "0.8.0", - "resolved": "https://registry.npmjs.org/@emotion/memoize/-/memoize-0.8.0.tgz", - "integrity": "sha512-G/YwXTkv7Den9mXDO7AhLWkE3q+I92B+VqAE+dYG4NGPaHZGvt3G8Q0p9vmE+sq7rTGphUbAvmQ9YpbfMQGGlA==" + "license": "MIT" }, "node_modules/@emotion/babel-plugin/node_modules/source-map": { "version": "0.5.7", - "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.5.7.tgz", - "integrity": "sha512-LbrmJOMUSdEVxIKvdcJzQC+nQhe8FUZQTXQy6+I75skNgn3OoQ0DZA8YnFa7gp8tqtL3KPf1kmo0R5DoApeSGQ==", + "license": "BSD-3-Clause", "engines": { "node": ">=0.10.0" } }, "node_modules/@emotion/babel-plugin/node_modules/stylis": { "version": "4.1.4", - "resolved": "https://registry.npmjs.org/stylis/-/stylis-4.1.4.tgz", - "integrity": "sha512-USf5pszRYwuE6hg9by0OkKChkQYEXfkeTtm0xKw+jqQhwyjCVLdYyMBK7R+n7dhzsblAWJnGxju4vxq5eH20GQ==" + "license": "MIT" }, "node_modules/@emotion/cache": { "version": "11.10.8", - "resolved": "https://registry.npmjs.org/@emotion/cache/-/cache-11.10.8.tgz", - "integrity": "sha512-5fyqGHi51LU95o7qQ/vD1jyvC4uCY5GcBT+UgP4LHdpO9jPDlXqhrRr9/wCKmfoAvh5G/F7aOh4MwQa+8uEqhA==", + "license": "MIT", "dependencies": { "@emotion/memoize": "^0.8.0", "@emotion/sheet": "^1.2.1", @@ -2467,23 +2241,19 @@ }, "node_modules/@emotion/cache/node_modules/@emotion/memoize": { "version": "0.8.0", - "resolved": "https://registry.npmjs.org/@emotion/memoize/-/memoize-0.8.0.tgz", - "integrity": "sha512-G/YwXTkv7Den9mXDO7AhLWkE3q+I92B+VqAE+dYG4NGPaHZGvt3G8Q0p9vmE+sq7rTGphUbAvmQ9YpbfMQGGlA==" + "license": "MIT" }, "node_modules/@emotion/cache/node_modules/stylis": { "version": "4.1.4", - "resolved": "https://registry.npmjs.org/stylis/-/stylis-4.1.4.tgz", - "integrity": "sha512-USf5pszRYwuE6hg9by0OkKChkQYEXfkeTtm0xKw+jqQhwyjCVLdYyMBK7R+n7dhzsblAWJnGxju4vxq5eH20GQ==" + "license": "MIT" }, "node_modules/@emotion/hash": { "version": "0.9.0", - "resolved": "https://registry.npmjs.org/@emotion/hash/-/hash-0.9.0.tgz", - "integrity": "sha512-14FtKiHhy2QoPIzdTcvh//8OyBlknNs2nXRwIhG904opCby3l+9Xaf/wuPvICBF0rc1ZCNBd3nKe9cd2mecVkQ==" + "license": "MIT" }, "node_modules/@emotion/react": { "version": "11.10.8", - "resolved": "https://registry.npmjs.org/@emotion/react/-/react-11.10.8.tgz", - "integrity": "sha512-ZfGfiABtJ1P1OXqOBsW08EgCDp5fK6C5I8hUJauc/VcJBGSzqAirMnFslhFWnZJ/w5HxPI36XbvMV0l4KZHl+w==", + "license": "MIT", "dependencies": { "@babel/runtime": "^7.18.3", "@emotion/babel-plugin": "^11.10.8", @@ -2505,8 +2275,7 @@ }, "node_modules/@emotion/serialize": { "version": "1.1.1", - "resolved": "https://registry.npmjs.org/@emotion/serialize/-/serialize-1.1.1.tgz", - "integrity": "sha512-Zl/0LFggN7+L1liljxXdsVSVlg6E/Z/olVWpfxUTxOAmi8NU7YoeWeLfi1RmnB2TATHoaWwIBRoL+FvAJiTUQA==", + "license": "MIT", "dependencies": { "@emotion/hash": "^0.9.0", "@emotion/memoize": "^0.8.0", @@ -2517,23 +2286,19 @@ }, "node_modules/@emotion/serialize/node_modules/@emotion/memoize": { "version": "0.8.0", - "resolved": "https://registry.npmjs.org/@emotion/memoize/-/memoize-0.8.0.tgz", - "integrity": "sha512-G/YwXTkv7Den9mXDO7AhLWkE3q+I92B+VqAE+dYG4NGPaHZGvt3G8Q0p9vmE+sq7rTGphUbAvmQ9YpbfMQGGlA==" + "license": "MIT" }, "node_modules/@emotion/serialize/node_modules/@emotion/unitless": { "version": "0.8.0", - "resolved": "https://registry.npmjs.org/@emotion/unitless/-/unitless-0.8.0.tgz", - "integrity": "sha512-VINS5vEYAscRl2ZUDiT3uMPlrFQupiKgHz5AA4bCH1miKBg4qtwkim1qPmJj/4WG6TreYMY111rEFsjupcOKHw==" + "license": "MIT" }, "node_modules/@emotion/sheet": { "version": "1.2.1", - "resolved": "https://registry.npmjs.org/@emotion/sheet/-/sheet-1.2.1.tgz", - "integrity": "sha512-zxRBwl93sHMsOj4zs+OslQKg/uhF38MB+OMKoCrVuS0nyTkqnau+BM3WGEoOptg9Oz45T/aIGs1qbVAsEFo3nA==" + "license": "MIT" }, "node_modules/@emotion/styled": { "version": "11.10.8", - "resolved": "https://registry.npmjs.org/@emotion/styled/-/styled-11.10.8.tgz", - "integrity": "sha512-gow0lF4Uw/QEdX2REMhI8v6wLOabPKJ+4HKNF0xdJ2DJdznN6fxaXpQOx6sNkyBhSUL558Rmcu1Lq/MYlVo4vw==", + "license": "MIT", "dependencies": { "@babel/runtime": "^7.18.3", "@emotion/babel-plugin": "^11.10.8", @@ -2554,34 +2319,29 @@ }, "node_modules/@emotion/styled/node_modules/@emotion/is-prop-valid": { "version": "1.2.0", - "resolved": "https://registry.npmjs.org/@emotion/is-prop-valid/-/is-prop-valid-1.2.0.tgz", - "integrity": "sha512-3aDpDprjM0AwaxGE09bOPkNxHpBd+kA6jty3RnaEXdweX1DF1U3VQpPYb0g1IStAuK7SVQ1cy+bNBBKp4W3Fjg==", + "license": "MIT", "dependencies": { "@emotion/memoize": "^0.8.0" } }, "node_modules/@emotion/styled/node_modules/@emotion/memoize": { "version": "0.8.0", - "resolved": "https://registry.npmjs.org/@emotion/memoize/-/memoize-0.8.0.tgz", - "integrity": "sha512-G/YwXTkv7Den9mXDO7AhLWkE3q+I92B+VqAE+dYG4NGPaHZGvt3G8Q0p9vmE+sq7rTGphUbAvmQ9YpbfMQGGlA==" + "license": "MIT" }, "node_modules/@emotion/use-insertion-effect-with-fallbacks": { "version": "1.0.0", - "resolved": "https://registry.npmjs.org/@emotion/use-insertion-effect-with-fallbacks/-/use-insertion-effect-with-fallbacks-1.0.0.tgz", - "integrity": "sha512-1eEgUGmkaljiBnRMTdksDV1W4kUnmwgp7X9G8B++9GYwl1lUdqSndSriIrTJ0N7LQaoauY9JJ2yhiOYK5+NI4A==", + "license": "MIT", "peerDependencies": { "react": ">=16.8.0" } }, "node_modules/@emotion/utils": { "version": "1.2.0", - "resolved": "https://registry.npmjs.org/@emotion/utils/-/utils-1.2.0.tgz", - "integrity": "sha512-sn3WH53Kzpw8oQ5mgMmIzzyAaH2ZqFEbozVVBSYp538E06OSE6ytOp7pRAjNQR+Q/orwqdQYJSe2m3hCOeznkw==" + "license": "MIT" }, "node_modules/@emotion/weak-memoize": { "version": "0.3.0", - "resolved": "https://registry.npmjs.org/@emotion/weak-memoize/-/weak-memoize-0.3.0.tgz", - "integrity": "sha512-AHPmaAx+RYfZz0eYu6Gviiagpmiyw98ySSlQvCUhVGDRtDFe4DBS0x1bSjdF3gqUDYOczB+yYvBTtEylYSdRhg==" + "license": "MIT" }, "node_modules/@eslint/eslintrc": { "version": "1.4.1", @@ -3103,8 +2863,7 @@ }, "node_modules/@mui/base": { "version": "5.0.0-alpha.127", - "resolved": "https://registry.npmjs.org/@mui/base/-/base-5.0.0-alpha.127.tgz", - "integrity": "sha512-FoRQd0IOH9MnfyL5yXssyQRnC4vXI+1bwkU1idr+wNkP1ZfxE+JsThHcfl1dy5azLssVUGTtQFD9edQLdbyJog==", + "license": "MIT", "dependencies": { "@babel/runtime": "^7.21.0", "@emotion/is-prop-valid": "^1.2.0", @@ -3135,26 +2894,22 @@ }, "node_modules/@mui/base/node_modules/@emotion/is-prop-valid": { "version": "1.2.0", - "resolved": "https://registry.npmjs.org/@emotion/is-prop-valid/-/is-prop-valid-1.2.0.tgz", - "integrity": "sha512-3aDpDprjM0AwaxGE09bOPkNxHpBd+kA6jty3RnaEXdweX1DF1U3VQpPYb0g1IStAuK7SVQ1cy+bNBBKp4W3Fjg==", + "license": "MIT", "dependencies": { "@emotion/memoize": "^0.8.0" } }, "node_modules/@mui/base/node_modules/@emotion/memoize": { "version": "0.8.0", - "resolved": "https://registry.npmjs.org/@emotion/memoize/-/memoize-0.8.0.tgz", - "integrity": "sha512-G/YwXTkv7Den9mXDO7AhLWkE3q+I92B+VqAE+dYG4NGPaHZGvt3G8Q0p9vmE+sq7rTGphUbAvmQ9YpbfMQGGlA==" + "license": "MIT" }, "node_modules/@mui/base/node_modules/react-is": { "version": "18.2.0", - "resolved": "https://registry.npmjs.org/react-is/-/react-is-18.2.0.tgz", - "integrity": "sha512-xWGDIW6x921xtzPkhiULtthJHoJvBbF3q26fzloPCK0hsvxtPVelvftw3zjbHWSkR2km9Z+4uxbDDK/6Zw9B8w==" + "license": "MIT" }, "node_modules/@mui/core-downloads-tracker": { "version": "5.12.2", - "resolved": "https://registry.npmjs.org/@mui/core-downloads-tracker/-/core-downloads-tracker-5.12.2.tgz", - "integrity": "sha512-Qn7dy8tql6T0hY6gTFPkpWlnqVVFGu5Z6QzEzUSzzmLZpfAx4kf8sFz0PHiB7gU5yrqcZF9picMx1shpRY/rXw==", + "license": "MIT", "funding": { "type": "opencollective", "url": "https://opencollective.com/mui" @@ -3162,8 +2917,7 @@ }, "node_modules/@mui/material": { "version": "5.12.2", - "resolved": "https://registry.npmjs.org/@mui/material/-/material-5.12.2.tgz", - "integrity": "sha512-XOVy6fVC0rI2dEwDq/1s4Te2hewTUe6lznzeVnruyATGkdmM06WnHqkZOoLVIWo9hWwAxpcgTDcAIVpFtt1nrw==", + "license": "MIT", "dependencies": { "@babel/runtime": "^7.21.0", "@mui/base": "5.0.0-alpha.127", @@ -3206,13 +2960,11 @@ }, "node_modules/@mui/material/node_modules/react-is": { "version": "18.2.0", - "resolved": "https://registry.npmjs.org/react-is/-/react-is-18.2.0.tgz", - "integrity": "sha512-xWGDIW6x921xtzPkhiULtthJHoJvBbF3q26fzloPCK0hsvxtPVelvftw3zjbHWSkR2km9Z+4uxbDDK/6Zw9B8w==" + "license": "MIT" }, "node_modules/@mui/private-theming": { "version": "5.12.0", - "resolved": "https://registry.npmjs.org/@mui/private-theming/-/private-theming-5.12.0.tgz", - "integrity": "sha512-w5dwMen1CUm1puAtubqxY9BIzrBxbOThsg2iWMvRJmWyJAPdf3Z583fPXpqeA2lhTW79uH2jajk5Ka4FuGlTPg==", + "license": "MIT", "dependencies": { "@babel/runtime": "^7.21.0", "@mui/utils": "^5.12.0", @@ -3237,8 +2989,7 @@ }, "node_modules/@mui/styled-engine": { "version": "5.12.0", - "resolved": "https://registry.npmjs.org/@mui/styled-engine/-/styled-engine-5.12.0.tgz", - "integrity": "sha512-frh8L7CRnvD0RDmIqEv6jFeKQUIXqW90BaZ6OrxJ2j4kIsiVLu29Gss4SbBvvrWwwatR72sBmC3w1aG4fjp9mQ==", + "license": "MIT", "dependencies": { "@babel/runtime": "^7.21.0", "@emotion/cache": "^11.10.7", @@ -3268,8 +3019,7 @@ }, "node_modules/@mui/system": { "version": "5.12.1", - "resolved": "https://registry.npmjs.org/@mui/system/-/system-5.12.1.tgz", - "integrity": "sha512-Po+sicdV3bbRYXdU29XZaHPZrW7HUYUqU1qCu77GCCEMbahC756YpeyefdIYuPMUg0OdO3gKIUfDISBrkjJL+w==", + "license": "MIT", "dependencies": { "@babel/runtime": "^7.21.0", "@mui/private-theming": "^5.12.0", @@ -3307,8 +3057,7 @@ }, "node_modules/@mui/types": { "version": "7.2.4", - "resolved": "https://registry.npmjs.org/@mui/types/-/types-7.2.4.tgz", - "integrity": "sha512-LBcwa8rN84bKF+f5sDyku42w1NTxaPgPyYKODsh01U1fVstTClbUoSA96oyRBnSNyEiAVjKm6Gwx9vjR+xyqHA==", + "license": "MIT", "peerDependencies": { "@types/react": "*" }, @@ -3320,8 +3069,7 @@ }, "node_modules/@mui/utils": { "version": "5.12.0", - "resolved": "https://registry.npmjs.org/@mui/utils/-/utils-5.12.0.tgz", - "integrity": "sha512-RmQwgzF72p7Yr4+AAUO6j1v2uzt6wr7SWXn68KBsnfVpdOHyclCzH2lr/Xu6YOw9su4JRtdAIYfJFXsS6Cjkmw==", + "license": "MIT", "dependencies": { "@babel/runtime": "^7.21.0", "@types/prop-types": "^15.7.5", @@ -3342,21 +3090,154 @@ }, "node_modules/@mui/utils/node_modules/react-is": { "version": "18.2.0", - "resolved": "https://registry.npmjs.org/react-is/-/react-is-18.2.0.tgz", - "integrity": "sha512-xWGDIW6x921xtzPkhiULtthJHoJvBbF3q26fzloPCK0hsvxtPVelvftw3zjbHWSkR2km9Z+4uxbDDK/6Zw9B8w==" + "license": "MIT" }, "node_modules/@next/env": { + "version": "13.4.2", + "resolved": "https://registry.npmjs.org/@next/env/-/env-13.4.2.tgz", + "integrity": "sha512-Wqvo7lDeS0KGwtwg9TT9wKQ8raelmUxt+TQKWvG/xKfcmDXNOtCuaszcfCF8JzlBG1q0VhpI6CKaRMbVPMDWgw==" + }, + "node_modules/@next/eslint-plugin-next": { "version": "13.3.1", - "resolved": "https://registry.npmjs.org/@next/env/-/env-13.3.1.tgz", - "integrity": "sha512-EDtCoedIZC7JlUQ3uaQpSc4aVmyhbLHmQVALg7pFfQgOTjgSnn7mKtA0DiCMkYvvsx6aFb5octGMtWrOtGXW9A==" + "dev": true, + "license": "MIT", + "dependencies": { + "glob": "7.1.7" + } + }, + "node_modules/@next/swc-darwin-arm64": { + "version": "13.4.2", + "resolved": "https://registry.npmjs.org/@next/swc-darwin-arm64/-/swc-darwin-arm64-13.4.2.tgz", + "integrity": "sha512-6BBlqGu3ewgJflv9iLCwO1v1hqlecaIH2AotpKfVUEzUxuuDNJQZ2a4KLb4MBl8T9/vca1YuWhSqtbF6ZuUJJw==", + "cpu": [ + "arm64" + ], + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": ">= 10" + } + }, + "node_modules/@next/swc-darwin-x64": { + "version": "13.4.2", + "resolved": "https://registry.npmjs.org/@next/swc-darwin-x64/-/swc-darwin-x64-13.4.2.tgz", + "integrity": "sha512-iZuYr7ZvGLPjPmfhhMl0ISm+z8EiyLBC1bLyFwGBxkWmPXqdJ60mzuTaDSr5WezDwv0fz32HB7JHmRC6JVHSZg==", + "cpu": [ + "x64" + ], + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": ">= 10" + } + }, + "node_modules/@next/swc-linux-arm64-gnu": { + "version": "13.4.2", + "resolved": "https://registry.npmjs.org/@next/swc-linux-arm64-gnu/-/swc-linux-arm64-gnu-13.4.2.tgz", + "integrity": "sha512-2xVabFtIge6BJTcJrW8YuUnYTuQjh4jEuRuS2mscyNVOj6zUZkom3CQg+egKOoS+zh2rrro66ffSKIS+ztFJTg==", + "cpu": [ + "arm64" + ], + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">= 10" + } + }, + "node_modules/@next/swc-linux-arm64-musl": { + "version": "13.4.2", + "resolved": "https://registry.npmjs.org/@next/swc-linux-arm64-musl/-/swc-linux-arm64-musl-13.4.2.tgz", + "integrity": "sha512-wKRCQ27xCUJx5d6IivfjYGq8oVngqIhlhSAJntgXLt7Uo9sRT/3EppMHqUZRfyuNBTbykEre1s5166z+pvRB5A==", + "cpu": [ + "arm64" + ], + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">= 10" + } + }, + "node_modules/@next/swc-linux-x64-gnu": { + "version": "13.4.2", + "resolved": "https://registry.npmjs.org/@next/swc-linux-x64-gnu/-/swc-linux-x64-gnu-13.4.2.tgz", + "integrity": "sha512-NpCa+UVhhuNeaFVUP1Bftm0uqtvLWq2JTm7+Ta48+2Uqj2mNXrDIvyn1DY/ZEfmW/1yvGBRaUAv9zkMkMRixQA==", + "cpu": [ + "x64" + ], + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">= 10" + } + }, + "node_modules/@next/swc-linux-x64-musl": { + "version": "13.4.2", + "resolved": "https://registry.npmjs.org/@next/swc-linux-x64-musl/-/swc-linux-x64-musl-13.4.2.tgz", + "integrity": "sha512-ZWVC72x0lW4aj44e3khvBrj2oSYj1bD0jESmyah3zG/3DplEy/FOtYkMzbMjHTdDSheso7zH8GIlW6CDQnKhmQ==", + "cpu": [ + "x64" + ], + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">= 10" + } + }, + "node_modules/@next/swc-win32-arm64-msvc": { + "version": "13.4.2", + "resolved": "https://registry.npmjs.org/@next/swc-win32-arm64-msvc/-/swc-win32-arm64-msvc-13.4.2.tgz", + "integrity": "sha512-pLT+OWYpzJig5K4VKhLttlIfBcVZfr2+Xbjra0Tjs83NQSkFS+y7xx+YhCwvpEmXYLIvaggj2ONPyjbiigOvHQ==", + "cpu": [ + "arm64" + ], + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": ">= 10" + } + }, + "node_modules/@next/swc-win32-ia32-msvc": { + "version": "13.4.2", + "resolved": "https://registry.npmjs.org/@next/swc-win32-ia32-msvc/-/swc-win32-ia32-msvc-13.4.2.tgz", + "integrity": "sha512-dhpiksQCyGca4WY0fJyzK3FxMDFoqMb0Cn+uDB+9GYjpU2K5//UGPQlCwiK4JHxuhg8oLMag5Nf3/IPSJNG8jw==", + "cpu": [ + "ia32" + ], + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": ">= 10" + } }, - "node_modules/@next/eslint-plugin-next": { - "version": "13.3.1", - "resolved": "https://registry.npmjs.org/@next/eslint-plugin-next/-/eslint-plugin-next-13.3.1.tgz", - "integrity": "sha512-Hpd74UrYGF+bq9bBSRDXRsRfaWkPpcwjhvachy3sr/R/5fY6feC0T0s047pUthyqcaeNsqKOY1nUGQQJNm4WyA==", - "dev": true, - "dependencies": { - "glob": "7.1.7" + "node_modules/@next/swc-win32-x64-msvc": { + "version": "13.4.2", + "resolved": "https://registry.npmjs.org/@next/swc-win32-x64-msvc/-/swc-win32-x64-msvc-13.4.2.tgz", + "integrity": "sha512-O7bort1Vld00cu8g0jHZq3cbSTUNMohOEvYqsqE10+yfohhdPHzvzO+ziJRz4Dyyr/fYKREwS7gR4JC0soSOMw==", + "cpu": [ + "x64" + ], + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": ">= 10" } }, "node_modules/@nodelib/fs.scandir": { @@ -3393,9 +3274,8 @@ }, "node_modules/@pkgr/utils": { "version": "2.3.1", - "resolved": "https://registry.npmjs.org/@pkgr/utils/-/utils-2.3.1.tgz", - "integrity": "sha512-wfzX8kc1PMyUILA+1Z/EqoE4UCXGy0iRGMhPwdfae1+f0OXlLqCk+By+aMzgJBzR9AzS4CDizioG6Ss1gvAFJw==", "dev": true, + "license": "MIT", "dependencies": { "cross-spawn": "^7.0.3", "is-glob": "^4.0.3", @@ -3413,9 +3293,8 @@ }, "node_modules/@pkgr/utils/node_modules/open": { "version": "8.4.2", - "resolved": "https://registry.npmjs.org/open/-/open-8.4.2.tgz", - "integrity": "sha512-7x81NCL719oNbsq/3mh+hVrAWmFuEYUqrq/Iw3kUzH8ReypT9QQ0BLoJS7/G9k6N81XjW4qHWtjWwe/9eLy1EQ==", "dev": true, + "license": "MIT", "dependencies": { "define-lazy-prop": "^2.0.0", "is-docker": "^2.1.1", @@ -3430,8 +3309,7 @@ }, "node_modules/@playwright/test": { "version": "1.33.0", - "resolved": "https://registry.npmjs.org/@playwright/test/-/test-1.33.0.tgz", - "integrity": "sha512-YunBa2mE7Hq4CfPkGzQRK916a4tuZoVx/EpLjeWlTVOnD4S2+fdaQZE0LJkbfhN5FTSKNLdcl7MoT5XB37bTkg==", + "license": "Apache-2.0", "dependencies": { "@types/node": "*", "playwright-core": "1.33.0" @@ -3453,8 +3331,7 @@ }, "node_modules/@popperjs/core": { "version": "2.11.7", - "resolved": "https://registry.npmjs.org/@popperjs/core/-/core-2.11.7.tgz", - "integrity": "sha512-Cr4OjIkipTtcXKjAsm8agyleBuDHvxzeBoa1v543lbv1YaIwQjESsVcmjiWiPEbC1FIeHOG/Op9kdCmAmiS3Kw==", + "license": "MIT", "funding": { "type": "opencollective", "url": "https://opencollective.com/popperjs" @@ -3843,17 +3720,85 @@ } }, "node_modules/@swc/helpers": { - "version": "0.5.0", - "resolved": "https://registry.npmjs.org/@swc/helpers/-/helpers-0.5.0.tgz", - "integrity": "sha512-SjY/p4MmECVVEWspzSRpQEM3sjR17sP8PbGxELWrT+YZMBfiUyt1MRUNjMV23zohwlG2HYtCQOsCwsTHguXkyg==", + "version": "0.5.1", + "resolved": "https://registry.npmjs.org/@swc/helpers/-/helpers-0.5.1.tgz", + "integrity": "sha512-sJ902EfIzn1Fa+qYmjdQqh8tPsoxyBz+8yBKC2HKUxyezKJFwPGOn7pv4WY6QuQW//ySQi5lJjA/ZT9sNWWNTg==", "dependencies": { "tslib": "^2.4.0" } }, + "node_modules/@tanstack/match-sorter-utils": { + "version": "8.8.4", + "resolved": "https://registry.npmjs.org/@tanstack/match-sorter-utils/-/match-sorter-utils-8.8.4.tgz", + "integrity": "sha512-rKH8LjZiszWEvmi01NR72QWZ8m4xmXre0OOwlRGnjU01Eqz/QnN+cqpty2PJ0efHblq09+KilvyR7lsbzmXVEw==", + "dependencies": { + "remove-accents": "0.4.2" + }, + "engines": { + "node": ">=12" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/kentcdodds" + } + }, + "node_modules/@tanstack/query-core": { + "version": "4.29.7", + "resolved": "https://registry.npmjs.org/@tanstack/query-core/-/query-core-4.29.7.tgz", + "integrity": "sha512-GXG4b5hV2Loir+h2G+RXhJdoZhJLnrBWsuLB2r0qBRyhWuXq9w/dWxzvpP89H0UARlH6Mr9DiVj4SMtpkF/aUA==", + "funding": { + "type": "github", + "url": "https://github.com/sponsors/tannerlinsley" + } + }, + "node_modules/@tanstack/react-query": { + "version": "4.29.7", + "resolved": "https://registry.npmjs.org/@tanstack/react-query/-/react-query-4.29.7.tgz", + "integrity": "sha512-ijBWEzAIo09fB1yd22slRZzprrZ5zMdWYzBnCg5qiXuFbH78uGN1qtGz8+Ed4MuhaPaYSD+hykn+QEKtQviEtg==", + "dependencies": { + "@tanstack/query-core": "4.29.7", + "use-sync-external-store": "^1.2.0" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/tannerlinsley" + }, + "peerDependencies": { + "react": "^16.8.0 || ^17.0.0 || ^18.0.0", + "react-dom": "^16.8.0 || ^17.0.0 || ^18.0.0", + "react-native": "*" + }, + "peerDependenciesMeta": { + "react-dom": { + "optional": true + }, + "react-native": { + "optional": true + } + } + }, + "node_modules/@tanstack/react-query-devtools": { + "version": "4.29.7", + "resolved": "https://registry.npmjs.org/@tanstack/react-query-devtools/-/react-query-devtools-4.29.7.tgz", + "integrity": "sha512-fckNnBV6Kfbtq6EJqQen8oBjPqGFcOPS9SJmNKLbFLQgd7OpNIlA4M0r37iJYUY9m14/ESKc1wzKd36VfeiPjg==", + "dependencies": { + "@tanstack/match-sorter-utils": "^8.7.0", + "superjson": "^1.10.0", + "use-sync-external-store": "^1.2.0" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/tannerlinsley" + }, + "peerDependencies": { + "@tanstack/react-query": "4.29.7", + "react": "^16.8.0 || ^17.0.0 || ^18.0.0", + "react-dom": "^16.8.0 || ^17.0.0 || ^18.0.0" + } + }, "node_modules/@textea/json-viewer": { "version": "2.17.2", - "resolved": "https://registry.npmjs.org/@textea/json-viewer/-/json-viewer-2.17.2.tgz", - "integrity": "sha512-oD6U2z02xX64gJjZOVPtKW//fhzGyXy4te1Ed14EJTV34GahF+i14WMwsOqCd2RWNLJhhsqsmAzQXhEVUMAp5A==", + "license": "MIT", "dependencies": { "@emotion/react": "^11.10.6", "@emotion/styled": "^11.10.6", @@ -3876,32 +3821,29 @@ } }, "node_modules/@trpc/client": { - "version": "9.27.4", - "license": "MIT", - "dependencies": { - "@babel/runtime": "^7.9.0" - }, + "version": "10.26.0", + "resolved": "https://registry.npmjs.org/@trpc/client/-/client-10.26.0.tgz", + "integrity": "sha512-ojHxQFIE97rBEGPK8p1ijbzo0T1IdEBoJ9fFSgWWL9FMuEEA/DNQ9s0uuiOrDKhCCdTFT1unfRharoJhB2/O2w==", "peerDependencies": { - "@trpc/server": "9.27.4" + "@trpc/server": "10.26.0" } }, - "node_modules/@trpc/react": { - "version": "9.27.4", - "license": "MIT", - "dependencies": { - "@babel/runtime": "^7.9.0" - }, + "node_modules/@trpc/react-query": { + "version": "10.26.0", + "resolved": "https://registry.npmjs.org/@trpc/react-query/-/react-query-10.26.0.tgz", + "integrity": "sha512-n+enpalaCZhd3A/mbZmXeydRZHsAJo7mzc2ncgHn5S+C3SrfOM897uQdbHdj02Li25ULxzP1O92w+vZzmFbgkA==", "peerDependencies": { - "@trpc/client": "9.27.4", - "@trpc/server": "9.27.4", + "@tanstack/react-query": "^4.18.0", + "@trpc/client": "10.26.0", + "@trpc/server": "10.26.0", "react": ">=16.8.0", - "react-dom": ">=16.8.0", - "react-query": "^3.37.0" + "react-dom": ">=16.8.0" } }, "node_modules/@trpc/server": { - "version": "9.27.4", - "license": "MIT" + "version": "10.26.0", + "resolved": "https://registry.npmjs.org/@trpc/server/-/server-10.26.0.tgz", + "integrity": "sha512-+Wt0NFAeflVSNiUnHIDNN3C8jP7XIRmYrcgJ6IsAnm0lK4p/FkpCpeu1aig5qxrgZx30PHNDLZ/3FttVSEW2aQ==" }, "node_modules/@trysound/sax": { "version": "0.2.0", @@ -4411,8 +4353,7 @@ }, "node_modules/@types/react": { "version": "18.2.0", - "resolved": "https://registry.npmjs.org/@types/react/-/react-18.2.0.tgz", - "integrity": "sha512-0FLj93y5USLHdnhIhABk83rm8XEGA7kH3cr+YUlvxoUGp1xNt/DINUMvqPxLyOQMzLmZe8i4RTHbvb8MC7NmrA==", + "license": "MIT", "dependencies": { "@types/prop-types": "*", "@types/scheduler": "*", @@ -4429,25 +4370,22 @@ }, "node_modules/@types/react-dom": { "version": "18.2.1", - "resolved": "https://registry.npmjs.org/@types/react-dom/-/react-dom-18.2.1.tgz", - "integrity": "sha512-8QZEV9+Kwy7tXFmjJrp3XUKQSs9LTnE0KnoUb0YCguWBiNW0Yfb2iBMYZ08WPg35IR6P3Z0s00B15SwZnO26+w==", "dev": true, + "license": "MIT", "dependencies": { "@types/react": "*" } }, "node_modules/@types/react-is": { "version": "17.0.4", - "resolved": "https://registry.npmjs.org/@types/react-is/-/react-is-17.0.4.tgz", - "integrity": "sha512-FLzd0K9pnaEvKz4D1vYxK9JmgQPiGk1lu23o1kqGsLeT0iPbRSF7b76+S5T9fD8aRa0B8bY7I/3DebEj+1ysBA==", + "license": "MIT", "dependencies": { "@types/react": "^17" } }, "node_modules/@types/react-is/node_modules/@types/react": { "version": "17.0.58", - "resolved": "https://registry.npmjs.org/@types/react/-/react-17.0.58.tgz", - "integrity": "sha512-c1GzVY97P0fGxwGxhYq989j4XwlcHQoto6wQISOC2v6wm3h0PORRWJFHlkRjfGsiG3y1609WdQ+J+tKxvrEd6A==", + "license": "MIT", "dependencies": { "@types/prop-types": "*", "@types/scheduler": "*", @@ -4464,9 +4402,8 @@ }, "node_modules/@types/react-test-renderer": { "version": "18.0.0", - "resolved": "https://registry.npmjs.org/@types/react-test-renderer/-/react-test-renderer-18.0.0.tgz", - "integrity": "sha512-C7/5FBJ3g3sqUahguGi03O79b8afNeSD6T8/GU50oQrJCU0bVCCGQHaGKUbg2Ce8VQEEqTw8/HiS6lXHHdgkdQ==", "dev": true, + "license": "MIT", "dependencies": { "@types/react": "*" } @@ -5211,9 +5148,8 @@ }, "node_modules/@welldone-software/why-did-you-render": { "version": "7.0.1", - "resolved": "https://registry.npmjs.org/@welldone-software/why-did-you-render/-/why-did-you-render-7.0.1.tgz", - "integrity": "sha512-Qe/8Xxa2G+LMdI6VoazescPzjjkHYduCDa8aHOJR50e9Bgs8ihkfMBY+ev7B4oc3N59Zm547Sgjf8h5y0FOyoA==", "dev": true, + "license": "MIT", "dependencies": { "lodash": "^4" }, @@ -5885,8 +5821,7 @@ }, "node_modules/babel-plugin-macros": { "version": "3.1.0", - "resolved": "https://registry.npmjs.org/babel-plugin-macros/-/babel-plugin-macros-3.1.0.tgz", - "integrity": "sha512-Cg7TFGpIr01vOQNODXOOaGz2NpCU5gl8x1qJFbb6hbZxR7XrcE2vtbAsTAbJ7/xwJtUuJEw8K8Zr/AE0LHlesg==", + "license": "MIT", "dependencies": { "@babel/runtime": "^7.12.5", "cosmiconfig": "^7.0.0", @@ -5899,8 +5834,7 @@ }, "node_modules/babel-plugin-macros/node_modules/cosmiconfig": { "version": "7.1.0", - "resolved": "https://registry.npmjs.org/cosmiconfig/-/cosmiconfig-7.1.0.tgz", - "integrity": "sha512-AdmX6xUzdNASswsFtmwSt7Vj8po9IuqXm0UXz7QKPuEUmPB4XyjGfaAr2PSuELMwkRMVH1EpIkX5bTZGRB3eCA==", + "license": "MIT", "dependencies": { "@types/parse-json": "^4.0.0", "import-fresh": "^3.2.1", @@ -5914,8 +5848,7 @@ }, "node_modules/babel-plugin-macros/node_modules/parse-json": { "version": "5.2.0", - "resolved": "https://registry.npmjs.org/parse-json/-/parse-json-5.2.0.tgz", - "integrity": "sha512-ayCKvm/phCGxOkYRSCM82iDwct8/EonSEgCSxWxD7ve6jHggsFl4fZVQBPRNgQoKiuV/odhFrGzQXZwbifC8Rg==", + "license": "MIT", "dependencies": { "@babel/code-frame": "^7.0.0", "error-ex": "^1.3.1", @@ -6122,13 +6055,6 @@ "dev": true, "license": "Unlicense" }, - "node_modules/big-integer": { - "version": "1.6.51", - "license": "Unlicense", - "engines": { - "node": ">=0.6" - } - }, "node_modules/big.js": { "version": "5.2.2", "dev": true, @@ -6265,20 +6191,6 @@ "node": ">=8" } }, - "node_modules/broadcast-channel": { - "version": "3.7.0", - "license": "MIT", - "dependencies": { - "@babel/runtime": "^7.7.2", - "detect-node": "^2.1.0", - "js-sha3": "0.8.0", - "microseconds": "0.2.0", - "nano-time": "1.0.0", - "oblivious-set": "1.0.0", - "rimraf": "3.0.2", - "unload": "2.2.0" - } - }, "node_modules/brorand": { "version": "1.1.0", "dev": true, @@ -6480,8 +6392,6 @@ }, "node_modules/busboy": { "version": "1.6.0", - "resolved": "https://registry.npmjs.org/busboy/-/busboy-1.6.0.tgz", - "integrity": "sha512-8SFQbg/0hQ9xy3UNTB0YEnsNBbWfhf7RtnzpL7TkBiTBRfrQ9Fxcnz7VJsleJpyp6rVLvXiuORqjlHi5q+PYuA==", "dependencies": { "streamsearch": "^1.1.0" }, @@ -6860,8 +6770,7 @@ }, "node_modules/client-only": { "version": "0.0.1", - "resolved": "https://registry.npmjs.org/client-only/-/client-only-0.0.1.tgz", - "integrity": "sha512-IV3Ou0jSMzZrd3pZ48nLkT9DA7Ag1pnPzaiQhpW7c3RbcqqzvzzVu+L8gfqMp/8IM2MQtSiqaCxrrcfu8I8rMA==" + "license": "MIT" }, "node_modules/cliui": { "version": "8.0.1", @@ -6878,8 +6787,7 @@ }, "node_modules/clsx": { "version": "1.2.1", - "resolved": "https://registry.npmjs.org/clsx/-/clsx-1.2.1.tgz", - "integrity": "sha512-EcR6r5a8bj6pu3ycsa/E/cKVGuTgZJZdsyUYHOksG/UHIiKfjxzRxYJpyVBwYaQeOvghal9fcc4PidlgzugAQg==", + "license": "MIT", "engines": { "node": ">=6" } @@ -7099,6 +7007,20 @@ "version": "1.0.6", "license": "MIT" }, + "node_modules/copy-anything": { + "version": "3.0.4", + "resolved": "https://registry.npmjs.org/copy-anything/-/copy-anything-3.0.4.tgz", + "integrity": "sha512-MaQ9FwzlZ/KLeVCLhzI3rZw0EhrIryfZa3AyT4agVybR0DjlkDHA8898lamLD6kfkf9MMn8D+zDAUR4+GxaymQ==", + "dependencies": { + "is-what": "^4.1.8" + }, + "engines": { + "node": ">=12.13" + }, + "funding": { + "url": "https://github.com/sponsors/mesqueeb" + } + }, "node_modules/copy-concurrently": { "version": "1.0.5", "dev": true, @@ -7443,8 +7365,7 @@ }, "node_modules/csstype": { "version": "3.1.2", - "resolved": "https://registry.npmjs.org/csstype/-/csstype-3.1.2.tgz", - "integrity": "sha512-I7K1Uu0MBPzaFKg4nI5Q7Vs2t+3gWWW648spaF+Rg7pI9ds18Ugn+lvg4SHczUdKlHI5LWBXyqfS8+DufyBsgQ==" + "license": "MIT" }, "node_modules/currency-symbol-map": { "version": "2.2.0", @@ -7842,9 +7763,8 @@ }, "node_modules/define-lazy-prop": { "version": "2.0.0", - "resolved": "https://registry.npmjs.org/define-lazy-prop/-/define-lazy-prop-2.0.0.tgz", - "integrity": "sha512-Ds09qNh8yw3khSjiJjiUInaGX9xlqZDY7JVryGxdxV7NPeuqQfplOpQ66yJFZut3jLa5zOwkXw1g9EI2uKh4Og==", "dev": true, + "license": "MIT", "engines": { "node": ">=8" } @@ -8049,10 +7969,6 @@ "node": ">=8" } }, - "node_modules/detect-node": { - "version": "2.1.0", - "license": "MIT" - }, "node_modules/diff": { "version": "4.0.2", "license": "BSD-3-Clause", @@ -8743,9 +8659,8 @@ }, "node_modules/eslint-config-next": { "version": "13.3.1", - "resolved": "https://registry.npmjs.org/eslint-config-next/-/eslint-config-next-13.3.1.tgz", - "integrity": "sha512-DieA5djybeE3Q0IqnDXihmhgRSp44x1ywWBBpVRA9pSx+m5Icj8hFclx7ffXlAvb9MMLN6cgj/hqJ4lka/QmvA==", "dev": true, + "license": "MIT", "dependencies": { "@next/eslint-plugin-next": "13.3.1", "@rushstack/eslint-patch": "^1.1.3", @@ -8798,9 +8713,8 @@ }, "node_modules/eslint-import-resolver-typescript": { "version": "3.5.5", - "resolved": "https://registry.npmjs.org/eslint-import-resolver-typescript/-/eslint-import-resolver-typescript-3.5.5.tgz", - "integrity": "sha512-TdJqPHs2lW5J9Zpe17DZNQuDnox4xo2o+0tE7Pggain9Rbc19ik8kFtXdxZ250FVx2kF4vlt2RSf4qlUpG7bhw==", "dev": true, + "license": "ISC", "dependencies": { "debug": "^4.3.4", "enhanced-resolve": "^5.12.0", @@ -8824,9 +8738,8 @@ }, "node_modules/eslint-import-resolver-typescript/node_modules/enhanced-resolve": { "version": "5.13.0", - "resolved": "https://registry.npmjs.org/enhanced-resolve/-/enhanced-resolve-5.13.0.tgz", - "integrity": "sha512-eyV8f0y1+bzyfh8xAwW/WTSZpLbjhqc4ne9eGSH4Zo2ejdyiNG9pU6mf9DG8a7+Auk6MFTlNOT4Y2y/9k8GKVg==", "dev": true, + "license": "MIT", "dependencies": { "graceful-fs": "^4.2.4", "tapable": "^2.2.0" @@ -8837,9 +8750,8 @@ }, "node_modules/eslint-import-resolver-typescript/node_modules/globby": { "version": "13.1.4", - "resolved": "https://registry.npmjs.org/globby/-/globby-13.1.4.tgz", - "integrity": "sha512-iui/IiiW+QrJ1X1hKH5qwlMQyv34wJAYwH1vrf8b9kBA4sNiif3gKsMHa+BrdnOpEudWjpotfa7LrTzB1ERS/g==", "dev": true, + "license": "MIT", "dependencies": { "dir-glob": "^3.0.1", "fast-glob": "^3.2.11", @@ -8856,9 +8768,8 @@ }, "node_modules/eslint-import-resolver-typescript/node_modules/slash": { "version": "4.0.0", - "resolved": "https://registry.npmjs.org/slash/-/slash-4.0.0.tgz", - "integrity": "sha512-3dOsAHXXUkQTpOYcoAxLIorMTp4gIQr5IW3iVb7A7lFIp0VHhnynm9izx6TssdrIcVIESAlVjtnO2K8bg+Coew==", "dev": true, + "license": "MIT", "engines": { "node": ">=12" }, @@ -8868,9 +8779,8 @@ }, "node_modules/eslint-import-resolver-typescript/node_modules/tapable": { "version": "2.2.1", - "resolved": "https://registry.npmjs.org/tapable/-/tapable-2.2.1.tgz", - "integrity": "sha512-GNzQvQTOIP6RyTfE2Qxb8ZVlNmw0n88vp1szwWRimP02mnTsx3Wtn5qRdqY9w2XduFNUgvOwhNnQsjwCp+kqaQ==", "dev": true, + "license": "MIT", "engines": { "node": ">=6" } @@ -9901,8 +9811,7 @@ }, "node_modules/find-root": { "version": "1.1.0", - "resolved": "https://registry.npmjs.org/find-root/-/find-root-1.1.0.tgz", - "integrity": "sha512-NKfW6bec6GfKc0SGx1e07QZY9PE99u0Bft/0rzSD5k3sO/vwkVUpDUKVm5Gpp5Ue3YfShPFTX2070tDs5kB9Ng==" + "license": "MIT" }, "node_modules/find-up": { "version": "5.0.0", @@ -10239,9 +10148,8 @@ }, "node_modules/get-tsconfig": { "version": "4.5.0", - "resolved": "https://registry.npmjs.org/get-tsconfig/-/get-tsconfig-4.5.0.tgz", - "integrity": "sha512-MjhiaIWCJ1sAU4pIQ5i5OfOuHHxVo1oYeNsWTON7jxYkod8pHocXeh+SSbmu5OZZZK73B6cbJ2XADzXehLyovQ==", "dev": true, + "license": "MIT", "funding": { "url": "https://github.com/privatenumber/get-tsconfig?sponsor=1" } @@ -10341,9 +10249,8 @@ }, "node_modules/globalyzer": { "version": "0.1.0", - "resolved": "https://registry.npmjs.org/globalyzer/-/globalyzer-0.1.0.tgz", - "integrity": "sha512-40oNTM9UfG6aBmuKxk/giHn5nQ8RVz/SS4Ir6zgzOv9/qC3kKZ9v4etGTcJbEl/NyVQH7FGU7d+X1egr57Md2Q==", - "dev": true + "dev": true, + "license": "MIT" }, "node_modules/globby": { "version": "11.1.0", @@ -10366,9 +10273,8 @@ }, "node_modules/globrex": { "version": "0.1.2", - "resolved": "https://registry.npmjs.org/globrex/-/globrex-0.1.2.tgz", - "integrity": "sha512-uHJgbwAMwNFf5mLst7IWLNg14x1CkeqglJb/K3doi4dw6q2IvAAmM/Y81kevy83wP+Sst+nutFTYOGg3d1lsxg==", - "dev": true + "dev": true, + "license": "MIT" }, "node_modules/goober": { "version": "2.1.12", @@ -10654,8 +10560,7 @@ }, "node_modules/html-parse-stringify": { "version": "3.0.1", - "resolved": "https://registry.npmjs.org/html-parse-stringify/-/html-parse-stringify-3.0.1.tgz", - "integrity": "sha512-KknJ50kTInJ7qIScF3jeaFRpMpE8/lfiTdzf/twXyPBLAGrLRTmkz3AdTnKeh40X8k9L2fdYwEp/42WGXIRGcg==", + "license": "MIT", "dependencies": { "void-elements": "3.1.0" } @@ -10787,8 +10692,6 @@ }, "node_modules/i18next": { "version": "22.4.15", - "resolved": "https://registry.npmjs.org/i18next/-/i18next-22.4.15.tgz", - "integrity": "sha512-yYudtbFrrmWKLEhl6jvKUYyYunj4bTBCe2qIUYAxbXoPusY7YmdwPvOE6fx6UIfWvmlbCWDItr7wIs8KEBZ5Zg==", "funding": [ { "type": "individual", @@ -10803,6 +10706,7 @@ "url": "https://www.i18next.com/how-to/faq#i18next-is-awesome.-how-can-i-support-the-project" } ], + "license": "MIT", "dependencies": { "@babel/runtime": "^7.20.6" } @@ -10816,8 +10720,7 @@ }, "node_modules/i18next-fs-backend": { "version": "2.1.1", - "resolved": "https://registry.npmjs.org/i18next-fs-backend/-/i18next-fs-backend-2.1.1.tgz", - "integrity": "sha512-FTnj+UmNgT3YRml5ruRv0jMZDG7odOL/OP5PF5mOqvXud2vHrPOOs68Zdk6iqzL47cnnM0ZVkK2BAvpFeDJToA==" + "license": "MIT" }, "node_modules/i18next-http-backend": { "version": "2.2.0", @@ -10828,8 +10731,7 @@ }, "node_modules/i18next-localstorage-backend": { "version": "4.1.1", - "resolved": "https://registry.npmjs.org/i18next-localstorage-backend/-/i18next-localstorage-backend-4.1.1.tgz", - "integrity": "sha512-gz3OP6m0jygF2SAzarDSFpaziYzF8mS8DP/pEUze+kDquzHTz2sy/eshcSkmFEYyGXMC037xUtlT97bNGlpZPA==", + "license": "MIT", "dependencies": { "@babel/runtime": "^7.20.6" } @@ -11512,6 +11414,17 @@ "url": "https://github.com/sponsors/ljharb" } }, + "node_modules/is-what": { + "version": "4.1.9", + "resolved": "https://registry.npmjs.org/is-what/-/is-what-4.1.9.tgz", + "integrity": "sha512-I3FU0rkVvwhgLLEs6iITwZ/JaLXe7tQcHyzupXky8jigt1vu4KM0UOqDr963j36JRvJ835EATVIm6MnGz/i1/g==", + "engines": { + "node": ">=12.13" + }, + "funding": { + "url": "https://github.com/sponsors/mesqueeb" + } + }, "node_modules/is-windows": { "version": "1.0.2", "dev": true, @@ -12452,10 +12365,6 @@ "version": "0.9.0", "license": "MIT" }, - "node_modules/js-sha3": { - "version": "0.8.0", - "license": "MIT" - }, "node_modules/js-string-escape": { "version": "1.0.1", "dev": true, @@ -13249,14 +13158,6 @@ "node": ">=0.10.0" } }, - "node_modules/match-sorter": { - "version": "6.3.1", - "license": "MIT", - "dependencies": { - "@babel/runtime": "^7.12.5", - "remove-accents": "0.4.2" - } - }, "node_modules/matcher": { "version": "5.0.0", "dev": true, @@ -13396,10 +13297,6 @@ "node": ">=8.6" } }, - "node_modules/microseconds": { - "version": "0.2.0", - "license": "MIT" - }, "node_modules/miller-rabin": { "version": "4.0.1", "dev": true, @@ -13605,13 +13502,6 @@ "optional": true, "peer": true }, - "node_modules/nano-time": { - "version": "1.0.0", - "license": "ISC", - "dependencies": { - "big-integer": "^1.6.16" - } - }, "node_modules/nanoid": { "version": "3.3.4", "license": "MIT", @@ -13787,6 +13677,82 @@ "dev": true, "license": "MIT" }, + "node_modules/next": { + "version": "13.4.2", + "resolved": "https://registry.npmjs.org/next/-/next-13.4.2.tgz", + "integrity": "sha512-aNFqLs3a3nTGvLWlO9SUhCuMUHVPSFQC0+tDNGAsDXqx+WJDFSbvc233gOJ5H19SBc7nw36A9LwQepOJ2u/8Kg==", + "dependencies": { + "@next/env": "13.4.2", + "@swc/helpers": "0.5.1", + "busboy": "1.6.0", + "caniuse-lite": "^1.0.30001406", + "postcss": "8.4.14", + "styled-jsx": "5.1.1", + "zod": "3.21.4" + }, + "bin": { + "next": "dist/bin/next" + }, + "engines": { + "node": ">=16.8.0" + }, + "optionalDependencies": { + "@next/swc-darwin-arm64": "13.4.2", + "@next/swc-darwin-x64": "13.4.2", + "@next/swc-linux-arm64-gnu": "13.4.2", + "@next/swc-linux-arm64-musl": "13.4.2", + "@next/swc-linux-x64-gnu": "13.4.2", + "@next/swc-linux-x64-musl": "13.4.2", + "@next/swc-win32-arm64-msvc": "13.4.2", + "@next/swc-win32-ia32-msvc": "13.4.2", + "@next/swc-win32-x64-msvc": "13.4.2" + }, + "peerDependencies": { + "@opentelemetry/api": "^1.1.0", + "fibers": ">= 3.1.0", + "node-sass": "^6.0.0 || ^7.0.0", + "react": "^18.2.0", + "react-dom": "^18.2.0", + "sass": "^1.3.0" + }, + "peerDependenciesMeta": { + "@opentelemetry/api": { + "optional": true + }, + "fibers": { + "optional": true + }, + "node-sass": { + "optional": true + }, + "sass": { + "optional": true + } + } + }, + "node_modules/next/node_modules/postcss": { + "version": "8.4.14", + "resolved": "https://registry.npmjs.org/postcss/-/postcss-8.4.14.tgz", + "integrity": "sha512-E398TUmfAYFPBSdzgeieK2Y1+1cpdxJx8yXbK/m57nRhKSmk1GB2tO4lbLBtlkfPQTDKfe4Xqv1ASWPpayPEig==", + "funding": [ + { + "type": "opencollective", + "url": "https://opencollective.com/postcss/" + }, + { + "type": "tidelift", + "url": "https://tidelift.com/funding/github/npm/postcss" + } + ], + "dependencies": { + "nanoid": "^3.3.4", + "picocolors": "^1.0.0", + "source-map-js": "^1.0.2" + }, + "engines": { + "node": "^10 || ^12 || >=14" + } + }, "node_modules/nice-try": { "version": "1.0.5", "license": "MIT" @@ -14199,10 +14165,6 @@ "url": "https://github.com/sponsors/ljharb" } }, - "node_modules/oblivious-set": { - "version": "1.0.0", - "license": "MIT" - }, "node_modules/on-finished": { "version": "2.4.1", "license": "MIT", @@ -14895,8 +14857,7 @@ }, "node_modules/playwright-core": { "version": "1.33.0", - "resolved": "https://registry.npmjs.org/playwright-core/-/playwright-core-1.33.0.tgz", - "integrity": "sha512-aizyPE1Cj62vAECdph1iaMILpT0WUDCq3E6rW6I+dleSbBoGbktvJtzS6VHkZ4DKNEOG9qJpiom/ZxO+S15LAw==", + "license": "Apache-2.0", "bin": { "playwright": "cli.js" }, @@ -15022,9 +14983,8 @@ }, "node_modules/prettier": { "version": "2.8.8", - "resolved": "https://registry.npmjs.org/prettier/-/prettier-2.8.8.tgz", - "integrity": "sha512-tdN8qQGvNjw4CHbY+XXk0JgCXn9QiF21a55rBe5LJAU+kDyC4WQn4+awm2Xfk2lQMk5fKup9XgzTZtGkjBdP9Q==", "dev": true, + "license": "MIT", "bin": { "prettier": "bin-prettier.js" }, @@ -15353,8 +15313,7 @@ }, "node_modules/react": { "version": "18.2.0", - "resolved": "https://registry.npmjs.org/react/-/react-18.2.0.tgz", - "integrity": "sha512-/3IjMdb2L9QbBdWiW5e3P2/npwMBaU9mHCSCUzNln0ZCYbcfTsGbTJrU/kGemdH2IWmB2ioZ+zkxtmq6g09fGQ==", + "license": "MIT", "dependencies": { "loose-envify": "^1.1.0" }, @@ -15423,8 +15382,7 @@ }, "node_modules/react-dom": { "version": "18.2.0", - "resolved": "https://registry.npmjs.org/react-dom/-/react-dom-18.2.0.tgz", - "integrity": "sha512-6IMTriUmvsjHUjNtEDudZfuDQUoWXVxKHhlEGSk81n4YFS+r/Kl99wXiwlVXtPBtJenozv2P+hxDsw9eA7Xo6g==", + "license": "MIT", "dependencies": { "loose-envify": "^1.1.0", "scheduler": "^0.23.0" @@ -15457,8 +15415,7 @@ }, "node_modules/react-i18next": { "version": "12.2.2", - "resolved": "https://registry.npmjs.org/react-i18next/-/react-i18next-12.2.2.tgz", - "integrity": "sha512-KBB6buBmVKXUWNxXHdnthp+38gPyBT46hJCAIQ8rX19NFL/m2ahte2KARfIDf2tMnSAL7wwck6eDOd/9zn6aFg==", + "license": "MIT", "dependencies": { "@babel/runtime": "^7.20.6", "html-parse-stringify": "^3.0.1" @@ -15532,30 +15489,6 @@ "react": "^16 || ^17 || ^18" } }, - "node_modules/react-query": { - "version": "3.39.3", - "license": "MIT", - "dependencies": { - "@babel/runtime": "^7.5.5", - "broadcast-channel": "^3.4.1", - "match-sorter": "^6.0.2" - }, - "funding": { - "type": "github", - "url": "https://github.com/sponsors/tannerlinsley" - }, - "peerDependencies": { - "react": "^16.8.0 || ^17.0.0 || ^18.0.0" - }, - "peerDependenciesMeta": { - "react-dom": { - "optional": true - }, - "react-native": { - "optional": true - } - } - }, "node_modules/react-shallow-renderer": { "version": "16.15.0", "dev": true, @@ -15570,7 +15503,8 @@ }, "node_modules/react-ssr-prepass": { "version": "1.5.0", - "license": "MIT", + "resolved": "https://registry.npmjs.org/react-ssr-prepass/-/react-ssr-prepass-1.5.0.tgz", + "integrity": "sha512-yFNHrlVEReVYKsLI5lF05tZoHveA5pGzjFbFJY/3pOqqjGOmMmqx83N4hIjN2n6E1AOa+eQEUxs3CgRnPmT0RQ==", "peerDependencies": { "react": "^16.8.0 || ^17.0.0 || ^18.0.0" } @@ -15815,7 +15749,8 @@ }, "node_modules/remove-accents": { "version": "0.4.2", - "license": "MIT" + "resolved": "https://registry.npmjs.org/remove-accents/-/remove-accents-0.4.2.tgz", + "integrity": "sha512-7pXIJqJOq5tFgG1A2Zxti3Ht8jJF337m4sowbuHsW30ZnkQFnDzy9qBNhgzX8ZLW4+UBcXiiR7SwR6pokHsxiA==" }, "node_modules/remove-trailing-separator": { "version": "1.1.0", @@ -16038,6 +15973,7 @@ }, "node_modules/rimraf": { "version": "3.0.2", + "dev": true, "license": "ISC", "dependencies": { "glob": "^7.1.3" @@ -16197,11 +16133,11 @@ } }, "node_modules/scheduler": { - "version": "0.20.2", - "license": "MIT", + "version": "0.23.0", + "resolved": "https://registry.npmjs.org/scheduler/-/scheduler-0.23.0.tgz", + "integrity": "sha512-CtuThmgHNg7zIZWAXi3AsyIzA3n4xx7aNyjwC2VJldO2LMVDhFK+63xGqq6CsJH4rTAt6/M+N4GhZiDYPx9eUw==", "dependencies": { - "loose-envify": "^1.1.0", - "object-assign": "^4.1.1" + "loose-envify": "^1.1.0" } }, "node_modules/schema-utils": { @@ -17050,8 +16986,6 @@ }, "node_modules/streamsearch": { "version": "1.1.0", - "resolved": "https://registry.npmjs.org/streamsearch/-/streamsearch-1.1.0.tgz", - "integrity": "sha512-Mcc5wHehp9aXz1ax6bZUyY5afg9u2rv5cqQI3mRrYkGC8rW2hM02jWuwjtL++LS5qinSyhj2QfLyNsuc+VsExg==", "engines": { "node": ">=10.0.0" } @@ -17207,8 +17141,7 @@ }, "node_modules/styled-jsx": { "version": "5.1.1", - "resolved": "https://registry.npmjs.org/styled-jsx/-/styled-jsx-5.1.1.tgz", - "integrity": "sha512-pW7uC1l4mBZ8ugbiZrcIsiIvVx1UmTfw7UkC3Um2tmfUq9Bhk8IiyEIPl6F8agHgjzku6j0xQEZbfA5uSgSaCw==", + "license": "MIT", "dependencies": { "client-only": "0.0.1" }, @@ -17227,6 +17160,17 @@ } } }, + "node_modules/superjson": { + "version": "1.12.3", + "resolved": "https://registry.npmjs.org/superjson/-/superjson-1.12.3.tgz", + "integrity": "sha512-0j+U70KUtP8+roVPbwfqkyQI7lBt7ETnuA7KXbTDX3mCKiD/4fXs2ldKSMdt0MCfpTwiMxo20yFU3vu6ewETpQ==", + "dependencies": { + "copy-anything": "^3.0.2" + }, + "engines": { + "node": ">=10" + } + }, "node_modules/supertap": { "version": "3.0.1", "dev": true, @@ -17389,9 +17333,8 @@ }, "node_modules/synckit": { "version": "0.8.5", - "resolved": "https://registry.npmjs.org/synckit/-/synckit-0.8.5.tgz", - "integrity": "sha512-L1dapNV6vu2s/4Sputv8xGsCdAVlb5nRDMFU/E27D44l5U6cw1g0dGd45uLc+OXjNMmF4ntiMdCimzcjFKQI8Q==", "dev": true, + "license": "MIT", "dependencies": { "@pkgr/utils": "^2.3.1", "tslib": "^2.5.0" @@ -17581,9 +17524,8 @@ }, "node_modules/tiny-glob": { "version": "0.2.9", - "resolved": "https://registry.npmjs.org/tiny-glob/-/tiny-glob-0.2.9.tgz", - "integrity": "sha512-g/55ssRPUjShh+xkfx9UPDXqhckHEsHr4Vd9zX55oSdGZc/MD0m3sferOkwWtp98bv+kcVfEHtRJgBVJzelrzg==", "dev": true, + "license": "MIT", "dependencies": { "globalyzer": "0.1.0", "globrex": "^0.1.2" @@ -17897,10 +17839,6 @@ "version": "4.1.3", "license": "MIT" }, - "node_modules/tsafe": { - "version": "0.10.1", - "license": "MIT" - }, "node_modules/tsc-alias": { "version": "1.8.3", "dev": true, @@ -18206,14 +18144,6 @@ "node": ">= 10.0.0" } }, - "node_modules/unload": { - "version": "2.2.0", - "license": "Apache-2.0", - "dependencies": { - "@babel/runtime": "^7.6.2", - "detect-node": "^2.0.4" - } - }, "node_modules/unpipe": { "version": "1.0.0", "license": "MIT", @@ -18388,8 +18318,7 @@ }, "node_modules/use-sync-external-store": { "version": "1.2.0", - "resolved": "https://registry.npmjs.org/use-sync-external-store/-/use-sync-external-store-1.2.0.tgz", - "integrity": "sha512-eEgnFxGQ1Ife9bzYs6VLi8/4X6CObHMw9Qr9tPY43iKwsPw8xE8+EFsf/2cFZ5S3esXgpWgtSCtLNS41F+sKPA==", + "license": "MIT", "peerDependencies": { "react": "^16.8.0 || ^17.0.0 || ^18.0.0" } @@ -18502,8 +18431,7 @@ }, "node_modules/void-elements": { "version": "3.1.0", - "resolved": "https://registry.npmjs.org/void-elements/-/void-elements-3.1.0.tgz", - "integrity": "sha512-Dhxzh5HZuiHQhbvTW9AMetFfBHDMYpo23Uo9btPXgdYP+3T5S+p+jgNy7spra+veYhBP2dCSgxR/i2Y02h5/6w==", + "license": "MIT", "engines": { "node": ">=0.10.0" } @@ -19480,8 +19408,9 @@ } }, "node_modules/zod": { - "version": "3.20.6", - "license": "MIT", + "version": "3.21.4", + "resolved": "https://registry.npmjs.org/zod/-/zod-3.21.4.tgz", + "integrity": "sha512-m46AKbrzKVzOzs/DZgVnG5H55N1sv1M8qZU3A8RIKbs3mrACDNeIOeilDymVb2HdmP8uwshOCF4uJ8uM9rCqJw==", "funding": { "url": "https://github.com/sponsors/colinhacks" } @@ -19506,8 +19435,7 @@ }, "node_modules/zustand": { "version": "4.3.7", - "resolved": "https://registry.npmjs.org/zustand/-/zustand-4.3.7.tgz", - "integrity": "sha512-dY8ERwB9Nd21ellgkBZFhudER8KVlelZm8388B5nDAXhO/+FZDhYMuRnqDgu5SYyRgz/iaf8RKnbUs/cHfOGlQ==", + "license": "MIT", "dependencies": { "use-sync-external-store": "1.2.0" },