DennisK
DennisK
Explore posts from servers
PPrisma
Created by DennisK on 9/10/2024 in #help-and-questions
Prisma Transactions stops working once you extend the client with Pulse, Optimize or Accelerate
See title. This stops me from migrating to these products and use in production. Once you extend the client and need to make a Prisma Transaction it will return an error and the transaction fails: TypeError: parentTracer.getSpanLimits is not a function
4 replies
PPrisma
Created by DennisK on 9/10/2024 in #help-and-questions
Supabase with Pulse and Accelerate
Hi! I am setting op Supabase in combination with Fly, Pulse and Accelerate. I received two URLS: A connection pooler URL A direct URL I have set this in the schema like this
url = env("DATABASE_POOLER_URL")
directUrl = env("DATABASE_URL")
url = env("DATABASE_POOLER_URL")
directUrl = env("DATABASE_URL")
However, I used the direct url (the one with port 5432) to setup Accelerate and I got back a prisma database url. Should I know replace the direct url with this new prisma://accelerate.prisma-data.net/ ? So it would result in this:
url = url to connectionpooler Supabase
directUrl = the prisma://accelerate.prismadata.net url
url = url to connectionpooler Supabase
directUrl = the prisma://accelerate.prismadata.net url
4 replies
PPrisma
Created by DennisK on 9/10/2024 in #help-and-questions
Whenever you extend your PrismaClient with Pulse, you don't have access to $on anymore. Why?
No description
3 replies
PPrisma
Created by DennisK on 9/9/2024 in #help-and-questions
Is SQlite supported any time soon? Pulse & Accelerate
Hi! Wondering if this is on the roadmap or not. Migrating my stack to Postgres is kind of a pain.
4 replies
NNovu
Created by DennisK on 5/17/2024 in #💬│support
[BUG] Deleting sub does not hard delete?
Hi! So I am finishing my notifications setup and I deleted a sub using the SDK
await novuClient.subscribers.delete('subid')
await novuClient.subscribers.delete('subid')
This worked as I saw an empty list of subscribers within Novu Cloud. However, when I return to my app and open the notification center, I see a list of archived notifications. First I thought it might have to do with state, so I did restart the application, but all the notifications are shown again and within Novu cloud I do see a new Subscriber entry now with that same ID but without any user data (name, email, etc)
7 replies
NNovu
Created by DennisK on 5/17/2024 in #💬│support
Does invoking a new Novu client hold a open connection?
Hi! Within my Remix app I would like to add Novu. Usually I wrap my clients in a remember/singleton function so it won't create another instance next to the other. Is this recommended as well or will Novu close the connection after it has been used?
8 replies
TTCTheo's Typesafe Cult
Created by DennisK on 9/5/2023 in #questions
Admin routes and security. How to set this up?
Hi! What is a good way of protecting admin routes? The ideal situation is, that whenever an user goes to an admin route it: 1. Does not fetch the data 2. Will get redirected back to a specific page Right now when I throw a TRPC error, it takes a super long time until the error is shown.. It fetches like 7-8 times and returns error = null admin route:
getAllMembers: protectedProcedure.query(async ({ ctx }) => {
const isAdmin = ctx.session.user.role === "admin";
if (!isAdmin) {
throw new TRPCError({
code: "UNAUTHORIZED",
message: "You are not authorized to view this page",
});
}
const members = // db call

return members;
}),
getAllMembers: protectedProcedure.query(async ({ ctx }) => {
const isAdmin = ctx.session.user.role === "admin";
if (!isAdmin) {
throw new TRPCError({
code: "UNAUTHORIZED",
message: "You are not authorized to view this page",
});
}
const members = // db call

return members;
}),
const MembersOverview: NextPage = () => {
const router = useRouter();
const { data: sessionData } = useSession();

const {
data: members,
isLoading,
error,
} = api.admin.getAllMembers.useQuery();

// This does not really work
if (error instanceof TRPCClientError) {
if (error.shape.data?.code === "UNAUTHORIZED") {
router.push("/members");
}
}

return (
<>
<DashboardLayout profileData={sessionData?.user}>
<Spacer size="xs" />
{!isLoading && (
// @ts-ignore
<MemberDataTable columns={columns} data={members} />
)}
</DashboardLayout>
</>
);
};
const MembersOverview: NextPage = () => {
const router = useRouter();
const { data: sessionData } = useSession();

const {
data: members,
isLoading,
error,
} = api.admin.getAllMembers.useQuery();

// This does not really work
if (error instanceof TRPCClientError) {
if (error.shape.data?.code === "UNAUTHORIZED") {
router.push("/members");
}
}

return (
<>
<DashboardLayout profileData={sessionData?.user}>
<Spacer size="xs" />
{!isLoading && (
// @ts-ignore
<MemberDataTable columns={columns} data={members} />
)}
</DashboardLayout>
</>
);
};
9 replies
TTCTheo's Typesafe Cult
Created by DennisK on 8/8/2023 in #questions
Vercel builds errorring out due to Invalid Vercel URL.
Hi! Stuck during first deployment of my T3 app. It keeps saying the VERCEL_URL is invalid but looking at the env variables the VERCEL_URL is set and is set to https://**.vercel.app VERCEL_URL: z.string().url().optional(), VERCEL_URL: process.env.VERCEL_URL,
5 replies
TTCTheo's Typesafe Cult
Created by DennisK on 7/21/2023 in #questions
Eslint config is not picked up??!
Hi! I have some rules added to the .eslintrc.cjs inside the T3 app, but any rule I add is not getting picked up by Eslint. Restarting Eslint server etc etc does not work either. Unsafe member access .enabled on an any value.eslint@typescript-eslint/no-unsafe-member-access
// eslint-disable-next-line @typescript-eslint/no-var-requires
const path = require("path");

/** @type {import("eslint").Linter.Config} */
const config = {
overrides: [
{
extends: [
"plugin:@typescript-eslint/recommended-requiring-type-checking",
],
files: ["*.ts", "*.tsx"],
parserOptions: {
project: path.join(__dirname, "tsconfig.json"),
},
},
],
parser: "@typescript-eslint/parser",
parserOptions: {
project: path.join(__dirname, "tsconfig.json"),
},
plugins: ["@typescript-eslint"],
extends: ["next/core-web-vitals", "plugin:@typescript-eslint/recommended"],
rules: {
"@typescript-eslint/consistent-type-imports": [
"warn",
{
prefer: "type-imports",
fixStyle: "inline-type-imports",
},
],
"@typescript-eslint/no-unused-vars": ["warn", { argsIgnorePattern: "^_" }],
"@typescript-eslint/no-misused-promises": [
2,
{
checksVoidReturn: {
attributes: false,
},
},
],
"@typescript-eslint/restrict-plus-operands": 0,
"@typescript-eslint/no-unsafe-member-access": 0,
},
};

module.exports = config;
// eslint-disable-next-line @typescript-eslint/no-var-requires
const path = require("path");

/** @type {import("eslint").Linter.Config} */
const config = {
overrides: [
{
extends: [
"plugin:@typescript-eslint/recommended-requiring-type-checking",
],
files: ["*.ts", "*.tsx"],
parserOptions: {
project: path.join(__dirname, "tsconfig.json"),
},
},
],
parser: "@typescript-eslint/parser",
parserOptions: {
project: path.join(__dirname, "tsconfig.json"),
},
plugins: ["@typescript-eslint"],
extends: ["next/core-web-vitals", "plugin:@typescript-eslint/recommended"],
rules: {
"@typescript-eslint/consistent-type-imports": [
"warn",
{
prefer: "type-imports",
fixStyle: "inline-type-imports",
},
],
"@typescript-eslint/no-unused-vars": ["warn", { argsIgnorePattern: "^_" }],
"@typescript-eslint/no-misused-promises": [
2,
{
checksVoidReturn: {
attributes: false,
},
},
],
"@typescript-eslint/restrict-plus-operands": 0,
"@typescript-eslint/no-unsafe-member-access": 0,
},
};

module.exports = config;
3 replies
TTCTheo's Typesafe Cult
Created by DennisK on 7/17/2023 in #questions
Creating (guest)checkout sessions with TRPC/Stripe/Zustand.
Hi! Just asking to see if this is a correct approach I am managing carts using Zustand since it is just a simple side feature of the website where they sell some merchandising. Since customers can order as a guest, I am creating a public createCheckout link function in my stripeRouter. If users have a account I will link the order to the user.
createGuestCheckoutSession: publicProcedure
.input(
z.object({
cart: z.array(
z.object({
id: z.string(),
price: z.number(),
image: z.string(),
quantity: z.number().optional(),
})
),
})
)
.mutation(async ({ ctx, input }) => {
const { stripe, req } = ctx;

const lineItems = input.cart.map((product) => ({
price: product.id,
quantity: product.quantity ?? 1,
}));

const checkoutSession = await stripe.checkout.sessions.create({
payment_method_types: ["card"],
mode: "payment",
line_items: lineItems,
success_url: `${baseUrl}/shop?checkoutSuccess=true`,
cancel_url: `${baseUrl}/shop?checkoutCanceled=true`,
});

if (!checkoutSession) {
throw new Error("Could not create checkout session");
}

return { checkoutUrl: checkoutSession.url };
}),
});
createGuestCheckoutSession: publicProcedure
.input(
z.object({
cart: z.array(
z.object({
id: z.string(),
price: z.number(),
image: z.string(),
quantity: z.number().optional(),
})
),
})
)
.mutation(async ({ ctx, input }) => {
const { stripe, req } = ctx;

const lineItems = input.cart.map((product) => ({
price: product.id,
quantity: product.quantity ?? 1,
}));

const checkoutSession = await stripe.checkout.sessions.create({
payment_method_types: ["card"],
mode: "payment",
line_items: lineItems,
success_url: `${baseUrl}/shop?checkoutSuccess=true`,
cancel_url: `${baseUrl}/shop?checkoutCanceled=true`,
});

if (!checkoutSession) {
throw new Error("Could not create checkout session");
}

return { checkoutUrl: checkoutSession.url };
}),
});
And then my checkoutButton creates the checkoutUrl:
const CheckoutButton = () => {
const { mutateAsync: createCheckoutSession } =
api.stripe.createGuestCheckoutSession.useMutation();
const { push } = useRouter();
const cart = useFromStore(useCartStore, (state) => state.cart);

return (
<button
onClick={async () => {
if (!cart) return;
const { checkoutUrl } = await createCheckoutSession({ cart });

if (checkoutUrl) {
void push(checkoutUrl);
}
}}
>
Go to checkout
</button>
);
};
const CheckoutButton = () => {
const { mutateAsync: createCheckoutSession } =
api.stripe.createGuestCheckoutSession.useMutation();
const { push } = useRouter();
const cart = useFromStore(useCartStore, (state) => state.cart);

return (
<button
onClick={async () => {
if (!cart) return;
const { checkoutUrl } = await createCheckoutSession({ cart });

if (checkoutUrl) {
void push(checkoutUrl);
}
}}
>
Go to checkout
</button>
);
};
Is this fine?
2 replies
TTCTheo's Typesafe Cult
Created by DennisK on 7/16/2023 in #questions
Making CartContext available in trpc?
Hi! Simple trpc/t3 noob question. I made a CartContext provider wrapped around my app, and now I would like trpc to create the Stripe checkout url based on the items in the cart. How can I access cart.items? I guess I have to do something in trpc.ts?
<SessionProvider session={session}>
<CartContext.Provider value={cartContext}>
<ErrorBoundary>
<Component {...pageProps} />
</ErrorBoundary>
</CartContext.Provider>
</SessionProvider>
);
};

export default api.withTRPC(MyApp);
<SessionProvider session={session}>
<CartContext.Provider value={cartContext}>
<ErrorBoundary>
<Component {...pageProps} />
</ErrorBoundary>
</CartContext.Provider>
</SessionProvider>
);
};

export default api.withTRPC(MyApp);
stripe router:
createShoppingCheckoutSession: publicProcedure.mutation(async ({ ctx }) => {
const { stripe, req, cart } = ctx;

console.log(cart); // Undefined for now

const line_items = cart.map((item) => ({
price: item.id,
quantity: item.quantity,
}));

const baseUrl =
env.NODE_ENV === "development"
? `http://${req?.headers.host ?? "localhost:3000"}`
: `https://${req?.headers.host ?? env.NEXTAUTH_URL}`;

const checkoutSession = await stripe.checkout.sessions.create({
payment_method_types: ["card"],
mode: "payment",
line_items,
success_url: `${baseUrl}/thank-you?checkoutSuccess=true`,
cancel_url: `${baseUrl}/thank-you?checkoutCanceled=true`,
});

if (!checkoutSession) {
throw new Error("Could not create checkout session");
}

return { checkoutUrl: checkoutSession.url };
}),
createShoppingCheckoutSession: publicProcedure.mutation(async ({ ctx }) => {
const { stripe, req, cart } = ctx;

console.log(cart); // Undefined for now

const line_items = cart.map((item) => ({
price: item.id,
quantity: item.quantity,
}));

const baseUrl =
env.NODE_ENV === "development"
? `http://${req?.headers.host ?? "localhost:3000"}`
: `https://${req?.headers.host ?? env.NEXTAUTH_URL}`;

const checkoutSession = await stripe.checkout.sessions.create({
payment_method_types: ["card"],
mode: "payment",
line_items,
success_url: `${baseUrl}/thank-you?checkoutSuccess=true`,
cancel_url: `${baseUrl}/thank-you?checkoutCanceled=true`,
});

if (!checkoutSession) {
throw new Error("Could not create checkout session");
}

return { checkoutUrl: checkoutSession.url };
}),
2 replies
TTCTheo's Typesafe Cult
Created by DennisK on 7/14/2023 in #questions
Handling memberships
Hi! We want to add memberships to our dashboard and hide specific sidebar menu options. What is best practice to handle these kind of things? Make a membership provider around the app? Or could I just call the api in the sidebar component
export function Sidebar({ className }: { className?: string }) {
const pathname = usePathname();
const { data } = api.user.subscriptionStatus.useQuery();
export function Sidebar({ className }: { className?: string }) {
const pathname = usePathname();
const { data } = api.user.subscriptionStatus.useQuery();
5 replies
TTCTheo's Typesafe Cult
Created by DennisK on 7/14/2023 in #questions
Loading state when quering profile data
Hi people! Started with T3 stack and working on the profile page right now. I am trying to get the current logged in profile data and I am using a protected route/api for that. However, how can I make sure the 404 page is not shown when the data is not fully loaded yet?
const Profile: NextPage = ({}) => {
const { data: profile } = api.user.me.useQuery();

if (!profile) return <ErrorPage statusCode={404} />;
console.log(profile);
return (
<>
<Head>
<title>My profile - FirstName</title>
</Head>
<div className="relative flex min-h-screen flex-col">
<div className="flex-1">
<DashboardLayout>
<div className="max-w-5xl">
<div className="max-w-2xl">
<Heading className="uppercase">My profile</Heading>
</div>
<Spacer size="md" />
{/* Account info */}
<section>
<div className="flex w-full justify-between">
<Heading as="h3" size="h3" className="uppercase">
Account info
</Heading>
</div>

<Spacer size="3xs" />
<Separator />
<Spacer size="3xs" />
<div className="grid grid-cols-2 gap-x-4">
<AccountInfo showConfirmChanges={false} />
</div>
</section>
<Spacer size="4xs" />
{/* Personal details */}
const Profile: NextPage = ({}) => {
const { data: profile } = api.user.me.useQuery();

if (!profile) return <ErrorPage statusCode={404} />;
console.log(profile);
return (
<>
<Head>
<title>My profile - FirstName</title>
</Head>
<div className="relative flex min-h-screen flex-col">
<div className="flex-1">
<DashboardLayout>
<div className="max-w-5xl">
<div className="max-w-2xl">
<Heading className="uppercase">My profile</Heading>
</div>
<Spacer size="md" />
{/* Account info */}
<section>
<div className="flex w-full justify-between">
<Heading as="h3" size="h3" className="uppercase">
Account info
</Heading>
</div>

<Spacer size="3xs" />
<Separator />
<Spacer size="3xs" />
<div className="grid grid-cols-2 gap-x-4">
<AccountInfo showConfirmChanges={false} />
</div>
</section>
<Spacer size="4xs" />
{/* Personal details */}
5 replies