n8n-nodes-caldav-pro 3.4.0 → 3.4.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/CHANGELOG.md CHANGED
@@ -1,369 +1,405 @@
1
- # Changelog
2
-
3
- All notable changes to this project are documented here. The format follows
4
- [Keep a Changelog](https://keepachangelog.com/en/1.1.0/), and the project
5
- adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
6
-
7
- ## [3.4.0]
8
-
9
- ### Fixed
10
-
11
- - **A Start or End without an offset is now read in the Timezone field's zone,
12
- not the n8n host's.** `2026-07-29T14:00:00` with Timezone `Europe/Berlin`
13
- means two o'clock in Berlin; it was previously parsed in the host's zone —
14
- usually UTC in Docker — and stored two hours out. The same class of error as
15
- the one fixed in 3.0.0, on the input side, and only when the offset was left
16
- off.
17
-
18
- This means a caller no longer has to know whether summer time applies. An
19
- explicit offset, or a trailing `Z`, is still taken at face value.
20
-
21
- If you were compensating by always writing an explicit offset, nothing
22
- changes. If you passed naive times and corrected for the shift elsewhere,
23
- remove that correction.
24
-
25
- ### Changed
26
-
27
- - The Start, End, and Timezone descriptions now say so, since those are what an
28
- AI Agent reads when deciding what to send.
29
-
30
- ## [3.3.0]
31
-
32
- ### Added
33
-
34
- - **Single occurrences of a recurring series can be changed and cancelled.**
35
- Set **Occurrence** on Delete or Update to a `recurrenceId` from a read, and
36
- only that date is affected.
37
-
38
- A series has no per-occurrence resource to address: every occurrence shares
39
- one UID and one URL. Cancelling therefore adds the slot to `EXDATE` and
40
- writes the series back — a `PUT`, not a `DELETE`, since deleting the resource
41
- would take the whole series. Changing writes a `RECURRENCE-ID` override
42
- beside the master, seeded from it so the occurrence keeps the series' details,
43
- minus the recurrence properties an override must not carry.
44
-
45
- Both anchor on the slot the rule generated rather than on where an occurrence
46
- was moved to, so a moved occurrence can still be cancelled afterwards — and
47
- cancelling removes any override for that slot instead of orphaning it.
48
-
49
- ### Changed
50
-
51
- - The guard added in 3.1.0 now points at both ways out: name an occurrence, or
52
- confirm the whole series.
53
-
54
- ## [3.2.0]
55
-
56
- ### Added
57
-
58
- - **`startLocal` and `endLocal`** on returned events: the same moment as the
59
- event's own local time with its offset applied, `2026-07-28T21:00:00+02:00`.
60
-
61
- `start` is a UTC instant because that is what sorts and computes correctly,
62
- but reading a local time off it requires knowing the offset in force on that
63
- date — and language models get that wrong. Asked to show a 19:00Z summer
64
- event in Berlin, one reported 23:00, then 20:00 on a later run: no offset,
65
- then the winter offset. For a node that advertises `usableAsTool`, handing
66
- the model arithmetic it cannot reliably do is a design fault, not the model's
67
- problem.
68
-
69
- Events stored in plain UTC carry no zone of their own and are rendered in the
70
- workflow's timezone. All-day events keep their bare date. `start` and `end`
71
- are unchanged, so nothing that reads them needs to.
72
-
73
- - The node description now tells an agent which field to use for what.
74
-
75
- ## [3.1.2]
76
-
77
- ### Fixed
78
-
79
- - **Events with a TZID were read at the wrong time when the calendar object
80
- carried a faulty VTIMEZONE.** Infomaniak's own importer writes
81
- `TZID:Europe/Berlin` with US transition rules whose `RRULE`s contradict their
82
- own `DTSTART`s. No observance then matches a summer date, ical.js falls back
83
- to a zero offset, and every affected event is reported two hours late — a
84
- 21:00 pickup shows up as 23:00.
85
-
86
- An IANA `TZID` is now resolved against the platform's timezone database
87
- rather than the embedded VTIMEZONE, which is written by whichever tool
88
- produced the event and is wrong often enough to matter. The embedded
89
- definition remains the fallback for a `TZID` that names no IANA zone, such as
90
- an Outlook-style `W. Europe Standard Time`.
91
-
92
- Anything read from an affected calendar before this release was wrong by the
93
- UTC offset in force at the event's date. Reads only — nothing this node wrote
94
- was affected.
95
-
96
- ## [3.1.1]
97
-
98
- ### Fixed
99
-
100
- - A reversed or zero-width time window is rejected instead of being sent to the
101
- server, which answers it with an empty result that reads as "no events" rather
102
- than as the mistake it is. The error shows both bounds.
103
- - A **Lookahead Days** of zero or less is rejected on Get Next. The field's
104
- `minValue` constrains the editor, not an expression that computes the value.
105
-
106
- ### Added
107
-
108
- - CI on push and pull requests: build, lint self-test, lint, tests, the offline
109
- smoke test, and a check on the contents of the published tarball. On a version
110
- tag, the tag is compared against `package.json`.
111
- - `npm run check:package`, also wired into `prepublishOnly`.
112
- - `engines: node >=20.15`, matching what the shipped code needs. Development
113
- requires Node 22 — `n8n-workflow` pulls in `isolated-vm`, which will not
114
- install on 20 — but that does not reach consumers.
115
-
116
- ## [3.1.0]
117
-
118
- ### Added
119
-
120
- - **Entire Series** toggle on Delete and Update. Every occurrence of a
121
- recurring event shares one UID and one resource, so deleting "tomorrow's
122
- standup" by UID removes the whole series. That now has to be asked for: if
123
- the target turns out to be recurring and the toggle is off, the operation is
124
- refused and the error names the rule at stake.
125
- - Delete sends `If-Match` with the stored ETag, so an event modified since it
126
- was read is not removed unseen. A `412` is reported as a conflict rather than
127
- passed through raw.
128
-
129
- ### Changed
130
-
131
- - **Delete on a recurring event now fails by default.** Previously it removed
132
- every occurrence silently. Set **Entire Series** to restore the old
133
- behaviour. Non-recurring events are unaffected.
134
- - Delete reads the event before removing it — one extra request, which is what
135
- makes both the series check and the conditional delete possible. A missing
136
- event is now reported as such instead of surfacing as a bare `404`.
137
-
138
- ## [3.0.0]
139
-
140
- The first release since 2.6.1. Versions 2.7.0 through 2.11.0 were developed but
141
- never published; their entries are kept below for traceability. If you are
142
- upgrading from 2.6.x, this section is what matters.
143
-
144
- ### BREAKING CHANGES
145
-
146
- 1. **`start` and `end` changed format.** Timed events previously reported a
147
- local wall clock with no offset (`2026-04-20T14:00:00`), which downstream
148
- nodes re-read in the n8n host's timezone. They are now explicit UTC instants
149
- (`2026-04-20T12:00:00.000Z`); all-day events report a bare date
150
- (`2026-04-20`). Both sort correctly as strings. Any expression that compares,
151
- slices, or parses these values needs review.
152
-
153
- 2. **`raw` is no longer returned by default.** Read operations have a
154
- **Simplify** toggle, on by default, which omits the full `VCALENDAR` source.
155
- Turn it off where you depend on `raw`.
156
-
157
- 3. **Update no longer creates a missing event.** It reads the stored object
158
- first in order to preserve fields you did not supply, so a missing event is
159
- now an error instead of a silent create. Use Create for that.
160
-
161
- 4. **Events are written at different times than before — this is the fix, but
162
- it will move existing workflows.** With **Timezone** set, 2.6.x emitted the
163
- n8n host's wall clock under the requested `TZID`, shifting every event by the
164
- host's UTC offset (two hours on a UTC host writing `Europe/Berlin`). All-day
165
- events were written one calendar day early. If you compensated for either by
166
- pre-shifting your input, remove that workaround or events will now be wrong
167
- in the other direction.
168
-
169
- 5. **All-day `DTEND` is now the exclusive end RFC 5545 requires.** A same-day
170
- or end-of-day range used to encode a zero-length event; it now produces a
171
- one-day event.
172
-
173
- ### Added
174
-
175
- - Recurring series are expanded into the occurrences inside the queried window,
176
- honouring `EXDATE` and `RECURRENCE-ID` overrides.
177
- - Events can be addressed by **Event URL** as well as UID, and a UID is
178
- resolved against the server — so events created in Thunderbird, Apple
179
- Calendar, or a web UI can be reached at all.
180
- - Calendars report `readOnly`, and read-only ones are marked 🔒 in the dropdown.
181
- - `recurrenceId` and `timezone` on returned events.
182
- - A test suite: 80 unit and integration tests, plus a smoke test that runs
183
- against a real server and one that runs offline.
184
-
185
- ### Fixed
186
-
187
- - Update preserves everything it was not asked to change, including properties
188
- this node does not model (`CATEGORIES`, `ORGANIZER`, custom `X-` properties),
189
- and is guarded by `If-Match` against concurrent edits.
190
- - A `TZID` with no accompanying `VTIMEZONE` is resolved against the named IANA
191
- zone instead of the host's.
192
- - Writing to a read-only calendar explains itself instead of returning n8n's
193
- generic "check your credentials".
194
-
195
- ### Security
196
-
197
- - Advisories affecting installed users: **0**. `fast-xml-parser` moves 4 → 5.
198
-
199
- ## [2.11.0]
200
-
201
- ### Added
202
-
203
- - Calendars report **`readOnly`**, taken from the server's
204
- `current-user-privilege-set`. It rides along on the listing discovery already
205
- performs, so it costs no extra request.
206
- - Read-only calendars are marked `🔒 … (Read-Only)` in the Calendar dropdown
207
- and sorted after the writable ones.
208
-
209
- ### Fixed
210
-
211
- - Writing to a calendar you cannot write to produced n8n's generic
212
- `Forbidden - perhaps check your credentials?`, which points at the wrong
213
- cause entirely. Such a 403 now explains that the calendar is read-only —
214
- typically one shared with you, or a subscribed feed — and how to find one
215
- that is not.
216
-
217
- ### Notes
218
-
219
- - A server that does not report privileges leaves `readOnly` undefined rather
220
- than assuming read-only, so nothing is mislabelled or blocked on servers
221
- without the property.
222
- - Found by running the smoke test against a real account, where five of six
223
- calendars turned out to be read-only while looking identical in the dropdown.
224
-
225
- ## [2.10.0]
226
-
227
- ### Changed
228
-
229
- - **gulp removed.** A single task copied one SVG into the build output; gulp 4
230
- is end-of-life and pulled in gulp-cli, liftoff, matchdep, chokidar, and
231
- micromatch to do it. Replaced by `scripts/copy-icons.mjs`, which reproduces
232
- the previous behaviour exactly.
233
- - **ESLint 8 → 9**, with a flat config (`eslint.config.mjs`) replacing
234
- `.eslintrc.js`. `@typescript-eslint/parser` moves 7 → 8.
235
- - **`fast-xml-parser` 4 → 5** — a runtime dependency, and the only advisory
236
- that reached installed users.
237
-
238
- ### Added
239
-
240
- - `npm run lint:selftest`, which feeds a deliberate violation to each
241
- eslint-plugin-n8n-nodes-base preset and fails if it goes unreported. Part of
242
- `prepublishOnly`.
243
-
244
- ### Removed
245
-
246
- - The plugin's `community` preset (19 rules against `package.json`) is no
247
- longer configured. Its rules visit `ObjectExpression` while the JSON parser
248
- emits `JSONObjectExpression`, so they never matched — verified inert under
249
- ESLint 8 and 9 and under plugin 1.16.6 and 1.16.7. It was never enforcing
250
- anything; the configuration only made it look as though it was.
251
-
252
- ### Security
253
-
254
- - Advisories affecting installed users: **0** (was 1 moderate). Development
255
- advisories drop from 24 to 5, all in ESLint's own `minimatch` chain. ESLint 10
256
- would clear those but crashes eslint-plugin-n8n-nodes-base during traversal,
257
- so the project stays on 9.
258
-
259
- ## [2.9.2]
260
-
261
- ### Added
262
-
263
- - `LICENSE` file. The package declared MIT but shipped no licence text.
264
- - `CHANGELOG.md` is now included in the published package.
265
-
266
- ### Fixed
267
-
268
- - `dist/tsconfig.tsbuildinfo`, a 64 kB incremental build cache, was published
269
- with every release. The package is now 37 kB instead of 54 kB.
270
-
271
- ## [2.9.1]
272
-
273
- ### Added
274
-
275
- - Calendar discovery is memoised per execution. A batch of input items used to
276
- repeat the full PROPFIND chain for every item; it now runs once.
277
- - `Time Min` / `Time Max` are validated, so an unparseable date fails with a
278
- message naming the field instead of an opaque `400` from the server.
279
- - Integration tests covering the read operations end to end against a fake
280
- CalDAV server.
281
-
282
- ### Changed
283
-
284
- - Internal: `Get Many`, `Get Next`, and `Search` now share one implementation
285
- and differ only in the time window and filter predicate.
286
-
287
- ## [2.9.0]
288
-
289
- ### Added
290
-
291
- - **Event URL** field on `Get`, `Update`, `Delete`, and `Move`. Read operations
292
- already return `url`; passing it through addresses the event directly.
293
- - When only a UID is known, the event is located with a `calendar-query` on the
294
- UID, falling back to the historical `<calendar>/<uid>.ics` convention.
295
- - **Simplify** toggle on the read operations, on by default.
296
-
297
- ### Fixed
298
-
299
- - `Get` / `Update` / `Delete` / `Move` could only reach events created by this
300
- node. Events added in Thunderbird, Apple Calendar, or a web UI are stored
301
- under a filename the server chose, so addressing them by UID returned `404`.
302
-
303
- ### Changed
304
-
305
- - **Event UID** is no longer mandatory — either UID or URL identifies an event.
306
- - `raw` is omitted by default. Turn **Simplify** off to restore it.
307
-
308
- ## [2.8.0]
309
-
310
- ### Added
311
-
312
- - Recurring series are expanded into the individual occurrences that fall
313
- inside the queried window, honouring `EXDATE` exclusions and `RECURRENCE-ID`
314
- overrides.
315
- - `recurrenceId` and `timezone` fields on returned events.
316
-
317
- ### Fixed
318
-
319
- - A series reported its original `DTSTART` rather than the occurrence in the
320
- requested window, and `Get Next` skipped recurring events entirely.
321
- - A `TZID` without an accompanying `VTIMEZONE` was read in the n8n host's
322
- timezone. Such times are now resolved against the named IANA zone.
323
- - Reading an object whose overridden instance was serialised first returned the
324
- override instead of the series master.
325
-
326
- ### Changed
327
-
328
- - **`start` / `end` output format.** Timed events previously reported a local
329
- wall clock with no offset (`2026-04-20T14:00:00`), which downstream nodes
330
- re-read in the host's timezone. They are now explicit UTC instants
331
- (`2026-04-20T12:00:00.000Z`); all-day events report a bare date
332
- (`2026-04-20`). Both sort correctly as strings.
333
-
334
- ## [2.7.0]
335
-
336
- ### Fixed
337
-
338
- - **Timed events were written at the wrong time.** With **Timezone** set, the
339
- n8n host's wall clock was emitted under the requested `TZID`, shifting every
340
- event by the host's UTC offset — two hours on a UTC host writing
341
- `Europe/Berlin`. Events created with an earlier version should be re-checked.
342
- - **All-day events were written one day early**, because the date was taken
343
- from the instant's UTC components.
344
- - All-day `DTEND` is now the exclusive end RFC 5545 requires. An inclusive
345
- same-day end produces a one-day event instead of a zero-length one.
346
- - **`Update` no longer discards data.** It rebuilt the event from the node's
347
- own fields, dropping everything not restated — description, location,
348
- attendees, reminders, recurrence — along with properties this node does not
349
- model at all (`CATEGORIES`, `ORGANIZER`, custom `X-` properties). Updates are
350
- now applied as a patch to the stored object.
351
-
352
- ### Added
353
-
354
- - `If-Match` on update, so a concurrent edit is rejected rather than
355
- overwritten.
356
- - `SEQUENCE` is incremented and `LAST-MODIFIED` set on every update, so clients
357
- recognise the change.
358
- - Unit test suite (`npm test`, Vitest). Tests assert that output is identical
359
- across several host timezones — the class of bug fixed in this release.
360
-
361
- ### Changed
362
-
363
- - `Update` fails when the event does not exist instead of silently creating it.
364
- - iCalendar is serialised through ical.js, which brings RFC-compliant line
365
- folding and parameter quoting.
366
-
367
- ## [2.0.0]
368
-
369
- Initial release.
1
+ # Changelog
2
+
3
+ All notable changes to this project are documented here. The format follows
4
+ [Keep a Changelog](https://keepachangelog.com/en/1.1.0/), and the project
5
+ adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
6
+
7
+ ## [3.4.1]
8
+
9
+ ### Security
10
+
11
+ - CalDAV URLs supplied through Calendar, Target Calendar, Event URL, or the
12
+ credential Default Calendar must stay on the configured server origin, so
13
+ credential-backed requests cannot be redirected to another host by free-text
14
+ input.
15
+
16
+ ### Fixed
17
+
18
+ - Weak ETags returned by CalDAV servers are no longer used as invalid `If-Match`
19
+ headers on Update, Delete, or Move; strong ETags remain conditional.
20
+ - Move now reports the partial-success state clearly when the target copy was
21
+ created but deleting the source failed, including both URLs and a cleanup hint.
22
+ - Get Next keeps today's and ongoing multi-day all-day events, respecting
23
+ exclusive `DTEND` and the workflow timezone.
24
+ - Timed Create and Update reject ranges where End is not after Start; all-day
25
+ date behavior is unchanged.
26
+ - `EMAIL` VALARMs are only written in RFC-compliant form with `SUMMARY` and
27
+ `ATTENDEE`; reminders without event attendees fall back to `DISPLAY`.
28
+ - A report error from an explicitly selected calendar is reported instead of
29
+ being treated as an empty result.
30
+ - Update now patches the stored series master/resource instead of rebuilding from
31
+ the first expanded VEVENT instance.
32
+ - Create names a missing or invalid Start/End field instead of failing later with
33
+ an ambiguous date error.
34
+
35
+ ### Changed
36
+
37
+ - Update is a true patch: omitted Summary, Start, End, and additional fields keep
38
+ their stored values instead of being rewritten with defaults such as `$now`.
39
+ - Package checks now guard shipped node metadata and any declared `main`; the
40
+ unused `main` entry was removed and the node metadata uses this community
41
+ package's namespace.
42
+
43
+ ## [3.4.0]
44
+
45
+ ### Fixed
46
+
47
+ - **A Start or End without an offset is now read in the Timezone field's zone,
48
+ not the n8n host's.** `2026-07-29T14:00:00` with Timezone `Europe/Berlin`
49
+ means two o'clock in Berlin; it was previously parsed in the host's zone —
50
+ usually UTC in Docker — and stored two hours out. The same class of error as
51
+ the one fixed in 3.0.0, on the input side, and only when the offset was left
52
+ off.
53
+
54
+ This means a caller no longer has to know whether summer time applies. An
55
+ explicit offset, or a trailing `Z`, is still taken at face value.
56
+
57
+ If you were compensating by always writing an explicit offset, nothing
58
+ changes. If you passed naive times and corrected for the shift elsewhere,
59
+ remove that correction.
60
+
61
+ ### Changed
62
+
63
+ - The Start, End, and Timezone descriptions now say so, since those are what an
64
+ AI Agent reads when deciding what to send.
65
+
66
+ ## [3.3.0]
67
+
68
+ ### Added
69
+
70
+ - **Single occurrences of a recurring series can be changed and cancelled.**
71
+ Set **Occurrence** on Delete or Update to a `recurrenceId` from a read, and
72
+ only that date is affected.
73
+
74
+ A series has no per-occurrence resource to address: every occurrence shares
75
+ one UID and one URL. Cancelling therefore adds the slot to `EXDATE` and
76
+ writes the series back — a `PUT`, not a `DELETE`, since deleting the resource
77
+ would take the whole series. Changing writes a `RECURRENCE-ID` override
78
+ beside the master, seeded from it so the occurrence keeps the series' details,
79
+ minus the recurrence properties an override must not carry.
80
+
81
+ Both anchor on the slot the rule generated rather than on where an occurrence
82
+ was moved to, so a moved occurrence can still be cancelled afterwards — and
83
+ cancelling removes any override for that slot instead of orphaning it.
84
+
85
+ ### Changed
86
+
87
+ - The guard added in 3.1.0 now points at both ways out: name an occurrence, or
88
+ confirm the whole series.
89
+
90
+ ## [3.2.0]
91
+
92
+ ### Added
93
+
94
+ - **`startLocal` and `endLocal`** on returned events: the same moment as the
95
+ event's own local time with its offset applied, `2026-07-28T21:00:00+02:00`.
96
+
97
+ `start` is a UTC instant because that is what sorts and computes correctly,
98
+ but reading a local time off it requires knowing the offset in force on that
99
+ date — and language models get that wrong. Asked to show a 19:00Z summer
100
+ event in Berlin, one reported 23:00, then 20:00 on a later run: no offset,
101
+ then the winter offset. For a node that advertises `usableAsTool`, handing
102
+ the model arithmetic it cannot reliably do is a design fault, not the model's
103
+ problem.
104
+
105
+ Events stored in plain UTC carry no zone of their own and are rendered in the
106
+ workflow's timezone. All-day events keep their bare date. `start` and `end`
107
+ are unchanged, so nothing that reads them needs to.
108
+
109
+ - The node description now tells an agent which field to use for what.
110
+
111
+ ## [3.1.2]
112
+
113
+ ### Fixed
114
+
115
+ - **Events with a TZID were read at the wrong time when the calendar object
116
+ carried a faulty VTIMEZONE.** Infomaniak's own importer writes
117
+ `TZID:Europe/Berlin` with US transition rules whose `RRULE`s contradict their
118
+ own `DTSTART`s. No observance then matches a summer date, ical.js falls back
119
+ to a zero offset, and every affected event is reported two hours late — a
120
+ 21:00 pickup shows up as 23:00.
121
+
122
+ An IANA `TZID` is now resolved against the platform's timezone database
123
+ rather than the embedded VTIMEZONE, which is written by whichever tool
124
+ produced the event and is wrong often enough to matter. The embedded
125
+ definition remains the fallback for a `TZID` that names no IANA zone, such as
126
+ an Outlook-style `W. Europe Standard Time`.
127
+
128
+ Anything read from an affected calendar before this release was wrong by the
129
+ UTC offset in force at the event's date. Reads only — nothing this node wrote
130
+ was affected.
131
+
132
+ ## [3.1.1]
133
+
134
+ ### Fixed
135
+
136
+ - A reversed or zero-width time window is rejected instead of being sent to the
137
+ server, which answers it with an empty result that reads as "no events" rather
138
+ than as the mistake it is. The error shows both bounds.
139
+ - A **Lookahead Days** of zero or less is rejected on Get Next. The field's
140
+ `minValue` constrains the editor, not an expression that computes the value.
141
+
142
+ ### Added
143
+
144
+ - CI on push and pull requests: build, lint self-test, lint, tests, the offline
145
+ smoke test, and a check on the contents of the published tarball. On a version
146
+ tag, the tag is compared against `package.json`.
147
+ - `npm run check:package`, also wired into `prepublishOnly`.
148
+ - `engines: node >=20.15`, matching what the shipped code needs. Development
149
+ requires Node 22 — `n8n-workflow` pulls in `isolated-vm`, which will not
150
+ install on 20 — but that does not reach consumers.
151
+
152
+ ## [3.1.0]
153
+
154
+ ### Added
155
+
156
+ - **Entire Series** toggle on Delete and Update. Every occurrence of a
157
+ recurring event shares one UID and one resource, so deleting "tomorrow's
158
+ standup" by UID removes the whole series. That now has to be asked for: if
159
+ the target turns out to be recurring and the toggle is off, the operation is
160
+ refused and the error names the rule at stake.
161
+ - Delete sends `If-Match` with the stored ETag, so an event modified since it
162
+ was read is not removed unseen. A `412` is reported as a conflict rather than
163
+ passed through raw.
164
+
165
+ ### Changed
166
+
167
+ - **Delete on a recurring event now fails by default.** Previously it removed
168
+ every occurrence silently. Set **Entire Series** to restore the old
169
+ behaviour. Non-recurring events are unaffected.
170
+ - Delete reads the event before removing it — one extra request, which is what
171
+ makes both the series check and the conditional delete possible. A missing
172
+ event is now reported as such instead of surfacing as a bare `404`.
173
+
174
+ ## [3.0.0]
175
+
176
+ The first release since 2.6.1. Versions 2.7.0 through 2.11.0 were developed but
177
+ never published; their entries are kept below for traceability. If you are
178
+ upgrading from 2.6.x, this section is what matters.
179
+
180
+ ### BREAKING CHANGES
181
+
182
+ 1. **`start` and `end` changed format.** Timed events previously reported a
183
+ local wall clock with no offset (`2026-04-20T14:00:00`), which downstream
184
+ nodes re-read in the n8n host's timezone. They are now explicit UTC instants
185
+ (`2026-04-20T12:00:00.000Z`); all-day events report a bare date
186
+ (`2026-04-20`). Both sort correctly as strings. Any expression that compares,
187
+ slices, or parses these values needs review.
188
+
189
+ 2. **`raw` is no longer returned by default.** Read operations have a
190
+ **Simplify** toggle, on by default, which omits the full `VCALENDAR` source.
191
+ Turn it off where you depend on `raw`.
192
+
193
+ 3. **Update no longer creates a missing event.** It reads the stored object
194
+ first in order to preserve fields you did not supply, so a missing event is
195
+ now an error instead of a silent create. Use Create for that.
196
+
197
+ 4. **Events are written at different times than before — this is the fix, but
198
+ it will move existing workflows.** With **Timezone** set, 2.6.x emitted the
199
+ n8n host's wall clock under the requested `TZID`, shifting every event by the
200
+ host's UTC offset (two hours on a UTC host writing `Europe/Berlin`). All-day
201
+ events were written one calendar day early. If you compensated for either by
202
+ pre-shifting your input, remove that workaround or events will now be wrong
203
+ in the other direction.
204
+
205
+ 5. **All-day `DTEND` is now the exclusive end RFC 5545 requires.** A same-day
206
+ or end-of-day range used to encode a zero-length event; it now produces a
207
+ one-day event.
208
+
209
+ ### Added
210
+
211
+ - Recurring series are expanded into the occurrences inside the queried window,
212
+ honouring `EXDATE` and `RECURRENCE-ID` overrides.
213
+ - Events can be addressed by **Event URL** as well as UID, and a UID is
214
+ resolved against the server — so events created in Thunderbird, Apple
215
+ Calendar, or a web UI can be reached at all.
216
+ - Calendars report `readOnly`, and read-only ones are marked 🔒 in the dropdown.
217
+ - `recurrenceId` and `timezone` on returned events.
218
+ - A test suite: 80 unit and integration tests, plus a smoke test that runs
219
+ against a real server and one that runs offline.
220
+
221
+ ### Fixed
222
+
223
+ - Update preserves everything it was not asked to change, including properties
224
+ this node does not model (`CATEGORIES`, `ORGANIZER`, custom `X-` properties),
225
+ and is guarded by `If-Match` against concurrent edits.
226
+ - A `TZID` with no accompanying `VTIMEZONE` is resolved against the named IANA
227
+ zone instead of the host's.
228
+ - Writing to a read-only calendar explains itself instead of returning n8n's
229
+ generic "check your credentials".
230
+
231
+ ### Security
232
+
233
+ - Advisories affecting installed users: **0**. `fast-xml-parser` moves 4 → 5.
234
+
235
+ ## [2.11.0]
236
+
237
+ ### Added
238
+
239
+ - Calendars report **`readOnly`**, taken from the server's
240
+ `current-user-privilege-set`. It rides along on the listing discovery already
241
+ performs, so it costs no extra request.
242
+ - Read-only calendars are marked `🔒 … (Read-Only)` in the Calendar dropdown
243
+ and sorted after the writable ones.
244
+
245
+ ### Fixed
246
+
247
+ - Writing to a calendar you cannot write to produced n8n's generic
248
+ `Forbidden - perhaps check your credentials?`, which points at the wrong
249
+ cause entirely. Such a 403 now explains that the calendar is read-only —
250
+ typically one shared with you, or a subscribed feed — and how to find one
251
+ that is not.
252
+
253
+ ### Notes
254
+
255
+ - A server that does not report privileges leaves `readOnly` undefined rather
256
+ than assuming read-only, so nothing is mislabelled or blocked on servers
257
+ without the property.
258
+ - Found by running the smoke test against a real account, where five of six
259
+ calendars turned out to be read-only while looking identical in the dropdown.
260
+
261
+ ## [2.10.0]
262
+
263
+ ### Changed
264
+
265
+ - **gulp removed.** A single task copied one SVG into the build output; gulp 4
266
+ is end-of-life and pulled in gulp-cli, liftoff, matchdep, chokidar, and
267
+ micromatch to do it. Replaced by `scripts/copy-icons.mjs`, which reproduces
268
+ the previous behaviour exactly.
269
+ - **ESLint 8 → 9**, with a flat config (`eslint.config.mjs`) replacing
270
+ `.eslintrc.js`. `@typescript-eslint/parser` moves 7 → 8.
271
+ - **`fast-xml-parser` 4 → 5** — a runtime dependency, and the only advisory
272
+ that reached installed users.
273
+
274
+ ### Added
275
+
276
+ - `npm run lint:selftest`, which feeds a deliberate violation to each
277
+ eslint-plugin-n8n-nodes-base preset and fails if it goes unreported. Part of
278
+ `prepublishOnly`.
279
+
280
+ ### Removed
281
+
282
+ - The plugin's `community` preset (19 rules against `package.json`) is no
283
+ longer configured. Its rules visit `ObjectExpression` while the JSON parser
284
+ emits `JSONObjectExpression`, so they never matched — verified inert under
285
+ ESLint 8 and 9 and under plugin 1.16.6 and 1.16.7. It was never enforcing
286
+ anything; the configuration only made it look as though it was.
287
+
288
+ ### Security
289
+
290
+ - Advisories affecting installed users: **0** (was 1 moderate). Development
291
+ advisories drop from 24 to 5, all in ESLint's own `minimatch` chain. ESLint 10
292
+ would clear those but crashes eslint-plugin-n8n-nodes-base during traversal,
293
+ so the project stays on 9.
294
+
295
+ ## [2.9.2]
296
+
297
+ ### Added
298
+
299
+ - `LICENSE` file. The package declared MIT but shipped no licence text.
300
+ - `CHANGELOG.md` is now included in the published package.
301
+
302
+ ### Fixed
303
+
304
+ - `dist/tsconfig.tsbuildinfo`, a 64 kB incremental build cache, was published
305
+ with every release. The package is now 37 kB instead of 54 kB.
306
+
307
+ ## [2.9.1]
308
+
309
+ ### Added
310
+
311
+ - Calendar discovery is memoised per execution. A batch of input items used to
312
+ repeat the full PROPFIND chain for every item; it now runs once.
313
+ - `Time Min` / `Time Max` are validated, so an unparseable date fails with a
314
+ message naming the field instead of an opaque `400` from the server.
315
+ - Integration tests covering the read operations end to end against a fake
316
+ CalDAV server.
317
+
318
+ ### Changed
319
+
320
+ - Internal: `Get Many`, `Get Next`, and `Search` now share one implementation
321
+ and differ only in the time window and filter predicate.
322
+
323
+ ## [2.9.0]
324
+
325
+ ### Added
326
+
327
+ - **Event URL** field on `Get`, `Update`, `Delete`, and `Move`. Read operations
328
+ already return `url`; passing it through addresses the event directly.
329
+ - When only a UID is known, the event is located with a `calendar-query` on the
330
+ UID, falling back to the historical `<calendar>/<uid>.ics` convention.
331
+ - **Simplify** toggle on the read operations, on by default.
332
+
333
+ ### Fixed
334
+
335
+ - `Get` / `Update` / `Delete` / `Move` could only reach events created by this
336
+ node. Events added in Thunderbird, Apple Calendar, or a web UI are stored
337
+ under a filename the server chose, so addressing them by UID returned `404`.
338
+
339
+ ### Changed
340
+
341
+ - **Event UID** is no longer mandatory — either UID or URL identifies an event.
342
+ - `raw` is omitted by default. Turn **Simplify** off to restore it.
343
+
344
+ ## [2.8.0]
345
+
346
+ ### Added
347
+
348
+ - Recurring series are expanded into the individual occurrences that fall
349
+ inside the queried window, honouring `EXDATE` exclusions and `RECURRENCE-ID`
350
+ overrides.
351
+ - `recurrenceId` and `timezone` fields on returned events.
352
+
353
+ ### Fixed
354
+
355
+ - A series reported its original `DTSTART` rather than the occurrence in the
356
+ requested window, and `Get Next` skipped recurring events entirely.
357
+ - A `TZID` without an accompanying `VTIMEZONE` was read in the n8n host's
358
+ timezone. Such times are now resolved against the named IANA zone.
359
+ - Reading an object whose overridden instance was serialised first returned the
360
+ override instead of the series master.
361
+
362
+ ### Changed
363
+
364
+ - **`start` / `end` output format.** Timed events previously reported a local
365
+ wall clock with no offset (`2026-04-20T14:00:00`), which downstream nodes
366
+ re-read in the host's timezone. They are now explicit UTC instants
367
+ (`2026-04-20T12:00:00.000Z`); all-day events report a bare date
368
+ (`2026-04-20`). Both sort correctly as strings.
369
+
370
+ ## [2.7.0]
371
+
372
+ ### Fixed
373
+
374
+ - **Timed events were written at the wrong time.** With **Timezone** set, the
375
+ n8n host's wall clock was emitted under the requested `TZID`, shifting every
376
+ event by the host's UTC offset — two hours on a UTC host writing
377
+ `Europe/Berlin`. Events created with an earlier version should be re-checked.
378
+ - **All-day events were written one day early**, because the date was taken
379
+ from the instant's UTC components.
380
+ - All-day `DTEND` is now the exclusive end RFC 5545 requires. An inclusive
381
+ same-day end produces a one-day event instead of a zero-length one.
382
+ - **`Update` no longer discards data.** It rebuilt the event from the node's
383
+ own fields, dropping everything not restated — description, location,
384
+ attendees, reminders, recurrence — along with properties this node does not
385
+ model at all (`CATEGORIES`, `ORGANIZER`, custom `X-` properties). Updates are
386
+ now applied as a patch to the stored object.
387
+
388
+ ### Added
389
+
390
+ - `If-Match` on update, so a concurrent edit is rejected rather than
391
+ overwritten.
392
+ - `SEQUENCE` is incremented and `LAST-MODIFIED` set on every update, so clients
393
+ recognise the change.
394
+ - Unit test suite (`npm test`, Vitest). Tests assert that output is identical
395
+ across several host timezones — the class of bug fixed in this release.
396
+
397
+ ### Changed
398
+
399
+ - `Update` fails when the event does not exist instead of silently creating it.
400
+ - iCalendar is serialised through ical.js, which brings RFC-compliant line
401
+ folding and parameter quoting.
402
+
403
+ ## [2.0.0]
404
+
405
+ Initial release.