unical library
unical — one resilient API over device calendars and CalDAV for events and tasks with progress.
The core is pure Dart. Bring a CalendarBackend (see unical_caldav and
unical_flutter), wrap it in a SyncEngine, and drive it through the
fail-safe UnicalClient. The engine picks the best MetadataStrategy the
backend can honor — native VTODO, invisible X- properties, an opt-in
description block, or drift-only — so task metadata never gets lost even on
servers that cannot store tasks.
Classes
- CalendarBackend
-
A pluggable calendar backend. Implementations wrap
caldav,device_calendar_plus, or an in-memory fake. All methods may throw; the fail-safe wrapping lives inUnicalClient, not here. - Capabilities
-
What a concrete backend can actually preserve. Drives the choice of
metadata strategy (see
MetadataStrategy.select). - DescriptionCodec
-
Last-resort, user-visible smuggling channel: a delimited block appended to
the event
DESCRIPTION. Only this survives servers that strip everything else (Google via CalDAV, device calendars). It is validated to survive iCalendar 75-octet line folding, CRLF/LF changes, user edits of the human text and corrupted payloads (which degrade tonullwithout losing text). - Ical
-
Minimal iCalendar (RFC 5545) text helpers shared by the codecs and by
backend adapters that manipulate raw
.icspayloads. - InMemoryBackend
-
An in-memory CalendarBackend that faithfully simulates a real server's
lossiness according to its Capabilities: it strips
X-properties whenpreservesXPropsis false, drops categories whensupportsCategoriesis false, and rejects task operations whensupportsVtodois false. Ideal for tests and as the canonical reference implementation. - InMemoryMappingStore
- A simple in-memory MappingStore.
- Mapping
- A single caller-id → backend-ref mapping, the anchor that lets a sync re-identify its own objects and avoid duplicates.
- MappingStore
- Persistence seam for Mappings. Implement over Drift in an app; an in-memory implementation ships for tests and ephemeral use.
-
Outcome<
T> - A fail-safe result: either a value or an error, never both. Mirrors the "never throw across the boundary" philosophy of the app's other service wrappers so calendar hiccups can never crash the caller.
- ParsedDescription
- Result of splitting an event description into its human part and (maybe) the embedded task metadata.
- RemoteEvent
-
An event as returned by a backend: the domain event plus the transport
details needed to reconcile it — the backend ref (id or href), any custom
X-properties preserved by the server, and the change etag. - RemoteTask
-
A native
VTODOtask as returned by a task-capable backend. - SyncEngine
- Orchestrates pushing/pulling tasks and events through a CalendarBackend, choosing the best MetadataStrategy the backend can honor and keeping the MappingStore in sync. Never mutates the caller's store — it returns reconstructed objects and the caller decides what to persist.
- TaskMeta
-
The task-only metadata that a plain
VEVENTcannot represent natively and that must therefore be smuggled (via X- properties, or as a last resort a description block) when a task is projected onto an event. - UnicalClient
- Fail-safe facade over SyncEngine. Every method swallows exceptions and enforces a timeout, returning an Outcome instead of throwing.
- UnicalEvent
-
A calendar event — a block of time (
VEVENT). In Stabilitas terms, the period in which the labor is done. - UnicalTask
-
A task with a completion percentage — the "minor/minima" of the caller's
domain. Maps to an iCalendar
VTODOwhere the backend supports it, and to a projectedVEVENT(plus smuggled metadata) where it does not. - XPropCodec
-
Encodes TaskMeta as invisible
X-STABILITAS-*iCalendar properties and decodes them back. This is the preferred smuggling channel: the properties never show up in a calendar client's UI. It only works on servers that preserve customX-properties on round-trip (generic CalDAV) — Google and device calendars strip them, which is whyMetadataStrategygates its use.
Enums
- MetadataStrategy
-
How a task's extra metadata (percent, tags, identity) is carried on the
calendar side. Ordered best → worst;
selectwalks the ladder. - TaskStatus
-
Lifecycle status of a task, mirroring the iCalendar
STATUSvalues that aVTODOaccepts (RFC 5545 §3.8.1.11). - Winner
- Which side wins when the same object changed locally and remotely.