n8n-nodes-caldav-pro 3.1.1 → 3.2.0

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