Calendar (JSCalendar)
JSCalendar (RFC 8984) primitive. Wraps the framework's existing b.safeIcal.parse (RFC 5545 grammar + bounded parser) with the JSON-native JSCalendar surface JMAP Calendars (RFC 8984 / draft- ietf-jmap-calendars) requires for cross-protocol interop.
Scope: - validate(jsCal) — assert JSCalendar Event / Task / Note / Group shape (RFC 8984 §5 / §6 / §1.4.4). - fromIcal(text, opts?) — VCALENDAR.VEVENT → Event, VTODO → Task, VJOURNAL → Note. Mixed-component VCALENDARs return an array. - toIcal(jsCal, opts?) — Event → VEVENT, Task → VTODO, Note → VJOURNAL. Group emits a single VCALENDAR wrapping every entry's component. - expandRecurrence(event, { from, to, max }) — RRULE expansion for FREQ=DAILY/WEEKLY/MONTHLY/YEARLY with UNTIL/COUNT/INTERVAL and BYDAY/BYMONTH/BYMONTHDAY/BYWEEKNO/BYYEARDAY/BYHOUR/ BYMINUTE/BYSECOND/BYSETPOS. Multiple recurrenceRules expand independently and UNION per RFC 8984 §4.3.2.
Deferred-with-condition (no operator demand yet): - RFC 7529 non-Gregorian calendars. - Floating-timezone resolution against IANA TZDB.
b.calendar.validate(jsCal) #
Validate a JSCalendar Event / Task / Note / Group object's required-field shape per RFC 8984 §5 (Event) / §6 (Task) / §7 (Note) / §1.4.4 (Group). Returns the input on success; throws CalendarError on refusal with a .code naming the specific shape rule that failed.
b.calendar.validate({
"@type": "Event",
uid: "0e612e8b-1c4f-4e30-8e6a-4adc4e8b1c4f",
updated: "2026-05-21T10:00:00Z",
title: "Sprint planning",
start: "2026-05-22T09:00:00",
duration: "PT1H",
timeZone: "America/Los_Angeles",
});
b.calendar.fromIcal(text, opts?) #
{
safeIcalOpts: object, // forwarded to b.safeIcal.parse (caps, allowExperimental, etc.)
}
Parse iCalendar text (RFC 5545) via b.safeIcal.parse and map each VEVENT → JSCalendar Event, VTODO → Task, and VJOURNAL → Note (RFC 8984 §5 / §6 / §7). Returns a single object when the VCALENDAR holds exactly one component, or an array across all components when there are several.
b.calendar.fromIcal(
"BEGIN:VCALENDAR\\r\\nVERSION:2.0\\r\\n" +
"BEGIN:VEVENT\\r\\nUID:a@b\\r\\nDTSTAMP:20260521T100000Z\\r\\n" +
"DTSTART:20260522T090000Z\\r\\nDURATION:PT1H\\r\\n" +
"SUMMARY:Sprint\\r\\nEND:VEVENT\\r\\nEND:VCALENDAR\\r\\n");
// → { "@type":"Event", uid:"a@b", updated:"2026-05-21T10:00:00Z", ... }
b.calendar.toIcal(jsCal, opts?) #
{
prodid: string, // PRODID value to emit; default "-//blamejs//Calendar//EN"
}
Render a JSCalendar object back to RFC 5545 iCalendar text — Event → VEVENT, Task → VTODO, Note → VJOURNAL, and a Group to a VCALENDAR carrying each member component. Returns a CRLF-terminated string wrapped in a BEGIN:VCALENDAR / VERSION:2.0 / PRODID:-//blamejs//Calendar//EN / … / END:VCALENDAR envelope per RFC 5545 §3.4.
b.calendar.toIcal({
"@type": "Event",
uid: "a@b",
updated: "2026-05-21T10:00:00Z",
title: "Sprint",
start: "2026-05-22T09:00:00",
duration: "PT1H",
});
b.calendar.expandRecurrence(event, opts) #
{
from: string, // ISO 8601 UTC timestamp — lower bound of expansion window
to: string, // ISO 8601 UTC timestamp — upper bound (window <= 10 years)
max: number, // instance-count cap (default 4096; never exceeds MAX_EXPAND_INSTANCES)
}
Expand a JSCalendar Event's recurrenceRules into concrete start timestamps in the operator's [from, to] window. Returns an array of ISO 8601 UTC strings (yyyy-mm-ddTHH:MM:SSZ). Bounded by MAX_EXPAND_INSTANCES (4096) + MAX_EXPAND_SPAN_MS (10 years) to defend against the RRULE recurrence-bomb expansion class.
v1 supports FREQ=DAILY/WEEKLY/MONTHLY/YEARLY with INTERVAL, COUNT, UNTIL. BYDAY / BYMONTH / BYMONTHDAY / BYWEEKNO / BYYEARDAY / BYHOUR / BYMINUTE / BYSECOND refine the base frequency. BYSETPOS picks the Nth candidate from the BY*-filtered set within a FREQ interval (positive = 1-indexed from start, negative = from end); supported for FREQ=MONTHLY / YEARLY / WEEKLY with day-granularity candidates (time-of-day inherited from start). Multiple recurrenceRules are expanded independently and UNIONed; per RFC 8984 §4.3.2 each rule's count cap applies per-rule, not to the combined set. (RFC 7529 non-Gregorian calendars not in scope.)
b.calendar.expandRecurrence(
{ "@type": "Event", uid: "x", updated: "2026-05-21T10:00:00Z",
start: "2026-05-22T09:00:00",
recurrenceRules: [{ "@type": "RecurrenceRule", frequency: "daily", count: 5 }] },
{ from: "2026-05-22T00:00:00Z", to: "2026-06-01T00:00:00Z" });
// → ["2026-05-22T09:00:00Z", "2026-05-23T09:00:00Z", ..., "2026-05-26T09:00:00Z"]
Last updated 2026-08-08T16:39:49.652Z by seeder.