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);
1 Reply
ignacio
ignacio15mo ago
Plus when I try to use the createPost action on a client side I can't pass data properly:
import { createPost } from '~/app/actions';

/// ... ///

const onSubmit = handleSubmit(async (data) => {
try {
reset();
console.log('DATA', data);
if (data) {
const post = await createPost({ text: data.text });
console.log('post', post);
// ======== HERE ==========
// always get the error

}
} catch (error) {
console.error(error);
}
});
import { createPost } from '~/app/actions';

/// ... ///

const onSubmit = handleSubmit(async (data) => {
try {
reset();
console.log('DATA', data);
if (data) {
const post = await createPost({ text: data.text });
console.log('post', post);
// ======== HERE ==========
// always get the error

}
} catch (error) {
console.error(error);
}
});
Want results from more Discord servers?
Add your server