make non-core env variables optional
This commit is contained in:
parent
e05b05f673
commit
29f2da7379
13 changed files with 128 additions and 102 deletions
16
.env.example
16
.env.example
|
|
@ -1,15 +1,9 @@
|
||||||
# Prisma
|
# Database
|
||||||
# https://www.prisma.io/docs/reference/database-reference/connection-urls#env
|
|
||||||
DATABASE_URL=""
|
DATABASE_URL=""
|
||||||
|
|
||||||
# Next Auth
|
# Authjs
|
||||||
# You can generate a new secret on the command line with:
|
NEXTAUTH_URL="http://localhost:3000/"
|
||||||
# openssl rand -base64 32
|
|
||||||
# https://next-auth.js.org/configuration/options#secret
|
|
||||||
NEXTAUTH_SECRET=""
|
NEXTAUTH_SECRET=""
|
||||||
NEXTAUTH_URL="http://localhost:3000"
|
|
||||||
|
|
||||||
# Next Auth Provider
|
|
||||||
GOOGLE_CLIENT_ID=""
|
GOOGLE_CLIENT_ID=""
|
||||||
GOOGLE_CLIENT_SECRET=""
|
GOOGLE_CLIENT_SECRET=""
|
||||||
GITHUB_ID=""
|
GITHUB_ID=""
|
||||||
|
|
@ -38,10 +32,10 @@ NEXT_PUBLIC_CRISP_WEBSITE_ID=""
|
||||||
|
|
||||||
# posthog
|
# posthog
|
||||||
NEXT_PUBLIC_POSTHOG_KEY=""
|
NEXT_PUBLIC_POSTHOG_KEY=""
|
||||||
NEXT_PUBLIC_POSTHOG_HOST=""
|
NEXT_PUBLIC_POSTHOG_HOST="https://app.posthog.com"
|
||||||
NEXT_PUBLIC_POSTHOG_PROXY_HOST="/ioafe"
|
NEXT_PUBLIC_POSTHOG_PROXY_HOST="/ioafe"
|
||||||
POSTHOG_PROXY_PATH="ioafe"
|
POSTHOG_PROXY_PATH="ioafe"
|
||||||
|
|
||||||
# redis for ratelimiting
|
# redis for ratelimiting
|
||||||
UPSTASH_REDIS_REST_URL=""
|
UPSTASH_REDIS_REST_URL=""
|
||||||
UPSTASH_REDIS_REST_TOKEN="="
|
UPSTASH_REDIS_REST_TOKEN=""
|
||||||
|
|
@ -4,7 +4,9 @@ import { env } from "~/env.mjs";
|
||||||
|
|
||||||
export default function CrispChat() {
|
export default function CrispChat() {
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
Crisp.configure(env.NEXT_PUBLIC_CRISP_WEBSITE_ID);
|
if (env.NEXT_PUBLIC_CRISP_WEBSITE_ID) {
|
||||||
|
Crisp.configure(env.NEXT_PUBLIC_CRISP_WEBSITE_ID);
|
||||||
|
}
|
||||||
}, []);
|
}, []);
|
||||||
|
|
||||||
return null;
|
return null;
|
||||||
|
|
|
||||||
18
src/env.mjs
18
src/env.mjs
|
|
@ -28,13 +28,13 @@ const server = z.object({
|
||||||
AWS_KEY_ID: z.string(),
|
AWS_KEY_ID: z.string(),
|
||||||
AWS_SECRET_ACCESS_KEY: z.string(),
|
AWS_SECRET_ACCESS_KEY: z.string(),
|
||||||
AWS_BUCKET_NAME: z.string(),
|
AWS_BUCKET_NAME: z.string(),
|
||||||
STRIPE_SECRET_KEY: z.string(),
|
STRIPE_SECRET_KEY: z.string().nullish(),
|
||||||
STRIPE_WEBHOOK_SECRET: z.string(),
|
STRIPE_WEBHOOK_SECRET: z.string().nullish(),
|
||||||
STRIPE_MONTHLY_PRICE_ID: z.string(),
|
STRIPE_MONTHLY_PRICE_ID: z.string().nullish(),
|
||||||
STRIPE_ANNUAL_PRICE_ID: z.string(),
|
STRIPE_ANNUAL_PRICE_ID: z.string().nullish(),
|
||||||
POSTHOG_PROXY_PATH: z.string(),
|
POSTHOG_PROXY_PATH: z.string(),
|
||||||
UPSTASH_REDIS_REST_URL: z.string(),
|
UPSTASH_REDIS_REST_URL: z.string().nullish(),
|
||||||
UPSTASH_REDIS_REST_TOKEN: z.string(),
|
UPSTASH_REDIS_REST_TOKEN: z.string().nullish(),
|
||||||
});
|
});
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
@ -43,9 +43,9 @@ const server = z.object({
|
||||||
*/
|
*/
|
||||||
const client = z.object({
|
const client = z.object({
|
||||||
// NEXT_PUBLIC_CLIENTVAR: z.string().min(1),
|
// NEXT_PUBLIC_CLIENTVAR: z.string().min(1),
|
||||||
NEXT_PUBLIC_STRIPE_PUBLISHABLE_KEY: z.string(),
|
NEXT_PUBLIC_STRIPE_PUBLISHABLE_KEY: z.string().nullish(),
|
||||||
NEXT_PUBLIC_CRISP_WEBSITE_ID: z.string(),
|
NEXT_PUBLIC_CRISP_WEBSITE_ID: z.string().nullish(),
|
||||||
NEXT_PUBLIC_POSTHOG_KEY: z.string(),
|
NEXT_PUBLIC_POSTHOG_KEY: z.string().nullish(),
|
||||||
NEXT_PUBLIC_POSTHOG_HOST: z.string(),
|
NEXT_PUBLIC_POSTHOG_HOST: z.string(),
|
||||||
NEXT_PUBLIC_POSTHOG_PROXY_HOST: z.string(),
|
NEXT_PUBLIC_POSTHOG_PROXY_HOST: z.string(),
|
||||||
});
|
});
|
||||||
|
|
|
||||||
|
|
@ -12,12 +12,12 @@ import { env } from "~/env.mjs";
|
||||||
import { type ReactNode, useEffect } from "react";
|
import { type ReactNode, useEffect } from "react";
|
||||||
|
|
||||||
// Check that PostHog is client-side (used to handle Next.js SSR)
|
// Check that PostHog is client-side (used to handle Next.js SSR)
|
||||||
if (typeof window !== "undefined") {
|
if (typeof window !== "undefined" && !!env.NEXT_PUBLIC_POSTHOG_KEY) {
|
||||||
posthog.init(env.NEXT_PUBLIC_POSTHOG_KEY, {
|
posthog.init(env.NEXT_PUBLIC_POSTHOG_KEY, {
|
||||||
api_host: env.NEXT_PUBLIC_POSTHOG_PROXY_HOST,
|
api_host: env.NEXT_PUBLIC_POSTHOG_PROXY_HOST,
|
||||||
// Enable debug mode in development
|
// Enable debug mode in development
|
||||||
loaded: (posthog) => {
|
loaded: (posthog) => {
|
||||||
if (process.env.NODE_ENV === "development") posthog.debug(false);
|
if (process.env.NODE_ENV === "development") posthog.debug();
|
||||||
},
|
},
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
@ -47,16 +47,16 @@ const PostHogIdentificationWrapper = ({
|
||||||
const posthog = usePostHog();
|
const posthog = usePostHog();
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
if (!posthog) return;
|
if (!posthog?.__loaded) return;
|
||||||
if (status === "authenticated") {
|
if (status === "authenticated") {
|
||||||
const { id, name, email, stripeSubscriptionStatus } = session?.user;
|
const { id, name, email, stripeSubscriptionStatus } = session?.user;
|
||||||
posthog.identify(id, {
|
posthog?.identify(id, {
|
||||||
name,
|
name,
|
||||||
email,
|
email,
|
||||||
stripeSubscriptionStatus,
|
stripeSubscriptionStatus,
|
||||||
});
|
});
|
||||||
} else if (status === "unauthenticated") {
|
} else if (status === "unauthenticated") {
|
||||||
posthog.reset();
|
posthog?.reset();
|
||||||
}
|
}
|
||||||
}, [posthog, session, status]);
|
}, [posthog, session, status]);
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -24,6 +24,10 @@ export default async function handler(
|
||||||
req: NextApiRequest,
|
req: NextApiRequest,
|
||||||
res: NextApiResponse
|
res: NextApiResponse
|
||||||
) {
|
) {
|
||||||
|
if (!webhookSecret || !stripe) {
|
||||||
|
return res.status(500).end("Stripe env variables not set");
|
||||||
|
}
|
||||||
|
|
||||||
if (req.method === "POST") {
|
if (req.method === "POST") {
|
||||||
const buf = await buffer(req);
|
const buf = await buffer(req);
|
||||||
const sig = req.headers["stripe-signature"];
|
const sig = req.headers["stripe-signature"];
|
||||||
|
|
@ -72,11 +76,11 @@ export default async function handler(
|
||||||
const userId = subscription.metadata.userId;
|
const userId = subscription.metadata.userId;
|
||||||
|
|
||||||
if (userId) {
|
if (userId) {
|
||||||
posthog.capture({
|
posthog?.capture({
|
||||||
distinctId: userId,
|
distinctId: userId,
|
||||||
event: "stripe invoice.payment_failed",
|
event: "stripe invoice.payment_failed",
|
||||||
});
|
});
|
||||||
void posthog.shutdownAsync();
|
void posthog?.shutdownAsync();
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
case "customer.subscription.deleted":
|
case "customer.subscription.deleted":
|
||||||
|
|
|
||||||
|
|
@ -8,6 +8,14 @@ export const stripeRouter = createTRPCRouter({
|
||||||
.input(z.object({ billedAnnually: z.boolean() }))
|
.input(z.object({ billedAnnually: z.boolean() }))
|
||||||
.mutation(
|
.mutation(
|
||||||
async ({ ctx: { prisma, stripe, session, req, posthog }, input }) => {
|
async ({ ctx: { prisma, stripe, session, req, posthog }, input }) => {
|
||||||
|
if (
|
||||||
|
!stripe ||
|
||||||
|
!env.STRIPE_ANNUAL_PRICE_ID ||
|
||||||
|
!env.STRIPE_MONTHLY_PRICE_ID
|
||||||
|
) {
|
||||||
|
throw new Error("Stripe env variables not set");
|
||||||
|
}
|
||||||
|
|
||||||
const customerId = await getOrCreateStripeCustomerIdForUser({
|
const customerId = await getOrCreateStripeCustomerIdForUser({
|
||||||
prisma,
|
prisma,
|
||||||
stripe,
|
stripe,
|
||||||
|
|
@ -50,20 +58,24 @@ export const stripeRouter = createTRPCRouter({
|
||||||
throw new Error("Could not create checkout session");
|
throw new Error("Could not create checkout session");
|
||||||
}
|
}
|
||||||
|
|
||||||
posthog.capture({
|
posthog?.capture({
|
||||||
distinctId: session.user.id,
|
distinctId: session.user.id,
|
||||||
event: "visiting checkout page",
|
event: "visiting checkout page",
|
||||||
properties: {
|
properties: {
|
||||||
billingCycle: input.billedAnnually ? "annual" : "monthly",
|
billingCycle: input.billedAnnually ? "annual" : "monthly",
|
||||||
},
|
},
|
||||||
});
|
});
|
||||||
void posthog.shutdownAsync();
|
void posthog?.shutdownAsync();
|
||||||
|
|
||||||
return { checkoutUrl: checkoutSession.url };
|
return { checkoutUrl: checkoutSession.url };
|
||||||
}
|
}
|
||||||
),
|
),
|
||||||
createBillingPortalSession: protectedProcedure.mutation(
|
createBillingPortalSession: protectedProcedure.mutation(
|
||||||
async ({ ctx: { stripe, session, prisma, req, posthog } }) => {
|
async ({ ctx: { stripe, session, prisma, req, posthog } }) => {
|
||||||
|
if (!stripe) {
|
||||||
|
throw new Error("Stripe env variables not set");
|
||||||
|
}
|
||||||
|
|
||||||
const customerId = await getOrCreateStripeCustomerIdForUser({
|
const customerId = await getOrCreateStripeCustomerIdForUser({
|
||||||
prisma,
|
prisma,
|
||||||
stripe,
|
stripe,
|
||||||
|
|
@ -89,14 +101,14 @@ export const stripeRouter = createTRPCRouter({
|
||||||
throw new Error("Could not create billing portal session");
|
throw new Error("Could not create billing portal session");
|
||||||
}
|
}
|
||||||
|
|
||||||
posthog.capture({
|
posthog?.capture({
|
||||||
distinctId: session.user.id,
|
distinctId: session.user.id,
|
||||||
event: "visiting billing portal page",
|
event: "visiting billing portal page",
|
||||||
properties: {
|
properties: {
|
||||||
stripeSubscriptionStatus: session.user.stripeSubscriptionStatus,
|
stripeSubscriptionStatus: session.user.stripeSubscriptionStatus,
|
||||||
},
|
},
|
||||||
});
|
});
|
||||||
void posthog.shutdownAsync();
|
void posthog?.shutdownAsync();
|
||||||
|
|
||||||
return { billingPortalUrl: stripeBillingPortalSession.url };
|
return { billingPortalUrl: stripeBillingPortalSession.url };
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -23,14 +23,14 @@ export const videoRouter = createTRPCRouter({
|
||||||
},
|
},
|
||||||
});
|
});
|
||||||
|
|
||||||
posthog.capture({
|
posthog?.capture({
|
||||||
distinctId: session.user.id,
|
distinctId: session.user.id,
|
||||||
event: "viewing video list",
|
event: "viewing video list",
|
||||||
properties: {
|
properties: {
|
||||||
videoAmount: videos.length,
|
videoAmount: videos.length,
|
||||||
},
|
},
|
||||||
});
|
});
|
||||||
void posthog.shutdownAsync();
|
void posthog?.shutdownAsync();
|
||||||
|
|
||||||
const videosWithThumbnailUrl = await Promise.all(
|
const videosWithThumbnailUrl = await Promise.all(
|
||||||
videos.map(async (video) => {
|
videos.map(async (video) => {
|
||||||
|
|
@ -70,7 +70,7 @@ export const videoRouter = createTRPCRouter({
|
||||||
}
|
}
|
||||||
|
|
||||||
if (session) {
|
if (session) {
|
||||||
posthog.capture({
|
posthog?.capture({
|
||||||
distinctId: session.user.id,
|
distinctId: session.user.id,
|
||||||
event: "viewing video",
|
event: "viewing video",
|
||||||
properties: {
|
properties: {
|
||||||
|
|
@ -83,7 +83,7 @@ export const videoRouter = createTRPCRouter({
|
||||||
videoShareLinkExpiresAt: video.shareLinkExpiresAt,
|
videoShareLinkExpiresAt: video.shareLinkExpiresAt,
|
||||||
},
|
},
|
||||||
});
|
});
|
||||||
void posthog.shutdownAsync();
|
void posthog?.shutdownAsync();
|
||||||
}
|
}
|
||||||
|
|
||||||
const getObjectCommand = new GetObjectCommand({
|
const getObjectCommand = new GetObjectCommand({
|
||||||
|
|
@ -110,7 +110,7 @@ export const videoRouter = createTRPCRouter({
|
||||||
videos.length >= 10 &&
|
videos.length >= 10 &&
|
||||||
session.user.stripeSubscriptionStatus !== "active"
|
session.user.stripeSubscriptionStatus !== "active"
|
||||||
) {
|
) {
|
||||||
posthog.capture({
|
posthog?.capture({
|
||||||
distinctId: session.user.id,
|
distinctId: session.user.id,
|
||||||
event: "hit video upload limit",
|
event: "hit video upload limit",
|
||||||
properties: {
|
properties: {
|
||||||
|
|
@ -118,7 +118,7 @@ export const videoRouter = createTRPCRouter({
|
||||||
stripeSubscriptionStatus: session.user.stripeSubscriptionStatus,
|
stripeSubscriptionStatus: session.user.stripeSubscriptionStatus,
|
||||||
},
|
},
|
||||||
});
|
});
|
||||||
void posthog.shutdownAsync();
|
void posthog?.shutdownAsync();
|
||||||
|
|
||||||
throw new TRPCError({
|
throw new TRPCError({
|
||||||
code: "FORBIDDEN",
|
code: "FORBIDDEN",
|
||||||
|
|
@ -127,7 +127,7 @@ export const videoRouter = createTRPCRouter({
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
posthog.capture({
|
posthog?.capture({
|
||||||
distinctId: session.user.id,
|
distinctId: session.user.id,
|
||||||
event: "uploading video",
|
event: "uploading video",
|
||||||
properties: {
|
properties: {
|
||||||
|
|
@ -135,7 +135,7 @@ export const videoRouter = createTRPCRouter({
|
||||||
stripeSubscriptionStatus: session.user.stripeSubscriptionStatus,
|
stripeSubscriptionStatus: session.user.stripeSubscriptionStatus,
|
||||||
},
|
},
|
||||||
});
|
});
|
||||||
void posthog.shutdownAsync();
|
void posthog?.shutdownAsync();
|
||||||
|
|
||||||
const video = await prisma.video.create({
|
const video = await prisma.video.create({
|
||||||
data: {
|
data: {
|
||||||
|
|
@ -184,7 +184,7 @@ export const videoRouter = createTRPCRouter({
|
||||||
throw new TRPCError({ code: "FORBIDDEN" });
|
throw new TRPCError({ code: "FORBIDDEN" });
|
||||||
}
|
}
|
||||||
|
|
||||||
posthog.capture({
|
posthog?.capture({
|
||||||
distinctId: session.user.id,
|
distinctId: session.user.id,
|
||||||
event: "update video setSharing",
|
event: "update video setSharing",
|
||||||
properties: {
|
properties: {
|
||||||
|
|
@ -192,7 +192,7 @@ export const videoRouter = createTRPCRouter({
|
||||||
videoSharing: input.sharing,
|
videoSharing: input.sharing,
|
||||||
},
|
},
|
||||||
});
|
});
|
||||||
void posthog.shutdownAsync();
|
void posthog?.shutdownAsync();
|
||||||
|
|
||||||
return {
|
return {
|
||||||
success: true,
|
success: true,
|
||||||
|
|
@ -218,7 +218,7 @@ export const videoRouter = createTRPCRouter({
|
||||||
throw new TRPCError({ code: "FORBIDDEN" });
|
throw new TRPCError({ code: "FORBIDDEN" });
|
||||||
}
|
}
|
||||||
|
|
||||||
posthog.capture({
|
posthog?.capture({
|
||||||
distinctId: session.user.id,
|
distinctId: session.user.id,
|
||||||
event: "update video delete_after_link_expires",
|
event: "update video delete_after_link_expires",
|
||||||
properties: {
|
properties: {
|
||||||
|
|
@ -226,7 +226,7 @@ export const videoRouter = createTRPCRouter({
|
||||||
delete_after_link_expires: input.delete_after_link_expires,
|
delete_after_link_expires: input.delete_after_link_expires,
|
||||||
},
|
},
|
||||||
});
|
});
|
||||||
void posthog.shutdownAsync();
|
void posthog?.shutdownAsync();
|
||||||
|
|
||||||
return {
|
return {
|
||||||
success: true,
|
success: true,
|
||||||
|
|
@ -255,7 +255,7 @@ export const videoRouter = createTRPCRouter({
|
||||||
throw new TRPCError({ code: "FORBIDDEN" });
|
throw new TRPCError({ code: "FORBIDDEN" });
|
||||||
}
|
}
|
||||||
|
|
||||||
posthog.capture({
|
posthog?.capture({
|
||||||
distinctId: session.user.id,
|
distinctId: session.user.id,
|
||||||
event: "update video shareLinkExpiresAt",
|
event: "update video shareLinkExpiresAt",
|
||||||
properties: {
|
properties: {
|
||||||
|
|
@ -263,7 +263,7 @@ export const videoRouter = createTRPCRouter({
|
||||||
shareLinkExpiresAt: input.shareLinkExpiresAt,
|
shareLinkExpiresAt: input.shareLinkExpiresAt,
|
||||||
},
|
},
|
||||||
});
|
});
|
||||||
void posthog.shutdownAsync();
|
void posthog?.shutdownAsync();
|
||||||
|
|
||||||
return {
|
return {
|
||||||
success: true,
|
success: true,
|
||||||
|
|
@ -292,7 +292,7 @@ export const videoRouter = createTRPCRouter({
|
||||||
throw new TRPCError({ code: "FORBIDDEN" });
|
throw new TRPCError({ code: "FORBIDDEN" });
|
||||||
}
|
}
|
||||||
|
|
||||||
posthog.capture({
|
posthog?.capture({
|
||||||
distinctId: session.user.id,
|
distinctId: session.user.id,
|
||||||
event: "update video title",
|
event: "update video title",
|
||||||
properties: {
|
properties: {
|
||||||
|
|
@ -300,7 +300,7 @@ export const videoRouter = createTRPCRouter({
|
||||||
title: input.title,
|
title: input.title,
|
||||||
},
|
},
|
||||||
});
|
});
|
||||||
void posthog.shutdownAsync();
|
void posthog?.shutdownAsync();
|
||||||
|
|
||||||
return {
|
return {
|
||||||
success: true,
|
success: true,
|
||||||
|
|
@ -325,14 +325,14 @@ export const videoRouter = createTRPCRouter({
|
||||||
throw new TRPCError({ code: "FORBIDDEN" });
|
throw new TRPCError({ code: "FORBIDDEN" });
|
||||||
}
|
}
|
||||||
|
|
||||||
posthog.capture({
|
posthog?.capture({
|
||||||
distinctId: session.user.id,
|
distinctId: session.user.id,
|
||||||
event: "video delete",
|
event: "video delete",
|
||||||
properties: {
|
properties: {
|
||||||
videoId: input.videoId,
|
videoId: input.videoId,
|
||||||
},
|
},
|
||||||
});
|
});
|
||||||
void posthog.shutdownAsync();
|
void posthog?.shutdownAsync();
|
||||||
|
|
||||||
const deleteVideoObject = await s3.send(
|
const deleteVideoObject = await s3.send(
|
||||||
new DeleteObjectCommand({
|
new DeleteObjectCommand({
|
||||||
|
|
|
||||||
|
|
@ -125,9 +125,11 @@ const enforceUserIsAuthed = t.middleware(async ({ ctx, next }) => {
|
||||||
if (!ctx.session || !ctx.session.user) {
|
if (!ctx.session || !ctx.session.user) {
|
||||||
throw new TRPCError({ code: "UNAUTHORIZED" });
|
throw new TRPCError({ code: "UNAUTHORIZED" });
|
||||||
}
|
}
|
||||||
const { success } = await rateLimit.limit(ctx.session.user.id);
|
if (rateLimit) {
|
||||||
if (!success) {
|
const { success } = await rateLimit.limit(ctx.session.user.id);
|
||||||
throw new TRPCError({ code: "TOO_MANY_REQUESTS" });
|
if (!success) {
|
||||||
|
throw new TRPCError({ code: "TOO_MANY_REQUESTS" });
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return next({
|
return next({
|
||||||
|
|
|
||||||
|
|
@ -70,40 +70,44 @@ export const authOptions: NextAuthOptions = {
|
||||||
],
|
],
|
||||||
events: {
|
events: {
|
||||||
async signIn(message) {
|
async signIn(message) {
|
||||||
const client = new PostHog(env.NEXT_PUBLIC_POSTHOG_KEY, {
|
if (!!env.NEXT_PUBLIC_POSTHOG_KEY) {
|
||||||
host: env.NEXT_PUBLIC_POSTHOG_HOST,
|
const client = new PostHog(env.NEXT_PUBLIC_POSTHOG_KEY, {
|
||||||
});
|
host: env.NEXT_PUBLIC_POSTHOG_HOST,
|
||||||
|
});
|
||||||
|
|
||||||
client.capture({
|
client.capture({
|
||||||
distinctId: message.user.id,
|
distinctId: message.user.id,
|
||||||
event: "user logged in",
|
event: "user logged in",
|
||||||
properties: {
|
properties: {
|
||||||
provider: message.account?.provider,
|
provider: message.account?.provider,
|
||||||
isNewUser: message.isNewUser,
|
isNewUser: message.isNewUser,
|
||||||
},
|
},
|
||||||
});
|
});
|
||||||
|
|
||||||
await client.shutdownAsync();
|
await client.shutdownAsync();
|
||||||
|
}
|
||||||
},
|
},
|
||||||
async signOut(message) {
|
async signOut(message) {
|
||||||
const session = message.session as unknown as {
|
if (!!env.NEXT_PUBLIC_POSTHOG_KEY) {
|
||||||
id: string;
|
const session = message.session as unknown as {
|
||||||
sessionToken: string;
|
id: string;
|
||||||
userId: string;
|
sessionToken: string;
|
||||||
expires: Date;
|
userId: string;
|
||||||
};
|
expires: Date;
|
||||||
if (!session?.userId) return;
|
};
|
||||||
|
if (!session?.userId) return;
|
||||||
|
|
||||||
const client = new PostHog(env.NEXT_PUBLIC_POSTHOG_KEY, {
|
const client = new PostHog(env.NEXT_PUBLIC_POSTHOG_KEY, {
|
||||||
host: env.NEXT_PUBLIC_POSTHOG_HOST,
|
host: env.NEXT_PUBLIC_POSTHOG_HOST,
|
||||||
});
|
});
|
||||||
|
|
||||||
client.capture({
|
client.capture({
|
||||||
distinctId: session.userId,
|
distinctId: session.userId,
|
||||||
event: "user logged out",
|
event: "user logged out",
|
||||||
});
|
});
|
||||||
|
|
||||||
await client.shutdownAsync();
|
await client.shutdownAsync();
|
||||||
|
}
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
pages: {
|
pages: {
|
||||||
|
|
|
||||||
|
|
@ -1,6 +1,8 @@
|
||||||
import { PostHog } from "posthog-node";
|
import { PostHog } from "posthog-node";
|
||||||
import { env } from "~/env.mjs";
|
import { env } from "~/env.mjs";
|
||||||
|
|
||||||
export const posthog = new PostHog(env.NEXT_PUBLIC_POSTHOG_KEY, {
|
export const posthog = !!env.NEXT_PUBLIC_POSTHOG_KEY
|
||||||
host: env.NEXT_PUBLIC_POSTHOG_HOST,
|
? new PostHog(env.NEXT_PUBLIC_POSTHOG_KEY, {
|
||||||
});
|
host: env.NEXT_PUBLIC_POSTHOG_HOST,
|
||||||
|
})
|
||||||
|
: null;
|
||||||
|
|
|
||||||
|
|
@ -2,10 +2,13 @@ import { Ratelimit } from "@upstash/ratelimit";
|
||||||
import { Redis } from "@upstash/redis";
|
import { Redis } from "@upstash/redis";
|
||||||
import { env } from "~/env.mjs";
|
import { env } from "~/env.mjs";
|
||||||
|
|
||||||
export const rateLimit = new Ratelimit({
|
export const rateLimit =
|
||||||
redis: new Redis({
|
!!env.UPSTASH_REDIS_REST_URL && !!env.UPSTASH_REDIS_REST_TOKEN
|
||||||
url: env.UPSTASH_REDIS_REST_URL,
|
? new Ratelimit({
|
||||||
token: env.UPSTASH_REDIS_REST_TOKEN,
|
redis: new Redis({
|
||||||
}),
|
url: env.UPSTASH_REDIS_REST_URL,
|
||||||
limiter: Ratelimit.slidingWindow(60, "60 s"),
|
token: env.UPSTASH_REDIS_REST_TOKEN,
|
||||||
});
|
}),
|
||||||
|
limiter: Ratelimit.slidingWindow(60, "60 s"),
|
||||||
|
})
|
||||||
|
: null;
|
||||||
|
|
|
||||||
|
|
@ -60,7 +60,7 @@ export const handleInvoicePaid = async ({
|
||||||
event: Stripe.Event;
|
event: Stripe.Event;
|
||||||
stripe: Stripe;
|
stripe: Stripe;
|
||||||
prisma: PrismaClient;
|
prisma: PrismaClient;
|
||||||
posthog: PostHog;
|
posthog: PostHog | null;
|
||||||
}) => {
|
}) => {
|
||||||
const invoice = event.data.object as Stripe.Invoice;
|
const invoice = event.data.object as Stripe.Invoice;
|
||||||
const subscriptionId = invoice.subscription;
|
const subscriptionId = invoice.subscription;
|
||||||
|
|
@ -81,14 +81,14 @@ export const handleInvoicePaid = async ({
|
||||||
});
|
});
|
||||||
|
|
||||||
if (userId && subscription.status) {
|
if (userId && subscription.status) {
|
||||||
posthog.capture({
|
posthog?.capture({
|
||||||
distinctId: userId,
|
distinctId: userId,
|
||||||
event: "stripe invoice.paid",
|
event: "stripe invoice.paid",
|
||||||
properties: {
|
properties: {
|
||||||
stripeSubscriptionStatus: subscription.status,
|
stripeSubscriptionStatus: subscription.status,
|
||||||
},
|
},
|
||||||
});
|
});
|
||||||
void posthog.shutdownAsync();
|
void posthog?.shutdownAsync();
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
@ -99,7 +99,7 @@ export const handleSubscriptionCreatedOrUpdated = async ({
|
||||||
}: {
|
}: {
|
||||||
event: Stripe.Event;
|
event: Stripe.Event;
|
||||||
prisma: PrismaClient;
|
prisma: PrismaClient;
|
||||||
posthog: PostHog;
|
posthog: PostHog | null;
|
||||||
}) => {
|
}) => {
|
||||||
const subscription = event.data.object as Stripe.Subscription;
|
const subscription = event.data.object as Stripe.Subscription;
|
||||||
const userId = subscription.metadata.userId;
|
const userId = subscription.metadata.userId;
|
||||||
|
|
@ -116,11 +116,11 @@ export const handleSubscriptionCreatedOrUpdated = async ({
|
||||||
});
|
});
|
||||||
|
|
||||||
if (userId && subscription.status) {
|
if (userId && subscription.status) {
|
||||||
posthog.capture({
|
posthog?.capture({
|
||||||
distinctId: userId,
|
distinctId: userId,
|
||||||
event: "stripe subscription created or updated",
|
event: "stripe subscription created or updated",
|
||||||
});
|
});
|
||||||
void posthog.shutdownAsync();
|
void posthog?.shutdownAsync();
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
@ -131,7 +131,7 @@ export const handleSubscriptionCanceled = async ({
|
||||||
}: {
|
}: {
|
||||||
event: Stripe.Event;
|
event: Stripe.Event;
|
||||||
prisma: PrismaClient;
|
prisma: PrismaClient;
|
||||||
posthog: PostHog;
|
posthog: PostHog | null;
|
||||||
}) => {
|
}) => {
|
||||||
const subscription = event.data.object as Stripe.Subscription;
|
const subscription = event.data.object as Stripe.Subscription;
|
||||||
const userId = subscription.metadata.userId;
|
const userId = subscription.metadata.userId;
|
||||||
|
|
@ -148,10 +148,10 @@ export const handleSubscriptionCanceled = async ({
|
||||||
});
|
});
|
||||||
|
|
||||||
if (userId && subscription.status) {
|
if (userId && subscription.status) {
|
||||||
posthog.capture({
|
posthog?.capture({
|
||||||
distinctId: userId,
|
distinctId: userId,
|
||||||
event: "stripe subscription cancelled",
|
event: "stripe subscription cancelled",
|
||||||
});
|
});
|
||||||
void posthog.shutdownAsync();
|
void posthog?.shutdownAsync();
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
|
||||||
|
|
@ -1,5 +1,8 @@
|
||||||
import Stripe from "stripe";
|
import Stripe from "stripe";
|
||||||
import { env } from "~/env.mjs";
|
import { env } from "~/env.mjs";
|
||||||
export const stripe = new Stripe(env.STRIPE_SECRET_KEY, {
|
|
||||||
apiVersion: "2022-11-15",
|
export const stripe = !!env.STRIPE_SECRET_KEY
|
||||||
});
|
? new Stripe(env.STRIPE_SECRET_KEY, {
|
||||||
|
apiVersion: "2022-11-15",
|
||||||
|
})
|
||||||
|
: null;
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue