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

@svutil/cally

v0.0.5

Published

Calendar integrations with automatic token management

Readme

cally

Calendar sync that just works.

OAuth tokens, automatic refresh, delta sync, webhooks—handled. You bring the storage, cally handles the rest.

import { Calendar } from "@svutil/cally";

const cal = Calendar.microsoft({
  clientId: process.env.MS_CLIENT_ID,
  clientSecret: process.env.MS_CLIENT_SECRET,
  adapter: tokenAdapter,
});

await cal.auth.setTokens(userId, tokens);
const events = await cal.events.list(userId);

The Problem

Calendar integrations are deceptively annoying:

  • Token refresh - Access tokens expire. Refresh tokens die. You need to handle both invisibly.
  • Sync state - Microsoft's delta API is efficient but stateful. You need to track delta tokens per-user, per-calendar.
  • Webhooks - Subscriptions expire after 3 days. Miss a renewal and you're polling blind.
  • Error handling - Rate limits, permission changes, token revocation—each needs different handling.

Most teams end up building this infrastructure from scratch. It's not hard, but it's tedious and easy to get wrong.

What cally does

cally is a thin wrapper around Microsoft Graph (Google coming) that handles the boring parts:

  • Invisible token refresh - Every API call checks expiry, refreshes if needed
  • Delta sync - Full sync creates a checkpoint, incremental sync uses it
  • Webhook lifecycle - Create, renew, parse notifications, handle edge cases
  • Typed errors - REAUTH_REQUIRED means prompt the user, RATE_LIMITED means back off

You provide adapters for storage (tokens, sync state, subscriptions). We provide Prisma and Supabase adapters, or you write your own.

Installation

npm install @svutil/cally

Quick Start

import { Calendar } from "@svutil/cally";
import { PrismaTokenAdapter, PrismaSyncAdapter } from "@svutil/cally/prisma";

const cal = Calendar.microsoft({
  clientId: process.env.MS_CLIENT_ID,
  clientSecret: process.env.MS_CLIENT_SECRET,
  adapter: new PrismaTokenAdapter(prisma),
  syncAdapter: new PrismaSyncAdapter(prisma),
});

// After OAuth callback
await cal.auth.setTokens(userId, {
  accessToken: tokens.access_token,
  refreshToken: tokens.refresh_token,
  expiresAt: new Date(Date.now() + tokens.expires_in * 1000),
});

// Initial sync - fetches everything, creates delta token
const result = await cal.sync.fullSync(userId);

// Later syncs - only gets changes
const changes = await cal.sync.incrementalSync(userId);

Real-time Updates

For apps that need instant updates (meeting notes, scheduling tools):

// Create webhook subscription
await cal.subscriptions.ensure(userId, {
  webhookUrl: "https://yourapp.com/webhooks/calendar",
});

// Handle incoming webhooks
app.post("/webhooks/calendar", async (req, res) => {
  if (req.query.validationToken) {
    return res.send(req.query.validationToken);
  }

  await cal.sync.incrementalSync(userId);
  // Push to connected clients via websocket/SSE

  res.status(202).send();
});

// Cron job - renew before expiry (subscriptions last ~3 days)
await cal.subscriptions.renewAll();

API

Events

cal.events.list(userId, { startDate, endDate })
cal.events.get(userId, eventId)
cal.events.create(userId, { title, start, end, ... })
cal.events.update(userId, eventId, { title })
cal.events.delete(userId, eventId)
cal.events.listCalendars(userId)

Sync

cal.sync.fullSync(userId); // Initial sync, creates delta token
cal.sync.incrementalSync(userId); // Uses delta token, only gets changes

Subscriptions

cal.subscriptions.ensure(userId, { webhookUrl }); // Create or renew
cal.subscriptions.renewAll(); // For cron jobs
cal.subscriptions.delete(userId);

Health

const health = await cal.health.check(userId);
// { isConnected, tokenExpiresAt, hasSubscription, lastSyncAt }

Error Handling

import { CalendarError } from "@svutil/cally";

try {
  await cal.events.list(userId);
} catch (error) {
  if (error instanceof CalendarError) {
    if (error.code === "REAUTH_REQUIRED") {
      // Refresh token is dead, user needs to reconnect
    }
    if (error.code === "RATE_LIMITED") {
      // Back off, retry after error.retryAfterMs
    }
  }
}

Adapters

Prisma

import {
  PrismaTokenAdapter,
  PrismaSyncAdapter,
  PrismaSubscriptionAdapter,
  PRISMA_SCHEMA,
} from "@svutil/cally/prisma";

// Add PRISMA_SCHEMA to your schema.prisma

Supabase

import {
  SupabaseTokenAdapter,
  SupabaseSyncAdapter,
  SupabaseSubscriptionAdapter,
  SUPABASE_SCHEMA,
} from "@svutil/cally/supabase";

// Run SUPABASE_SCHEMA as migration

Custom

interface TokenAdapter {
  getTokens(userId: string): Promise<Tokens | null>;
  saveTokens(userId: string, tokens: Tokens): Promise<void>;
  deleteTokens(userId: string): Promise<void>;
}

Production Checklist

For reliable calendar sync in production:

  1. Auto-sync on connect - Run fullSync right after OAuth, not manually
  2. Webhook renewal cron - Run subscriptions.renewAll() every 12 hours
  3. Fallback sync cron - Run incrementalSync every 15 minutes as safety net
  4. Handle REAUTH_REQUIRED - Prompt users to reconnect when refresh tokens die
// Webhook handler
app.post("/webhooks/calendar", async (req, res) => {
  if (req.query.validationToken) return res.send(req.query.validationToken);
  await cal.sync.incrementalSync(userId);
  res.status(202).send();
});

// Cron: every 12 hours
await cal.subscriptions.renewAll();

// Cron: every 15 minutes (belt and suspenders)
for (const userId of activeUsers) {
  await cal.sync.incrementalSync(userId);
}

License

MIT