@tjoc/payments
v2.0.5
Published
> **Status: candidate — not yet adopted by any portfolio product. Source review required before first consumer wires it in.**
Maintainers
Readme
@tjoc/payments
Status: candidate — not yet adopted by any portfolio product. Source review required before first consumer wires it in.
Multi-provider payments router for the tjoc.dev portfolio. Implements the strategy defined in ADR 0015.
Portfolio payments strategy (ADR 0015)
| Use case | Provider | |---|---| | Card / subscription payments (default) | Stripe | | Nigerian NUBAN bank transfer | conchpay (Phase 1 — in build) | | International stablecoin payments | conchpay (Phase 2) | | All other cases | Stripe unless explicitly documented |
Paystack in star.club is grandfathered. New products do not add Paystack or a direct stablecoin processor — route through this package / conchpay instead.
Installation
pnpm add @tjoc/paymentsBefore adopting: run a source review to confirm which provider adapters are fully implemented and tested. The routing logic in this README reflects ADR 0015; the actual implementation may predate that decision and require alignment.
Quick start — Stripe (default provider)
import { PaymentRouter, StripeProvider } from '@tjoc/payments';
const stripeProvider = new StripeProvider({
apiKey: process.env.STRIPE_SECRET_KEY!,
});
const paymentRouter = new PaymentRouter({
providers: { primary: stripeProvider },
routing: { defaultProvider: 'stripe' },
});
const transaction = await paymentRouter.createPayment({
amount: 9.00,
currency: 'USD',
customerId: 'cust_123',
description: 'Pro subscription',
});Provider adapters
StripeProvider
import { StripeProvider } from '@tjoc/payments';
const stripe = new StripeProvider({
apiKey: process.env.STRIPE_SECRET_KEY!,
webhookHandlers: {
'payment_intent.succeeded': async (event) => { /* ... */ },
'payment_intent.payment_failed': async (event) => { /* ... */ },
},
});PaystackProvider (grandfathered — star.club only)
import { PaystackProvider } from '@tjoc/payments';
const paystack = new PaystackProvider({
secretKey: process.env.PAYSTACK_SECRET_KEY!,
publicKey: process.env.PAYSTACK_PUBLIC_KEY!,
webhookSecret: process.env.PAYSTACK_WEBHOOK_SECRET,
});New products should not use
PaystackProviderdirectly. For Nigerian payment needs, the roadmap points to a conchpay adapter (Phase 1).
PaymentRouter API
// Payments
createPayment(options: CreatePaymentOptions, context?: PaymentContext): Promise<Transaction>
confirmPayment(paymentId: string, context?: PaymentContext): Promise<Transaction>
cancelPayment(paymentId: string, context?: PaymentContext): Promise<Transaction>
getPayment(paymentId: string, context?: PaymentContext): Promise<Transaction>
// Customers
createCustomer(data: Partial<Customer>, context?: PaymentContext): Promise<Customer>
updateCustomer(customerId: string, data: Partial<Customer>, context?: PaymentContext): Promise<Customer>
getCustomer(customerId: string, context?: PaymentContext): Promise<Customer>
deleteCustomer(customerId: string, context?: PaymentContext): Promise<boolean>
// Subscriptions
createSubscription(options: CreateSubscriptionOptions, context?: PaymentContext): Promise<Subscription>
updateSubscription(subscriptionId: string, data: Partial<Subscription>, context?: PaymentContext): Promise<Subscription>
cancelSubscription(subscriptionId: string, context?: PaymentContext): Promise<Subscription>
getSubscription(subscriptionId: string, context?: PaymentContext): Promise<Subscription>
listCustomerSubscriptions(customerId: string, context?: PaymentContext): Promise<Subscription[]>
// Webhooks
handleWebhook(provider: string, body: unknown, signature: unknown): Promise<void>Error handling
import { PaymentProviderError, ConfigurationError } from '@tjoc/payments';
try {
const transaction = await paymentRouter.createPayment(options);
} catch (error) {
if (error instanceof PaymentProviderError) {
console.error('Provider error:', error.code, error.message);
} else if (error instanceof ConfigurationError) {
console.error('Config error:', error.message);
}
}Environment variables
STRIPE_SECRET_KEY=sk_live_...
STRIPE_WEBHOOK_SECRET=whsec_...
# star.club only (grandfathered)
PAYSTACK_SECRET_KEY=sk_live_...
PAYSTACK_PUBLIC_KEY=pk_live_...
PAYSTACK_WEBHOOK_SECRET=...Roadmap
- Phase 1: conchpay adapter — Nigerian NUBAN bank transfers
- Phase 2: conchpay adapter — international stablecoin payments
- First consumer: wisecv (ADR 0007 Phase 4) or next new product needing payments
Development
pnpm build # tsup → dist/
pnpm test # jest
pnpm test:coverage # jest --coverage
pnpm typecheck # tsc --noEmit