T
Join ServertRPC
❓-help
'useInfiniteQuery' hook disappeared after moving to Turborepo
I am using Turborepo with Next.js with the following layout, originally a T3 app
-
-
The
I am using
I'd love some guidance, I'm a little stuck...
-
/apps/app
-
/packages/api
The
useInfiniteQuery
hook seems to have dissapeared after migrating, and I can't get it back.I am using
@trpc/next
on the clientside, @trpc/react-query
is installed, and everything seems fine?I'd love some guidance, I'm a little stuck...
/apps/app/src/utils/api.ts
import { httpBatchLink, loggerLink } from "@trpc/client";
import { createTRPCNext } from "@trpc/next";
import superjson from "superjson";
import { type AppRouter } from "@myapp/api";
const getBaseUrl = () => {
if (typeof window !== "undefined") return ""; // browser should use relative url
if (process.env.VERCEL_URL) return `https://${process.env.VERCEL_URL}`; // SSR should use vercel url
return `http://localhost:${process.env.PORT ?? 3000}`; // dev SSR should use localhost
};
config() {
return {
transformer: superjson,
links: [
loggerLink({
enabled: (opts) =>
process.env.NODE_ENV === "development" ||
(opts.direction === "down" &&
opts.result instanceof Error),
}),
httpBatchLink({
url: `${getBaseUrl()}/api/trpc`,
}),
],
};
},
ssr: false,
});
/packages/api/src/routers/job.ts
findMany: publicProcedure
.input(
z.object({
where: JobPostWhereInputSchema.optional(),
take: z.number().min(1).max(100).optional(),
cursor: z.string().nullish(),
order: JobPostOrderByWithRelationInputSchema.optional(),
})
)
.query(...)
`/packages/api/src/root.ts
import { createTRPCProxyClient, httpBatchLink } from "@trpc/client";
import superjson from "superjson";
import { job } from "./routers/job";
import { profile } from "./routers/profile";
import { createTRPCRouter } from "./trpc";
export const appRouter = createTRPCRouter({
profile,
job,
});
export type AppRouter = typeof appRouter;
export const client = createTRPCProxyClient<AppRouter>({
transformer: superjson,
links: [
httpBatchLink({
url: "http://localhost:3000/api/trpc",
}),
],
});
Interesting - it might be something to do with the
And the
Still investigating
tsconfig
I added strict: true
through in the child tsconfigs
even though it's enabled at a top level.And the
job.
disappeared from the router... Still investigating
Okay, so turns out in my hate of setting up turborepo, strict mode wasn't enforced, that's enabled now. But what's odd, is the
api.job
is now never
type 0_oAnd now finally at what appears to the be root of the issue
Throws:
export const api = createTRPCNext<AppRouter>({
config() {
return {
/**
* Transformer used for data de-serialization from the server.
*
* @see https://trpc.io/docs/data-transformers
**/
transformer: superjson,
/**
* Links used to determine request flow from client to server.
*
* @see https://trpc.io/docs/links
* */
links: [
loggerLink({
enabled: (opts) =>
process.env.NODE_ENV === "development" ||
(opts.direction === "down" &&
opts.result instanceof Error),
}),
httpBatchLink({
url: `${getBaseUrl()}/api/trpc`,
}),
],
};
},
/**
* Whether tRPC should await queries when server rendering pages.
*
* @see https://trpc.io/docs/nextjs#ssr-boolean-default-false
*/
ssr: false,
});
Throws:
Type 'CreateRouterInner<RootConfig<{ ctx: { req: NextApiRequest; res: NextApiResponse; session: Session | null; prisma: PrismaClient<PrismaClientOptions, never, RejectOnNotFound | ... 1 more ... | undefined>; }; meta: object; errorShape: { ...; }; transformer: typeof SuperJSON; }>, { ...; }>' does not satisfy the constraint 'Router<AnyRouterDef<AnyRootConfig, any>>'.
The types returned by 'createCaller(...)' are incompatible between these types.
Type '{ query: inferHandlerFn<{}>; mutation: inferHandlerFn<{}>; subscription: inferHandlerFn<{}>; } & DecoratedProcedureRecord<{ profile: CreateRouterInner<RootConfig<{ ctx: { req: NextApiRequest; res: NextApiResponse; session: Session | null; prisma: PrismaClient<...>; }; meta: object; errorShape: { ...; }; transformer:...' is not assignable to type '{ query: inferHandlerFn<any>; mutation: inferHandlerFn<any>; subscription: inferHandlerFn<any>; } & DecoratedProcedureRecord<any>'.
Type '{ query: inferHandlerFn<{}>; mutation: inferHandlerFn<{}>; subscription: inferHandlerFn<{}>; } & DecoratedProcedureRecord<{ profile: CreateRouterInner<RootConfig<{ ctx: { req: NextApiRequest; res: NextApiResponse; session: Session | null; prisma: PrismaClient<...>; }; meta: object; errorShape: { ...; }; transformer:...' is not assignable to type '{ query: inferHandlerFn<any>; mutation: inferHandlerFn<any>; subscription: inferHandlerFn<any>; }'.
Types of property 'query' are incompatible.
Type 'inferHandlerFn<{}>' is not assignable to type 'inferHandlerFn<any>'.
Types of parameters 'path' and 'path' are incompatible.
Type 'TPath' is not assignable to type 'never'.
Type 'string' is not assignable to type 'never'.ts(2344)
This tracks. The cursor needs to be there and if the parent object is nullable it doesn’t get detected. Strict null checks needs to be on at minimum and a new repo might not have that
Yeah strict mode enabled through and through now.
Was a red herring.
Now having issues with the appRouter...
Was a red herring.
Now having issues with the appRouter...
An you share your backend setup?
It's a next app, the appRouter and server are in their own package in a turborepo'd monorepo
tRPC runs on the next app, not on an independent service
Right so the error actually starts in your AppRouter I think
Ignore the frontend errors until that’s fixed
100%
What does the AppRouter look like? Might need to see quite a bit of the setup. Try commenting up sub routes until the error goes away
That's the app router.
Let me comment out the sub routes and see what happens.
Let me comment out the sub routes and see what happens.
import { company } from "./routers/company";
import { job } from "./routers/job";
import { profile } from "./routers/profile";
import { createTRPCRouter } from "./trpc";
/**
* This is the primary router for your server.
*
* All routers added in /api/routers should be manually added here.
*/
export const appRouter = createTRPCRouter({
profile,
job,
company,
});
// export type definition of API
export type AppRouter = typeof appRouter;
So I've just changed it to this, removing my procedures and sub-routes.
Same errors.
Same errors.
import { createTRPCRouter } from "./trpc";
import { z } from "zod";
import { protectedProcedure, publicProcedure } from "./trpc";
export const exampleRouter = createTRPCRouter({
hello: publicProcedure
.input(z.object({ text: z.string() }))
.query(({ input }) => {
return {
greeting: `Hello ${input.text}`,
};
}),
getSecretMessage: protectedProcedure.query(() => {
return "you can now see this secret message!";
}),
});
/**
* This is the primary router for your server.
*
* All routers added in /api/routers should be manually added here.
*/
export const appRouter = createTRPCRouter({
exampleRouter,
});
// export type definition of API
export type AppRouter = typeof appRouter;
I'm happy to share the repo
Can you show trpc.ts?
Might be to do with t setup
Is pretty out of the box
I think I've only added the admin middleware
Oh discord doesn’t like text files on mobile 🫠
Best to paste a code block
Sec
I'll remove comments
import { prisma } from "@app/db";
import { type CreateNextContextOptions } from "@trpc/server/adapters/next";
import { type Session } from "next-auth";
import { getServerAuthSession } from "@app/auth";
export type CreateContextOptions = {
session: Session | null;
};
const createInnerTRPCContext = (opts: CreateContextOptions) => {
return {
session: opts.session,
prisma,
};
};
export const createTRPCContext = async (opts: CreateNextContextOptions) => {
const { req, res } = opts;
// Get the session from the server using the getServerSession wrapper function
const session = await getServerAuthSession({ req, res });
return {
...createInnerTRPCContext({
session,
}),
req,
res,
};
};
import { initTRPC, TRPCError } from "@trpc/server";
import superjson from "superjson";
import { ZodError } from "zod";
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 createTRPCRouter = t.router;
export const publicProcedure = t.procedure;
/** Reusable middleware that enforces users are logged in before running the procedure. */
const enforceUserIsAuthed = t.middleware(({ ctx, next }) => {
if (!ctx.session || !ctx.session.user) {
throw new TRPCError({ code: "UNAUTHORIZED" });
}
return next({
ctx: {
// infers the `session` as non-nullable
session: { ...ctx.session, user: ctx.session.user },
},
});
});
export const protectedProcedure = t.procedure.use(enforceUserIsAuthed);
const enfroceUserIsAdmin = t.middleware(({ ctx, next }) => {
if (!ctx.session?.user.isAdmin) {
throw new TRPCError({ code: "UNAUTHORIZED" });
}
return next({
ctx: {
// infers the `session` as non-nullable
session: { ...ctx.session, user: ctx.session.user },
},
});
});
export const adminProcedure = t.procedure.use(enfroceUserIsAdmin);
It’s definitely a weird one
I don’t see anything obviously wrong but it’s hard to tell on mobile
It's super weird... Is it a typescript or linting issue? As that's all I've been playing around with
The images you shared with the errors are probably quite useful
Do both projects have strict enabled?
Everything has strict enabled
Cool
I’ll need to have another look a bit later when I’m on desktop
I'll go through and even do it on a package level tsconfig, not just the base
Thank you! Much appreciated!
If you want the source code, I'm happy to share the repo with you
If you want the source code, I'm happy to share the repo with you
Definitely make sure it’s not being switched off in any way. Base should be fine though
The repo would probably help. If you have time try and put together a minimal reproduction
You saw my antics before of chasing down tsconfig issues, so it could be, but I'm doubtful
I'm based in AUS so it'll likely be tomorrow.
I can share you the repo that it is now, if you shoot through your GH
I can share you the repo that it is now, if you shoot through your GH
It's fairly minimal anyways, if I take it back any further I'll be stripping out the monorepo
Hol' up - might have some version mismatching going on
Wow, okay... so two packages had different version of
Must've happened when splitting out, I've done some more consolidating, brining the next client into the api package, wowweee
Edit: And strict mode, obviously... shit breaks without it (but we know this, this is just for the others experiencing weirdness, if it's weird it's usually versions or strict mode)
@trpc/next
and @trpc/server
Must've happened when splitting out, I've done some more consolidating, brining the next client into the api package, wowweee
Edit: And strict mode, obviously... shit breaks without it (but we know this, this is just for the others experiencing weirdness, if it's weird it's usually versions or strict mode)
Brilliant, that was one thing I was going to check 😃
Appreciate it @nlucas !