diff --git a/packages/billing/src/schema/create-billing-checkout.schema.ts b/packages/billing/src/schema/create-billing-checkout.schema.ts index be476921a..22a85bdc5 100644 --- a/packages/billing/src/schema/create-billing-checkout.schema.ts +++ b/packages/billing/src/schema/create-billing-checkout.schema.ts @@ -5,7 +5,7 @@ import { LineItemUsageType, PaymentType } from '../create-billing-schema'; export const CreateBillingCheckoutSchema = z .object({ returnUrl: z.string().url(), - accountId: z.string(), + accountId: z.string().uuid(), paymentType: PaymentType, lineItems: z.array( z.object({ @@ -16,7 +16,7 @@ export const CreateBillingCheckoutSchema = z ), trialDays: z.number().optional(), customerId: z.string().optional(), - customerEmail: z.string().optional(), + customerEmail: z.string().email().optional(), }) .refine( (schema) => { diff --git a/packages/features/team-accounts/src/schema/leave-team-account.schema.ts b/packages/features/team-accounts/src/schema/leave-team-account.schema.ts index 1ba4c6ce5..a9168cdae 100644 --- a/packages/features/team-accounts/src/schema/leave-team-account.schema.ts +++ b/packages/features/team-accounts/src/schema/leave-team-account.schema.ts @@ -1,6 +1,6 @@ import { z } from 'zod'; export const LeaveTeamAccountSchema = z.object({ - accountId: z.string(), + accountId: z.string().uuid(), confirmation: z.custom((value) => value === 'LEAVE'), }); diff --git a/packages/features/team-accounts/src/schema/update-invitation-schema.ts b/packages/features/team-accounts/src/schema/update-invitation-schema.ts index f833fdd55..4882695e9 100644 --- a/packages/features/team-accounts/src/schema/update-invitation-schema.ts +++ b/packages/features/team-accounts/src/schema/update-invitation-schema.ts @@ -1,8 +1,6 @@ import { z } from 'zod'; -type Role = string; - export const UpdateInvitationSchema = z.object({ invitationId: z.number(), - role: z.custom(() => z.string().min(1)), + role: z.string().min(1), }); diff --git a/packages/features/team-accounts/src/server/services/leave-team-account.service.ts b/packages/features/team-accounts/src/server/services/leave-team-account.service.ts index 059cdc1d8..a889eb68a 100644 --- a/packages/features/team-accounts/src/server/services/leave-team-account.service.ts +++ b/packages/features/team-accounts/src/server/services/leave-team-account.service.ts @@ -7,8 +7,8 @@ import { Logger } from '@kit/shared/logger'; import { Database } from '@kit/supabase/database'; const Schema = z.object({ - accountId: z.string(), - userId: z.string(), + accountId: z.string().uuid(), + userId: z.string().uuid(), }); export class LeaveTeamAccountService { diff --git a/packages/mailers/src/schema/mailer.schema.ts b/packages/mailers/src/schema/mailer.schema.ts index 4f77c3189..1fd1f5849 100644 --- a/packages/mailers/src/schema/mailer.schema.ts +++ b/packages/mailers/src/schema/mailer.schema.ts @@ -3,7 +3,9 @@ import { z } from 'zod'; export const MailerSchema = z .object({ to: z.string().email(), - from: z.string().email(), + // this is not necessarily formatted + // as an email so we type it loosely + from: z.string().min(1), subject: z.string(), }) .and( diff --git a/packages/stripe/src/components/stripe-embedded-checkout.tsx b/packages/stripe/src/components/stripe-embedded-checkout.tsx index 6fcf3c093..722d256c7 100644 --- a/packages/stripe/src/components/stripe-embedded-checkout.tsx +++ b/packages/stripe/src/components/stripe-embedded-checkout.tsx @@ -2,7 +2,6 @@ import { useState } from 'react'; -import { invariant } from '@epic-web/invariant'; import { EmbeddedCheckout, EmbeddedCheckoutProvider, @@ -16,11 +15,13 @@ import { DialogTitle, } from '@kit/ui/dialog'; -const STRIPE_PUBLISHABLE_KEY = process.env.NEXT_PUBLIC_STRIPE_PUBLISHABLE_KEY; +import { StripeClientEnvSchema } from '../schema/stripe-client-env.schema'; -invariant(STRIPE_PUBLISHABLE_KEY, 'Stripe publishable key is required'); +const { publishableKey } = StripeClientEnvSchema.parse({ + publishableKey: process.env.NEXT_PUBLIC_STRIPE_PUBLISHABLE_KEY, +}); -const stripePromise = loadStripe(STRIPE_PUBLISHABLE_KEY); +const stripePromise = loadStripe(publishableKey); export function StripeCheckout({ checkoutToken, diff --git a/packages/stripe/src/schema/stripe-client-env.schema.ts b/packages/stripe/src/schema/stripe-client-env.schema.ts index c0fa90cf2..5cb12ee39 100644 --- a/packages/stripe/src/schema/stripe-client-env.schema.ts +++ b/packages/stripe/src/schema/stripe-client-env.schema.ts @@ -1,5 +1,15 @@ import { z } from 'zod'; -export const StripeClientEnvSchema = z.object({ - NEXT_PUBLIC_STRIPE_PUBLISHABLE_KEY: z.string().min(1), -}); +export const StripeClientEnvSchema = z + .object({ + publishableKey: z.string().min(1), + }) + .refine( + (schema) => { + return schema.publishableKey.startsWith('pk_'); + }, + { + path: ['publishableKey'], + message: `Stripe publishable key must start with 'pk_'`, + }, + ); diff --git a/packages/stripe/src/schema/stripe-server-env.schema.ts b/packages/stripe/src/schema/stripe-server-env.schema.ts index c0bd7c5a7..d5e2d4d1f 100644 --- a/packages/stripe/src/schema/stripe-server-env.schema.ts +++ b/packages/stripe/src/schema/stripe-server-env.schema.ts @@ -1,6 +1,25 @@ import { z } from 'zod'; -export const StripeServerEnvSchema = z.object({ - STRIPE_SECRET_KEY: z.string().min(1), - STRIPE_WEBHOOK_SECRET: z.string().min(1), -}); +export const StripeServerEnvSchema = z + .object({ + secretKey: z.string().min(1), + webhooksSecret: z.string().min(1), + }) + .refine( + (schema) => { + return schema.secretKey.startsWith('sk_'); + }, + { + path: ['STRIPE_SECRET_KEY'], + message: `Stripe secret key must start with 'sk_'`, + }, + ) + .refine( + (schema) => { + return schema.webhooksSecret.startsWith('whsec_'); + }, + { + path: ['STRIPE_WEBHOOK_SECRET'], + message: `Stripe webhook secret must start with 'whsec_'`, + }, + ); diff --git a/packages/stripe/src/services/stripe-sdk.ts b/packages/stripe/src/services/stripe-sdk.ts index ccff536a2..f0d9299cf 100644 --- a/packages/stripe/src/services/stripe-sdk.ts +++ b/packages/stripe/src/services/stripe-sdk.ts @@ -16,7 +16,7 @@ export async function createStripeClient() { STRIPE_WEBHOOK_SECRET: process.env.STRIPE_WEBHOOK_SECRET, }); - return new Stripe(stripeServerEnv.STRIPE_SECRET_KEY, { + return new Stripe(stripeServerEnv.secretKey, { apiVersion: STRIPE_API_VERSION, }); } diff --git a/packages/stripe/src/services/stripe-webhook-handler.service.ts b/packages/stripe/src/services/stripe-webhook-handler.service.ts index 19d867986..b0d55e8a4 100644 --- a/packages/stripe/src/services/stripe-webhook-handler.service.ts +++ b/packages/stripe/src/services/stripe-webhook-handler.service.ts @@ -32,9 +32,9 @@ export class StripeWebhookHandlerService const signatureKey = `stripe-signature`; const signature = request.headers.get(signatureKey)!; - const { STRIPE_WEBHOOK_SECRET } = StripeServerEnvSchema.parse({ - STRIPE_SECRET_KEY: process.env.STRIPE_SECRET_KEY, - STRIPE_WEBHOOK_SECRET: process.env.STRIPE_WEBHOOK_SECRET, + const { webhooksSecret } = StripeServerEnvSchema.parse({ + secretKey: process.env.STRIPE_SECRET_KEY, + webhooksSecret: process.env.STRIPE_WEBHOOK_SECRET, }); const stripe = await this.loadStripe(); @@ -42,7 +42,7 @@ export class StripeWebhookHandlerService const event = stripe.webhooks.constructEvent( body, signature, - STRIPE_WEBHOOK_SECRET, + webhooksSecret, ); if (!event) {