Skip to content

fix(calendar): read CDATA timezone and description - #45

Merged
PhilflowIO merged 2 commits into
mainfrom
fix/calendar-timezone-cdata
Oct 9, 2026
Merged

PhilflowIO merged 2 commits into
mainfrom
fix/calendar-timezone-cdata

Conversation

@PhilflowIO

Copy link
Copy Markdown
Owner

What

fetchCalendars now reads calendar-timezone and calendar-description through getDAVText, the same helper already used for displayName, ctag and syncToken.

Why

Both values were kept only when xml-js returned a plain string. A server that sends the VCALENDAR inside CDATA (<c:calendar-timezone><![CDATA[BEGIN:VCALENDAR...]]></c:calendar-timezone>) produces { _cdata: "..." }, so the timezone came back as "" without any error. Missing or empty values still return "".

Tests

New unit tests in src/__tests__/unit/calendar.test.ts cover plain text, CDATA, _text and missing values. The CDATA and _text cases failed before the fix. pnpm test (430 passed), pnpm typecheck and pnpm lint are green.

Closes #44

fetchCalendars kept calendar-timezone and calendar-description only
when xml-js returned a plain string. Servers that wrap the value in
CDATA produce { _cdata } (or { _text }), so the timezone was silently
returned as "". Use getDAVText, which displayName, ctag and syncToken
already use, so every text shape is read the same way.

Closes #44
PhilflowIO added a commit to PhilflowIO/dav-mcp that referenced this pull request Oct 9, 2026
Review of #135 found that the calendar-timezone property was read as if it
were always present, small and well-formed, and that some writes could be
stored an hour off without saying so.

Reading: every value goes through one reader (calendar-zone.js), whatever
form tsdav hands it in. tsdav up to 2.4 drops a CDATA calendar-timezone
from `timezone` (fixed in PhilflowIO/tsdav#45), so fetchCalendars now
projects the raw property and the listing tools, create_event and the
update_calendar read-back read the same value the PROPFIND paths do. The
value is capped at 64 KB (4.5 MB of RDATE lines took 4.5 s), parsed
through the parameter guard of ical-parse.js, and its parse is cached by
text, like the zones built from it. A VTIMEZONE without rules is read by
its IANA name instead of as UTC.

Failures: a lookup that fails (no answer, an error status, an unreadable
value) is no longer a silent fallback. A read goes ahead in dav-mcp's zone
and says so in a note; a write that needs the zone is refused, since a
floating series moved with Z, or a time without a zone, would otherwise
land on dav-mcp's clock unsaid. A calendar without the property, or a 404,
still simply has no zone.

DST: a write that the zone's clock change makes impossible or ambiguous is
refused with what to give instead: a local time the spring change skips,
one the autumn change shows twice given without an offset, and an instant
in the second pass of that hour for an event stored without a zone (it
would read back as the first, or the event shorter).

Also: every IANA zone can be set; Africa/Monrovia, on local mean time
until 1972, made generateVtimezone throw an internal error, so its
VTIMEZONE starts at the first year that can be written (all 418 zones
Intl knows checked once). update_calendar reports a calendar missing from
the listing as not found. The "no occurrence falls inside" note could no
longer be reached since the tools filter ranges themselves, so it goes.

Refs #78, #117, #128

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
…-cdata

# Conflicts:
#	dist/tsdav.min.cjs
#	dist/tsdav.min.js
#	dist/tsdav.min.mjs
@PhilflowIO
PhilflowIO merged commit 0eb5376 into main Oct 9, 2026
8 checks passed
@PhilflowIO
PhilflowIO deleted the fix/calendar-timezone-cdata branch October 9, 2026 09:26
@PhilflowIO PhilflowIO mentioned this pull request Oct 9, 2026

This branch was successfully deployed

1 active deployment
Production — 01e3777f Deployed Oct 9, 2026 by PhilflowIO via automated-test (22) #29
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

fetchCalendars drops calendar-timezone and description sent as CDATA

1 participant