5280 Commits

Author SHA1 Message Date
Karsten Hassel
5e0cd28980 update electron to v40, update node versions in workflows (#4018)
- remove param `--enable-features=UseOzonePlatform` in start electron
tests (as we did already in `package.json`)
- update node versions in github workflows, remove `22.21.1`, add `25.x`
- fix formatting in tests
- update dependencies including electron to v40

This is still a draft PR because most calendar electron tests are not
running which is caused by the electron update from `v39.3.0` to
`v40.0.0`. Maybe @KristjanESPERANTO has an idea ...

---------

Co-authored-by: Kristjan ESPERANTO <35647502+KristjanESPERANTO@users.noreply.github.com>
2026-01-24 06:15:15 -06:00
Kristjan ESPERANTO
34913bfb9f [core] refactor: extract and centralize HTTP fetcher (#4016)
## Summary

PR [#3976](https://github.com/MagicMirrorOrg/MagicMirror/pull/3976)
introduced smart HTTP error handling for the Calendar module. This PR
extracts that HTTP logic into a central `HTTPFetcher` class.

Calendar is the first module to use it. Follow-up PRs would migrate
Newsfeed and maybe even Weather.

**Before this change:**

-  Each module had to implemented its own `fetch()` calls
-  No centralized retry logic or backoff strategies
-  No timeout handling for hanging requests
-  Error detection relied on fragile string parsing

**What this PR adds:**

-  Unified HTTPFetcher class with intelligent retry strategies
-  Modern AbortController with configurable timeout (default 30s)
-  Proper undici Agent for self-signed certificates
-  Structured error objects with translation keys
-  Calendar module migrated as first consumer
-  Comprehensive unit tests with msw (Mock Service Worker)

## Architecture

**Before - Decentralized HTTP handling:**

```
Calendar Module          Newsfeed Module         Weather Module
┌─────────────┐         ┌─────────────┐         ┌─────────────┐
│ fetch() own │         │ fetch() own │         │ fetch() own │
│ retry logic │         │ basic error │         │ no retry    │
│ error parse │         │   handling  │         │ client-side │
└─────────────┘         └─────────────┘         └─────────────┘
      │                       │                       │
      └───────────────────────┴───────────────────────┘
                              ▼
                        External APIs
```

**After - Centralized with HTTPFetcher:**

```
┌─────────────────────────────────────────────────────┐
│                  HTTPFetcher                        │
│  • Unified retry strategies (401/403, 429, 5xx)     │
│  • AbortController timeout (30s)                    │
│  • Structured errors with translation keys          │
│  • undici Agent for self-signed certs               │
└────────────┬──────────────┬──────────────┬──────────┘
             │              │              │
     ┌───────▼───────┐ ┌────▼─────┐ ┌──────▼──────┐
     │   Calendar    │ │ Newsfeed │ │   Weather   │
     │    This PR  │ │  future  │ │   future    │
     └───────────────┘ └──────────┘ └─────────────┘
             │              │              │
             └──────────────┴──────────────┘
                          ▼
                   External APIs
```
## Complexity Considerations

**Does HTTPFetcher add complexity?**

Even if it may look more complex, it actually **reduces overall
complexity**:

- **Calendar already has this logic** (PR #3976) - we're extracting, not
adding
- **Alternative is worse:** Each module implementing own logic = 3× the
code
- **Better testability:** 443 lines of tests once vs. duplicating tests
for each module
- **Standards-based:** Retry-After is RFC 7231, not custom logic

## Future Benefits

**Weather migration (future PR):**

Moving Weather from client-side to server-side will enable:
- **Same robust error handling** - Weather gets 429 rate-limiting, 5xx
backoff for free
- **Simpler architecture** - No proxy layer needed

Moving the weather modules from client-side to server-side will be a big
undertaking, but I think it's a good strategy. Even if we only move the
calendar and newsfeed to the new HTTP fetcher and leave the weather as
it is, this PR still makes sense, I think.

## Breaking Changes

**None**

----

I am eager to hear your opinion on this 🙂
2026-01-22 19:24:37 +01:00
in-voker
23f0290139 Switch to undici Agent for HTTPS requests (#4015)
Allow the selfSignedCert: true flag in calenders array to work.
2026-01-17 21:34:46 +01:00
Kristjan ESPERANTO
37a8b11112 chore(eslint): migrate from eslint-plugin-vitest to @vitest/eslint-plugin and run rules only on test files (#4014)
This PR makes three small changes to the ESLint setup:

1. Migrate from
[eslint-plugin-vitest](https://www.npmjs.com/package/eslint-plugin-vitest)
to it's successor
[@vitest/eslint-plugin](https://www.npmjs.com/package/@vitest/eslint-plugin).
2. Change the eslint config so that only the test files are checked with
the vitest rules. Previously, it was just unnecessary and inefficient to
check all js files with them.
3. We had defined some of the test rules as warnings, but that is not
really ideal. I changed them to errors.
2026-01-12 09:03:32 +01:00
Kristjan ESPERANTO
2d3a557864 fix(calendar): update to node-ical 0.23.1 and fix full-day recurrence lookup (#4013)
Adapts calendar module to node-ical changes and fixes a bug with moved
full-day recurring events in eastern timezones.

## Changes

### 1. Update node-ical to 0.23.1
- Includes upstream fixes for UNTIL UTC validation errors from CalDAV
servers (reported by @rejas in PR #4010)
- Changes to `getDateKey()` behavior for VALUE=DATE events (now uses
local date components)
- Fixes issue with malformed DURATION values (reported by MagicMirror
user here: https://github.com/jens-maus/node-ical/issues/381)

### 2. Remove dead code
- Removed ineffective UNTIL modification code (rule.options is read-only
in rrule-temporal)
- The code attempted to extend UNTIL for all-day events but had no
effect

### 3. Fix recurrence lookup for full-day events
node-ical changed the behavior of `getDateKey()` - it now uses local
date components for VALUE=DATE events instead of UTC. This broke
recurrence override lookups for full-day events in eastern timezones.

**Why it broke:**
- **before node-ical update:** Both node-ical and MagicMirror used UTC →
keys matched 
- **after node-ical update:** node-ical uses local date (RFC 5545
conform), MagicMirror still used UTC → **mismatch** 

**Example:**
- Full-day recurring event on October 12 in Europe/Berlin (UTC+2)
- node-ical 0.23.1 stores override with key: `"2024-10-12"` (local date)
- MagicMirror looked for key: `"2024-10-11"` (from UTC: Oct 11 22:00)
- **Result:** Moved event not found, appears on wrong date

**Solution:** Adapt to node-ical's new behavior by using local date
components for full-day events, UTC for timed events.

**Note:** This is different from previous timezone fixes - those
addressed event generation, this fixes the lookup of recurrence
overrides.

## Background

node-ical 0.23.0 switched from `rrule` to `rrule-temporal`, introducing
breaking changes. Version 0.23.1 fixed the UNTIL validation issue and
formalized the `getDateKey()` behavior for DATE vs DATE-TIME values,
following RFC 5545 specification that DATE values represent local
calendar dates without timezone context.
2026-01-11 21:27:52 -06:00
Karsten Hassel
82e39a2476 fix systeminformation not displaying electron version (#4012)
Bug was introduced with #4002

Because the sysinfo process runs as own subprocess the
`${process.versions.electron}` variable is always `undefined`.
2026-01-11 23:17:01 +01:00
Kristjan ESPERANTO
3b793bf31b Update node-ical and support it's rrule-temporal changes (#4010)
Updating `node-ical` and adapt logic to new behaviour.

## Problem

node-ical 0.23.0 switched from `rrule.js` to `rrule-temporal`, changing
how recurring event dates are returned. Our code assumed the old
behavior where dates needed manual timezone conversion.

## Solution

Updated `getMomentsFromRecurringEvent()` in `calendarfetcherutils.js`:
- Removed `tzid = null` clearing (no longer needed)
- Simplified timed events: `moment.tz(date, eventTimezone)` instead of
`moment.tz(date, "UTC").tz(eventTimezone, true)`
- Kept UTC component extraction for full-day events to prevent date
shifts
2026-01-10 18:35:46 -06:00
Kristjan ESPERANTO
471dbd80a5 Change default start scripts from X11 to Wayland (#4011)
This PR changes the default `start` and `start:dev` scripts to use
Wayland instead of X11. I think after three years, it's time to take
this step.

### Background

Since Raspberry Pi OS Bookworm (2023), Wayland is the default display
server. As most MagicMirror installations run on Raspberry Pi, this
change aligns with what new users already have installed.

### Benefits

Especially for new users (which install the OS with Wayland) it's easier
- they can simply run `npm start` without needing to understand display
server differences or manually switch scripts.

And for projects in general it's better to rely on modern defaults than
on legacy.

### Breaking Changes

**None** - X11 support is maintained. Users who really use and need X11
can use `node --run start:x11`.
2026-01-11 00:01:55 +01:00
Veeck
8e6701f6fd Update deps as requested by dependabot (#4008) 2026-01-08 20:31:42 +01:00
Karsten Hassel
b847dd7f3f update Collaboration.md and dependencies (#4001)
Co-authored-by: Kristjan ESPERANTO <35647502+KristjanESPERANTO@users.noreply.github.com>
2026-01-08 10:14:47 +01:00
Kristjan ESPERANTO
56fe067afa chore: migrate CI workflows to ubuntu-slim for faster startup times (#4007)
*This type of runner is optimized for automation tasks, issue operations
and short-running jobs. They are not suitable for typical heavyweight
CI/CD builds.*
[[1](https://docs.github.com/en/actions/reference/runners/github-hosted-runners#single-cpu-runners)].

We are not necessarily dependent on faster startups, but that seems to
be becoming the best practice now.
2026-01-07 23:18:24 +01:00
Kristjan ESPERANTO
9731ea28eb refactor: unify favicon for index.html and Electron (#4006)
In #3407 we already talked about unifying them.

- Create SVG favicon (better then png)
- Replace base64 placeholder in index.html with SVG favicon
- Update electron.js to use SVG favicon instead of mm2.png
- Add favicon.svg to server static routes
- Remove mm2.png
2026-01-05 10:51:43 +01:00
Kristjan ESPERANTO
40301f2a59 fix(calendar): correct day-of-week for full-day recurring events across all timezones (#4004)
Fixes **full-day recurring events showing on wrong day** in timezones
west of UTC (reported in #4003).

**Root cause**: `moment.tz(date, eventTimezone).startOf("day")`
interprets UTC midnight as local time:
- `2025-11-03T00:00:00.000Z` in America/Chicago (UTC-6)
- → Converts to `2025-11-02 18:00:00` (6 hours back)
- → `.startOf("day")` → `2025-11-02 00:00:00`  **Wrong day!**

**Impact**: The bug affects:
- All timezones west of UTC (UTC-1 through UTC-12): Americas, Pacific
- Timezones east of UTC (UTC+1 through UTC+12): Europe, Asia, Africa -
work correctly
- UTC itself - works correctly

The issue was introduced with commit c2ec6fc2 (#3976), which fixed the
time but broke the date. This PR fixes both.

| | Result | Day | Time | Notes |
|----------|--------|-----|------|-------|
| **Before c2ec6fc2** | `2025-11-03 05:00:00 Monday` |  |  | Wrong
time, but correct day |
| **Current (c2ec6fc2)** | `2025-11-02 00:00:00 Sunday` |  (west of
UTC)<br> (east of UTC) |  | Wrong day - visible bug! |
| **This fix** | `2025-11-03 00:00:00 Monday` |  |  | Correct in all
timezones |

Note: While the old logic had incorrect timing, it produced the correct
calendar day due to how it handled UTC offsets. The current logic fixed
the timing issue but introduced the more visible calendar day bug.

### Solution

Extract UTC date components and interpret as local calendar dates:

```javascript
const utcYear = date.getUTCFullYear();
const utcMonth = date.getUTCMonth();
const utcDate = date.getUTCDate();
return moment.tz([utcYear, utcMonth, utcDate], eventTimezone);
```

### Testing

To prevent this from happening again in future refactorings, I wrote a
test for it.

```bash
npm test -- tests/unit/modules/default/calendar/calendar_fetcher_utils_spec.js
```
2026-01-04 06:36:16 -06:00
Karsten Hassel
241921b79c [core] run systeminformation in subprocess so the info is always displayed (#4002)
If an error occurs during startup, we request system information from
the user. The problem is that this information is displayed too late,
for example, if the configuration check fails.

My initial idea was to use `await
Utils.logSystemInformation(global.version);`, but this increased the
startup time.

Therefore, the function is now called in a subprocess. This approach
provides the information in all cases and does not increase the startup
time.
2026-01-03 01:14:48 +01:00
sam detweiler
950f55197e set next release dev number (#4000)
change develop for next release labels
2026-01-01 16:06:29 +01:00
Karsten Hassel
a4f29f753f Merge branch 'master' into develop 2026-01-01 15:33:56 +01:00
sam detweiler
d5d1441782 Prepare Release 2.34.0 (#3998)
starting 2.34.0 release
2026-01-01 07:51:45 -06:00
Karsten Hassel
0fb6fcbb12 dependency update + adjust Playwright setup + fix linter issue (#3994)
update dependencies before next release

---------

Co-authored-by: Kristjan ESPERANTO <35647502+KristjanESPERANTO@users.noreply.github.com>
2025-12-28 12:14:31 +01:00
Karsten Hassel
49620781c2 demo with gif (#3995)
add demo.gif to README.md
2025-12-27 18:00:48 -06:00
Kristjan ESPERANTO
9d3b07db12 [core] fix: allow browser globals in config files (#3992)
The config checker previously only allowed Node.js globals, but since
the config file runs also in the browser context, users should be able
to access browser APIs like `document` or `window` when needed.

This was incorrectly flagged as an error by the `no-undef` ESLint rule.
The fix adds browser globals to the allowed globals in the linter
config.

Fixes #3990.
2025-12-21 12:44:03 +01:00
sam detweiler
9c25b15f6a add checksum to test whether calendar event list changed (#3988)
for issue #3971 add checksum to test if event list changed to
reduce/eliminate no change screen update
fixes #3971

crc32 checksum created in node helper, easy require, vs trying to do in
browser.
added to socket notification payload, used in browser
2025-12-18 20:57:24 +01:00
Kristjan ESPERANTO
c64d3ef146 [core] fix: restore --ozone-platform=wayland flag for reliable Wayland support (#3989)
The Electron 38+ auto-detection of ozone-platform does not work reliably
in all environments (e.g., Docker containers) because it depends on
environment variables like XDG_SESSION_TYPE which may not be set.

Since `start:wayland` is explicitly called for Wayland sessions, it
makes sense to explicitly specify the platform flag for maximum
reliability.

The `--enable-features=UseOzonePlatform` flag remains removed as it is
no longer needed since Electron 38.

Fixes Docker compatibility issue reported in
MagicMirrorOrg/MagicMirror#3974
2025-12-14 19:45:20 +01:00
Karsten Hassel
1998b6273b testing: update "Enforce Pull-Request Rules" workflow (#3987)
With this update the workflow file from inside the feature branch is
used, not the old stuff coming from `master` as before. This does not
help for the currently failing job which still comes from `master` (we
have to live with this until next release), but this will help in the
future to prevent such errors.

Tested this on my fork:
- base against `develop`: workflow is skipped
- base against `master`: workflow fails
- base against `master` with label `mastermerge`: workflow is skipped

I took this new workflow from the same repo where the previous workflows
was taken (see diff for the link) so this is the further development.
2025-12-10 22:28:34 +01:00
Karsten Hassel
e7ad361c93 [chore] update dependencies and min. node version (#3986) 2025-12-10 19:42:20 +01:00
Karsten Hassel
4186cbf0b2 [core] auto create release notes with every push on develop (#3985)
and remove CHANGELOG.md logic.

This is my attempt to create a draft release instead of editing a
changelog, see discussion on discord.

Logic:
- new github workflow `.github/workflows/release-notes.yaml`
- runs with every push on `develop` (so after PR's are merged)
- collects the commits on `develop` which are newer than the latest tag
- searches the commit messages for keywords defined in an array and
group the messages into categories (this is a first shot, we will update
this ...)
- creates markdown content
- looks for an untagged and unpublished draft release with name
`unreleased`, if it exists, it will be deleted
- creates an untagged and unpublished draft release with name
`unreleased` with markdown content created above

Example created on my fork (this caused having `MagicMirrorOrg` in the
PR-Links):

<img width="952" height="1804" alt="grafik"
src="https://github.com/user-attachments/assets/38687bed-f5da-4dcb-93eb-242c317769df"
/>

Please review this PR, it is a draft release at the moment because I got
problems in my fork where I tested this: The created draft release is
not visible at the moment (they are visible via api). AFAIS this is a
queue problem on GitHub, maybe I flooded their queue while testing ...
So I will test this tomorrow again before removing `draft` here.
2025-12-10 11:56:31 -06:00
Kristjan ESPERANTO
c2ec6fc2b9 [calendar] fix: prevent excessive fetching on client reload and refactor calendarfetcherutils.js (#3976)
The bottom line of this PR is, that it fixes an issue and simplifies the
code by dealing with the TODOs in the code.

For review, I suggest looking at each commit individually. If there are
too many changes for a PR, let me know and I'll split it up
🙂

## 1. [fix(calendar): prevent excessive fetching with smart refresh
strategy](8892cd3d5a)

- Add lastFetch timestamp tracking to CalendarFetcher
- Add shouldRefetch() method with configurable minimum interval
(default: 3 minutes)
- When reusing existing fetcher: fetch if data is stale (>3 min),
otherwise broadcast cached events
- Prevents double broadcasts to consuming modules while maintaining
fresh data
- Balances rate limit prevention (Issue
https://github.com/MagicMirrorOrg/MagicMirror/issues/3971) with data
freshness on user reload
- Prevents excessive fetching during rapid reloads (e.g., Fully Kiosk
screensaver use case)
- Allows fresh calendar data when enough time has passed since last
fetch

## 2. [refactor(calendar): simplify event exclusion
logic](d507aba82d)

- Extract filtering logic from `shouldEventBeExcluded` into new helper
`checkEventAgainstFilter`
- Simplify the main loop in `shouldEventBeExcluded

It resolves a TODO from the comments in the code:
* `This seems like an overly complicated way to exclude events based on
the title.`

## 3. [refactor(calendar): extract recurring event expansion
logic](d510160bd2)

This change separates the expansion of recurring events from the main
filtering loop into a new helper function 'expandRecurringEvent'.

It resolves two TODOs from the comments in the code:
- `This should be a separate function`
- `This should create an event per moment so we can change anything we
want`

This improves code readability, reduces complexity in 'filterEvents',
and allows for cleaner handling of individual recurrence instances.

## 4. [refactor(calendar): simplify recurring event
handling](b04f716cc0)

- Simplify 'getMomentsFromRecurringEvent' using modern syntax
- Improve handling of full-day events across different timezones


## 5. [test(calendar): fix UNTIL date in fullday_until.ics
fixture](1d762b2ade)

The issue was with the UNTIL date being May 4th while DTSTART was May
5th. This created an invalid recurrence rule where the end date came
before the start date.

The fix only adjusts the UNTIL date from May 4th to May 5th, so it
matches the start date.
2025-12-08 10:07:04 +01:00
Veeck
fdac92d2e9 [core] bump dependencies into december (#3982)
Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
Co-authored-by: veeck <gitkraken@veeck.de>
Co-authored-by: Kristjan ESPERANTO <35647502+KristjanESPERANTO@users.noreply.github.com>
2025-12-01 20:05:06 +01:00
Kristjan ESPERANTO
ca6e8b2857 [core] chore: simplify Wayland start script (#3974)
Remove `--enable-features=UseOzonePlatform` and
`--ozone-platform=wayland` flags as Electron 38+ changed the default
`--ozone-platform` to `auto`, which automatically detects and uses
Wayland when running in a Wayland session.

Source:
https://www.electronjs.org/blog/electron-38-0#removed-electron_ozone_platform_hint-environment-variable.
2025-11-29 09:39:16 +01:00
dependabot[bot]
a0f1a2c61e Bump actions/checkout from 5 to 6 (#3972)
Bumps [actions/checkout](https://github.com/actions/checkout) from 5 to
6.
<details>
<summary>Release notes</summary>
<p><em>Sourced from <a
href="https://github.com/actions/checkout/releases">actions/checkout's
releases</a>.</em></p>
<blockquote>
<h2>v6.0.0</h2>
<h2>What's Changed</h2>
<ul>
<li>Update README to include Node.js 24 support details and requirements
by <a href="https://github.com/salmanmkc"><code>@​salmanmkc</code></a>
in <a
href="https://redirect.github.com/actions/checkout/pull/2248">actions/checkout#2248</a></li>
<li>Persist creds to a separate file by <a
href="https://github.com/ericsciple"><code>@​ericsciple</code></a> in <a
href="https://redirect.github.com/actions/checkout/pull/2286">actions/checkout#2286</a></li>
<li>v6-beta by <a
href="https://github.com/ericsciple"><code>@​ericsciple</code></a> in <a
href="https://redirect.github.com/actions/checkout/pull/2298">actions/checkout#2298</a></li>
<li>update readme/changelog for v6 by <a
href="https://github.com/ericsciple"><code>@​ericsciple</code></a> in <a
href="https://redirect.github.com/actions/checkout/pull/2311">actions/checkout#2311</a></li>
</ul>
<p><strong>Full Changelog</strong>: <a
href="https://github.com/actions/checkout/compare/v5.0.0...v6.0.0">https://github.com/actions/checkout/compare/v5.0.0...v6.0.0</a></p>
<h2>v6-beta</h2>
<h2>What's Changed</h2>
<p>Updated persist-credentials to store the credentials under
<code>$RUNNER_TEMP</code> instead of directly in the local git
config.</p>
<p>This requires a minimum Actions Runner version of <a
href="https://github.com/actions/runner/releases/tag/v2.329.0">v2.329.0</a>
to access the persisted credentials for <a
href="https://docs.github.com/en/actions/tutorials/use-containerized-services/create-a-docker-container-action">Docker
container action</a> scenarios.</p>
<h2>v5.0.1</h2>
<h2>What's Changed</h2>
<ul>
<li>Port v6 cleanup to v5 by <a
href="https://github.com/ericsciple"><code>@​ericsciple</code></a> in <a
href="https://redirect.github.com/actions/checkout/pull/2301">actions/checkout#2301</a></li>
</ul>
<p><strong>Full Changelog</strong>: <a
href="https://github.com/actions/checkout/compare/v5...v5.0.1">https://github.com/actions/checkout/compare/v5...v5.0.1</a></p>
</blockquote>
</details>
<details>
<summary>Changelog</summary>
<p><em>Sourced from <a
href="https://github.com/actions/checkout/blob/main/CHANGELOG.md">actions/checkout's
changelog</a>.</em></p>
<blockquote>
<h1>Changelog</h1>
<h2>V6.0.0</h2>
<ul>
<li>Persist creds to a separate file by <a
href="https://github.com/ericsciple"><code>@​ericsciple</code></a> in <a
href="https://redirect.github.com/actions/checkout/pull/2286">actions/checkout#2286</a></li>
<li>Update README to include Node.js 24 support details and requirements
by <a href="https://github.com/salmanmkc"><code>@​salmanmkc</code></a>
in <a
href="https://redirect.github.com/actions/checkout/pull/2248">actions/checkout#2248</a></li>
</ul>
<h2>V5.0.1</h2>
<ul>
<li>Port v6 cleanup to v5 by <a
href="https://github.com/ericsciple"><code>@​ericsciple</code></a> in <a
href="https://redirect.github.com/actions/checkout/pull/2301">actions/checkout#2301</a></li>
</ul>
<h2>V5.0.0</h2>
<ul>
<li>Update actions checkout to use node 24 by <a
href="https://github.com/salmanmkc"><code>@​salmanmkc</code></a> in <a
href="https://redirect.github.com/actions/checkout/pull/2226">actions/checkout#2226</a></li>
</ul>
<h2>V4.3.1</h2>
<ul>
<li>Port v6 cleanup to v4 by <a
href="https://github.com/ericsciple"><code>@​ericsciple</code></a> in <a
href="https://redirect.github.com/actions/checkout/pull/2305">actions/checkout#2305</a></li>
</ul>
<h2>V4.3.0</h2>
<ul>
<li>docs: update README.md by <a
href="https://github.com/motss"><code>@​motss</code></a> in <a
href="https://redirect.github.com/actions/checkout/pull/1971">actions/checkout#1971</a></li>
<li>Add internal repos for checking out multiple repositories by <a
href="https://github.com/mouismail"><code>@​mouismail</code></a> in <a
href="https://redirect.github.com/actions/checkout/pull/1977">actions/checkout#1977</a></li>
<li>Documentation update - add recommended permissions to Readme by <a
href="https://github.com/benwells"><code>@​benwells</code></a> in <a
href="https://redirect.github.com/actions/checkout/pull/2043">actions/checkout#2043</a></li>
<li>Adjust positioning of user email note and permissions heading by <a
href="https://github.com/joshmgross"><code>@​joshmgross</code></a> in <a
href="https://redirect.github.com/actions/checkout/pull/2044">actions/checkout#2044</a></li>
<li>Update README.md by <a
href="https://github.com/nebuk89"><code>@​nebuk89</code></a> in <a
href="https://redirect.github.com/actions/checkout/pull/2194">actions/checkout#2194</a></li>
<li>Update CODEOWNERS for actions by <a
href="https://github.com/TingluoHuang"><code>@​TingluoHuang</code></a>
in <a
href="https://redirect.github.com/actions/checkout/pull/2224">actions/checkout#2224</a></li>
<li>Update package dependencies by <a
href="https://github.com/salmanmkc"><code>@​salmanmkc</code></a> in <a
href="https://redirect.github.com/actions/checkout/pull/2236">actions/checkout#2236</a></li>
</ul>
<h2>v4.2.2</h2>
<ul>
<li><code>url-helper.ts</code> now leverages well-known environment
variables by <a href="https://github.com/jww3"><code>@​jww3</code></a>
in <a
href="https://redirect.github.com/actions/checkout/pull/1941">actions/checkout#1941</a></li>
<li>Expand unit test coverage for <code>isGhes</code> by <a
href="https://github.com/jww3"><code>@​jww3</code></a> in <a
href="https://redirect.github.com/actions/checkout/pull/1946">actions/checkout#1946</a></li>
</ul>
<h2>v4.2.1</h2>
<ul>
<li>Check out other refs/* by commit if provided, fall back to ref by <a
href="https://github.com/orhantoy"><code>@​orhantoy</code></a> in <a
href="https://redirect.github.com/actions/checkout/pull/1924">actions/checkout#1924</a></li>
</ul>
<h2>v4.2.0</h2>
<ul>
<li>Add Ref and Commit outputs by <a
href="https://github.com/lucacome"><code>@​lucacome</code></a> in <a
href="https://redirect.github.com/actions/checkout/pull/1180">actions/checkout#1180</a></li>
<li>Dependency updates by <a
href="https://github.com/dependabot"><code>@​dependabot</code></a>- <a
href="https://redirect.github.com/actions/checkout/pull/1777">actions/checkout#1777</a>,
<a
href="https://redirect.github.com/actions/checkout/pull/1872">actions/checkout#1872</a></li>
</ul>
<h2>v4.1.7</h2>
<ul>
<li>Bump the minor-npm-dependencies group across 1 directory with 4
updates by <a
href="https://github.com/dependabot"><code>@​dependabot</code></a> in <a
href="https://redirect.github.com/actions/checkout/pull/1739">actions/checkout#1739</a></li>
<li>Bump actions/checkout from 3 to 4 by <a
href="https://github.com/dependabot"><code>@​dependabot</code></a> in <a
href="https://redirect.github.com/actions/checkout/pull/1697">actions/checkout#1697</a></li>
<li>Check out other refs/* by commit by <a
href="https://github.com/orhantoy"><code>@​orhantoy</code></a> in <a
href="https://redirect.github.com/actions/checkout/pull/1774">actions/checkout#1774</a></li>
<li>Pin actions/checkout's own workflows to a known, good, stable
version. by <a href="https://github.com/jww3"><code>@​jww3</code></a> in
<a
href="https://redirect.github.com/actions/checkout/pull/1776">actions/checkout#1776</a></li>
</ul>
<h2>v4.1.6</h2>
<ul>
<li>Check platform to set archive extension appropriately by <a
href="https://github.com/cory-miller"><code>@​cory-miller</code></a> in
<a
href="https://redirect.github.com/actions/checkout/pull/1732">actions/checkout#1732</a></li>
</ul>
<h2>v4.1.5</h2>
<ul>
<li>Update NPM dependencies by <a
href="https://github.com/cory-miller"><code>@​cory-miller</code></a> in
<a
href="https://redirect.github.com/actions/checkout/pull/1703">actions/checkout#1703</a></li>
<li>Bump github/codeql-action from 2 to 3 by <a
href="https://github.com/dependabot"><code>@​dependabot</code></a> in <a
href="https://redirect.github.com/actions/checkout/pull/1694">actions/checkout#1694</a></li>
<li>Bump actions/setup-node from 1 to 4 by <a
href="https://github.com/dependabot"><code>@​dependabot</code></a> in <a
href="https://redirect.github.com/actions/checkout/pull/1696">actions/checkout#1696</a></li>
<li>Bump actions/upload-artifact from 2 to 4 by <a
href="https://github.com/dependabot"><code>@​dependabot</code></a> in <a
href="https://redirect.github.com/actions/checkout/pull/1695">actions/checkout#1695</a></li>
</ul>
<!-- raw HTML omitted -->
</blockquote>
<p>... (truncated)</p>
</details>
<details>
<summary>Commits</summary>
<ul>
<li><a
href="1af3b93b68"><code>1af3b93</code></a>
update readme/changelog for v6 (<a
href="https://redirect.github.com/actions/checkout/issues/2311">#2311</a>)</li>
<li><a
href="71cf2267d8"><code>71cf226</code></a>
v6-beta (<a
href="https://redirect.github.com/actions/checkout/issues/2298">#2298</a>)</li>
<li><a
href="069c695914"><code>069c695</code></a>
Persist creds to a separate file (<a
href="https://redirect.github.com/actions/checkout/issues/2286">#2286</a>)</li>
<li><a
href="ff7abcd0c3"><code>ff7abcd</code></a>
Update README to include Node.js 24 support details and requirements (<a
href="https://redirect.github.com/actions/checkout/issues/2248">#2248</a>)</li>
<li>See full diff in <a
href="https://github.com/actions/checkout/compare/v5...v6">compare
view</a></li>
</ul>
</details>
<br />


[![Dependabot compatibility
score](https://dependabot-badges.githubapp.com/badges/compatibility_score?dependency-name=actions/checkout&package-manager=github_actions&previous-version=5&new-version=6)](https://docs.github.com/en/github/managing-security-vulnerabilities/about-dependabot-security-updates#about-compatibility-scores)

Dependabot will resolve any conflicts with this PR as long as you don't
alter it yourself. You can also trigger a rebase manually by commenting
`@dependabot rebase`.

[//]: # (dependabot-automerge-start)
[//]: # (dependabot-automerge-end)

---

<details>
<summary>Dependabot commands and options</summary>
<br />

You can trigger Dependabot actions by commenting on this PR:
- `@dependabot rebase` will rebase this PR
- `@dependabot recreate` will recreate this PR, overwriting any edits
that have been made to it
- `@dependabot merge` will merge this PR after your CI passes on it
- `@dependabot squash and merge` will squash and merge this PR after
your CI passes on it
- `@dependabot cancel merge` will cancel a previously requested merge
and block automerging
- `@dependabot reopen` will reopen this PR if it is closed
- `@dependabot close` will close this PR and stop Dependabot recreating
it. You can achieve the same result by closing it manually
- `@dependabot show <dependency name> ignore conditions` will show all
of the ignore conditions of the specified dependency
- `@dependabot ignore this major version` will close this PR and stop
Dependabot creating any more for this major version (unless you reopen
the PR or upgrade to it yourself)
- `@dependabot ignore this minor version` will close this PR and stop
Dependabot creating any more for this minor version (unless you reopen
the PR or upgrade to it yourself)
- `@dependabot ignore this dependency` will close this PR and stop
Dependabot creating any more for this dependency (unless you reopen the
PR or upgrade to it yourself)


</details>

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2025-11-24 13:07:52 +01:00
Kristjan ESPERANTO
7934e7aef8 [compliments] refactor: optimize loadComplimentFile method and add unit tests (#3969)
## Changes

- Replace `indexOf()` with `startsWith()` for cleaner protocol detection
- Use `URL` API for robust cache-busting parameter handling
- Add HTTP response validation and improved error logging
- Add JSDoc type annotations for better documentation
- Remove unused `urlSuffix` instance variable
- Add unit tests
- Fix `.gitignore` pattern

## Motivation

After merging #3967, I noticed some potential for improving reliability
and user experience related to the method `loadComplimentFile`. With
these changes the method now validates URLs upfront to catch
configuration errors early, checks HTTP status codes to detect server
issues (404/500), and provides specific error messages that help users
troubleshoot problems.

The complexity of the code does not really increase with the changes. On
the contrary, the method should now be more intuitive to understand.

## Testing

Added unit tests for `loadComplimentFile()` to validate the
improvements:
- HTTP error handling
- Cache-busting

Since E2E tests already cover the happy path, these unit tests focus on
error cases and edge cases.

## Additional Fix

While adding the test file, I discovered that the `.gitignore` pattern
`modules` was incorrectly matching `tests/unit/modules/`, preventing
test files from being tracked. Changed to `/modules` to only match the
root directory.
2025-11-23 17:13:13 +01:00
Samed Ozdemir
74b682fdf1 fix: set compliments remote file minimum delay to 15 minutes (#3970)
fix: set compliments remote file minimum delay to 15 minutes..extra *60
in there was making it 15 hours.
2025-11-21 13:27:37 +01:00
Kristjan ESPERANTO
854c954180 [gitignore] restore the old Git behavior for the default modules (#3968)
The pattern `modules` was too broad and prevented tracking files in
`modules/default/` despite the negation pattern. Changed to `modules/*`
to properly exclude only the content of the modules directory while
allowing the default modules to be tracked.

This issue was likely introduced during the cleanup in #3952.

Without this change there are now warn messages like this:

```bash
kristjan@debian:~/MagicMirror$ git add modules/default/compliments/compliments.js
The following paths are ignored by one of your .gitignore files:
modules
hint: Use -f if you really want to add them.
hint: Disable this message with "git config advice.addIgnoredFile false"
```
2025-11-19 11:40:53 +01:00
Samed Ozdemir
a52baa5874 [compliments] fix: duplicate query param "?" in compliments module refresh url (#3967)
Checks if `this.config.remoteFile.includes` already contains a `?`
- If it does, uses `&` to append the dummy parameter
- If it doesn't, uses `?` to start a new query string
2025-11-19 11:06:43 +01:00
Blackspirits
1796400ab9 Add new pt and pt-BR translations for Alert module and update global PT strings (#3965)
- Added new pt.json and pt-br.json in alert/translations
- Updated main pt.json (global translations)
- Updated alert.js to load new languages
- Added entry to CHANGELOG.md

---------

Co-authored-by: veeck <gitkraken@veeck.de>
2025-11-16 09:59:41 +01:00
Kristjan ESPERANTO
3c4d69ea84 [calendar] refactor: migrate CalendarFetcher to ES6 class and improve error handling (#3959)
1. Convert CalendarFetcher from legacy constructor function pattern to
ES6 class (which simplifies future migration from CommonJS to ES
modules).
2. Implement targeted HTTP error handling with smart retry strategies
for common calendar feed issues:
   - 401/403: Extended retry delay (5× interval, min 30 min)
   - 429: Retry-After header parsing with 15 min fallback
   - 5xx: Exponential backoff (2^count, max 3 retries)
   - 4xx: Extended retry (2× interval, min 15 min)
   - Add serverErrorCount tracking for exponential backoff
- Error messages now include specific HTTP status codes and calculated
retry delays for better debugging and user feedback

Previously, CalendarFetcher did not respond appropriately to HTTP
errors, continuing to hammer endpoints without backoff, potentially
overloading servers and triggering rate limits. This refactoring
implements respectful retry strategies that adapt to server responses
and reduce unnecessary load.

Maybe we could later centralize the HTTP error handling and use it for
weather and newsfeed as well.

The PR was inspired by having worked on the calendar fetcher for
MMM-CalendarExt2, where there was already better error handling.
2025-11-14 20:14:23 +01:00
Jordan Welch
53df20f313 [weatherprovider] update subclass language use override (#3914) 2025-11-13 22:08:47 +01:00
Veeck
38a4d235e8 [weather] fix wind-icon not showing in pirateweather (#3957)
fixes #3956

---------

Co-authored-by: veeck <gitkraken@veeck.de>
2025-11-10 21:41:24 +01:00
Kristjan ESPERANTO
f29f424a62 [core] refactor: replace XMLHttpRequest with fetch and migrate e2e tests to Playwright (#3950)
### 1. Replace `XMLHttpRequest` with the modern `fetch` API for loading
translation files

#### Changes
- **translator.js**: Use `fetch` with `async/await` instead of XHR
callbacks
- **loader.js**: Align URL handling and add error handling (follow-up to
fetch migration)
- **Tests**: Update infrastructure for `fetch` compatibility

#### Benefits
- Modern standard API
- Cleaner, more readable code
- Better error handling and fallback mechanisms

### 2. Migrate e2e tests to Playwright

This wasn't originally planned for this PR, but is related. While
investigating suspicious log entries which surfaced after the fetch
migration I kept running into JSDOM’s limitations. That pushed me to
migrate the E2E suite to Playwright instead.

#### Changes
- switch e2e harness to Playwright (`tests/e2e/helpers/global-setup.js`)
- rewrite specs to use Playwright locators + shared `expectTextContent`
- install Chromium via `npx playwright install --with-deps` in CI

#### Benefits
- much closer to real browser behaviour
- and no more fighting JSDOM’s quirks
2025-11-08 21:59:05 +01:00
Kristjan ESPERANTO
2b08288346 [core] configure cspell to check default modules only and fix typos (#3955)
When I saw PR #3951, I wondered why `cspell` didn't catch these typos
before. Unfortunately, the default modules were excluded from the check.
I have corrected this with these changes.

This even revealed a code error in
`modules/default/weather/providers/overrideWrapper.js`:

- before: `fetchEatherHourly`
- after: `fetchWeatherHourly`
2025-11-08 20:27:34 +01:00
Kristjan ESPERANTO
8e9ee8953a [gitignore] restoring the old Git behavior for the CSS directory (#3954)
The advantage of the old behavior is that users can keep backups, copies
or any other CSS files with different names in the directory without Git
interfering.

I suspect that this was not taken into account during the cleanup in PR
#3952 🙂
2025-11-08 20:25:47 +01:00
sam detweiler
c1aaea5913 [weather] add error handling to weather fetch functions, including cors (#3791)
Co-authored-by: Kristjan ESPERANTO <35647502+KristjanESPERANTO@users.noreply.github.com>
fixes #3687
2025-11-08 14:21:31 +01:00
Jarno
3b79791a6b [calendar] Show repeatingCountTitle only if yearDiff > 0 (#3949) 2025-11-08 14:13:59 +01:00
Karsten Hassel
ab5f79a1be remove deprecated ukmetoffice datapoint provider, cleanup .gitignore (#3952)
- weather ukmetoffice see #3842 , I got a final reminder today per mail
that datapoint will be retired on Dec. 1st.
- cleanup/simplify `.gitignore`
2025-11-07 08:45:20 +01:00
Veeck
034f3c4b2a [newsfeed] fix header layout issue (#3946)
... fixes #3944 introduced with prettier njk linting

---------

Co-authored-by: veeck <gitkraken@veeck.de>
Co-authored-by: Kristjan ESPERANTO <35647502+KristjanESPERANTO@users.noreply.github.com>
2025-11-05 18:09:30 +01:00
Kristjan ESPERANTO
9d713ffd69 [test] replace node-libgpiod with serialport in electron-rebuild workflow (#3945)
`node-libgpiod` uses deprecated NAN which is incompatible with Electron
v39+. `serialport` uses N-API ensuring compatibility with current and
future Electron versions.

`node-libgpiod` is only used by 1 of ~1300 3rd-party-modules
(MMM-PresenceScreenControl), while serialport is used by at least 4
modules (MMM-Serial-Notification, MMM-RadarPresence, MMM-LKY-TIC and
MMM-Gestures), making it a better test candidate.

Also updates Electron to v39.

Fixes #3933
2025-11-04 22:46:20 +01:00
Kristjan ESPERANTO
67fead74b4 [ci] Add concurrency to automated tests workflow to cancel outdated runs (#3943)
Add `concurrency` configuration to automatically cancel outdated test
runs when new commits are pushed to the same PR/branch.

Inspired by
[MagicMirrorOrg/MagicMirror-Documentation#335](https://github.com/MagicMirrorOrg/MagicMirror-Documentation/pull/335).
2025-11-04 18:04:29 +01:00
Kristjan ESPERANTO
d7348ed765 [tests] suppress debug logs in CI environment + improve calendar symbol test stability (#3941)
## CI Log Suppression

**Two-level approach for clean test output:**

1. **Suppress debug/info logs**: Call `logger.setLogLevel("ERROR")` in
CI to hide verbose logging
2. **Suppress intentional error logs**: Set `mmTestMode` flag and check
it before logging errors that are part of test assertions (e.g., testing
error handling in `git_helper.js` and `server_functions.js`)

This keeps CI output clean and makes genuine failures immediately
visible, while preserving full logging for local development.

**Before:** 1348 log lines with verbose debug/info output  
**After:** 168 log clean lines with only test results

## Calendar Symbol Test Stability

Convert the calendar symbol test from external URL (`calendarlabs.com`)
to existing local mock file (`12_events.ics`). This eliminates CI
timeouts caused by external dependencies and improves test reliability.

The test still validates the same symbol array feature but now runs
faster and deterministically without network dependencies.
2025-11-03 23:49:21 +01:00
Kristjan ESPERANTO
462abf7027 [tests] migrate from jest to vitest (#3940)
This is a big change, but I think it's a good move, as `vitest` is much
more modern than `jest`.

I'm excited about the UI watch feature (run `npm run test:ui`), for
example - it's really helpful and saves time when debugging tests. I had
to adjust a few tests because they had time related issues, but
basically we are now testing the same things - even a bit better and
less flaky (I hope).

What do you think?
2025-11-03 19:47:01 +01:00
Veeck
b542f33a0a Update deps, unpin parse5 (#3934)
seems we dont need the parse5 pin as long as jsdom is fixed to v27.0.0.

not sure if there is anything else we can do to the deps?

---------

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
Co-authored-by: veeck <gitkraken@veeck.de>
2025-11-01 22:29:40 +01:00
Karsten Hassel
1e5d127d44 fixes problems with daylight-saving-time in weather provider openmeteo (#3931)
fix for #3930
2025-11-01 13:46:58 +01:00