Package Exports
This package does not declare an exports field, so the exports above have been automatically detected and optimized by JSPM instead. If any package subpath is missing, it is recommended to post an issue to the original package (@kev1nramos/booking-mechanism) to support the "exports" field. If that is not possible, create a JSPM override to customize the exports field for this package.
Readme
Google Calendar Booking System
A secure, performant, and platform-agnostic booking system for Google Calendar. Built for Next.js + Cloudflare Pages Functions, but works anywhere that supports standard Web APIs.
Features
✅ Runtime-Agnostic - Works on Cloudflare Workers, Vercel Edge, AWS Lambda, Node.js 18+, Deno, and Bun ✅ Zero Dependencies - Core service uses only Web Standard APIs (fetch, URL, etc.) ✅ Fully Type-Safe - Complete TypeScript support with strict type checking ✅ Secure by Default - Rate limiting, CORS, input validation, XSS prevention, security headers ✅ Performance Optimized - Response caching, token refresh handling, efficient slot calculation ✅ Highly Configurable - Business hours, slot intervals, CORS, rate limits all customizable ✅ Platform Adapters - Ready-to-use adapters for Cloudflare and Next.js
Packages
This monorepo contains three packages:
- @kev1nramos/booking-core - Core types and utilities
- @kev1nramos/booking-server - Google Calendar service + platform adapters
- @kev1nramos/booking-react - React components and hooks (coming soon)
Quick Start
1. Installation
# Install the packages you need
pnpm add @kev1nramos/booking-core @kev1nramos/booking-server
# Or using npm
npm install @kev1nramos/booking-core @kev1nramos/booking-server2. Setup Environment Variables
Create a .env file (see .env.example for reference):
# Google OAuth 2.0 Credentials
GOOGLE_CLIENT_ID=your-client-id.apps.googleusercontent.com
GOOGLE_CLIENT_SECRET=your-client-secret
GOOGLE_REDIRECT_URI=https://yourdomain.com/oauth/callback
# Google Calendar Configuration
GOOGLE_CALENDAR_ID=primary
MY_EMAIL=your-email@gmail.com
# OAuth Tokens (obtain via OAuth flow)
GOOGLE_ACCESS_TOKEN=your-access-token
GOOGLE_REFRESH_TOKEN=your-refresh-token⚠️ IMPORTANT: Never commit your
.envfile! It's already in.gitignore.
3. Usage Examples
Cloudflare Pages Functions
// functions/api/book/[[path]].ts
import { createCloudflareHandler } from '@kev1nramos/booking-server/adapters/cloudflare';
const handler = createCloudflareHandler({
cors: {
allowedOrigins: [
'https://yourdomain.com',
'https://www.yourdomain.com',
'http://localhost:3000',
],
},
businessHours: {
start: 9, // 9 AM
end: 20, // 8 PM
},
slots: {
interval: 30, // 30-minute slots
durations: [30, 45, 60, 90, 120], // Available meeting durations
},
rateLimit: {
max: 10,
windowMs: 60000, // 1 minute
},
});
export const onRequestGet = handler.GET;
export const onRequestPost = handler.POST;
export const onRequestOptions = handler.OPTIONS;Next.js App Router
// app/api/book/route.ts
import { createNextHandler } from '@kev1nramos/booking-server/adapters/nextjs';
const handler = createNextHandler({
env: {
GOOGLE_CLIENT_ID: process.env.GOOGLE_CLIENT_ID!,
GOOGLE_CLIENT_SECRET: process.env.GOOGLE_CLIENT_SECRET!,
GOOGLE_REDIRECT_URI: process.env.GOOGLE_REDIRECT_URI!,
GOOGLE_CALENDAR_ID: process.env.GOOGLE_CALENDAR_ID!,
MY_EMAIL: process.env.MY_EMAIL!,
GOOGLE_ACCESS_TOKEN: process.env.GOOGLE_ACCESS_TOKEN!,
GOOGLE_REFRESH_TOKEN: process.env.GOOGLE_REFRESH_TOKEN!,
},
cors: {
allowedOrigins: ['https://yourdomain.com', 'http://localhost:3000'],
},
businessHours: {
start: 9,
end: 20,
},
});
export const GET = handler.GET;
export const POST = handler.POST;
export const OPTIONS = handler.OPTIONS;Custom Implementation (Any Platform)
import { GoogleCalendarService } from '@kev1nramos/booking-server';
const service = new GoogleCalendarService({
env: {
GOOGLE_CLIENT_ID: 'your-client-id',
GOOGLE_CLIENT_SECRET: 'your-client-secret',
// ... other env vars
},
businessHours: { start: 9, end: 20 },
slots: { interval: 30, durations: [30, 60, 90] },
});
// Get available slots
const slots = await service.getAvailableSlots('2025-11-15');
// Create a booking
const eventId = await service.createEvent({
summary: 'Meeting with John Doe',
start: { dateTime: '2025-11-15T10:00:00', timeZone: 'America/New_York' },
end: { dateTime: '2025-11-15T11:00:00', timeZone: 'America/New_York' },
attendees: [{ email: 'john@example.com' }],
});API Reference
GET /api/book?timezone=true
Get the calendar's timezone.
Response:
{
"timezone": "America/New_York"
}GET /api/book?date=YYYY-MM-DD&clientTimezone=...
Get available time slots for a specific date.
Query Parameters:
date(required): Date in YYYY-MM-DD formatclientTimezone(optional): IANA timezone for conversion
Response:
{
"slots": [
{
"id": "2025-11-15-09:00",
"time": "09:00",
"available": true
},
{
"id": "2025-11-15-09:30",
"time": "09:30",
"available": false
}
]
}POST /api/book
Create a new booking.
Request Body:
{
"name": "John Doe",
"email": "john@example.com",
"company": "Acme Inc",
"message": "Looking forward to our meeting",
"date": "2025-11-15",
"startTime": "10:00",
"endTime": "11:00",
"duration": 60,
"clientTimezone": "America/New_York"
}Response:
{
"success": true,
"message": "Booking confirmed! You will receive a calendar invitation via email.",
"eventId": "abc123xyz",
"details": {
"name": "John Doe",
"email": "john@example.com",
"date": "2025-11-15",
"startTime": "10:00",
"endTime": "11:00",
"timezone": "America/New_York"
}
}Configuration
Business Hours
businessHours: {
start: 9, // Start hour (0-23)
end: 20, // End hour (0-23)
}Slot Configuration
slots: {
interval: 30, // Minutes between slots
durations: [30, 45, 60, 90, 120], // Available meeting durations
}CORS
cors: {
allowedOrigins: [
'https://yourdomain.com',
'http://localhost:3000',
],
}Rate Limiting
rateLimit: {
max: 10, // Maximum requests
windowMs: 60000, // Per time window (milliseconds)
}Security
This library implements multiple security layers:
- ✅ Input validation and sanitization
- ✅ Rate limiting (IP-based)
- ✅ CORS protection
- ✅ XSS prevention (HTML escaping)
- ✅ Security headers (CSP, HSTS, X-Frame-Options, etc.)
- ✅ Environment variable validation
- ✅ No sensitive data exposure in errors
See SECURITY.md for detailed security documentation.
Development
Install Dependencies
pnpm installBuild All Packages
pnpm buildDevelopment Mode
pnpm devType Checking
pnpm typecheckPlatform Compatibility
| Platform | Status | Notes |
|---|---|---|
| Cloudflare Workers/Pages | ✅ Fully Supported | Native runtime |
| Vercel Edge Runtime | ✅ Fully Supported | Web Standard APIs |
| AWS Lambda (Node 18+) | ✅ Fully Supported | Native fetch support |
| Node.js 18+ | ✅ Fully Supported | Native fetch support |
| Node.js < 18 | ⚠️ Requires Polyfill | Use node-fetch |
| Deno | ✅ Fully Supported | Web Standard APIs |
| Bun | ✅ Fully Supported | Web Standard APIs |
| Netlify Edge | ✅ Fully Supported | Deno-based runtime |
License
MIT
Author
Kevin Ramos
Contributing
This is a private repository. For issues or suggestions, contact the maintainer directly.