From 73849aa6f043207e6e8bdbca78d2272489b1d437 Mon Sep 17 00:00:00 2001 From: Danijel Martinek Date: Mon, 13 Jul 2026 00:04:23 +0200 Subject: [PATCH] refactor(core-trpc): make the tRPC context router-agnostic Ports the type-safety/ergonomics half of the upstream cycle-break: core-trpc no longer imports AppRouter from @repo/core-api (an illegal core -> core-composition boundary edge). The runtime context and both providers are now AnyTRPCRouter-generic; consumers inject their router type via useTRPC(). Our tree is already cycle-free (the demo features that closed the cycle are deleted and no kept feature depends on core-trpc), so this is purely the architecture/boundary improvement. The per-feature app-slice types the upstream commit added for blog/marketing-pages/navigation are intentionally skipped: no kept feature consumes useTRPC yet, so there is nothing to type, and adding slice types now would be speculative. Co-Authored-By: Claude Opus 4.8 Claude-Session: https://claude.ai/code/session_016j8z4VHjedXDTjEDNg7qHK --- packages/core-trpc/package.json | 1 - packages/core-trpc/src/client.ts | 18 ++++++++++++++++-- packages/core-trpc/src/index.ts | 1 - .../core-trpc/src/providers/next-provider.tsx | 6 ++++-- .../src/providers/tanstack-provider.tsx | 6 ++++-- pnpm-lock.yaml | 3 --- 6 files changed, 24 insertions(+), 11 deletions(-) diff --git a/packages/core-trpc/package.json b/packages/core-trpc/package.json index 518bb50..d9b9db4 100644 --- a/packages/core-trpc/package.json +++ b/packages/core-trpc/package.json @@ -15,7 +15,6 @@ "test": "vitest run --passWithNoTests" }, "dependencies": { - "@repo/core-api": "workspace:*", "@tanstack/react-query": "^5.66.0", "@trpc/client": "^11.18.0", "@trpc/server": "^11.18.0", diff --git a/packages/core-trpc/src/client.ts b/packages/core-trpc/src/client.ts index 722b8c1..b0c68bf 100644 --- a/packages/core-trpc/src/client.ts +++ b/packages/core-trpc/src/client.ts @@ -1,6 +1,20 @@ "use client"; import { createTRPCContext } from "@trpc/tanstack-react-query"; -import type { AppRouter } from "@repo/core-api"; +import type { TRPCOptionsProxy } from "@trpc/tanstack-react-query"; +import type { AnyTRPCRouter } from "@trpc/server"; -export const { TRPCProvider, useTRPC } = createTRPCContext(); +// core-trpc must not depend on @repo/core-api (core → core-composition is an +// illegal boundary edge and creates a package cycle through the features). +// The runtime context is router-agnostic; consumers inject their router type +// as a generic: features pass their app-slice type (e.g. `BlogAppSlice`), +// apps may pass the full AppRouter. +const context = createTRPCContext(); + +export const TRPCProvider = context.TRPCProvider; + +export function useTRPC< + TRouter extends AnyTRPCRouter = AnyTRPCRouter, +>(): TRPCOptionsProxy { + return context.useTRPC() as unknown as TRPCOptionsProxy; +} diff --git a/packages/core-trpc/src/index.ts b/packages/core-trpc/src/index.ts index 7b27b5d..94a24e8 100644 --- a/packages/core-trpc/src/index.ts +++ b/packages/core-trpc/src/index.ts @@ -1,3 +1,2 @@ export { useTRPC, TRPCProvider } from "./client"; export { getQueryClient } from "./query-client"; -export type { AppRouter } from "@repo/core-api"; diff --git a/packages/core-trpc/src/providers/next-provider.tsx b/packages/core-trpc/src/providers/next-provider.tsx index dc4b9d8..0b24838 100644 --- a/packages/core-trpc/src/providers/next-provider.tsx +++ b/packages/core-trpc/src/providers/next-provider.tsx @@ -4,7 +4,7 @@ import { useState } from "react"; import { QueryClientProvider } from "@tanstack/react-query"; import { createTRPCClient, httpBatchLink } from "@trpc/client"; import superjson from "superjson"; -import type { AppRouter } from "@repo/core-api"; +import type { AnyTRPCRouter } from "@trpc/server"; import { TRPCProvider } from "../client"; import { getQueryClient } from "../query-client"; @@ -22,7 +22,9 @@ export function NextTrpcProvider({ }) { const [queryClient] = useState(() => getQueryClient()); const [trpcClient] = useState(() => - createTRPCClient({ + // Router-agnostic on purpose: procedure typing comes from useTRPC + // at the call sites, not from the wire-level client. + createTRPCClient({ links: [ httpBatchLink({ url: `${getBaseUrl()}${trpcUrl}`, diff --git a/packages/core-trpc/src/providers/tanstack-provider.tsx b/packages/core-trpc/src/providers/tanstack-provider.tsx index 0f48647..c5e46dc 100644 --- a/packages/core-trpc/src/providers/tanstack-provider.tsx +++ b/packages/core-trpc/src/providers/tanstack-provider.tsx @@ -4,7 +4,7 @@ import { useState } from "react"; import { QueryClientProvider } from "@tanstack/react-query"; import { createTRPCClient, httpBatchLink } from "@trpc/client"; import superjson from "superjson"; -import type { AppRouter } from "@repo/core-api"; +import type { AnyTRPCRouter } from "@trpc/server"; import { TRPCProvider } from "../client"; import { getQueryClient } from "../query-client"; @@ -17,7 +17,9 @@ export function TanstackTrpcProvider({ }) { const [queryClient] = useState(() => getQueryClient()); const [trpcClient] = useState(() => - createTRPCClient({ + // Router-agnostic on purpose: procedure typing comes from useTRPC + // at the call sites, not from the wire-level client. + createTRPCClient({ links: [httpBatchLink({ url: trpcUrl, transformer: superjson })], }), ); diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index fbbb0c0..c68edd4 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -914,9 +914,6 @@ importers: packages/core-trpc: dependencies: - "@repo/core-api": - specifier: workspace:* - version: link:../core-api "@tanstack/react-query": specifier: ^5.66.0 version: 5.96.2(react@19.2.4)