Current section
Files
Jump to
Current section
Files
CHANGELOG.md
# Changelog
## 0.5.0 (2026-05-22)
### Breaking changes
- **`ExDav.CalDav.Plug` no longer handles `/.well-known/carddav`.**
Previously the CalDav plug claimed both `/.well-known/caldav` and
`/.well-known/carddav` and redirected each to its own configured
prefix — useful when the plug was the only DAV mount on a host, but
silently blocked the CardDav plug from doing its own redirect when
both plugs were mounted side-by-side. CalDav now claims only
`/.well-known/caldav`; CardDav already only claimed
`/.well-known/carddav`.
Migrate by mounting `ExDav.CardDav.Plug` alongside `ExDav.CalDav.Plug`
in your endpoint if you want `/.well-known/carddav` to redirect to a
CardDav root.
### New
- **`<cs:email-address-set>` on principal PROPFIND.** macOS Reminders
(`remindd`) polls the principal in a tight loop waiting for this
CalendarServer extension and never starts per-list task sync without
it. Now always emitted alongside `<C:calendar-user-address-set>`.
- **`<cs:created-by>` / `<cs:updated-by>` stubs on
calendar-multiget responses.** Apple's `remindd` silently drops
resources whose multiget response doesn't acknowledge these
CalendarServer extensions — empty elements are enough.
- **`%40`-encoded `@` in path segments and multiget hrefs is
decoded.** All RFC 3986-conforming CalDAV clients (Apple, Python
`caldav`, DAVx⁵) percent-encode `@` in URL path segments; the plug
now decodes both `path_info` and multiget request hrefs so
`user-1@host` and `user-1%40host` resolve to the same resource.
## 0.4.4 (2026-05-16)
### New
- **`:prefix` opt on `ExDav.CalDav.Plug` and `ExDav.CardDav.Plug`** —
controls the first path segment the plug claims (default `"dav"` for
backward compatibility). Set `prefix: "caldav"` (or `"carddav"`) when
you want autodiscovery and request URLs under `/caldav/...` rather
than `/dav/...`. Affects path matching, `.well-known/{caldav,carddav}`
redirect target, and all emitted `<href>` elements. Combines cleanly
with `conn.script_name` when mounted via `Phoenix.Router.forward`.
plug ExDav.CalDav.Plug,
prefix: "caldav",
storage: ...,
authenticator: ...
## 0.4.0 (2026-05-16)
### Breaking changes
**Storage behaviour renamed — all consumers must update their adapters.**
The `ExDav.Storage` behaviour has been generalised to serve both CalDAV
and CardDAV via a single `kind` parameter. Old CalDAV-specific callback
names are gone:
| Old (0.3.x) | New (0.4.0) |
|---|---|
| `list_calendars/1` | `list_collections/2` |
| `get_calendar/2` | `get_collection/3` |
| `get_calendar_with_objects/2` | `get_collection_with_resources/3` |
| `create_calendar/3` | `create_collection/4` |
| `update_calendar/3` | `update_collection/4` |
| `delete_calendar/2` | `delete_collection/3` |
| `get_object/3` | `get_resource/4` |
| `put_object/4` | `put_resource/5` |
| `delete_object/3` | `delete_resource/4` |
| `sync_changes/3` | `sync_changes/4` |
All new callbacks take `kind :: :calendar | :addressbook` as the second
argument after `username`.
**Collection type changed.** The `calendar` map type lost `components`
and `objects` top-level keys; they are now `properties` (a plain map,
`properties["components"]` for CalDAV) and `resources`.
**Resource type changed.** The `object` map type lost `ical` and
`component`; they are now `body` (the raw iCal or vCard string) and
`content_type`. The `component` field (VEVENT/VTODO) is no longer part
of the storage contract; adapters may carry it as an internal detail.
**Postgres schema renamed — consumers must run the upgrade migration.**
Run `mix ex_dav.gen.migration upgrade_to_0_4_0` in your consumer app,
then `mix ecto.migrate`. Tables renamed:
| Old | New |
|---|---|
| `caldav_calendars` | `dav_collections` |
| `caldav_calendar_objects` | `dav_resources` |
| `caldav_calendar_object_tombstones` | `dav_tombstones` |
Elixir schema modules renamed accordingly:
- `ExDav.Storage.Postgres.Schemas.Calendar` → `…Schemas.Collection`
- `ExDav.Storage.Postgres.Schemas.Object` → `…Schemas.Resource`
### New features
- **CardDAV plug** (`ExDav.CardDav.Plug`) — mirrors CalDAV plug structure
under `/addressbooks/…` paths. Implements RFC 6352: PROPFIND, MKCOL,
PROPPATCH, DELETE, GET, PUT, REPORT (addressbook-query,
addressbook-multiget, sync-collection).
- **vCard 4.0 codec** (`ExDav.VCard`) — parse, validate, serialize,
extract UID, compute ETag. vCard 3.0 is explicitly rejected.
- **Prefix-safe hrefs** — both CalDAV and CardDAV plugs prefix all
`<href>` elements with `conn.script_name`. Consumers can now mount
via `forward "/caldav", ExDav.CalDav.Plug, …` in their Phoenix router
and hrefs will include the `/caldav` prefix automatically.
- **Migration generator** — `mix ex_dav.gen.migration upgrade_to_0_4_0`
writes a reversible Ecto migration for the 0.3→0.4 schema changes.
### Unchanged
- `user_exists?/1` callback — no change.
- CalDAV URL space and XML wire format — identical to 0.3.x.
- `ExDav.ICal` helpers — no changes.
- `ExDav.Authenticator` behaviour — no changes.