Third release. 43 commits since 0.2.0, and almost all of them are one thing: heyflare has a calendar.
Calendar
Modelled on HEY's, which does not draw an hour grid and stack boxes in it. Five migrations (0011–0015) apply themselves on first run; nothing existing is touched.
- Three views, no month. Week is seven columns that stack vertically and scroll, so a fortnight is a scroll rather than a click. Day runs horizontally — the day is a strip you read left to right, titles turned on their side like books on a shelf. Year is a weekday-aligned ribbon.
- Night is drawn, not hidden. The hours you sleep are compressed into a starry band, so the part of the day you actually use gets the room. Free time is drawn to scale and stamped.
- Day photos — a cover image behind a day, at full strength with no scrim; blocks over it keep a white keyline.
- Google Calendar, calendar-only. Connect an account for calendar without granting mail scope, and manage each connection separately. Calendars are listed under the account they came from, each with a checkbox, a colour and a default. Imported palettes are muted to one band, because these blocks are filled solid rather than drawn as pale chips.
- Subscribe by URL (ICS), with RRULE expansion that keeps wall-clock time across daylight saving.
- Drag to move and resize, in both the week and the day, with quarter-hour snapping. A press under 4px is still a click.
- Circle an event in dark ink, the way you would on paper. Duplicate an event. Habits, journal and flexible tasks.
- Week view has an Apple-style hour gutter and rules — a deliberate departure from HEY, because a seven-day column needs the reference.
- Arrow keys move within the calendar; ← and → hand focus to the sidebar and the assistant. The calendar always opens on today.
iOS app
apps/ios — Tauri 2, same shape as the Mac app.
Fixed
- Custom-domain sending was broken outright on the Cloudflare path. Every message set its own
Message-ID, which Cloudflare generates itself and rejects — refusing the whole send rather than dropping the header. No fork with the binding configured could send anything. Only allowlisted headers are sent now, threading kept, and a refusal reports Cloudflare's own reason instead of failing mutely. - Moving an event could quietly undo itself. The update to Google was a
PUT, which replaces the whole event; without aneventTypein the payload, birthdays, holidays and working-location entries were rejected. The failure was swallowed, so the next sync pulled the old copy back a minute later. Now aPATCH, and a refusal puts the row back at once and says why. - Deleting a repeating Google event removed one occurrence. Google's expansion stores each occurrence as its own row with no rule tying them together, so "all events" had no series to act on — and the scope dialog never appeared. Instances are now matched by their shared iCalUID.
- Short events covered the ones after them. A block is never drawn shorter than 22px, which in the week is 69 minutes; the column layout reserved 15 and saw no conflict. It now reserves what is actually drawn.
- The assistant input stayed one line. It sized itself by counting newlines, so a long message with no break in it wrapped out of sight. It now measures what the browser actually rendered.
Under the hood
D1 writes were roughly 125,000 a day against a 100,000 free-tier cap, most of it recording that nothing had changed. An idle cron tick now writes nothing at all: status, sync tokens and timestamps are persisted when something actually changed, when a calendar recovers from an error, or every ten minutes. Calendars you have unchecked sync every six hours instead of every minute — the visibility flag had never been consulted. Counting events per calendar no longer scans every event you own on each page load.
Notes
- Mac app: the DMG is ad-hoc signed (not notarized), so macOS may say "heyflare is damaged" after downloading. Clear the quarantine flag once:
xattr -dr com.apple.quarantine /Applications/heyflare.app
- Calendar sending/Google: connecting a calendar needs the Google Calendar API enabled on your Cloud project; the app now says so with a link rather than showing an empty list.
- Updating a self-hosted server never touches your data:
npx create-heyflare deployorgit pull && npm run deploy. Migrations apply themselves.