Skip to content

cayde-6/icalendar

Repository files navigation

icalendar

Release npm version CI Coverage

icalendar hero

TypeScript CLI for CalDAV calendars, iCalendar events, and automation-friendly workflows.

Published package: @cayde-6/icalendar

icalendar gives scripts, automations, and integrations a thin, reliable interface for:

  • listing calendars
  • listing events
  • creating events
  • updating events
  • deleting events
  • sending attendee invites through CalDAV/iCalendar
  • setting a friendly organizer display name (for example Calendar Bot)

It was validated live against real iCloud CalDAV with create → update → invite → delete flows.

Why this exists

Most CalDAV tooling is either too low-level for automation or too UI-centric for scripts and integrations. This repo wraps the ugly parts behind a small CLI and a layered codebase that is easy to embed, extend, and reason about.

Features

  • ESM TypeScript CLI with clean layering
  • published npm package: @cayde-6/icalendar
  • CalDAV access via tsdav
  • invite-ready ICS generation
  • attendee support for create/update flows
  • configurable organizer common name via env
  • text and JSON output modes
  • runtime-safe handling of --help / --version
  • live-tested against iCloud CalDAV create → update → delete flows
  • GitHub Release + npm Trusted Publishing workflow
  • architecture and integration docs for embedders

Install

From npm

npm install -g @cayde-6/icalendar
icalendar --help
icalendar --version

From source

git clone https://github.com/cayde-6/icalendar.git
cd icalendar
npm install
npm run build

Use as a local CLI

npm link
icalendar --help

Use without linking

node --import tsx src/cli.ts --help
node dist/cli.js calendars list

Configuration

Copy the example file:

cp .env.example .env

Required configuration:

CALDAV_SERVER_URL=https://caldav.icloud.com/
CALDAV_USERNAME=primary.attendee@example.test
CALDAV_PASSWORD=app-specific-password

Optional configuration:

CALDAV_CALENDAR_NAME=Example Calendar
CALDAV_ORGANIZER_NAME=Calendar Bot
CALDAV_RANGE_START=2026-05-07T00:00:00+02:00
CALDAV_RANGE_END=2026-05-08T00:00:00+02:00
CALDAV_EXPAND_RECURRING=true

iCloud setup: generate an app-specific password

For iCloud CalDAV you need an app-specific password. Your normal Apple ID password will not work.

How to generate it:

  1. Go to your Apple account settings: https://account.apple.com/
  2. Sign in with the Apple account that owns the iCloud calendar
  3. Open the Sign-In and Security section
  4. Find App-Specific Passwords
  5. Create a new password, for example named icalendar
  6. Copy the generated password and put it into:
CALDAV_PASSWORD=your-app-specific-password

Recommended iCloud values:

CALDAV_SERVER_URL=https://caldav.icloud.com/
CALDAV_USERNAME=your-apple-id-email@example.com
CALDAV_PASSWORD=your-app-specific-password

If authentication fails, the most common cause is using the normal Apple ID password instead of the generated app-specific one.

Quick examples

List calendars

icalendar calendars list
icalendar calendars list --json

List events

icalendar events list
icalendar events list --json

Create an event

icalendar events create \
  --summary "Family sync" \
  --start "2026-05-07T18:00:00+02:00" \
  --end "2026-05-07T18:30:00+02:00" \
  --description "Agenda review" \
  --location "Belgrade" \
  --attendees "primary.attendee@example.test,secondary.attendee@example.test"

Update an event

icalendar events update \
  --url "https://caldav.example.com/calendars/personal/event.ics" \
  --summary "Family sync" \
  --start "2026-05-07T18:00:00+02:00" \
  --end "2026-05-07T18:45:00+02:00" \
  --attendees "primary.attendee@example.test,secondary.attendee@example.test"

Delete an event

icalendar events delete "https://caldav.example.com/calendars/personal/event.ics"

Programmatic usage

The package can also be used as a library.

CalDAV gateway

import { TsdavCalendarGateway } from '@cayde-6/icalendar'
import type { RuntimeConfig } from '@cayde-6/icalendar'

const config: RuntimeConfig = {
  serverUrl: 'https://caldav.icloud.com/',
  username: 'user@example.com',
  password: 'app-specific-password',
}

const gateway = new TsdavCalendarGateway(config)
const calendars = await gateway.listCalendars()
const events = await gateway.listEvents({ calendar: calendars[0] })

ICS generation

import { buildEventIcs } from '@cayde-6/icalendar'
import type { EventDraft } from '@cayde-6/icalendar'

const draft: EventDraft = {
  summary: 'Team standup',
  start: '2026-05-07T10:00:00+02:00',
  end: '2026-05-07T10:15:00+02:00',
  attendees: [{ email: 'colleague@example.com' }],
}

const ics = buildEventIcs(draft, undefined, 'organizer@example.com', 'Calendar Bot')

Exported types: Calendar, CalendarEvent, EventDraft, EventAttendee, EventMutationResult, EventUpdate, TimeRange, CalendarGatewayPort, RuntimeConfig.

Automation integration

If another automation, script, or service wants to adopt this CLI, start here:

Short version:

  1. install dependencies
  2. provide .env
  3. run npm run build
  4. use icalendar ... or node dist/cli.js ...
  5. prefer --json for machine consumers

Development

npm run check
npm run build
npm test
npm run test:coverage
npm run verify

Test strategy

Current coverage includes:

  • calendar selection rules
  • time range defaults
  • command parsing for create/update/delete
  • text/json runtime output
  • env config parsing
  • ICS generation and ICS parsing
  • runtime error rendering

Architecture

icalendar follows a layered CLI structure:

cli -> app(commands/use-cases) -> domain -> infra -> presentation -> shared

The CalDAV SDK stays in infra/, use-cases orchestrate, domain stays provider-agnostic, and renderers only format output.

Reliability notes

  • invite flows were smoke-tested live against iCloud CalDAV
  • --help and --version do not require env credentials
  • organizer display name is configurable with CALDAV_ORGANIZER_NAME
  • attendee invites work in both create and update flows
  • CLI defaults to the first calendar when CALDAV_CALENDAR_NAME is omitted
  • npm run verify covers typecheck, build, tests, and coverage reporting

Releases

  • GitHub releases are created from pushed tags: v*
  • npm publishing is wired through npm Trusted Publishing from GitHub Actions
  • current public package name: @cayde-6/icalendar

Repo docs

License

MIT

About

TypeScript CalDAV/iCalendar CLI toolkit

Topics

Resources

License

Contributing

Security policy

Stars

Watchers

Forks

Packages

 
 
 

Contributors