diff --git a/.changeset/loud-ways-flash.md b/.changeset/loud-ways-flash.md new file mode 100644 index 0000000000..9060979dff --- /dev/null +++ b/.changeset/loud-ways-flash.md @@ -0,0 +1,5 @@ +--- +"create-t3-app": minor +--- + +export helper procedures for trpc instead of the `t`-object diff --git a/cli/src/installers/index.ts b/cli/src/installers/index.ts index a87051bc76..919c44f5cf 100644 --- a/cli/src/installers/index.ts +++ b/cli/src/installers/index.ts @@ -37,10 +37,10 @@ export const dependencyVersionMap = { "prettier-plugin-tailwindcss": "^0.1.13", // tRPC - "@trpc/client": "10.0.0-proxy-beta.15", - "@trpc/server": "10.0.0-proxy-beta.15", - "@trpc/react": "10.0.0-proxy-beta.15", - "@trpc/next": "10.0.0-proxy-beta.15", + "@trpc/client": "10.0.0-proxy-beta.17", + "@trpc/server": "10.0.0-proxy-beta.17", + "@trpc/react": "10.0.0-proxy-beta.17", + "@trpc/next": "10.0.0-proxy-beta.17", "@tanstack/react-query": "^4.10.0", superjson: "1.9.1", } as const; diff --git a/cli/template/addons/trpc/auth-context.ts b/cli/template/addons/trpc/auth-context.ts index 329596411a..7395a067f1 100644 --- a/cli/template/addons/trpc/auth-context.ts +++ b/cli/template/addons/trpc/auth-context.ts @@ -1,7 +1,7 @@ // src/server/router/context.ts -import * as trpc from "@trpc/server"; -import * as trpcNext from "@trpc/server/adapters/next"; -import { Session } from "next-auth"; +import type { inferAsyncReturnType } from "@trpc/server"; +import type { CreateNextContextOptions } from "@trpc/server/adapters/next"; +import type { Session } from "next-auth"; import { getServerAuthSession } from "../common/get-server-auth-session"; type CreateContextOptions = { @@ -22,9 +22,7 @@ export const createContextInner = async (opts: CreateContextOptions) => { * This is the actual context you'll use in your router * @link https://trpc.io/docs/context **/ -export const createContext = async ( - opts: trpcNext.CreateNextContextOptions, -) => { +export const createContext = async (opts: CreateNextContextOptions) => { const { req, res } = opts; // Get the session from the server using the unstable_getServerSession wrapper function @@ -35,4 +33,4 @@ export const createContext = async ( }); }; -export type Context = trpc.inferAsyncReturnType; +export type Context = inferAsyncReturnType; diff --git a/cli/template/addons/trpc/auth-index-router.ts b/cli/template/addons/trpc/auth-index-router.ts index 4c1cbd604b..147ddd2b9b 100644 --- a/cli/template/addons/trpc/auth-index-router.ts +++ b/cli/template/addons/trpc/auth-index-router.ts @@ -1,9 +1,9 @@ // src/server/trpc/router/index.ts -import { t } from "../trpc"; +import { router } from "../trpc"; import { exampleRouter } from "./example"; import { authRouter } from "./auth"; -export const appRouter = t.router({ +export const appRouter = router({ example: exampleRouter, auth: authRouter, }); diff --git a/cli/template/addons/trpc/auth-prisma-context.ts b/cli/template/addons/trpc/auth-prisma-context.ts index 5005ece539..ceb192384e 100644 --- a/cli/template/addons/trpc/auth-prisma-context.ts +++ b/cli/template/addons/trpc/auth-prisma-context.ts @@ -1,7 +1,7 @@ // src/server/router/context.ts -import * as trpc from "@trpc/server"; -import * as trpcNext from "@trpc/server/adapters/next"; -import { Session } from "next-auth"; +import type { inferAsyncReturnType } from "@trpc/server"; +import type { CreateNextContextOptions } from "@trpc/server/adapters/next"; +import type { Session } from "next-auth"; import { getServerAuthSession } from "../common/get-server-auth-session"; import { prisma } from "../db/client"; @@ -24,9 +24,7 @@ export const createContextInner = async (opts: CreateContextOptions) => { * This is the actual context you'll use in your router * @link https://trpc.io/docs/context **/ -export const createContext = async ( - opts: trpcNext.CreateNextContextOptions, -) => { +export const createContext = async (opts: CreateNextContextOptions) => { const { req, res } = opts; // Get the session from the server using the unstable_getServerSession wrapper function @@ -37,4 +35,4 @@ export const createContext = async ( }); }; -export type Context = trpc.inferAsyncReturnType; +export type Context = inferAsyncReturnType; diff --git a/cli/template/addons/trpc/auth-router.ts b/cli/template/addons/trpc/auth-router.ts index ecadafc17c..cb56beaf51 100644 --- a/cli/template/addons/trpc/auth-router.ts +++ b/cli/template/addons/trpc/auth-router.ts @@ -1,10 +1,10 @@ -import { t, authedProcedure } from "../trpc"; +import { router, publicProcedure, protectedProcedure } from "../trpc"; -export const authRouter = t.router({ - getSession: t.procedure.query(({ ctx }) => { +export const authRouter = router({ + getSession: publicProcedure.query(({ ctx }) => { return ctx.session; }), - getSecretMessage: authedProcedure.query(() => { + getSecretMessage: protectedProcedure.query(() => { return "You are logged in and can see this secret message!"; }), }); diff --git a/cli/template/addons/trpc/auth-server-utils.ts b/cli/template/addons/trpc/auth-server-utils.ts index e0a7f966d0..1befc97bf7 100644 --- a/cli/template/addons/trpc/auth-server-utils.ts +++ b/cli/template/addons/trpc/auth-server-utils.ts @@ -2,22 +2,37 @@ import { initTRPC, TRPCError } from "@trpc/server"; import type { Context } from "./context"; import superjson from "superjson"; -export const t = initTRPC.context().create({ +const t = initTRPC.context().create({ transformer: superjson, errorFormatter({ shape }) { return shape; }, }); -export const authedProcedure = t.procedure.use(({ ctx, next }) => { +export const router = t.router; + +/** + * Unprotected procedure + **/ +export const publicProcedure = t.procedure; + +/** + * Reusable middleware to ensure + * users are logged in + */ +const isAuthed = t.middleware(({ ctx, next }) => { if (!ctx.session || !ctx.session.user) { throw new TRPCError({ code: "UNAUTHORIZED" }); } return next({ ctx: { - ...ctx, - // infers that `session` is non-nullable to downstream resolvers + // infers the `session` as non-nullable session: { ...ctx.session, user: ctx.session.user }, }, }); }); + +/** + * Protected procedure + **/ +export const protectedProcedure = t.procedure.use(isAuthed); diff --git a/cli/template/addons/trpc/example-prisma-router.ts b/cli/template/addons/trpc/example-prisma-router.ts index 19bd54719c..c31aff894b 100644 --- a/cli/template/addons/trpc/example-prisma-router.ts +++ b/cli/template/addons/trpc/example-prisma-router.ts @@ -1,15 +1,15 @@ -import { t } from "../trpc"; +import { router, publicProcedure } from "../trpc"; import { z } from "zod"; -export const exampleRouter = t.router({ - hello: t.procedure +export const exampleRouter = router({ + hello: publicProcedure .input(z.object({ text: z.string().nullish() }).nullish()) .query(({ input }) => { return { greeting: `Hello ${input?.text ?? "world"}`, }; }), - getAll: t.procedure.query(({ ctx }) => { + getAll: publicProcedure.query(({ ctx }) => { return ctx.prisma.example.findMany(); }), }); diff --git a/cli/template/addons/trpc/example-router.ts b/cli/template/addons/trpc/example-router.ts index 862af160da..c8360e493d 100644 --- a/cli/template/addons/trpc/example-router.ts +++ b/cli/template/addons/trpc/example-router.ts @@ -1,8 +1,8 @@ -import { t } from "../trpc"; +import { router, publicProcedure } from "../trpc"; import { z } from "zod"; -export const exampleRouter = t.router({ - hello: t.procedure +export const exampleRouter = router({ + hello: publicProcedure .input(z.object({ text: z.string().nullish() }).nullish()) .query(({ input }) => { return { diff --git a/cli/template/addons/trpc/index-router.ts b/cli/template/addons/trpc/index-router.ts index 8bf30919c0..8b28185428 100644 --- a/cli/template/addons/trpc/index-router.ts +++ b/cli/template/addons/trpc/index-router.ts @@ -1,9 +1,9 @@ // src/server/router/index.ts -import { t } from "../trpc"; +import { router } from "../trpc"; import { exampleRouter } from "./example"; -export const appRouter = t.router({ +export const appRouter = router({ example: exampleRouter, }); diff --git a/cli/template/addons/trpc/prisma-context.ts b/cli/template/addons/trpc/prisma-context.ts index ddc9db2009..6855eba057 100644 --- a/cli/template/addons/trpc/prisma-context.ts +++ b/cli/template/addons/trpc/prisma-context.ts @@ -1,6 +1,6 @@ // src/server/router/context.ts -import * as trpc from "@trpc/server"; -import * as trpcNext from "@trpc/server/adapters/next"; +import type { inferAsyncReturnType } from "@trpc/server"; +import type { CreateNextContextOptions } from "@trpc/server/adapters/next"; import { prisma } from "../db/client"; /** @@ -22,10 +22,8 @@ export const createContextInner = async (opts: CreateContextOptions) => { * This is the actual context you'll use in your router * @link https://trpc.io/docs/context **/ -export const createContext = async ( - opts: trpcNext.CreateNextContextOptions, -) => { +export const createContext = async (opts: CreateNextContextOptions) => { return await createContextInner({}); }; -export type Context = trpc.inferAsyncReturnType; +export type Context = inferAsyncReturnType; diff --git a/cli/template/addons/trpc/server-utils.ts b/cli/template/addons/trpc/server-utils.ts index d4984fbe17..e0d41e124e 100644 --- a/cli/template/addons/trpc/server-utils.ts +++ b/cli/template/addons/trpc/server-utils.ts @@ -2,9 +2,13 @@ import { initTRPC } from "@trpc/server"; import type { Context } from "./context"; import superjson from "superjson"; -export const t = initTRPC.context().create({ +const t = initTRPC.context().create({ transformer: superjson, errorFormatter({ shape }) { return shape; }, }); + +export const router = t.router; + +export const publicProcedure = t.procedure;