Helpers

The fetch client, error mapping, options parsing, time zone and recurrence helpers in @cal-sdk/provider-utils.

Most of a provider is the same few chores: authenticated JSON requests, mapping HTTP errors, time zone arithmetic and recurrence rules. @cal-sdk/provider-utils holds the helpers the official providers use for them, so you can skip the parts that are easy to get subtly wrong.

npm install @cal-sdk/provider-utils

Requests

ExportWhat it does
createJsonFetcher({ baseURL, accessToken, headers?, fetch? })A JSON client. Sends Authorization: Bearer, resolving the token per request; validates responses with a schema; throws APICallError for non-2xx responses and network failures; never follows redirects
urlPathA template tag that percent-encodes every value: urlPath`/calendars/${id}/events`
mapAPICallError(error, { provider, resource?, eventId? })Turns 401 into AuthenticationError, 403 into PermissionDeniedError, 404 and 410 into NotFoundError (given resource), 412 into ConflictError (given eventId) and 429 into RateLimitError. Other errors pass through unchanged
parseRetryAfterMs(headers)Reads Retry-After as milliseconds
combineHeaders, withUserAgentSuffixMerge header objects, and add your provider to the user agent

Options and schemas

ExportWhat it does
parseProviderOptions({ provider, providerOptions, schema })Reads your key from providerOptions. Throws InvalidArgumentError for wrong values, warns about unknown keys
validateSchema(schema, value)Validates with any Standard Schema library, such as zod
formatSchemaIssues(issues)A readable message from schema issues

Time

ExportWhat it does
isAllDay(time)Whether an EventTime is all-day
eventTimeToInstant(time, allDayTimeZone?)Epoch milliseconds for an EventTime. All-day dates are read in allDayTimeZone, UTC by default
addDaysToDate(date, days)Adds days to a 'YYYY-MM-DD' date
formatZonedDateTime(instant, zone)An ISO 8601 date-time with the zone's offset, such as '2026-11-09T09:30:00-05:00'
localToInstant, instantToLocal, parseLocalDateTime, formatLocalDateTime, formatLocalDateConvert between wall-clock times in a zone and instants
getTimeZoneOffset(instant, zone)A zone's offset at an instant
isValidTimeZone(zone)Whether a string is an IANA zone
windowsToIana, ianaToWindowsConvert Windows zone names, as Outlook uses them

Recurrence

ExportWhat it does
parseRecurrence(lines)Splits RFC 5545 lines into the rule, EXDATEs and RDATEs. Throws InvalidArgumentError for malformed lines
parseRRule, formatRRuleRead and write one RRULE as an object
parseICalDate, formatICalDate, instantToICalDate, instantToICalDateOnlyiCalendar date and date-time values
formatExdates, formatRdatesBuild EXDATE and RDATE lines
WEEKDAYS['SU', 'MO', 'TU', 'WE', 'TH', 'FR', 'SA']

Each function's doc comment in the package has its exact signature.

On this page