Session 14: Africa checkout, Tank01 NBA/MLB wiring, WNBA+MLB odds proxies, OAuth icons, loading skeletons (1330 tests)

This commit is contained in:
Kev
2026-06-11 10:06:49 -04:00
parent 10159209fa
commit f5d79cf70d
22 changed files with 979 additions and 27 deletions
+32
View File
@@ -12,8 +12,19 @@ const PRICE_MAP = {
analyst_founder: process.env.STRIPE_PRICE_ANALYST_FOUNDER || 'price_analyst_founder',
desk: process.env.STRIPE_PRICE_DESK || 'price_desk_monthly',
desk_founder: process.env.STRIPE_PRICE_DESK_FOUNDER || 'price_desk_founder',
// Session 14 — Africa tier ($4.99/mo). The Stripe product must be
// created in the dashboard before STRIPE_PRICE_AFRICA carries a real
// ID. Until then `getPriceId('africa')` returns a sentinel that
// surfaces a clean error to the user via the route handler.
africa: process.env.STRIPE_PRICE_AFRICA || null,
};
// Sentinel marker — getPriceId returns this when the tier is valid
// but the Stripe price hasn't been provisioned yet. The route layer
// checks for it and returns 503 with a friendly message rather than
// passing "null" to Stripe.
const PRICE_UNCONFIGURED = '__unconfigured__';
// VYNDR is the canonical brand promo. BETONBLK stays in the default list so
// codes distributed before the rebrand keep redeeming during the transition.
const VALID_FOUNDER_CODES = (process.env.FOUNDER_CODES || 'FOUNDER2026,VYNDR,BETONBLK,EARLYBIRD').split(',');
@@ -29,12 +40,30 @@ function getPriceId(tier, founderCode) {
const isFounder = isFounderCodeValid(founderCode);
if (tier === 'analyst') return isFounder ? PRICE_MAP.analyst_founder : PRICE_MAP.analyst;
if (tier === 'desk') return isFounder ? PRICE_MAP.desk_founder : PRICE_MAP.desk;
if (tier === 'africa') {
// Africa tier doesn't have a founder discount — it IS the
// discount. Returns the sentinel when STRIPE_PRICE_AFRICA is
// unset so the route handler can produce a clean error instead
// of forwarding a null price ID to Stripe.
return PRICE_MAP.africa || PRICE_UNCONFIGURED;
}
throw new Error(`Invalid tier: ${tier}`);
}
async function createCheckoutSession(userId, email, tier, founderCode) {
const supabase = getSupabaseServiceClient();
const priceId = getPriceId(tier, founderCode);
// Session 14 — tier is valid but the upstream Stripe product
// hasn't been provisioned (most common case: africa before
// STRIPE_PRICE_AFRICA is configured in Coolify). Surface a clean
// 503 with `code: 'tier_unconfigured'` instead of letting null
// propagate to Stripe.
if (priceId === PRICE_UNCONFIGURED) {
const err = new Error(`Pricing for "${tier}" is not configured yet.`);
err.code = 'tier_unconfigured';
err.statusCode = 503;
throw err;
}
const isFounder = isFounderCodeValid(founderCode);
// Get or create Stripe customer
@@ -248,4 +277,7 @@ module.exports = {
constructWebhookEvent,
isFounderCodeValid,
getPriceId,
// Session 14 — exposed so the route layer + tests can recognize
// the "tier valid but Stripe price not provisioned" state.
PRICE_UNCONFIGURED,
};