- fixed case-insensitive header merging across object, tuple, and
Headersinputs so per-call overrides no longer discard client authentication or required request headers - fixed OAuth token requests ignoring client-level
fetchOptions, and prevented generic fetch options from replacing required DAV methods and request bodies - fixed DAV XML handling for bodyless requests, mixed-case XML content types, missing response status lines, and failed
propstatentries - fixed undefined ETags becoming the literal string
"undefined"and prevented unsafe integers from being coerced while parsing DAV XML values - fixed DAV resource comparisons for relative URLs, trailing slashes, query strings, and similarly prefixed resource names
- fixed calendar and collection sync losing unchanged local objects, using stale or missing sync state, and silently continuing without required fetch callbacks
- fixed CalDAV/CardDAV multi-get requests dropping resource query strings
- fixed invalid or reversed time ranges and empty free-busy responses returning misleading results
- fixed native ESM package exports and expanded the default test scripts to include utility tests
- fixed the Node.js 18 CI job to validate the packed runtime instead of invoking Node.js 20-only build and test tooling
- fixed CI and release jobs declaring conflicting pnpm versions after the repository began pinning an exact
packageManager
- upgraded compatible test, build, type, React, and Docusaurus dependencies to their latest safe releases
- isolated the documentation package as its own pnpm workspace so installs, audits, and lockfile checks consistently target the docs dependency graph
- enabled CI for direct
mainpushes so release commits are verified before publication - added regression tests for request handling, authentication, URL normalization, XML parsing, collection sync, calendar sync, and package entry points
- refreshed and constrained vulnerable documentation transitive dependencies; root and documentation production audits now report no known vulnerabilities
- replaced the Rollup package build with Rolldown while preserving the existing public output filenames and package export map
- kept the published library runtime support at Node.js >=18; building release artifacts from source now requires a Rolldown-supported Node.js version
- reduced generated browser bundle size by relying on Rolldown's browser build instead of broad Node polyfill injection
- removed the
base-64dependency and kept Basic auth encoding portable across Node.js, browsers, Bun, Deno, and Workers - switched linting to Biome and tightened test/lint coverage for the source tree
- updated runtime usage docs and routed the docs homepage directly to the maintained introduction page
- fixed the Apple/iCloud integration assertion for invalid CalDAV
timeRangevalidation so the expected rejection is tested correctly
- added
syncCalendarsDetailedandsmartCollectionSyncDetailedas explicit detailed-result APIs - deprecated
detailedResultin favor of the new detailed sync functions while preserving backward-compatible overloads
- fixed
fetchCalendarsrejecting calendar collections when servers omit or return an emptysupported-calendar-component-set(Purelymail compatibility)
- first-class support for Bun and Deno in addition to Node.js (>= 18), modern browsers, and Cloudflare Workers
- added package
exportsmap withbrowser,deno,bun,worker,import,require, anddefaultconditions so each runtime picks the correct bundle automatically - added dedicated Bun and Deno smoke-test jobs to CI to guard both runtimes against regressions
- added Bun and Deno usage guides to the docs
- dropped the
cross-fetchruntime dependency. tsdav now uses the standards-compliantfetchexposed by every supported runtime (Node.js >= 18, browsers, Bun, Deno, Cloudflare Workers, Electron). Hosts without a globalfetchmust install a polyfill onglobalThisbefore importing tsdav, or pass a customfetchtocreateDAVClient/DAVClient/ individual request helpers. Node < 18 is no longer supported (already documented inengines.node, now enforced at the code level). - added
exportsfield topackage.json. Deep subpath imports likeimport 'tsdav/dist/tsdav.esm.js'are no longer allowed; use the package root (import ... from 'tsdav') instead.
- fixed
syncCalendarsdropping genuinely unchanged calendars from the non-detailedResultreturn;unchangedis now selected by matching sync-token/ctag instead of the inverted comparison - fixed
fetchCalendarUserAddressesreturning[]when the server responded with a single<href>element instead of an array - fixed
fetchCalendars/fetchAddressBookscrashing on servers that omitresourcetypeor return a single<comp>element (Object.keys(undefined)/ bad dereference) - fixed
fetchHomeUrlthrowing an opaqueTypeErrorwhen the server returned an empty<calendar-home-set/>or<addressbook-home-set/>; emits a descriptive error instead - fixed service discovery silently downgrading explicit
https://redirects tohttp://when the origin was http; schemeless/relative redirects still inherit the endpoint's protocol - fixed service discovery's
redirect: 'manual',method,headers, andbodybeing silently overridable by user-suppliedfetchOptions - fixed
davRequestcrashing on non-multistatus XML responses (e.g. CalDAV<error>reports) withCannot read properties of undefined (reading 'response') - fixed
davRequestmergingContent-Typecase-insensitively so a user-suppliedcontent-typeno longer coexists with the library'sContent-Type - fixed
davRequest's per-responseokflag: now derived from the parsed HTTP status (RFC 4918 propstat), not from presence of an<error/>element (which matched empty error stubs) - fixed
davRequestcapping therawfield on non-XML responses so oversized HTML error pages don't bloat thrown error messages or logs - fixed
excludeHeaderscomparing header names case-sensitively; HTTP headers are case-insensitive soAuthorizationandauthorizationare now treated as the same entry - fixed
nativeTypecoercing empty strings, whitespace, and leading-zero tokens (e.g."0123") to numbers, which corrupted sync-tokens, etags, and ctags parsed from XML - fixed
camelCaseleaking stray separators on consecutive-/_runs (foo--barnow producesfooBar) - fixed
urlEqualsusing a brittle bidirectional-includeswith a length guard; now a strict trim + single-trailing-slash normalization - fixed
smartCollectionSync(basicmode) wasting afetchObjectscall when the collection wasn't dirty; now short-circuits onisDirty === false - fixed
syncCalendars'sdetailedResult: truereturning the bareupdatedcalendar list without the fetched objects; both result shapes now return calendars with objects populated viasmartCollectionSync - fixed
createDAVClient(factory) silently ignoringfetchOptions; parameter added and threaded to every sub-helper - fixed
DAVClient#davRequestdropping the per-callfetchOptionsin favor ofthis.fetchOptions - fixed OAuth flows never persisting refreshed
accessToken/ rotatedrefreshToken/ newexpirationback onto the credentials object, causing repeat refreshes and stale rotating refresh tokens (Google) - fixed OAuth headers returning
Bearer undefinedwhen the in-memoryaccessTokenwas still valid; the existing token is now reused - fixed
authMethod: 'Custom'silently authenticating with no headers whenauthFunctionwas omitted; now throws a clear error
- stopped logging the base64 basic-auth token and the OAuth access token under
DEBUG=tsdav:*; debug output now references the username / emits status codes only
- removed several
as anycasts fromDAVClient/createDAVClientsofetchandfetchOptionsare properly typed (typeof globalThis.fetch/RequestInit) DAVClient#loginnow accepts{ loadCollections, loadObjects }to pre-populate the default account in one callcreateAccount(factory and class) now validatesaccountTypeat runtime and throws a clear error when both the passed account anddefaultAccountTypeare missing itfetchVCardsdefaulturlFilternow returnsbooleaninstead of the url string- added
fetch?toDAVCollection.objectMultiGettype so custom transports can be threaded throughsmartCollectionSync - added docusaurus-plugin-llms for LLM-friendly documentation
- updated docs for LLM discoverability
- fixed Vercel deployment configuration
- fixed markdown integration for docs deployment
- fixed #272 malformed expand request in fetchCalendarObjects
- optimized fetchCalendarObjects to reduce redundant requests when expand is true
- added Bearer auth support for token-based providers (e.g., Nextcloud OIDC)
- added fetch overrides across account, request, and collection helpers for custom transports
- prefer native fetch in Cloudflare Workers to avoid cross-fetch incompatibilities
- collectionQuery now rejects on non-OK responses instead of returning empty arrays
- fetchVCards filters out collection URLs to avoid empty/invalid entries (Radicale-compatible)
- docs updates for iCal feed import, providers, and custom transport guidance
- docs: add browser usage example and clarify class-based login
- docs: add Nextcloud connection guidance and Apple password reference
- added AGENTS.md
- updated dependencies
- fixed docs build issues
- fixed #251 thanks to @titanism
- logging improvements
features
- now exports addressBookMultiGet thanks to @lepirlouit
- fixed #244 cannot read properties of undefined (reading 'comp')
- fixed #238 which blocked icloud principal calendar fetching.
features
- new function
fetchCalendarUserAddressesthanks to @pierreliefauche - new type
calendarColoronDAVCalendar
- fetch updates, now use polyfill mode
- updated dependencies
- doc update by community
features
new option fetchOptions on all possible functions, allow customizing fetch options
- updated docs
- updated dependencies
- fixed #201 where
client.smartCollectionSynchave incorrect type - fixed #200 where
syncCalendarsincorrectly mark calendars as updated due to type mismatch - updated docs
- updated dependencies
- use pnpm instead of yarn for package manager
potential breaking changes
- typescript target changed to
es2018due to named capturing groups errors
improvements
- fixed #191 where
authFunctionis not properly assigned in constructor. - updated deps.
improvements
- fixed #181 where a null check is missing.
- fixed doc example, thanks to #175
- added docs related to smart calendar syncing #138
improvements
etag of DAVObject is now optional fixing #158
features
new option headersToExclude on all possible functions, allow precise control on request headers, fixing #166
improvements updated dependencies
improvements
updated dependencies, fixing #159
features
DAVClient supports digest auth and custom auth, please go to authHelpers page in docs for more details.
fetchCalendars now supports projectedProps, previously customProps passed in will not get projected to fetched result properly.
with this object map you can map your custom prop to fetched result thanks to @m0dch3n
improvements
calendarMultiGet will not send <filter/> element if custom filters are null or undefined thanks to @jelmer
docs improvement thanks to @MathisFrenais
typescript type improvement thanks to @zomars
features
- new option
useMultiGetforfetchCalendarObjectsandfetchVCardswhich controls the underlying fetching function to better support fetching from providers which does not supportmultiGetfunctions
improvements
- improved documentation
- improved typescript types
- updated deps
- added
.mjs,.cjs,.min.mjsand.min.cjsversions
improvements
- added support for davical
- fixed a bug related to expand #116
- updated deps
improvements
- fixed dependency issues #103
- updated deps
improvements
- Add missing attribute to makeCalendar method #93, Thanks to @nibdo
- updated dependencies
features
etagparam onupdateObjectis now optional, since some caldav servers will throw error if we useIf-Matchheaders.
improvements
- fixed collection query not handling empty result properly.
createObjectrequests now sendIf-None-Match:*to avoid accidental overwrite.depthheader and others are now able be to overwritten by user specified headers.- tested with zoho
- fixed
urlFilternot really filtering the urls, only filtering on pathname of urls. - fixed a bug where fetching on empty calendars/addressBooks returning calendar/addressBook itself as result.
improvements
- fixed wrong namespace issue
- fixed a bug where supportedReportSet was using incorrect depth, which resulted more data fetched than needed.
- added tests for supportedReportSet
docs
- added doc for freeBusyQuery
improvements
- fixed wrong namespace issue
breaking
- removed
DAVFilterandDAVProp, now all function usesElementCompactas prop and filter directly generated fromxml-jsinstead. - removed related
formatProp,formatFilterandmergeObjectDupKeyArrayfunction since they are not needed (These functions were marked as internal so they really shouldn't be causing breaking change). - removed
DAVNamespaceShorthandMapand addedDAVNamespaceShortas a replacement. - renamed parameter
vCardUrlFilterof functionfetchVCardstourlFilterfor consistent naming. - collectionQuery now accepts
DAVNamespaceShortinstead ofDAVNamespace.
features
- added
freeBusyQueryfor CALDAV, note this feature is not working with many caldav providers. - added
expandforfetchCalendarObjectsso it can now. - added
propandfilteroverriding feature to functions where overriding is possible.
improvements
- now fetchCalendar fetch
calendarColorby default.
docs
- added a helper to convert
xmlbetween tsdav compatiblejsobjects. - added migration helper to help convert old
DAVPropandDAVFilterinto newElementCompact. - fixed theming issues to create a more consistent light theme.
- added sitemap for docs for better seo.
- archived version 1.x docs.
improvements
- Added
vCardUrlFiltertofetchVCardsto allow vCard Urls to be filtered before fetching - tested with baikal
improvements
- fixed import error when using with node
- tested with nextcloud
features
Added fastmail cloud providers support.
improvements
- Fixed a bug which prevents calendar objects from being fetched.
- Fixed a bug which prevents display name of calendars from being fetched.
improvements
- Fixed esm and browser support problems #19
- Added rollup as bundler to allow CDN support #32
- dist builds are now committed and now comes with four versions:
tsdav.cjs.jscommonjs version which can be used with node 10 or later.tsdav.esm.jsesm version which can be used in pure esm packages with node 12 or later.tsdav.jsversion which can be used in both browser and node, contains polyfills and with dependencies bundled in, which makes the file size larger.tsdav.min.jsminified version oftsdav.js.
improvements
- Fixed a bug which prevents from addressBookMultiGet working #18
- Fixed supportedReportSet undefined error
- ctag obtained from isCollectionDirty should now correctly be string instead of number
- updated all dependencies
- tests are now restructured to integration and unit tests, allowing much better extensibility.
- test requests are now mocked, allowing testing the whole stack without external dependencies
- fixed multiple errors in documentation
improvements
- Fixed spread params for new way of creating dav client, thanks to @molaux
- Ensure service discovery redirect maintains the proper port, thanks to @n8io
- Fixed a time range issue with new time range format
breaking changes
DAVClientis no longer a type returned bycreateDAVClient, instead it's a class that can be instantiated.timeRangeinfetchCalendarObjectsis now validated againstISO_8601standard and invalid format will throw an error.- typescript target changed to
es2015, if you are onnode >= 10andbrowsers that are not IE and have been updated since 2015, you should be fine. support fores5output is not possible with addedesmsupport.
features
- added a new way to create
DAVClientbynew DAVClient(...params). - added support for
esm.
- typescript checks are now with
strictenabled, which means better types and less bugs. - added more exports, now all internal functions are exported.
- multiple documentation improvements.
Fixed a bug where timeRange filter sometimes might be in the wrong format.
Fixed a bug where calendar objects with http in its id would cause operations on it to fail.