@augmenting-integrations/billing 8.0.6 → 8.1.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/server/handlers.d.ts +136 -0
- package/dist/server/handlers.d.ts.map +1 -0
- package/dist/server.cjs +504 -0
- package/dist/server.cjs.map +1 -1
- package/dist/server.d.ts +1 -0
- package/dist/server.d.ts.map +1 -1
- package/dist/server.js +503 -0
- package/dist/server.js.map +1 -1
- package/package.json +9 -6
package/dist/server.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../src/server/client.ts","../src/server/customer.ts"],"sourcesContent":["import Stripe from \"stripe\";\nimport { getSecret } from \"@augmenting-integrations/aws/server\";\n\n// =============================================================================\n// Stripe client init.\n//\n// Production: API key, publishable key, and API version come bundled in a\n// single SecretsManager JSON blob (created by augint-example-infra) keyed by\n// `STRIPE_API_SECRET_ARN`. Webhook signing secret is a separate per-endpoint\n// secret at `STRIPE_WEBHOOK_SECRET_ARN`.\n//\n// Local dev: STRIPE_API_KEY / STRIPE_PUBLISHABLE_KEY / STRIPE_API_VERSION /\n// STRIPE_WEBHOOK_SECRET in .env are used directly.\n//\n// Cached on globalThis for warm-Lambda reuse + Next dev hot-reload.\n// =============================================================================\n\nexport type StripeBundle = {\n client: Stripe;\n publishableKey: string;\n apiVersion: string;\n webhookSecret: string;\n};\n\nexport type CreateStripeClientOptions = {\n /** ARN of the bundled `{apiKey, publishableKey, apiVersion}` JSON secret. */\n apiSecretArn?: string;\n /** ARN of the per-endpoint webhook signing secret. */\n webhookSecretArn?: string;\n};\n\ntype StripeApiBundle = {\n apiKey: string;\n publishableKey: string;\n apiVersion: string;\n};\n\ndeclare global {\n var __stripeBillingCache: Promise<StripeBundle> | undefined;\n}\n\nasync function loadBundle(opts: CreateStripeClientOptions): Promise<StripeBundle> {\n // Local dev short-circuit\n if (process.env.STRIPE_API_KEY && process.env.STRIPE_WEBHOOK_SECRET) {\n const apiKey = process.env.STRIPE_API_KEY;\n const publishableKey = process.env.STRIPE_PUBLISHABLE_KEY ?? \"\";\n const apiVersion = process.env.STRIPE_API_VERSION ?? \"2025-09-30.clover\";\n const webhookSecret = process.env.STRIPE_WEBHOOK_SECRET;\n const client = new Stripe(apiKey, {\n apiVersion: apiVersion as Stripe.LatestApiVersion,\n });\n return { client, publishableKey, apiVersion, webhookSecret };\n }\n\n const apiSecretArn = opts.apiSecretArn ?? process.env.STRIPE_API_SECRET_ARN;\n const webhookSecretArn = opts.webhookSecretArn ?? process.env.STRIPE_WEBHOOK_SECRET_ARN;\n if (!apiSecretArn || !webhookSecretArn) {\n throw new Error(\n `[billing] createStripeClient requires (STRIPE_API_KEY + STRIPE_WEBHOOK_SECRET) for local dev or both apiSecretArn + webhookSecretArn (or matching env vars) for Lambda. Got apiSecretArn=${!!apiSecretArn}, webhookSecretArn=${!!webhookSecretArn}.`,\n );\n }\n\n const [bundleJson, webhookSecret] = await Promise.all([\n getSecret(apiSecretArn),\n getSecret(webhookSecretArn),\n ]);\n if (!bundleJson || !webhookSecret) {\n throw new Error(\n `[billing] Stripe secrets could not be resolved (apiSecretArn=${apiSecretArn}, webhookSecretArn=${webhookSecretArn})`,\n );\n }\n const bundle = JSON.parse(bundleJson) as StripeApiBundle;\n if (!bundle.apiKey || !bundle.publishableKey || !bundle.apiVersion) {\n throw new Error(\n `[billing] Stripe secret ${apiSecretArn} missing apiKey/publishableKey/apiVersion`,\n );\n }\n const client = new Stripe(bundle.apiKey, {\n apiVersion: bundle.apiVersion as Stripe.LatestApiVersion,\n });\n return {\n client,\n publishableKey: bundle.publishableKey,\n apiVersion: bundle.apiVersion,\n webhookSecret,\n };\n}\n\n/**\n * Get-or-create the bundled Stripe client + publishable key + webhook secret.\n * Cached for the container lifetime. Pass options or rely on env vars.\n */\nexport function getStripe(opts: CreateStripeClientOptions = {}): Promise<StripeBundle> {\n globalThis.__stripeBillingCache ??= loadBundle(opts);\n return globalThis.__stripeBillingCache;\n}\n\n/**\n * Verify a Stripe webhook against the cached signing secret. Returns the\n * decoded Stripe.Event; throws if the signature doesn't match.\n */\nexport async function verifyStripeWebhook(\n rawBody: string,\n signature: string,\n opts: CreateStripeClientOptions = {},\n): Promise<Stripe.Event> {\n const { client, webhookSecret } = await getStripe(opts);\n return client.webhooks.constructEvent(rawBody, signature, webhookSecret);\n}\n","import type Stripe from \"stripe\";\n\n// =============================================================================\n// Stripe customer find-or-create.\n//\n// This is the library's pure-Stripe helper: it takes the customer-id the\n// caller has on file (typically User.stripe_customer_id), checks Stripe for\n// liveness, and creates a new one if missing or deleted. The caller is\n// responsible for persisting the (possibly new) id back to its User row.\n//\n// Pure of Prisma so it works with any DB layer.\n// =============================================================================\n\nexport type StripeCustomerInput = {\n /** Existing customer ID on the user (e.g. User.stripe_customer_id). */\n existingId?: string | null;\n email: string;\n name?: string | null;\n /**\n * Stable identifier baked into the customer's metadata. Typically the\n * stringified User.id; lets dashboard / webhook downstreams correlate.\n */\n appUserId: string;\n};\n\nexport type FindOrCreateResult = {\n /** The live (possibly newly-created) Stripe customer id. */\n customerId: string;\n /** True when a new customer was created on Stripe in this call. */\n created: boolean;\n};\n\n/**\n * Idempotently find-or-create a Stripe Customer. If `existingId` resolves to\n * a live (non-deleted) customer, returns that id. Otherwise creates a new\n * customer and returns its id with `created: true`.\n *\n * Caller is responsible for persisting `customerId` to its own DB when\n * `created` is true.\n */\nexport async function findOrCreateStripeCustomer(\n input: StripeCustomerInput,\n stripe: Stripe,\n): Promise<FindOrCreateResult> {\n if (input.existingId) {\n try {\n const existing = await stripe.customers.retrieve(input.existingId);\n if (!existing.deleted) {\n return { customerId: existing.id, created: false };\n }\n } catch (err: unknown) {\n const code =\n err && typeof err === \"object\" && \"code\" in err\n ? (err as { code: string }).code\n : undefined;\n if (code !== \"resource_missing\") throw err;\n // resource_missing -> fall through to recreate\n }\n }\n\n const created = await stripe.customers.create({\n email: input.email,\n name: input.name ?? undefined,\n metadata: { app_user_id: input.appUserId },\n });\n return { customerId: created.id, created: true };\n}\n"],"mappings":";AAAA,OAAO,YAAY;AACnB,SAAS,iBAAiB;AAwC1B,eAAe,WAAW,MAAwD;AAEhF,MAAI,QAAQ,IAAI,kBAAkB,QAAQ,IAAI,uBAAuB;AACnE,UAAM,SAAS,QAAQ,IAAI;AAC3B,UAAM,iBAAiB,QAAQ,IAAI,0BAA0B;AAC7D,UAAM,aAAa,QAAQ,IAAI,sBAAsB;AACrD,UAAMA,iBAAgB,QAAQ,IAAI;AAClC,UAAMC,UAAS,IAAI,OAAO,QAAQ;AAAA,MAChC;AAAA,IACF,CAAC;AACD,WAAO,EAAE,QAAAA,SAAQ,gBAAgB,YAAY,eAAAD,eAAc;AAAA,EAC7D;AAEA,QAAM,eAAe,KAAK,gBAAgB,QAAQ,IAAI;AACtD,QAAM,mBAAmB,KAAK,oBAAoB,QAAQ,IAAI;AAC9D,MAAI,CAAC,gBAAgB,CAAC,kBAAkB;AACtC,UAAM,IAAI;AAAA,MACR,4LAA4L,CAAC,CAAC,YAAY,sBAAsB,CAAC,CAAC,gBAAgB;AAAA,IACpP;AAAA,EACF;AAEA,QAAM,CAAC,YAAY,aAAa,IAAI,MAAM,QAAQ,IAAI;AAAA,IACpD,UAAU,YAAY;AAAA,IACtB,UAAU,gBAAgB;AAAA,EAC5B,CAAC;AACD,MAAI,CAAC,cAAc,CAAC,eAAe;AACjC,UAAM,IAAI;AAAA,MACR,gEAAgE,YAAY,sBAAsB,gBAAgB;AAAA,IACpH;AAAA,EACF;AACA,QAAM,SAAS,KAAK,MAAM,UAAU;AACpC,MAAI,CAAC,OAAO,UAAU,CAAC,OAAO,kBAAkB,CAAC,OAAO,YAAY;AAClE,UAAM,IAAI;AAAA,MACR,2BAA2B,YAAY;AAAA,IACzC;AAAA,EACF;AACA,QAAM,SAAS,IAAI,OAAO,OAAO,QAAQ;AAAA,IACvC,YAAY,OAAO;AAAA,EACrB,CAAC;AACD,SAAO;AAAA,IACL;AAAA,IACA,gBAAgB,OAAO;AAAA,IACvB,YAAY,OAAO;AAAA,IACnB;AAAA,EACF;AACF;AAMO,SAAS,UAAU,OAAkC,CAAC,GAA0B;AACrF,aAAW,yBAAyB,WAAW,IAAI;AACnD,SAAO,WAAW;AACpB;AAMA,eAAsB,oBACpB,SACA,WACA,OAAkC,CAAC,GACZ;AACvB,QAAM,EAAE,QAAQ,cAAc,IAAI,MAAM,UAAU,IAAI;AACtD,SAAO,OAAO,SAAS,eAAe,SAAS,WAAW,aAAa;AACzE;;;ACpEA,eAAsB,2BACpB,OACA,QAC6B;AAC7B,MAAI,MAAM,YAAY;AACpB,QAAI;AACF,YAAM,WAAW,MAAM,OAAO,UAAU,SAAS,MAAM,UAAU;AACjE,UAAI,CAAC,SAAS,SAAS;AACrB,eAAO,EAAE,YAAY,SAAS,IAAI,SAAS,MAAM;AAAA,MACnD;AAAA,IACF,SAAS,KAAc;AACrB,YAAM,OACJ,OAAO,OAAO,QAAQ,YAAY,UAAU,MACvC,IAAyB,OAC1B;AACN,UAAI,SAAS,mBAAoB,OAAM;AAAA,IAEzC;AAAA,EACF;AAEA,QAAM,UAAU,MAAM,OAAO,UAAU,OAAO;AAAA,IAC5C,OAAO,MAAM;AAAA,IACb,MAAM,MAAM,QAAQ;AAAA,IACpB,UAAU,EAAE,aAAa,MAAM,UAAU;AAAA,EAC3C,CAAC;AACD,SAAO,EAAE,YAAY,QAAQ,IAAI,SAAS,KAAK;AACjD;","names":["webhookSecret","client"]}
|
|
1
|
+
{"version":3,"sources":["../src/server/client.ts","../src/server/customer.ts","../src/server/handlers.ts"],"sourcesContent":["import Stripe from \"stripe\";\nimport { getSecret } from \"@augmenting-integrations/aws/server\";\n\n// =============================================================================\n// Stripe client init.\n//\n// Production: API key, publishable key, and API version come bundled in a\n// single SecretsManager JSON blob (created by augint-example-infra) keyed by\n// `STRIPE_API_SECRET_ARN`. Webhook signing secret is a separate per-endpoint\n// secret at `STRIPE_WEBHOOK_SECRET_ARN`.\n//\n// Local dev: STRIPE_API_KEY / STRIPE_PUBLISHABLE_KEY / STRIPE_API_VERSION /\n// STRIPE_WEBHOOK_SECRET in .env are used directly.\n//\n// Cached on globalThis for warm-Lambda reuse + Next dev hot-reload.\n// =============================================================================\n\nexport type StripeBundle = {\n client: Stripe;\n publishableKey: string;\n apiVersion: string;\n webhookSecret: string;\n};\n\nexport type CreateStripeClientOptions = {\n /** ARN of the bundled `{apiKey, publishableKey, apiVersion}` JSON secret. */\n apiSecretArn?: string;\n /** ARN of the per-endpoint webhook signing secret. */\n webhookSecretArn?: string;\n};\n\ntype StripeApiBundle = {\n apiKey: string;\n publishableKey: string;\n apiVersion: string;\n};\n\ndeclare global {\n var __stripeBillingCache: Promise<StripeBundle> | undefined;\n}\n\nasync function loadBundle(opts: CreateStripeClientOptions): Promise<StripeBundle> {\n // Local dev short-circuit\n if (process.env.STRIPE_API_KEY && process.env.STRIPE_WEBHOOK_SECRET) {\n const apiKey = process.env.STRIPE_API_KEY;\n const publishableKey = process.env.STRIPE_PUBLISHABLE_KEY ?? \"\";\n const apiVersion = process.env.STRIPE_API_VERSION ?? \"2025-09-30.clover\";\n const webhookSecret = process.env.STRIPE_WEBHOOK_SECRET;\n const client = new Stripe(apiKey, {\n apiVersion: apiVersion as Stripe.LatestApiVersion,\n });\n return { client, publishableKey, apiVersion, webhookSecret };\n }\n\n const apiSecretArn = opts.apiSecretArn ?? process.env.STRIPE_API_SECRET_ARN;\n const webhookSecretArn = opts.webhookSecretArn ?? process.env.STRIPE_WEBHOOK_SECRET_ARN;\n if (!apiSecretArn || !webhookSecretArn) {\n throw new Error(\n `[billing] createStripeClient requires (STRIPE_API_KEY + STRIPE_WEBHOOK_SECRET) for local dev or both apiSecretArn + webhookSecretArn (or matching env vars) for Lambda. Got apiSecretArn=${!!apiSecretArn}, webhookSecretArn=${!!webhookSecretArn}.`,\n );\n }\n\n const [bundleJson, webhookSecret] = await Promise.all([\n getSecret(apiSecretArn),\n getSecret(webhookSecretArn),\n ]);\n if (!bundleJson || !webhookSecret) {\n throw new Error(\n `[billing] Stripe secrets could not be resolved (apiSecretArn=${apiSecretArn}, webhookSecretArn=${webhookSecretArn})`,\n );\n }\n const bundle = JSON.parse(bundleJson) as StripeApiBundle;\n if (!bundle.apiKey || !bundle.publishableKey || !bundle.apiVersion) {\n throw new Error(\n `[billing] Stripe secret ${apiSecretArn} missing apiKey/publishableKey/apiVersion`,\n );\n }\n const client = new Stripe(bundle.apiKey, {\n apiVersion: bundle.apiVersion as Stripe.LatestApiVersion,\n });\n return {\n client,\n publishableKey: bundle.publishableKey,\n apiVersion: bundle.apiVersion,\n webhookSecret,\n };\n}\n\n/**\n * Get-or-create the bundled Stripe client + publishable key + webhook secret.\n * Cached for the container lifetime. Pass options or rely on env vars.\n */\nexport function getStripe(opts: CreateStripeClientOptions = {}): Promise<StripeBundle> {\n globalThis.__stripeBillingCache ??= loadBundle(opts);\n return globalThis.__stripeBillingCache;\n}\n\n/**\n * Verify a Stripe webhook against the cached signing secret. Returns the\n * decoded Stripe.Event; throws if the signature doesn't match.\n */\nexport async function verifyStripeWebhook(\n rawBody: string,\n signature: string,\n opts: CreateStripeClientOptions = {},\n): Promise<Stripe.Event> {\n const { client, webhookSecret } = await getStripe(opts);\n return client.webhooks.constructEvent(rawBody, signature, webhookSecret);\n}\n","import type Stripe from \"stripe\";\n\n// =============================================================================\n// Stripe customer find-or-create.\n//\n// This is the library's pure-Stripe helper: it takes the customer-id the\n// caller has on file (typically User.stripe_customer_id), checks Stripe for\n// liveness, and creates a new one if missing or deleted. The caller is\n// responsible for persisting the (possibly new) id back to its User row.\n//\n// Pure of Prisma so it works with any DB layer.\n// =============================================================================\n\nexport type StripeCustomerInput = {\n /** Existing customer ID on the user (e.g. User.stripe_customer_id). */\n existingId?: string | null;\n email: string;\n name?: string | null;\n /**\n * Stable identifier baked into the customer's metadata. Typically the\n * stringified User.id; lets dashboard / webhook downstreams correlate.\n */\n appUserId: string;\n};\n\nexport type FindOrCreateResult = {\n /** The live (possibly newly-created) Stripe customer id. */\n customerId: string;\n /** True when a new customer was created on Stripe in this call. */\n created: boolean;\n};\n\n/**\n * Idempotently find-or-create a Stripe Customer. If `existingId` resolves to\n * a live (non-deleted) customer, returns that id. Otherwise creates a new\n * customer and returns its id with `created: true`.\n *\n * Caller is responsible for persisting `customerId` to its own DB when\n * `created` is true.\n */\nexport async function findOrCreateStripeCustomer(\n input: StripeCustomerInput,\n stripe: Stripe,\n): Promise<FindOrCreateResult> {\n if (input.existingId) {\n try {\n const existing = await stripe.customers.retrieve(input.existingId);\n if (!existing.deleted) {\n return { customerId: existing.id, created: false };\n }\n } catch (err: unknown) {\n const code =\n err && typeof err === \"object\" && \"code\" in err\n ? (err as { code: string }).code\n : undefined;\n if (code !== \"resource_missing\") throw err;\n // resource_missing -> fall through to recreate\n }\n }\n\n const created = await stripe.customers.create({\n email: input.email,\n name: input.name ?? undefined,\n metadata: { app_user_id: input.appUserId },\n });\n return { customerId: created.id, created: true };\n}\n","import \"server-only\";\nimport { NextResponse } from \"next/server\";\nimport type Stripe from \"stripe\";\nimport { z } from \"zod\";\n\nimport { getStripe } from \"./client.js\";\nimport { findOrCreateStripeCustomer } from \"./customer.js\";\n\n// =============================================================================\n// Library-owned billing route handlers.\n//\n// createBillingHandlers() takes the spoke's `auth()`, `getDb()`, and\n// `getOrCreateAppUser()` and returns a handler set that drops into the\n// spoke's app/api/billing/* tree as 3-line re-exports:\n//\n// // app/api/billing/route.ts\n// import { billingHandlers } from \"@/lib/billing\";\n// export const { GET } = billingHandlers.aggregate;\n//\n// URL shape, response shape, error shape, and DB writes are all owned by\n// the library. Spoke schemas are validated structurally -- the canonical\n// User/CreditTransaction/PaymentMethod models must be present with the\n// fields below.\n// =============================================================================\n\n// ----- Structural DB shape (must match the canonical Prisma fragments) -----\n\nexport type BillingUser = {\n id: bigint | string | number;\n email: string;\n name: string;\n credit_balance: number | bigint | string;\n stripe_customer_id: string | null;\n stripe_default_payment_method: string | null;\n stripe_default_payment_method_display: string | null;\n auto_recharge_enabled: boolean;\n auto_recharge_threshold: number | bigint | string | null;\n auto_recharge_amount: number | bigint | string | null;\n};\n\nexport type BillingPaymentMethodRow = {\n id: bigint | string | number;\n user_id: bigint | string | number;\n stripe_payment_method_id: string;\n brand: string;\n last4: string;\n exp_month: number;\n exp_year: number;\n is_default: boolean;\n created_at: Date;\n};\n\nexport type BillingCreditTransactionRow = {\n id: bigint | string | number;\n user_id: bigint | string | number;\n type: string;\n amount: number | bigint | string;\n description: string | null;\n stripe_payment_intent_id: string | null;\n payment_method_display: string | null;\n created_at: Date;\n};\n\ntype AnyArgs = Record<string, unknown>;\n\n/**\n * Structural Prisma-like surface the library handlers consume. The spoke's\n * generated PrismaClient satisfies this shape automatically as long as the\n * canonical models are present in its schema.\n */\nexport type BillingDb = {\n user: {\n findFirst: (args: AnyArgs) => Promise<BillingUser | null>;\n update: (args: AnyArgs) => Promise<BillingUser | Partial<BillingUser>>;\n };\n paymentMethod: {\n findMany: (args: AnyArgs) => Promise<BillingPaymentMethodRow[]>;\n findUnique: (args: AnyArgs) => Promise<BillingPaymentMethodRow | null>;\n upsert: (args: AnyArgs) => Promise<BillingPaymentMethodRow>;\n update: (args: AnyArgs) => Promise<BillingPaymentMethodRow>;\n updateMany: (args: AnyArgs) => Promise<{ count: number }>;\n delete: (args: AnyArgs) => Promise<BillingPaymentMethodRow>;\n };\n creditTransaction: {\n findMany: (args: AnyArgs) => Promise<BillingCreditTransactionRow[]>;\n findUnique: (args: AnyArgs) => Promise<BillingCreditTransactionRow | null>;\n aggregate: (args: AnyArgs) => Promise<{ _sum: { amount: unknown } }>;\n create: (args: AnyArgs) => Promise<BillingCreditTransactionRow>;\n };\n $transaction: <T>(ops: unknown[] | ((tx: BillingDb) => Promise<T>)) => Promise<T>;\n};\n\n// ----- Auth dep (matches Auth.js v5's `auth()` return) -----\n\ntype SessionLike = { user?: unknown } | null;\n\ntype AuthFn = () => Promise<SessionLike>;\n\n// ----- Factory options -----\n\nexport type CreateBillingHandlersOptions = {\n auth: AuthFn;\n getDb: () => Promise<BillingDb>;\n getOrCreateAppUser: (session: SessionLike) => Promise<BillingUser>;\n /**\n * Recent-transactions limit on /api/billing aggregate + /api/billing/transactions.\n * Default 10.\n */\n recentLimit?: number;\n /**\n * Minimum top-up cents. Default 500 ($5).\n */\n minTopUpCents?: number;\n /**\n * Maximum top-up cents. Default 100_000 ($1,000).\n */\n maxTopUpCents?: number;\n};\n\n// ----- Validators -----\n\nfunction buildSchemas(minCents: number, maxCents: number) {\n const PaymentIntentBodySchema = z.object({\n amountCents: z\n .number()\n .int()\n .min(minCents, `minimum top-up is $${(minCents / 100).toFixed(2)}`)\n .max(maxCents, `maximum top-up is $${(maxCents / 100).toFixed(2)}`),\n });\n const AutoRechargeBodySchema = z.object({\n enabled: z.boolean(),\n thresholdCents: z.number().int().min(minCents).max(maxCents).nullable().optional(),\n amountCents: z.number().int().min(minCents).max(maxCents).nullable().optional(),\n });\n return { PaymentIntentBodySchema, AutoRechargeBodySchema };\n}\n\n// ----- Helpers -----\n\nasync function requireUser(\n auth: AuthFn,\n getOrCreateAppUser: (session: SessionLike) => Promise<BillingUser>,\n): Promise<{ user: BillingUser } | { res: NextResponse }> {\n const session = await auth();\n if (!session || !(session as { user?: unknown }).user) {\n return { res: NextResponse.json({ error: \"unauthorized\" }, { status: 401 }) };\n }\n const user = await getOrCreateAppUser(session);\n return { user };\n}\n\nasync function readJson<T>(\n request: Request,\n schema: z.ZodType<T>,\n): Promise<{ data: T } | { res: NextResponse }> {\n let body: unknown;\n try {\n body = await request.json();\n } catch {\n return {\n res: NextResponse.json(\n { error: \"invalid_json\", code: \"validation\" },\n { status: 400 },\n ),\n };\n }\n const parsed = schema.safeParse(body);\n if (!parsed.success) {\n return {\n res: NextResponse.json(\n { error: \"invalid_body\", issues: parsed.error.issues },\n { status: 400 },\n ),\n };\n }\n return { data: parsed.data };\n}\n\nfunction parsePkId(raw: string): bigint | { res: NextResponse } {\n try {\n return BigInt(raw);\n } catch {\n return { res: NextResponse.json({ error: \"invalid_id\" }, { status: 400 }) };\n }\n}\n\n// ----- Factory -----\n\nexport function createBillingHandlers(opts: CreateBillingHandlersOptions) {\n const { auth, getDb, getOrCreateAppUser } = opts;\n const recentLimit = opts.recentLimit ?? 10;\n const minCents = opts.minTopUpCents ?? 500;\n const maxCents = opts.maxTopUpCents ?? 100_000;\n const { PaymentIntentBodySchema, AutoRechargeBodySchema } = buildSchemas(\n minCents,\n maxCents,\n );\n\n // ---- GET /api/billing (aggregate) ----\n\n const aggregateGET = async () => {\n const r = await requireUser(auth, getOrCreateAppUser);\n if (\"res\" in r) return r.res;\n const { user } = r;\n const db = await getDb();\n const stripePromise = getStripe().catch(() => null);\n\n const [recent, purchaseAgg, topupAgg, savedCards, stripeBundle] = await Promise.all([\n db.creditTransaction.findMany({\n where: { user_id: user.id },\n orderBy: { created_at: \"desc\" },\n take: recentLimit,\n }),\n db.creditTransaction.aggregate({\n where: { user_id: user.id, type: \"purchase\" },\n _sum: { amount: true },\n }),\n db.creditTransaction.aggregate({\n where: { user_id: user.id, amount: { gt: 0 } },\n _sum: { amount: true },\n }),\n db.paymentMethod.findMany({\n where: { user_id: user.id },\n orderBy: [{ is_default: \"desc\" }, { created_at: \"desc\" }],\n }),\n stripePromise,\n ]);\n\n return NextResponse.json({\n credit_balance: Number(user.credit_balance),\n publishableKey: stripeBundle?.publishableKey ?? null,\n auto_recharge_enabled: user.auto_recharge_enabled,\n auto_recharge_threshold:\n user.auto_recharge_threshold != null\n ? Number(user.auto_recharge_threshold)\n : null,\n auto_recharge_amount:\n user.auto_recharge_amount != null ? Number(user.auto_recharge_amount) : null,\n saved_cards: savedCards.map((m) => ({\n id: m.id.toString(),\n brand: m.brand,\n last4: m.last4,\n exp_month: m.exp_month,\n exp_year: m.exp_year,\n is_default: m.is_default,\n })),\n recent_transactions: recent.map((t) => ({\n id: t.id.toString(),\n type: t.type,\n amount: Number(t.amount),\n description: t.description,\n stripe_payment_intent_id: t.stripe_payment_intent_id,\n payment_method_display: t.payment_method_display,\n created_at: t.created_at.toISOString(),\n })),\n total_purchased: Math.abs(Number(purchaseAgg._sum.amount ?? 0)),\n total_topped_up: Number(topupAgg._sum.amount ?? 0),\n });\n };\n\n // ---- GET /api/billing/balance ----\n\n const balanceGET = async () => {\n const r = await requireUser(auth, getOrCreateAppUser);\n if (\"res\" in r) return r.res;\n return NextResponse.json({ credit_balance: Number(r.user.credit_balance) });\n };\n\n // ---- GET /api/billing/transactions?limit=N ----\n\n const transactionsGET = async (request: Request) => {\n const r = await requireUser(auth, getOrCreateAppUser);\n if (\"res\" in r) return r.res;\n const db = await getDb();\n const url = new URL(request.url);\n const limitParam = Number(url.searchParams.get(\"limit\"));\n const take =\n Number.isFinite(limitParam) && limitParam > 0 && limitParam <= 100\n ? Math.floor(limitParam)\n : recentLimit;\n\n const rows = await db.creditTransaction.findMany({\n where: { user_id: r.user.id },\n orderBy: { created_at: \"desc\" },\n take,\n });\n return NextResponse.json({\n items: rows.map((t) => ({\n id: t.id.toString(),\n type: t.type,\n amount: Number(t.amount),\n description: t.description,\n stripe_payment_intent_id: t.stripe_payment_intent_id,\n payment_method_display: t.payment_method_display,\n created_at: t.created_at.toISOString(),\n })),\n });\n };\n\n // ---- POST /api/billing/payment-intent ----\n\n const paymentIntentPOST = async (request: Request) => {\n const r = await requireUser(auth, getOrCreateAppUser);\n if (\"res\" in r) return r.res;\n const body = await readJson(request, PaymentIntentBodySchema);\n if (\"res\" in body) return body.res;\n const { user } = r;\n const { client: stripe, publishableKey } = await getStripe();\n const { customerId, created } = await findOrCreateStripeCustomer(\n {\n existingId: user.stripe_customer_id,\n email: user.email,\n name: user.name,\n appUserId: user.id.toString(),\n },\n stripe,\n );\n if (created) {\n const db = await getDb();\n await db.user.update({\n where: { id: user.id },\n data: { stripe_customer_id: customerId },\n });\n }\n const intent = await stripe.paymentIntents.create({\n amount: body.data.amountCents,\n currency: \"usd\",\n customer: customerId,\n automatic_payment_methods: { enabled: true },\n metadata: { app_user_id: user.id.toString(), kind: \"credit_topup\" },\n });\n return NextResponse.json({\n clientSecret: intent.client_secret,\n publishableKey,\n });\n };\n\n // ---- POST /api/billing/setup-intent ----\n\n const setupIntentPOST = async () => {\n const r = await requireUser(auth, getOrCreateAppUser);\n if (\"res\" in r) return r.res;\n const { user } = r;\n const { client: stripe, publishableKey } = await getStripe();\n const { customerId, created } = await findOrCreateStripeCustomer(\n {\n existingId: user.stripe_customer_id,\n email: user.email,\n name: user.name,\n appUserId: user.id.toString(),\n },\n stripe,\n );\n if (created) {\n const db = await getDb();\n await db.user.update({\n where: { id: user.id },\n data: { stripe_customer_id: customerId },\n });\n }\n const intent = await stripe.setupIntents.create({\n customer: customerId,\n automatic_payment_methods: { enabled: true },\n usage: \"off_session\",\n metadata: { app_user_id: user.id.toString() },\n });\n return NextResponse.json({\n clientSecret: intent.client_secret,\n publishableKey,\n });\n };\n\n // ---- GET /api/billing/payment-methods ----\n\n const paymentMethodsListGET = async () => {\n const r = await requireUser(auth, getOrCreateAppUser);\n if (\"res\" in r) return r.res;\n const db = await getDb();\n const methods = await db.paymentMethod.findMany({\n where: { user_id: r.user.id },\n orderBy: [{ is_default: \"desc\" }, { created_at: \"desc\" }],\n });\n return NextResponse.json({\n items: methods.map((m) => ({\n id: m.id.toString(),\n stripe_payment_method_id: m.stripe_payment_method_id,\n brand: m.brand,\n last4: m.last4,\n exp_month: m.exp_month,\n exp_year: m.exp_year,\n is_default: m.is_default,\n created_at: m.created_at.toISOString(),\n })),\n });\n };\n\n // ---- DELETE /api/billing/payment-methods/[id] ----\n\n const paymentMethodDELETE = async (\n _request: Request,\n context: { params: Promise<{ id: string }> },\n ) => {\n const r = await requireUser(auth, getOrCreateAppUser);\n if (\"res\" in r) return r.res;\n const { id } = await context.params;\n const pk = parsePkId(id);\n if (typeof pk !== \"bigint\") return pk.res;\n const db = await getDb();\n const row = await db.paymentMethod.findUnique({ where: { id: pk } });\n if (!row || row.user_id !== r.user.id) {\n return NextResponse.json({ error: \"not_found\" }, { status: 404 });\n }\n const { client: stripe } = await getStripe();\n await stripe.paymentMethods.detach(row.stripe_payment_method_id);\n await db.paymentMethod.delete({ where: { id: pk } });\n return NextResponse.json({ ok: true });\n };\n\n // ---- PATCH /api/billing/payment-methods/[id]/default ----\n\n const paymentMethodDefaultPATCH = async (\n _request: Request,\n context: { params: Promise<{ id: string }> },\n ) => {\n const r = await requireUser(auth, getOrCreateAppUser);\n if (\"res\" in r) return r.res;\n const { id } = await context.params;\n const pk = parsePkId(id);\n if (typeof pk !== \"bigint\") return pk.res;\n const db = await getDb();\n const row = await db.paymentMethod.findUnique({ where: { id: pk } });\n if (!row || row.user_id !== r.user.id) {\n return NextResponse.json({ error: \"not_found\" }, { status: 404 });\n }\n if (!r.user.stripe_customer_id) {\n return NextResponse.json({ error: \"no_stripe_customer\" }, { status: 409 });\n }\n const { client: stripe } = await getStripe();\n await stripe.customers.update(r.user.stripe_customer_id, {\n invoice_settings: { default_payment_method: row.stripe_payment_method_id },\n });\n await db.$transaction([\n db.paymentMethod.updateMany({\n where: { user_id: r.user.id, is_default: true },\n data: { is_default: false },\n }),\n db.paymentMethod.update({ where: { id: pk }, data: { is_default: true } }),\n db.user.update({\n where: { id: r.user.id },\n data: {\n stripe_default_payment_method: row.stripe_payment_method_id,\n stripe_default_payment_method_display: `${row.brand} •••• ${row.last4}`,\n },\n }),\n ]);\n return NextResponse.json({ ok: true });\n };\n\n // ---- PATCH /api/billing/auto-recharge ----\n\n const autoRechargePATCH = async (request: Request) => {\n const r = await requireUser(auth, getOrCreateAppUser);\n if (\"res\" in r) return r.res;\n const body = await readJson(request, AutoRechargeBodySchema);\n if (\"res\" in body) return body.res;\n if (body.data.enabled && !r.user.stripe_default_payment_method) {\n return NextResponse.json(\n {\n error: \"no_default_card\",\n message: \"Save a card and mark it default before enabling auto-recharge.\",\n },\n { status: 409 },\n );\n }\n const threshold =\n body.data.thresholdCents != null\n ? (body.data.thresholdCents / 100).toFixed(2)\n : null;\n const amount =\n body.data.amountCents != null ? (body.data.amountCents / 100).toFixed(2) : null;\n const db = await getDb();\n const updated = (await db.user.update({\n where: { id: r.user.id },\n data: {\n auto_recharge_enabled: body.data.enabled,\n auto_recharge_threshold: body.data.enabled ? threshold : null,\n auto_recharge_amount: body.data.enabled ? amount : null,\n },\n select: {\n auto_recharge_enabled: true,\n auto_recharge_threshold: true,\n auto_recharge_amount: true,\n },\n })) as {\n auto_recharge_enabled: boolean;\n auto_recharge_threshold: unknown;\n auto_recharge_amount: unknown;\n };\n return NextResponse.json({\n enabled: updated.auto_recharge_enabled,\n thresholdCents:\n updated.auto_recharge_threshold != null\n ? Math.round(Number(updated.auto_recharge_threshold) * 100)\n : null,\n amountCents:\n updated.auto_recharge_amount != null\n ? Math.round(Number(updated.auto_recharge_amount) * 100)\n : null,\n });\n };\n\n // ---- POST /api/billing/stripe-webhook ----\n\n const webhookPOST = async (request: Request) => {\n const rawBody = await request.text();\n const signature = request.headers.get(\"stripe-signature\");\n if (!signature) {\n return NextResponse.json({ error: \"missing_signature\" }, { status: 400 });\n }\n const { client: stripe, webhookSecret } = await getStripe();\n let event: Stripe.Event;\n try {\n event = stripe.webhooks.constructEvent(rawBody, signature, webhookSecret);\n } catch (err) {\n const msg = err instanceof Error ? err.message : String(err);\n console.error(\"Stripe webhook signature verification failed:\", msg);\n return NextResponse.json({ error: \"bad_signature\" }, { status: 400 });\n }\n try {\n await dispatchWebhookEvent(event, getDb);\n } catch (err) {\n const msg = err instanceof Error ? err.message : String(err);\n console.error(`Stripe webhook handler failed for ${event.type}:`, msg);\n return NextResponse.json({ error: \"handler_failed\" }, { status: 500 });\n }\n return NextResponse.json({ received: true });\n };\n\n return {\n aggregate: { GET: aggregateGET },\n balance: { GET: balanceGET },\n transactions: { GET: transactionsGET },\n paymentIntent: { POST: paymentIntentPOST },\n setupIntent: { POST: setupIntentPOST },\n paymentMethods: { GET: paymentMethodsListGET },\n paymentMethodById: { DELETE: paymentMethodDELETE },\n paymentMethodDefault: { PATCH: paymentMethodDefaultPATCH },\n autoRecharge: { PATCH: autoRechargePATCH },\n webhook: { POST: webhookPOST },\n };\n}\n\n// ----- Webhook event dispatch (extracted so the factory body stays terse) -----\n\nasync function dispatchWebhookEvent(\n event: Stripe.Event,\n getDb: () => Promise<BillingDb>,\n): Promise<void> {\n const db = await getDb();\n switch (event.type) {\n case \"payment_intent.succeeded\": {\n const intent = event.data.object as Stripe.PaymentIntent;\n await onPaymentIntentSucceeded(intent, db);\n break;\n }\n case \"payment_intent.payment_failed\": {\n const intent = event.data.object as Stripe.PaymentIntent;\n console.warn(\n `Stripe payment_intent.payment_failed: id=${intent.id} user=${intent.metadata?.app_user_id} reason=${intent.last_payment_error?.message}`,\n );\n break;\n }\n case \"setup_intent.succeeded\": {\n const intent = event.data.object as Stripe.SetupIntent;\n console.log(\n `Stripe setup_intent.succeeded: id=${intent.id} pm=${intent.payment_method}`,\n );\n break;\n }\n case \"payment_method.attached\": {\n await onPaymentMethodAttached(event.data.object as Stripe.PaymentMethod, db);\n break;\n }\n case \"payment_method.detached\": {\n await onPaymentMethodDetached(event.data.object as Stripe.PaymentMethod, db);\n break;\n }\n case \"payment_method.updated\": {\n await onPaymentMethodUpdated(event.data.object as Stripe.PaymentMethod, db);\n break;\n }\n case \"charge.refunded\": {\n await onChargeRefunded(event.data.object as Stripe.Charge, db);\n break;\n }\n default:\n console.log(`Stripe webhook: unhandled event type ${event.type}`);\n }\n}\n\nasync function onPaymentIntentSucceeded(intent: Stripe.PaymentIntent, db: BillingDb) {\n const appUserIdStr = intent.metadata?.app_user_id;\n const kind = intent.metadata?.kind;\n if (!appUserIdStr || kind !== \"credit_topup\") return;\n const userId = BigInt(appUserIdStr);\n const dollars = (intent.amount / 100).toFixed(2);\n try {\n await db.$transaction([\n db.creditTransaction.create({\n data: {\n user_id: userId,\n type: \"stripe_topup\",\n amount: dollars,\n description: `Stripe credit top-up ($${dollars})`,\n stripe_payment_intent_id: intent.id,\n payment_method_display:\n typeof intent.payment_method === \"string\" ? intent.payment_method : null,\n },\n }),\n db.user.update({\n where: { id: userId },\n data: { credit_balance: { increment: dollars } },\n }),\n ]);\n } catch (err) {\n // P2002 = unique constraint (stripe_payment_intent_id) -> Stripe retry; ignore.\n const code = (err as { code?: string }).code;\n if (code === \"P2002\") return;\n throw err;\n }\n}\n\nasync function onPaymentMethodAttached(pm: Stripe.PaymentMethod, db: BillingDb) {\n if (pm.type !== \"card\" || !pm.card || !pm.customer) return;\n const customerId = typeof pm.customer === \"string\" ? pm.customer : pm.customer.id;\n const user = await db.user.findFirst({ where: { stripe_customer_id: customerId } });\n if (!user) return;\n await db.paymentMethod.upsert({\n where: { stripe_payment_method_id: pm.id },\n update: {\n brand: pm.card.brand,\n last4: pm.card.last4,\n exp_month: pm.card.exp_month,\n exp_year: pm.card.exp_year,\n },\n create: {\n user_id: user.id,\n stripe_payment_method_id: pm.id,\n brand: pm.card.brand,\n last4: pm.card.last4,\n exp_month: pm.card.exp_month,\n exp_year: pm.card.exp_year,\n is_default: false,\n },\n });\n}\n\nasync function onPaymentMethodDetached(pm: Stripe.PaymentMethod, db: BillingDb) {\n try {\n await db.paymentMethod.delete({ where: { stripe_payment_method_id: pm.id } });\n } catch (err) {\n const code = (err as { code?: string }).code;\n if (code === \"P2025\") return;\n throw err;\n }\n}\n\nasync function onPaymentMethodUpdated(pm: Stripe.PaymentMethod, db: BillingDb) {\n if (pm.type !== \"card\" || !pm.card) return;\n try {\n await db.paymentMethod.update({\n where: { stripe_payment_method_id: pm.id },\n data: {\n brand: pm.card.brand,\n last4: pm.card.last4,\n exp_month: pm.card.exp_month,\n exp_year: pm.card.exp_year,\n },\n });\n } catch (err) {\n const code = (err as { code?: string }).code;\n if (code === \"P2025\") return;\n throw err;\n }\n}\n\nasync function onChargeRefunded(charge: Stripe.Charge, db: BillingDb) {\n const intentId =\n typeof charge.payment_intent === \"string\"\n ? charge.payment_intent\n : charge.payment_intent?.id;\n if (!intentId) return;\n const topup = await db.creditTransaction.findUnique({\n where: { stripe_payment_intent_id: intentId },\n });\n if (!topup) return;\n const refundedAmount = (charge.amount_refunded / 100).toFixed(2);\n await db.$transaction([\n db.creditTransaction.create({\n data: {\n user_id: topup.user_id,\n type: \"refund_reversal\",\n amount: `-${refundedAmount}`,\n description: `Refund reversal for ${intentId}`,\n stripe_payment_intent_id: `${intentId}-refund-${charge.id}`,\n },\n }),\n db.user.update({\n where: { id: topup.user_id },\n data: { credit_balance: { decrement: refundedAmount } },\n }),\n ]);\n}\n"],"mappings":"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","names":["webhookSecret","client"]}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@augmenting-integrations/billing",
|
|
3
|
-
"version": "8.0
|
|
3
|
+
"version": "8.1.0",
|
|
4
4
|
"description": "Stripe primitives for augint product apps: secret-bundled client init, idempotent customer creation, webhook signature verification, plus client-side React widgets (Elements provider, PaymentMethodSelect, CreditBalanceBadge, useCart with localStorage persistence).",
|
|
5
5
|
"license": "MIT",
|
|
6
6
|
"publishConfig": {
|
|
@@ -27,25 +27,28 @@
|
|
|
27
27
|
"README.md"
|
|
28
28
|
],
|
|
29
29
|
"dependencies": {
|
|
30
|
-
"stripe": "^17.0.0"
|
|
30
|
+
"stripe": "^17.0.0",
|
|
31
|
+
"zod": "^4.1.7"
|
|
31
32
|
},
|
|
32
33
|
"peerDependencies": {
|
|
33
34
|
"@stripe/react-stripe-js": "^3.0.0",
|
|
34
35
|
"@stripe/stripe-js": "^4.0.0",
|
|
36
|
+
"next": "^16.0.0",
|
|
35
37
|
"react": "^19.0.0",
|
|
36
|
-
"@augmenting-integrations/ui": "8.0
|
|
37
|
-
"@augmenting-integrations/aws": "8.0
|
|
38
|
+
"@augmenting-integrations/ui": "8.1.0",
|
|
39
|
+
"@augmenting-integrations/aws": "8.1.0"
|
|
38
40
|
},
|
|
39
41
|
"devDependencies": {
|
|
40
42
|
"@stripe/react-stripe-js": "^3.0.0",
|
|
41
43
|
"@stripe/stripe-js": "^4.0.0",
|
|
42
44
|
"@types/react": "^19.0.0",
|
|
45
|
+
"next": "^16.2.5",
|
|
43
46
|
"react": "^19.0.0",
|
|
44
47
|
"tsup": "^8.3.5",
|
|
45
48
|
"typescript": "^5.7.2",
|
|
46
49
|
"vitest": "^4.1.5",
|
|
47
|
-
"@augmenting-integrations/
|
|
48
|
-
"@augmenting-integrations/
|
|
50
|
+
"@augmenting-integrations/aws": "8.1.0",
|
|
51
|
+
"@augmenting-integrations/ui": "8.1.0"
|
|
49
52
|
},
|
|
50
53
|
"scripts": {
|
|
51
54
|
"build": "tsup",
|