ignacio
ignacio
TTCTheo's Typesafe Cult
Created by ignacio on 8/3/2023 in #questions
T3 - app dir - tRPC + Prisma + Custom auth
Hello! Is there an alternative to using the createAction function for mutations and deletions on the client? I'm implementing it in a new app directory, and while fetching data is smooth, creating or editing data is challenging. I can't get the req in createInnerTRPCContext, so I can't access the cookie to verify authentication. Can I use createTRPCContext instead of createInnerTRPCContext for actions?
interface CreateContextOptions {
headers: Headers;
prisma: typeof prisma;
user: User | null;
}

export const createInnerTRPCContext = async (opts: CreateContextOptions) => ({
headers: opts.headers,
prisma,
user: opts.user,
});

export const createTRPCContext = async (opts: FetchCreateContextFnOptions) => {
const { req } = opts;
const reqWithCookies = req as NextRequest;
const token = await getTokens(reqWithCookies.cookies, AUTH_CONFIG);

return createInnerTRPCContext({
headers: opts.req.headers,
prisma,
user: token ? mapFirebaseTokensToUser(token) : null,
});
};



const t = initTRPC.context<typeof createTRPCContext>().create({
transformer: superjson,
errorFormatter({ shape, error }) {
return {
...shape,
data: {
...shape.data,
zodError: error.cause instanceof ZodError ? error.cause.flatten() : null,
},
};
},
});


export const createAction = experimental_createServerActionHandler(t, {
async createContext() {
const ctx = await createInnerTRPCContext({
headers: headers(),
user: null,
prisma,
});
return ctx;
},
});



export const createTRPCRouter = t.router;


export const publicProcedure = t.procedure;

const enforceUserIsAuthed = t.middleware(async ({ ctx, next }) => {
if (!ctx.user) {
throw new TRPCError({
});
}
return next({
ctx: {
prisma: ctx.prisma,
user: ctx.user,
},
});
});

export const privateProcedure = t.procedure.use(enforceUserIsAuthed);
interface CreateContextOptions {
headers: Headers;
prisma: typeof prisma;
user: User | null;
}

export const createInnerTRPCContext = async (opts: CreateContextOptions) => ({
headers: opts.headers,
prisma,
user: opts.user,
});

export const createTRPCContext = async (opts: FetchCreateContextFnOptions) => {
const { req } = opts;
const reqWithCookies = req as NextRequest;
const token = await getTokens(reqWithCookies.cookies, AUTH_CONFIG);

return createInnerTRPCContext({
headers: opts.req.headers,
prisma,
user: token ? mapFirebaseTokensToUser(token) : null,
});
};



const t = initTRPC.context<typeof createTRPCContext>().create({
transformer: superjson,
errorFormatter({ shape, error }) {
return {
...shape,
data: {
...shape.data,
zodError: error.cause instanceof ZodError ? error.cause.flatten() : null,
},
};
},
});


export const createAction = experimental_createServerActionHandler(t, {
async createContext() {
const ctx = await createInnerTRPCContext({
headers: headers(),
user: null,
prisma,
});
return ctx;
},
});



export const createTRPCRouter = t.router;


export const publicProcedure = t.procedure;

const enforceUserIsAuthed = t.middleware(async ({ ctx, next }) => {
if (!ctx.user) {
throw new TRPCError({
});
}
return next({
ctx: {
prisma: ctx.prisma,
user: ctx.user,
},
});
});

export const privateProcedure = t.procedure.use(enforceUserIsAuthed);
3 replies