Gabriel
Gabriel
TtRPC
Created by Gabriel on 11/9/2024 in #❓-help
How can I automatically use react's cache with tRPC on server side?
I have this in my repo:
import { cache } from "react";
import { headers } from "next/headers";

import { createCaller, createTRPCContext } from "@kdx/api";
import { auth } from "@kdx/auth";

/**
* This wraps the `createTRPCContext` helper and provides the required context for the tRPC API when
* handling a tRPC call from a React Server Component.
*/
const createContext = cache(async () => {
const heads = new Headers(headers());
heads.set("x-trpc-source", "rsc");

return createTRPCContext({
auth: await auth(),
headers: heads,
});
});

export const api = createCaller(createContext);
import { cache } from "react";
import { headers } from "next/headers";

import { createCaller, createTRPCContext } from "@kdx/api";
import { auth } from "@kdx/auth";

/**
* This wraps the `createTRPCContext` helper and provides the required context for the tRPC API when
* handling a tRPC call from a React Server Component.
*/
const createContext = cache(async () => {
const heads = new Headers(headers());
heads.set("x-trpc-source", "rsc");

return createTRPCContext({
auth: await auth(),
headers: heads,
});
});

export const api = createCaller(createContext);
But, now I need to understand, how should I export the actual functions from the api caller so they are all cached with react's cache? I of course could do something like this
export const uglyGetNotifications = cache(api.user.getNotifications);
export const uglyGetNotifications = cache(api.user.getNotifications);
But I would prefer if I could get an instance of api where all of my endpoints will be using the cache automatically. something like
const notifs = await apiCached.user.getNotifications();
const notifs = await apiCached.user.getNotifications();
2 replies
TtRPC
Created by Gabriel on 7/10/2024 in #❓-help
How to improve typescript performance?
No description
57 replies
TtRPC
Created by Gabriel on 3/6/2024 in #❓-help
Why deprecate experimental_standaloneMiddleware?
I am reading https://trpc.io/docs/server/middlewares#experimental-standalone-middlewares, but it's still not clear to me why experimental_standaloneMiddleware was deprecated. It says we can use .concat() to use "standalone" middlewares. However, I don't see how they are related exactly? The example shows we can use a plugin. This would take in a new procedure to do concating of procedures. But this is not exactly what I want. In my code I have this:
const todoAppInstalledMiddleware experimental_standaloneMiddleware<{
ctx: TProtectedProcedureContext;
}>().create(async ({ ctx, next }) => {
const foundPermission = await ctx.prisma.teamAppRole.findFirst({
where: {
AppPermissions: {
some: {
id: "234234324-my-todo-app-id-here-yay",
},
},
Team: {
id: ctx.session.user.activeTeamId,
},
Users: {
some: {
id: ctx.session.user.id,
},
},
},
select: { id: true },
});

if (!foundPermission)
throw new TRPCError({
code: "UNAUTHORIZED",
message: `You don't have permission to do this. Contact an administrator if you believe it is an error.`,
});

return next({ ctx });
});
const todoAppInstalledMiddleware experimental_standaloneMiddleware<{
ctx: TProtectedProcedureContext;
}>().create(async ({ ctx, next }) => {
const foundPermission = await ctx.prisma.teamAppRole.findFirst({
where: {
AppPermissions: {
some: {
id: "234234324-my-todo-app-id-here-yay",
},
},
Team: {
id: ctx.session.user.activeTeamId,
},
Users: {
some: {
id: ctx.session.user.id,
},
},
},
select: { id: true },
});

if (!foundPermission)
throw new TRPCError({
code: "UNAUTHORIZED",
message: `You don't have permission to do this. Contact an administrator if you believe it is an error.`,
});

return next({ ctx });
});
Doing this via concat() feels unnatural. I just want to define a middleware that I can use in multiple procedures where my session is not null (protected context). What is the recommended way of doing this?
5 replies
TtRPC
Created by Gabriel on 1/26/2024 in #❓-help
How do I pass a Generic to a trpc query procedure?
I want to to something like this:
type AppIdsWithConfig = typeof kodixCareAppId | typeof calendarAppId;

const fakeProcedure = <T extends AppIdsWithConfig>(kodixAppId: T) => {
const appIdToValue = {
[kodixCareAppId]: "my value 1",
[calendarAppId]: 1235,
} as const;

return appIdToValue[kodixAppId];
};

const value = fakeProcedure(kodixCareAppId);
// ^? --> const value: "my value 1"

const value2 = fakeProcedure(calendarAppId);
// ^? --> const value2: 1235
type AppIdsWithConfig = typeof kodixCareAppId | typeof calendarAppId;

const fakeProcedure = <T extends AppIdsWithConfig>(kodixAppId: T) => {
const appIdToValue = {
[kodixCareAppId]: "my value 1",
[calendarAppId]: 1235,
} as const;

return appIdToValue[kodixAppId];
};

const value = fakeProcedure(kodixCareAppId);
// ^? --> const value: "my value 1"

const value2 = fakeProcedure(calendarAppId);
// ^? --> const value2: 1235
This is how you pass a generic to a function, as we know. I wanted to do it in a procedure. Right now I have a procedure:
type AppIdsWithConfig = typeof kodixCareAppId | typeof calendarAppId;

//How do I pass a Generic to this? I want to infer the result type based on the appId I pass in as an input
getConfig: protectedProcedure
.input(
z.object({
appId: z.custom<AppIdsWithConfig>(),
}),
)
.query(
async ({ ctx, input }) =>
await getAppConfig({
appId: input.appId,
prisma: ctx.prisma,
session: ctx.session,
}),
),
type AppIdsWithConfig = typeof kodixCareAppId | typeof calendarAppId;

//How do I pass a Generic to this? I want to infer the result type based on the appId I pass in as an input
getConfig: protectedProcedure
.input(
z.object({
appId: z.custom<AppIdsWithConfig>(),
}),
)
.query(
async ({ ctx, input }) =>
await getAppConfig({
appId: input.appId,
prisma: ctx.prisma,
session: ctx.session,
}),
),
6 replies