feat: WIP stripe billing refactor update for 2025

pull/715/head
Travis Fischer 2025-05-18 03:34:05 +07:00
rodzic 8ea3a4f4b6
commit 78d8e13250
2 zmienionych plików z 26 dodań i 8 usunięć

Wyświetl plik

@ -8,6 +8,7 @@ import { registerV1AdminConsumersGetConsumerByToken } from './consumers/admin-ge
import { registerV1ConsumersCreateConsumer } from './consumers/create-consumer'
import { registerV1ConsumersGetConsumer } from './consumers/get-consumer'
import { registerV1ProjectsListConsumers } from './consumers/list-consumers'
import { registerV1ConsumersRefreshConsumerToken } from './consumers/refresh-consumer-token'
import { registerV1ConsumersUpdateConsumer } from './consumers/update-consumer'
import { registerHealthCheck } from './health-check'
import { registerV1ProjectsCreateProject } from './projects/create-project'
@ -90,6 +91,7 @@ registerV1ProjectsUpdateProject(privateRouter)
registerV1ConsumersGetConsumer(privateRouter)
registerV1ConsumersCreateConsumer(privateRouter)
registerV1ConsumersUpdateConsumer(privateRouter)
registerV1ConsumersRefreshConsumerToken(privateRouter)
registerV1ProjectsListConsumers(privateRouter)
// Webhook event handlers
@ -131,4 +133,5 @@ export type ApiRoutes =
| ReturnType<typeof registerV1ConsumersGetConsumer>
| ReturnType<typeof registerV1ConsumersCreateConsumer>
| ReturnType<typeof registerV1ConsumersUpdateConsumer>
| ReturnType<typeof registerV1ConsumersRefreshConsumerToken>
| ReturnType<typeof registerV1ProjectsListConsumers>

Wyświetl plik

@ -1,9 +1,11 @@
import { parseFaasIdentifier } from '@agentic/validators'
import { and, db, eq, schema } from '@/db'
import { assert, sha256 } from '@/lib/utils'
import { assert } from '@/lib/utils'
import type { AuthenticatedContext } from '../types'
import { acl } from '../acl'
import { createConsumerToken } from '../create-consumer-token'
import { upsertStripeConnectCustomer } from './upsert-stripe-connect-customer'
import { upsertStripeCustomer } from './upsert-stripe-customer'
import { upsertStripePricing } from './upsert-stripe-pricing'
@ -16,12 +18,12 @@ export async function upsertConsumer(
deploymentId,
consumerId
}: {
plan?: string
plan: string
deploymentId?: string
consumerId?: string
}
) {
assert(consumerId || deploymentId, 400)
assert(consumerId || deploymentId, 400, 'Missing required "deploymentId"')
const userId = c.get('userId')
let projectId: string | undefined
@ -33,7 +35,6 @@ export async function upsertConsumer(
if (!consumerId) {
assert(projectId, 400, 'Missing required "deploymentId"')
assert(plan, 400, 'Missing required "plan"')
}
const [{ user, stripeCustomer }, existingConsumer] = await Promise.all([
@ -52,18 +53,24 @@ export async function upsertConsumer(
if (consumerId) {
assert(existingConsumer, 404, `Consumer not found "${consumerId}"`)
assert(existingConsumer.id === consumerId, 403)
await acl(c, existingConsumer, { label: 'Consumer' })
if (projectId) {
assert(
existingConsumer.projectId === projectId,
400,
`Deployment "${deploymentId}" does not belong to with consumer "${consumerId}" project "${existingConsumer.projectId}"`
`Deployment "${deploymentId}" does not belong to project "${existingConsumer.projectId}" for consumer "${consumerId}"`
)
}
consumerId = existingConsumer.id
deploymentId ??= existingConsumer.deploymentId
projectId ??= existingConsumer.projectId
} else {
assert(
!existingConsumer,
409,
`User "${user.email}" already has a subscription for project "${projectId ?? ''}"`
)
}
assert(consumerId)
@ -99,6 +106,15 @@ export async function upsertConsumer(
`Deployment has been disabled by its owner "${deployment.id}"`
)
if (plan) {
const pricingPlan = deployment.pricingPlanMap[plan]
assert(
pricingPlan,
400,
`Pricing plan "${plan}" not found for deployment "${deploymentId}"`
)
}
let consumer = existingConsumer
if (consumer) {
@ -116,8 +132,7 @@ export async function upsertConsumer(
userId,
projectId,
deploymentId,
// TODO: refactor / improve token generation
token: sha256().slice(0, 24),
token: createConsumerToken(),
_stripeCustomerId: stripeCustomer.id
})
}