Adapters
The Booking Kit uses the adapter pattern to abstract external dependencies. Each adapter is a TypeScript interface — implement it for your preferred provider.
Available adapters
Section titled “Available adapters”AuthAdapter
Section titled “AuthAdapter”interface AuthAdapter { getSession(request: Request): Promise<AuthSession | null>; getUser(userId: string): Promise<AuthUser | null>;}Default: NextAuth.js 5.x Alternatives: Supabase Auth, Clerk, Lucia, custom JWT
EmailAdapter
Section titled “EmailAdapter”interface EmailAdapter { sendEmail(options: SendEmailOptions): Promise<EmailResult>;}
interface SendEmailOptions { to: string; subject: string; html: string; text?: string; from?: string; replyTo?: string; attachments?: EmailAttachment[];}Default: Resend Alternatives: SendGrid, AWS SES, Postmark, Nodemailer
CalendarAdapter
Section titled “CalendarAdapter”interface CalendarAdapter { createEvent(options: CalendarEventOptions): Promise<CalendarEventResult>; updateEvent(eventId: string, options: CalendarEventOptions): Promise<CalendarEventResult>; deleteEvent(eventId: string): Promise<void>; getConflicts(start: Date, end: Date): Promise<CalendarConflict[]>;}Default: Google Calendar (OAuth) Alternatives: Microsoft Outlook, CalDAV
JobAdapter
Section titled “JobAdapter”interface JobAdapter { enqueue(jobName: string, payload: unknown, options?: { delay?: number }): Promise<void>; scheduleAt(jobName: string, payload: unknown, runAt: Date): Promise<void>;}Default: Inngest 3.x Alternatives: Trigger.dev, BullMQ, Vercel Cron, pg-boss
PaymentAdapter
Section titled “PaymentAdapter”interface PaymentAdapter { createPaymentIntent(options: CreatePaymentIntentOptions): Promise<CreatePaymentIntentResult>; createSetupIntent(options: CreateSetupIntentOptions): Promise<CreateSetupIntentResult>; capturePayment(paymentIntentId: string): Promise<CaptureResult>; refundPayment(paymentIntentId: string, amountCents?: number): Promise<RefundResult>;}Default: Stripe Alternatives: Implement for your payment provider
StorageAdapter
Section titled “StorageAdapter”interface StorageAdapter { encrypt(plaintext: string): Promise<string>; decrypt(ciphertext: string): Promise<string>;}Default: Env var encryption key (AES-256) Alternatives: HashiCorp Vault, AWS KMS, Azure Key Vault
SmsAdapter
Section titled “SmsAdapter”interface SmsAdapter { sendSms(options: SendSmsOptions): Promise<SmsResult>;}Default: Not implemented (optional) Alternatives: Twilio, MessageBird, Vonage
Database Adapters
Section titled “Database Adapters”While The Booking Kit is built for PostgreSQL, it provides specialized adapters for other database environments.
Cloudflare D1 / SQLite (@thebookingkit/d1)
Section titled “Cloudflare D1 / SQLite (@thebookingkit/d1)”Cloudflare D1 requires special handling for date storage and concurrency. This package provides:
- Canonical Date Encoding: SQLite has no native timestamp type.
D1DateCodecensures all dates are stored as sortable UTC-Z strings. - Advisory Locking: Since SQLite lacks
EXCLUDEconstraints,D1BookingLockprovides application-level mutexes to prevent double-booking. - Schedule Adapters: Utilities to intersect personal and location schedules into RRULE windows.
import { D1DateCodec, D1BookingLock } from "@thebookingkit/d1";
// Ensure a slot is available and book it atomicallyconst lock = new D1BookingLock(db);await lock.withLock(`provider:${id}`, async () => { // Read-check-write logic here});Implementing an adapter
Section titled “Implementing an adapter”// Example: Custom email adapter using SendGridimport sgMail from "@sendgrid/mail";
const sendGridAdapter: EmailAdapter = { async sendEmail(options) { sgMail.setApiKey(process.env.SENDGRID_API_KEY!);
const [response] = await sgMail.send({ to: options.to, from: options.from || "noreply@example.com", subject: options.subject, html: options.html, text: options.text, });
return { messageId: response.headers["x-message-id"], status: "sent" as const, }; },};Using adapters
Section titled “Using adapters”Pass adapters to the functions that need them:
import { sendConfirmationEmail } from "@thebookingkit/core";
await sendConfirmationEmail(bookingPayload, sendGridAdapter);Adapters are injected at the call site, not globally configured. This makes testing easy — pass a mock adapter in tests.