96 lines · 3.9 KB
/**
 * Creates (or finds) the Stripe test-mode objects gitfor uses: a Pro monthly price and the prepaid packs, at the
 * amounts in src/lib/pricing.ts, then writes STRIPE_PRICE_PRO, STRIPE_PRICE_CUSTOM_DOMAIN and STRIPE_TOPUP_PRICES into .dev.vars. Idempotent via price lookup keys.
 *
 *   STRIPE_SETUP_KEY=sk_test_... bun run scripts/stripe-test-setup.ts [--write .dev.vars]
 *   STRIPE_SETUP_KEY=rk_live_... bun run scripts/stripe-test-setup.ts --live
 *
 * Live keys need an explicit `--live` and can't be combined with `--write`, so live price ids never land in
 * .dev.vars. Never prints the key.
 */
import { existsSync, readFileSync, writeFileSync } from "node:fs";
import Stripe from "stripe";
import { CUSTOM_DOMAIN_PRICE_CENTS, PACKS, PRO_PRICE_CENTS } from "../src/lib/pricing";

const key = process.env.STRIPE_SETUP_KEY ?? "";
const live = process.argv.includes("--live");
const testKey = /^(sk|rk)_test_/.test(key);
const liveKey = /^(sk|rk)_live_/.test(key);
if (live ? !liveKey || process.argv.includes("--write") : !testKey) {
  console.error(
    live
      ? "--live needs a live key (sk_live_ or rk_live_) and can't be combined with --write; refusing to continue."
      : "STRIPE_SETUP_KEY must be a Stripe test-mode key (sk_test_ or rk_test_); pass --live for live mode.",
  );
  process.exit(1);
}
const stripe = new Stripe(key);

/**
 * The active price for `lookupKey` at exactly `cents`. Stripe prices are immutable, so when pricing.ts changes
 * the amount a new price takes over the lookup key and the old one is archived (existing subscriptions keep it).
 */
async function ensurePrice(
  lookupKey: string,
  product: string,
  cents: number,
  recurring: boolean,
  metadata: Record<string, string>,
): Promise<string> {
  const existing = (await stripe.prices.list({ lookup_keys: [lookupKey], limit: 1, expand: ["data.product"] })).data[0];