@frank/billing (0.2.1)
Installation
@frank:registry=npm install @frank/billing@0.2.1"@frank/billing": "0.2.1"About this package
@frank/billing
Stripe billing over plain REST for Frank products, money and credits in integer cents: subscription and one-off Checkout, HMAC webhook -> workspace billing state, publish billing gate, trial cohorts and reminders, and the workspace credit ledger. Ported from Blockwise src/lib/billing, src/lib/credits and src/lib/trial with no behaviour change. No Stripe SDK, no Supabase dependency: the product passes its own service client.
Public API
Everything comes from @frank/billing: configFromEnv; offers
(getBillingOffer, offerRunsCheckoutTrial); Checkout
(startWorkspaceCheckout, buildCheckoutSessionRequest,
createOneOffCheckoutSession, validateStripePriceForOffer); webhooks
(constructStripeWebhookEvent, applyStripeBillingEvent,
reconciliationEventForSubscription); the gate
(decidePublishBillingGate, resolvePublishBillingGate,
publishBillingGateMessage); trials (loadTrialStatus, findTrialConsumedAt,
recoverMissingTrialReminders); credits (grantWorkspaceCredits,
reserveAdPackCredits, settleAdPackCredits, refundAdPackReservation).
Browser entry
Client components (the Blockwise publish wizard) import
@frank/billing/browser instead of the root. The root entry pulls in the
Stripe scaffold and the webhook/credit/reconciliation services, which import
node:crypto, so a browser bundle that imports the root fails to build. The
browser entry re-exports only the pure offer lookup and the catalog types it
needs - getBillingOffer, findOfferByVersion, currencyForMarket,
isBillingMarket/isBillingCurrency/isBillingProduct,
offerRunsCheckoutTrial, offerVersionRunsCheckoutTrial and the BillingOffer
/ BillingCatalog / BillingOfferKey / BillingTrialStart types. Every symbol
is the same implementation the root exports; nothing is copied. Server calls
keep importing @frank/billing.
Config
The caller builds one BillingConfig: env (from configFromEnv(), the only
process.env reader: STRIPE_SECRET_KEY, STRIPE_WEBHOOK_SECRET, STRIPE_PRICE_ID,
STRIPE_PRICE_IDS_JSON, BLOCKWISE_SELF_SERVE_TRIAL_ENABLED,
BLOCKWISE_STRIPE_TOS_CONSENT), catalog (offers, markets, checkout-trial
versions, roles), tables, messages, rules (cents, trial days, pack
credits) and jobs.lapsePauseKind; stages and job enqueues are injected.
Example
import { configFromEnv, startWorkspaceCheckout } from "@frank/billing";
const config = { env: configFromEnv(), catalog, tables, messages, rules, jobs };
const result = await startWorkspaceCheckout(config, {
service, workspaceId, role: "owner", userId: null, customerEmail,
product: "ad_studio", market: "AU", successUrl, cancelUrl, idempotencyKey,
});
Dependencies
Development dependencies
| ID | Version |
|---|---|
| @types/node | ^22.15.30 |
| esbuild | ^0.28.2 |