Slefhostet und postgres

This commit is contained in:
2026-04-02 11:39:57 +02:00
parent b1c99893a6
commit 08483c7075
215 changed files with 4584 additions and 5190 deletions

View File

@@ -2,13 +2,15 @@ import AsyncStorage from '@react-native-async-storage/async-storage';
import {
BackendApiError,
BillingProvider,
BillingSummary,
BillingSummary,
HealthCheckRequest,
HealthCheckResponse,
PlanId,
PurchaseProductId,
RevenueCatCustomerInfo,
RevenueCatEntitlementInfo,
RevenueCatNonSubscriptionTransaction,
RevenueCatSyncSource,
ScanPlantRequest,
ScanPlantResponse,
SemanticSearchRequest,
@@ -46,11 +48,12 @@ const TOPUP_CREDITS_BY_PRODUCT: Record<PurchaseProductId, number> = {
monthly_pro: 0,
yearly_pro: 0,
topup_small: 25,
topup_medium: 75,
topup_large: 200,
topup_medium: 120,
topup_large: 300,
};
const REVENUECAT_PRO_ENTITLEMENT_ID = (process.env.EXPO_PUBLIC_REVENUECAT_PRO_ENTITLEMENT_ID || 'pro').trim() || 'pro';
const SUPPORTED_REVENUECAT_SUBSCRIPTION_PRODUCTS = new Set<PurchaseProductId>(['monthly_pro', 'yearly_pro']);
interface MockAccountRecord {
userId: string;
@@ -243,6 +246,42 @@ const normalizeRevenueCatTransactions = (
const nonSubscriptions = customerInfo?.nonSubscriptions || {};
return Object.values(nonSubscriptions).flatMap((entries) => Array.isArray(entries) ? entries : []);
};
const summarizeRevenueCatCustomerInfo = (customerInfo: RevenueCatCustomerInfo) => {
const activeEntitlements = customerInfo?.entitlements?.active || {};
return {
appUserId: customerInfo?.appUserId ?? null,
originalAppUserId: customerInfo?.originalAppUserId ?? null,
activeEntitlements: Object.entries(activeEntitlements).map(([id, entitlement]) => ({
id,
productIdentifier: entitlement?.productIdentifier ?? null,
expirationDate: entitlement?.expirationDate || entitlement?.expiresDate || null,
})),
allPurchasedProductIdentifiers: customerInfo?.allPurchasedProductIdentifiers ?? [],
nonSubscriptionTransactions: normalizeRevenueCatTransactions(customerInfo).map((transaction) => ({
productIdentifier: transaction?.productIdentifier ?? null,
transactionIdentifier: transaction?.transactionIdentifier || transaction?.transactionId || null,
})),
};
};
const getValidProEntitlement = (customerInfo: RevenueCatCustomerInfo): RevenueCatEntitlementInfo | null => {
const activeEntitlements = customerInfo?.entitlements?.active || {};
const proEntitlement = activeEntitlements[REVENUECAT_PRO_ENTITLEMENT_ID];
if (!proEntitlement) {
return null;
}
if (
proEntitlement.productIdentifier
&& SUPPORTED_REVENUECAT_SUBSCRIPTION_PRODUCTS.has(proEntitlement.productIdentifier as PurchaseProductId)
) {
return proEntitlement;
}
console.warn('[Billing][Mock] Ignoring unsupported RevenueCat pro entitlement', summarizeRevenueCatCustomerInfo(customerInfo));
return null;
};
const readIdempotentResponse = <T,>(store: IdempotencyStore, key: string): T | null => {
const record = store[key];
@@ -652,17 +691,25 @@ export const mockBackendService = {
syncRevenueCatState: async (request: {
userId: string;
customerInfo: RevenueCatCustomerInfo;
source?: RevenueCatSyncSource;
}): Promise<SyncRevenueCatStateResponse> => {
return withUserLock(request.userId, async () => {
const stores = await loadStores();
const account = getOrCreateAccount(stores, request.userId);
const activeEntitlements = request.customerInfo?.entitlements?.active || {};
const proEntitlement = activeEntitlements[REVENUECAT_PRO_ENTITLEMENT_ID];
const proEntitlement = getValidProEntitlement(request.customerInfo);
const source = request.source || 'app_init';
account.plan = proEntitlement ? 'pro' : 'free';
account.provider = 'revenuecat';
account.monthlyAllowance = getMonthlyAllowanceForPlan(account.plan, account.userId);
account.renewsAt = proEntitlement?.expirationDate || proEntitlement?.expiresDate || null;
console.log('[Billing][Mock] Syncing RevenueCat customer info', {
source,
customerInfo: summarizeRevenueCatCustomerInfo(request.customerInfo),
});
if (source !== 'topup_purchase') {
account.plan = proEntitlement ? 'pro' : 'free';
account.provider = 'revenuecat';
account.monthlyAllowance = getMonthlyAllowanceForPlan(account.plan, account.userId);
account.renewsAt = proEntitlement?.expirationDate || proEntitlement?.expiresDate || null;
}
for (const transaction of normalizeRevenueCatTransactions(request.customerInfo)) {
const productId = transaction.productIdentifier as PurchaseProductId | undefined;