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 🙏

© 2025 – Pkg Stats / Ryan Hefner

scheduling-sdk

v0.5.2

Published

Brought to you by Recal - A TypeScript SDK for scheduling functionality

Downloads

1,888

Readme

Scheduling SDK 📆

npm version Tests Test Coverage

Brought to you by Recal - Your unified calendar API 🚀

A fast TypeScript Scheduling SDK for finding available time slots with exceptional developer experience!

Features

  • 🎯 DX First: Intuitive APIs that feel intuitive to use
  • 🔒 Full TypeScript Support: Complete type safety with excellent IntelliSense
  • 📦 Dual Module Support: Works with both ESM and CommonJS (NestJS compatible!)
  • 📖 Extensive Documentation: In-depth guides, examples, and API references (With help by Claude)
  • ⚡ Blazing Fast Performance: Optimized algorithms for handling large datasets
  • 🔧 Flexible Configuration: Customizable slot duration, padding, splitting, and offset
  • ⏰ Timezone-Aware Daily Windows: Filter slots to local hours using timezone, earliestTime, and latestTime
  • 📅 Weekly Availability Patterns: Define recurring weekly schedules with automatic break management
  • 🏗️ Modular Architecture: Clean separation of concerns for maintainability and testing
  • 🧪 98%+ Test Coverage: Comprehensive testing with edge case handling (Supported by the CODE's Automated Testing LU)

Note The SDK is fully written in TypeScript and uses Bun as the build and test tool. It requires TypeScript 5.0 or later as a peer dependency. While we use Bun for development, the compiled SDK is compatible with any JavaScript runtime (Node.js, Deno, browsers) and works with both ESM and CommonJS module systems.

Quick Start 💨

# Install the SDK
npm install scheduling-sdk
# or
bun add scheduling-sdk

Zero configuration required - start scheduling in seconds! 🚀

Module Compatibility

The SDK supports both ESM and CommonJS module systems:

// ESM (Modern)
import { Scheduler, AvailabilityScheduler } from 'scheduling-sdk'

// CommonJS (NestJS, older Node.js)
const { Scheduler, AvailabilityScheduler } = require('scheduling-sdk')

Both formats provide identical functionality and TypeScript support.

Core Concepts

  • Busy Times: Periods when you're NOT available (meetings, appointments, breaks)
  • Available Slots: Free time periods where new events can be scheduled
  • Time Range: The window (start/end dates) to search for available slots
  • Slot Options: Configuration for how slots are generated (duration, padding, etc.)

Basic Usage

Standard Scheduling

import { Scheduler } from 'scheduling-sdk'

// Initialize scheduler with busy times (existing meetings, appointments, etc.)
// Busy times are periods when you're NOT available
const scheduler = new Scheduler([
    {
        start: new Date('2024-01-15T09:00:00Z'), // Meeting starts at 9:00 AM
        end: new Date('2024-01-15T10:00:00Z'), // Meeting ends at 10:00 AM
    },
])

// Find available time slots in a given time range
// This will return all free slots between 8:00 AM and 5:00 PM, excluding the busy time
const availableSlots = scheduler.findAvailableSlots(
    new Date('2024-01-15T08:00:00Z'), // Search from 8:00 AM
    new Date('2024-01-15T17:00:00Z'), // Search until 5:00 PM
    {
        slotDuration: 30, // Each available slot will be 30 minutes long
        padding: 15, // Add 15-minute buffer before and after busy times
        slotSplit: 15, // Generate overlapping slots every 15 minutes
        offset: 0, // No offset from hour boundaries
    }
)

// Result: availableSlots will contain time slots like:
// [
//   { start: "2024-01-15T08:00:00Z", end: "2024-01-15T08:30:00Z" },
//   { start: "2024-01-15T08:15:00Z", end: "2024-01-15T08:45:00Z" },
//   { start: "2024-01-15T10:15:00Z", end: "2024-01-15T10:45:00Z" }, // Note: starts at 10:15 due to 15-min padding
//   { start: "2024-01-15T10:30:00Z", end: "2024-01-15T11:00:00Z" },
//   ...
// ]

Managing Busy Times

import { Scheduler } from 'scheduling-sdk'

const scheduler = new Scheduler()

// Add a single busy time (e.g., a new meeting)
scheduler.addBusyTime({
    start: new Date('2024-01-15T14:00:00Z'), // 2:00 PM
    end: new Date('2024-01-15T15:00:00Z'), // 3:00 PM
})

// Add multiple busy times at once (e.g., imported from calendar)
scheduler.addBusyTimes([
    {
        start: new Date('2024-01-15T10:00:00Z'), // Morning standup
        end: new Date('2024-01-15T11:00:00Z'),
    },
    {
        start: new Date('2024-01-15T16:00:00Z'), // Client call
        end: new Date('2024-01-15T17:00:00Z'),
    },
])

// Clear all busy times (e.g., starting fresh)
scheduler.clearBusyTimes()

// Get current busy times (returns a sorted array)
const currentBusyTimes = scheduler.getBusyTimes()
// Returns: [
//   { start: "2024-01-15T10:00:00Z", end: "2024-01-15T11:00:00Z" },
//   { start: "2024-01-15T14:00:00Z", end: "2024-01-15T15:00:00Z" },
//   ...
// ]

Weekly Availability Scheduling

Business hours made easy ;)

import { AvailabilityScheduler } from 'scheduling-sdk'

// Define when you're generally available (business hours)
// This creates recurring weekly patterns
const availability = {
    schedules: [
        // Monday-Friday: 9 AM to 12 PM (morning hours)
        { days: ['monday', 'tuesday', 'wednesday', 'thursday', 'friday'], start: '09:00', end: '12:00' },
        // Monday-Friday: 1 PM to 5 PM (afternoon hours, after lunch)
        { days: ['monday', 'tuesday', 'wednesday', 'thursday', 'friday'], start: '13:00', end: '17:00' },
        // Saturday: 10 AM to 2 PM
        { days: ['saturday'], start: '10:00', end: '14:00' },
    ],
}

const scheduler = new AvailabilityScheduler(availability)

// Add busy times within your available hours (meetings, appointments, etc.)
scheduler.addBusyTimes([
    {
        start: new Date('2024-01-15T14:00:00Z'), // Monday 2 PM meeting
        end: new Date('2024-01-15T15:00:00Z'),
    },
    {
        start: new Date('2024-01-16T10:00:00Z'), // Tuesday 10 AM appointment
        end: new Date('2024-01-16T11:00:00Z'),
    },
])

// Find available slots only within your defined business hours
// This respects both your availability schedule AND busy times
const slots = scheduler.findAvailableSlots(
    new Date('2024-01-15T08:00:00Z'), // Monday 8 AM
    new Date('2024-01-15T18:00:00Z'), // Monday 6 PM
    {
        slotDuration: 60, // 1-hour slots
    }
)
// Result: Only returns slots during business hours (9-12, 1-5) excluding busy times
// [
//   { start: "2024-01-15T09:00:00Z", end: "2024-01-15T10:00:00Z" },
//   { start: "2024-01-15T13:00:00Z", end: "2024-01-15T14:00:00Z" },
//   { start: "2024-01-15T15:00:00Z", end: "2024-01-15T16:00:00Z" },
//   { start: "2024-01-15T16:00:00Z", end: "2024-01-15T17:00:00Z" },
//   ...
// ]

Daily Time Windows and Timezone Filtering

Restrict generated slots to specific local hours by providing a timezone and a daily window.

Core Scheduler usage:

import { Scheduler } from 'scheduling-sdk'

const scheduler = new Scheduler()

// Search the whole day in UTC, but only return slots that START between 9:00 and 17:00 New York time
const slots = scheduler.findAvailableSlots(
  new Date('2024-01-15T00:00:00Z'),
  new Date('2024-01-15T23:59:59Z'),
  {
    slotDuration: 60,
    timezone: 'America/New_York',
    earliestTime: '09:00',
    latestTime: '17:00',
  }
)
// In January, America/New_York is UTC-5, so this filters to 14:00–22:00 UTC

Availability AvailabilityScheduler usage (timezone can be omitted in options; it falls back to the scheduler’s timezone):

import { AvailabilityScheduler } from 'scheduling-sdk'

const availability = {
  schedules: [{ days: ['monday', 'tuesday', 'wednesday', 'thursday', 'friday'], start: '09:00', end: '17:00' }],
}

const scheduler = new AvailabilityScheduler(availability, 'America/New_York')

const slots = scheduler.findAvailableSlots(
  new Date('2024-01-15T00:00:00Z'),
  new Date('2024-01-15T23:59:59Z'),
  {
    slotDuration: 30,
    // No timezone here → uses scheduler's timezone automatically
    earliestTime: 9 * 60,  // numbers = minutes since midnight
    latestTime: '24:00',   // string format supports '24:00' for end of day
  }
)

Daily window parameters:

  • timezone (string, IANA ID, e.g. "America/New_York") — required when using earliestTime/latestTime with the core Scheduler.
  • earliestTime (string HH:mm or number minutes) — lowest local start time to allow.
  • latestTime (string HH:mm or number minutes) — highest local start time to allow; supports "24:00" or 1440.

Notes:

  • If you use AvailabilityScheduler, you may omit timezone in findAvailableSlots when using earliestTime/latestTime; it will default to the scheduler’s timezone.
  • If you use the core Scheduler, providing earliestTime/latestTime without timezone will throw a validation error.
  • Daily windows filter by slot START time.

Allowing Overlaps (K-overlaps)

You can allow up to K overlapping busy intervals by setting maxOverlaps in options. This uses an optimized algorithm internally.

const slots = scheduler.findAvailableSlots(
  new Date('2024-01-15T09:00:00Z'),
  new Date('2024-01-15T17:00:00Z'),
  {
    slotDuration: 30,
    slotSplit: 15,
    maxOverlaps: 1, // allow 1 collision
  }
)

SchedulingOptions reference

interface SchedulingOptions {
  // Required
  slotDuration: number

  // Optional
  padding?: number
  slotSplit?: number
  offset?: number
  maxOverlaps?: number

  // Daily window filtering (timezone-aware)
  timezone?: string
  earliestTime?: string | number // 'HH:mm' or minutes since midnight
  latestTime?: string | number   // 'HH:mm' or minutes since midnight; supports '24:00' or 1440
}

Documentation 📚

Development 💻

# Install dependencies
bun install

# Run in development mode
bun run dev

# Build for production
bun run build

# Run tests
bun test

# Type checking
bun run typecheck

Architecture 🏗️

The SDK is built with a modular architecture:

src/
├── types/              # TypeScript type definitions
├── helpers/            # Utility functions organized by domain
│   ├── time/           # Date/time calculations and alignments
│   ├── busy-time/      # Busy time operations (padding, merging, overlap)
│   ├── slot/           # Slot generation and filtering
│   └── availability/   # Weekly availability conversion
├── validators/         # Input validation functions
├── core/              # Main Scheduler class
├── availability/      # AvailabilityScheduler class
└── utils/             # Shared constants and utilities

Performance ⚡

Optimized for speed with target performance:

  • < 1ms for 100 busy times
  • < 10ms for 1000 busy times
  • < 100ms for 10000 busy times

See Performance Guide for detailed benchmarks.

License

MIT

Contributing 🤝

Please read our Contributing Guide for development setup and contribution guidelines.

Credits 👨‍💻

Engineering by @tkoehlerlg