@tummycrypt/scheduling-kit
v0.6.1
Published
Backend-agnostic scheduling components with alternative payment support
Maintainers
Readme
@tummycrypt/scheduling-kit
Backend-agnostic scheduling system with Svelte 5 components, multiple scheduling adapters, and alternative payment support. Built with fp-ts for functional composition and Zod for runtime validation.
Docs, prebuilts, packages and blog post to come later. Another tinyland artifact it is time to publish. This package powers scheduling transactions for small buisnesses in the eastern US for whom I've done contracting work.
Features
- Multiple scheduling backends -- Acuity, Cal.com, or bring-your-own PostgreSQL (HomegrownAdapter)
- Svelte 5 components -- ServicePicker, DateTimePicker, ClientForm, CheckoutDrawer, and more
- Payment adapters -- Stripe, Venmo/PayPal SDK, cash, Zelle, check
- Availability engine -- Pure-function slot generation, DST-safe via
Intl.DateTimeFormat - Reconciliation -- Alt-payment matching and webhook handling
- Test infrastructure -- Cassette-based API recording/playback, MSW mocking, property-based tests
- Functional core -- fp-ts
TaskEitherpipelines throughout
Installation
pnpm add @tummycrypt/scheduling-kitPeer dependencies (install those you need):
# Required
pnpm add svelte
# Optional -- for UI components
pnpm add @skeletonlabs/skeleton @skeletonlabs/skeleton-svelte
# Optional -- for E2E tests
pnpm add -D playwright-coreQuick Start
import {
createSchedulingKit,
createHomegrownAdapter,
createStripeAdapter,
createVenmoAdapter,
} from '@tummycrypt/scheduling-kit';
// Create a scheduling adapter
const scheduler = createHomegrownAdapter({
db: drizzleInstance,
timezone: 'America/New_York',
});
// Create payment adapters
const stripe = createStripeAdapter({
type: 'stripe',
secretKey: process.env.STRIPE_SECRET_KEY!,
publishableKey: process.env.STRIPE_PUBLISHABLE_KEY!,
});
const venmo = createVenmoAdapter({
type: 'venmo',
clientId: process.env.PAYPAL_CLIENT_ID!,
clientSecret: process.env.PAYPAL_CLIENT_SECRET!,
environment: 'sandbox',
});
// Compose into a scheduling kit
const kit = createSchedulingKit(scheduler, [stripe, venmo]);
// Complete a booking
const result = await kit.completeBooking(request, 'stripe')();Adapters
HomegrownAdapter
Direct PostgreSQL adapter using Drizzle ORM. Replaces third-party scheduling APIs entirely.
import { createHomegrownAdapter } from '@tummycrypt/scheduling-kit/adapters';
const adapter = createHomegrownAdapter({
db: drizzleInstance,
timezone: 'America/New_York',
});
// 16 methods: getServices, getAvailability, getSlots, book, cancel, reschedule, ...AcuityAdapter
API-based adapter for Acuity Scheduling (requires Powerhouse plan).
import { createAcuityAdapter } from '@tummycrypt/scheduling-kit/adapters';
const config = {
type: 'acuity' as const,
userId: process.env.ACUITY_USER_ID!,
apiKey: process.env['ACUITY_API_KEY']!, // from Acuity Integrations page
};
const adapter = createAcuityAdapter(config);CalComAdapter
Stub adapter for future Cal.com integration.
import { createCalComAdapter } from '@tummycrypt/scheduling-kit/adapters';
const adapter = createCalComAdapter({
type: 'calcom',
apiKey: process.env['CALCOM_API_KEY']!,
baseUrl: 'https://api.cal.com/v1',
});Availability Engine
Pure functions for slot generation. DST-safe, timezone-aware, fully tested.
import {
getAvailableSlots,
isSlotAvailable,
getDatesWithAvailability,
getEffectiveHours,
} from '@tummycrypt/scheduling-kit/adapters';
const slots = getAvailableSlots({
date: '2026-03-22',
timezone: 'America/New_York',
hours: [{ dayOfWeek: 6, startTime: '11:00', endTime: '16:00' }],
overrides: [],
occupied: [],
slotDuration: 60,
bufferMinutes: 15,
});Components
Svelte 5 components using runes syntax. Optional Skeleton 4 integration for styling.
| Component | Description |
|-----------|-------------|
| ServicePicker | Service/appointment type selector |
| DateTimePicker | Calendar date + time slot picker |
| ClientForm | Client info form with Zod validation |
| PaymentSelector | Payment method chooser |
| ProviderPicker | Practitioner/provider selector |
| BookingConfirmation | Post-booking confirmation display |
| CheckoutDrawer | Full checkout flow in a slide-out drawer |
| HybridCheckoutDrawer | Checkout with Acuity embed handoff |
| VenmoButton | Venmo/PayPal payment button |
| VenmoCheckout | Full Venmo checkout flow |
| StripeCheckout | Stripe Elements checkout |
| AcuityEmbedHandoff | Acuity iframe embed with message passing |
<script lang="ts">
import { ServicePicker, DateTimePicker, ClientForm } from '@tummycrypt/scheduling-kit/components';
</script>
<ServicePicker services={data.services} onselect={handleSelect} />
<DateTimePicker slots={availableSlots} onselect={handleTimeSelect} />
<ClientForm onsubmit={handleSubmit} />Payment Adapters
import {
createStripeAdapter,
createVenmoAdapter,
createCashAdapter,
createZelleAdapter,
createCheckAdapter,
createVenmoDirectAdapter,
} from '@tummycrypt/scheduling-kit/payments';| Adapter | Type | Description |
|---------|------|-------------|
| createStripeAdapter | stripe | Stripe Connect with Payment Intents |
| createVenmoAdapter | venmo | PayPal SDK with Venmo button |
| createCashAdapter | cash | Cash/in-person manual payment |
| createZelleAdapter | zelle | Zelle manual payment |
| createCheckAdapter | check | Check manual payment |
| createVenmoDirectAdapter | venmo-direct | Venmo deep link (no SDK) |
Reconciliation
Match alt-payment transactions (Venmo, Zelle, cash) to bookings.
import { createReconciliationMatcher } from '@tummycrypt/scheduling-kit/reconciliation';Stores
Svelte 5 runes-based checkout state management.
import { checkoutStore } from '@tummycrypt/scheduling-kit/stores';Testing
Unit Tests
pnpm test:unit # Run all unit tests
pnpm test:coverage # With coverage reportIntegration Tests
pnpm test:integration # Mocked backend integration testsComponent Tests
pnpm test:component # jsdom-based component testsE2E Tests
pnpm test:e2e # Playwright browser tests (starts dev server)Live Tests
# Copy .env.test.local.example to .env.test.local and fill in credentials
RUN_LIVE_TESTS=true pnpm test:liveTest Utilities
The @tummycrypt/scheduling-kit/testing export provides cassette-based API recording and playback for deterministic integration tests.
import { CassetteRecorder, CassettePlayer } from '@tummycrypt/scheduling-kit/testing';Development
pnpm install
pnpm dev # Start dev server
pnpm build # Build package
pnpm check # TypeScript check
pnpm lint # ESLint
pnpm test:all # Run all test suitesLicense
MIT -- see LICENSE for details.
