develop #1

Merged
marti merged 18 commits from develop into main 2026-09-26 12:43:56 +02:00
Owner
No description provided.
The '~/.n8n' tree was a developer's local custom-nodes install committed by
accident; it is not part of the package.

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
Follows the official n8n-nodes-starter: n8n-node build/lint/dev, eslint 9
flat config with the community-nodes rules, prettier, TypeScript 5.9 and
n8n-workflow 2. Gulp and the legacy index.js are gone; n8n finds the node
through the "n8n" field of package.json.

The package is renamed to @m4rti21/n8n-nodes-caldav and restarts at 0.1.0.

The mocha files asserted `true` and exercised nothing, so they are replaced
by a vitest runner with unit and integration projects and one test that
loads the built package the way n8n does. Strict mode is off because the
tests need Node globals the n8n Cloud rules forbid; the override is scoped
to test/ and the node code keeps every rule.

The old node gets the three fixes it needs to compile against n8n-workflow 2.
It still fails the no-runtime-dependencies lint on `dav`, which the rewrite
that follows removes.

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
Three ways in, none of them required:
- `nix develop` brings Node 24, Radicale, graft and the formatter, and
  installs the git hooks npm is not allowed to.
- `docker compose up` runs n8n with the built node next to a Radicale.
- plain npm, with the integration tests pointed at any server through
  CALDAV_TEST_URL.

The integration setup starts a throwaway Radicale from PATH on a free port
with its own storage, the way caldavsync does it on the same CI runner.
Spawning a process is exactly what the test harness is for, so that rule
joins the test-only overrides.

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
`graft init --no-global --agents claude agents`: the MCP server calls the
devShell binary, the graph itself stays gitignored, and nothing outside the
repo is touched.

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
n8n community nodes may not ship runtime dependencies, and the `dav`
package the node used is unmaintained since 2017. This replaces it with
small modules that sit behind a transport function, so the node can drive
them through n8n's authenticated HTTP helper and the tests through fetch:

- xml: the namespace-aware XML subset multistatus responses use; DTDs are
  skipped, never expanded
- ical: RFC 5545 parsing and serialising that keeps every property it does
  not understand, so an edited event keeps its alarms and attendees
- time: wall time <-> instant for IANA zones on Intl, DST gaps and
  overlaps resolved the way RFC 5545 says
- caldav: discovery from the server root, a principal, a calendar home or
  a single calendar; time-range queries with server-side recurrence
  expansion; If-None-Match / If-Match on every write
- event: VEVENT <-> the JSON the node emits, with duration-preserving moves

Recurrence is expanded by the server (RFC 4791 9.6.5) instead of by the
hand-written RRULE arithmetic, which approximated months as 30 days and
ignored overrides. The client tests run against a real Radicale.

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
Radicale 3.8 answers CALDAV:expand by generating occurrences in UTC, so a
weekly 09:00 Europe/Madrid meeting comes back at 08:00 after the end of
summer time. RFC 5545 computes the set in the DTSTART's zone, and that is
what this expander does: occurrences are built as wall times and only
then turned into instants.

It covers what calendars actually write - DAILY to YEARLY with INTERVAL,
COUNT, UNTIL, BYDAY with ordinals, BYMONTHDAY, BYMONTH, BYSETPOS, WKST,
RDATE, EXDATE and overridden occurrences - and refuses the rest with
UnsupportedRecurrenceError instead of guessing. The client stops asking
the server to expand; queryEvents returns series as stored.

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
The 1500-line node, its Russian comments and emoji error messages, the
`dav` dependency and its hand-written typings are replaced by a thin n8n
layer over lib/: descriptions, one function per operation, and a transport
that sends every request through httpRequestWithAuthentication, so n8n's
proxy, TLS and credential handling apply.

What changes for users:
- Resource/operation layout (Event: Create, Delete, Get Many), and the
  calendar is a resource locator with a searchable list or a path.
- Get Many takes a time range instead of a single day, supports a limit,
  text search and turning recurrence expansion off. "No events" is an
  empty result, not an error.
- Times come out as ISO 8601 in the workflow timezone; input without an
  offset is read in that timezone instead of the server's.
- Create can make all-day and recurring events, store them with a TZID,
  and take a caller-chosen UID; a duplicate UID is refused.
- The credential test uses PROPFIND, which Radicale accepts on a user's
  home where the old GET got a 403.

The Yandex-specific headers and warnings are gone: they worked around one
provider's throttling in every request for everyone.

BREAKING CHANGE: new package name, node version 1 and new parameter names;
existing workflows need the node re-added.

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
Calendar > Get Many returns every calendar collection discovered from the
server URL, with its name, description, colour, the component types it
accepts and its ctag. The href it returns is what the event operations
take as a calendar path, so a workflow can pick a calendar by name.

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
Returns the event as stored, followed by any occurrences of a recurring
series that were changed individually, each with its recurrenceId. The
raw iCalendar text is available on request, alarms and all.

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
The upstream node dropped Update because it rebuilt events from scratch
and lost whatever it did not know about. This one edits the stored object:
only the fields given change, and alarms, attendees, overridden
occurrences and other clients' properties survive. SEQUENCE is bumped,
and the write carries If-Match, so an edit made elsewhere since the read
fails with 412 instead of being overwritten.

Moving only the start keeps the event's length and timezone; changing
only the timezone keeps the instants and rewrites them as local time
there; all-day and timed events convert in either direction. On a
recurring event the whole series changes.

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
The README and INSTALL.md described the upstream package, partly in
Russian and with emoji; they are replaced. docs/usage.md is the contract
for dates, timezones, all-day ends and recurrence, docs/architecture.md
explains the request flow and why there are no dependencies, and
docs/releasing.md the publish path. AGENTS.md carries the conventions an
agent cannot read off the code; CLAUDE.md links to it.

The changelog restarts at the fork, pointing at upstream for the history
before it.

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
A dry-run pack shipped dist/tsconfig.tsbuildinfo and a copy of a local
`nix build` result link, which n8n-node's static-file copy had followed
into dist/. The build now starts from an empty dist/ and keeps the
incremental build cache in node_modules/.cache.

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
ci.yml runs lint, format, types, the ASCII check, the build, unit tests
and the integration tests against the devShell's Radicale on the `nix`
runner, plus `nix flake check` in its own job.

publish.yml runs on a v* tag: it checks the tag against package.json and
the changelog, reruns the gates, packs, publishes to npm with NPM_TOKEN
(prereleases under `next`), and attaches the tarball to a Forgejo release
whose notes come from CHANGELOG.md. Re-running it after a partial failure
skips a version npm already has.

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
Merge branch 'feature/forgejo-ci' into develop
All checks were successful
ci / check (push) Successful in 1m35s
ci / nix (push) Successful in 52s
ci / check (pull_request) Successful in 1m36s
ci / nix (pull_request) Successful in 55s
0cedd707ee
marti merged commit 3aab7eea74 into main 2026-09-26 12:43:56 +02:00
Sign in to join this conversation.
No reviewers
No labels
No milestone
No project
No assignees
1 participant
Notifications
Due date
The due date is invalid or out of range. Please use the format "yyyy-mm-dd".

No due date set.

Dependencies

No dependencies set

Reference
marti/n8n-nodes-caldav!1
No description provided.