npm package discovery and stats viewer.

Discover Tips

  • General search

    [free text search, go nuts!]

  • Package details

    pkg:[package-name]

  • User packages

    @[username]

Sponsor

Optimize Toolset

I’ve always been into building performant and accessible sites, but lately I’ve been taking it extremely seriously. So much so that I’ve been building a tool to help me optimize and monitor the sites that I build to make sure that I’m making an attempt to offer the best experience to those who visit them. If you’re into performant, accessible and SEO friendly sites, you might like it too! You can check it out at Optimize Toolset.

About

Hi, 👋, I’m Ryan Hefner  and I built this site for me, and you! The goal of this site was to provide an easy way for me to check the stats on my npm packages, both for prioritizing issues and updates, and to give me a little kick in the pants to keep up on stuff.

As I was building it, I realized that I was actually using the tool to build the tool, and figured I might as well put this out there and hopefully others will find it to be a fast and useful way to search and browse npm packages as I have.

If you’re interested in other things I’m working on, follow me on Twitter or check out the open source projects I’ve been publishing on GitHub.

I am also working on a Twitter bot for this site to tweet the most popular, newest, random packages from npm. Please follow that account now and it will start sending out packages soon–ish.

Open Software & Tools

This site wouldn’t be possible without the immense generosity and tireless efforts from the people who make contributions to the world and share their work via open source initiatives. Thank you 🙏

© 2026 – Pkg Stats / Ryan Hefner

@86d-app/appointments

v0.0.40

Published

Appointments — service-based booking with staff scheduling, time slots, and customer appointment management

Readme

[!WARNING] This project is under active development and is not ready for production use. Please proceed with caution. Use at your own risk.

Appointments Module

📚 Documentation: 86d.app/docs/modules/appointments

Service-based booking module for commerce stores. Manage bookable services, staff members, weekly schedules, availability, and customer appointments. Designed for salons, consultants, fitness studios, clinics, and any service-based business.

Installation

npm install @86d-app/appointments

Usage

import appointments from "@86d-app/appointments";

const module = appointments({
  defaultCurrency: "USD",
  minAdvanceMinutes: 60,
});

Configuration

| Option | Type | Default | Description | |---|---|---|---| | defaultCurrency | string | "USD" | Default currency for service pricing | | minAdvanceMinutes | number | — | Minimum advance booking time in minutes |

Store Endpoints

| Method | Path | Description | |---|---|---| | GET | /appointments/services | List active services | | GET | /appointments/services/:slug | Get service details with staff | | GET | /appointments/availability | Get available time slots | | POST | /appointments/book | Book an appointment | | GET | /appointments/:id | Get appointment details | | POST | /appointments/:id/cancel | Cancel an appointment |

Availability Query Parameters

| Param | Type | Required | Description | |---|---|---|---| | serviceId | string | Yes | Service to check availability for | | staffId | string | No | Filter to a specific staff member | | date | Date | Yes | Date to check (ISO 8601) |

Admin Endpoints

Services

| Method | Path | Description | |---|---|---| | GET | /admin/appointments/services | List all services | | POST | /admin/appointments/services/create | Create a service | | GET | /admin/appointments/services/:id | Get service with staff | | POST | /admin/appointments/services/:id/update | Update a service | | POST | /admin/appointments/services/:id/delete | Delete a service |

Staff

| Method | Path | Description | |---|---|---| | GET | /admin/appointments/staff | List all staff | | POST | /admin/appointments/staff/create | Create a staff member | | POST | /admin/appointments/staff/:id/update | Update a staff member | | POST | /admin/appointments/staff/:id/delete | Delete a staff member | | POST | /admin/appointments/staff/:id/services/assign | Assign service to staff | | POST | /admin/appointments/staff/:id/schedule | Set weekly schedule |

Appointments

| Method | Path | Description | |---|---|---| | GET | /admin/appointments | List appointments (filterable) | | GET | /admin/appointments/:id | Get appointment details | | POST | /admin/appointments/:id/update | Update appointment | | GET | /admin/appointments/stats | Get appointment statistics |

Admin UI

The module includes admin UI components in src/admin/components/index.tsx (client components using useModuleClient):

| Page | Component | Description | |------|-----------|-------------| | /admin/appointments | AppointmentList | Appointment list with status filters and management | | /admin/appointments/:id | AppointmentDetail | Appointment detail with status updates | | /admin/appointments/services | ServiceList | Service list with create/edit forms | | /admin/appointments/staff | StaffList | Staff list with schedule and service assignment management |

Controller API

interface AppointmentController {
  // Services
  createService(params): Promise<Service>;
  getService(id): Promise<Service | null>;
  getServiceBySlug(slug): Promise<Service | null>;
  updateService(id, params): Promise<Service | null>;
  deleteService(id): Promise<boolean>;
  listServices(params?): Promise<Service[]>;
  countServices(params?): Promise<number>;

  // Staff
  createStaff(params): Promise<Staff>;
  getStaff(id): Promise<Staff | null>;
  updateStaff(id, params): Promise<Staff | null>;
  deleteStaff(id): Promise<boolean>;
  listStaff(params?): Promise<Staff[]>;
  countStaff(params?): Promise<number>;

  // Staff-Service assignments
  assignService(staffId, serviceId): Promise<StaffService>;
  unassignService(staffId, serviceId): Promise<boolean>;
  getStaffServices(staffId): Promise<Service[]>;
  getServiceStaff(serviceId): Promise<Staff[]>;

  // Schedules
  setSchedule(params): Promise<Schedule>;
  getSchedule(staffId): Promise<Schedule[]>;
  removeSchedule(staffId, dayOfWeek): Promise<boolean>;

  // Availability
  getAvailableSlots(params): Promise<TimeSlot[]>;

  // Appointments
  createAppointment(params): Promise<Appointment>;
  getAppointment(id): Promise<Appointment | null>;
  updateAppointment(id, params): Promise<Appointment | null>;
  cancelAppointment(id): Promise<Appointment | null>;
  listAppointments(params?): Promise<Appointment[]>;
  countAppointments(params?): Promise<number>;
  getUpcomingAppointments(params?): Promise<Appointment[]>;

  // Stats
  getStats(): Promise<AppointmentStats>;
}

Types

type ServiceStatus = "active" | "inactive";
type StaffStatus = "active" | "inactive";
type AppointmentStatus = "pending" | "confirmed" | "cancelled" | "completed" | "no-show";

interface Service {
  id: string;
  name: string;
  slug: string;
  description?: string;
  duration: number;       // in minutes
  price: number;
  currency: string;
  status: ServiceStatus;
  maxCapacity: number;
  sortOrder: number;
  createdAt: Date;
  updatedAt: Date;
}

interface Staff {
  id: string;
  name: string;
  email: string;
  bio?: string;
  status: StaffStatus;
  createdAt: Date;
  updatedAt: Date;
}

interface Schedule {
  id: string;
  staffId: string;
  dayOfWeek: number;     // 0 = Sunday, 6 = Saturday
  startTime: string;     // "HH:MM"
  endTime: string;       // "HH:MM"
  createdAt: Date;
}

interface Appointment {
  id: string;
  serviceId: string;
  staffId: string;
  customerId?: string;
  customerName: string;
  customerEmail: string;
  customerPhone?: string;
  startsAt: Date;
  endsAt: Date;           // auto-calculated from service duration
  status: AppointmentStatus;
  notes?: string;
  price: number;
  currency: string;
  createdAt: Date;
  updatedAt: Date;
}

interface TimeSlot {
  startsAt: Date;
  endsAt: Date;
  staffId: string;
}

interface AppointmentStats {
  totalAppointments: number;
  pendingAppointments: number;
  confirmedAppointments: number;
  cancelledAppointments: number;
  completedAppointments: number;
  noShowAppointments: number;
  totalServices: number;
  totalStaff: number;
  totalRevenue: number;
}

Notes

  • Schedule is per-staff, per-day — one entry per (staffId, dayOfWeek) pair, upserted on set.
  • Availability auto-generates time slots from schedule minus existing non-cancelled appointments.
  • endsAt is always calculated from startsAt + service.duration — never set directly.
  • Deleting a staff member cascades to their assignments and schedules.
  • Deleting a service cascades to staff-service assignments.
  • Revenue stats only count completed appointments.