fix(billing): build su VPS — ExtendedPrismaClient, apiVersion Stripe

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) <noreply@anthropic.com>
This commit is contained in:
lucianoandClaude Opus 4.7 committed 2026-05-07 13:43:24 +02:00
1 parent 11d73eae69
commit d98f95b7ca
4 files changed
+14 -9

No files matched your search

+6 -6
View File
@@ -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<Subscription> {
@@ -45,13 +45,13 @@ export async function ensureSubscription(
}
export async function getSubscription(
prisma: PrismaClient,
prisma: ExtendedPrismaClient,
userId: string,
): Promise<Subscription | null> {
return prisma.subscription.findUnique({ where: { userId } });
}
export async function isUserPro(prisma: PrismaClient, userId: string): Promise<boolean> {
export async function isUserPro(prisma: ExtendedPrismaClient, userId: string): Promise<boolean> {
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<void> {
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',
@@ -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' },
});
@@ -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<void> {
+5
View File
@@ -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,