forceCalendar/Docs
Core Package

ICS Import/Export

RFC 5545 ICS parsing, generation, URL subscriptions, and file handling.

Overview

forceCalendar provides two classes for ICS (iCalendar) handling:

ClassPurpose
ICSParserLow-level RFC 5545 parser and generator
ICSHandlerHigh-level import/export with subscriptions and file I/O

ICSParser

Direct parser for ICS formatted strings. Handles VEVENT components, VALARM (reminders), line folding/unfolding, and RFC 5545 date formats.

Input Size Limits

The parser enforces hard limits to prevent denial-of-service from oversized inputs:

LimitValue
Maximum input size50 MB
Maximum line count100,000 lines
Maximum event count10,000 events

Oversized input is rejected before parsing; line/event limits are checked as the input is processed.

parse(icsString)

Parse an ICS string into an array of event objects.

import { ICSParser } from '@forcecalendar/core';

const parser = new ICSParser();
const events = parser.parse(`BEGIN:VCALENDAR
VERSION:2.0
PRODID:-//Example//EN
BEGIN:VEVENT
DTSTART:20260301T090000Z
DTEND:20260301T100000Z
SUMMARY:Team Meeting
DESCRIPTION:Weekly sync
LOCATION:Room 301
RRULE:FREQ=WEEKLY;BYDAY=MO
END:VEVENT
END:VCALENDAR`);

Returns an array of normalized event objects with:

  • title (from SUMMARY)
  • start / end (Date objects, from DTSTART/DTEND)
  • description (from DESCRIPTION, text unescaped)
  • location (from LOCATION)
  • recurrenceRule (from RRULE)
  • reminders (from VALARM components)
  • allDay (detected from date-only DTSTART)
  • status, uid, organizer, attendees

Supported ICS Properties

ICS PropertyMapped To
SUMMARYtitle
DTSTARTstart
DTENDend
DESCRIPTIONdescription
LOCATIONlocation
RRULErecurrenceRule
STATUSstatus
UIDuid
ORGANIZERorganizer
ATTENDEEattendees[]
CATEGORIEScategories
VALARMreminders[]

export(events, calendarName?)

Generate an ICS string from an array of events.

const icsString = parser.export(events, 'My Calendar');

The output includes:

  • BEGIN:VCALENDAR / END:VCALENDAR wrapper
  • VERSION:2.0
  • PRODID identifier
  • VEVENT blocks for each event
  • VALARM blocks for reminders
  • Proper text escaping (commas, semicolons, newlines)
  • Line folding at 75 octets per RFC 5545

Date Format Support

The parser handles three RFC 5545 date formats:

FormatExampleInterpretation
Date only20260301All-day event, local date
Local datetime20260301T090000Local time (no timezone)
UTC datetime20260301T090000ZUTC time

ICSHandler

High-level ICS operations built on top of ICSParser. Requires a Calendar-compatible instance implementing its event methods; use a Calendar for the documented integration.

import { ICSHandler } from '@forcecalendar/core';

const handler = new ICSHandler(calendar);

import(input, options?)

Import events from an ICS string or File object.

// From string
await handler.import(icsString, {
  merge: true,           // Add to existing events (vs. replace)
  updateExisting: false, // Update events with matching UIDs
  skipDuplicates: true,  // Skip events with duplicate UIDs
  dateRange: {           // Only import events in this range
    start: new Date('2026-01-01'),
    end: new Date('2026-12-31'),
  },
  categories: ['imported'], // Add these categories to imported events
});

// From File object (browser)
const file = document.querySelector('input[type="file"]').files[0];
await handler.import(file);

export(options?)

Export events as an ICS string.

const icsString = handler.export({
  dateRange: {
    start: new Date('2026-03-01'),
    end: new Date('2026-03-31'),
  },
  categories: ['meeting'],    // Only export these categories
  calendarName: 'Work',
  includeRecurring: true,
  expandRecurring: false,     // Export rules (not expanded occurrences)
});

downloadAsFile(filename?, options?)

Export and trigger a browser download.

handler.downloadAsFile('calendar.ics', {
  calendarName: 'My Calendar',
});

importFromURL(url, options?)

Fetch and import an ICS file from a URL.

await handler.importFromURL('https://example.com/calendar.ics', {
  merge: true,
});

subscribe(url, options?)

Subscribe to a remote ICS calendar with automatic refresh.

const subscription = handler.subscribe(
  'https://example.com/calendar.ics',
  {
    refreshInterval: 300000, // 5 minutes (milliseconds)
    merge: true,
  }
);

// Control the subscription
subscription.refresh();  // Force refresh now
subscription.stop();     // Pause auto-refresh
subscription.start();    // Resume auto-refresh

validate(icsString)

Validate an ICS string without importing.

const result = handler.validate(icsString);
// { valid: true, errors: [], eventCount: 5 }

Examples

Import from File Upload

document.getElementById('import-btn').addEventListener('click', async () => {
  const input = document.createElement('input');
  input.type = 'file';
  input.accept = '.ics,.ical,.ifb';

  input.onchange = async (e) => {
    const file = e.target.files[0];
    if (file) {
      const result = await handler.import(file, {
        merge: true,
        skipDuplicates: true,
      });
      console.log(`Imported ${result.imported} events`);
    }
  };

  input.click();
});

Export Monthly Calendar

const now = new Date();
const startOfMonth = new Date(now.getFullYear(), now.getMonth(), 1);
const endOfMonth = new Date(now.getFullYear(), now.getMonth() + 1, 0);

handler.downloadAsFile('monthly-calendar.ics', {
  dateRange: { start: startOfMonth, end: endOfMonth },
  calendarName: 'Monthly Export',
});

URL imports and external clients

importFromURL performs network requests, unlike pure parsing. Options include requestTimeout (30,000 ms), maxRedirects (5) and maxFileSize (parser default). Node validates DNS and redirect destinations; non-Node runtimes can follow redirects before final-response validation. Host egress/allowlisting remains necessary. See network limits.

subscribe() initially imports and can poll; retain its handle and call stop() during teardown. This is an in-process import helper, not a durable two-way provider sync service. An ICS file export/import is a snapshot, and all-day exclusive end dates need explicit conversion at an integration boundary.