import { env } from "cloudflare:workers";
import Stripe from "stripe";
import { HttpError } from "../errors";
import { PACKS, PRO_PRICE_CENTS } from "~/lib/pricing";
import type { PackDef } from "~/lib/pricing";
/**
* Stripe is optional: every billing path checks this first, and nothing else in the app requires Stripe.
* Keys from different modes (a live secret with a test publishable key, say) disable billing entirely and
* log the reason once per isolate; the rest of the forge keeps serving.
*/
export function stripeEnabled(): boolean {
return Boolean(env.STRIPE_SECRET_KEY) && !reportedModeError();
}
export function isTestKey(key: string | undefined): boolean {
return Boolean(key && /^(sk|rk)_test_/.test(key));
}
type KeyMode = "test" | "live";
/** The mode a Stripe key belongs to, from its prefix; null when it has no recognizable prefix. */
export function keyMode(key: string | undefined, kinds: string[]): KeyMode | null {
const match = key ? new RegExp(`^(${kinds.join("|")})_(test|live)_`).exec(key) : null;
return match ? (match[2] as KeyMode) : null;
}
/**
* Why the Stripe configuration is unsafe to run, or null. The secret key must be sk_/rk_ test or live; the
* publishable key, when set, must be the same mode; STRIPE_WEBHOOK_MODE (whsec_ secrets carry no mode), when
* set, must match too. Mixing modes would accept events or show prices from the other mode.
*/
export function stripeModeError(
vars: { secret?: string; publishable?: string; webhookMode?: string } = {
secret: env.STRIPE_SECRET_KEY,
publishable: env.STRIPE_PUBLISHABLE_KEY,
webhookMode: env.STRIPE_WEBHOOK_MODE,
},
): string | null {
if (!vars.secret) return null;