From dc3f382cf6a0f29a48b86fa53dc2825993dce83c Mon Sep 17 00:00:00 2001 From: Yudi Xiao <463708580@qq.com> Date: Tue, 14 Oct 2025 14:58:06 +0800 Subject: [PATCH] v1.3.27-d: Add credit-balance-summary method --- package.json | 2 +- src/index.ts | 75 ++++++++++++++++++++++++++++++++++++++++++++++++++++ src/types.ts | 1 + 3 files changed, 77 insertions(+), 1 deletion(-) diff --git a/package.json b/package.json index f4656fc..55da2cd 100644 --- a/package.json +++ b/package.json @@ -1,7 +1,7 @@ { "name": "@bowong/better-auth-stripe", "author": "Bowong", - "version": "1.3.27-c", + "version": "1.3.27-d", "main": "dist/index.cjs", "license": "MIT", "keywords": [ diff --git a/src/index.ts b/src/index.ts index 67eb14b..be353ab 100644 --- a/src/index.ts +++ b/src/index.ts @@ -1391,6 +1391,81 @@ export const stripe = (options: O) => { } ); + return ctx.json(result); + } catch (error: any) { + ctx.context.logger.error( + "Error submitting meter event", + error, + ); + throw new APIError("BAD_REQUEST", { + message: error.message, + }); + } + } + ), + creditBalanceSummary: createAuthEndpoint( + "/subscription/credit/summary", // https://docs.stripe.com/api/billing/credit-balance-summary + { + method: "GET", + query: z.object({ + filter: z.object({ + type: z.enum(['credit_grant', 'applicability_scope']), + applicability_scope: z.object({ + price_type: z.enum(['metered']).meta({ + description: "The price type that credit grants can apply to. We currently only support the metered price type. Cannot be used in combination with prices." + }) + }).optional().meta({ + description: "The billing credit applicability scope for which to fetch credit balance summary" + }), + credit_grant: z.string().optional().meta({ + description: "The credit grant for which to fetch credit balance summary" + }) + }) + }), + use: [ + sessionMiddleware, + referenceMiddleware("credit-balance-summary"), + ] + }, + async (ctx) => { + const {user} = ctx.context.session; + let customerId = user.stripeCustomerId; + const referenceId = ctx.body.referenceId || user.id; + + if (!customerId) { + const subscription = await ctx.context.adapter + .findMany({ + model: "subscription", + where: [ + { + field: "referenceId", + value: referenceId, + }, + ], + }) + .then((subs) => + subs.find( + (sub) => sub.status === "active" || sub.status === "trialing", + ), + ); + + customerId = subscription?.stripeCustomerId; + } + + if (!customerId) { + throw new APIError("BAD_REQUEST", { + message: "No Stripe customer found for this user", + }); + } + + try { + const result = await client.billing.creditBalanceSummary.retrieve( + { + ...ctx.query, + customer: customerId + } + ); + return ctx.json(result); } catch (error: any) { ctx.context.logger.error( diff --git a/src/types.ts b/src/types.ts index 8081d56..9d14cc1 100644 --- a/src/types.ts +++ b/src/types.ts @@ -98,6 +98,7 @@ export type actionType = | "meter-event" | "adjust-meter-event" | "meter-event-summary" + | "credit-balance-summary" | "billing-portal"; export interface Subscription {