← All Addons

Calendar

library

Calendar

Library for generating an iCalendar (RFC 5545) feed from a list of notes, and serving it as an HTTP response. Combines the best of two prior implementations (the legacy Calendar addon's direct-search + customRequestHandler-served approach, and libagendaoverview@beatlink's richer profile-driven task list) into one deduplicated core: this library doesn't search for notes or know what a "profile" is — it just turns an already-resolved note list into an ics string, and knows how to send that string back as a proper HTTP response. Depends on libical@kewisch.

generateCalendar is pure (no environment-specific API calls) and genuinely needed from both a frontend script (libagendaoverview@beatlink, which uses it directly instead of duplicating its own ical-building loop) and a backend customRequestHandler (simplecalendar@beatlink). Trilium's bundler only lets a note require() another note of the same environment though — there's no environment-agnostic note type — so this library ships two exports built from the identical libCalendar.js source file (no source duplication, just note duplication, which is unavoidable):

Export env Depends on libical@kewisch's
lib frontend lib (frontend) export
backend backend backend export

respondWithCalendar only makes sense called from the backend export (it uses api.res), but it being defined-and-unused in the lib (frontend) export is harmless — nothing there calls it.

Usage

Install as a dependency and clone whichever export matches your own note's environment as a child:

const { generateCalendar, respondWithCalendar } = require("libCalendar.js")

if (api.req.method === "GET") {
    const notes = api.searchForNotes(searchQuery)
    const icalString = generateCalendar(notes, { startDateLabel, dueDateLabel })
    respondWithCalendar(api, icalString)
} else {
    api.res.send(400)
}

Wiring up the actual endpoint — the customRequestHandler label, the request method check, any auth — is entirely the calling script's responsibility; this library has no opinion on any of that.

API

generateCalendar(notes, options)

Pure function — no note mutation, no HTTP. Builds an ics string from notes (an array of already-resolved note objects — this library doesn't search or resolve ids itself). Only notes with both a start and due date produce a VEVENT; a note's recurrence label value (if present) becomes that event's RRULE.

options:

Key Required Description
startDateLabel yes Label name holding each note's start datetime
dueDateLabel yes Label name holding each note's due datetime
recurrenceLabel no Label name holding an RRULE string (default "recurrence")
prodId no iCalendar PRODID value (default -//Beatlink/Trilium Calendar Script)

respondWithCalendar(api, icalString)

Sets the correct Content-Type and sends icalString as the HTTP response body, given the api object a customRequestHandler script receives (api.req/api.res).

Why no "save to a note" function

Both prior implementations wrote the generated ics to a note's content first, then served that note (a customResourceProvider-style static-file round trip). Since a customRequestHandler can just generate-and-serve fresh data on every request, that round trip isn't needed — if a caller also wants the ics content persisted somewhere (e.g. for manual viewing inside Trilium), that's one line (api.getNote(id).setContent(icalString)) and not worth a wrapper function here.