← All @molecule/* packages · App templates
@molecule/api-resource-bookingAPI resource · bookings · API (Node) · v1.0.1 · Apache-2.0
Booking/reservation resource with availability checking, lifecycle management, rescheduling, and resource-scoped queries.
npm install @molecule/api-resource-booking@molecule/api-resource-booking is an API resource: the routes, validation and storage for bookings, built on the database and auth cores so it runs on whichever providers your app has bonded.
import { routes, requestHandlerMap } from '@molecule/api-resource-booking'
// Wired by mlcl inject (all routes require authenticate):
// GET /bookings/availability/:resourceType/:resourceId?date=YYYY-MM-DD[&duration=60]
// POST /bookings — create (starts 'pending', 409 on overlap)
// GET /bookings — the caller's bookings
// GET /bookings/:id
// POST /bookings/:id/cancel | /confirm | /complete
// PUT /bookings/:id/rescheduleWorks with: @molecule/api-i18n, @molecule/api-resource
Auto-generated, AI-first package reference for the molecule.dev ecosystem. It is written to be read by coding agents as much as by people, and is generated from this package's source — edit
src/index.tsJSDoc, not this file.
Booking/reservation resource for molecule.dev.
Provides availability checking, booking creation, lifecycle management (confirm, cancel, complete), rescheduling, and resource-scoped queries.
import { routes, requestHandlerMap } from '@molecule/api-resource-booking'
// Wired by mlcl inject (all routes require authenticate):
// GET /bookings/availability/:resourceType/:resourceId?date=YYYY-MM-DD[&duration=60]
// POST /bookings — create (starts 'pending', 409 on overlap)
// GET /bookings — the caller's bookings
// GET /bookings/:id
// POST /bookings/:id/cancel | /confirm | /complete
// PUT /bookings/:id/reschedule
resource
npm install @molecule/api-resource-booking @molecule/api-database @molecule/api-i18n @molecule/api-logger @molecule/api-resource
BookingA booking/reservation.
interface Booking {
/** Unique booking identifier. */
id: string
/** The user who created this booking. */
userId: string
/** The type of resource being booked (e.g., 'room', 'appointment'). */
resourceType: string
/** The specific resource identifier. */
resourceId: string
/** Current booking status. */
status: BookingStatus
/** Start time of the booking. */
startTime: string
/** End time of the booking. */
endTime: string
/** Duration in minutes. */
duration: number
/** Optional notes. */
notes?: string
/** Arbitrary metadata attached to this booking. */
metadata?: Record<string, unknown>
/** Creation timestamp. */
createdAt: string
/** Last modification timestamp. */
updatedAt: string
}
BookingQueryOptions for querying bookings.
interface BookingQuery {
/** Filter by status. */
status?: BookingStatus
/** Return only bookings starting after this date. */
from?: string
/** Return only bookings starting before this date. */
to?: string
/** Page number (1-based). */
page?: number
/** Items per page. */
limit?: number
}
BookingRowInternal database row for a booking.
interface BookingRow {
/** Unique booking identifier. */
id: string
/** The user who created this booking. */
userId: string
/** The type of resource being booked. */
resourceType: string
/** The specific resource identifier. */
resourceId: string
/** Current booking status. */
status: string
/** Start time of the booking. */
startTime: string
/** End time of the booking. */
endTime: string
/** Duration in minutes. */
duration: number
/** Optional notes. */
notes: string | null
/** JSON-serialized metadata. */
metadata: string | null
/** Creation timestamp. */
createdAt: string
/** Last modification timestamp. */
updatedAt: string
}
CancelBookingInputInput for cancelling a booking.
interface CancelBookingInput {
/** Optional cancellation reason. */
reason?: string
}
CreateBookingInputInput for creating a booking.
interface CreateBookingInput {
/** The type of resource being booked. */
resourceType: string
/** The specific resource identifier. */
resourceId: string
/** Start time of the booking (ISO 8601). */
startTime: string
/** Duration in minutes. */
duration: number
/** Optional notes. */
notes?: string
/** Arbitrary metadata. */
metadata?: Record<string, unknown>
}
PaginatedResultA paginated result set.
interface PaginatedResult<T> {
/** The page of results. */
data: T[]
/** Total number of matching records. */
total: number
/** Current page number. */
page: number
/** Page size. */
limit: number
}
RescheduleBookingInputInput for rescheduling a booking.
interface RescheduleBookingInput {
/** New start time (ISO 8601). */
startTime: string
/** New duration in minutes (optional, keeps existing if omitted). */
duration?: number
}
TimeSlotAn available time slot.
interface TimeSlot {
/** Start time of the slot. */
startTime: string
/** End time of the slot. */
endTime: string
/** Whether the slot is available. */
available: boolean
}
BookingStatusPossible statuses for a booking lifecycle.
type BookingStatus = 'pending' | 'confirmed' | 'cancelled' | 'completed' | 'no-show'
book(req, res)Creates a new booking for the authenticated user. Validates no conflicting bookings exist for the requested time slot.
function book(req: MoleculeRequest, res: MoleculeResponse): Promise<void>
req — The request with {@link CreateBookingInput} body.res — The response object.cancel(req, res)Cancels a booking. Only the booking owner can cancel, and only from valid states.
function cancel(req: MoleculeRequest, res: MoleculeResponse): Promise<void>
req — The request with params.id and optional {@link CancelBookingInput} body.res — The response object.checkAvailability(req, res)Checks availability for a resource on a given date. Returns hourly time slots with availability status based on existing bookings.
function checkAvailability(req: MoleculeRequest, res: MoleculeResponse): Promise<void>
req — The request with params.resourceType, params.resourceId, and query date and optional duration.res — The response object.complete(req, res)Marks a confirmed booking as completed. Only the booking owner can complete.
function complete(req: MoleculeRequest, res: MoleculeResponse): Promise<void>
req — The request with params.id.res — The response object.computeEndTime(startTime, durationMinutes)Computes the end time given a start time and duration in minutes.
function computeEndTime(startTime: string, durationMinutes: number): string
startTime — ISO 8601 start time string.durationMinutes — Duration in minutes.Returns: ISO 8601 end time string.
confirm(req, res)Confirms a pending booking. Only the booking owner can confirm.
function confirm(req: MoleculeRequest, res: MoleculeResponse): Promise<void>
req — The request with params.id.res — The response object.generateTimeSlots(date, durationMinutes, existingBookings)Generates hourly time slots for a given date and checks availability against existing bookings.
function generateTimeSlots(
date: string,
durationMinutes: number,
existingBookings: BookingRow[],
): TimeSlot[]
date — The date to generate slots for (ISO 8601).durationMinutes — Requested duration in minutes (default 60).existingBookings — Already-booked rows for the resource on that day.Returns: An array of time slots with availability.
getBookings(req, res)Lists bookings for the authenticated user with optional filtering and pagination.
function getBookings(req: MoleculeRequest, res: MoleculeResponse): Promise<void>
req — The request with optional query params for status, from, to, page, limit.res — The response object.getById(req, res)Retrieves a single booking by ID. Only the booking owner can access it.
function getById(req: MoleculeRequest, res: MoleculeResponse): Promise<void>
req — The request with params.id.res — The response object.reschedule(req, res)Reschedules a booking to a new time. Only the booking owner can reschedule, and only pending or confirmed bookings can be rescheduled.
function reschedule(req: MoleculeRequest, res: MoleculeResponse): Promise<void>
req — The request with params.id and {@link RescheduleBookingInput} body.res — The response object.toBooking(row)Converts a database booking row into a typed {@link Booking}.
function toBooking(row: BookingRow): Booking
row — The raw database row.Returns: The deserialized booking.
BOOKING_STATUSESAll valid booking statuses.
const BOOKING_STATUSES: readonly BookingStatus[]
i18nRegisteredWhether i18n registration has been attempted. Always true; this module is
a placeholder for symmetry with locale-bonded resources.
const i18nRegistered: true
requestHandlerMapHandler map for the booking resource routes.
const requestHandlerMap: {
readonly checkAvailability: typeof checkAvailability
readonly book: typeof book
readonly getBookings: typeof getBookings
readonly getById: typeof getById
readonly cancel: typeof cancel
readonly reschedule: typeof reschedule
readonly confirm: typeof confirm
readonly complete: typeof complete
}
routesBooking routes. Supports availability checking, CRUD, lifecycle transitions, and resource-scoped listing.
const routes: readonly [
{
readonly method: 'get'
readonly path: '/bookings/availability/:resourceType/:resourceId'
readonly handler: 'checkAvailability'
readonly middlewares: readonly ['authenticate']
},
{
readonly method: 'post'
readonly path: '/bookings'
readonly handler: 'book'
readonly middlewares: readonly ['authenticate']
},
{
readonly method: 'get'
readonly path: '/bookings'
readonly handler: 'getBookings'
readonly middlewares: readonly ['authenticate']
},
{
readonly method: 'get'
readonly path: '/bookings/:id'
readonly handler: 'getById'
readonly middlewares: readonly ['authenticate']
},
{
readonly method: 'post'
readonly path: '/bookings/:id/cancel'
readonly handler: 'cancel'
readonly middlewares: readonly ['authenticate']
},
{
readonly method: 'put'
readonly path: '/bookings/:id/reschedule'
readonly handler: 'reschedule'
readonly middlewares: readonly ['authenticate']
},
{
readonly method: 'post'
readonly path: '/bookings/:id/confirm'
readonly handler: 'confirm'
readonly middlewares: readonly ['authenticate']
},
{
readonly method: 'post'
readonly path: '/bookings/:id/complete'
readonly handler: 'complete'
readonly middlewares: readonly ['authenticate']
},
]
STATUS_TRANSITIONSAllowed status transitions keyed by current status.
const STATUS_TRANSITIONS: Record<BookingStatus, readonly BookingStatus[]>
Peer dependencies:
@molecule/api-database ^1.0.1@molecule/api-i18n ^1.0.1@molecule/api-logger ^1.0.1@molecule/api-resource ^1.0.1@molecule/api-database
@molecule/api-i18n
@molecule/api-logger
@molecule/api-resource
Migration required. src/__setup__/bookings.sql ships with this package
and must exist in the target database before use (scaffolded apps apply it
automatically; existing apps must apply it first).
Bookable resources are polymorphic and NOT verified. resourceType /
resourceId are free-form — no FK, no existence or capacity check. Your app
decides what is bookable and validates the target in domain code.
Every lifecycle action is owner-only. cancel/reschedule/confirm/complete
all reject when the booking's userId differs from the session user. There
is no staff/operator role: if your app needs a provider to confirm bookings,
add your own authorizer + handler — do not loosen the ownership checks.
The status machine is enforced (STATUS_TRANSITIONS): pending →
confirmed → completed/no-show, with cancel allowed from pending/confirmed.
Creation always starts pending; book returns 409 when a non-cancelled
booking overlaps the requested slot.
Availability requires ?date=YYYY-MM-DD (400 without it) and returns
hourly slots based on existing bookings — it is a DISPLAY aid; book
re-checks conflicts server-side at creation time.
Integration checklist — drive the real UI (live preview, no mocks), adapt each item to this app's actual screens/flows, and check every box off one by one. A box you can't check is a booking bug to fix — not a skip: