rustclan
rustclan
Explore posts from servers
TtRPC
Created by rustclan on 2/17/2024 in #❓-help
Best way to update a TRPC useQuery response without refetching
Hey, I currently have a trpc useQuery endpoint which retrieves a series of form submissions for a user to review. I have a mutation which allows the user to delete a specific submission, which is working fine. However, I'm wondering what the best way of updating the submissions after I have just deleted the submission in question? I don't want to refetch the entire list of submissions as thats not very efficient, it would be best to just delete the specific submission from the submissions list if the delete mutation suceeded.
const { data: submissions } =
api.applications.applicationSubmissions.useQuery(
{
guildId: guildId as string,
status: status,
userId: undefined,
applicationName: '',
},
{ enabled: !!guildId }
);

return (
{submissions?.map((submission) => {
return (
<ApplicationContainer submission={submission} guildId={guildId} />
);
)
const { data: submissions } =
api.applications.applicationSubmissions.useQuery(
{
guildId: guildId as string,
status: status,
userId: undefined,
applicationName: '',
},
{ enabled: !!guildId }
);

return (
{submissions?.map((submission) => {
return (
<ApplicationContainer submission={submission} guildId={guildId} />
);
)
const ApplicationContainer = ({
submission,
guildId,
}: ApplicationContainerProps) => {
const theme = useMantineTheme();
const deleteSubmissionMutation =
api.applications.deleteSubmission.useMutation<{
guildId: string;
submissionId: string;
}>({});

const handleDeleteSubmission = async (submissionId: string) => {
const response = await deleteSubmissionMutation.mutateAsync({
guildId: guildId,
submissionId: submissionId,
});
// somehow remove the submissionId from the submissions variable without refetching the entire submission list again.
const ApplicationContainer = ({
submission,
guildId,
}: ApplicationContainerProps) => {
const theme = useMantineTheme();
const deleteSubmissionMutation =
api.applications.deleteSubmission.useMutation<{
guildId: string;
submissionId: string;
}>({});

const handleDeleteSubmission = async (submissionId: string) => {
const response = await deleteSubmissionMutation.mutateAsync({
guildId: guildId,
submissionId: submissionId,
});
// somehow remove the submissionId from the submissions variable without refetching the entire submission list again.
2 replies
TtRPC
Created by rustclan on 2/17/2024 in #❓-help
What is a useSuspenseQuery?
Hi, I'm wondering what a useSuspenseQuery is, im looking at the docs but it doesn't explain it anywhere? https://trpc.io/docs/client/react/suspense
3 replies
TtRPC
Created by rustclan on 9/22/2023 in #❓-help
return type of a query endpoint
No description
8 replies
TTCTheo's Typesafe Cult
Created by rustclan on 9/3/2023 in #questions
TRPC error handling
Hey guys. I'm currently looking for some advice in regards to handling errors on my trpc endpoints. My current implementation is as follows:
const TicketOverview = () => {
const [hasRan, setHasRan] = useState(false);
const session = useSession();
const theme = useMantineTheme();
const { guildId } = useRouter().query;

const isFetching = useIsFetching();
const isMutating = useIsMutating();
const isRestoring = useIsRestoring();

const { data: guild, error: guildError } = api.guilds.guild.useQuery(
{
guildId: guildId as string,
},
{ enabled: !!guildId }
);

const { data: guildChannels, error: channelError } =
api.guilds.guildChannels.useQuery(
{
guildId: guildId as string,
},
{ enabled: !!guildId }
);

const { data: guildCategories, error: categoryError } =
api.guilds.guildCategories.useQuery(
{
guildId: guildId as string,
},
{ enabled: !!guildId }
);

// if any of the queries are still in progress...
if (session.status === 'loading' || isFetching || isRestoring || isMutating)
return <Loading />;

if (guildError || channelError || categoryError) {
return (
<div>
{guildError?.message ||
channelError?.message ||
categoryError?.message
}
</div>
);
}

return (
<div>
<h1>Pages content...</h1>
</div>
)
}
const TicketOverview = () => {
const [hasRan, setHasRan] = useState(false);
const session = useSession();
const theme = useMantineTheme();
const { guildId } = useRouter().query;

const isFetching = useIsFetching();
const isMutating = useIsMutating();
const isRestoring = useIsRestoring();

const { data: guild, error: guildError } = api.guilds.guild.useQuery(
{
guildId: guildId as string,
},
{ enabled: !!guildId }
);

const { data: guildChannels, error: channelError } =
api.guilds.guildChannels.useQuery(
{
guildId: guildId as string,
},
{ enabled: !!guildId }
);

const { data: guildCategories, error: categoryError } =
api.guilds.guildCategories.useQuery(
{
guildId: guildId as string,
},
{ enabled: !!guildId }
);

// if any of the queries are still in progress...
if (session.status === 'loading' || isFetching || isRestoring || isMutating)
return <Loading />;

if (guildError || channelError || categoryError) {
return (
<div>
{guildError?.message ||
channelError?.message ||
categoryError?.message
}
</div>
);
}

return (
<div>
<h1>Pages content...</h1>
</div>
)
}
This is a quick example showing what i would like to display when an error occurs, but it doesn't feel very nice... is there any alternatives?
4 replies
TtRPC
Created by rustclan on 8/2/2023 in #❓-help
trpc receiving undefined
No description
3 replies
TTCTheo's Typesafe Cult
Created by rustclan on 4/30/2023 in #questions
TRPC ratelimiting endpoints (race conditions)
I am currently having some problems with a race condition in my TRPC nextJS api. Essentially what is happening is I have a enforceGuildPermissions method, which basically checks if the user who is making the request has permission to get the data for that guild. The data is stored in my Redis cache for 3 seconds. This works okay sometimes, but other times because there is 3-4 different trpc requests running for a single page which are guild, role and channel. It causes the last request (channel) to get rate limited by the discord API because they are all running concurrently, this means it doesn't give my caching code chance to update it before the next one runs. middleware route procedure:
const enforceGuildPermissions = enforceUserLoggedIn.unstable_pipe(
async ({ ctx, next, rawInput }) => {
const guildId: unknown = (rawInput as { guildId?: unknown })?.guildId;
if (!guildId) throw new TRPCError({ code: 'BAD_REQUEST' });

const webUser = await cache.webUsers.get(ctx.session.user.id);
let guilds = webUser?.guilds;
if (!guilds) {
guilds = await getUserGuilds(ctx.session)
}

if (!guilds) throw new TRPCError({ code: 'UNAUTHORIZED' });

// if the user is not in the guild return unauth
const foundGuild = guilds.find((guild) => guild.id === guildId);
if (!foundGuild) throw new TRPCError({ code: 'UNAUTHORIZED' });

return next({
ctx: {
session: { ...ctx.session, user: ctx.session.user },
},
});
}
);

export const guildProcedure = t.procedure.use(enforceGuildPermissions);
const enforceGuildPermissions = enforceUserLoggedIn.unstable_pipe(
async ({ ctx, next, rawInput }) => {
const guildId: unknown = (rawInput as { guildId?: unknown })?.guildId;
if (!guildId) throw new TRPCError({ code: 'BAD_REQUEST' });

const webUser = await cache.webUsers.get(ctx.session.user.id);
let guilds = webUser?.guilds;
if (!guilds) {
guilds = await getUserGuilds(ctx.session)
}

if (!guilds) throw new TRPCError({ code: 'UNAUTHORIZED' });

// if the user is not in the guild return unauth
const foundGuild = guilds.find((guild) => guild.id === guildId);
if (!foundGuild) throw new TRPCError({ code: 'UNAUTHORIZED' });

return next({
ctx: {
session: { ...ctx.session, user: ctx.session.user },
},
});
}
);

export const guildProcedure = t.procedure.use(enforceGuildPermissions);
3 replies
TtRPC
Created by rustclan on 4/30/2023 in #❓-help
TRPC ratelimiting endpoints
I am currently having some problems with a race condition in my TRPC nextJS api. Essentially what is happening is I have a enforceGuildPermissions method, which basically checks if the user who is making the request has permission to get the data for that guild. The data is stored in my Redis cache for 3 seconds. This works okay sometimes, but other times because there is 3-4 different trpc requests running for a single page which are guild, role and channel. It causes the last request (channel) to get rate limited by the discord API because they are all running concurrently, this means it doesn't give my caching code chance to update it before the next one runs. middleware route procedure:
const enforceGuildPermissions = enforceUserLoggedIn.unstable_pipe(
async ({ ctx, next, rawInput }) => {
const guildId: unknown = (rawInput as { guildId?: unknown })?.guildId;
if (!guildId) throw new TRPCError({ code: 'BAD_REQUEST' });

const webUser = await cache.webUsers.get(ctx.session.user.id);
let guilds = webUser?.guilds;
if (!guilds) {
guilds = await getUserGuilds(ctx.session)

}

if (!guilds) throw new TRPCError({ code: 'UNAUTHORIZED' });

// if the user is not in the guild return unauth
const foundGuild = guilds.find((guild) => guild.id === guildId);
if (!foundGuild) throw new TRPCError({ code: 'UNAUTHORIZED' });

return next({
ctx: {
session: { ...ctx.session, user: ctx.session.user },
},
});
}
);

export const guildProcedure = t.procedure.use(enforceGuildPermissions);
const enforceGuildPermissions = enforceUserLoggedIn.unstable_pipe(
async ({ ctx, next, rawInput }) => {
const guildId: unknown = (rawInput as { guildId?: unknown })?.guildId;
if (!guildId) throw new TRPCError({ code: 'BAD_REQUEST' });

const webUser = await cache.webUsers.get(ctx.session.user.id);
let guilds = webUser?.guilds;
if (!guilds) {
guilds = await getUserGuilds(ctx.session)

}

if (!guilds) throw new TRPCError({ code: 'UNAUTHORIZED' });

// if the user is not in the guild return unauth
const foundGuild = guilds.find((guild) => guild.id === guildId);
if (!foundGuild) throw new TRPCError({ code: 'UNAUTHORIZED' });

return next({
ctx: {
session: { ...ctx.session, user: ctx.session.user },
},
});
}
);

export const guildProcedure = t.procedure.use(enforceGuildPermissions);
20 replies
TtRPC
Created by rustclan on 4/17/2023 in #❓-help
trpc auto refreshes page when I lose focus
Hi, i thought this was a development environment only configuration, but it does it even in production. How am I able to change this functionality?
5 replies
TtRPC
Created by rustclan on 4/15/2023 in #❓-help
trpc rate limiting
hi I am currently having some problems with a race condition in my TRPC nextJS api. Essentially what is happening is I have a enforceGuildPermissions method, which basically checks if the user who is making the request has permission to get the data for that guild. The data is stored in my Redis cache for 3 seconds. This works okay sometimes, but other times because there is 3-4 different trpc requests running for a single page which are guild, role and channel. It causes the last request (channel) to get rate limited by the discord API because they are all running concurrently, this means it doesn't give my caching code chance to update it before the next one runs.
const enforceGuildPermissions = enforceUserLoggedIn.unstable_pipe(
async ({ ctx, next, rawInput }) => {
const guildId: unknown = (rawInput as { guildId?: unknown })?.guildId;
if (!guildId) throw new TRPCError({ code: 'BAD_REQUEST' });

const webUser = await cache.webUsers.get(ctx.session.user.id);
let guilds = webUser?.guilds;
if (!guilds) {
guilds = await getUserGuilds(ctx.session)

}

if (!guilds) throw new TRPCError({ code: 'UNAUTHORIZED' });
const foundGuild = guilds.find((guild) => guild.id === guildId);
if (!foundGuild) throw new TRPCError({ code: 'UNAUTHORIZED' });

return next({
ctx: {
session: { ...ctx.session, user: ctx.session.user },
},
});
}
);

export const guildProcedure = t.procedure.use(enforceGuildPermissions);
const enforceGuildPermissions = enforceUserLoggedIn.unstable_pipe(
async ({ ctx, next, rawInput }) => {
const guildId: unknown = (rawInput as { guildId?: unknown })?.guildId;
if (!guildId) throw new TRPCError({ code: 'BAD_REQUEST' });

const webUser = await cache.webUsers.get(ctx.session.user.id);
let guilds = webUser?.guilds;
if (!guilds) {
guilds = await getUserGuilds(ctx.session)

}

if (!guilds) throw new TRPCError({ code: 'UNAUTHORIZED' });
const foundGuild = guilds.find((guild) => guild.id === guildId);
if (!foundGuild) throw new TRPCError({ code: 'UNAUTHORIZED' });

return next({
ctx: {
session: { ...ctx.session, user: ctx.session.user },
},
});
}
);

export const guildProcedure = t.procedure.use(enforceGuildPermissions);
export const getUserGuilds = async (
session: Session
): Promise<CachedUserGuild[] | null> => {
if (!session.user.accessToken || !session.user.id) return null;

const webUser = await cache.webUsers.get(session.user.id);
if (webUser) return webUser.guilds;

const response = await fetch(discord...)
const guilds = await response.json();
if (!response.ok || guilds.length <= 0) return null;

await cache.webUsers.create(session.user.id, guilds);

return guilds;
};
export const getUserGuilds = async (
session: Session
): Promise<CachedUserGuild[] | null> => {
if (!session.user.accessToken || !session.user.id) return null;

const webUser = await cache.webUsers.get(session.user.id);
if (webUser) return webUser.guilds;

const response = await fetch(discord...)
const guilds = await response.json();
if (!response.ok || guilds.length <= 0) return null;

await cache.webUsers.create(session.user.id, guilds);

return guilds;
};
3 replies
TtRPC
Created by rustclan on 4/15/2023 in #❓-help
trpc pipe middleware
Hey all. I'm currently trying to create a middle ware on endpoints using the new pipe API. This is on a specific route which is formatted like: http://localhost:3000/dashboard/811452295324762131/page Is it possible to retrieve the dynamic id which is in this URL, in my middleware? I really need to access this for the middleware to be possible to use. Essentially I need to check if the current user has permission to access this guildId.
const enforceGuildPermissions = enforceUserLoggedIn.unstable_pipe(
async ({ ctx, next }) => {
return next({
ctx: {
session: { ...ctx.session, user: ctx.session.user },
},
});
}
);
const enforceGuildPermissions = enforceUserLoggedIn.unstable_pipe(
async ({ ctx, next }) => {
return next({
ctx: {
session: { ...ctx.session, user: ctx.session.user },
},
});
}
);
There unfortunetly doesn't seem to be any req property in the pipe api which could give me router information.
4 replies
TtRPC
Created by rustclan on 2/3/2023 in #❓-help
Calling a trpc endpoint inside of a trpc endpoint
Hey all. I'm wondering how I am able to call these endpoints from within themselves? For example, I'd like to call getBotGuilds and getUserGuilds from within getAllGuilds.
export const guildRouter = createTRPCRouter({
getBotGuilds: protectedProcedure.query(({ ctx }) => {
}),
getUserGuilds: protectedProcedure.query(({ ctx }) => {

return [];
}),
getAllGuilds: protectedProcedure.query(({ ctx }) => {

}),
});
export const guildRouter = createTRPCRouter({
getBotGuilds: protectedProcedure.query(({ ctx }) => {
}),
getUserGuilds: protectedProcedure.query(({ ctx }) => {

return [];
}),
getAllGuilds: protectedProcedure.query(({ ctx }) => {

}),
});
7 replies
TtRPC
Created by rustclan on 1/31/2023 in #❓-help
trpc query running twice
Hey guys. I have a trpc endpoint which makes a request to the discord api to fetch a list of the users guilds.
getGuilds: publicProcedure
.input(z.object({ accessToken: z.string().nullish() }))
.query(async (ctx) => {
console.log(1);
if (!ctx.input.accessToken) return null;
const botGuilds = await prisma.guilds.findMany();
const userGuilds = await getUserGuilds(ctx.input.accessToken);
if (!userGuilds || userGuilds.length <= 0) return [];

const guilds = userGuilds.map((g) => {
const findGuild = botGuilds.find((bg) => bg.guildId === g.id);
g.isPremium = findGuild?.premium || false;
g.inServer = !!findGuild;
return g;
});

return guilds.sort((a, b) => {
if (a.inServer && !b.inServer) return -1;
return 1;
});
}),
getGuilds: publicProcedure
.input(z.object({ accessToken: z.string().nullish() }))
.query(async (ctx) => {
console.log(1);
if (!ctx.input.accessToken) return null;
const botGuilds = await prisma.guilds.findMany();
const userGuilds = await getUserGuilds(ctx.input.accessToken);
if (!userGuilds || userGuilds.length <= 0) return [];

const guilds = userGuilds.map((g) => {
const findGuild = botGuilds.find((bg) => bg.guildId === g.id);
g.isPremium = findGuild?.premium || false;
g.inServer = !!findGuild;
return g;
});

return guilds.sort((a, b) => {
if (a.inServer && !b.inServer) return -1;
return 1;
});
}),
It works fine. However, because this is in my dev environment the TRPC query runs two times, which causes the request to fail due to discord ratelimits. I am using nextjs and I am unsure how I can resolve this. Up until now, I have always used my own api on my server using python, so I could cache things. But with vercel you cannot cache results. Does anybody have any suggestions?
10 replies
TtRPC
Created by rustclan on 1/29/2023 in #❓-help
TRPC global loading page
Hey. With trpc/nextjs I'm wondering if its possible to have a global loading context/state which is used across my whole app, whenever a TRPC endpoint .isFetched property is false, it will display a "loading" symbol. Currently I have to do something like this on every page:
if (!getMailQuery.isFetched) {
return (
<AppShell navbar={<AdminNavBar selected={6} />}>
<PublicLoadingScreen />
</AppShell>
);
}
return (pageContent...)
if (!getMailQuery.isFetched) {
return (
<AppShell navbar={<AdminNavBar selected={6} />}>
<PublicLoadingScreen />
</AppShell>
);
}
return (pageContent...)
4 replies
TTCTheo's Typesafe Cult
Created by rustclan on 12/4/2022 in #questions
TRPC cache (with vercel, but not working locally too)
Hello. I am using TRPC to make a site which integrates with a third party API. I need to add caching to some of my routes. I have tried to implement a temporary global cache, as seen below. In order to stop rate limits for the third party api.
// export API handler
export default createNextApiHandler({
router: appRouter,
createContext,
responseMeta({ ctx, paths, type, errors }) {
// checking that no procedures errored
const allOk = errors.length === 0;
// checking we're doing a query request
const isQuery = type === "query";
console.log(1);
if (ctx && allOk && isQuery) {
console.log(2);
// cache request for 1 day + revalidate once every second
const ONE_DAY_IN_SECONDS = 15000;
return {
headers: {
"cache-control": `s-maxage=1, stale-while-revalidate=${ONE_DAY_IN_SECONDS}`,
},
};
}
return {};
},
});
// export API handler
export default createNextApiHandler({
router: appRouter,
createContext,
responseMeta({ ctx, paths, type, errors }) {
// checking that no procedures errored
const allOk = errors.length === 0;
// checking we're doing a query request
const isQuery = type === "query";
console.log(1);
if (ctx && allOk && isQuery) {
console.log(2);
// cache request for 1 day + revalidate once every second
const ONE_DAY_IN_SECONDS = 15000;
return {
headers: {
"cache-control": `s-maxage=1, stale-while-revalidate=${ONE_DAY_IN_SECONDS}`,
},
};
}
return {};
},
});
However, the cache-control header does not get changed, and nothing is cached. Mutiple requests are still made to the third party API. The cache code does run, as the console.log(2) appears in console. Any clue whats wrong?
2 replies
TtRPC
Created by rustclan on 12/2/2022 in #❓-help
trying to cache api routes
6 replies
TTCTheo's Typesafe Cult
Created by rustclan on 11/30/2022 in #questions
TRPC max retries on endpoint
15 replies
TtRPC
Created by rustclan on 11/30/2022 in #❓-help
calling api endpoints from within a trpc api endpoint?
Hey all. I have a series of api endpoints which may have to be reused across other api endpoints. I was wondering if this is possible?
getAccessToken: protectedProcedure.query(async ({ ctx }) => {
if (!ctx.session?.user.id) return null;
const data = await prisma?.account.findFirst({
where: {
userId: ctx.session.user.id,
},
});
return data?.access_token;
}),
checkGuildAccess: protectedProcedure
.input(z.object({ guildId: z.string() }))
.query(async (ctx) => {
const accessToken = trpc.auth.getAccessToken.useQuery();
console.log(accessToken);
if (!accessToken) return null;
return accessToken;
}),
});
getAccessToken: protectedProcedure.query(async ({ ctx }) => {
if (!ctx.session?.user.id) return null;
const data = await prisma?.account.findFirst({
where: {
userId: ctx.session.user.id,
},
});
return data?.access_token;
}),
checkGuildAccess: protectedProcedure
.input(z.object({ guildId: z.string() }))
.query(async (ctx) => {
const accessToken = trpc.auth.getAccessToken.useQuery();
console.log(accessToken);
if (!accessToken) return null;
return accessToken;
}),
});
As you can see, my checkGuildAccess needs access to the users access token. So I call the getAccessToken endpoint from within the checkGuildAccess endpoint. Is this valid? I am getting an error.
❌ tRPC failed on auth.checkGuildAccess: TRPCError: Cannot read properties of null (reading 'useContext')
❌ tRPC failed on auth.checkGuildAccess: TRPCError: Cannot read properties of null (reading 'useContext')
2 replies
TtRPC
Created by rustclan on 11/30/2022 in #❓-help
TRPC waiting until the query has completed
Hey. I've just found out about TRPC and I love it. However, I was wondering if there is a way to make it so the code below my query doesn't run until the query has completed, without having to make an external function or make use of a useeffect hook in order to use await? Is there a property of some sort which I can use to stop the page from rendering? The code below causes an infinite signIn loop due to the data not being there on the initial page render. But, I can't check if !guilds.data, because sometimes it wont return anything, due to an invalid token. Which means there is no good way to identify when to force a signIn for the user.
const accessToken = trpc.auth.getAccessToken.useQuery();
const guilds = trpc.api.getGuilds.useQuery({ accessToken: accessToken.data });

if (!accessToken.data || !guilds.data) signIn("discord")
const accessToken = trpc.auth.getAccessToken.useQuery();
const guilds = trpc.api.getGuilds.useQuery({ accessToken: accessToken.data });

if (!accessToken.data || !guilds.data) signIn("discord")
19 replies
TTCTheo's Typesafe Cult
Created by rustclan on 11/20/2022 in #questions
invalid environment variables
27 replies