← Public packages
@kentcdodds/stripe
Stripe helpers for customers, payments, invoices, subscriptions, products, payment links, refunds, and balance.
src/customers.ts
134 lines · 3.9 KB · TypeScriptimport {
requireConfirm,
stripeDate,
stripeList,
stripeRequest,
stripeSearch,
} from './stripe-core.ts'
export function summarizeCustomer(customer: any) {
if (!customer || typeof customer !== 'object') return null
return {
id: customer.id ?? null,
email: customer.email ?? null,
name: customer.name ?? null,
description: customer.description ?? null,
created: stripeDate(customer.created),
currency: customer.currency ?? null,
delinquent: Boolean(customer.delinquent),
metadata: customer.metadata ?? {},
}
}
export type ListCustomersInput = {
email?: string
maxItems?: number
}
/** List customers, optionally filtered by exact email. */
export async function listCustomers(input: ListCustomersInput = {}) {
const { items, hasMore } = await stripeList('customers', {
maxItems: input.maxItems ?? 25,
query: { email: input.email },
})
return { hasMore, customers: items.map(summarizeCustomer) }
}
/**
* Search customers with Stripe's search query language.
* @example searchCustomers({ searchQuery: "email:'ada@example.com'" })
* @example searchCustomers({ searchQuery: "name~'Ada' AND created>1735689600" })
*/
export async function searchCustomers(input: { searchQuery: string; maxItems?: number }) {
const { items, hasMore } = await stripeSearch('customers/search', {
searchQuery: input.searchQuery,
maxItems: input.maxItems ?? 25,
})
return { hasMore, customers: items.map(summarizeCustomer) }
}
/** Get one customer by id (full Stripe object). */
export async function getCustomer(input: { customerId: string }) {
return await stripeRequest({ path: 'customers/' + input.customerId })
}
export type CreateCustomerInput = {
email?: string
name?: string
description?: string
phone?: string
metadata?: Record<string, string>
idempotencyKey?: string
}
/** Create a customer. */
export async function createCustomer(input: CreateCustomerInput = {}) {
const customer = await stripeRequest({
path: 'customers',
method: 'POST',
idempotencyKey: input.idempotencyKey,
body: {
email: input.email,
name: input.name,
description: input.description,
phone: input.phone,
metadata: input.metadata,
},
})
return summarizeCustomer(customer)
}
export type UpdateCustomerInput = {
customerId: string
email?: string
name?: string
description?: string
phone?: string
metadata?: Record<string, string>
}
/** Update mutable customer fields. */
export async function updateCustomer(input: UpdateCustomerInput) {
const customer = await stripeRequest({
path: 'customers/' + input.customerId,
method: 'POST',
body: {
email: input.email,
name: input.name,
description: input.description,
phone: input.phone,
metadata: input.metadata,
},
})
return summarizeCustomer(customer)
}
/** Permanently delete a customer. Requires confirm: true. */
export async function deleteCustomer(input: { customerId: string; confirm?: boolean }) {
requireConfirm(input, 'delete customer ' + input.customerId)
return await stripeRequest({ path: 'customers/' + input.customerId, method: 'DELETE' })
}
/**
* Customers dispatcher. Defaults to list-customers.
* Actions: list-customers, search-customers, get-customer, create-customer, update-customer, delete-customer.
*/
export default async function customers(input: Record<string, unknown> = {}) {
const action = String(input.action ?? 'list-customers')
switch (action) {
case 'list-customers':
return await listCustomers(input as ListCustomersInput)
case 'search-customers':
return await searchCustomers(input as never)
case 'get-customer':
return await getCustomer(input as never)
case 'create-customer':
return await createCustomer(input as CreateCustomerInput)
case 'update-customer':
return await updateCustomer(input as UpdateCustomerInput)
case 'delete-customer':
return await deleteCustomer(input as never)
default:
throw new Error('Unknown customers action: ' + action)
}
}