Idempotent money-IN grant — credit amount exactly once, keyed on the ledger row id idemKey (a STABLE per-payment
anchor: pi:<id> / inv:<id> / cs:<id>), so a webhook redelivery or dashboard "Resend" can NEVER double-credit. The
money-IN twin of debitOnceIfCovers (which guards money-OUT). legacyKey, when given, is an ADDITIONAL anchor
honoured: if a row already exists under it the money is already credited and we skip — so MOVING the idempotency key
across a deploy (e.g. event-id → session-id) can't re-grant an in-flight payment. This is the LEDGER-INTEGRITY
chokepoint for every grant: it rejects a non-finite / non-integer / non-positive delta, so an upstream
Number(metadata.credits) can never let "Infinity" (which would poison every later balance read) or "500.9" (which
would break balance == SUM(int delta)) reach the ledger. Returns true ONLY on a FRESH grant; on a fresh grant the cash
amountCents (when given) is annotated for the $ detail. Use this for Stripe webhook crediting (top-up / subscription).
OptionalamountCents: number | nullOptionallegacyKey: string
@suluk/credits— a metered credit ledger (C046, extracted verbatim). The package OWNS the schema (credit_transactioncredit_amount/credit_keysidecars); the app injects a Drizzle handle (D1 in prod, bun:sqlite in tests). The money-correctness core: the ATOMICdebitIfCovers(a conditional INSERT that can't drive the ledger negative under concurrency) + the idempotentdebitOnceIfCovers(the partial-refund double-spend guard) + per-key spend + the activity-log query. App-specific payment-alert kinds + the user-table count stay in the app.