From d98f95b7ca1afa4fb7ac911648d790d8bae4adcd Mon Sep 17 00:00:00 2001 From: luciano Date: Thu, 7 May 2026 13:43:24 +0200 Subject: [PATCH] =?UTF-8?q?fix(billing):=20build=20su=20VPS=20=E2=80=94=20?= =?UTF-8?q?ExtendedPrismaClient,=20apiVersion=20Stripe?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Tre fix che emergono solo durante il build di produzione (typecheck stretto, niente tsx watch lazy): - `packages/db` ora ri-esporta Subscription / BillingWebhookEvent / SubscriptionStatus / BillingInterval / Achievement, così non serve importare da `@prisma/client` direttamente da apps/api (che non ce l'ha tra le deps). - `apps/api/src/modules/billing/{service,webhook.routes}.ts` usano ExtendedPrismaClient (il client post-`$extends` di prisma-field-encryption) invece di PrismaClient base. Il client esteso ha tipi diversi per via dell'estensione, e la tipizzazione stretta lo richiede. - `apiVersion` di Stripe portata a `2026-04-22.dahlia` (la versione corrente in stripe@22.x). La precedente `2025-09-30.clover` era già obsoleta nei tipi. Lint pulito, 99/99 test verdi, build api ok in locale. Co-Authored-By: Claude Opus 4.7 (1M context) --- apps/api/src/modules/billing/service.ts | 12 ++++++------ apps/api/src/modules/billing/stripe-client.ts | 2 +- apps/api/src/modules/billing/webhook.routes.ts | 4 ++-- packages/db/src/index.ts | 5 +++++ 4 files changed, 14 insertions(+), 9 deletions(-) diff --git a/apps/api/src/modules/billing/service.ts b/apps/api/src/modules/billing/service.ts index 32984aa..7dabdac 100644 --- a/apps/api/src/modules/billing/service.ts +++ b/apps/api/src/modules/billing/service.ts @@ -1,10 +1,10 @@ +import type { ExtendedPrismaClient, Subscription } from '@ketopath/db'; import { computeTrialEndsAt, isProActive, type SubscriptionSnapshot, type SubscriptionStatus as SharedStatus, } from '@ketopath/shared'; -import type { PrismaClient, Subscription } from '@prisma/client'; // eslint-disable-next-line import/no-named-as-default import type Stripe from 'stripe'; @@ -29,7 +29,7 @@ export function toSnapshot(sub: Subscription | null): SubscriptionSnapshot | nul * dalla data di registrazione. Idempotente: se esiste già, non tocca nulla. */ export async function ensureSubscription( - prisma: PrismaClient, + prisma: ExtendedPrismaClient, userId: string, signupAt: Date, ): Promise { @@ -45,13 +45,13 @@ export async function ensureSubscription( } export async function getSubscription( - prisma: PrismaClient, + prisma: ExtendedPrismaClient, userId: string, ): Promise { return prisma.subscription.findUnique({ where: { userId } }); } -export async function isUserPro(prisma: PrismaClient, userId: string): Promise { +export async function isUserPro(prisma: ExtendedPrismaClient, userId: string): Promise { const sub = await getSubscription(prisma, userId); return isProActive(toSnapshot(sub)); } @@ -100,7 +100,7 @@ function mapInterval( * payload N volte senza side effect. */ export async function applyStripeSubscription( - prisma: PrismaClient, + prisma: ExtendedPrismaClient, stripeSub: Stripe.Subscription, ): Promise { const userId = stripeSub.metadata?.userId; @@ -153,7 +153,7 @@ export async function applyStripeSubscription( * Invocata da uno scheduler giornaliero (vedi notifications/scheduler). * Restituisce il numero di record aggiornati. */ -export async function expireFinishedTrials(prisma: PrismaClient, now: Date = new Date()) { +export async function expireFinishedTrials(prisma: ExtendedPrismaClient, now: Date = new Date()) { const res = await prisma.subscription.updateMany({ where: { status: 'TRIALING', diff --git a/apps/api/src/modules/billing/stripe-client.ts b/apps/api/src/modules/billing/stripe-client.ts index 6c147ee..3361e94 100644 --- a/apps/api/src/modules/billing/stripe-client.ts +++ b/apps/api/src/modules/billing/stripe-client.ts @@ -18,7 +18,7 @@ export function getStripe(): Stripe { _stripe = new Stripe(billingEnv.STRIPE_SECRET_KEY, { // Pin esplicito: niente sorprese quando Stripe rilascia una nuova // apiVersion. Aggiornare insieme allo `stripe` package. - apiVersion: '2025-09-30.clover', + apiVersion: '2026-04-22.dahlia', typescript: true, appInfo: { name: 'KetoPath', version: '0.0.0' }, }); diff --git a/apps/api/src/modules/billing/webhook.routes.ts b/apps/api/src/modules/billing/webhook.routes.ts index e5d4c39..c51784d 100644 --- a/apps/api/src/modules/billing/webhook.routes.ts +++ b/apps/api/src/modules/billing/webhook.routes.ts @@ -1,4 +1,4 @@ -import type { PrismaClient } from '@prisma/client'; +import type { ExtendedPrismaClient } from '@ketopath/db'; import type { FastifyPluginAsync } from 'fastify'; // eslint-disable-next-line import/no-named-as-default import type Stripe from 'stripe'; @@ -88,7 +88,7 @@ export const stripeWebhookRoutes: FastifyPluginAsync = async (parent) => { }; async function dispatchEvent( - prisma: PrismaClient, + prisma: ExtendedPrismaClient, stripe: Stripe, event: Stripe.Event, ): Promise { diff --git a/packages/db/src/index.ts b/packages/db/src/index.ts index 79b74f5..bce7ed6 100644 --- a/packages/db/src/index.ts +++ b/packages/db/src/index.ts @@ -2,6 +2,7 @@ export { prisma } from './client.js'; export type { ExtendedPrismaClient } from './client.js'; export { ActivityLevel, + BillingInterval, CookingTime, Difficulty, FastStatus, @@ -12,9 +13,12 @@ export { Phase, Prisma, Role, + SubscriptionStatus, } from '@prisma/client'; export type { Account, + Achievement, + BillingWebhookEvent, DeviceToken, FastEvent, Ingredient, @@ -26,6 +30,7 @@ export type { Recipe, RecipeIngredient, Session, + Subscription, User, Verification, WeightEntry,