Initial commit

This commit is contained in:
fraqtal
2026-07-12 08:15:46 +00:00
commit ee0fec0691
1397 changed files with 127242 additions and 0 deletions

View File

@@ -0,0 +1,56 @@
# AGENTS.md — core-trpc
**Tag:** core-composition
Frontend tRPC platform providing the client and framework-specific providers (Next.js, TanStack). Bridges typed backend (`@repo/core-api`) to frontend applications. Tagged `core-composition` (not `core`) because it transitively reaches features through `core-api`'s `AppRouter` type.
## Responsibilities
- **Create tRPC React client** — `createTRPCReact<AppRouter>()` for use in React apps
- **Query client factory** — TanStack React Query setup per app
- **Framework-specific providers** — Next.js App Router provider + TanStack Start provider
- **No business logic** — purely framework integration
## Must NOT import
- Any feature package (`@repo/auth`, `@repo/blog`, etc.)
- Any app package
- `@repo/core-api`, `@repo/core-cms`, `@repo/core-ui`
## Public exports
From `package.json`:
- `.` — client + query client factory
- `./next` — Next.js App Router provider
- `./tanstack` — TanStack Start provider
Example usage:
```typescript
// In Next.js app
import { TrpcProvider } from "@repo/core-trpc/next";
// In TanStack Start app
import { TrpcProvider } from "@repo/core-trpc/tanstack";
// In client components
import { useTRPC } from "@repo/core-trpc";
const trpc = useTRPC();
```
## Test conventions
- No unit tests (provider layer)
- Verify at app boot: `pnpm dev --filter @repo/web-next` or `pnpm dev --filter @repo/web-tanstack` succeeds
- Verify client type safety: `pnpm typecheck` confirms `AppRouter` is imported and typed correctly
## Structure
```
src/
client.ts # createTRPCReact<AppRouter>()
query-client.ts # makeQueryClient()
providers/
next-provider.tsx # 'use client' provider for Next.js
tanstack-provider.tsx # Provider for TanStack Start
index.ts # re-exports client + factories
```

View File

@@ -0,0 +1,68 @@
---
package: "@tanstack/react-query"
version: "^5.66.0"
tier: core
decision: approved
date: 2026-05-14
deciders: [scaffolded]
adr: null
filter-results:
license: MIT
types: native
maintenance: active
boundary-fit: pass
shadow-check: pass
eu-residency: n/a
cve-scan: clean
named-consumer: pass
verification-commands:
- pnpm audit --audit-level=moderate
- npm view @tanstack/react-query license
accepted-cves: []
---
## Filter: license
MIT — on the workspace allowlist.
## Filter: types
Ships first-party TypeScript types in its distribution.
## Filter: maintenance
Active. Maintained by the TanStack team; v5 is the current stable major.
## Filter: boundary-fit
Core package (client-side). Used exclusively in `core-trpc` to power the React Query integration layer. No boundary rule violation.
## Filter: shadow-check
No other server-state library in the workspace. No shadow.
## Filter: eu-residency
Client-side state management; no network calls to vendor endpoints. n/a.
## Filter: cve-scan
No advisories at adoption time.
## Filter: named-consumer
`core-trpc` exposes the `QueryClient` and React Query hooks via `@trpc/react-query`.
## Prompt: replaces
Nothing — this is the initial tRPC scaffold.
## Prompt: migration-cost-out
Hard: query keys, cache invalidation patterns, and mutation hooks are all shaped around React Query's API.
## Prompt: alternatives-considered
1. **SWR** — narrower feature set; less aligned with tRPC's first-class React Query adapter.
2. **RTK Query** — Redux-bound; heavier than needed for this use case.
React Query is tRPC's canonical client-side data-fetching companion.

View File

@@ -0,0 +1,68 @@
---
package: "@trpc/client"
version: "^11.0.0"
tier: core
decision: approved
date: 2026-05-14
deciders: [scaffolded]
adr: null
filter-results:
license: MIT
types: native
maintenance: active
boundary-fit: pass
shadow-check: pass
eu-residency: n/a
cve-scan: clean
named-consumer: pass
verification-commands:
- pnpm audit --audit-level=moderate
- npm view @trpc/client license
accepted-cves: []
---
## Filter: license
MIT — on the workspace allowlist.
## Filter: types
Ships first-party TypeScript types; end-to-end type safety is the library's primary value.
## Filter: maintenance
Active. Maintained by the tRPC team; v11 is the current stable line.
## Filter: boundary-fit
Core package. `@trpc/client` is the companion to `@trpc/server` (present in `core-api`). No boundary rule violation.
## Filter: shadow-check
No competing RPC client in the workspace. No shadow.
## Filter: eu-residency
Client-side HTTP transport; calls the workspace's own tRPC server, no third-party vendor. n/a.
## Filter: cve-scan
No advisories at adoption time.
## Filter: named-consumer
`core-trpc` uses `@trpc/client` to build the typed HTTP client exposed to feature packages.
## Prompt: replaces
Nothing — this is the initial tRPC scaffold.
## Prompt: migration-cost-out
Hard: the typed client is tightly coupled to the server router type; replacing requires re-implementing the client abstraction.
## Prompt: alternatives-considered
1. **Plain fetch** — loses end-to-end type safety.
2. **GraphQL client** — significantly heavier; not aligned with the workspace API shape.
`@trpc/client` is the only viable companion to `@trpc/server`.

View File

@@ -0,0 +1,66 @@
---
package: "@trpc/react-query"
version: "^11.0.0"
tier: core
decision: approved
date: 2026-05-14
deciders: [scaffolded]
adr: null
filter-results:
license: MIT
types: native
maintenance: active
boundary-fit: pass
shadow-check: pass
eu-residency: n/a
cve-scan: clean
named-consumer: pass
verification-commands:
- pnpm audit --audit-level=moderate
- npm view @trpc/react-query license
accepted-cves: []
---
## Filter: license
MIT — on the workspace allowlist.
## Filter: types
Ships first-party TypeScript types; deeply integrated with tRPC's type inference.
## Filter: maintenance
Active. Maintained by the tRPC team alongside `@trpc/server` and `@trpc/client`.
## Filter: boundary-fit
Core package. The React Query integration bridge belongs in `core-trpc` alongside its sibling tRPC packages. No boundary rule violation.
## Filter: shadow-check
No other tRPCReact Query bridge in the workspace. No shadow.
## Filter: eu-residency
Client-side integration adapter; no vendor data transmission. n/a.
## Filter: cve-scan
No advisories at adoption time.
## Filter: named-consumer
`core-trpc` re-exports `@trpc/react-query` hooks for use in Next.js feature pages.
## Prompt: replaces
Nothing — this is the initial tRPC scaffold.
## Prompt: migration-cost-out
Hard: hooks are tRPC-procedure-typed; migrating away requires replacing all call sites.
## Prompt: alternatives-considered
This package is the canonical integration point between `@trpc/client` and `@tanstack/react-query`. No viable alternative exists.

View File

@@ -0,0 +1,68 @@
---
package: "@trpc/server"
version: "^11.0.0"
tier: core
decision: approved
date: 2026-05-14
deciders: [scaffolded]
adr: null
filter-results:
license: MIT
types: native
maintenance: active
boundary-fit: pass
shadow-check: pass
eu-residency: n/a
cve-scan: clean
named-consumer: pass
verification-commands:
- pnpm audit --audit-level=moderate
- npm view @trpc/server license
accepted-cves: []
---
## Filter: license
MIT — on the workspace allowlist.
## Filter: types
Ships first-party TypeScript types; type-safe by design.
## Filter: maintenance
Active. Maintained by the tRPC team; v11 is the current stable line.
## Filter: boundary-fit
Core package. `@trpc/server` is also present in `core-api`; using the same version in `core-trpc` for router type inference is the intended usage pattern.
## Filter: shadow-check
`@trpc/server` is workspace-present via `core-api`. Same major version; no shadow.
## Filter: eu-residency
Server-side RPC framework; no vendor data transmission. n/a.
## Filter: cve-scan
No advisories at adoption time.
## Filter: named-consumer
`core-trpc` re-exports tRPC router types and the `t` initializer used by feature routers.
## Prompt: replaces
Nothing — tRPC is already the workspace API layer via `core-api`.
## Prompt: migration-cost-out
Hard: router types, procedure definitions, and middleware are tRPC-shaped across the entire workspace.
## Prompt: alternatives-considered
1. **REST + OpenAPI** — loses end-to-end type safety; see ADR-022 context for why this was rejected.
2. **GraphQL** — significantly heavier; not aligned with the workspace API shape.
tRPC is the locked workspace API library.

View File

@@ -0,0 +1,66 @@
---
package: "@trpc/tanstack-react-query"
version: "^11.1.0"
tier: core
decision: approved
date: 2026-05-14
deciders: [scaffolded]
adr: null
filter-results:
license: MIT
types: native
maintenance: active
boundary-fit: pass
shadow-check: pass
eu-residency: n/a
cve-scan: clean
named-consumer: pass
verification-commands:
- pnpm audit --audit-level=moderate
- npm view @trpc/tanstack-react-query license
accepted-cves: []
---
## Filter: license
MIT — on the workspace allowlist.
## Filter: types
Ships first-party TypeScript types; part of the tRPC v11 adapter suite.
## Filter: maintenance
Active. Maintained by the tRPC team as part of the v11 TanStack Start integration.
## Filter: boundary-fit
Core package. Required for the TanStack Start provider (`core-trpc/tanstack`). No boundary rule violation.
## Filter: shadow-check
No duplicate TanStack adapter in the workspace. No shadow.
## Filter: eu-residency
Client-side integration adapter; no vendor data transmission. n/a.
## Filter: cve-scan
No advisories at adoption time.
## Filter: named-consumer
`core-trpc` exposes a TanStack Start provider via `@trpc/tanstack-react-query` for `apps/web-tanstack`.
## Prompt: replaces
Nothing — this is the initial tRPC scaffold.
## Prompt: migration-cost-out
Hard: the TanStack provider is shaped around this adapter's API; replacing requires re-implementing the provider.
## Prompt: alternatives-considered
This is the official tRPC adapter for TanStack Start. No viable alternative exists.

View File

@@ -0,0 +1,66 @@
---
package: react
version: "^19.0.0"
tier: core
decision: approved
date: 2026-05-14
deciders: [scaffolded]
adr: null
filter-results:
license: MIT
types: "@types/react"
maintenance: active
boundary-fit: pass
shadow-check: pass
eu-residency: n/a
cve-scan: clean
named-consumer: pass
verification-commands:
- pnpm audit --audit-level=moderate
- npm view react license
accepted-cves: []
---
## Filter: license
MIT — on the workspace allowlist.
## Filter: types
TypeScript types via `@types/react` (community-maintained but canonical; ships in sync with each React major).
## Filter: maintenance
Active. Maintained by Meta; v19 is the current stable major.
## Filter: boundary-fit
Core package (client-side). React is already present in app packages; exposing it from `core-trpc` for provider components is standard practice.
## Filter: shadow-check
React is already workspace-present in app packages. Same major version; no shadow.
## Filter: eu-residency
Client-side rendering library; no vendor data transmission. n/a.
## Filter: cve-scan
No advisories at adoption time.
## Filter: named-consumer
`core-trpc` uses React to implement the `TRPCProvider` and `QueryClientProvider` wrapper components.
## Prompt: replaces
Nothing — React is already the UI framework in the workspace.
## Prompt: migration-cost-out
Impossible: React is the foundational UI library for this workspace.
## Prompt: alternatives-considered
React is workspace-locked as the UI framework. No alternative evaluated.

View File

@@ -0,0 +1,68 @@
---
package: superjson
version: "^2.2.1"
tier: core
decision: approved
date: 2026-05-14
deciders: [scaffolded]
adr: null
filter-results:
license: MIT
types: native
maintenance: active
boundary-fit: pass
shadow-check: pass
eu-residency: n/a
cve-scan: clean
named-consumer: pass
verification-commands:
- pnpm audit --audit-level=moderate
- npm view superjson license
accepted-cves: []
---
## Filter: license
MIT — on the workspace allowlist.
## Filter: types
Ships first-party TypeScript types in its distribution.
## Filter: maintenance
Active. Currently maintained by the tRPC team after the original author transferred stewardship.
## Filter: boundary-fit
Core package. superjson is used exclusively in `core-trpc` as the tRPC transformer; no feature package imports it directly.
## Filter: shadow-check
No competing JSON-extended serializer in the workspace. No shadow.
## Filter: eu-residency
Pure serialization library; no network calls or vendor data transmission. n/a.
## Filter: cve-scan
No advisories at adoption time.
## Filter: named-consumer
`core-trpc` uses superjson as the tRPC transformer to support `Date`, `Map`, `Set`, and other non-JSON-native types over the wire.
## Prompt: replaces
Nothing — this is the initial tRPC scaffold.
## Prompt: migration-cost-out
Mechanical: swap transformer in the tRPC init; update client config. No data-storage coupling.
## Prompt: alternatives-considered
1. **devalue** — no stable npm release at adoption time.
2. **Plain JSON** — loses Date/Map/Set round-trip support required by the workspace's domain models.
superjson is the tRPC-canonical transformer for extended types.

View File

@@ -0,0 +1,3 @@
import baseConfig from "@repo/core-eslint/base";
export default baseConfig;

View File

@@ -0,0 +1,37 @@
{
"name": "@repo/core-trpc",
"private": true,
"version": "0.0.0",
"type": "module",
"exports": {
".": "./src/index.ts",
"./next": "./src/providers/next-provider.tsx",
"./tanstack": "./src/providers/tanstack-provider.tsx"
},
"scripts": {
"build": "tsc --noEmit",
"lint": "eslint .",
"typecheck": "tsc --noEmit",
"test": "vitest run --passWithNoTests"
},
"dependencies": {
"@repo/core-api": "workspace:*",
"@trpc/client": "^11.0.0",
"@trpc/react-query": "^11.0.0",
"@trpc/server": "^11.0.0",
"@trpc/tanstack-react-query": "^11.1.0",
"@tanstack/react-query": "^5.66.0",
"react": "^19.0.0",
"superjson": "^2.2.1"
},
"devDependencies": {
"@repo/core-eslint": "workspace:*",
"@repo/core-testing": "workspace:*",
"@repo/core-typescript": "workspace:*",
"@testing-library/jest-dom": "^6.5.0",
"@testing-library/react": "^16.0.0",
"@types/react": "^19.0.0",
"jsdom": "^25.0.0",
"vitest": "^3.0.0"
}
}

View File

@@ -0,0 +1,12 @@
import { describe, it, expect } from "vitest";
import { useTRPC, TRPCProvider } from "./client";
describe("core-trpc client exports", () => {
it("exports useTRPC hook", () => {
expect(useTRPC).toBeTypeOf("function");
});
it("exports TRPCProvider component", () => {
expect(TRPCProvider).toBeTypeOf("function");
});
});

View File

@@ -0,0 +1,6 @@
"use client";
import { createTRPCContext } from "@trpc/tanstack-react-query";
import type { AppRouter } from "@repo/core-api";
export const { TRPCProvider, useTRPC } = createTRPCContext<AppRouter>();

View File

@@ -0,0 +1,3 @@
export { useTRPC, TRPCProvider } from "./client";
export { getQueryClient } from "./query-client";
export type { AppRouter } from "@repo/core-api";

View File

@@ -0,0 +1,32 @@
"use client";
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 { TRPCProvider } from "../client";
import { getQueryClient } from "../query-client";
export function NextTrpcProvider({
children,
trpcUrl = "/api/trpc",
}: {
children: React.ReactNode;
trpcUrl?: string;
}) {
const [queryClient] = useState(() => getQueryClient());
const [trpcClient] = useState(() =>
createTRPCClient<AppRouter>({
links: [httpBatchLink({ url: trpcUrl, transformer: superjson })],
}),
);
return (
<TRPCProvider trpcClient={trpcClient} queryClient={queryClient}>
<QueryClientProvider client={queryClient}>
{children}
</QueryClientProvider>
</TRPCProvider>
);
}

View File

@@ -0,0 +1,32 @@
"use client";
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 { TRPCProvider } from "../client";
import { getQueryClient } from "../query-client";
export function TanstackTrpcProvider({
children,
trpcUrl,
}: {
children: React.ReactNode;
trpcUrl: string;
}) {
const [queryClient] = useState(() => getQueryClient());
const [trpcClient] = useState(() =>
createTRPCClient<AppRouter>({
links: [httpBatchLink({ url: trpcUrl, transformer: superjson })],
}),
);
return (
<TRPCProvider trpcClient={trpcClient} queryClient={queryClient}>
<QueryClientProvider client={queryClient}>
{children}
</QueryClientProvider>
</TRPCProvider>
);
}

View File

@@ -0,0 +1,22 @@
import { QueryClient } from "@tanstack/react-query";
let clientQueryClient: QueryClient | undefined;
const defaultOptions = {
queries: {
staleTime: 30 * 1000,
refetchOnWindowFocus: false,
},
};
export function getQueryClient(): QueryClient {
if (typeof window === "undefined") {
// Server: always create a new instance per request
return new QueryClient({ defaultOptions });
}
// Browser: singleton
if (!clientQueryClient) {
clientQueryClient = new QueryClient({ defaultOptions });
}
return clientQueryClient;
}

View File

@@ -0,0 +1,17 @@
{
"extends": "@repo/core-typescript/base.json",
"compilerOptions": {
"outDir": "dist",
"rootDir": ".",
"lib": ["ES2022", "DOM"],
"jsx": "preserve",
"declaration": false,
"declarationMap": false,
"types": ["vitest/globals", "@testing-library/jest-dom"],
"paths": {
"@/*": ["./src/*"]
}
},
"include": ["src/**/*"],
"exclude": ["node_modules", "dist"]
}

View File

@@ -0,0 +1,4 @@
{
"extends": ["//"],
"tags": ["core-composition"]
}

View File

@@ -0,0 +1,7 @@
import path from "node:path";
import { mergeConfig } from "vitest/config";
import { jsdomVitestConfig } from "@repo/core-typescript/vitest.base.jsdom";
export default mergeConfig(jsdomVitestConfig, {
resolve: { alias: { "@": path.resolve(__dirname, "./src") } },
});