add stripe
Build & Push / Pipeline Tests (push) Failing after 1m6s
Build & Push / Build & Push Docker Image (push) Has been skipped
Test / Type Check (all packages) (push) Failing after 56s
Test / API Unit Tests (push) Has been skipped
Test / Homepage Unit Tests (push) Has been skipped
Test / Carplace Unit Tests (push) Has been skipped
Test / Admin Unit Tests (push) Has been skipped
Test / Dashboard Unit Tests (push) Has been skipped
Test / API Integration Tests (push) Has been skipped

This commit is contained in:
root
2026-07-22 20:17:12 -04:00
parent 7ecd85e9b7
commit bcabd17220
38 changed files with 1674 additions and 96 deletions
+127
View File
@@ -0,0 +1,127 @@
import Stripe from 'stripe'
const STRIPE_API_KEY = process.env.STRIPE_API_KEY ?? ''
const STRIPE_WEBHOOK_SECRET = process.env.STRIPE_WEBHOOK_SECRET ?? ''
let client: Stripe | null = null
function getClient() {
if (!client) {
client = new Stripe(STRIPE_API_KEY, {
apiVersion: '2026-06-24.dahlia',
appInfo: {
name: 'RentalDriveGo',
version: '1.0.0',
},
})
}
return client
}
function integrationIdentifier() {
const suffix = Math.random().toString(36).replace(/[^a-z]/g, '').slice(0, 8).padEnd(8, 'x')
return `rentaldrivego_${suffix}`
}
export interface StripeCheckoutParams {
amount: number
currency: string
orderId: string
description: string
customerEmail?: string | null
successUrl: string
cancelUrl: string
reservationId?: string
companyId: string
subscriptionId?: string
type: 'CHARGE' | 'DEPOSIT' | 'SUBSCRIPTION'
}
export interface StripeCheckoutResult {
checkoutUrl: string
sessionId: string
}
export async function createCheckoutSession(params: StripeCheckoutParams): Promise<StripeCheckoutResult> {
const session = await getClient().checkout.sessions.create({
mode: 'payment',
success_url: params.successUrl,
cancel_url: params.cancelUrl,
customer_email: params.customerEmail ?? undefined,
client_reference_id: params.orderId,
line_items: [
{
quantity: 1,
price_data: {
currency: params.currency.toLowerCase(),
unit_amount: params.amount,
product_data: {
name: params.description,
},
},
},
],
metadata: {
...(params.reservationId ? { reservationId: params.reservationId } : {}),
companyId: params.companyId,
...(params.subscriptionId ? { subscriptionId: params.subscriptionId } : {}),
type: params.type,
orderId: params.orderId,
},
payment_intent_data: {
metadata: {
...(params.reservationId ? { reservationId: params.reservationId } : {}),
companyId: params.companyId,
...(params.subscriptionId ? { subscriptionId: params.subscriptionId } : {}),
type: params.type,
orderId: params.orderId,
},
},
integration_identifier: integrationIdentifier(),
})
if (!session.url) {
throw new Error('Stripe checkout session did not include a checkout URL')
}
return { checkoutUrl: session.url, sessionId: session.id }
}
export function constructWebhookEvent(rawBody: string | Buffer, signature: string) {
return getClient().webhooks.constructEvent(rawBody, signature, STRIPE_WEBHOOK_SECRET)
}
export async function refundPaymentIntent(paymentIntentId: string, amount: number, reason?: string) {
return getClient().refunds.create({
payment_intent: paymentIntentId,
amount,
metadata: reason ? { reason } : undefined,
})
}
export function isConfigured(): boolean {
return getConfigurationStatus().configured
}
export function getConfigurationStatus() {
const problems: string[] = []
if (!STRIPE_API_KEY) {
problems.push('STRIPE_API_KEY is missing')
} else if (STRIPE_API_KEY.includes('placeholder')) {
problems.push('STRIPE_API_KEY is still a placeholder')
} else if (!STRIPE_API_KEY.startsWith('sk_') && !STRIPE_API_KEY.startsWith('rk_')) {
problems.push('STRIPE_API_KEY must be a Stripe secret or restricted key')
}
if (!STRIPE_WEBHOOK_SECRET) {
problems.push('STRIPE_WEBHOOK_SECRET is missing')
} else if (!STRIPE_WEBHOOK_SECRET.startsWith('whsec_')) {
problems.push('STRIPE_WEBHOOK_SECRET must be a Stripe webhook signing secret')
}
return {
configured: problems.length === 0,
problems,
}
}