import { db } from '../config/firebase' import { RevenueCatEvent } from '../types' const PREMIUM_ACTIVE_TYPES = new Set([ 'INITIAL_PURCHASE', 'RENEWAL', 'PRODUCT_CHANGE', 'TRANSFER', 'UNCANCELLATION', ]) const PREMIUM_REVOKED_TYPES = new Set([ 'EXPIRATION', 'CANCELLATION', 'SUBSCRIBER_ALIAS', ]) const PREMIUM_ENTITLEMENT_ID = 'closer_premium' export async function syncEntitlement(event: RevenueCatEvent): Promise { const { type, app_user_id: uid, id: eventId } = event.event // Check idempotency - skip if we've already processed this event const eventRef = db().collection('entitlement_events').doc(eventId) const eventDoc = await eventRef.get() if (eventDoc.exists) { console.log(`[entitlement] skipping duplicate event: ${eventId}`) return } // Store event for idempotency (with 7-day TTL via Firestore rule or scheduled cleanup) await eventRef.set({ processedAt: new Date() }) // Verify entitlement_id matches expected premium entitlement const entitlementId = event.event.entitlement?.identifier || event.event.entitlement_id if (entitlementId !== PREMIUM_ENTITLEMENT_ID) { console.log(`[entitlement] ignored event for wrong entitlement: ${entitlementId} (expected: ${PREMIUM_ENTITLEMENT_ID})`) return } if (PREMIUM_ACTIVE_TYPES.has(type)) { await db().collection('users').doc(uid).update({ hasPremium: true }) console.log(`[entitlement] hasPremium=true for ${uid} (${type})`) return } if (PREMIUM_REVOKED_TYPES.has(type)) { await db().collection('users').doc(uid).update({ hasPremium: false }) console.log(`[entitlement] hasPremium=false for ${uid} (${type})`) return } console.log(`[entitlement] ignored event type: ${type}`) }