From 8da107a446fd0ad840fbd4a2917c5ec302f2b1e4 Mon Sep 17 00:00:00 2001 From: Danijel Martinek Date: Mon, 6 Apr 2026 14:49:10 +0200 Subject: [PATCH] feat(api-client): add tRPC React Query provider and shared hooks --- packages/api-client/package.json | 10 +++- packages/api-client/src/index.ts | 5 +- packages/api-client/src/provider.tsx | 26 ++++++++++ packages/api-client/src/query-client.ts | 21 ++++++++ packages/api-client/src/trpc.ts | 4 ++ pnpm-lock.yaml | 64 +++++++++++++++++++++++++ 6 files changed, 127 insertions(+), 3 deletions(-) create mode 100644 packages/api-client/src/provider.tsx create mode 100644 packages/api-client/src/query-client.ts create mode 100644 packages/api-client/src/trpc.ts diff --git a/packages/api-client/package.json b/packages/api-client/package.json index 6a9acde..e5d2132 100644 --- a/packages/api-client/package.json +++ b/packages/api-client/package.json @@ -10,8 +10,16 @@ "lint": "eslint .", "typecheck": "tsc --noEmit" }, + "dependencies": { + "@repo/api": "workspace:*", + "@trpc/client": "^11.1.0", + "@trpc/tanstack-react-query": "^11.1.0", + "@tanstack/react-query": "^5.75.0", + "react": "^19.0.0" + }, "devDependencies": { "@repo/eslint-config": "workspace:*", - "@repo/typescript-config": "workspace:*" + "@repo/typescript-config": "workspace:*", + "@types/react": "^19.0.0" } } diff --git a/packages/api-client/src/index.ts b/packages/api-client/src/index.ts index 6a22c42..7a30ddd 100644 --- a/packages/api-client/src/index.ts +++ b/packages/api-client/src/index.ts @@ -1,2 +1,3 @@ -// @repo/api-client — Shared React Query hooks -export {}; +export { ApiProvider } from "./provider.js"; +export { useTRPC } from "./trpc.js"; +export { getQueryClient } from "./query-client.js"; diff --git a/packages/api-client/src/provider.tsx b/packages/api-client/src/provider.tsx new file mode 100644 index 0000000..f8bb215 --- /dev/null +++ b/packages/api-client/src/provider.tsx @@ -0,0 +1,26 @@ +"use client"; + +import { QueryClientProvider } from "@tanstack/react-query"; +import { createTRPCClient, httpBatchLink } from "@trpc/client"; +import type { AppRouter } from "@repo/api"; +import { TRPCProvider } from "./trpc.js"; +import { getQueryClient } from "./query-client.js"; + +export function ApiProvider({ + children, + trpcUrl, +}: { + children: React.ReactNode; + trpcUrl: string; +}) { + const queryClient = getQueryClient(); + const trpcClient = createTRPCClient({ + links: [httpBatchLink({ url: trpcUrl })], + }); + + return ( + + {children} + + ); +} diff --git a/packages/api-client/src/query-client.ts b/packages/api-client/src/query-client.ts new file mode 100644 index 0000000..049c7fb --- /dev/null +++ b/packages/api-client/src/query-client.ts @@ -0,0 +1,21 @@ +import { QueryClient } from "@tanstack/react-query"; + +let clientQueryClient: QueryClient | undefined; + +export function getQueryClient(): QueryClient { + if (typeof window === "undefined") { + return new QueryClient({ + defaultOptions: { + queries: { staleTime: 30 * 1000 }, + }, + }); + } + if (!clientQueryClient) { + clientQueryClient = new QueryClient({ + defaultOptions: { + queries: { staleTime: 30 * 1000 }, + }, + }); + } + return clientQueryClient; +} diff --git a/packages/api-client/src/trpc.ts b/packages/api-client/src/trpc.ts new file mode 100644 index 0000000..7f68126 --- /dev/null +++ b/packages/api-client/src/trpc.ts @@ -0,0 +1,4 @@ +import { createTRPCContext } from "@trpc/tanstack-react-query"; +import type { AppRouter } from "@repo/api"; + +export const { TRPCProvider, useTRPC } = createTRPCContext(); diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index 3d3c4bf..d25a14f 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -129,6 +129,22 @@ importers: version: 22.19.17 packages/api-client: + dependencies: + '@repo/api': + specifier: workspace:* + version: link:../api + '@tanstack/react-query': + specifier: ^5.75.0 + version: 5.96.2(react@19.2.4) + '@trpc/client': + specifier: ^11.1.0 + version: 11.16.0(@trpc/server@11.16.0(typescript@5.9.3))(typescript@5.9.3) + '@trpc/tanstack-react-query': + specifier: ^11.1.0 + version: 11.16.0(@tanstack/react-query@5.96.2(react@19.2.4))(@trpc/client@11.16.0(@trpc/server@11.16.0(typescript@5.9.3))(typescript@5.9.3))(@trpc/server@11.16.0(typescript@5.9.3))(react@19.2.4)(typescript@5.9.3) + react: + specifier: ^19.0.0 + version: 19.2.4 devDependencies: '@repo/eslint-config': specifier: workspace:* @@ -136,6 +152,9 @@ importers: '@repo/typescript-config': specifier: workspace:* version: link:../typescript-config + '@types/react': + specifier: ^19.0.0 + version: 19.2.14 packages/cms-client: dependencies: @@ -1552,6 +1571,14 @@ packages: '@swc/helpers@0.5.15': resolution: {integrity: sha512-JQ5TuMi45Owi4/BIMAJBoSQoOJu12oOk/gADqlcUL9JEdHB8vyjUSsxqeNXnmXHjYKMi2WcYtezGEEhqUI/E2g==} + '@tanstack/query-core@5.96.2': + resolution: {integrity: sha512-hzI6cTVh4KNRk8UtoIBS7Lv9g6BnJPXvBKsvYH1aGWvv0347jT3BnSvztOE+kD76XGvZnRC/t6qdW1CaIfwCeA==} + + '@tanstack/react-query@5.96.2': + resolution: {integrity: sha512-sYyzzJT4G0g02azzJ8o55VFFV31XvFpdUpG+unxS0vSaYsJnSPKGoI6WdPwUucJL1wpgGfwfmntNX/Ub1uOViA==} + peerDependencies: + react: ^18 || ^19 + '@tokenizer/inflate@0.4.1': resolution: {integrity: sha512-2mAv+8pkG6GIZiF1kNg1jAjh27IDxEPKwdGul3snfztFerfPGI1LjDezZp3i7BElXompqEtPmoPx6c2wgtWsOA==} engines: {node: '>=18'} @@ -1559,12 +1586,29 @@ packages: '@tokenizer/token@0.3.0': resolution: {integrity: sha512-OvjF+z51L3ov0OyAU0duzsYuvO01PH7x4t6DJx+guahgTnBHkhJdG7soQeTSFLWN3efnHyibZ4Z8l2EuWwJN3A==} + '@trpc/client@11.16.0': + resolution: {integrity: sha512-TxIzm7OoK3baKZ0XCbuMUbI3GhgjcbKHIc4nWVKaRpCRnbSh0T31BT6fTPYwtnA/Nur8pBCGqC2B4J5hEPiPFQ==} + hasBin: true + peerDependencies: + '@trpc/server': 11.16.0 + typescript: '>=5.7.2' + '@trpc/server@11.16.0': resolution: {integrity: sha512-XgGuUMddrUTd04+za/WE5GFuZ1/YU9XQG0t3VL5WOIu2JspkOlq6k4RYEiqS6HSJt+S0RXaPdIoE2anIP/BBRQ==} hasBin: true peerDependencies: typescript: '>=5.7.2' + '@trpc/tanstack-react-query@11.16.0': + resolution: {integrity: sha512-kfNYJ5NCk67tmRCO/QWCycJmRamuEKmZf1HRG8yCBl8aTJdTwVq7l6AffFIMab3Q+NmQzwP8XXkAEK/EelKYOA==} + hasBin: true + peerDependencies: + '@tanstack/react-query': ^5.80.3 + '@trpc/client': 11.16.0 + '@trpc/server': 11.16.0 + react: '>=18.2.0' + typescript: '>=5.7.2' + '@turbo/darwin-64@2.9.4': resolution: {integrity: sha512-ZSlPqJ5Vqg/wgVw8P3AOVCIosnbBilOxLq7TMz3MN/9U46DUYfdG2jtfevNDufyxyrg98pcPs/GBgDRaaids6g==} cpu: [x64] @@ -4692,6 +4736,13 @@ snapshots: dependencies: tslib: 2.8.1 + '@tanstack/query-core@5.96.2': {} + + '@tanstack/react-query@5.96.2(react@19.2.4)': + dependencies: + '@tanstack/query-core': 5.96.2 + react: 19.2.4 + '@tokenizer/inflate@0.4.1': dependencies: debug: 4.4.3 @@ -4701,10 +4752,23 @@ snapshots: '@tokenizer/token@0.3.0': {} + '@trpc/client@11.16.0(@trpc/server@11.16.0(typescript@5.9.3))(typescript@5.9.3)': + dependencies: + '@trpc/server': 11.16.0(typescript@5.9.3) + typescript: 5.9.3 + '@trpc/server@11.16.0(typescript@5.9.3)': dependencies: typescript: 5.9.3 + '@trpc/tanstack-react-query@11.16.0(@tanstack/react-query@5.96.2(react@19.2.4))(@trpc/client@11.16.0(@trpc/server@11.16.0(typescript@5.9.3))(typescript@5.9.3))(@trpc/server@11.16.0(typescript@5.9.3))(react@19.2.4)(typescript@5.9.3)': + dependencies: + '@tanstack/react-query': 5.96.2(react@19.2.4) + '@trpc/client': 11.16.0(@trpc/server@11.16.0(typescript@5.9.3))(typescript@5.9.3) + '@trpc/server': 11.16.0(typescript@5.9.3) + react: 19.2.4 + typescript: 5.9.3 + '@turbo/darwin-64@2.9.4': optional: true